diff --git a/catalog/admin/#user.php# b/catalog/admin/#user.php#
new file mode 100644
index 0000000..9c88027
--- /dev/null
+++ b/catalog/admin/#user.php#
@@ -0,0 +1,76 @@
+db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_users");
+getstr ("filter");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this user.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ $f->Text ("user", "user", "User", SQLCHAR, 80, 240, true);
+ $f->Text ("login", "login", "Login", SQLCHAR, 80, 240, true);
+ $f->TextArea ("note", "note", "Note", SQLCHAR, 4, 80, false);
+
+ $f->LoadData ("select * from users where pk = $fk_users");
+}
+$f->Hidden ("fk_users");
+$f->Hidden ("filter");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into users " . $sql)) {
+ msg ("User added !");
+ } else {
+ error_msg ("Could not add user!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update users set " . $sql . "where pk = $fk_users")) {
+ msg ("User modified !");
+ } else {
+ error_msg ("Could not modify user !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->Exec ("delete from mn_users_permissions where fk_users = $fk_users");
+ if ($db->Exec ("delete from users where pk = $fk_users")) {
+ msg ("User deleted !");
+ } else {
+ error_msg ("Could not delete user !");
+ }
+}
+
+if (isupdate ()) {
+ if (!isupdatemode ("delete")) {
+ p ("Back to User ");
+ }
+} else {
+ $f->Output ($caption, $caption);
+}
+
+p ("Back to User List ");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/.#user.php b/catalog/admin/.#user.php
new file mode 120000
index 0000000..5f12a5e
--- /dev/null
+++ b/catalog/admin/.#user.php
@@ -0,0 +1 @@
+gutenbackend@login2.ibiblio.org.27895:1596734584
\ No newline at end of file
diff --git a/catalog/admin/.acl.gutenwebprod b/catalog/admin/.acl.gutenwebprod
new file mode 100644
index 0000000..3221f43
--- /dev/null
+++ b/catalog/admin/.acl.gutenwebprod
@@ -0,0 +1,3 @@
+
+ DirectoryIndex index.php
+
diff --git a/catalog/admin/a.php b/catalog/admin/a.php
new file mode 100644
index 0000000..5f757d0
--- /dev/null
+++ b/catalog/admin/a.php
@@ -0,0 +1,5 @@
+
diff --git a/catalog/admin/alias.php b/catalog/admin/alias.php
new file mode 100644
index 0000000..22915b4
--- /dev/null
+++ b/catalog/admin/alias.php
@@ -0,0 +1,66 @@
+db ();
+$db->logger = new logger ();
+
+getstr ("mode");
+getint ("fk_aliases");
+getint ("fk_authors");
+
+$caption = ucfirst ($mode);
+
+$f = new SQLForm ();
+
+if (ismode ("add")) {
+ $f->SQLInject ("fk_authors", "fk_authors", SQLINT);
+}
+$f->Text ("alias", "alias", "Alias", SQLCHAR, 80, 240, true);
+
+$f->KeySelect ("alias_heading", "alias_heading", "Heading", SQLINT, 10, 2, false);
+$f->last->PushOptions ($titles_heading);
+$f->last->ToolTip ("Should this alias generate a user-visible heading?");
+
+$f->LoadData ("select * from aliases where pk = $fk_aliases");
+
+$f->Hidden ("fk_aliases");
+$f->Hidden ("fk_authors");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this alias. " .
+ "Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+}
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ $retcode = $db->Exec ("insert into aliases " . $sql);
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ $retcode = $db->Exec ("update aliases set " . $sql . "where pk = $fk_aliases");
+ }
+}
+if (isupdatemode ("delete")) {
+ $retcode = $db->Exec ("delete from aliases where pk = $fk_aliases");
+}
+
+if (isupdate ()) {
+ $msg = confirmation_msg ($retcode, $mode, "alias");
+ header ("Location: author?mode=edit&fk_authors=$fk_authors&$msg");
+ return;
+}
+
+pageheader ("$caption Author Alias");
+$f->Output ($caption, $caption);
+pagefooter ();
+
+?>
diff --git a/catalog/admin/alias.php~ b/catalog/admin/alias.php~
new file mode 100644
index 0000000..4e5239a
--- /dev/null
+++ b/catalog/admin/alias.php~
@@ -0,0 +1,65 @@
+db ();
+$db->logger = new logger ();
+
+getstr ("mode");
+getint ("fk_aliases");
+getint ("fk_authors");
+
+$caption = ucfirst ($mode);
+
+$f = new SQLForm ();
+
+if (ismode ("add")) {
+ $f->SQLInject ("fk_authors", "fk_authors", SQLINT);
+}
+$f->Text ("alias", "alias", "Alias", SQLCHAR, 80, 240, true);
+
+$f->KeySelect ("alias_heading", "alias_heading", "Heading", SQLINT, 10, 2, false);
+$f->last->PushOptions ($titles_heading);
+$f->last->ToolTip ("Should this alias generate a user-visible heading?");
+
+$f->LoadData ("select * from aliases where pk = $fk_aliases");
+
+$f->Hidden ("fk_aliases");
+$f->Hidden ("fk_authors");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this alias. " .
+ "Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+}
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ $retcode = $db->Exec ("insert into aliases " . $sql);
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ $retcode = $db->Exec ("update aliases set " . $sql . "where pk = $fk_aliases");
+ }
+}
+if (isupdatemode ("delete")) {
+ $retcode = $db->Exec ("delete from aliases where pk = $fk_aliases");
+}
+
+if (isupdate ()) {
+ $msg = confirmation_msg ($retcode, $mode, "alias");
+ header ("Location: author?mode=edit&fk_authors=$fk_authors&$msg");
+ return;
+}
+
+pageheader ("$caption Author Alias");
+$f->Output ($caption, $caption);
+pagefooter ();
+
+?>
diff --git a/catalog/admin/attribute.php b/catalog/admin/attribute.php
new file mode 100644
index 0000000..2b28663
--- /dev/null
+++ b/catalog/admin/attribute.php
@@ -0,0 +1,82 @@
+db ();
+$db->logger = new logger ();
+
+getstr ("mode");
+getint ("pk");
+getint ("fk_books");
+
+$caption = ucfirst ($mode);
+
+$f = new SQLForm ();
+
+if (ismode ("add")) {
+ $f->SQLInject ("fk_books", "fk_books", SQLINT);
+}
+$f->KeySelect ("fk_attriblist", "fk_attriblist", "Attribute", SQLINT, 40, 40, true);
+$f->last->LoadSQL ("select pk as key, name as caption from attriblist where type = 'unc' order by name");
+$f->last->DefValue (500);
+$f->last->ToolTip ("Select an attribute.");
+
+$f->TextArea ("text", "text", "Value", SQLCHAR, 5, 80, true);
+$f->ToolTip ("Enter the value for the selected attribute.");
+
+$f->Text ("nonfiling", "nonfiling", "Nonfiling Chars", SQLINT, 2, 2, false);
+$f->DefValue (0);
+$f->ToolTip ("No. of nonfiling characters. eg. 'The Idiot' => 4");
+
+$f->Text ("indicators", "indicators", "MARC indicators", SQLCHAR, 2, 2, false);
+$f->ToolTip ("MARC indicators (2 digits). See MARC Spec for details. If you are unsure leave blank.");
+
+$f->KeySelect ("fk_langs", "fk_langs", "Language", SQLCHAR, 40, 40, true);
+$f->last->PushOption (null, "undefined");
+$f->last->LoadSQL ("select pk as key, lang as caption from langs order by lang");
+$f->last->DefValue ("en");
+$f->last->ToolTip ("Which language is this attribute in?");
+
+$f->LoadData ("select * from attributes where pk = $pk");
+
+$f->Hidden ("pk");
+$f->Hidden ("fk_books");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this attribute. " .
+ "Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+}
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ $retcode = $db->Exec ("insert into attributes " . $sql);
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ $retcode = $db->Exec ("update attributes set " . $sql . "where pk = $pk");
+ }
+}
+if (isupdatemode ("delete")) {
+ $retcode = $db->Exec ("delete from attributes where pk = $pk");
+}
+
+if (isupdate ()) {
+ $msg = confirmation_msg ($retcode, $mode, "attribute");
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+pageheader ("$caption Attribute");
+p ("A Summary of Commonly Used MARC 21 Fields ");
+$f->Output ($caption, $caption);
+pagefooter ();
+
+?>
diff --git a/catalog/admin/attribute.php~ b/catalog/admin/attribute.php~
new file mode 100644
index 0000000..e080ff9
--- /dev/null
+++ b/catalog/admin/attribute.php~
@@ -0,0 +1,81 @@
+db ();
+$db->logger = new logger ();
+
+getstr ("mode");
+getint ("pk");
+getint ("fk_books");
+
+$caption = ucfirst ($mode);
+
+$f = new SQLForm ();
+
+if (ismode ("add")) {
+ $f->SQLInject ("fk_books", "fk_books", SQLINT);
+}
+$f->KeySelect ("fk_attriblist", "fk_attriblist", "Attribute", SQLINT, 40, 40, true);
+$f->last->LoadSQL ("select pk as key, name as caption from attriblist where type = 'unc' order by name");
+$f->last->DefValue (500);
+$f->last->ToolTip ("Select an attribute.");
+
+$f->TextArea ("text", "text", "Value", SQLCHAR, 5, 80, true);
+$f->ToolTip ("Enter the value for the selected attribute.");
+
+$f->Text ("nonfiling", "nonfiling", "Nonfiling Chars", SQLINT, 2, 2, false);
+$f->DefValue (0);
+$f->ToolTip ("No. of nonfiling characters. eg. 'The Idiot' => 4");
+
+$f->Text ("indicators", "indicators", "MARC indicators", SQLCHAR, 2, 2, false);
+$f->ToolTip ("MARC indicators (2 digits). See MARC Spec for details. If you are unsure leave blank.");
+
+$f->KeySelect ("fk_langs", "fk_langs", "Language", SQLCHAR, 40, 40, true);
+$f->last->PushOption (null, "undefined");
+$f->last->LoadSQL ("select pk as key, lang as caption from langs order by lang");
+$f->last->DefValue ("en");
+$f->last->ToolTip ("Which language is this attribute in?");
+
+$f->LoadData ("select * from attributes where pk = $pk");
+
+$f->Hidden ("pk");
+$f->Hidden ("fk_books");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this attribute. " .
+ "Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+}
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ $retcode = $db->Exec ("insert into attributes " . $sql);
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ $retcode = $db->Exec ("update attributes set " . $sql . "where pk = $pk");
+ }
+}
+if (isupdatemode ("delete")) {
+ $retcode = $db->Exec ("delete from attributes where pk = $pk");
+}
+
+if (isupdate ()) {
+ $msg = confirmation_msg ($retcode, $mode, "attribute");
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+pageheader ("$caption Attribute");
+p ("A Summary of Commonly Used MARC 21 Fields ");
+$f->Output ($caption, $caption);
+pagefooter ();
+
+?>
diff --git a/catalog/admin/attribute_list.php b/catalog/admin/attribute_list.php
new file mode 100644
index 0000000..ba3becc
--- /dev/null
+++ b/catalog/admin/attribute_list.php
@@ -0,0 +1,39 @@
+db ();
+$db->logger = new logger ();
+
+$db->Exec("select name from attriblist where pk = $attribute");
+$marcfield = $db->Get("name");
+if (!$marcfield) {
+ pageheader("Usage of ... field");
+
+ echo("Error: Unrecognized MARC attribute \"$attribute\" given. ");
+ pagefooter();
+ return;
+ }
+pageheader ("Usage of $marcfield field");
+$db->Exec("select fk_books, text from attributes " .
+ "where fk_attriblist = $attribute");
+if ($db->Get("fk_books")) {
+ echo("
\n".
+ "Uses " .
+ "Etext# Text of MARC field ");
+ do {
+ $etext=$db->Get("fk_books");
+ echo("${etext} " .
+ $db->Get("text") . " \n");
+ } while ($db->NextRow());
+ echo ("
");
+ } else {
+ echo("MARC field $attribute is unused.");
+ }
+pagefooter();
+?>
diff --git a/catalog/admin/attribute_list.php~ b/catalog/admin/attribute_list.php~
new file mode 100644
index 0000000..5547411
--- /dev/null
+++ b/catalog/admin/attribute_list.php~
@@ -0,0 +1,38 @@
+db ();
+$db->logger = new logger ();
+
+$db->Exec("select name from attriblist where pk = $attribute");
+$marcfield = $db->Get("name");
+if (!$marcfield) {
+ pageheader("Usage of ... field");
+
+ echo("Error: Unrecognized MARC attribute \"$attribute\" given. ");
+ pagefooter();
+ return;
+ }
+pageheader ("Usage of $marcfield field");
+$db->Exec("select fk_books, text from attributes " .
+ "where fk_attriblist = $attribute");
+if ($db->Get("fk_books")) {
+ echo("\n".
+ "Uses " .
+ "Etext# Text of MARC field ");
+ do {
+ $etext=$db->Get("fk_books");
+ echo("${etext} " .
+ $db->Get("text") . " \n");
+ } while ($db->NextRow());
+ echo ("
");
+ } else {
+ echo("MARC field $attribute is unused.");
+ }
+pagefooter();
+?>
\ No newline at end of file
diff --git a/catalog/admin/attribute_stats.php b/catalog/admin/attribute_stats.php
new file mode 100644
index 0000000..36f547c
--- /dev/null
+++ b/catalog/admin/attribute_stats.php
@@ -0,0 +1,42 @@
+db ();
+$db->logger = new logger ();
+
+$marc_fields = array();
+$db->Exec("select pk, name from attriblist order by pk");
+do {
+ $marc_fields[] = array($db->Get("pk"), $db->Get("name"));
+ } while ($db->NextRow());
+
+echo <<< EOT
+This is a list of all the MARC field/attribute/tag/code names currently
+present in the cataloging system. As you can see, we do not actually use
+MARC attributes for Author, Language, Subject or LoCC (they are stored
+& modified elsewhere), but the system does know about them. This should
+probably be fixed. -- Jan 2008
+ Click on the attribute name to get a list of all the uses of it in the system,
+ along with links to edit them.
+EOT;
+
+echo("\n".
+ "# of times each MARC field is used in the PG catalog. " .
+ "MARC field # of entries ");
+for ($i = 0 ; $i < count($marc_fields); $i++) {
+ $db->Exec("select count(*) as cnt from attributes where fk_attriblist = " .
+ $marc_fields[$i][0]);
+ echo("" .
+ $marc_fields[$i][1] . " " . $db->Get("cnt") .
+ " \n");
+ }
+echo ("
");
+
+pagefooter();
+?>
diff --git a/catalog/admin/attribute_stats.php~ b/catalog/admin/attribute_stats.php~
new file mode 100644
index 0000000..a80a6e8
--- /dev/null
+++ b/catalog/admin/attribute_stats.php~
@@ -0,0 +1,41 @@
+db ();
+$db->logger = new logger ();
+
+$marc_fields = array();
+$db->Exec("select pk, name from attriblist order by pk");
+do {
+ $marc_fields[] = array($db->Get("pk"), $db->Get("name"));
+ } while ($db->NextRow());
+
+echo <<< EOT
+This is a list of all the MARC field/attribute/tag/code names currently
+present in the cataloging system. As you can see, we do not actually use
+MARC attributes for Author, Language, Subject or LoCC (they are stored
+& modified elsewhere), but the system does know about them. This should
+probably be fixed. -- Jan 2008
+ Click on the attribute name to get a list of all the uses of it in the system,
+ along with links to edit them.
+EOT;
+
+echo("\n".
+ "# of times each MARC field is used in the PG catalog. " .
+ "MARC field # of entries ");
+for ($i = 0 ; $i < count($marc_fields); $i++) {
+ $db->Exec("select count(*) as cnt from attributes where fk_attriblist = " .
+ $marc_fields[$i][0]);
+ echo("" .
+ $marc_fields[$i][1] . " " . $db->Get("cnt") .
+ " \n");
+ }
+echo ("
");
+
+pagefooter();
+?>
\ No newline at end of file
diff --git a/catalog/admin/author.php b/catalog/admin/author.php
new file mode 100644
index 0000000..253910f
--- /dev/null
+++ b/catalog/admin/author.php
@@ -0,0 +1,182 @@
+AddColumn ("$prefix=edit&fk_aliases=#pk#\">Edit",
+ "$prefix=add\">Add", "narrow");
+ $this->AddColumn ("$prefix=delete&fk_aliases=#pk#\">Delete", "", "narrow");
+ $this->AddSimpleColumn ("alias", "Alias");
+ $this->AddSimpleColumn ("c_alias_heading", "Heading", "narrow");
+
+ $this->AddSubCaption
+ ("Less prominent names and pseudonyms the author is also known under, " .
+ "ASCII-fied versions, variant orthographies, common mis-spellings (Gutenburg).");
+ }
+}
+
+class ListAuthorUrlsTable extends ListTable {
+ function __construct () {
+ global $fk_authors;
+ $prefix = "AddColumn ("$prefix=edit&fk_author_urls=#pk#\">Edit ",
+ "$prefix=add\">Add", "narrow");
+ $this->AddColumn ("$prefix=delete&fk_author_urls=#pk#\">Delete", "", "narrow");
+
+ $this->AddSimpleColumn ("description", "Description");
+ $this->AddSimpleColumn ("url", "URL");
+
+ $this->AddSubCaption ("Interesting sites about the author.");
+ }
+}
+
+class ListBooksTable extends ListTable {
+ function __construct () {
+ $this->AddColumn ("#fk_books# ",
+ "Etext Nr.", "narrow right");
+ $this->AddSimpleColumn ("title", "Title");
+ $this->AddSimpleColumn ("lang", "Language", "narrow");
+ $this->AddSimpleColumn ("role", "Role", "narrow");
+
+ $this->AddSubCaption ("Books linked to author.");
+ }
+}
+
+$db = $config->db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_authors");
+
+if (ismode ("delete")) {
+ $db->Exec ("select count (*) as cnt from mn_books_authors where fk_authors = $fk_authors");
+ $cnt = $db->get ("cnt");
+ if ($cnt > 0) {
+ error_msg ("There are still $cnt books related to this author. " .
+ "You must delete them first.");
+ }
+ $db->Exec ("select author from authors where pk = $fk_authors");
+ $author = $db->get("author");
+ $f->SubCaption ("You are about to delete author: $author.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+print "editing \n";
+ $f->SubCaption ("The best-known name or pseudonym and other data.");
+ $f->Text ("author", "author", "Name", SQLCHAR, 80, 240, true);
+ $f->ToolTip ("Enter the name or pseudonym the author is best known under. " .
+ "Put lesser known names or pseudonyms in aliases. " .
+ "Use full unicode here and put an ASCII-fied version in aliases." .
+ "(eg. Brontë, Charlotte)");
+
+ $f->Text ("born_floor", "born_floor", "Born (earliest)", SQLINT, 12, 12, false);
+ $f->ToolTip ("Year the author was born (earliest estimate). Leave empty if unknown. ".
+ "(eg. 1803, -250)");
+ $f->Text ("born_ceil", "born_ceil", "Born (latest)", SQLINT, 12, 12, false);
+ $f->ToolTip ("Year the author was born (latest estimate). Leave empty if unknown. ".
+ "(eg. 1803, -250)");
+
+ $f->Text ("died_floor", "died_floor", "Died (earliest)", SQLINT, 12, 12, false);
+ $f->ToolTip ("Year the author died (earliest estimate). Leave empty if unknown. ".
+ "(eg. 1803, -250)");
+ $f->Text ("died_ceil", "died_ceil", "Died (latest)", SQLINT, 12, 12, false);
+ $f->ToolTip ("Year the author died (latest estimate). Leave empty if unknown. ".
+ "(eg. 1803, -250)");
+
+ $f->TextArea ("note", "note", "Note", SQLCHAR, 4, 80, false);
+ $f->ToolTip ("Any note relevant to the cataloging people.");
+ $f->LoadData ("select * from authors where pk = $fk_authors");
+}
+$f->Hidden ("fk_authors");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into authors " . $sql)) {
+ msg ("Author added !");
+ } else {
+ error_msg ("Could not add Author!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update authors set " . $sql . "where pk = $fk_authors")) {
+ msg ("Author modified !");
+ } else {
+ error_msg ("Could not modify author !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->Exec ("delete from aliases where fk_authors = $fk_authors");
+ $db->Exec ("delete from author_urls where fk_authors = $fk_authors");
+ if ($db->Exec ("delete from authors where pk = $fk_authors")) {
+ msg ("Author deleted !");
+ $fk_authors = null;
+ } else {
+ error_msg ("Could not delete author !");
+ }
+}
+
+if (isupdate ()) {
+ if ($fk_authors)
+ p ("" .
+ "Back to Author ");
+} else {
+
+ $f->Output ($caption, $caption);
+
+ if (ismode ("edit")) {
+ $db->exec ("select * from authors where pk = $fk_authors");
+ if ($db->FirstRow ()) {
+ $author_from = $db->Get ("author", SQLCHAR);
+ p ("Transfer Books ");
+ }
+
+ p("" .
+ "Delete Author ");
+ $db->exec ("select * from aliases where fk_authors = $fk_authors;");
+ $db->calcfields ["c_alias_heading"] = new CalcFieldAliasHeading ();
+ $table = new ListAliasesTable ();
+ $table->PrintTable ($db, "Aliases");
+
+ $db->exec ("select * from author_urls where fk_authors = $fk_authors;");
+ $table = new ListAuthorUrlsTable ();
+ $table->PrintTable ($db, "URLs");
+
+ $db->exec ("select * from v_books where fk_authors = $fk_authors order by title;");
+ $table = new ListBooksTable ();
+ $table->PrintTable ($db, "Books");
+ }
+}
+
+pagefooter ();
+
+// Local Variables:
+// mode:php
+// coding:utf-8-unix
+// fill-column: 75
+// End:
+
+?>
diff --git a/catalog/admin/author.php~ b/catalog/admin/author.php~
new file mode 100644
index 0000000..7fe9aea
--- /dev/null
+++ b/catalog/admin/author.php~
@@ -0,0 +1,181 @@
+AddColumn ("$prefix=edit&fk_aliases=#pk#\">Edit",
+ "$prefix=add\">Add", "narrow");
+ $this->AddColumn ("$prefix=delete&fk_aliases=#pk#\">Delete", "", "narrow");
+ $this->AddSimpleColumn ("alias", "Alias");
+ $this->AddSimpleColumn ("c_alias_heading", "Heading", "narrow");
+
+ $this->AddSubCaption
+ ("Less prominent names and pseudonyms the author is also known under, " .
+ "ASCII-fied versions, variant orthographies, common mis-spellings (Gutenburg).");
+ }
+}
+
+class ListAuthorUrlsTable extends ListTable {
+ function __construct () {
+ global $fk_authors;
+ $prefix = "AddColumn ("$prefix=edit&fk_author_urls=#pk#\">Edit ",
+ "$prefix=add\">Add", "narrow");
+ $this->AddColumn ("$prefix=delete&fk_author_urls=#pk#\">Delete", "", "narrow");
+
+ $this->AddSimpleColumn ("description", "Description");
+ $this->AddSimpleColumn ("url", "URL");
+
+ $this->AddSubCaption ("Interesting sites about the author.");
+ }
+}
+
+class ListBooksTable extends ListTable {
+ function __construct () {
+ $this->AddColumn ("#fk_books# ",
+ "Etext Nr.", "narrow right");
+ $this->AddSimpleColumn ("title", "Title");
+ $this->AddSimpleColumn ("lang", "Language", "narrow");
+ $this->AddSimpleColumn ("role", "Role", "narrow");
+
+ $this->AddSubCaption ("Books linked to author.");
+ }
+}
+
+$db = $config->db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_authors");
+
+if (ismode ("delete")) {
+ $db->Exec ("select count (*) as cnt from mn_books_authors where fk_authors = $fk_authors");
+ $cnt = $db->get ("cnt");
+ if ($cnt > 0) {
+ error_msg ("There are still $cnt books related to this author. " .
+ "You must delete them first.");
+ }
+ $db->Exec ("select author from authors where pk = $fk_authors");
+ $author = $db->get("author");
+ $f->SubCaption ("You are about to delete author: $author.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+print "editing \n";
+ $f->SubCaption ("The best-known name or pseudonym and other data.");
+ $f->Text ("author", "author", "Name", SQLCHAR, 80, 240, true);
+ $f->ToolTip ("Enter the name or pseudonym the author is best known under. " .
+ "Put lesser known names or pseudonyms in aliases. " .
+ "Use full unicode here and put an ASCII-fied version in aliases." .
+ "(eg. Brontë, Charlotte)");
+
+ $f->Text ("born_floor", "born_floor", "Born (earliest)", SQLINT, 12, 12, false);
+ $f->ToolTip ("Year the author was born (earliest estimate). Leave empty if unknown. ".
+ "(eg. 1803, -250)");
+ $f->Text ("born_ceil", "born_ceil", "Born (latest)", SQLINT, 12, 12, false);
+ $f->ToolTip ("Year the author was born (latest estimate). Leave empty if unknown. ".
+ "(eg. 1803, -250)");
+
+ $f->Text ("died_floor", "died_floor", "Died (earliest)", SQLINT, 12, 12, false);
+ $f->ToolTip ("Year the author died (earliest estimate). Leave empty if unknown. ".
+ "(eg. 1803, -250)");
+ $f->Text ("died_ceil", "died_ceil", "Died (latest)", SQLINT, 12, 12, false);
+ $f->ToolTip ("Year the author died (latest estimate). Leave empty if unknown. ".
+ "(eg. 1803, -250)");
+
+ $f->TextArea ("note", "note", "Note", SQLCHAR, 4, 80, false);
+ $f->ToolTip ("Any note relevant to the cataloging people.");
+ $f->LoadData ("select * from authors where pk = $fk_authors");
+}
+$f->Hidden ("fk_authors");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into authors " . $sql)) {
+ msg ("Author added !");
+ } else {
+ error_msg ("Could not add Author!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update authors set " . $sql . "where pk = $fk_authors")) {
+ msg ("Author modified !");
+ } else {
+ error_msg ("Could not modify author !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->Exec ("delete from aliases where fk_authors = $fk_authors");
+ $db->Exec ("delete from author_urls where fk_authors = $fk_authors");
+ if ($db->Exec ("delete from authors where pk = $fk_authors")) {
+ msg ("Author deleted !");
+ $fk_authors = null;
+ } else {
+ error_msg ("Could not delete author !");
+ }
+}
+
+if (isupdate ()) {
+ if ($fk_authors)
+ p ("" .
+ "Back to Author ");
+} else {
+
+ $f->Output ($caption, $caption);
+
+ if (ismode ("edit")) {
+ $db->exec ("select * from authors where pk = $fk_authors");
+ if ($db->FirstRow ()) {
+ $author_from = $db->Get ("author", SQLCHAR);
+ p ("Transfer Books ");
+ }
+
+ p("" .
+ "Delete Author ");
+ $db->exec ("select * from aliases where fk_authors = $fk_authors;");
+ $db->calcfields ["c_alias_heading"] = new CalcFieldAliasHeading ();
+ $table = new ListAliasesTable ();
+ $table->PrintTable ($db, "Aliases");
+
+ $db->exec ("select * from author_urls where fk_authors = $fk_authors;");
+ $table = new ListAuthorUrlsTable ();
+ $table->PrintTable ($db, "URLs");
+
+ $db->exec ("select * from v_books where fk_authors = $fk_authors order by title;");
+ $table = new ListBooksTable ();
+ $table->PrintTable ($db, "Books");
+ }
+}
+
+pagefooter ();
+
+// Local Variables:
+// mode:php
+// coding:utf-8-unix
+// fill-column: 75
+// End:
+
+?>
diff --git a/catalog/admin/author_url.php b/catalog/admin/author_url.php
new file mode 100644
index 0000000..c3551bb
--- /dev/null
+++ b/catalog/admin/author_url.php
@@ -0,0 +1,72 @@
+db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_author_urls");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this URL.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ if (ismode ("add")) {
+ $f->SQLInject ("fk_authors", "fk_authors", SQLINT);
+ }
+ $f->Text ("description", "description", "Description", SQLCHAR, 80, 240, true);
+ $f->Text ("url", "url", "URL", SQLCHAR, 80, 240, true);
+ $f->LoadData ("select * from author_urls where pk = $fk_author_urls");
+}
+$f->Hidden ("fk_author_urls");
+$f->Hidden ("fk_authors");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into author_urls " . $sql)) {
+ msg ("Author URL added !");
+ } else {
+ error_msg ("Could not add author URL!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update author_urls set " . $sql . "where pk = $fk_author_urls")) {
+ msg ("Author URL modified !");
+ } else {
+ error_msg ("Could not modify author URL !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from author_urls where pk = $fk_author_urls")) {
+ msg ("Author URL deleted !");
+ } else {
+ error_msg ("Could not delete author URL !");
+ }
+}
+
+if (isupdate ()) {
+ getint ("fk_authors");
+ echo ("Back to Author
\n\n");
+} else {
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/author_url.php~ b/catalog/admin/author_url.php~
new file mode 100644
index 0000000..f5b4064
--- /dev/null
+++ b/catalog/admin/author_url.php~
@@ -0,0 +1,71 @@
+db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_author_urls");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this URL.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ if (ismode ("add")) {
+ $f->SQLInject ("fk_authors", "fk_authors", SQLINT);
+ }
+ $f->Text ("description", "description", "Description", SQLCHAR, 80, 240, true);
+ $f->Text ("url", "url", "URL", SQLCHAR, 80, 240, true);
+ $f->LoadData ("select * from author_urls where pk = $fk_author_urls");
+}
+$f->Hidden ("fk_author_urls");
+$f->Hidden ("fk_authors");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into author_urls " . $sql)) {
+ msg ("Author URL added !");
+ } else {
+ error_msg ("Could not add author URL!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update author_urls set " . $sql . "where pk = $fk_author_urls")) {
+ msg ("Author URL modified !");
+ } else {
+ error_msg ("Could not modify author URL !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from author_urls where pk = $fk_author_urls")) {
+ msg ("Author URL deleted !");
+ } else {
+ error_msg ("Could not delete author URL !");
+ }
+}
+
+if (isupdate ()) {
+ getint ("fk_authors");
+ echo ("Back to Author
\n\n");
+} else {
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/authors_list.php b/catalog/admin/authors_list.php
new file mode 100644
index 0000000..0f9966b
--- /dev/null
+++ b/catalog/admin/authors_list.php
@@ -0,0 +1,74 @@
+AddColumn ("Edit ",
+ "Add ", "narrow");
+ $this->AddColumn ("Delete ",
+ "", "narrow");
+ if ($fk_authors_from) {
+ $this->AddColumn ("Transfer To ",
+ "", "narrow");
+ $this->TitleColumn ("Transfer all books linked to $author_from to this one.");
+ } else {
+ $this->AddColumn ("Transfer From ",
+ "", "narrow");
+ $this->TitleColumn ("Transfer all books linked to this author to a different one.");
+ }
+ $this->AddSimpleColumn ("author", "Name");
+ $this->AddSimpleColumn ("cnt_books", "No. of Books", "narrow right");
+ $this->AddSimpleColumn ("born_floor", "Born", "narrow right");
+ $this->AddSimpleColumn ("died_floor", "Died", "narrow right");
+ }
+}
+
+$db = $config->db ();
+
+echo ("
+Please enter the first few characters of the authors name (at least one).
+Search is case-insensitive.
+Use * as wildcard. (eg. Moli*re)
+To see everything just enter *.
+");
+
+form_open ();
+echo (" \n");
+form_hidden ("fk_authors_from", $fk_authors_from);
+form_hidden ("author_from", $author_from);
+form_submit ("Search");
+form_close ();
+
+if ($filter != "") {
+ $sql_filter = str_replace ('*', '%', $filter);
+ $sql_filter = $db->f ("$sql_filter%", SQLCHAR);
+ $db->exec ("select *, (select count (*) from mn_books_authors where fk_authors = authors.pk) as cnt_books from authors where " .
+ "(author ilike $sql_filter or authors.pk in " .
+ "(select fk_authors from aliases where alias ilike $sql_filter)) " .
+ "order by author");
+ $table = new ListAuthorsTable ();
+ $table->PrintTable ($db, $caption, "pgdbfiles");
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/authors_list.php~ b/catalog/admin/authors_list.php~
new file mode 100644
index 0000000..47a4bcf
--- /dev/null
+++ b/catalog/admin/authors_list.php~
@@ -0,0 +1,73 @@
+AddColumn ("Edit ",
+ "Add ", "narrow");
+ $this->AddColumn ("Delete ",
+ "", "narrow");
+ if ($fk_authors_from) {
+ $this->AddColumn ("Transfer To ",
+ "", "narrow");
+ $this->TitleColumn ("Transfer all books linked to $author_from to this one.");
+ } else {
+ $this->AddColumn ("Transfer From ",
+ "", "narrow");
+ $this->TitleColumn ("Transfer all books linked to this author to a different one.");
+ }
+ $this->AddSimpleColumn ("author", "Name");
+ $this->AddSimpleColumn ("cnt_books", "No. of Books", "narrow right");
+ $this->AddSimpleColumn ("born_floor", "Born", "narrow right");
+ $this->AddSimpleColumn ("died_floor", "Died", "narrow right");
+ }
+}
+
+$db = $config->db ();
+
+echo ("
+Please enter the first few characters of the authors name (at least one).
+Search is case-insensitive.
+Use * as wildcard. (eg. Moli*re)
+To see everything just enter *.
+");
+
+form_open ();
+echo (" \n");
+form_hidden ("fk_authors_from", $fk_authors_from);
+form_hidden ("author_from", $author_from);
+form_submit ("Search");
+form_close ();
+
+if ($filter != "") {
+ $sql_filter = str_replace ('*', '%', $filter);
+ $sql_filter = $db->f ("$sql_filter%", SQLCHAR);
+ $db->exec ("select *, (select count (*) from mn_books_authors where fk_authors = authors.pk) as cnt_books from authors where " .
+ "(author ilike $sql_filter or authors.pk in " .
+ "(select fk_authors from aliases where alias ilike $sql_filter)) " .
+ "order by author");
+ $table = new ListAuthorsTable ();
+ $table->PrintTable ($db, $caption, "pgdbfiles");
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/authors_transfer.php b/catalog/admin/authors_transfer.php
new file mode 100644
index 0000000..b29939c
--- /dev/null
+++ b/catalog/admin/authors_transfer.php
@@ -0,0 +1,75 @@
+db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_authors_from");
+getint ("fk_authors_to");
+
+if (!$fk_authors_from) error_msg ("No From Author");
+if (!$fk_authors_to) error_msg ("No To Author");
+// don't test for author equality, transferring to the same author
+// can be useful to batch-change the role.
+// if ($fk_authors_to == $fk_authors_from) error_msg ("But that is the same author!");
+
+if (!isupdate ()) {
+ $db->Exec ("select count (*) as cnt from mn_books_authors where fk_authors = $fk_authors_from");
+ $cnt = $db->get ("cnt");
+ $f->SQLSelect ("fk_roles", "fk_roles", "Author Role", SQLCHAR, 40, 40, true,
+ "select 'same' as value, 'Same Role' as caption union " .
+ "select pk as value, role as caption from roles order by caption");
+ $f->SetFieldData ("fk_roles", "same");
+ $f->SubCaption ("You are about to transfer $cnt books from $author_from to $author_to.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+}
+
+$f->Hidden ("fk_authors_from");
+$f->Hidden ("fk_authors_to");
+$f->Hidden ("author_from");
+$f->Hidden ("author_to");
+
+if (isupdate ()) {
+ getstr ("fk_roles");
+ if ($fk_roles == "same") {
+ $sql = "update mn_books_authors set fk_authors = $fk_authors_to " .
+ "where fk_authors = $fk_authors_from";
+ } else {
+ $sql_fk_roles = $db->f ($fk_roles, SQLCHAR);
+ $sql = "update mn_books_authors set fk_authors = $fk_authors_to, fk_roles = $sql_fk_roles " .
+ "where fk_authors = $fk_authors_from";
+ }
+ if ($db->exec ($sql)) {
+ msg ("Books transferred !");
+ } else {
+ error_msg ("Could not transfer books !");
+ }
+ p ("Delete From Author ($author_from) ");
+ p ("Back to To Author ($author_to) ");
+} else {
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+// Local Variables:
+// mode:php
+// coding:utf-8-unix
+// fill-column: 75
+// End:
+
+?>
+
diff --git a/catalog/admin/authors_transfer.php~ b/catalog/admin/authors_transfer.php~
new file mode 100644
index 0000000..af7fe40
--- /dev/null
+++ b/catalog/admin/authors_transfer.php~
@@ -0,0 +1,74 @@
+db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_authors_from");
+getint ("fk_authors_to");
+
+if (!$fk_authors_from) error_msg ("No From Author");
+if (!$fk_authors_to) error_msg ("No To Author");
+// don't test for author equality, transferring to the same author
+// can be useful to batch-change the role.
+// if ($fk_authors_to == $fk_authors_from) error_msg ("But that is the same author!");
+
+if (!isupdate ()) {
+ $db->Exec ("select count (*) as cnt from mn_books_authors where fk_authors = $fk_authors_from");
+ $cnt = $db->get ("cnt");
+ $f->SQLSelect ("fk_roles", "fk_roles", "Author Role", SQLCHAR, 40, 40, true,
+ "select 'same' as value, 'Same Role' as caption union " .
+ "select pk as value, role as caption from roles order by caption");
+ $f->SetFieldData ("fk_roles", "same");
+ $f->SubCaption ("You are about to transfer $cnt books from $author_from to $author_to.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+}
+
+$f->Hidden ("fk_authors_from");
+$f->Hidden ("fk_authors_to");
+$f->Hidden ("author_from");
+$f->Hidden ("author_to");
+
+if (isupdate ()) {
+ getstr ("fk_roles");
+ if ($fk_roles == "same") {
+ $sql = "update mn_books_authors set fk_authors = $fk_authors_to " .
+ "where fk_authors = $fk_authors_from";
+ } else {
+ $sql_fk_roles = $db->f ($fk_roles, SQLCHAR);
+ $sql = "update mn_books_authors set fk_authors = $fk_authors_to, fk_roles = $sql_fk_roles " .
+ "where fk_authors = $fk_authors_from";
+ }
+ if ($db->exec ($sql)) {
+ msg ("Books transferred !");
+ } else {
+ error_msg ("Could not transfer books !");
+ }
+ p ("Delete From Author ($author_from) ");
+ p ("Back to To Author ($author_to) ");
+} else {
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+// Local Variables:
+// mode:php
+// coding:utf-8-unix
+// fill-column: 75
+// End:
+
+?>
+
diff --git a/catalog/admin/book-make-fileinfo.php b/catalog/admin/book-make-fileinfo.php
new file mode 100644
index 0000000..010596a
--- /dev/null
+++ b/catalog/admin/book-make-fileinfo.php
@@ -0,0 +1,78 @@
+FirstRow ()) {
+ do {
+ $v = $db->get ("value", SQLCHAR);
+ echo ("$caption: $v\n");
+ } while ($db->NextRow ());
+ }
+}
+
+$db = $config->db ();
+
+$db->exec ("select * from books where pk = $fk_books");
+if (!$db->FirstRow ()) {
+ exit ();
+}
+
+$release_date = $db->get ("release_date", SQLDATE);
+$copyrighted = $db->get ("copyrighted", SQLINT);
+echo ("Etext-Nr: $fk_books\n");
+echo ("Release-Date: " . date ("M d, Y\n", $release_date));
+echo ("Copyrighted: $copyrighted\n");
+
+$db->exec ("select author, role from v_books_authors " .
+ "where fk_books = $fk_books");
+if ($db->FirstRow ()) {
+ do {
+ $author = $db->get ("author", SQLCHAR);
+ $role = $db->get ("role", SQLCHAR);
+ echo ("$role: $author\n");
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select title as value from titles where title_order = 1 and fk_books = $fk_books");
+output ($db, "Title");
+
+$db->exec ("select title as value from titles where title_order = 2 and fk_books = $fk_books");
+output ($db, "Alternate Title");
+
+$db->exec ("select title as value from titles where title_order = 3 and fk_books = $fk_books");
+output ($db, "Contents");
+
+$db->exec ("select note as value from notes where fk_books = $fk_books");
+output ($db, "Note");
+
+$db->exec ("select lang as value from langs, mn_books_langs " .
+ "where langs.pk = fk_langs and fk_books = $fk_books");
+output ($db, "Language");
+
+$db->exec ("select pk as value from loccs, mn_books_loccs " .
+ "where loccs.pk = fk_loccs and fk_books = $fk_books");
+output ($db, "Locc");
+
+$db->exec ("select subject as value from subjects, mn_books_subjects " .
+ "where subjects.pk = fk_subjects and fk_books = $fk_books");
+output ($db, "Subject");
+
+$db->exec ("select category as value from categories, mn_books_categories " .
+ "where categories.pk = fk_categories and fk_books = $fk_books");
+output ($db, "Category");
+
+echo ("----------\n");
+
+?>
diff --git a/catalog/admin/book-make-fileinfo.php~ b/catalog/admin/book-make-fileinfo.php~
new file mode 100644
index 0000000..08c55bd
--- /dev/null
+++ b/catalog/admin/book-make-fileinfo.php~
@@ -0,0 +1,77 @@
+FirstRow ()) {
+ do {
+ $v = $db->get ("value", SQLCHAR);
+ echo ("$caption: $v\n");
+ } while ($db->NextRow ());
+ }
+}
+
+$db = $config->db ();
+
+$db->exec ("select * from books where pk = $fk_books");
+if (!$db->FirstRow ()) {
+ exit ();
+}
+
+$release_date = $db->get ("release_date", SQLDATE);
+$copyrighted = $db->get ("copyrighted", SQLINT);
+echo ("Etext-Nr: $fk_books\n");
+echo ("Release-Date: " . date ("M d, Y\n", $release_date));
+echo ("Copyrighted: $copyrighted\n");
+
+$db->exec ("select author, role from v_books_authors " .
+ "where fk_books = $fk_books");
+if ($db->FirstRow ()) {
+ do {
+ $author = $db->get ("author", SQLCHAR);
+ $role = $db->get ("role", SQLCHAR);
+ echo ("$role: $author\n");
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select title as value from titles where title_order = 1 and fk_books = $fk_books");
+output ($db, "Title");
+
+$db->exec ("select title as value from titles where title_order = 2 and fk_books = $fk_books");
+output ($db, "Alternate Title");
+
+$db->exec ("select title as value from titles where title_order = 3 and fk_books = $fk_books");
+output ($db, "Contents");
+
+$db->exec ("select note as value from notes where fk_books = $fk_books");
+output ($db, "Note");
+
+$db->exec ("select lang as value from langs, mn_books_langs " .
+ "where langs.pk = fk_langs and fk_books = $fk_books");
+output ($db, "Language");
+
+$db->exec ("select pk as value from loccs, mn_books_loccs " .
+ "where loccs.pk = fk_loccs and fk_books = $fk_books");
+output ($db, "Locc");
+
+$db->exec ("select subject as value from subjects, mn_books_subjects " .
+ "where subjects.pk = fk_subjects and fk_books = $fk_books");
+output ($db, "Subject");
+
+$db->exec ("select category as value from categories, mn_books_categories " .
+ "where categories.pk = fk_categories and fk_books = $fk_books");
+output ($db, "Category");
+
+echo ("----------\n");
+
+?>
\ No newline at end of file
diff --git a/catalog/admin/book.php b/catalog/admin/book.php
new file mode 100644
index 0000000..4577455
--- /dev/null
+++ b/catalog/admin/book.php
@@ -0,0 +1,336 @@
+AddColumn ("$prefix=edit&pk=#pk#\">Edit",
+ "$prefix=add\">Add", "narrow");
+ $this->AddColumn ("$prefix=delete&pk=#pk#\">Delete", "", "narrow");
+
+ $this->AddSimpleColumn ("name", "MARC Tag");
+ $this->AddSimpleColumn ("indicators", "MARC Indicators", "narrow");
+ $this->AddSimpleColumn ("nonfiling", "Nonfiling Chars", "narrow");
+ $this->AddSimpleColumn ("text", "Text");
+ }
+}
+
+class ListMarcFieldsTable extends ListTable {
+ function __construct () {
+ global $fk_books, $fk_marcauthrecs;
+ $prefix = "AddColumn ("$prefix=delete&fk_marcauthrecs=#fk_marcauthrecs#&fk_marctags=#fk_marctags#\">Unlink ",
+ "", "narrow");
+ // $this->AddColumn ("$prefix=edit&fk_marcauthrecs=#fk_marcauthrecs#&fk_marctags=#fk_marctags#\">Edit Link", "", "narrow");
+
+ $this->AddSimpleColumn ("name", "MARC Tag");
+ // $this->AddSimpleColumn ("indicators", "MARC Indicators", "narrow");
+ // $this->AddSimpleColumn ("nonfiling", "Nonfiling Chars", "narrow");
+ $this->AddSimpleColumn ("text", "Text");
+ }
+}
+
+class ListAuthorsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $prefix = "AddColumn ("$prefix=delete&fk_authors=#pk#&fk_roles=#fk_roles#\">Unlink ",
+ "Link ",
+ "narrow");
+ $this->AddColumn ("$prefix=edit&fk_authors=#pk#&fk_roles=#fk_roles#\">Edit Link",
+ "", "narrow");
+ $this->AddColumn ("#author# ", "Author");
+ $this->AddSimpleColumn ("role", "Role", "narrow");
+ $this->AddSimpleColumn ("c_heading", "Heading", "narrow");
+ $this->AddSimpleColumn ("born_floor", "Born", "narrow right");
+ $this->AddSimpleColumn ("died_floor", "Died", "narrow right");
+
+ $this->AddSubCaption ("All authors for this work.");
+ }
+}
+
+class ListReviewsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $this->AddSubCaption ("All reviews for this work.");
+
+ $prefix = "AddColumn ("$prefix=edit&fk_reviews=#pk#\">Edit ",
+ "$prefix=add\">Add", "narrow");
+ $this->AddColumn ("$prefix=delete&fk_reviews=#pk#\">Delete", "", "narrow");
+
+ $this->AddSimpleColumn ("name", "Reviewer");
+ $this->AddSimpleColumn ("review", "Review");
+ }
+}
+
+class ListCategoriesTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $prefix = "AddColumn ("$prefix=delete&fk_categories=#pk#\">Unlink ",
+ "$prefix=add\">Link", "narrow");
+
+ $this->AddSimpleColumn ("category", "Category");
+
+ $this->AddSubCaption ("All categories for this work.");
+ }
+}
+
+class ListSubjectsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $prefix = "AddColumn ("$prefix=delete&fk_subjects=#pk#\">Unlink ",
+ "$prefix=add\">Link", "narrow");
+
+ $this->AddColumn ("#subject# ", "Subject");
+ //Make the subject name's clickable links to the edit & list of books page
+
+ $this->AddColumn ("#pk#", "#", "narrow");
+ //List the Internal Code #.
+
+ $this->AddSubCaption ("All subjects for this work.");
+ }
+}
+
+class ListLangsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $prefix = "AddColumn ("$prefix=delete&fk_langs=#pk#\">Unlink ",
+ "$prefix=add\">Link", "narrow");
+
+ $this->AddSimpleColumn ("lang", "Language");
+
+ $this->AddSubCaption ("Languages of all major sections in this work.");
+ }
+}
+
+class ListLoccsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $prefix = "AddColumn ("$prefix=delete&fk_loccs=#pk#\">Unlink ",
+ "$prefix=add\">Link", "narrow");
+ $this->AddSimpleColumn("pk", "Code");
+ $this->AddSimpleColumn ("locc", "LoC class");
+
+ $this->AddSubCaption ("All LoC Classes this work falls into.");
+ }
+}
+
+$db = $config->db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_books");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this book.");
+ $f->SubCaption ("Press the '$caption' button to continue or hit " .
+ "the back button on your browser to dismiss.");
+} else {
+ $f->Text ("pk", "pk", "EText Nr.", SQLINT, 20, 5, true);
+ $f->ToolTip ("Enter the ebook number.");
+ $f->Text ("release_date", "release_date", "Release Date", SQLCHAR, 20, 20, false);
+ $f->ToolTip ("Enter the official release date.");
+ $f->CheckBox ("copyrighted", "copyrighted", "Copyrighted", SQLINT);
+ $f->ToolTip ("Check if book is copyrighted.");
+ $f->CheckBox ("updatemode", "updatemode", "Manual Update", SQLINT);
+ $f->ToolTip ("Check if book is manually updated.");
+
+ $f->LoadData ("select * from books where pk = $fk_books");
+}
+$f->Hidden ("fk_books");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into books " . $sql)) {
+ msg ("Book added !");
+ } else {
+ error_msg ("Could not add Book!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ // set manually updated mode
+ if ($db->Exec ("update books set " . $sql . "where pk = $fk_books")) {
+ msg ("Book modified !");
+ } else {
+ error_msg ("Could not modify book !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->exec ("delete from files where fk_books = $fk_books");
+ $db->exec ("delete from attributes where fk_books = $fk_books");
+ $db->exec ("delete from reviews.reviews where fk_books = $fk_books");
+ $db->Exec ("delete from mn_books_authors where fk_books = $fk_books");
+ $db->Exec ("delete from mn_books_langs where fk_books = $fk_books");
+ $db->Exec ("delete from mn_books_loccs where fk_books = $fk_books");
+ $db->Exec ("delete from mn_books_subjects where fk_books = $fk_books");
+ $db->Exec ("delete from mn_books_categories where fk_books = $fk_books");
+ if ($db->Exec ("delete from books where pk = $fk_books")) {
+ msg ("Book deleted !");
+ } else {
+ error_msg ("Could not delete book !");
+ }
+}
+
+if (isupdate ()) {
+ getint ("fk_books");
+ echo (" Back to Book
\n\n");
+} else {
+ $f->Output ($caption, $caption);
+
+ if (ismode ("edit")) {
+
+ p ("Goto Edit Files Page — " .
+ "etext/${fk_books}#bibrec\">Goto Bibrec Page — " .
+ "etext/${fk_books}#download\">Goto Bibrec Download Page ");
+
+ $db->exec ("select gutindex from books where pk = $fk_books");
+ if ($db->FirstRow ()) {
+ $gutindex = $db->get ("gutindex", SQLCHAR);
+ if (!empty ($gutindex)) {
+ echo ("$gutindex \n");
+ }
+ }
+
+ // Authors for book
+ $db->exec ("select authors.pk as pk, author, heading, born_floor, died_floor, " .
+ "fk_roles, role " .
+ "from authors, mn_books_authors, roles " .
+ "where authors.pk = mn_books_authors.fk_authors " .
+ "and mn_books_authors.fk_roles = roles.pk " .
+ "and mn_books_authors.fk_books = $fk_books " .
+ "order by author;");
+ $db->calcfields ["c_heading"] = new CalcFieldHeading ();
+ $table = new ListAuthorsTable ();
+ $table->PrintTable ($db, "Authors", "pgdbdata");
+
+ p ("A Summary of Commonly Used MARC 21 Fields ");
+
+ // Uncontrolled Fields for book
+ $db->exec ("select attributes.*, attriblist.name from attributes, attriblist " .
+ "where attributes.fk_books = $fk_books and " .
+ "attributes.fk_attriblist = attriblist.pk " .
+ "order by attriblist.name;");
+ $table = new ListAttributesTable ();
+ $table->PrintTable ($db, "Uncontrolled MARC 21 Fields", "pgdbdata");
+
+ // Controlled Fields for book
+// $db->exec ("select marcfields.text, marctags.name, mn_books_marcauthrecs.* " .
+// "from mn_books_marcauthrecs, marcfields, marctags " .
+// "where mn_books_marcauthrecs.fk_books = $fk_books " .
+// "and marcfields.fk_marcauthrecs = mn_books_marcauthrecs.fk_marcauthrecs " .
+// "and marctags.pk = mn_books_marcauthrecs.fk_marctags " .
+// "and marcfields.fk_marctags like 'A1%' order by marctags.name, marcfields.text;");
+
+// $table = new ListMarcFieldsTable ();
+// $table->PrintTable ($db, "Controlled MARC 21 Fields", "pgdbdata");
+
+// $f2 = new SQLForm ("mn_books_marcauthrecs", "get");
+// $f2->KeySelect ("fk_marctags", "fk_marctags", "Tag to Link", SQLCHAR, 40, 40, true);
+// $f2->last->LoadSQL ("select pk as key, name as caption from marctags where pk like 'B%' and type IS NOT NULL and not exists (select * from mn_books_marcauthrecs as mnm, marctags as mt where mnm.fk_books = $fk_books and mnm.fk_marctags = mt.pk and mt.excludes = marctags.excludes) order by name");
+// $f2->last->DefValue ("B100");
+// $f2->last->ToolTip ("Select a Bibliographic MARC Tag.");
+// $f2->Hidden ("fk_books");
+// $f2->Hidden ("mode", "add");
+// $f2->Hidden ("step", "first");
+// $f2->Output ("Link Controlled Field", "Link Controlled Field");
+
+ // Categories for book
+ $db->exec ("select * from categories, mn_books_categories " .
+ "where categories.pk = mn_books_categories.fk_categories " .
+ "and mn_books_categories.fk_books =$fk_books " .
+ "order by category;");
+ $table = new ListCategoriesTable ();
+ $table->PrintTable ($db, "Categories", "pgdbdata");
+
+ // Subjects for book
+ $db->exec ("select * from subjects, mn_books_subjects " .
+ "where subjects.pk = mn_books_subjects.fk_subjects " .
+ "and mn_books_subjects.fk_books =$fk_books " .
+ "order by subject;");
+ $table = new ListSubjectsTable ();
+ $table->PrintTable ($db, "Subjects", "pgdbdata");
+
+ form_open ("mn_books_subjects");
+ form_hidden ("mode", "add");
+ form_hidden ("step", "update");
+ form_hidden ("fk_books", $fk_books);
+ echo ("Quick link subject: Use internal subject #!\n");
+ form_submit ("Link Subject");
+ echo ("(See \"#\" column above.)");
+ form_close ();
+
+ // Languages for book
+ $db->exec ("select langs.pk as pk, lang from langs, mn_books_langs " .
+ "where mn_books_langs.fk_langs = langs.pk " .
+ "and fk_books = $fk_books order by lang;");
+ $table = new ListLangsTable ();
+ $table->PrintTable ($db, "Languages", "pgdbdata");
+
+ form_open ("mn_books_langs");
+ form_hidden ("mode", "add");
+ form_hidden ("step", "update");
+ form_hidden ("fk_books", $fk_books);
+ echo ("Quick link language: Use 2-letter code!\n");
+ form_submit ("Link Language");
+ form_close ();
+
+ // LoCCs for book
+ $db->exec ("select loccs.pk as pk, locc from loccs, mn_books_loccs " .
+ "where mn_books_loccs.fk_loccs = loccs.pk " .
+ "and fk_books = $fk_books order by locc;");
+ $table = new ListLoccsTable ();
+ $table->PrintTable ($db, "LoC Classes", "pgdbdata");
+
+ form_open ("mn_books_loccs");
+ form_hidden ("mode", "add");
+ form_hidden ("step", "update");
+ form_hidden ("fk_books", $fk_books);
+ echo ("Quick link LoC class: Use code!\n");
+ form_submit ("Link LoC Class");
+ form_close ();
+
+ // Reviews for book
+ $db->exec ("select reviews.reviews.*, reviews.reviewers.name from reviews.reviews, reviews.reviewers where fk_books = $fk_books and reviews.reviewers.pk = reviews.reviews.fk_reviewers;");
+ $table = new ListReviewsTable ();
+ $table->PrintTable ($db, "Reviews", "pgdbdata");
+
+ }
+}
+
+pagefooter ();
+
+// Local Variables:
+// mode:php
+// coding:utf-8-unix
+// fill-column: 75
+// End:
+
+?>
diff --git a/catalog/admin/book.php~ b/catalog/admin/book.php~
new file mode 100644
index 0000000..6f4dde4
--- /dev/null
+++ b/catalog/admin/book.php~
@@ -0,0 +1,335 @@
+AddColumn ("$prefix=edit&pk=#pk#\">Edit",
+ "$prefix=add\">Add", "narrow");
+ $this->AddColumn ("$prefix=delete&pk=#pk#\">Delete", "", "narrow");
+
+ $this->AddSimpleColumn ("name", "MARC Tag");
+ $this->AddSimpleColumn ("indicators", "MARC Indicators", "narrow");
+ $this->AddSimpleColumn ("nonfiling", "Nonfiling Chars", "narrow");
+ $this->AddSimpleColumn ("text", "Text");
+ }
+}
+
+class ListMarcFieldsTable extends ListTable {
+ function __construct () {
+ global $fk_books, $fk_marcauthrecs;
+ $prefix = "AddColumn ("$prefix=delete&fk_marcauthrecs=#fk_marcauthrecs#&fk_marctags=#fk_marctags#\">Unlink ",
+ "", "narrow");
+ // $this->AddColumn ("$prefix=edit&fk_marcauthrecs=#fk_marcauthrecs#&fk_marctags=#fk_marctags#\">Edit Link", "", "narrow");
+
+ $this->AddSimpleColumn ("name", "MARC Tag");
+ // $this->AddSimpleColumn ("indicators", "MARC Indicators", "narrow");
+ // $this->AddSimpleColumn ("nonfiling", "Nonfiling Chars", "narrow");
+ $this->AddSimpleColumn ("text", "Text");
+ }
+}
+
+class ListAuthorsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $prefix = "AddColumn ("$prefix=delete&fk_authors=#pk#&fk_roles=#fk_roles#\">Unlink ",
+ "Link ",
+ "narrow");
+ $this->AddColumn ("$prefix=edit&fk_authors=#pk#&fk_roles=#fk_roles#\">Edit Link",
+ "", "narrow");
+ $this->AddColumn ("#author# ", "Author");
+ $this->AddSimpleColumn ("role", "Role", "narrow");
+ $this->AddSimpleColumn ("c_heading", "Heading", "narrow");
+ $this->AddSimpleColumn ("born_floor", "Born", "narrow right");
+ $this->AddSimpleColumn ("died_floor", "Died", "narrow right");
+
+ $this->AddSubCaption ("All authors for this work.");
+ }
+}
+
+class ListReviewsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $this->AddSubCaption ("All reviews for this work.");
+
+ $prefix = "AddColumn ("$prefix=edit&fk_reviews=#pk#\">Edit ",
+ "$prefix=add\">Add", "narrow");
+ $this->AddColumn ("$prefix=delete&fk_reviews=#pk#\">Delete", "", "narrow");
+
+ $this->AddSimpleColumn ("name", "Reviewer");
+ $this->AddSimpleColumn ("review", "Review");
+ }
+}
+
+class ListCategoriesTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $prefix = "AddColumn ("$prefix=delete&fk_categories=#pk#\">Unlink ",
+ "$prefix=add\">Link", "narrow");
+
+ $this->AddSimpleColumn ("category", "Category");
+
+ $this->AddSubCaption ("All categories for this work.");
+ }
+}
+
+class ListSubjectsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $prefix = "AddColumn ("$prefix=delete&fk_subjects=#pk#\">Unlink ",
+ "$prefix=add\">Link", "narrow");
+
+ $this->AddColumn ("#subject# ", "Subject");
+ //Make the subject name's clickable links to the edit & list of books page
+
+ $this->AddColumn ("#pk#", "#", "narrow");
+ //List the Internal Code #.
+
+ $this->AddSubCaption ("All subjects for this work.");
+ }
+}
+
+class ListLangsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $prefix = "AddColumn ("$prefix=delete&fk_langs=#pk#\">Unlink ",
+ "$prefix=add\">Link", "narrow");
+
+ $this->AddSimpleColumn ("lang", "Language");
+
+ $this->AddSubCaption ("Languages of all major sections in this work.");
+ }
+}
+
+class ListLoccsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $prefix = "AddColumn ("$prefix=delete&fk_loccs=#pk#\">Unlink ",
+ "$prefix=add\">Link", "narrow");
+ $this->AddSimpleColumn("pk", "Code");
+ $this->AddSimpleColumn ("locc", "LoC class");
+
+ $this->AddSubCaption ("All LoC Classes this work falls into.");
+ }
+}
+
+$db = $config->db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_books");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this book.");
+ $f->SubCaption ("Press the '$caption' button to continue or hit " .
+ "the back button on your browser to dismiss.");
+} else {
+ $f->Text ("pk", "pk", "EText Nr.", SQLINT, 20, 5, true);
+ $f->ToolTip ("Enter the ebook number.");
+ $f->Text ("release_date", "release_date", "Release Date", SQLCHAR, 20, 20, false);
+ $f->ToolTip ("Enter the official release date.");
+ $f->CheckBox ("copyrighted", "copyrighted", "Copyrighted", SQLINT);
+ $f->ToolTip ("Check if book is copyrighted.");
+ $f->CheckBox ("updatemode", "updatemode", "Manual Update", SQLINT);
+ $f->ToolTip ("Check if book is manually updated.");
+
+ $f->LoadData ("select * from books where pk = $fk_books");
+}
+$f->Hidden ("fk_books");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into books " . $sql)) {
+ msg ("Book added !");
+ } else {
+ error_msg ("Could not add Book!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ // set manually updated mode
+ if ($db->Exec ("update books set " . $sql . "where pk = $fk_books")) {
+ msg ("Book modified !");
+ } else {
+ error_msg ("Could not modify book !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->exec ("delete from files where fk_books = $fk_books");
+ $db->exec ("delete from attributes where fk_books = $fk_books");
+ $db->exec ("delete from reviews.reviews where fk_books = $fk_books");
+ $db->Exec ("delete from mn_books_authors where fk_books = $fk_books");
+ $db->Exec ("delete from mn_books_langs where fk_books = $fk_books");
+ $db->Exec ("delete from mn_books_loccs where fk_books = $fk_books");
+ $db->Exec ("delete from mn_books_subjects where fk_books = $fk_books");
+ $db->Exec ("delete from mn_books_categories where fk_books = $fk_books");
+ if ($db->Exec ("delete from books where pk = $fk_books")) {
+ msg ("Book deleted !");
+ } else {
+ error_msg ("Could not delete book !");
+ }
+}
+
+if (isupdate ()) {
+ getint ("fk_books");
+ echo (" Back to Book
\n\n");
+} else {
+ $f->Output ($caption, $caption);
+
+ if (ismode ("edit")) {
+
+ p ("Goto Edit Files Page — " .
+ "etext/${fk_books}#bibrec\">Goto Bibrec Page — " .
+ "etext/${fk_books}#download\">Goto Bibrec Download Page ");
+
+ $db->exec ("select gutindex from books where pk = $fk_books");
+ if ($db->FirstRow ()) {
+ $gutindex = $db->get ("gutindex", SQLCHAR);
+ if (!empty ($gutindex)) {
+ echo ("$gutindex \n");
+ }
+ }
+
+ // Authors for book
+ $db->exec ("select authors.pk as pk, author, heading, born_floor, died_floor, " .
+ "fk_roles, role " .
+ "from authors, mn_books_authors, roles " .
+ "where authors.pk = mn_books_authors.fk_authors " .
+ "and mn_books_authors.fk_roles = roles.pk " .
+ "and mn_books_authors.fk_books = $fk_books " .
+ "order by author;");
+ $db->calcfields ["c_heading"] = new CalcFieldHeading ();
+ $table = new ListAuthorsTable ();
+ $table->PrintTable ($db, "Authors", "pgdbdata");
+
+ p ("A Summary of Commonly Used MARC 21 Fields ");
+
+ // Uncontrolled Fields for book
+ $db->exec ("select attributes.*, attriblist.name from attributes, attriblist " .
+ "where attributes.fk_books = $fk_books and " .
+ "attributes.fk_attriblist = attriblist.pk " .
+ "order by attriblist.name;");
+ $table = new ListAttributesTable ();
+ $table->PrintTable ($db, "Uncontrolled MARC 21 Fields", "pgdbdata");
+
+ // Controlled Fields for book
+// $db->exec ("select marcfields.text, marctags.name, mn_books_marcauthrecs.* " .
+// "from mn_books_marcauthrecs, marcfields, marctags " .
+// "where mn_books_marcauthrecs.fk_books = $fk_books " .
+// "and marcfields.fk_marcauthrecs = mn_books_marcauthrecs.fk_marcauthrecs " .
+// "and marctags.pk = mn_books_marcauthrecs.fk_marctags " .
+// "and marcfields.fk_marctags like 'A1%' order by marctags.name, marcfields.text;");
+
+// $table = new ListMarcFieldsTable ();
+// $table->PrintTable ($db, "Controlled MARC 21 Fields", "pgdbdata");
+
+// $f2 = new SQLForm ("mn_books_marcauthrecs", "get");
+// $f2->KeySelect ("fk_marctags", "fk_marctags", "Tag to Link", SQLCHAR, 40, 40, true);
+// $f2->last->LoadSQL ("select pk as key, name as caption from marctags where pk like 'B%' and type IS NOT NULL and not exists (select * from mn_books_marcauthrecs as mnm, marctags as mt where mnm.fk_books = $fk_books and mnm.fk_marctags = mt.pk and mt.excludes = marctags.excludes) order by name");
+// $f2->last->DefValue ("B100");
+// $f2->last->ToolTip ("Select a Bibliographic MARC Tag.");
+// $f2->Hidden ("fk_books");
+// $f2->Hidden ("mode", "add");
+// $f2->Hidden ("step", "first");
+// $f2->Output ("Link Controlled Field", "Link Controlled Field");
+
+ // Categories for book
+ $db->exec ("select * from categories, mn_books_categories " .
+ "where categories.pk = mn_books_categories.fk_categories " .
+ "and mn_books_categories.fk_books =$fk_books " .
+ "order by category;");
+ $table = new ListCategoriesTable ();
+ $table->PrintTable ($db, "Categories", "pgdbdata");
+
+ // Subjects for book
+ $db->exec ("select * from subjects, mn_books_subjects " .
+ "where subjects.pk = mn_books_subjects.fk_subjects " .
+ "and mn_books_subjects.fk_books =$fk_books " .
+ "order by subject;");
+ $table = new ListSubjectsTable ();
+ $table->PrintTable ($db, "Subjects", "pgdbdata");
+
+ form_open ("mn_books_subjects");
+ form_hidden ("mode", "add");
+ form_hidden ("step", "update");
+ form_hidden ("fk_books", $fk_books);
+ echo ("Quick link subject: Use internal subject #!\n");
+ form_submit ("Link Subject");
+ echo ("(See \"#\" column above.)");
+ form_close ();
+
+ // Languages for book
+ $db->exec ("select langs.pk as pk, lang from langs, mn_books_langs " .
+ "where mn_books_langs.fk_langs = langs.pk " .
+ "and fk_books = $fk_books order by lang;");
+ $table = new ListLangsTable ();
+ $table->PrintTable ($db, "Languages", "pgdbdata");
+
+ form_open ("mn_books_langs");
+ form_hidden ("mode", "add");
+ form_hidden ("step", "update");
+ form_hidden ("fk_books", $fk_books);
+ echo ("Quick link language: Use 2-letter code!\n");
+ form_submit ("Link Language");
+ form_close ();
+
+ // LoCCs for book
+ $db->exec ("select loccs.pk as pk, locc from loccs, mn_books_loccs " .
+ "where mn_books_loccs.fk_loccs = loccs.pk " .
+ "and fk_books = $fk_books order by locc;");
+ $table = new ListLoccsTable ();
+ $table->PrintTable ($db, "LoC Classes", "pgdbdata");
+
+ form_open ("mn_books_loccs");
+ form_hidden ("mode", "add");
+ form_hidden ("step", "update");
+ form_hidden ("fk_books", $fk_books);
+ echo ("Quick link LoC class: Use code!\n");
+ form_submit ("Link LoC Class");
+ form_close ();
+
+ // Reviews for book
+ $db->exec ("select reviews.reviews.*, reviews.reviewers.name from reviews.reviews, reviews.reviewers where fk_books = $fk_books and reviews.reviewers.pk = reviews.reviews.fk_reviewers;");
+ $table = new ListReviewsTable ();
+ $table->PrintTable ($db, "Reviews", "pgdbdata");
+
+ }
+}
+
+pagefooter ();
+
+// Local Variables:
+// mode:php
+// coding:utf-8-unix
+// fill-column: 75
+// End:
+
+?>
diff --git a/catalog/admin/books_form.php b/catalog/admin/books_form.php
new file mode 100644
index 0000000..992ef8a
--- /dev/null
+++ b/catalog/admin/books_form.php
@@ -0,0 +1,47 @@
+Search a book\n");
+
+form_open ("books_list");
+?>
+
+
+
+Add a book \n");
+
+pagefooter ();
+?>
diff --git a/catalog/admin/books_form.php~ b/catalog/admin/books_form.php~
new file mode 100644
index 0000000..b371e45
--- /dev/null
+++ b/catalog/admin/books_form.php~
@@ -0,0 +1,45 @@
+Search a book\n");
+
+form_open ("books_list");
+?>
+
+
+
+Add a book \n");
+
+pagefooter ();
+?>
diff --git a/catalog/admin/books_list.php b/catalog/admin/books_list.php
new file mode 100644
index 0000000..f924182
--- /dev/null
+++ b/catalog/admin/books_list.php
@@ -0,0 +1,56 @@
+AddColumn ("Edit ",
+ "Add ", "left", "1%");
+ $this->AddColumn ("Delete ",
+ "", "left", "1%");
+ $this->AddSimpleColumn ("fk_books", "Nr.", "right", "1%");
+ $this->AddSimpleColumn ("author", "Author");
+ $this->AddSimpleColumn ("title", "Title");
+ }
+}
+
+$db = $config->db ();
+$f = $db->GetFormatter ();
+
+if (isset ($author)) {
+ $author = $f->f ("$author%", SQLCHAR);
+ $author = "and author ilike $author ";
+}
+if (isset ($title)) {
+ $title = $f->f ("%$title%", SQLCHAR);
+ $title = "and title ilike $title ";
+}
+if (isset ($nr)) {
+ $nr = $f->f ($nr, SQLINT);
+ $nr = "and fk_books = $nr ";
+}
+
+$where = substr ($author . $title . $nr, 4);
+
+if (strlen ($where)) {
+ $where = "where $where";
+
+ $db->exec ("select * from v_books $where order by author, title");
+
+ $table = new ListBooksTable ();
+ $table->PrintTable ($db, $caption);
+} else {
+ msg ("Please enter at least one search argument.");
+}
+
+pagefooter ();
+?>
diff --git a/catalog/admin/books_list.php~ b/catalog/admin/books_list.php~
new file mode 100644
index 0000000..cace8dc
--- /dev/null
+++ b/catalog/admin/books_list.php~
@@ -0,0 +1,55 @@
+AddColumn ("Edit ",
+ "Add ", "left", "1%");
+ $this->AddColumn ("Delete ",
+ "", "left", "1%");
+ $this->AddSimpleColumn ("fk_books", "Nr.", "right", "1%");
+ $this->AddSimpleColumn ("author", "Author");
+ $this->AddSimpleColumn ("title", "Title");
+ }
+}
+
+$db = $config->db ();
+$f = $db->GetFormatter ();
+
+if (isset ($author)) {
+ $author = $f->f ("$author%", SQLCHAR);
+ $author = "and author ilike $author ";
+}
+if (isset ($title)) {
+ $title = $f->f ("%$title%", SQLCHAR);
+ $title = "and title ilike $title ";
+}
+if (isset ($nr)) {
+ $nr = $f->f ($nr, SQLINT);
+ $nr = "and fk_books = $nr ";
+}
+
+$where = substr ($author . $title . $nr, 4);
+
+if (strlen ($where)) {
+ $where = "where $where";
+
+ $db->exec ("select * from v_books $where order by author, title");
+
+ $table = new ListBooksTable ();
+ $table->PrintTable ($db, $caption);
+} else {
+ msg ("Please enter at least one search argument.");
+}
+
+pagefooter ();
+?>
diff --git a/catalog/admin/cat.php b/catalog/admin/cat.php
new file mode 100644
index 0000000..b230e29
--- /dev/null
+++ b/catalog/admin/cat.php
@@ -0,0 +1,17 @@
+
diff --git a/catalog/admin/cat.php~ b/catalog/admin/cat.php~
new file mode 100644
index 0000000..8e5c6fc
--- /dev/null
+++ b/catalog/admin/cat.php~
@@ -0,0 +1,16 @@
+
diff --git a/catalog/admin/catalog-o-matic.php b/catalog/admin/catalog-o-matic.php
new file mode 100644
index 0000000..d6641f5
--- /dev/null
+++ b/catalog/admin/catalog-o-matic.php
@@ -0,0 +1,642 @@
+db ();
+
+echo ("after db () ...\n"); flush ();
+
+$db->logger = new logger ();
+
+echo ("Initializing ...\n"); flush ();
+
+$db->Exec ("select pk, lang from langs");
+if ($db->FirstRow ()) {
+ do {
+ $languages[$db->Get ("lang", SQLCHAR)] = $db->Get ("pk", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select pk, filetype from filetypes");
+if ($db->FirstRow ()) {
+ do {
+ $filetypes[$db->Get ("pk", SQLCHAR)] = $db->Get ("filetype", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select pk, compression from compressions");
+if ($db->FirstRow ()) {
+ do {
+ $compressions[$db->Get ("pk", SQLCHAR)] = $db->Get ("compression", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select pk from encodings");
+if ($db->FirstRow ()) {
+ do {
+ $encodings[$db->Get ("pk", SQLCHAR)] = 1;
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select pk, role from roles");
+if ($db->FirstRow ()) {
+ do {
+ $roles[$db->Get ("role", SQLCHAR)] = $db->get ("pk", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+$importfilename = $argv[1];
+if (empty ($importfilename))
+ $importfilename = $config->catalogupdatelog;
+
+echo ("Processing $importfilename ...\n"); flush ();
+
+$old_etext_number = -1;
+
+function guess_filetype ($filename) {
+ // guesses filetype, encoding from filename only
+ //
+ // needs following hashes:
+ // usually loaded from the same tables in the database
+ // $filetypes: 'txt' => 'Plain text'
+ // $encodings: 'us-ascii'
+ global $filetypes, $encodings;
+
+ $extension_aliases = array (
+ 'htm' => 'html',
+ 'tif' => 'tiff',
+ 'jpeg' => 'jpg',
+ 'midi' => 'mid'
+ );
+
+ $ft = $enc = null;
+ $base = $ext = "";
+ $base_after_hyphen = "";
+
+ if (preg_match ("/^(.*)\.(.*)$/", $filename, $matches)) {
+ $base = strtolower ($matches[1]);
+ $ext = strtolower ($matches[2]);
+ }
+
+ $post10k = preg_match ("/^\d{5}(-|$)/", $base);
+ if (preg_match ("/-(.*)$/", $base, $matches))
+ $base_after_hyphen = $matches[1];
+
+ // guess filetype from file extension
+ if (isset ($extension_aliases[$ext])) {
+ $ext = $extension_aliases[$ext];
+ }
+ if (isset ($filetypes[$ext])) {
+ $ft = $ext;
+ }
+
+ if (preg_match ("/[-_]index\.html?$/i", $filename)) {
+ $ft = "index";
+ }
+ if (preg_match ("/readme\.txt$/i", $filename)) {
+ $ft = "readme";
+ }
+ if (preg_match ("/license\.txt$/i", $filename)) {
+ $ft = "license";
+ }
+ if (preg_match ("/page-images/i", $filename)) {
+ $ft = "pageimages";
+ }
+
+ // guess encoding from file name
+ if ($ext == "txt") {
+ if ($post10k) {
+ switch ($base_after_hyphen) {
+ case "" : $enc = "us-ascii"; break;
+ case "8" : $enc = "iso-8859-1"; break;
+ case "0" : $enc = "utf-8"; break;
+ case "5" : $enc = "big5"; break;
+ }
+ } else {
+ $enc = "us-ascii";
+ if (preg_match ("/^8\w.+\d\da?$/", $base))
+ $enc = "iso-8859-1";
+ if (preg_match ("/^8\w.+\d\du$/", $base))
+ $enc = "utf-8";
+ }
+ }
+
+ return array ($ft, $enc);
+}
+
+function fix_encoding ($encoding) {
+ global $encodings;
+
+ $encoding_aliases = array (
+ 'ascii' => 'us-ascii',
+ 'usascii' => 'us-ascii',
+ 'iso88591' => 'iso-8859-1',
+ 'latin1' => 'iso-8859-1',
+ 'iso88592' => 'iso-8859-2',
+ 'latin2' => 'iso-8859-2',
+ 'iso88593' => 'iso-8859-3',
+ 'latin3' => 'iso-8859-3',
+ 'iso88594' => 'iso-8859-4',
+ 'latin4' => 'iso-8859-4',
+ 'iso88595' => 'iso-8859-5',
+ 'cyrillic' => 'iso-8859-5',
+ 'iso88596' => 'iso-8859-6',
+ 'arabic' => 'iso-8859-6',
+ 'iso88597' => 'iso-8859-7',
+ 'greek' => 'iso-8859-7',
+ 'iso88598' => 'iso-8859-8',
+ 'hebrew' => 'iso-8859-8',
+ 'iso88599' => 'iso-8859-9',
+ 'latin5' => 'iso-8859-9',
+ 'iso885910' => 'iso-8859-10',
+ 'latin6' => 'iso-8859-10',
+ 'iso885913' => 'iso-8859-13',
+ 'iso885914' => 'iso-8859-14',
+ 'latin8' => 'iso-8859-14',
+ 'iso885915' => 'iso-8859-15',
+ 'latin9' => 'iso-8859-15',
+ 'iso885916' => 'iso-8859-16',
+ 'latin10' => 'iso-8859-16',
+ 'utf7' => 'utf-7',
+ 'utf8' => 'utf-8',
+ 'win1250' => 'windows-1250',
+ 'win1251' => 'windows-1251',
+ 'win1252' => 'windows-1252',
+ 'win1253' => 'windows-1253',
+ 'koi8r' => 'koi8-r'
+ );
+
+ $pat[] = "/[- _=<]/"; $rep[] = "";
+ $pat[] = "/^unicode/"; $rep[] = "";
+ $pat[] = "/^windowscodepage/"; $rep[] = "win";
+ $pat[] = "/^windows/"; $rep[] = "win";
+ $pat[] = "/^codepage/"; $rep[] = "win";
+ $pat[] = "/^cp/"; $rep[] = "win";
+ $pat[] = "/^isolatin/"; $rep[] = "latin";
+
+ $encoding = strtolower ($encoding);
+ $encoding = preg_replace ($pat, $rep, $encoding);
+
+ if (isset ($encodings[$encoding])) {
+ return $encoding;
+ }
+ if (isset ($encoding_aliases[$encoding])) {
+ return $encoding_aliases[$encoding];
+ }
+
+ if (strpos ($encoding, "iso88591")) {
+ $encoding = "iso-8859-1";
+ } elseif (strpos ($encoding, "utf8")) {
+ $encoding = "utf-8";
+ } else {
+ $encoding = null;
+ // print ("#$nr: unknown encoding $enc\n");
+ }
+ return $encoding;
+}
+
+function encode_language ($l) {
+ global $languages;
+ $l = ucfirst ($l);
+
+ if (isset ($languages[$l])) {
+ return $languages[$l];
+ }
+ return null;
+}
+
+function decode_author ($whole) {
+ global $roles;
+
+ $parts = preg_split ("/ *, */", $whole);
+ $names = array ();
+ $name = "";
+ $born = null;
+ $died = null;
+ $role = "aut";
+
+ foreach ($parts as $part) {
+ if (empty ($part))
+ continue;
+ if (preg_match ("/^(\d+\??)-(\d*\??)$/", $part, $matches)) {
+ $born = "$matches[1]";
+ $died = "$matches[2]";
+ continue;
+ }
+ if (preg_match ("/^-(\d+)$/", $part, $matches)) {
+ $died = "$matches[1]";
+ continue;
+ }
+ if (isset ($roles[$part])) {
+ $role = $roles[$part];
+ continue;
+ }
+ array_push ($names, $part);
+ }
+
+ return array (join (", ", $names), $born, $died, $role);
+}
+
+function insert_author ($author, $born, $died) {
+ global $db;
+ if (empty ($author))
+ return null;
+
+ $sql_author = $db->f ($author, SQLCHAR);
+ $sql_born = $db->f ($born, SQLINT);
+ $sql_died = $db->f ($died, SQLINT);
+ $sql_author_like = $db->f ("$author%", SQLCHAR);
+
+ $pk = 0;
+ $db->exec ("select pk from authors where author ilike $sql_author_like order by pk");
+ if ($db->FirstRow ()) {
+ $pk = $db->Get ("pk", SQLINT);
+ } else {
+ // try aliases
+ $db->exec ("select fk_authors from aliases where alias ilike $sql_author_like order by fk_authors");
+ if ($db->FirstRow ()) {
+ $pk = $db->Get ("fk_authors", SQLINT);
+ }
+ }
+ if ($pk == 0) {
+ $db->exec ("insert into authors (author, born_floor, died_floor, born_ceil, died_ceil) " .
+ "values ($sql_author, $sql_born, $sql_died, $sql_born, $sql_died)");
+ $db->exec ("select pk from authors where author = $sql_author");
+ $pk = $db->Get ("pk", SQLINT);
+ echo ("Added author '$author' to database. !!!!\n");
+ }
+ return $pk;
+}
+
+function insert_title ($etext_number, $title, $marc = 245) {
+ global $db, $titles;
+ if (empty ($title))
+ return;
+
+ $nonfilings = array ('The ', 'A ', 'An ',
+ 'Der ', 'Die ', 'Das ', 'Eine ', 'Ein ',
+ 'La ', 'Le ', 'Les ', 'L\'',
+ 'El ');
+ $nonfiling = 0;
+
+ foreach ($nonfilings as $key => $value) {
+ if (preg_match ("/^$value/", $title)) {
+ $nonfiling = strlen ($value);
+ }
+ }
+
+ $title = preg_replace ("/--/", "\xE2\x80\x94", $title);
+ $title = preg_replace ("/ *_ */", "\n", $title);
+ $sql_title = $db->f ($title, SQLCHAR);
+ $sql_etext_number = $db->f ($etext_number, SQLINT);
+ $sql_marc = $db->f ($marc, SQLINT);
+ $sql_nonfiling = $db->f ($nonfiling, SQLINT);
+
+ $db->exec ("select pk from attributes where fk_books = $sql_etext_number and text = $sql_title");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into attributes (fk_books, text, nonfiling, fk_attriblist) " .
+ "values ($sql_etext_number, $sql_title, $sql_nonfiling, $sql_marc)");
+
+ echo ("Added title '$title' to book $etext_number\n");
+ }
+}
+
+function capture ($tok, $e) {
+ $matches = array ();
+ if (preg_match ("/^$tok: (.*)$/im", $e, $matches))
+ return $matches[1];
+ return null;
+}
+
+function process_section ($e) {
+ global $db, $filetypes, $compressions, $encodings, $roles, $old_etext_number;
+ $etext_number = $pk_author = null;
+ $cnt_authors = $updatemode = 0;
+ $got_title = 0;
+
+ // try to read etext_number from inputfile
+ $etext_number = capture ("Etext-Nr", $e);
+ if (empty ($etext_number)) {
+ // no etext_number ?
+ // try to compute etext_number from directory
+ $directory = capture ("directory", $e);
+ if (preg_match ("/^(?:\d\/)+(\d{2,5})/", $directory, $matches)) {
+ $etext_number = intval ($matches[1]);
+ // double-check this
+ $dir = etext2dir ($etext_number);
+ if (strncmp ("$directory/", $dir, strlen ($dir)))
+ $etext_number = null;
+ } elseif (preg_match ("/^([1-9])$/", $directory, $matches)) {
+ $etext_number = intval ($matches[1]);
+ }
+ }
+
+ if ($etext_number != $old_etext_number) {
+ echo ("----------\n\n");
+ $old_etext_number = $etext_number;
+ }
+
+ // insert file into files table
+ if ($filename = capture ("filename", $e)) {
+ $matches = array ();
+
+ $directory = capture ("directory", $e);
+ $mtime = capture ("mtime", $e);
+ $size = capture ("size", $e);
+ $edition = capture ("edition", $e);
+ $filetype = capture ("filetype", $e);
+ $obsoleted = capture ("obsoleted", $e);
+ $encoding = fix_encoding (capture ("encoding", $e));
+ $zipmember = capture ("Zipmemberfilename", $e);
+
+ /*
+ $md5hash = @pack ("H*", capture ("md5.hex", $e));
+ $sha1hash = @pack ("H*", capture ("sha1.hex", $e));
+ $kzhash = @pack ("H*", capture ("kzhash.hex", $e));
+ $ed2khash = @pack ("H*", capture ("ed2khash.hex", $e));
+ $tigertreehash = @pack ("H*", capture ("tigertree.hex", $e));
+ */
+
+ $md5hash = capture ("md5.hex", $e);
+ $sha1hash = capture ("sha1.hex", $e);
+ $kzhash = capture ("kzhash.hex", $e);
+ $ed2khash = capture ("ed2khash.hex", $e);
+ $tigertreehash = capture ("tigertree.hex", $e);
+
+ // filetype and encoding
+ list ($fk_filetypes, $fk_encodings) =
+ guess_filetype (empty ($zipmember) ? $filename : $zipmember);
+
+ // the encoding is better taken from the file, if present
+ if (isset ($encodings[$encoding])) {
+ $fk_encodings = $encoding;
+ }
+
+ // the filetype is better taken from the file, if present (not used for now)
+ // if (!empty ($filetype) && isset ($filetypes[$filetype])) {
+ // $fk_filetypes = $filetype;
+ // }
+
+ // compression
+ $fk_compressions = 'none';
+ if (preg_match ("/^(.*)\.(.*)$/", $filename, $matches)) {
+ if (isset ($compressions[strtolower ($matches[2])])) {
+ $fk_compressions = strtolower ($matches[2]);
+ }
+ }
+
+ // obsoleted
+ if (preg_match ("/\/old(\/|$)/", $directory)) {
+ $obsoleted = 1;
+ }
+
+ $diskstatus = 0;
+
+ // hide image files
+ if (strpos ($directory, "/$etext_number-")) {
+ if (in_array ($fk_filetypes, array ("jpg", "png", "gif", "svg", "css", "xsl")))
+ $diskstatus = 1;
+ if (preg_match ("/\/images(\/|$)/", $directory))
+ $diskstatus = 1;
+ if (preg_match ("/-h\/files(\/|$)/", $directory))
+ $diskstatus = 1;
+ }
+
+ $sql_diskstatus = $db->f ($diskstatus, SQLINT);
+ $sql_fk_filetypes = $db->f ($fk_filetypes, SQLCHAR);
+ $sql_fk_compressions = $db->f ($fk_compressions, SQLCHAR);
+ $sql_fk_encodings = $db->f ($fk_encodings, SQLCHAR);
+ $sql_mtime = $db->f ($mtime, SQLDATE);
+ $sql_size = $db->f ($size, SQLINT);
+ $sql_edition = $db->f ($edition, SQLINT);
+ $sql_obsoleted = $db->f ($obsoleted, SQLINT);
+ $sql_etext_number = $db->f ($etext_number, SQLINT);
+ $sql_filename = $db->f ("$directory/$filename", SQLCHAR);
+ $sql_md5hash = $db->f ($md5hash, SQLBYTE);
+ $sql_sha1hash = $db->f ($sha1hash, SQLBYTE);
+ $sql_kzhash = $db->f ($kzhash, SQLBYTE);
+ $sql_ed2khash = $db->f ($ed2khash, SQLBYTE);
+ $sql_tigertreehash = $db->f ($tigertreehash, SQLBYTE);
+
+ $fields =
+ (empty ($etext_number) ? "" : "fk_books = $sql_etext_number, ") .
+ (empty ($fk_filetypes) ? "" : "fk_filetypes = $sql_fk_filetypes, ") .
+ (empty ($fk_encodings) ? "" : "fk_encodings = $sql_fk_encodings, ") .
+ (empty ($fk_compressions) ? "" : "fk_compressions = $sql_fk_compressions, ") .
+ (empty ($md5hash) ? "" : "md5hash = $sql_md5hash, ") .
+ (empty ($sha1hash) ? "" : "sha1hash = $sql_sha1hash, ") .
+ (empty ($kzhash) ? "" : "kzhash = $sql_kzhash, ") .
+ (empty ($ed2khash) ? "" : "ed2khash = $sql_ed2khash, ") .
+ (empty ($tigertreehash) ? "" : "tigertreehash = $sql_tigertreehash, ") .
+ (empty ($edition) ? "" : "edition = $sql_edition, ") .
+ (empty ($obsoleted) ? "" : "obsoleted = $sql_obsoleted, ") .
+ (empty ($size) ? "" : "filesize = $sql_size, ") .
+ (empty ($mtime) ? "" : "filemtime = $sql_mtime, ") .
+ "diskstatus = $sql_diskstatus";
+
+ // $fields = rtrim ($fields, ", ");
+
+ $db->BeginTrans ();
+
+ $db->exec ("select pk from files where filename = $sql_filename");
+ $newfile = !$db->FirstRow ();
+
+ if ($newfile) {
+ $db->exec ("insert into files (filename, diskstatus) values ($sql_filename, 0);");
+ }
+
+ $db->exec ("update files set $fields where filename = $sql_filename");
+
+ $db->Commit ();
+
+ echo (($newfile ? "Added" : "Updated") . " file $directory/$filename " .
+ "($sql_etext_number $sql_fk_filetypes $sql_fk_compressions $sql_fk_encodings $sql_diskstatus $sql_obsoleted)\n");
+ }
+
+ // maybe insert book into books table
+ if (!empty ($etext_number)) {
+ $db->BeginTrans ();
+
+ $sql_etext_number = $db->f ($etext_number, SQLINT);
+ $db->exec ("select * from books where pk = $sql_etext_number");
+
+ if ($db->FirstRow ()) {
+ $updatemode = $db->get ("updatemode", SQLINT); // 0 = auto, 1 = manual
+ } else {
+ $db->exec ("insert into books (pk) values ($sql_etext_number)");
+ echo ("Inserted book $etext_number into database\n");
+ }
+
+ if ($updatemode == 0) {
+ if ($fk_encodings != "utf-8") {
+ iconv_set_encoding ("internal_encoding", "UTF-8");
+ $converted = iconv (strtoupper ($fk_encodings), "UTF-8", $e);
+ if ($converted !== FALSE) {
+ $e = $converted;
+ }
+ }
+ $lines = preg_split ("/\n/", $e);
+ foreach ($lines as $line) {
+ if (empty ($line)) continue;
+ if (!preg_match ("/^(.*?):\s+(.*)$/", $line, $matches))
+ continue;
+ list ($dummy, $key, $value) = $matches; // preg_split ("/:\s+/", $line); //FIXME
+ if (empty ($value)) continue;
+
+ if (isset ($roles[$key])) {
+ list ($author, $born, $died, $role) = decode_author ($value);
+ $pk_author = insert_author ($author, $born, $died);
+ if ($key != "Author") {
+ $role = $roles[$key];
+ }
+ if ($pk_author) {
+ $sql_fk_authors = $db->f ($pk_author, SQLINT);
+ $sql_fk_roles = $db->f ($role, SQLCHAR);
+ $db->exec ("select * from mn_books_authors " .
+ "where fk_books = $sql_etext_number and fk_authors = $sql_fk_authors " .
+ "and fk_roles = $sql_fk_roles");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into mn_books_authors (fk_books, fk_authors, fk_roles) " .
+ "values ($sql_etext_number, $sql_fk_authors, $sql_fk_roles)");
+ echo ("Added author '$author' role $role to book $etext_number\n");
+ }
+ }
+ $cnt_authors++;
+ continue;
+ }
+ if ($key == "Title") {
+ insert_title ($etext_number, $value, 245);
+ $got_title = 1;
+ continue;
+ }
+ if ($key == "Alternate Title") {
+ insert_title ($etext_number, $value, 246);
+ continue;
+ }
+ if ($key == "Contents") {
+ insert_title ($etext_number, $value, 505);
+ continue;
+ }
+ if ($key == "Language") {
+ $lang = encode_language ($value);
+ if (!empty ($lang)) {
+ $sql_lang = $db->f ($lang, SQLCHAR);
+ $db->exec ("select * from mn_books_langs " .
+ "where fk_books = $sql_etext_number and fk_langs = $sql_lang");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into mn_books_langs (fk_books, fk_langs) " .
+ "values ($sql_etext_number, $sql_lang)");
+ }
+ }
+ continue;
+ }
+ if ($key == "Locc") {
+ $sql_locc = $db->f (strtoupper ($value), SQLCHAR);
+ $db->exec ("select * from mn_books_loccs " .
+ "where fk_books = $sql_etext_number and fk_loccs = $sql_locc");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into mn_books_loccs (fk_books, fk_loccs) " .
+ "values ($sql_etext_number, $sql_locc)");
+ }
+ continue;
+ }
+ if ($key == "Subject") {
+ $sql_subject = $db->f ($value, SQLCHAR);
+ $db->exec ("select pk from subjects where subject = $sql_subject");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into subjects (subject) values ($sql_subject)");
+ $db->exec ("select pk from subjects where subject = $sql_subject");
+ }
+ $pk_subjects = $db->Get ("pk", SQLINT);
+ $sql_fk_subjects = $db->f ($pk_subjects, SQLINT);
+
+ $db->exec ("select * from mn_books_subjects " .
+ "where fk_books = $sql_etext_number and fk_subjects = $sql_fk_subjects");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into mn_books_subjects (fk_books, fk_subjects) " .
+ "values ($sql_etext_number, $sql_fk_subjects)");
+ }
+ continue;
+ }
+ if ($key == "Note") {
+ $sql_note = $db->f ($value, SQLCHAR);
+ $db->exec ("select * from attributes " .
+ "where fk_books = $sql_etext_number and text = $sql_note");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into attributes (fk_books, fk_attriblist, text) values ($sql_etext_number, 500, $sql_note)");
+ }
+ continue;
+ }
+ if ($key == "Copyright") {
+ $sql_copyrighted = $db->f ($value, SQLINT);
+ $db->exec ("update books set copyrighted = $sql_copyrighted where pk = $sql_etext_number");
+ continue;
+ }
+ if ($key == "Category") {
+ $sql_category = $db->f ($value, SQLCHAR);
+ $db->exec ("select pk from categories where category = $sql_category");
+ if ($db->FirstRow ()) {
+ $fk_categories = $db->get ("pk", SQLINT);
+ $sql_fk_categories = $db->f ($fk_categories, SQLINT);
+
+ $db->exec ("select * from mn_books_categories " .
+ "where fk_books = $sql_etext_number and fk_categories = $sql_fk_categories");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into mn_books_categories (fk_books, fk_categories) " .
+ "values ($sql_etext_number, $fk_categories)");
+ }
+ }
+ continue;
+ }
+ if ($key == "Release-Date") {
+ if (strpos ($value, ',') === false) {
+ $vale = "1 $value";
+ }
+ $release_date = strtotime ("$value");
+ $sql_release_date = $db->f ($release_date, SQLDATE);
+ $db->exec ("update books set release_date = $sql_release_date where pk = $sql_etext_number");
+ continue;
+ }
+ }
+
+ // hack! makefiles.pl sorts filenames so that 8-bit ones come first
+ // this way we prefer titles etc. from 8-bit files over html and 7-bit files
+ if ($got_title) {
+ $db->exec ("update books set updatemode = 1 where pk = $sql_etext_number");
+ }
+
+ $db->Commit ();
+ }
+ }
+}
+
+register_shutdown_function ('rollback_transaction');
+set_time_limit (0);
+
+$buffer = "";
+if ($hd = fopen ($importfilename, "r")) {
+ while (!feof ($hd)) {
+ $line = fgets ($hd);
+ if (preg_match ("/^---*[\r\n]*$/", $line)) {
+ process_section ($buffer);
+ $buffer = "";
+ echo ("\n"); flush ();
+ } else {
+ $buffer .= $line;
+ }
+ }
+ process_section ($buffer);
+ fclose ($hd);
+}
+
+?>
diff --git a/catalog/admin/catalog-o-matic.php~ b/catalog/admin/catalog-o-matic.php~
new file mode 100644
index 0000000..0e055cc
--- /dev/null
+++ b/catalog/admin/catalog-o-matic.php~
@@ -0,0 +1,641 @@
+db ();
+
+echo ("after db () ...\n"); flush ();
+
+$db->logger = new logger ();
+
+echo ("Initializing ...\n"); flush ();
+
+$db->Exec ("select pk, lang from langs");
+if ($db->FirstRow ()) {
+ do {
+ $languages[$db->Get ("lang", SQLCHAR)] = $db->Get ("pk", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select pk, filetype from filetypes");
+if ($db->FirstRow ()) {
+ do {
+ $filetypes[$db->Get ("pk", SQLCHAR)] = $db->Get ("filetype", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select pk, compression from compressions");
+if ($db->FirstRow ()) {
+ do {
+ $compressions[$db->Get ("pk", SQLCHAR)] = $db->Get ("compression", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select pk from encodings");
+if ($db->FirstRow ()) {
+ do {
+ $encodings[$db->Get ("pk", SQLCHAR)] = 1;
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select pk, role from roles");
+if ($db->FirstRow ()) {
+ do {
+ $roles[$db->Get ("role", SQLCHAR)] = $db->get ("pk", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+$importfilename = $argv[1];
+if (empty ($importfilename))
+ $importfilename = $config->catalogupdatelog;
+
+echo ("Processing $importfilename ...\n"); flush ();
+
+$old_etext_number = -1;
+
+function guess_filetype ($filename) {
+ // guesses filetype, encoding from filename only
+ //
+ // needs following hashes:
+ // usually loaded from the same tables in the database
+ // $filetypes: 'txt' => 'Plain text'
+ // $encodings: 'us-ascii'
+ global $filetypes, $encodings;
+
+ $extension_aliases = array (
+ 'htm' => 'html',
+ 'tif' => 'tiff',
+ 'jpeg' => 'jpg',
+ 'midi' => 'mid'
+ );
+
+ $ft = $enc = null;
+ $base = $ext = "";
+ $base_after_hyphen = "";
+
+ if (preg_match ("/^(.*)\.(.*)$/", $filename, $matches)) {
+ $base = strtolower ($matches[1]);
+ $ext = strtolower ($matches[2]);
+ }
+
+ $post10k = preg_match ("/^\d{5}(-|$)/", $base);
+ if (preg_match ("/-(.*)$/", $base, $matches))
+ $base_after_hyphen = $matches[1];
+
+ // guess filetype from file extension
+ if (isset ($extension_aliases[$ext])) {
+ $ext = $extension_aliases[$ext];
+ }
+ if (isset ($filetypes[$ext])) {
+ $ft = $ext;
+ }
+
+ if (preg_match ("/[-_]index\.html?$/i", $filename)) {
+ $ft = "index";
+ }
+ if (preg_match ("/readme\.txt$/i", $filename)) {
+ $ft = "readme";
+ }
+ if (preg_match ("/license\.txt$/i", $filename)) {
+ $ft = "license";
+ }
+ if (preg_match ("/page-images/i", $filename)) {
+ $ft = "pageimages";
+ }
+
+ // guess encoding from file name
+ if ($ext == "txt") {
+ if ($post10k) {
+ switch ($base_after_hyphen) {
+ case "" : $enc = "us-ascii"; break;
+ case "8" : $enc = "iso-8859-1"; break;
+ case "0" : $enc = "utf-8"; break;
+ case "5" : $enc = "big5"; break;
+ }
+ } else {
+ $enc = "us-ascii";
+ if (preg_match ("/^8\w.+\d\da?$/", $base))
+ $enc = "iso-8859-1";
+ if (preg_match ("/^8\w.+\d\du$/", $base))
+ $enc = "utf-8";
+ }
+ }
+
+ return array ($ft, $enc);
+}
+
+function fix_encoding ($encoding) {
+ global $encodings;
+
+ $encoding_aliases = array (
+ 'ascii' => 'us-ascii',
+ 'usascii' => 'us-ascii',
+ 'iso88591' => 'iso-8859-1',
+ 'latin1' => 'iso-8859-1',
+ 'iso88592' => 'iso-8859-2',
+ 'latin2' => 'iso-8859-2',
+ 'iso88593' => 'iso-8859-3',
+ 'latin3' => 'iso-8859-3',
+ 'iso88594' => 'iso-8859-4',
+ 'latin4' => 'iso-8859-4',
+ 'iso88595' => 'iso-8859-5',
+ 'cyrillic' => 'iso-8859-5',
+ 'iso88596' => 'iso-8859-6',
+ 'arabic' => 'iso-8859-6',
+ 'iso88597' => 'iso-8859-7',
+ 'greek' => 'iso-8859-7',
+ 'iso88598' => 'iso-8859-8',
+ 'hebrew' => 'iso-8859-8',
+ 'iso88599' => 'iso-8859-9',
+ 'latin5' => 'iso-8859-9',
+ 'iso885910' => 'iso-8859-10',
+ 'latin6' => 'iso-8859-10',
+ 'iso885913' => 'iso-8859-13',
+ 'iso885914' => 'iso-8859-14',
+ 'latin8' => 'iso-8859-14',
+ 'iso885915' => 'iso-8859-15',
+ 'latin9' => 'iso-8859-15',
+ 'iso885916' => 'iso-8859-16',
+ 'latin10' => 'iso-8859-16',
+ 'utf7' => 'utf-7',
+ 'utf8' => 'utf-8',
+ 'win1250' => 'windows-1250',
+ 'win1251' => 'windows-1251',
+ 'win1252' => 'windows-1252',
+ 'win1253' => 'windows-1253',
+ 'koi8r' => 'koi8-r'
+ );
+
+ $pat[] = "/[- _=<]/"; $rep[] = "";
+ $pat[] = "/^unicode/"; $rep[] = "";
+ $pat[] = "/^windowscodepage/"; $rep[] = "win";
+ $pat[] = "/^windows/"; $rep[] = "win";
+ $pat[] = "/^codepage/"; $rep[] = "win";
+ $pat[] = "/^cp/"; $rep[] = "win";
+ $pat[] = "/^isolatin/"; $rep[] = "latin";
+
+ $encoding = strtolower ($encoding);
+ $encoding = preg_replace ($pat, $rep, $encoding);
+
+ if (isset ($encodings[$encoding])) {
+ return $encoding;
+ }
+ if (isset ($encoding_aliases[$encoding])) {
+ return $encoding_aliases[$encoding];
+ }
+
+ if (strpos ($encoding, "iso88591")) {
+ $encoding = "iso-8859-1";
+ } elseif (strpos ($encoding, "utf8")) {
+ $encoding = "utf-8";
+ } else {
+ $encoding = null;
+ // print ("#$nr: unknown encoding $enc\n");
+ }
+ return $encoding;
+}
+
+function encode_language ($l) {
+ global $languages;
+ $l = ucfirst ($l);
+
+ if (isset ($languages[$l])) {
+ return $languages[$l];
+ }
+ return null;
+}
+
+function decode_author ($whole) {
+ global $roles;
+
+ $parts = preg_split ("/ *, */", $whole);
+ $names = array ();
+ $name = "";
+ $born = null;
+ $died = null;
+ $role = "aut";
+
+ foreach ($parts as $part) {
+ if (empty ($part))
+ continue;
+ if (preg_match ("/^(\d+\??)-(\d*\??)$/", $part, $matches)) {
+ $born = "$matches[1]";
+ $died = "$matches[2]";
+ continue;
+ }
+ if (preg_match ("/^-(\d+)$/", $part, $matches)) {
+ $died = "$matches[1]";
+ continue;
+ }
+ if (isset ($roles[$part])) {
+ $role = $roles[$part];
+ continue;
+ }
+ array_push ($names, $part);
+ }
+
+ return array (join (", ", $names), $born, $died, $role);
+}
+
+function insert_author ($author, $born, $died) {
+ global $db;
+ if (empty ($author))
+ return null;
+
+ $sql_author = $db->f ($author, SQLCHAR);
+ $sql_born = $db->f ($born, SQLINT);
+ $sql_died = $db->f ($died, SQLINT);
+ $sql_author_like = $db->f ("$author%", SQLCHAR);
+
+ $pk = 0;
+ $db->exec ("select pk from authors where author ilike $sql_author_like order by pk");
+ if ($db->FirstRow ()) {
+ $pk = $db->Get ("pk", SQLINT);
+ } else {
+ // try aliases
+ $db->exec ("select fk_authors from aliases where alias ilike $sql_author_like order by fk_authors");
+ if ($db->FirstRow ()) {
+ $pk = $db->Get ("fk_authors", SQLINT);
+ }
+ }
+ if ($pk == 0) {
+ $db->exec ("insert into authors (author, born_floor, died_floor, born_ceil, died_ceil) " .
+ "values ($sql_author, $sql_born, $sql_died, $sql_born, $sql_died)");
+ $db->exec ("select pk from authors where author = $sql_author");
+ $pk = $db->Get ("pk", SQLINT);
+ echo ("Added author '$author' to database. !!!!\n");
+ }
+ return $pk;
+}
+
+function insert_title ($etext_number, $title, $marc = 245) {
+ global $db, $titles;
+ if (empty ($title))
+ return;
+
+ $nonfilings = array ('The ', 'A ', 'An ',
+ 'Der ', 'Die ', 'Das ', 'Eine ', 'Ein ',
+ 'La ', 'Le ', 'Les ', 'L\'',
+ 'El ');
+ $nonfiling = 0;
+
+ foreach ($nonfilings as $key => $value) {
+ if (preg_match ("/^$value/", $title)) {
+ $nonfiling = strlen ($value);
+ }
+ }
+
+ $title = preg_replace ("/--/", "\xE2\x80\x94", $title);
+ $title = preg_replace ("/ *_ */", "\n", $title);
+ $sql_title = $db->f ($title, SQLCHAR);
+ $sql_etext_number = $db->f ($etext_number, SQLINT);
+ $sql_marc = $db->f ($marc, SQLINT);
+ $sql_nonfiling = $db->f ($nonfiling, SQLINT);
+
+ $db->exec ("select pk from attributes where fk_books = $sql_etext_number and text = $sql_title");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into attributes (fk_books, text, nonfiling, fk_attriblist) " .
+ "values ($sql_etext_number, $sql_title, $sql_nonfiling, $sql_marc)");
+
+ echo ("Added title '$title' to book $etext_number\n");
+ }
+}
+
+function capture ($tok, $e) {
+ $matches = array ();
+ if (preg_match ("/^$tok: (.*)$/im", $e, $matches))
+ return $matches[1];
+ return null;
+}
+
+function process_section ($e) {
+ global $db, $filetypes, $compressions, $encodings, $roles, $old_etext_number;
+ $etext_number = $pk_author = null;
+ $cnt_authors = $updatemode = 0;
+ $got_title = 0;
+
+ // try to read etext_number from inputfile
+ $etext_number = capture ("Etext-Nr", $e);
+ if (empty ($etext_number)) {
+ // no etext_number ?
+ // try to compute etext_number from directory
+ $directory = capture ("directory", $e);
+ if (preg_match ("/^(?:\d\/)+(\d{2,5})/", $directory, $matches)) {
+ $etext_number = intval ($matches[1]);
+ // double-check this
+ $dir = etext2dir ($etext_number);
+ if (strncmp ("$directory/", $dir, strlen ($dir)))
+ $etext_number = null;
+ } elseif (preg_match ("/^([1-9])$/", $directory, $matches)) {
+ $etext_number = intval ($matches[1]);
+ }
+ }
+
+ if ($etext_number != $old_etext_number) {
+ echo ("----------\n\n");
+ $old_etext_number = $etext_number;
+ }
+
+ // insert file into files table
+ if ($filename = capture ("filename", $e)) {
+ $matches = array ();
+
+ $directory = capture ("directory", $e);
+ $mtime = capture ("mtime", $e);
+ $size = capture ("size", $e);
+ $edition = capture ("edition", $e);
+ $filetype = capture ("filetype", $e);
+ $obsoleted = capture ("obsoleted", $e);
+ $encoding = fix_encoding (capture ("encoding", $e));
+ $zipmember = capture ("Zipmemberfilename", $e);
+
+ /*
+ $md5hash = @pack ("H*", capture ("md5.hex", $e));
+ $sha1hash = @pack ("H*", capture ("sha1.hex", $e));
+ $kzhash = @pack ("H*", capture ("kzhash.hex", $e));
+ $ed2khash = @pack ("H*", capture ("ed2khash.hex", $e));
+ $tigertreehash = @pack ("H*", capture ("tigertree.hex", $e));
+ */
+
+ $md5hash = capture ("md5.hex", $e);
+ $sha1hash = capture ("sha1.hex", $e);
+ $kzhash = capture ("kzhash.hex", $e);
+ $ed2khash = capture ("ed2khash.hex", $e);
+ $tigertreehash = capture ("tigertree.hex", $e);
+
+ // filetype and encoding
+ list ($fk_filetypes, $fk_encodings) =
+ guess_filetype (empty ($zipmember) ? $filename : $zipmember);
+
+ // the encoding is better taken from the file, if present
+ if (isset ($encodings[$encoding])) {
+ $fk_encodings = $encoding;
+ }
+
+ // the filetype is better taken from the file, if present (not used for now)
+ // if (!empty ($filetype) && isset ($filetypes[$filetype])) {
+ // $fk_filetypes = $filetype;
+ // }
+
+ // compression
+ $fk_compressions = 'none';
+ if (preg_match ("/^(.*)\.(.*)$/", $filename, $matches)) {
+ if (isset ($compressions[strtolower ($matches[2])])) {
+ $fk_compressions = strtolower ($matches[2]);
+ }
+ }
+
+ // obsoleted
+ if (preg_match ("/\/old(\/|$)/", $directory)) {
+ $obsoleted = 1;
+ }
+
+ $diskstatus = 0;
+
+ // hide image files
+ if (strpos ($directory, "/$etext_number-")) {
+ if (in_array ($fk_filetypes, array ("jpg", "png", "gif", "svg", "css", "xsl")))
+ $diskstatus = 1;
+ if (preg_match ("/\/images(\/|$)/", $directory))
+ $diskstatus = 1;
+ if (preg_match ("/-h\/files(\/|$)/", $directory))
+ $diskstatus = 1;
+ }
+
+ $sql_diskstatus = $db->f ($diskstatus, SQLINT);
+ $sql_fk_filetypes = $db->f ($fk_filetypes, SQLCHAR);
+ $sql_fk_compressions = $db->f ($fk_compressions, SQLCHAR);
+ $sql_fk_encodings = $db->f ($fk_encodings, SQLCHAR);
+ $sql_mtime = $db->f ($mtime, SQLDATE);
+ $sql_size = $db->f ($size, SQLINT);
+ $sql_edition = $db->f ($edition, SQLINT);
+ $sql_obsoleted = $db->f ($obsoleted, SQLINT);
+ $sql_etext_number = $db->f ($etext_number, SQLINT);
+ $sql_filename = $db->f ("$directory/$filename", SQLCHAR);
+ $sql_md5hash = $db->f ($md5hash, SQLBYTE);
+ $sql_sha1hash = $db->f ($sha1hash, SQLBYTE);
+ $sql_kzhash = $db->f ($kzhash, SQLBYTE);
+ $sql_ed2khash = $db->f ($ed2khash, SQLBYTE);
+ $sql_tigertreehash = $db->f ($tigertreehash, SQLBYTE);
+
+ $fields =
+ (empty ($etext_number) ? "" : "fk_books = $sql_etext_number, ") .
+ (empty ($fk_filetypes) ? "" : "fk_filetypes = $sql_fk_filetypes, ") .
+ (empty ($fk_encodings) ? "" : "fk_encodings = $sql_fk_encodings, ") .
+ (empty ($fk_compressions) ? "" : "fk_compressions = $sql_fk_compressions, ") .
+ (empty ($md5hash) ? "" : "md5hash = $sql_md5hash, ") .
+ (empty ($sha1hash) ? "" : "sha1hash = $sql_sha1hash, ") .
+ (empty ($kzhash) ? "" : "kzhash = $sql_kzhash, ") .
+ (empty ($ed2khash) ? "" : "ed2khash = $sql_ed2khash, ") .
+ (empty ($tigertreehash) ? "" : "tigertreehash = $sql_tigertreehash, ") .
+ (empty ($edition) ? "" : "edition = $sql_edition, ") .
+ (empty ($obsoleted) ? "" : "obsoleted = $sql_obsoleted, ") .
+ (empty ($size) ? "" : "filesize = $sql_size, ") .
+ (empty ($mtime) ? "" : "filemtime = $sql_mtime, ") .
+ "diskstatus = $sql_diskstatus";
+
+ // $fields = rtrim ($fields, ", ");
+
+ $db->BeginTrans ();
+
+ $db->exec ("select pk from files where filename = $sql_filename");
+ $newfile = !$db->FirstRow ();
+
+ if ($newfile) {
+ $db->exec ("insert into files (filename, diskstatus) values ($sql_filename, 0);");
+ }
+
+ $db->exec ("update files set $fields where filename = $sql_filename");
+
+ $db->Commit ();
+
+ echo (($newfile ? "Added" : "Updated") . " file $directory/$filename " .
+ "($sql_etext_number $sql_fk_filetypes $sql_fk_compressions $sql_fk_encodings $sql_diskstatus $sql_obsoleted)\n");
+ }
+
+ // maybe insert book into books table
+ if (!empty ($etext_number)) {
+ $db->BeginTrans ();
+
+ $sql_etext_number = $db->f ($etext_number, SQLINT);
+ $db->exec ("select * from books where pk = $sql_etext_number");
+
+ if ($db->FirstRow ()) {
+ $updatemode = $db->get ("updatemode", SQLINT); // 0 = auto, 1 = manual
+ } else {
+ $db->exec ("insert into books (pk) values ($sql_etext_number)");
+ echo ("Inserted book $etext_number into database\n");
+ }
+
+ if ($updatemode == 0) {
+ if ($fk_encodings != "utf-8") {
+ iconv_set_encoding ("internal_encoding", "UTF-8");
+ $converted = iconv (strtoupper ($fk_encodings), "UTF-8", $e);
+ if ($converted !== FALSE) {
+ $e = $converted;
+ }
+ }
+ $lines = preg_split ("/\n/", $e);
+ foreach ($lines as $line) {
+ if (empty ($line)) continue;
+ if (!preg_match ("/^(.*?):\s+(.*)$/", $line, $matches))
+ continue;
+ list ($dummy, $key, $value) = $matches; // preg_split ("/:\s+/", $line); //FIXME
+ if (empty ($value)) continue;
+
+ if (isset ($roles[$key])) {
+ list ($author, $born, $died, $role) = decode_author ($value);
+ $pk_author = insert_author ($author, $born, $died);
+ if ($key != "Author") {
+ $role = $roles[$key];
+ }
+ if ($pk_author) {
+ $sql_fk_authors = $db->f ($pk_author, SQLINT);
+ $sql_fk_roles = $db->f ($role, SQLCHAR);
+ $db->exec ("select * from mn_books_authors " .
+ "where fk_books = $sql_etext_number and fk_authors = $sql_fk_authors " .
+ "and fk_roles = $sql_fk_roles");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into mn_books_authors (fk_books, fk_authors, fk_roles) " .
+ "values ($sql_etext_number, $sql_fk_authors, $sql_fk_roles)");
+ echo ("Added author '$author' role $role to book $etext_number\n");
+ }
+ }
+ $cnt_authors++;
+ continue;
+ }
+ if ($key == "Title") {
+ insert_title ($etext_number, $value, 245);
+ $got_title = 1;
+ continue;
+ }
+ if ($key == "Alternate Title") {
+ insert_title ($etext_number, $value, 246);
+ continue;
+ }
+ if ($key == "Contents") {
+ insert_title ($etext_number, $value, 505);
+ continue;
+ }
+ if ($key == "Language") {
+ $lang = encode_language ($value);
+ if (!empty ($lang)) {
+ $sql_lang = $db->f ($lang, SQLCHAR);
+ $db->exec ("select * from mn_books_langs " .
+ "where fk_books = $sql_etext_number and fk_langs = $sql_lang");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into mn_books_langs (fk_books, fk_langs) " .
+ "values ($sql_etext_number, $sql_lang)");
+ }
+ }
+ continue;
+ }
+ if ($key == "Locc") {
+ $sql_locc = $db->f (strtoupper ($value), SQLCHAR);
+ $db->exec ("select * from mn_books_loccs " .
+ "where fk_books = $sql_etext_number and fk_loccs = $sql_locc");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into mn_books_loccs (fk_books, fk_loccs) " .
+ "values ($sql_etext_number, $sql_locc)");
+ }
+ continue;
+ }
+ if ($key == "Subject") {
+ $sql_subject = $db->f ($value, SQLCHAR);
+ $db->exec ("select pk from subjects where subject = $sql_subject");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into subjects (subject) values ($sql_subject)");
+ $db->exec ("select pk from subjects where subject = $sql_subject");
+ }
+ $pk_subjects = $db->Get ("pk", SQLINT);
+ $sql_fk_subjects = $db->f ($pk_subjects, SQLINT);
+
+ $db->exec ("select * from mn_books_subjects " .
+ "where fk_books = $sql_etext_number and fk_subjects = $sql_fk_subjects");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into mn_books_subjects (fk_books, fk_subjects) " .
+ "values ($sql_etext_number, $sql_fk_subjects)");
+ }
+ continue;
+ }
+ if ($key == "Note") {
+ $sql_note = $db->f ($value, SQLCHAR);
+ $db->exec ("select * from attributes " .
+ "where fk_books = $sql_etext_number and text = $sql_note");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into attributes (fk_books, fk_attriblist, text) values ($sql_etext_number, 500, $sql_note)");
+ }
+ continue;
+ }
+ if ($key == "Copyright") {
+ $sql_copyrighted = $db->f ($value, SQLINT);
+ $db->exec ("update books set copyrighted = $sql_copyrighted where pk = $sql_etext_number");
+ continue;
+ }
+ if ($key == "Category") {
+ $sql_category = $db->f ($value, SQLCHAR);
+ $db->exec ("select pk from categories where category = $sql_category");
+ if ($db->FirstRow ()) {
+ $fk_categories = $db->get ("pk", SQLINT);
+ $sql_fk_categories = $db->f ($fk_categories, SQLINT);
+
+ $db->exec ("select * from mn_books_categories " .
+ "where fk_books = $sql_etext_number and fk_categories = $sql_fk_categories");
+ if (!$db->FirstRow ()) {
+ $db->exec ("insert into mn_books_categories (fk_books, fk_categories) " .
+ "values ($sql_etext_number, $fk_categories)");
+ }
+ }
+ continue;
+ }
+ if ($key == "Release-Date") {
+ if (strpos ($value, ',') === false) {
+ $vale = "1 $value";
+ }
+ $release_date = strtotime ("$value");
+ $sql_release_date = $db->f ($release_date, SQLDATE);
+ $db->exec ("update books set release_date = $sql_release_date where pk = $sql_etext_number");
+ continue;
+ }
+ }
+
+ // hack! makefiles.pl sorts filenames so that 8-bit ones come first
+ // this way we prefer titles etc. from 8-bit files over html and 7-bit files
+ if ($got_title) {
+ $db->exec ("update books set updatemode = 1 where pk = $sql_etext_number");
+ }
+
+ $db->Commit ();
+ }
+ }
+}
+
+register_shutdown_function ('rollback_transaction');
+set_time_limit (0);
+
+$buffer = "";
+if ($hd = fopen ($importfilename, "r")) {
+ while (!feof ($hd)) {
+ $line = fgets ($hd);
+ if (preg_match ("/^---*[\r\n]*$/", $line)) {
+ process_section ($buffer);
+ $buffer = "";
+ echo ("\n"); flush ();
+ } else {
+ $buffer .= $line;
+ }
+ }
+ process_section ($buffer);
+ fclose ($hd);
+}
+
+?>
diff --git a/catalog/admin/categories_list.php b/catalog/admin/categories_list.php
new file mode 100644
index 0000000..937ec3f
--- /dev/null
+++ b/catalog/admin/categories_list.php
@@ -0,0 +1,44 @@
+AddColumn ("$prefix=edit&fk_categories=#pk#\">Edit",
+ "$prefix=add\">Add", "left", "1%");
+ $this->AddColumn ("$prefix=delete&fk_categories=#pk#\">Delete",
+ "", "left", "1%");
+ $this->AddSimpleColumn ("category", "Category");
+ }
+}
+
+$db = $config->db ();
+
+p ("Please enter the first few characters of the category (at least one).
+Search is case-sensitive.
+Use * as wildcard. (eg. *human)
+To see everything just enter *.");
+
+form_open ();
+echo (" \n");
+form_submit ("Search");
+form_close ();
+
+if ($filter != "") {
+ $filt = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from categories where category ilike '$filt%' order by category;");
+ $table = new ListCategoriesTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/categories_list.php~ b/catalog/admin/categories_list.php~
new file mode 100644
index 0000000..ea55bb9
--- /dev/null
+++ b/catalog/admin/categories_list.php~
@@ -0,0 +1,43 @@
+AddColumn ("$prefix=edit&fk_categories=#pk#\">Edit",
+ "$prefix=add\">Add", "left", "1%");
+ $this->AddColumn ("$prefix=delete&fk_categories=#pk#\">Delete",
+ "", "left", "1%");
+ $this->AddSimpleColumn ("category", "Category");
+ }
+}
+
+$db = $config->db ();
+
+p ("Please enter the first few characters of the category (at least one).
+Search is case-sensitive.
+Use * as wildcard. (eg. *human)
+To see everything just enter *.");
+
+form_open ();
+echo (" \n");
+form_submit ("Search");
+form_close ();
+
+if ($filter != "") {
+ $filt = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from categories where category ilike '$filt%' order by category;");
+ $table = new ListCategoriesTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/category.php b/catalog/admin/category.php
new file mode 100644
index 0000000..3768229
--- /dev/null
+++ b/catalog/admin/category.php
@@ -0,0 +1,92 @@
+AddColumn ("#pk# ",
+ "Etext Nr.", "right", "1*");
+ $this->AddSimpleColumn ("author", "Author");
+ $this->AddSimpleColumn ("title", "Title");
+ $this->limit = 25;
+ $this->relay = array ("fk_categories", "mode", "filter");
+ }
+}
+
+$db = $config->db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_categories");
+getstr ("filter");
+
+if (ismode ("delete")) {
+ $db->Exec ("select count (*) as cnt from mn_books_categories " .
+ "where fk_categories = $fk_categories");
+ $cnt = $db->get ("cnt");
+ if ($cnt > 0) {
+ $f->SubCaption ("Warning: There are $cnt books related to this category. ");
+ }
+ $f->SubCaption ("You are about to delete this category.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ $f->Text ("category", "category", "Category", SQLCHAR, 80, 240, true);
+ $f->LoadData ("select * from categories where pk = $fk_categories");
+}
+$f->Hidden ("fk_categories");
+$f->Hidden ("filter");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into categories " . $sql)) {
+ msg ("Category added !");
+ } else {
+ error_msg ("Could not add category!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update categories set " . $sql . "where pk = $fk_categories")) {
+ msg ("Category modified !");
+ } else {
+ error_msg ("Could not modify category !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->Exec ("delete from mn_books_categories where fk_categories = $fk_categories");
+ if ($db->Exec ("delete from categories where pk = $fk_categories")) {
+ msg ("Category deleted !");
+ } else {
+ error_msg ("Could not delete category !");
+ }
+}
+
+if (isupdate ()) {
+ if (!isupdatemode ("delete")) {
+ echo (" " .
+ "Back to Category
\n\n");
+ }
+} else {
+ $f->Output ($caption, $caption);
+}
+
+echo (" " .
+ "Back to Category List
\n\n");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/category.php~ b/catalog/admin/category.php~
new file mode 100644
index 0000000..253b3e3
--- /dev/null
+++ b/catalog/admin/category.php~
@@ -0,0 +1,91 @@
+AddColumn ("#pk# ",
+ "Etext Nr.", "right", "1*");
+ $this->AddSimpleColumn ("author", "Author");
+ $this->AddSimpleColumn ("title", "Title");
+ $this->limit = 25;
+ $this->relay = array ("fk_categories", "mode", "filter");
+ }
+}
+
+$db = $config->db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_categories");
+getstr ("filter");
+
+if (ismode ("delete")) {
+ $db->Exec ("select count (*) as cnt from mn_books_categories " .
+ "where fk_categories = $fk_categories");
+ $cnt = $db->get ("cnt");
+ if ($cnt > 0) {
+ $f->SubCaption ("Warning: There are $cnt books related to this category. ");
+ }
+ $f->SubCaption ("You are about to delete this category.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ $f->Text ("category", "category", "Category", SQLCHAR, 80, 240, true);
+ $f->LoadData ("select * from categories where pk = $fk_categories");
+}
+$f->Hidden ("fk_categories");
+$f->Hidden ("filter");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into categories " . $sql)) {
+ msg ("Category added !");
+ } else {
+ error_msg ("Could not add category!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update categories set " . $sql . "where pk = $fk_categories")) {
+ msg ("Category modified !");
+ } else {
+ error_msg ("Could not modify category !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->Exec ("delete from mn_books_categories where fk_categories = $fk_categories");
+ if ($db->Exec ("delete from categories where pk = $fk_categories")) {
+ msg ("Category deleted !");
+ } else {
+ error_msg ("Could not delete category !");
+ }
+}
+
+if (isupdate ()) {
+ if (!isupdatemode ("delete")) {
+ echo (" " .
+ "Back to Category
\n\n");
+ }
+} else {
+ $f->Output ($caption, $caption);
+}
+
+echo (" " .
+ "Back to Category List
\n\n");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/charset_guesser.php b/catalog/admin/charset_guesser.php
new file mode 100644
index 0000000..5b1bb61
--- /dev/null
+++ b/catalog/admin/charset_guesser.php
@@ -0,0 +1,96 @@
+db ();
+getstr ("file");
+getint ("samples", 10);
+
+pageheader ("Encoding Guesses for $file");
+
+$root = "/public/ftp/pub/docs/books/gutenberg/";
+
+$path = realpath ("$root$file");
+
+if (!preg_match ("|^$root|", $path) || (!$hd = fopen ($path, "r"))) {
+ // serve only files below root
+ header("HTTP/1.0 404 Not Found");
+ echo ("I see no such file here\n");
+ exit;
+}
+
+// get some words with funny characters
+
+$data = file_get_contents ($path);
+preg_match_all ("/\b.{0,20}[\x80-\xFF].{0,20}\b/s", $data, $matches);
+$found_samples = count ($matches[0]);
+
+if ($found_samples == 0) {
+ echo ("No non-ascii characters found.
");
+ pagefooter ();
+ exit ();
+}
+
+$more_samples = $samples > 0 && $found_samples > $samples;
+
+$words = join ("\n", $samples ? array_slice ($matches[0], 0, $samples) : $matches[0]);
+
+// convert those words to all known encodings
+
+$encodings = array ();
+$db->exec ("select pk from encodings order by pk");
+if ($db->FirstRow ()) {
+ do {
+ $encodings[] = $db->Get ("pk");
+ } while ($db->NextRow ());
+}
+
+$me = $_SERVER['PATH_INFO'] . htmlspecialchars ("?file=$file");
+if ($more_samples) {
+ $caption = "Samples (first $samples of $found_samples found) show all ";
+} else {
+ $caption = "Samples (all $found_samples found)";
+ if ($found_samples > 10)
+ $caption .= " show only first 10 ";
+}
+
+echo ("Encoding $caption \n");
+
+function hex ($c) {
+ return sprintf ('\x%2X', ord ($c));
+}
+
+$sample = htmlspecialchars (@preg_replace ("/[\x80-\xFF]/e", 'hex ($0)', $words));
+$sample = preg_replace ("/\n/", " ", $sample);
+echo ("hex-escaped $sample \n");
+
+mb_regex_encoding ("UTF-8");
+mb_ereg_search_init ("[\x80-\x9F]");
+
+foreach ($encodings as $enc) {
+ $wordslen = strlen ($words);
+ $sample = @iconv ($enc, "UTF-8", $words);
+ if ($sample) {
+ if (!mb_ereg ("[\200-\237]", $sample)) {
+ if (iconv_strlen ($sample, 'UTF-8') == $wordslen) {
+ $sample = preg_replace ("/\n/", " ", htmlspecialchars ($sample));
+ echo ("$enc $sample \n");
+ }
+ }
+ }
+}
+
+echo ("
");
+
+pagefooter ();
+
+// Local Variables:
+// mode:php
+// coding:utf-8-unix
+// fill-column: 75
+// End:
+
+?>
diff --git a/catalog/admin/charset_guesser.php~ b/catalog/admin/charset_guesser.php~
new file mode 100644
index 0000000..2aa7bb5
--- /dev/null
+++ b/catalog/admin/charset_guesser.php~
@@ -0,0 +1,95 @@
+db ();
+getstr ("file");
+getint ("samples", 10);
+
+pageheader ("Encoding Guesses for $file");
+
+$root = "/public/ftp/pub/docs/books/gutenberg/";
+
+$path = realpath ("$root$file");
+
+if (!preg_match ("|^$root|", $path) || (!$hd = fopen ($path, "r"))) {
+ // serve only files below root
+ header("HTTP/1.0 404 Not Found");
+ echo ("I see no such file here\n");
+ exit;
+}
+
+// get some words with funny characters
+
+$data = file_get_contents ($path);
+preg_match_all ("/\b.{0,20}[\x80-\xFF].{0,20}\b/s", $data, $matches);
+$found_samples = count ($matches[0]);
+
+if ($found_samples == 0) {
+ echo ("No non-ascii characters found.
");
+ pagefooter ();
+ exit ();
+}
+
+$more_samples = $samples > 0 && $found_samples > $samples;
+
+$words = join ("\n", $samples ? array_slice ($matches[0], 0, $samples) : $matches[0]);
+
+// convert those words to all known encodings
+
+$encodings = array ();
+$db->exec ("select pk from encodings order by pk");
+if ($db->FirstRow ()) {
+ do {
+ $encodings[] = $db->Get ("pk");
+ } while ($db->NextRow ());
+}
+
+$me = $_SERVER['PATH_INFO'] . htmlspecialchars ("?file=$file");
+if ($more_samples) {
+ $caption = "Samples (first $samples of $found_samples found) show all ";
+} else {
+ $caption = "Samples (all $found_samples found)";
+ if ($found_samples > 10)
+ $caption .= " show only first 10 ";
+}
+
+echo ("Encoding $caption \n");
+
+function hex ($c) {
+ return sprintf ('\x%2X', ord ($c));
+}
+
+$sample = htmlspecialchars (@preg_replace ("/[\x80-\xFF]/e", 'hex ($0)', $words));
+$sample = preg_replace ("/\n/", " ", $sample);
+echo ("hex-escaped $sample \n");
+
+mb_regex_encoding ("UTF-8");
+mb_ereg_search_init ("[\x80-\x9F]");
+
+foreach ($encodings as $enc) {
+ $wordslen = strlen ($words);
+ $sample = @iconv ($enc, "UTF-8", $words);
+ if ($sample) {
+ if (!mb_ereg ("[\200-\237]", $sample)) {
+ if (iconv_strlen ($sample, 'UTF-8') == $wordslen) {
+ $sample = preg_replace ("/\n/", " ", htmlspecialchars ($sample));
+ echo ("$enc $sample \n");
+ }
+ }
+ }
+}
+
+echo ("
");
+
+pagefooter ();
+
+// Local Variables:
+// mode:php
+// coding:utf-8-unix
+// fill-column: 75
+// End:
+
+?>
diff --git a/catalog/admin/check_urls.php b/catalog/admin/check_urls.php
new file mode 100644
index 0000000..19d8dd1
--- /dev/null
+++ b/catalog/admin/check_urls.php
@@ -0,0 +1,84 @@
+db ();
+
+$cnt = 0;
+
+$db->exec ("select author, url from authors, author_urls where authors.pk = author_urls.fk_authors order by url");
+
+if ($db->FirstRow ()) {
+ do {
+ $url = $db->get ("url", SQLCHAR);
+ $author = $db->get ("author", SQLCHAR);
+
+ sleep (1);
+
+ if (!preg_match ("!^http://(.*?)(/.*)$!", $url, $matches)) {
+ echo ("$author\nNot a http url: $url\n");
+ $cnt++;
+ continue;
+ }
+
+ $host = $matches[1];
+ $path = $matches[2];
+
+ $sock = @fsockopen ($host, 80, $errno, $errstr, 120);
+ if (!$sock) {
+ echo ("$author\nHost $host unreachable! $errstr ($errno)\n");
+ $cnt++;
+ continue;
+ }
+
+ $request = "HEAD $path HTTP/1.0\r\nHost: $host\r\n\r\n";
+
+ // echo ($request);
+
+ fwrite ($sock, $request);
+
+ $headers = "";
+ while ($str = trim (fgets ($sock, 4096)))
+ $headers .= "$str\n";
+
+ fclose ($sock);
+
+ if (!preg_match ("!^HTTP/\d\.\d\s+(\d+)!", $headers, $matches)) {
+ echo ("$author\nGot bogus response from $host!\n\n($headers)\n\n");
+ $cnt++;
+ continue;
+ }
+
+ $code = intval ($matches[1]);
+
+ if ($code == 200) {
+ continue;
+ }
+ if ($code >= 300 && $code < 400) {
+ echo ("$author\n$url Redirected $code");
+ if (preg_match ("!^Location:\s+(.*)$!im", $headers, $matches)) {
+ $location = $matches[1];
+ echo (" to $location");
+ }
+ echo ("\n");
+ continue;
+ }
+
+ echo ("$author\n$url Error $code!\n");
+ $cnt++;
+
+ } while ($db->NextRow ());
+}
+
+if ($cnt) {
+ echo ("$cnt urls failed!!\n");
+ return 1;
+}
+
+return 0;
+
+?>
diff --git a/catalog/admin/check_urls.php~ b/catalog/admin/check_urls.php~
new file mode 100644
index 0000000..021c84c
--- /dev/null
+++ b/catalog/admin/check_urls.php~
@@ -0,0 +1,83 @@
+db ();
+
+$cnt = 0;
+
+$db->exec ("select author, url from authors, author_urls where authors.pk = author_urls.fk_authors order by url");
+
+if ($db->FirstRow ()) {
+ do {
+ $url = $db->get ("url", SQLCHAR);
+ $author = $db->get ("author", SQLCHAR);
+
+ sleep (1);
+
+ if (!preg_match ("!^http://(.*?)(/.*)$!", $url, $matches)) {
+ echo ("$author\nNot a http url: $url\n");
+ $cnt++;
+ continue;
+ }
+
+ $host = $matches[1];
+ $path = $matches[2];
+
+ $sock = @fsockopen ($host, 80, $errno, $errstr, 120);
+ if (!$sock) {
+ echo ("$author\nHost $host unreachable! $errstr ($errno)\n");
+ $cnt++;
+ continue;
+ }
+
+ $request = "HEAD $path HTTP/1.0\r\nHost: $host\r\n\r\n";
+
+ // echo ($request);
+
+ fwrite ($sock, $request);
+
+ $headers = "";
+ while ($str = trim (fgets ($sock, 4096)))
+ $headers .= "$str\n";
+
+ fclose ($sock);
+
+ if (!preg_match ("!^HTTP/\d\.\d\s+(\d+)!", $headers, $matches)) {
+ echo ("$author\nGot bogus response from $host!\n\n($headers)\n\n");
+ $cnt++;
+ continue;
+ }
+
+ $code = intval ($matches[1]);
+
+ if ($code == 200) {
+ continue;
+ }
+ if ($code >= 300 && $code < 400) {
+ echo ("$author\n$url Redirected $code");
+ if (preg_match ("!^Location:\s+(.*)$!im", $headers, $matches)) {
+ $location = $matches[1];
+ echo (" to $location");
+ }
+ echo ("\n");
+ continue;
+ }
+
+ echo ("$author\n$url Error $code!\n");
+ $cnt++;
+
+ } while ($db->NextRow ());
+}
+
+if ($cnt) {
+ echo ("$cnt urls failed!!\n");
+ return 1;
+}
+
+return 0;
+
+?>
diff --git a/catalog/admin/checklink.php b/catalog/admin/checklink.php
new file mode 100644
index 0000000..ed60987
--- /dev/null
+++ b/catalog/admin/checklink.php
@@ -0,0 +1,44 @@
+db ();
+
+$db->exec ("select * from files where fk_filetypes = 'html' and fk_compressions = 'none' order by filename");
+
+if ($db->FirstRow ()) {
+ do {
+ $filename = $db->get ("filename", SQLCHAR);
+
+ echo ("Checking $filename ...");
+
+ $url = "http://$config->domain/dirs/$filename";
+ $output = `/public/vhost/g/gutenberg/private/local/bin/checklink -q -s --broken $url`;
+
+ if (preg_match ("/broken links/i", $output)) {
+ echo (" ERRORS!\n$output\n");
+ $validator = "http://validator.w3.org/checklink?uri=" . urlencode ($url) . "&hide_type=all&depth=&check=Check";
+
+ mail ("marcello@perathoner.de", "Broken links in $filename",
+ "Validator url:\n\n$validator\n\nValidator output was:\n$output",
+ "From: linkchecker@gutenberg.org\r\n" .
+ "Reply-To: webmaster@gutenberg.org\r\n");
+
+ } else {
+ echo (" OK\n");
+ }
+
+ } while ($db->NextRow ());
+}
+
+?>
diff --git a/catalog/admin/checklink.php~ b/catalog/admin/checklink.php~
new file mode 100644
index 0000000..1acc604
--- /dev/null
+++ b/catalog/admin/checklink.php~
@@ -0,0 +1,43 @@
+db ();
+
+$db->exec ("select * from files where fk_filetypes = 'html' and fk_compressions = 'none' order by filename");
+
+if ($db->FirstRow ()) {
+ do {
+ $filename = $db->get ("filename", SQLCHAR);
+
+ echo ("Checking $filename ...");
+
+ $url = "http://$config->domain/dirs/$filename";
+ $output = `/public/vhost/g/gutenberg/private/local/bin/checklink -q -s --broken $url`;
+
+ if (preg_match ("/broken links/i", $output)) {
+ echo (" ERRORS!\n$output\n");
+ $validator = "http://validator.w3.org/checklink?uri=" . urlencode ($url) . "&hide_type=all&depth=&check=Check";
+
+ mail ("marcello@perathoner.de", "Broken links in $filename",
+ "Validator url:\n\n$validator\n\nValidator output was:\n$output",
+ "From: linkchecker@gutenberg.org\r\n" .
+ "Reply-To: webmaster@gutenberg.org\r\n");
+
+ } else {
+ echo (" OK\n");
+ }
+
+ } while ($db->NextRow ());
+}
+
+?>
diff --git a/catalog/admin/chmod-cache.php b/catalog/admin/chmod-cache.php
new file mode 100644
index 0000000..9bd124b
--- /dev/null
+++ b/catalog/admin/chmod-cache.php
@@ -0,0 +1,19 @@
+start ...');
+flush ();
+
+/*
+for ($i = 0; $i < 31000; $i++) {
+ chmod ("/public/vhost/g/gutenberg/html/cache/bibrec/$i", 0777);
+ if (($i % 100) == 0) {
+ echo ("$i
");
+ flush ();
+ }
+}
+*/
+
+echo (`chmod -R 777 /public/vhost/g/gutenberg/html/cache/wiki/*`);
+
+echo ('done
');
+
+?>
diff --git a/catalog/admin/cp.php b/catalog/admin/cp.php
new file mode 100644
index 0000000..ba5694f
--- /dev/null
+++ b/catalog/admin/cp.php
@@ -0,0 +1,13 @@
+
diff --git a/catalog/admin/cp.php~ b/catalog/admin/cp.php~
new file mode 100644
index 0000000..ce7480d
--- /dev/null
+++ b/catalog/admin/cp.php~
@@ -0,0 +1,12 @@
+
diff --git a/catalog/admin/delete-o-matic.php b/catalog/admin/delete-o-matic.php
new file mode 100644
index 0000000..4b68fad
--- /dev/null
+++ b/catalog/admin/delete-o-matic.php
@@ -0,0 +1,115 @@
+db ();
+$db->logger = new logger ();
+
+echo ("Initializing ...\n");
+
+register_shutdown_function ('rollback_transaction');
+set_time_limit (0);
+
+$cnt = 0;
+$db->Exec ("select filename from files where diskstatus != 5 order by filename");
+if ($db->FirstRow ()) {
+ do {
+ $files[$db->Get ("filename", SQLCHAR)] = 0;
+ $cnt++;
+ } while ($db->NextRow ());
+}
+
+echo ("$cnt files in database.\n");
+
+echo ("Stat-ing files ...\n");
+
+$cnt = 0;
+$gonecnt = 0;
+foreach ($files as $filename => $value) {
+ if ($filename[0] == '/') {
+ if (@stat ($filename) === FALSE) {
+ $gone[$filename] = 1;
+ $gonecnt++;
+ echo ("Gone: $filename\n");
+ }
+ } elseif (preg_match ('/^(cache|masters)\//', $filename)) {
+ if (@stat ("$config->documentroot/$filename") === FALSE) {
+ $gone[$filename] = 1;
+ $gonecnt++;
+ echo ("Gone: $config->documentroot//$filename\n");
+ }
+ } else {
+ if (@stat ("$config->filesroot/$filename") === FALSE) {
+ $gone[$filename] = 1;
+ $gonecnt++;
+ echo ("Gone: $config->filesroot//$filename\n");
+ }
+ }
+ $cnt++;
+ if (($cnt % 100000) == 0) {
+ echo ("Stat: $cnt gone: $gonecnt\n");
+ }
+ if ($gonecnt > 10000) {
+ echo ("Gone over 10.000 files!\nDeleted nothing. Check for errors.");
+ die ();
+ }
+}
+
+$files = null;
+echo ("Gone: $gonecnt files\n");
+
+// stat everything again, maybe nfs is flaky today
+for ($i = 0; $i < 10; $i++) {
+ if (!$gonecnt)
+ break;
+ echo ("Waiting ...\n");
+ sleep (600);
+ echo ("Re-stat-ing: $gonecnt files\n");
+ clearstatcache ();
+ foreach ($gone as $filename => $value) {
+ if ($value == 1) {
+ if (preg_match ('/^cache\//', $filename)) {
+ if (@stat ("$config->documentroot/$filename") !== FALSE) {
+ $gone[$filename] = 0;
+ $gonecnt--;
+ }
+ } else {
+ if (@stat ("$config->filesroot/$filename") !== FALSE) {
+ $gone[$filename] = 0;
+ $gonecnt--;
+ }
+ }
+ }
+ }
+}
+
+if ($gonecnt) {
+ echo ("Deleting: $gonecnt files ...\n");
+
+ foreach ($gone as $filename => $value) {
+ if ($value == 1) {
+ echo ("Marking as deleted: $filename\n");
+ $esc_filename = addslashes($filename);
+ $db->exec ("update files set diskstatus = 5 where filename = '$esc_filename'");
+
+ $infofile = "$config->privateroot/fileinfo/$filename.info";
+ @unlink ($infofile);
+ }
+ }
+}
+
+echo ("Done.\n");
+
+?>
diff --git a/catalog/admin/delete-o-matic.php~ b/catalog/admin/delete-o-matic.php~
new file mode 100644
index 0000000..65c6745
--- /dev/null
+++ b/catalog/admin/delete-o-matic.php~
@@ -0,0 +1,114 @@
+db ();
+$db->logger = new logger ();
+
+echo ("Initializing ...\n");
+
+register_shutdown_function ('rollback_transaction');
+set_time_limit (0);
+
+$cnt = 0;
+$db->Exec ("select filename from files where diskstatus != 5 order by filename");
+if ($db->FirstRow ()) {
+ do {
+ $files[$db->Get ("filename", SQLCHAR)] = 0;
+ $cnt++;
+ } while ($db->NextRow ());
+}
+
+echo ("$cnt files in database.\n");
+
+echo ("Stat-ing files ...\n");
+
+$cnt = 0;
+$gonecnt = 0;
+foreach ($files as $filename => $value) {
+ if ($filename[0] == '/') {
+ if (@stat ($filename) === FALSE) {
+ $gone[$filename] = 1;
+ $gonecnt++;
+ echo ("Gone: $filename\n");
+ }
+ } elseif (preg_match ('/^(cache|masters)\//', $filename)) {
+ if (@stat ("$config->documentroot/$filename") === FALSE) {
+ $gone[$filename] = 1;
+ $gonecnt++;
+ echo ("Gone: $config->documentroot//$filename\n");
+ }
+ } else {
+ if (@stat ("$config->filesroot/$filename") === FALSE) {
+ $gone[$filename] = 1;
+ $gonecnt++;
+ echo ("Gone: $config->filesroot//$filename\n");
+ }
+ }
+ $cnt++;
+ if (($cnt % 100000) == 0) {
+ echo ("Stat: $cnt gone: $gonecnt\n");
+ }
+ if ($gonecnt > 10000) {
+ echo ("Gone over 10.000 files!\nDeleted nothing. Check for errors.");
+ die ();
+ }
+}
+
+$files = null;
+echo ("Gone: $gonecnt files\n");
+
+// stat everything again, maybe nfs is flaky today
+for ($i = 0; $i < 10; $i++) {
+ if (!$gonecnt)
+ break;
+ echo ("Waiting ...\n");
+ sleep (600);
+ echo ("Re-stat-ing: $gonecnt files\n");
+ clearstatcache ();
+ foreach ($gone as $filename => $value) {
+ if ($value == 1) {
+ if (preg_match ('/^cache\//', $filename)) {
+ if (@stat ("$config->documentroot/$filename") !== FALSE) {
+ $gone[$filename] = 0;
+ $gonecnt--;
+ }
+ } else {
+ if (@stat ("$config->filesroot/$filename") !== FALSE) {
+ $gone[$filename] = 0;
+ $gonecnt--;
+ }
+ }
+ }
+ }
+}
+
+if ($gonecnt) {
+ echo ("Deleting: $gonecnt files ...\n");
+
+ foreach ($gone as $filename => $value) {
+ if ($value == 1) {
+ echo ("Marking as deleted: $filename\n");
+ $esc_filename = addslashes($filename);
+ $db->exec ("update files set diskstatus = 5 where filename = '$esc_filename'");
+
+ $infofile = "$config->privateroot/fileinfo/$filename.info";
+ @unlink ($infofile);
+ }
+ }
+}
+
+echo ("Done.\n");
+
+?>
diff --git a/catalog/admin/dupl_attrib_list.php b/catalog/admin/dupl_attrib_list.php
new file mode 100644
index 0000000..651a404
--- /dev/null
+++ b/catalog/admin/dupl_attrib_list.php
@@ -0,0 +1,27 @@
+db ();
+$db->logger = new logger ();
+
+pageheader("Books with duplicate MARC fields");
+
+class DuplAttribTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "#name# ", "MARC Field");
+ $this->AddColumn("#cnt#", "# of fields per book");
+ $this->AddColumn("#count#", "# of books");
+ }
+}
+p("Click on the MARC Fields to see a list of the actual duplicates.");
+$db->Exec("select name, code, cnt, count(cnt) from (select fk_attriblist as code, count(fk_attriblist) as cnt from attributes group by fk_books, fk_attriblist having count(fk_attriblist)>1) as foo join attriblist on code=attriblist.pk group by attriblist.pk, attriblist.name, code, cnt order by code");
+$table = new DuplAttribTable();
+$table->PrintTable($db, "Duplicate MARC Fields");
+
+pagefooter();
diff --git a/catalog/admin/dupl_attrib_list.php~ b/catalog/admin/dupl_attrib_list.php~
new file mode 100644
index 0000000..34dce11
--- /dev/null
+++ b/catalog/admin/dupl_attrib_list.php~
@@ -0,0 +1,26 @@
+db ();
+$db->logger = new logger ();
+
+pageheader("Books with duplicate MARC fields");
+
+class DuplAttribTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "#name# ", "MARC Field");
+ $this->AddColumn("#cnt#", "# of fields per book");
+ $this->AddColumn("#count#", "# of books");
+ }
+}
+p("Click on the MARC Fields to see a list of the actual duplicates.");
+$db->Exec("select name, code, cnt, count(cnt) from (select fk_attriblist as code, count(fk_attriblist) as cnt from attributes group by fk_books, fk_attriblist having count(fk_attriblist)>1) as foo join attriblist on code=attriblist.pk group by attriblist.pk, attriblist.name, code, cnt order by code");
+$table = new DuplAttribTable();
+$table->PrintTable($db, "Duplicate MARC Fields");
+
+pagefooter();
diff --git a/catalog/admin/dupl_attribs.php b/catalog/admin/dupl_attribs.php
new file mode 100644
index 0000000..3904c63
--- /dev/null
+++ b/catalog/admin/dupl_attribs.php
@@ -0,0 +1,34 @@
+db ();
+$db->logger = new logger ();
+
+getint("fk_attriblist");
+getint("cnt");
+
+$db->Exec("select name from attriblist where pk=$fk_attriblist");
+$attr_name = $db->Get("name");
+
+pageheader("Books with $cnt of the '$attr_name' field");
+
+
+class DuplAttribDetailTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "#fk_books# ", "Etext #");
+ $this->AddColumn("#text#", "Text of field");
+ }
+}
+$table= new DuplAttribDetailTable();
+$db->Exec ("select fk_books, text from attributes where fk_attriblist=$fk_attriblist and fk_books in (select fk_books from attributes where fk_attriblist=$fk_attriblist group by fk_books, fk_attriblist having count(fk_attriblist)=$cnt) order by fk_books");
+$table->PrintTable($db, "");
+/* TODO: Convert $cnt to words, i.e. "five" not "5" */
+
+p("Return to list ");
+
+pagefooter();
diff --git a/catalog/admin/dupl_attribs.php~ b/catalog/admin/dupl_attribs.php~
new file mode 100644
index 0000000..42b8c5e
--- /dev/null
+++ b/catalog/admin/dupl_attribs.php~
@@ -0,0 +1,33 @@
+db ();
+$db->logger = new logger ();
+
+getint("fk_attriblist");
+getint("cnt");
+
+$db->Exec("select name from attriblist where pk=$fk_attriblist");
+$attr_name = $db->Get("name");
+
+pageheader("Books with $cnt of the '$attr_name' field");
+
+
+class DuplAttribDetailTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "#fk_books# ", "Etext #");
+ $this->AddColumn("#text#", "Text of field");
+ }
+}
+$table= new DuplAttribDetailTable();
+$db->Exec ("select fk_books, text from attributes where fk_attriblist=$fk_attriblist and fk_books in (select fk_books from attributes where fk_attriblist=$fk_attriblist group by fk_books, fk_attriblist having count(fk_attriblist)=$cnt) order by fk_books");
+$table->PrintTable($db, "");
+/* TODO: Convert $cnt to words, i.e. "five" not "5" */
+
+p("Return to list ");
+
+pagefooter();
diff --git a/catalog/admin/empty_authors.php b/catalog/admin/empty_authors.php
new file mode 100644
index 0000000..a8fdac0
--- /dev/null
+++ b/catalog/admin/empty_authors.php
@@ -0,0 +1,32 @@
+db ();
+
+$db->logger = new logger ();
+
+class AuthorsBirthDeathDeletionTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "Delete ", "", "narrow");
+ $this->AddColumn("" .
+ "#author# ", "Author");
+ $this->AddSimpleColumn("born_floor", "Birth");
+ $this->AddSimpleColumn("died_floor", "Death");
+ }
+}
+
+pageheader("Authors with no books");
+
+$table = new AuthorsBirthDeathDeletionTable ();
+$db->Exec("select distinct pk, author, born_floor, died_floor " .
+ "from authors left join mn_books_authors " .
+ "on fk_authors=authors.pk where fk_books is null " .
+ "order by author, pk");
+$table->PrintTable($db, "Authors with no books linked");
+
+pagefooter();
diff --git a/catalog/admin/empty_authors.php~ b/catalog/admin/empty_authors.php~
new file mode 100644
index 0000000..9a1e285
--- /dev/null
+++ b/catalog/admin/empty_authors.php~
@@ -0,0 +1,31 @@
+db ();
+
+$db->logger = new logger ();
+
+class AuthorsBirthDeathDeletionTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "Delete ", "", "narrow");
+ $this->AddColumn("" .
+ "#author# ", "Author");
+ $this->AddSimpleColumn("born_floor", "Birth");
+ $this->AddSimpleColumn("died_floor", "Death");
+ }
+}
+
+pageheader("Authors with no books");
+
+$table = new AuthorsBirthDeathDeletionTable ();
+$db->Exec("select distinct pk, author, born_floor, died_floor " .
+ "from authors left join mn_books_authors " .
+ "on fk_authors=authors.pk where fk_books is null " .
+ "order by author, pk");
+$table->PrintTable($db, "Authors with no books linked");
+
+pagefooter();
diff --git a/catalog/admin/file.php b/catalog/admin/file.php
new file mode 100644
index 0000000..6e78b21
--- /dev/null
+++ b/catalog/admin/file.php
@@ -0,0 +1,71 @@
+db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+
+getint ("fk_files");
+getint ("fk_books");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this file.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ if (ismode ("add")) {
+ $f->SQLInject ("fk_books", "fk_books", SQLINT);
+ }
+ $f->Text ("filename", "filename", "Filename", SQLCHAR, 80, 240, true);
+ $f->Text ("fk_books", "fk_books", "Etext-Nr.", SQLINT, 20, 80, false);
+ $f->Text ("edition", "edition", "Edition", SQLINT, 20, 80, false);
+ $f->Text ("filemtime", "filemtime", "File Modification Time", SQLDATE, 20, 20, false);
+ $f->CheckBox ("obsoleted", "obsoleted", "Obsoleted", SQLINT);
+ $f->SQLSelect ("fk_filetypes", "fk_filetypes", "File Type", SQLCHAR, 40, 80, true,
+ "select pk as value, filetype as caption from filetypes order by filetype");
+ $f->SQLSelect ("fk_compressions", "fk_compressions", "Compression", SQLCHAR, 40, 80, true,
+ "select pk as value, compression as caption from compressions order by compression");
+ $f->SQLSelect ("fk_encodings", "fk_encodings", "Encoding", SQLCHAR, 40, 80, false,
+ "select null as value, 'unknown' as caption union " .
+ "select pk as value, pk as caption from encodings order by caption");
+ $f->Text ("filesize", "filesize", "File Size", SQLINT, 20, 80, false);
+ $f->TextArea ("note", "note", "Note", SQLCHAR, 4, 80, false);
+ $f->LoadData ("select * from files where pk = $fk_files");
+}
+$f->Hidden ("fk_files");
+$f->Hidden ("fk_books");
+$f->Hidden ("filemask");
+
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update files set " . $sql . "where pk = $fk_files")) {
+ msg ("File modified !");
+ } else {
+ error_msg ("Could not modify file !");
+ }
+ }
+}
+
+if (isupdate ()) {
+ getint ("fk_books");
+ getstr ("filemask");
+ echo ("Back to Book Files
\n\n");
+} else {
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/file.php~ b/catalog/admin/file.php~
new file mode 100644
index 0000000..6ccd451
--- /dev/null
+++ b/catalog/admin/file.php~
@@ -0,0 +1,70 @@
+db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+
+getint ("fk_files");
+getint ("fk_books");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this file.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ if (ismode ("add")) {
+ $f->SQLInject ("fk_books", "fk_books", SQLINT);
+ }
+ $f->Text ("filename", "filename", "Filename", SQLCHAR, 80, 240, true);
+ $f->Text ("fk_books", "fk_books", "Etext-Nr.", SQLINT, 20, 80, false);
+ $f->Text ("edition", "edition", "Edition", SQLINT, 20, 80, false);
+ $f->Text ("filemtime", "filemtime", "File Modification Time", SQLDATE, 20, 20, false);
+ $f->CheckBox ("obsoleted", "obsoleted", "Obsoleted", SQLINT);
+ $f->SQLSelect ("fk_filetypes", "fk_filetypes", "File Type", SQLCHAR, 40, 80, true,
+ "select pk as value, filetype as caption from filetypes order by filetype");
+ $f->SQLSelect ("fk_compressions", "fk_compressions", "Compression", SQLCHAR, 40, 80, true,
+ "select pk as value, compression as caption from compressions order by compression");
+ $f->SQLSelect ("fk_encodings", "fk_encodings", "Encoding", SQLCHAR, 40, 80, false,
+ "select null as value, 'unknown' as caption union " .
+ "select pk as value, pk as caption from encodings order by caption");
+ $f->Text ("filesize", "filesize", "File Size", SQLINT, 20, 80, false);
+ $f->TextArea ("note", "note", "Note", SQLCHAR, 4, 80, false);
+ $f->LoadData ("select * from files where pk = $fk_files");
+}
+$f->Hidden ("fk_files");
+$f->Hidden ("fk_books");
+$f->Hidden ("filemask");
+
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update files set " . $sql . "where pk = $fk_files")) {
+ msg ("File modified !");
+ } else {
+ error_msg ("Could not modify file !");
+ }
+ }
+}
+
+if (isupdate ()) {
+ getint ("fk_books");
+ getstr ("filemask");
+ echo ("Back to Book Files
\n\n");
+} else {
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/files.php b/catalog/admin/files.php
new file mode 100644
index 0000000..d9fabba
--- /dev/null
+++ b/catalog/admin/files.php
@@ -0,0 +1,206 @@
+db ();
+getint ("fk_books");
+getstr ("filemask");
+
+pageheader ("Files for EBook #$fk_books");
+
+p ("Careful! If you change the Ebook number you link the file to a different Ebook.");
+p ("Note: you cannot add files to the database. " .
+ "That is done automagically by a nightly cron job.");
+
+p ("Goto Edit Book Page — " .
+ "etext/${fk_books}\">Goto Bibrec Page ");
+
+function mk_options ($name, $options, $option) {
+ $ret = "";
+ foreach ($options as $value => $opt) {
+ $selected = ($opt == $option) ? " selected=\"selected\"" : "";
+ $ret .= "$opt \n";
+ }
+ return "\n" . $ret . " \n";
+}
+
+$filetypes[null] = "unknown";
+$db->Exec ("select * from filetypes order by filetype");
+if ($db->FirstRow ()) {
+ do {
+ $filetypes[$db->Get ("pk")] = $db->Get ("filetype");
+ } while ($db->NextRow ());
+}
+
+$compressions[null] = "unknown";
+$db->Exec ("select * from compressions order by compression");
+if ($db->FirstRow ()) {
+ do {
+ $compressions[$db->Get ("pk")] = $db->Get ("compression");
+ } while ($db->NextRow ());
+}
+
+$encodings[null] = "unknown";
+$db->Exec ("select * from encodings order by pk");
+if ($db->FirstRow ()) {
+ do {
+ $encodings[$db->Get ("pk")] = $db->Get ("pk");
+ } while ($db->NextRow ());
+}
+
+class HeadColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "", "narrow");
+ }
+ function Data ($db) {
+ $filename = $db->get ("filename");
+ if (preg_match ("/\.zip$/i", $filename))
+ return "Dir ";
+ return "Head ";
+ }
+}
+
+class CharsetColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "", "narrow");
+ }
+ function Data ($db) {
+ $filename = $db->get ("filename");
+ if (preg_match ("/\.zip$/i", $filename))
+ return " ";
+ return "Guess ";
+ }
+}
+
+class SizeColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "Size", "pgdbfilessize");
+ }
+ function Header () {
+ return "Size ";
+ }
+ function Data ($db) {
+ return "" . human_readable_size ($db->get ("filesize")) . " ";
+ }
+}
+
+class FiletypeColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "File Type", "pgdbfilesfiletype");
+ }
+ function Data ($db) {
+ global $filetypes;
+ return "" . mk_options ("fk_filetypes", $filetypes, $db->get ("filetype")) . " ";
+ }
+}
+
+class CompressionColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "Compression", "pgdbfilescompression");
+ }
+ function Data ($db) {
+ global $compressions;
+ return "" . mk_options ("fk_compressions", $compressions, $db->get ("compression")) . " ";
+ }
+}
+
+class EncodingColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "Encoding", "pgdbfilesencoding");
+ }
+ function Data ($db) {
+ global $encodings;
+ return "" . mk_options ("fk_encodings", $encodings, $db->get ("fk_encodings")) . " ";
+ }
+}
+
+class ObsoletedColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "Obs.", "pgdbfilesobsoleted");
+ }
+ function Data ($db) {
+ $obs = $db->get ("obsoleted", SQLINT) ? " checked=\"checked\"" : "";
+ $pk = $db->get ("pk", SQLINT);
+ return " ";
+ }
+}
+
+form_open_get ();
+echo ("Enter Perl RegExp: eg. /12345/");
+form_relay ("fk_books");
+form_submit ("Reload");
+form_close ();
+
+// Files for book
+$prefix = "AddColumn (" ", "", "narrow");
+$t->AddColumn ("$prefix=edit&fk_files=#pk#\">Edit ", "", "narrow");
+$t->AddColumnObject (new HeadColumn ());
+$t->AddColumn ("Bug ", "", "narrow");
+$t->AddColumn ("downloadbase/#filename#\">#filename# " .
+ " ",
+ "Filename");
+$t->AddColumn (" " .
+ " ", "EBook");
+$t->AddColumn (" ", "Edition");
+$t->AddColumnObject (new ObsoletedColumn ());
+$t->AddColumnObject (new FiletypeColumn ());
+$t->AddColumnObject (new EncodingColumn ());
+$t->AddColumnObject (new CharsetColumn ());
+$t->AddColumnObject (new CompressionColumn ());
+$t->AddColumnObject (new SizeColumn ());
+
+/////////////////////////////////////////////////////////////////////////////////
+// Generate list of candidate files
+//
+
+/*if (empty ($filemask)) {
+ if ($fk_books > 10000) {
+ $filemask = "/${fk_books}[.-]";
+ } else {
+ $db->Exec ("select * from books where pk = $fk_books");
+ $filemask = $db->Get ("filemask");
+ if (!empty ($filemask)) {
+ $filemask = preg_replace ("/\./", "\\.", $filemask);
+ $filemask = preg_replace ("/x+/", ".*", $filemask);
+ $filemask = preg_replace ("/^[?]/", "[78]", $filemask);
+ }
+ }
+}*/
+
+$sql = "select files.pk as pk, fk_books, filename, edition, obsoleted, filetype, " .
+ "compression, fk_encodings, filesize " .
+ "from files left join filetypes on files.fk_filetypes = filetypes.pk " .
+ "left join compressions on files.fk_compressions = compressions.pk " .
+ "where " . (empty ($filemask) ? "" : "filename ~ '$filemask' or ") .
+ "(fk_books = $fk_books and diskstatus = 0) " .
+ "order by (fk_books = $fk_books) desc, obsoleted, " .
+ "filetype, fk_encodings, compression, filename;";
+
+$db->exec ($sql);
+
+form_open ("files2");
+$t->limit = 100;
+$t->PrintTable ($db, "Files Linked to Book $fk_books or Matching RegExp: $filemask", "pgdbfiles");
+form_relay ("fk_books");
+form_relay ("filemask");
+form_submit ("Update Checked File Entries");
+form_close ();
+
+p ("To be implemented: functions for viewing bottom n lines from file, check
+for character encoding, diff files, look into zips. In my copious free time.");
+
+pagefooter ();
+
+// Local Variables:
+// mode:php
+// coding:utf-8-unix
+// fill-column: 75
+// End:
+
+?>
diff --git a/catalog/admin/files.php~ b/catalog/admin/files.php~
new file mode 100644
index 0000000..4a21489
--- /dev/null
+++ b/catalog/admin/files.php~
@@ -0,0 +1,205 @@
+db ();
+getint ("fk_books");
+getstr ("filemask");
+
+pageheader ("Files for EBook #$fk_books");
+
+p ("Careful! If you change the Ebook number you link the file to a different Ebook.");
+p ("Note: you cannot add files to the database. " .
+ "That is done automagically by a nightly cron job.");
+
+p ("Goto Edit Book Page — " .
+ "etext/${fk_books}\">Goto Bibrec Page ");
+
+function mk_options ($name, $options, $option) {
+ $ret = "";
+ foreach ($options as $value => $opt) {
+ $selected = ($opt == $option) ? " selected=\"selected\"" : "";
+ $ret .= "$opt \n";
+ }
+ return "\n" . $ret . " \n";
+}
+
+$filetypes[null] = "unknown";
+$db->Exec ("select * from filetypes order by filetype");
+if ($db->FirstRow ()) {
+ do {
+ $filetypes[$db->Get ("pk")] = $db->Get ("filetype");
+ } while ($db->NextRow ());
+}
+
+$compressions[null] = "unknown";
+$db->Exec ("select * from compressions order by compression");
+if ($db->FirstRow ()) {
+ do {
+ $compressions[$db->Get ("pk")] = $db->Get ("compression");
+ } while ($db->NextRow ());
+}
+
+$encodings[null] = "unknown";
+$db->Exec ("select * from encodings order by pk");
+if ($db->FirstRow ()) {
+ do {
+ $encodings[$db->Get ("pk")] = $db->Get ("pk");
+ } while ($db->NextRow ());
+}
+
+class HeadColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "", "narrow");
+ }
+ function Data ($db) {
+ $filename = $db->get ("filename");
+ if (preg_match ("/\.zip$/i", $filename))
+ return "Dir ";
+ return "Head ";
+ }
+}
+
+class CharsetColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "", "narrow");
+ }
+ function Data ($db) {
+ $filename = $db->get ("filename");
+ if (preg_match ("/\.zip$/i", $filename))
+ return " ";
+ return "Guess ";
+ }
+}
+
+class SizeColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "Size", "pgdbfilessize");
+ }
+ function Header () {
+ return "Size ";
+ }
+ function Data ($db) {
+ return "" . human_readable_size ($db->get ("filesize")) . " ";
+ }
+}
+
+class FiletypeColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "File Type", "pgdbfilesfiletype");
+ }
+ function Data ($db) {
+ global $filetypes;
+ return "" . mk_options ("fk_filetypes", $filetypes, $db->get ("filetype")) . " ";
+ }
+}
+
+class CompressionColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "Compression", "pgdbfilescompression");
+ }
+ function Data ($db) {
+ global $compressions;
+ return "" . mk_options ("fk_compressions", $compressions, $db->get ("compression")) . " ";
+ }
+}
+
+class EncodingColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "Encoding", "pgdbfilesencoding");
+ }
+ function Data ($db) {
+ global $encodings;
+ return "" . mk_options ("fk_encodings", $encodings, $db->get ("fk_encodings")) . " ";
+ }
+}
+
+class ObsoletedColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "Obs.", "pgdbfilesobsoleted");
+ }
+ function Data ($db) {
+ $obs = $db->get ("obsoleted", SQLINT) ? " checked=\"checked\"" : "";
+ $pk = $db->get ("pk", SQLINT);
+ return " ";
+ }
+}
+
+form_open_get ();
+echo ("Enter Perl RegExp: eg. /12345/");
+form_relay ("fk_books");
+form_submit ("Reload");
+form_close ();
+
+// Files for book
+$prefix = "AddColumn (" ", "", "narrow");
+$t->AddColumn ("$prefix=edit&fk_files=#pk#\">Edit ", "", "narrow");
+$t->AddColumnObject (new HeadColumn ());
+$t->AddColumn ("Bug ", "", "narrow");
+$t->AddColumn ("downloadbase/#filename#\">#filename# " .
+ " ",
+ "Filename");
+$t->AddColumn (" " .
+ " ", "EBook");
+$t->AddColumn (" ", "Edition");
+$t->AddColumnObject (new ObsoletedColumn ());
+$t->AddColumnObject (new FiletypeColumn ());
+$t->AddColumnObject (new EncodingColumn ());
+$t->AddColumnObject (new CharsetColumn ());
+$t->AddColumnObject (new CompressionColumn ());
+$t->AddColumnObject (new SizeColumn ());
+
+/////////////////////////////////////////////////////////////////////////////////
+// Generate list of candidate files
+//
+
+/*if (empty ($filemask)) {
+ if ($fk_books > 10000) {
+ $filemask = "/${fk_books}[.-]";
+ } else {
+ $db->Exec ("select * from books where pk = $fk_books");
+ $filemask = $db->Get ("filemask");
+ if (!empty ($filemask)) {
+ $filemask = preg_replace ("/\./", "\\.", $filemask);
+ $filemask = preg_replace ("/x+/", ".*", $filemask);
+ $filemask = preg_replace ("/^[?]/", "[78]", $filemask);
+ }
+ }
+}*/
+
+$sql = "select files.pk as pk, fk_books, filename, edition, obsoleted, filetype, " .
+ "compression, fk_encodings, filesize " .
+ "from files left join filetypes on files.fk_filetypes = filetypes.pk " .
+ "left join compressions on files.fk_compressions = compressions.pk " .
+ "where " . (empty ($filemask) ? "" : "filename ~ '$filemask' or ") .
+ "(fk_books = $fk_books and diskstatus = 0) " .
+ "order by (fk_books = $fk_books) desc, obsoleted, " .
+ "filetype, fk_encodings, compression, filename;";
+
+$db->exec ($sql);
+
+form_open ("files2");
+$t->limit = 100;
+$t->PrintTable ($db, "Files Linked to Book $fk_books or Matching RegExp: $filemask", "pgdbfiles");
+form_relay ("fk_books");
+form_relay ("filemask");
+form_submit ("Update Checked File Entries");
+form_close ();
+
+p ("To be implemented: functions for viewing bottom n lines from file, check
+for character encoding, diff files, look into zips. In my copious free time.");
+
+pagefooter ();
+
+// Local Variables:
+// mode:php
+// coding:utf-8-unix
+// fill-column: 75
+// End:
+
+?>
diff --git a/catalog/admin/files2.php b/catalog/admin/files2.php
new file mode 100644
index 0000000..2d010f3
--- /dev/null
+++ b/catalog/admin/files2.php
@@ -0,0 +1,71 @@
+db ();
+$db->logger = new logger ();
+
+getint ("fk_files");
+getint ("fk_books");
+getstr ("filemask");
+
+getarray ("pks_update");
+getarray ("pks");
+getarray ("fk_books_a");
+getarray ("filenames");
+getarray ("editions");
+getarray ("obsoleteds");
+getarray ("fk_filetypes");
+getarray ("fk_compressions");
+getarray ("fk_encodings");
+
+foreach ($pks as $pk) {
+ $fk_book = array_shift ($fk_books_a);
+ $filename = array_shift ($filenames);
+ $edition = array_shift ($editions);
+ $fk_filetype = array_shift ($fk_filetypes);
+ $fk_compression = array_shift ($fk_compressions);
+ $fk_encoding = array_shift ($fk_encodings);
+
+ // p ("file: $pk $filename $fk_book $fk_filetype $fk_compression $fk_encoding");
+
+ if (!in_array ($pk, $pks_update))
+ continue;
+
+ $sql_pk = $db->f ($pk, SQLINT);
+ $sql_fk_books = $db->f ($fk_book, SQLINT);
+ $sql_edition = $db->f ($edition, SQLINT);
+ $sql_obsoleted = $db->f ($obsoleted, SQLINT);
+ $sql_fk_filetypes = $db->f ($fk_filetype, SQLCHAR);
+ $sql_fk_compressions = $db->f ($fk_compression, SQLCHAR);
+ $sql_fk_encodings = $db->f ($fk_encoding, SQLCHAR);
+ $sql_obsoleted = in_array ($pk, $obsoleteds) ? 1 : 0;
+
+ $sql = "update files set " .
+ "fk_books = $sql_fk_books, " .
+ "edition = $sql_edition, " .
+ "obsoleted = $sql_obsoleted, " .
+ "fk_filetypes = $sql_fk_filetypes, " .
+ "fk_compressions = $sql_fk_compressions, " .
+ "fk_encodings = $sql_fk_encodings " .
+ "where pk = $sql_pk";
+
+ // p ($sql);
+
+ if ($db->exec ($sql)) {
+ msg ("File $filename updated !");
+ } else {
+ error_msg ("Could not update file $filename !");
+ }
+}
+
+p ("Back to Book Files ");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/files2.php~ b/catalog/admin/files2.php~
new file mode 100644
index 0000000..e1211af
--- /dev/null
+++ b/catalog/admin/files2.php~
@@ -0,0 +1,70 @@
+db ();
+$db->logger = new logger ();
+
+getint ("fk_files");
+getint ("fk_books");
+getstr ("filemask");
+
+getarray ("pks_update");
+getarray ("pks");
+getarray ("fk_books_a");
+getarray ("filenames");
+getarray ("editions");
+getarray ("obsoleteds");
+getarray ("fk_filetypes");
+getarray ("fk_compressions");
+getarray ("fk_encodings");
+
+foreach ($pks as $pk) {
+ $fk_book = array_shift ($fk_books_a);
+ $filename = array_shift ($filenames);
+ $edition = array_shift ($editions);
+ $fk_filetype = array_shift ($fk_filetypes);
+ $fk_compression = array_shift ($fk_compressions);
+ $fk_encoding = array_shift ($fk_encodings);
+
+ // p ("file: $pk $filename $fk_book $fk_filetype $fk_compression $fk_encoding");
+
+ if (!in_array ($pk, $pks_update))
+ continue;
+
+ $sql_pk = $db->f ($pk, SQLINT);
+ $sql_fk_books = $db->f ($fk_book, SQLINT);
+ $sql_edition = $db->f ($edition, SQLINT);
+ $sql_obsoleted = $db->f ($obsoleted, SQLINT);
+ $sql_fk_filetypes = $db->f ($fk_filetype, SQLCHAR);
+ $sql_fk_compressions = $db->f ($fk_compression, SQLCHAR);
+ $sql_fk_encodings = $db->f ($fk_encoding, SQLCHAR);
+ $sql_obsoleted = in_array ($pk, $obsoleteds) ? 1 : 0;
+
+ $sql = "update files set " .
+ "fk_books = $sql_fk_books, " .
+ "edition = $sql_edition, " .
+ "obsoleted = $sql_obsoleted, " .
+ "fk_filetypes = $sql_fk_filetypes, " .
+ "fk_compressions = $sql_fk_compressions, " .
+ "fk_encodings = $sql_fk_encodings " .
+ "where pk = $sql_pk";
+
+ // p ($sql);
+
+ if ($db->exec ($sql)) {
+ msg ("File $filename updated !");
+ } else {
+ error_msg ("Could not update file $filename !");
+ }
+}
+
+p ("Back to Book Files ");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/fix-fileinfos.php b/catalog/admin/fix-fileinfos.php
new file mode 100644
index 0000000..2dc08dc
--- /dev/null
+++ b/catalog/admin/fix-fileinfos.php
@@ -0,0 +1,35 @@
+db ();
+
+set_time_limit (0);
+
+$cnt = 0;
+$db->Exec ("select filename from files where diskstatus = 5 order by filename");
+if ($db->FirstRow ()) {
+ do {
+ $filename = $db->Get ("filename", SQLCHAR);
+ $infofile = "$config->privateroot/fileinfo/$filename.info";
+ echo ("unlinking $infofile\n");
+ if (unlink ($infofile))
+ $cnt++;
+ } while ($db->NextRow ());
+}
+
+echo ("unlinked $cnt files.\n");
+
+echo ("Done.\n");
+
+?>
diff --git a/catalog/admin/fix-fileinfos.php~ b/catalog/admin/fix-fileinfos.php~
new file mode 100644
index 0000000..f3aced7
--- /dev/null
+++ b/catalog/admin/fix-fileinfos.php~
@@ -0,0 +1,34 @@
+db ();
+
+set_time_limit (0);
+
+$cnt = 0;
+$db->Exec ("select filename from files where diskstatus = 5 order by filename");
+if ($db->FirstRow ()) {
+ do {
+ $filename = $db->Get ("filename", SQLCHAR);
+ $infofile = "$config->privateroot/fileinfo/$filename.info";
+ echo ("unlinking $infofile\n");
+ if (unlink ($infofile))
+ $cnt++;
+ } while ($db->NextRow ());
+}
+
+echo ("unlinked $cnt files.\n");
+
+echo ("Done.\n");
+
+?>
diff --git a/catalog/admin/fixcontents.php b/catalog/admin/fixcontents.php
new file mode 100644
index 0000000..fad7407
--- /dev/null
+++ b/catalog/admin/fixcontents.php
@@ -0,0 +1,32 @@
+db ();
+$db2 = $config->db ();
+
+$db->exec ("select * from attributes where fk_attriblist = 505 and text ~ '^Contents:' order by text");
+
+if ($db->FirstRow ()) {
+ do {
+ $title = $db->get ("text", SQLCHAR);
+ $orig = $title;
+ $pk = $db->get ("pk", SQLINT);
+ $nonfiling = "";
+
+ $title = preg_replace ("/^Contents: /", "", $title);
+
+ if ($title != $orig) {
+ $sql_title = $db-> f ($title, SQLCHAR);
+ echo ("update attributes set text = $sql_title where pk = $pk\n");
+ $db2->exec ("update attributes set text = $sql_title where pk = $pk");
+ }
+
+ } while ($db->NextRow ());
+}
+
+?>
diff --git a/catalog/admin/fixcontents.php~ b/catalog/admin/fixcontents.php~
new file mode 100644
index 0000000..f87aaab
--- /dev/null
+++ b/catalog/admin/fixcontents.php~
@@ -0,0 +1,31 @@
+db ();
+$db2 = $config->db ();
+
+$db->exec ("select * from attributes where fk_attriblist = 505 and text ~ '^Contents:' order by text");
+
+if ($db->FirstRow ()) {
+ do {
+ $title = $db->get ("text", SQLCHAR);
+ $orig = $title;
+ $pk = $db->get ("pk", SQLINT);
+ $nonfiling = "";
+
+ $title = preg_replace ("/^Contents: /", "", $title);
+
+ if ($title != $orig) {
+ $sql_title = $db-> f ($title, SQLCHAR);
+ echo ("update attributes set text = $sql_title where pk = $pk\n");
+ $db2->exec ("update attributes set text = $sql_title where pk = $pk");
+ }
+
+ } while ($db->NextRow ());
+}
+
+?>
diff --git a/catalog/admin/fixentities.php b/catalog/admin/fixentities.php
new file mode 100644
index 0000000..eddb9b8
--- /dev/null
+++ b/catalog/admin/fixentities.php
@@ -0,0 +1,95 @@
+db ();
+$db2 = $config->db ();
+
+$trans = get_html_translation_table (HTML_ENTITIES);
+$trans = array_flip ($trans);
+array_walk ($trans, create_function ('&$v,$k', '$v = utf8_encode ($v);'));
+$trans['—'] = chr (0xe2) . chr (0x80) . chr (0x94);
+$trans['–'] = chr (0xe2) . chr (0x80) . chr (0x93);
+
+
+$cnt = 0;
+
+$db->exec ("select * from titles order by title");
+
+if ($db->FirstRow ()) {
+ do {
+ $title = $db->get ("title", SQLCHAR);
+ $orig = $title;
+ $pk = $db->get ("pk", SQLINT);
+
+ $title = strtr ($title, $trans);
+
+ if ($title != $orig) {
+ $sql_title = $db-> f ($title, SQLCHAR);
+ echo ("update titles set title = $sql_title where pk = $pk\n");
+ $db2->exec ("update titles set title = $sql_title where pk = $pk");
+ $cnt++;
+ }
+
+ } while ($db->NextRow ());
+}
+
+echo ("$cnt title changes\n");
+
+
+
+$cnt = 0;
+
+$db->exec ("select * from authors order by author");
+
+if ($db->FirstRow ()) {
+ do {
+ $author = $db->get ("author", SQLCHAR);
+ $orig = $author;
+ $pk = $db->get ("pk", SQLINT);
+
+ $author = strtr ($author, $trans);
+
+ if ($author != $orig) {
+ $sql_author = $db-> f ($author, SQLCHAR);
+ echo ("update authors set author = $sql_author where pk = $pk\n");
+ $db2->exec ("update authors set author = $sql_author where pk = $pk");
+ $cnt++;
+ }
+
+ } while ($db->NextRow ());
+}
+
+echo ("$cnt author changes\n");
+
+
+
+$cnt = 0;
+
+$db->exec ("select * from aliases order by alias");
+
+if ($db->FirstRow ()) {
+ do {
+ $alias = $db->get ("alias", SQLCHAR);
+ $orig = $alias;
+ $pk = $db->get ("pk", SQLINT);
+
+ $alias = strtr ($alias, $trans);
+
+ if ($alias != $orig) {
+ $sql_alias = $db-> f ($alias, SQLCHAR);
+ echo ("update aliases set alias = $sql_alias where pk = $pk\n");
+ $db2->exec ("update aliases set alias = $sql_alias where pk = $pk");
+ $cnt++;
+ }
+
+ } while ($db->NextRow ());
+}
+
+echo ("$cnt alias changes\n");
+
+?>
diff --git a/catalog/admin/fixentities.php~ b/catalog/admin/fixentities.php~
new file mode 100644
index 0000000..04b9973
--- /dev/null
+++ b/catalog/admin/fixentities.php~
@@ -0,0 +1,94 @@
+db ();
+$db2 = $config->db ();
+
+$trans = get_html_translation_table (HTML_ENTITIES);
+$trans = array_flip ($trans);
+array_walk ($trans, create_function ('&$v,$k', '$v = utf8_encode ($v);'));
+$trans['—'] = chr (0xe2) . chr (0x80) . chr (0x94);
+$trans['–'] = chr (0xe2) . chr (0x80) . chr (0x93);
+
+
+$cnt = 0;
+
+$db->exec ("select * from titles order by title");
+
+if ($db->FirstRow ()) {
+ do {
+ $title = $db->get ("title", SQLCHAR);
+ $orig = $title;
+ $pk = $db->get ("pk", SQLINT);
+
+ $title = strtr ($title, $trans);
+
+ if ($title != $orig) {
+ $sql_title = $db-> f ($title, SQLCHAR);
+ echo ("update titles set title = $sql_title where pk = $pk\n");
+ $db2->exec ("update titles set title = $sql_title where pk = $pk");
+ $cnt++;
+ }
+
+ } while ($db->NextRow ());
+}
+
+echo ("$cnt title changes\n");
+
+
+
+$cnt = 0;
+
+$db->exec ("select * from authors order by author");
+
+if ($db->FirstRow ()) {
+ do {
+ $author = $db->get ("author", SQLCHAR);
+ $orig = $author;
+ $pk = $db->get ("pk", SQLINT);
+
+ $author = strtr ($author, $trans);
+
+ if ($author != $orig) {
+ $sql_author = $db-> f ($author, SQLCHAR);
+ echo ("update authors set author = $sql_author where pk = $pk\n");
+ $db2->exec ("update authors set author = $sql_author where pk = $pk");
+ $cnt++;
+ }
+
+ } while ($db->NextRow ());
+}
+
+echo ("$cnt author changes\n");
+
+
+
+$cnt = 0;
+
+$db->exec ("select * from aliases order by alias");
+
+if ($db->FirstRow ()) {
+ do {
+ $alias = $db->get ("alias", SQLCHAR);
+ $orig = $alias;
+ $pk = $db->get ("pk", SQLINT);
+
+ $alias = strtr ($alias, $trans);
+
+ if ($alias != $orig) {
+ $sql_alias = $db-> f ($alias, SQLCHAR);
+ echo ("update aliases set alias = $sql_alias where pk = $pk\n");
+ $db2->exec ("update aliases set alias = $sql_alias where pk = $pk");
+ $cnt++;
+ }
+
+ } while ($db->NextRow ());
+}
+
+echo ("$cnt alias changes\n");
+
+?>
diff --git a/catalog/admin/fixorphans.php b/catalog/admin/fixorphans.php
new file mode 100644
index 0000000..37a9958
--- /dev/null
+++ b/catalog/admin/fixorphans.php
@@ -0,0 +1,42 @@
+db ();
+$db2 = $config->db ();
+
+function getno ($filename) {
+ $etext_number = null;
+ if (preg_match ("/^(?:\d\/)+(\d{2,5})/", $filename, $matches)) {
+ $etext_number = intval ($matches[1]);
+ // double-check this
+ $dir = etext2dir ($etext_number);
+ if (strncmp ("$filename/", $dir, strlen ($dir)))
+ $etext_number = null;
+ } elseif (preg_match ("/^([1-9])$/", $filename, $matches)) {
+ $etext_number = intval ($matches[1]);
+ }
+ return $etext_number;
+}
+
+$db->exec ("select pk, filename from files where fk_books is null and diskstatus != 2");
+if ($db->FirstRow ()) {
+ do {
+ $pk = $db->get ("pk", SQLINT);
+ $filename = $db->get ("filename", SQLCHAR);
+ $no = getno ($filename);
+ if (!empty ($no)) {
+ echo ("$no $filename\n");
+ $db2->exec ("update files set fk_books = $no where pk = $pk");
+ }
+ } while ($db->Nextrow ());
+}
+
+
+?>
diff --git a/catalog/admin/fixorphans.php~ b/catalog/admin/fixorphans.php~
new file mode 100644
index 0000000..c60e11d
--- /dev/null
+++ b/catalog/admin/fixorphans.php~
@@ -0,0 +1,41 @@
+db ();
+$db2 = $config->db ();
+
+function getno ($filename) {
+ $etext_number = null;
+ if (preg_match ("/^(?:\d\/)+(\d{2,5})/", $filename, $matches)) {
+ $etext_number = intval ($matches[1]);
+ // double-check this
+ $dir = etext2dir ($etext_number);
+ if (strncmp ("$filename/", $dir, strlen ($dir)))
+ $etext_number = null;
+ } elseif (preg_match ("/^([1-9])$/", $filename, $matches)) {
+ $etext_number = intval ($matches[1]);
+ }
+ return $etext_number;
+}
+
+$db->exec ("select pk, filename from files where fk_books is null and diskstatus != 2");
+if ($db->FirstRow ()) {
+ do {
+ $pk = $db->get ("pk", SQLINT);
+ $filename = $db->get ("filename", SQLCHAR);
+ $no = getno ($filename);
+ if (!empty ($no)) {
+ echo ("$no $filename\n");
+ $db2->exec ("update files set fk_books = $no where pk = $pk");
+ }
+ } while ($db->Nextrow ());
+}
+
+
+?>
diff --git a/catalog/admin/fixtitles.php b/catalog/admin/fixtitles.php
new file mode 100644
index 0000000..fbf17de
--- /dev/null
+++ b/catalog/admin/fixtitles.php
@@ -0,0 +1,61 @@
+db ();
+$db2 = $config->db ();
+
+$articles = array ("The", "A", "An", "La", "Le", "Der", "Die", "Das");
+$prepositions = array ("The", "A", "An", "In", "From", "To", "On", "Of", "Out", "For",
+ "Into", "At", "About", "And", "Or", "But", "With", "Under", "Over", "As");
+
+foreach ($prepositions as $s) {
+ $search[] = " $s ";
+ $replace[] = strtolower (" $s ");
+}
+
+$search[] = "--";
+$replace[] = "—";
+$search[] = "Vol.";
+$replace[] = "Volume";
+$search[] = "vol.";
+$replace[] = "Volume";
+
+
+$db->exec ("select * from titles order by title");
+
+if ($db->FirstRow ()) {
+ do {
+ $title = $db->get ("title", SQLCHAR);
+ $orig = $title;
+ $pk = $db->get ("pk", SQLINT);
+ $nonfiling = "";
+
+ if (preg_match ("/Reserved:/i", $title))
+ continue;
+
+ foreach ($articles as $article) {
+ if (preg_match ("/, $article\$/", $title)) {
+ $title = preg_replace ("/, $article\$/", "", $title);
+ $title = "$article $title";
+ $nonfiling = ", nonfiling = " . strlen ("$article ");
+ break;
+ }
+ }
+
+ $title = str_replace ($search, $replace, $title);
+
+ if ($title != $orig) {
+ $sql_title = $db-> f ($title, SQLCHAR);
+ echo ("update titles set title = $sql_title$nonfiling where pk = $pk\n");
+ $db2->exec ("update titles set title = $sql_title$nonfiling where pk = $pk");
+ }
+
+ } while ($db->NextRow ());
+}
+
+?>
diff --git a/catalog/admin/fixtitles.php~ b/catalog/admin/fixtitles.php~
new file mode 100644
index 0000000..5b004a0
--- /dev/null
+++ b/catalog/admin/fixtitles.php~
@@ -0,0 +1,60 @@
+db ();
+$db2 = $config->db ();
+
+$articles = array ("The", "A", "An", "La", "Le", "Der", "Die", "Das");
+$prepositions = array ("The", "A", "An", "In", "From", "To", "On", "Of", "Out", "For",
+ "Into", "At", "About", "And", "Or", "But", "With", "Under", "Over", "As");
+
+foreach ($prepositions as $s) {
+ $search[] = " $s ";
+ $replace[] = strtolower (" $s ");
+}
+
+$search[] = "--";
+$replace[] = "—";
+$search[] = "Vol.";
+$replace[] = "Volume";
+$search[] = "vol.";
+$replace[] = "Volume";
+
+
+$db->exec ("select * from titles order by title");
+
+if ($db->FirstRow ()) {
+ do {
+ $title = $db->get ("title", SQLCHAR);
+ $orig = $title;
+ $pk = $db->get ("pk", SQLINT);
+ $nonfiling = "";
+
+ if (preg_match ("/Reserved:/i", $title))
+ continue;
+
+ foreach ($articles as $article) {
+ if (preg_match ("/, $article\$/", $title)) {
+ $title = preg_replace ("/, $article\$/", "", $title);
+ $title = "$article $title";
+ $nonfiling = ", nonfiling = " . strlen ("$article ");
+ break;
+ }
+ }
+
+ $title = str_replace ($search, $replace, $title);
+
+ if ($title != $orig) {
+ $sql_title = $db-> f ($title, SQLCHAR);
+ echo ("update titles set title = $sql_title$nonfiling where pk = $pk\n");
+ $db2->exec ("update titles set title = $sql_title$nonfiling where pk = $pk");
+ }
+
+ } while ($db->NextRow ());
+}
+
+?>
diff --git a/catalog/admin/fixurls.php b/catalog/admin/fixurls.php
new file mode 100644
index 0000000..70e506e
--- /dev/null
+++ b/catalog/admin/fixurls.php
@@ -0,0 +1,51 @@
+db ();
+$db2 = $config->db ();
+
+$cnt = 0;
+
+$db->exec ("select * from author_urls order by url");
+
+if ($db->FirstRow ()) {
+ do {
+ $url = $db->get ("url", SQLCHAR);
+ $orig = $url;
+ $pk = $db->get ("pk", SQLINT);
+
+ $url = rawurldecode ($url);
+ if ($url == $orig) {
+ continue;
+ }
+
+ // echo ("$orig\n");
+
+ if (utf8_encode (utf8_decode ($url)) != $url) {
+ // not an utf-8 string
+ if (($url = iconv ("ISO-8859-1", "UTF-8", $url)) === FALSE) {
+ // nor an iso-8859-1 one ???
+ // punt on this one
+ continue;
+ }
+ }
+
+ // echo ("$url\n");
+
+ if ($url != $orig) {
+ $sql_url = $db-> f ($url, SQLCHAR);
+ echo ("update author_urls set url = $sql_url where pk = $pk\n");
+ $db2->exec ("update author_urls set url = $sql_url where pk = $pk;");
+ $cnt++;
+ }
+
+ } while ($db->NextRow ());
+}
+
+echo ("$cnt url changes\n");
+?>
diff --git a/catalog/admin/fixurls.php~ b/catalog/admin/fixurls.php~
new file mode 100644
index 0000000..773c00d
--- /dev/null
+++ b/catalog/admin/fixurls.php~
@@ -0,0 +1,50 @@
+db ();
+$db2 = $config->db ();
+
+$cnt = 0;
+
+$db->exec ("select * from author_urls order by url");
+
+if ($db->FirstRow ()) {
+ do {
+ $url = $db->get ("url", SQLCHAR);
+ $orig = $url;
+ $pk = $db->get ("pk", SQLINT);
+
+ $url = rawurldecode ($url);
+ if ($url == $orig) {
+ continue;
+ }
+
+ // echo ("$orig\n");
+
+ if (utf8_encode (utf8_decode ($url)) != $url) {
+ // not an utf-8 string
+ if (($url = iconv ("ISO-8859-1", "UTF-8", $url)) === FALSE) {
+ // nor an iso-8859-1 one ???
+ // punt on this one
+ continue;
+ }
+ }
+
+ // echo ("$url\n");
+
+ if ($url != $orig) {
+ $sql_url = $db-> f ($url, SQLCHAR);
+ echo ("update author_urls set url = $sql_url where pk = $pk\n");
+ $db2->exec ("update author_urls set url = $sql_url where pk = $pk;");
+ $cnt++;
+ }
+
+ } while ($db->NextRow ());
+}
+
+echo ("$cnt url changes\n");
+?>
diff --git a/catalog/admin/gutindex-parser.php b/catalog/admin/gutindex-parser.php
new file mode 100644
index 0000000..25dd90e
--- /dev/null
+++ b/catalog/admin/gutindex-parser.php
@@ -0,0 +1,82 @@
+documentroot/dirs/GUTINDEX.ALL.iso-8859-1.txt";
+
+$fp = fopen ($gutindex, "r");
+if (!$fp) {
+ die ("cannot open $gutindex");
+}
+
+$db = $config->db ();
+
+$pks = array ();
+$gutindex = array ();
+
+$db->exec ("select * from books");
+if ($db->FirstRow ()) {
+ do {
+ $pk = $db->get ("pk", SQLINT);
+ $pks[$pk] = 1;
+ } while ($db->NextRow ());
+}
+
+$mode = 0;
+$pk = 0;
+$buffer = "";
+
+while (!feof ($fp)) {
+ $line = fgets ($fp);
+ $tline = trim ($line);
+
+ switch ($mode) {
+ case 0:
+ if (preg_match ("/^~ ~ ~ ~/", $tline, $matches)) {
+ $mode = 1;
+ }
+ break;
+ case 1:
+ if ($tline == "<==End of GUTINDEX.ALL==>") {
+ $mode = 0;
+ break;
+ }
+ // fall thru
+ case 2:
+ if (preg_match ("/(\d+)[-BC]?$/", $tline, $matches)) {
+ if (!preg_match ("/GUTINDEX/", $tline)) {
+ $gutindex[$pk] = $buffer;
+ $buffer = utf8_encode ($line);
+ $mode = 2;
+ $pk = intval ($matches [1]);
+ break;
+ }
+ }
+ if (empty ($tline) || preg_match ("/\*$/", $tline)) {
+ $gutindex[$pk] = $buffer;
+ $buffer = "";
+ $mode = 1;
+ $pk = 0;
+ break;
+ }
+ $buffer .= utf8_encode ($line);
+ break;
+ }
+}
+
+fclose ($fp);
+
+foreach ($gutindex as $pk => $book) {
+ if (isset ($pks[$pk])) {
+ $sql_book = $db->f ($book, SQLCHAR);
+ $db->exec ("update books set gutindex = $sql_book where pk = $pk");
+ $db->exec ("commit");
+ // echo ("Updated #$pk\n");
+ }
+}
+
+?>
diff --git a/catalog/admin/gutindex-parser.php~ b/catalog/admin/gutindex-parser.php~
new file mode 100644
index 0000000..d0e0433
--- /dev/null
+++ b/catalog/admin/gutindex-parser.php~
@@ -0,0 +1,81 @@
+documentroot/dirs/GUTINDEX.ALL.iso-8859-1.txt";
+
+$fp = fopen ($gutindex, "r");
+if (!$fp) {
+ die ("cannot open $gutindex");
+}
+
+$db = $config->db ();
+
+$pks = array ();
+$gutindex = array ();
+
+$db->exec ("select * from books");
+if ($db->FirstRow ()) {
+ do {
+ $pk = $db->get ("pk", SQLINT);
+ $pks[$pk] = 1;
+ } while ($db->NextRow ());
+}
+
+$mode = 0;
+$pk = 0;
+$buffer = "";
+
+while (!feof ($fp)) {
+ $line = fgets ($fp);
+ $tline = trim ($line);
+
+ switch ($mode) {
+ case 0:
+ if (preg_match ("/^~ ~ ~ ~/", $tline, $matches)) {
+ $mode = 1;
+ }
+ break;
+ case 1:
+ if ($tline == "<==End of GUTINDEX.ALL==>") {
+ $mode = 0;
+ break;
+ }
+ // fall thru
+ case 2:
+ if (preg_match ("/(\d+)[-BC]?$/", $tline, $matches)) {
+ if (!preg_match ("/GUTINDEX/", $tline)) {
+ $gutindex[$pk] = $buffer;
+ $buffer = utf8_encode ($line);
+ $mode = 2;
+ $pk = intval ($matches [1]);
+ break;
+ }
+ }
+ if (empty ($tline) || preg_match ("/\*$/", $tline)) {
+ $gutindex[$pk] = $buffer;
+ $buffer = "";
+ $mode = 1;
+ $pk = 0;
+ break;
+ }
+ $buffer .= utf8_encode ($line);
+ break;
+ }
+}
+
+fclose ($fp);
+
+foreach ($gutindex as $pk => $book) {
+ if (isset ($pks[$pk])) {
+ $sql_book = $db->f ($book, SQLCHAR);
+ $db->exec ("update books set gutindex = $sql_book where pk = $pk");
+ $db->exec ("commit");
+ // echo ("Updated #$pk\n");
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/catalog/admin/head.php b/catalog/admin/head.php
new file mode 100644
index 0000000..3b690b5
--- /dev/null
+++ b/catalog/admin/head.php
@@ -0,0 +1,29 @@
+ 0)) {
+ $buffer = fgets ($hd, 4096);
+ echo ($buffer);
+ --$lines;
+}
+fclose ($hd);
+
+?>
diff --git a/catalog/admin/head.php~ b/catalog/admin/head.php~
new file mode 100644
index 0000000..738b51e
--- /dev/null
+++ b/catalog/admin/head.php~
@@ -0,0 +1,27 @@
+ 0)) {
+ $buffer = fgets ($hd, 4096);
+ echo ($buffer);
+ --$lines;
+}
+fclose ($hd);
+
+?>
diff --git a/catalog/admin/index.php b/catalog/admin/index.php
new file mode 100644
index 0000000..5487662
--- /dev/null
+++ b/catalog/admin/index.php
@@ -0,0 +1,139 @@
+
+
+Read This First
+
+Entities and relations
+
+In this catalog you will find 2 different recurring concepts:
+
+
+ the entity
+ the relation (or link).
+
+
+Don't confuse database link (relation) with HTML-link (underlined
+text to click.)
+
+Book, Author, Subject, Language and LoC Class are entities.
+
+Book-Author, Book-Subject, Book-Language and Book-LoC Class are
+relations.
+
+You can add , edit and
+delete entities. Add an author, add a book. You can
+create and remove links between existing entities (link
+and unlink entities). Link an author to a book.
+Remember: to link you have to create the entities first. Of course, if
+you find that the entity already exists in the catalog, you should not
+create it again.
+
+The advantage of the entity and link concept is that you have to enter data
+only once. Every author exists only once in the database. You have to enter
+the date of birth and of death only once. You have to enter the pseudonyms
+and different orthografies of the name only once. If you find an error, you
+have to fix it only once.
+
+To add a new book:
+
+
+ Search for the author. If you don't find her, add her.
+ Enter the book data.
+ Link the author to the book.
+
+
+HTML-Links and Buttons
+
+Clicking on a HTML-link will never alter any data.
+
+Clicking on a button with: add, edit, delete, link or unlink in the
+caption will alter data. (There are some other buttons though that don't
+alter data.)
+
+Starting points
+
+Reports / Statistics
+
+
+
+List all the MARC attributes/tags/codes currently in the system,
+ and how many records use them; and see the usage.
+
+
+
+List all the books which do not have any Subjects and/or LoCCs attached to them,
+ sorted by Etext#, i.e. least recent first.
+
+
+
+ Various statistics, mainly focused on authors.
+
+
+
+A list of author entries that have no books attached to them, which usually means
+ they should be deleted.
+
+
+
+MARC attributes whose values are not unique.
+
+User Tasks
+
+
+
+Manage authors, author aliases and interesting URLs for author.
+
+
+
+Manage books, book-titles, book-authors, book-subjects, book-languages
+and book-LoC classes.
+
+
+
+Select a batch of titles by regular expression and
+edit them all in one place.
+
+
+
+Manage subjects.
+
+
+
+Manage categories.
+
+
+
+Manage LoC Classes.
+
+
+
+Manage Languages. You will seldom need this, as most languages are
+already entered.
+
+
+
+Change your password. You'll probably have to login again.
+
+Administrator Tasks
+
+Requires Administrator rights.
+
+
+
+Manage users. Add, remove, reset password etc.
+
+
+
+Manage mirrors.
+
+
+
diff --git a/catalog/admin/index.php~ b/catalog/admin/index.php~
new file mode 100644
index 0000000..fbf1307
--- /dev/null
+++ b/catalog/admin/index.php~
@@ -0,0 +1,137 @@
+
+
+Read This First
+
+Entities and relations
+
+In this catalog you will find 2 different recurring concepts:
+
+
+ the entity
+ the relation (or link).
+
+
+Don't confuse database link (relation) with HTML-link (underlined
+text to click.)
+
+Book, Author, Subject, Language and LoC Class are entities.
+
+Book-Author, Book-Subject, Book-Language and Book-LoC Class are
+relations.
+
+You can add , edit and
+delete entities. Add an author, add a book. You can
+create and remove links between existing entities (link
+and unlink entities). Link an author to a book.
+Remember: to link you have to create the entities first. Of course, if
+you find that the entity already exists in the catalog, you should not
+create it again.
+
+The advantage of the entity and link concept is that you have to enter data
+only once. Every author exists only once in the database. You have to enter
+the date of birth and of death only once. You have to enter the pseudonyms
+and different orthografies of the name only once. If you find an error, you
+have to fix it only once.
+
+To add a new book:
+
+
+ Search for the author. If you don't find her, add her.
+ Enter the book data.
+ Link the author to the book.
+
+
+HTML-Links and Buttons
+
+Clicking on a HTML-link will never alter any data.
+
+Clicking on a button with: add, edit, delete, link or unlink in the
+caption will alter data. (There are some other buttons though that don't
+alter data.)
+
+Starting points
+
+Reports / Statistics
+
+
+
+List all the MARC attributes/tags/codes currently in the system,
+ and how many records use them; and see the usage.
+
+
+
+List all the books which do not have any Subjects and/or LoCCs attached to them,
+ sorted by Etext#, i.e. least recent first.
+
+
+
+ Various statistics, mainly focused on authors.
+
+
+
+A list of author entries that have no books attached to them, which usually means
+ they should be deleted.
+
+
+
+MARC attributes whose values are not unique.
+
+User Tasks
+
+
+
+Manage authors, author aliases and interesting URLs for author.
+
+
+
+Manage books, book-titles, book-authors, book-subjects, book-languages
+and book-LoC classes.
+
+
+
+Select a batch of titles by regular expression and
+edit them all in one place.
+
+
+
+Manage subjects.
+
+
+
+Manage categories.
+
+
+
+Manage LoC Classes.
+
+
+
+Manage Languages. You will seldom need this, as most languages are
+already entered.
+
+
+
+Change your password. You'll probably have to login again.
+
+Administrator Tasks
+
+Requires Administrator rights.
+
+
+
+Manage users. Add, remove, reset password etc.
+
+
+
+Manage mirrors.
+
+
+
diff --git a/catalog/admin/ip-activity.php b/catalog/admin/ip-activity.php
new file mode 100644
index 0000000..3289c1a
--- /dev/null
+++ b/catalog/admin/ip-activity.php
@@ -0,0 +1,128 @@
+ $cnt) {
+ p ("$ip => $cnt");
+}
+
+/*
+
+
+function fixnetwork ($ip) {
+ if (($pos = strpos ($ip, "/")) !== false) {
+ $ip = substr ($ip, 0, $pos);
+ $ip = long2ip (ip2long ($ip) + 1);
+ }
+ return $ip;
+}
+
+class CalcFieldHost {
+ function f ($db) {
+ return @gethostbyaddr (fixnetwork ($db->get ("ip", SQLCHAR)));
+ }
+}
+
+class CalcFieldRBL {
+ function __construct ($list) {
+ $this->list = $list;
+ }
+ function f ($db) {
+ $ip = fixnetwork ($db->get ("ip", SQLCHAR));
+ $reverse_ip = join (".", array_reverse (explode (".", $ip)));
+ $host = gethostbyname ("$reverse_ip.$this->list");
+ // return $host; // debug
+ return strncmp ($host, "127.", 4) ? "" : "Yes";
+ }
+}
+
+class RobotHitTable extends ListTable {
+ function __construct () {
+ $this->AddSimpleColumn ("date", "Date");
+ $this->AddSimpleColumn ("ip", "IP");
+ $this->AddSimpleColumn ("c_host", "Host");
+ $this->AddSimpleColumn ("hits", "Hits");
+ $this->AddSimpleColumn ("restricted", "Restricted");
+ $this->AddSimpleColumn ("c_isdialup", "Dialup");
+ $this->AddSimpleColumn ("c_spam", "Spam");
+ $this->AddSimpleColumn ("c_spews", "SPEWS");
+ }
+}
+
+class RobotJailTable extends ListTable {
+ function __construct () {
+ $this->AddSimpleColumn ("firstseen", "First Sighted");
+ $this->AddSimpleColumn ("lastseen", "Last Seen");
+ $this->AddSimpleColumn ("ip", "IP");
+ $this->AddSimpleColumn ("c_host", "Host");
+ $this->AddSimpleColumn ("hits", "Hits");
+ $this->AddSimpleColumn ("restricted", "Restricted");
+ $this->AddSimpleColumn ("charge", "Charge");
+ $this->AddSimpleColumn ("c_isdialup", "Dialup");
+ $this->AddSimpleColumn ("c_spam", "Spam");
+ $this->AddSimpleColumn ("c_spews", "SPEWS");
+ $this->AddSimpleColumn ("ua", "User-Agent");
+ }
+}
+
+$db = $config->db ();
+
+$db->exec ("select * from robots.stat");
+$lastcron = $db->get ("lastcron", SQLCHAR);
+p ("Last Cron Run: $lastcron");
+
+// Jailed
+
+$db->exec ("
+select * from robots.jail order by firstseen;
+");
+
+$db->calcfields ["c_host"] = new CalcFieldHost ();
+$db->calcfields ["c_isdialup"] = new CalcFieldRBL ("dul.dnsbl.sorbs.net");
+$db->calcfields ["c_spam"] = new CalcFieldRBL ("spam.dnsbl.sorbs.net");
+$db->calcfields ["c_spews"] = new CalcFieldRBL ("l2.spews.dnsbl.sorbs.net");
+
+$table = new RobotJailTable ();
+$table->PrintTable ($db, "Currently Jailed Robots");
+flush ();
+
+// Recent
+
+$db->exec ("
+select date, ip, hits, restricted from robots.hit_totals
+union
+select current_date, ip, count (ip), sum (restricted) from robots.hits
+group by ip having count (ip) > 1000
+order by date desc, ip;
+");
+
+
+$db->calcfields ["c_host"] = new CalcFieldHost ();
+$db->calcfields ["c_isdialup"] = new CalcFieldRBL ("dul.dnsbl.sorbs.net");
+$db->calcfields ["c_spam"] = new CalcFieldRBL ("spam.dnsbl.sorbs.net");
+$db->calcfields ["c_spews"] = new CalcFieldRBL ("l2.spews.dnsbl.sorbs.net");
+
+$table = new RobotHitTable ();
+$table->PrintTable ($db, "Recently Active Robots");
+flush ();
+*/
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/ip-activity.php~ b/catalog/admin/ip-activity.php~
new file mode 100644
index 0000000..c1d9c6d
--- /dev/null
+++ b/catalog/admin/ip-activity.php~
@@ -0,0 +1,127 @@
+ $cnt) {
+ p ("$ip => $cnt");
+}
+
+/*
+
+
+function fixnetwork ($ip) {
+ if (($pos = strpos ($ip, "/")) !== false) {
+ $ip = substr ($ip, 0, $pos);
+ $ip = long2ip (ip2long ($ip) + 1);
+ }
+ return $ip;
+}
+
+class CalcFieldHost {
+ function f ($db) {
+ return @gethostbyaddr (fixnetwork ($db->get ("ip", SQLCHAR)));
+ }
+}
+
+class CalcFieldRBL {
+ function __construct ($list) {
+ $this->list = $list;
+ }
+ function f ($db) {
+ $ip = fixnetwork ($db->get ("ip", SQLCHAR));
+ $reverse_ip = join (".", array_reverse (explode (".", $ip)));
+ $host = gethostbyname ("$reverse_ip.$this->list");
+ // return $host; // debug
+ return strncmp ($host, "127.", 4) ? "" : "Yes";
+ }
+}
+
+class RobotHitTable extends ListTable {
+ function __construct () {
+ $this->AddSimpleColumn ("date", "Date");
+ $this->AddSimpleColumn ("ip", "IP");
+ $this->AddSimpleColumn ("c_host", "Host");
+ $this->AddSimpleColumn ("hits", "Hits");
+ $this->AddSimpleColumn ("restricted", "Restricted");
+ $this->AddSimpleColumn ("c_isdialup", "Dialup");
+ $this->AddSimpleColumn ("c_spam", "Spam");
+ $this->AddSimpleColumn ("c_spews", "SPEWS");
+ }
+}
+
+class RobotJailTable extends ListTable {
+ function __construct () {
+ $this->AddSimpleColumn ("firstseen", "First Sighted");
+ $this->AddSimpleColumn ("lastseen", "Last Seen");
+ $this->AddSimpleColumn ("ip", "IP");
+ $this->AddSimpleColumn ("c_host", "Host");
+ $this->AddSimpleColumn ("hits", "Hits");
+ $this->AddSimpleColumn ("restricted", "Restricted");
+ $this->AddSimpleColumn ("charge", "Charge");
+ $this->AddSimpleColumn ("c_isdialup", "Dialup");
+ $this->AddSimpleColumn ("c_spam", "Spam");
+ $this->AddSimpleColumn ("c_spews", "SPEWS");
+ $this->AddSimpleColumn ("ua", "User-Agent");
+ }
+}
+
+$db = $config->db ();
+
+$db->exec ("select * from robots.stat");
+$lastcron = $db->get ("lastcron", SQLCHAR);
+p ("Last Cron Run: $lastcron");
+
+// Jailed
+
+$db->exec ("
+select * from robots.jail order by firstseen;
+");
+
+$db->calcfields ["c_host"] = new CalcFieldHost ();
+$db->calcfields ["c_isdialup"] = new CalcFieldRBL ("dul.dnsbl.sorbs.net");
+$db->calcfields ["c_spam"] = new CalcFieldRBL ("spam.dnsbl.sorbs.net");
+$db->calcfields ["c_spews"] = new CalcFieldRBL ("l2.spews.dnsbl.sorbs.net");
+
+$table = new RobotJailTable ();
+$table->PrintTable ($db, "Currently Jailed Robots");
+flush ();
+
+// Recent
+
+$db->exec ("
+select date, ip, hits, restricted from robots.hit_totals
+union
+select current_date, ip, count (ip), sum (restricted) from robots.hits
+group by ip having count (ip) > 1000
+order by date desc, ip;
+");
+
+
+$db->calcfields ["c_host"] = new CalcFieldHost ();
+$db->calcfields ["c_isdialup"] = new CalcFieldRBL ("dul.dnsbl.sorbs.net");
+$db->calcfields ["c_spam"] = new CalcFieldRBL ("spam.dnsbl.sorbs.net");
+$db->calcfields ["c_spews"] = new CalcFieldRBL ("l2.spews.dnsbl.sorbs.net");
+
+$table = new RobotHitTable ();
+$table->PrintTable ($db, "Recently Active Robots");
+flush ();
+*/
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/lang.php b/catalog/admin/lang.php
new file mode 100644
index 0000000..cf96ced
--- /dev/null
+++ b/catalog/admin/lang.php
@@ -0,0 +1,106 @@
+AddColumn ("#pk# ",
+ "Etext Nr.", "right", "1*");
+ $this->AddSimpleColumn ("author", "Author");
+ $this->AddSimpleColumn ("title", "Title");
+ $this->limit = 25;
+ $this->relay = array ("fk_langs", "mode", "filter");
+ }
+}
+
+$db = $config->db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getstr ("fk_langs");
+getstr ("filter");
+
+if (ismode ("delete")) {
+ $db->Exec ("select count (*) as cnt from mn_books_langs " .
+ "where fk_langs = '$fk_langs'");
+ $cnt = $db->get ("cnt");
+ if ($cnt > 0) {
+ $f->SubCaption ("Warning: There are $cnt books related to this language. ");
+ }
+ $f->SubCaption ("You are about to delete this language.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ $f->Text ("fk_langs", "pk", "Id", SQLCHAR, 10, 10, true);
+ $f->Text ("lang", "lang", "Language", SQLCHAR, 80, 240, true);
+ $f->LoadData ("select * from langs where pk = '$fk_langs'");
+}
+$f->Hidden ("fk_langs");
+$f->Hidden ("filter");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into langs " . $sql)) {
+ msg ("Language added !");
+ } else {
+ error_msg ("Could not add language!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update langs set " . $sql . "where pk = '$fk_langs'")) {
+ msg ("Language modified !");
+ } else {
+ error_msg ("Could not modify language !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->Exec ("delete from mn_books_langs where fk_langs = '$fk_langs'");
+ if ($db->Exec ("delete from langs where pk = '$fk_langs'")) {
+ msg ("Language deleted !");
+ } else {
+ error_msg ("Could not delete language !");
+ }
+}
+
+if (isupdate ()) {
+ if (!isupdatemode ("delete")) {
+ echo (" " .
+ "Back to Lang
\n\n");
+ }
+} else {
+ $f->Output ($caption, $caption);
+
+ if (ismode ("edit")) {
+ $table = new ListBooksTable ();
+ $db->exec ("select books.pk as pk, title, author " .
+ "from books, mn_books_langs, titles, mn_books_authors, authors " .
+ "where books.pk = mn_books_langs.fk_books " .
+ "and books.pk = mn_books_authors.fk_books " .
+ "and authors.pk = mn_books_authors.fk_authors " .
+ "and books.pk = titles.fk_books " .
+ "and mn_books_langs.fk_langs = '$fk_langs' order by author, title " .
+ $table->MkOffset ());
+ $table->PrintTable ($db, "Books for Language");
+ }
+}
+
+echo (" " .
+ "Back to Language List
\n\n");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/lang.php~ b/catalog/admin/lang.php~
new file mode 100644
index 0000000..c149848
--- /dev/null
+++ b/catalog/admin/lang.php~
@@ -0,0 +1,105 @@
+AddColumn ("#pk# ",
+ "Etext Nr.", "right", "1*");
+ $this->AddSimpleColumn ("author", "Author");
+ $this->AddSimpleColumn ("title", "Title");
+ $this->limit = 25;
+ $this->relay = array ("fk_langs", "mode", "filter");
+ }
+}
+
+$db = $config->db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getstr ("fk_langs");
+getstr ("filter");
+
+if (ismode ("delete")) {
+ $db->Exec ("select count (*) as cnt from mn_books_langs " .
+ "where fk_langs = '$fk_langs'");
+ $cnt = $db->get ("cnt");
+ if ($cnt > 0) {
+ $f->SubCaption ("Warning: There are $cnt books related to this language. ");
+ }
+ $f->SubCaption ("You are about to delete this language.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ $f->Text ("fk_langs", "pk", "Id", SQLCHAR, 10, 10, true);
+ $f->Text ("lang", "lang", "Language", SQLCHAR, 80, 240, true);
+ $f->LoadData ("select * from langs where pk = '$fk_langs'");
+}
+$f->Hidden ("fk_langs");
+$f->Hidden ("filter");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into langs " . $sql)) {
+ msg ("Language added !");
+ } else {
+ error_msg ("Could not add language!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update langs set " . $sql . "where pk = '$fk_langs'")) {
+ msg ("Language modified !");
+ } else {
+ error_msg ("Could not modify language !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->Exec ("delete from mn_books_langs where fk_langs = '$fk_langs'");
+ if ($db->Exec ("delete from langs where pk = '$fk_langs'")) {
+ msg ("Language deleted !");
+ } else {
+ error_msg ("Could not delete language !");
+ }
+}
+
+if (isupdate ()) {
+ if (!isupdatemode ("delete")) {
+ echo (" " .
+ "Back to Lang
\n\n");
+ }
+} else {
+ $f->Output ($caption, $caption);
+
+ if (ismode ("edit")) {
+ $table = new ListBooksTable ();
+ $db->exec ("select books.pk as pk, title, author " .
+ "from books, mn_books_langs, titles, mn_books_authors, authors " .
+ "where books.pk = mn_books_langs.fk_books " .
+ "and books.pk = mn_books_authors.fk_books " .
+ "and authors.pk = mn_books_authors.fk_authors " .
+ "and books.pk = titles.fk_books " .
+ "and mn_books_langs.fk_langs = '$fk_langs' order by author, title " .
+ $table->MkOffset ());
+ $table->PrintTable ($db, "Books for Language");
+ }
+}
+
+echo (" " .
+ "Back to Language List
\n\n");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/langs_list.php b/catalog/admin/langs_list.php
new file mode 100644
index 0000000..49bb2a7
--- /dev/null
+++ b/catalog/admin/langs_list.php
@@ -0,0 +1,48 @@
+AddColumn ("$prefix=edit&fk_langs=#pk#\">Edit",
+ "$prefix=add\">Add", "left", "1%");
+ $this->AddColumn ("$prefix=delete&fk_langs=#pk#\">Delete",
+ "", "left", "1%");
+ $this->AddSimpleColumn ("pk", "Id", "left", "1%");
+ $this->AddSimpleColumn ("lang", "Language");
+ $this->AddSimpleColumn ("cnt", "# of books");
+ }
+}
+
+$db = $config->db ();
+
+echo ("
+Please enter the first few characters of the language (at least one).
+Search is case-sensitive.
+Use * as wildcard. (eg. *ish)
+To see everything just enter *.
+");
+
+form_open ();
+echo (" \n");
+form_submit ("Search");
+form_close ();
+
+if ($filter != "") {
+ $filt = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select pk, lang, (select count(fk_books) from mn_books_langs where fk_langs=pk) as cnt from langs where lang like '$filt%' order by cnt, lang;");
+ $table = new ListLangsTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/langs_list.php~ b/catalog/admin/langs_list.php~
new file mode 100644
index 0000000..3168cc7
--- /dev/null
+++ b/catalog/admin/langs_list.php~
@@ -0,0 +1,47 @@
+AddColumn ("$prefix=edit&fk_langs=#pk#\">Edit",
+ "$prefix=add\">Add", "left", "1%");
+ $this->AddColumn ("$prefix=delete&fk_langs=#pk#\">Delete",
+ "", "left", "1%");
+ $this->AddSimpleColumn ("pk", "Id", "left", "1%");
+ $this->AddSimpleColumn ("lang", "Language");
+ $this->AddSimpleColumn ("cnt", "# of books");
+ }
+}
+
+$db = $config->db ();
+
+echo ("
+Please enter the first few characters of the language (at least one).
+Search is case-sensitive.
+Use * as wildcard. (eg. *ish)
+To see everything just enter *.
+");
+
+form_open ();
+echo (" \n");
+form_submit ("Search");
+form_close ();
+
+if ($filter != "") {
+ $filt = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select pk, lang, (select count(fk_books) from mn_books_langs where fk_langs=pk) as cnt from langs where lang like '$filt%' order by cnt, lang;");
+ $table = new ListLangsTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/locc.php b/catalog/admin/locc.php
new file mode 100644
index 0000000..ea34326
--- /dev/null
+++ b/catalog/admin/locc.php
@@ -0,0 +1,105 @@
+AddColumn ("#pk# ",
+ "Etext Nr.", "right", "1*");
+ $this->AddSimpleColumn ("title", "Title");
+ $this->limit = 25;
+ $this->relay = array ("fk_loccs", "mode", "filter");
+ }
+}
+
+$db = $config->db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getstr ("fk_loccs");
+getstr ("filter");
+
+if (ismode ("delete")) {
+ $db->Exec ("select count (*) as cnt from mn_books_loccs " .
+ "where fk_loccs = '$fk_loccs'");
+ $cnt = $db->get ("cnt");
+ if ($cnt > 0) {
+ $f->SubCaption ("Warning: There are $cnt books related to this LoC class. ");
+ }
+ $f->SubCaption ("You are about to delete this LoC class.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ $f->Text ("fk_loccs", "pk", "Id", SQLCHAR, 10, 10, true);
+ $f->Text ("locc", "locc", "LoC Class", SQLCHAR, 80, 240, true);
+ $f->LoadData ("select * from loccs where pk = '$fk_loccs'");
+}
+$f->Hidden ("fk_loccs");
+$f->Hidden ("filter");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into loccs " . $sql)) {
+ msg ("LoC class added !");
+ } else {
+ error_msg ("Could not add LoC class!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update loccs set " . $sql . "where pk = '$fk_loccs'")) {
+ msg ("LoC class modified !");
+ } else {
+ error_msg ("Could not modify LoC class !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->Exec ("delete from mn_books_loccs where fk_loccs = '$fk_loccs'");
+ if ($db->Exec ("delete from loccs where pk = '$fk_loccs'")) {
+ msg ("LoC class deleted !");
+ } else {
+ error_msg ("Could not delete LoC class !");
+ }
+}
+
+if (isupdate ()) {
+ if (!isupdatemode ("delete")) {
+ echo (" " .
+ "Back to Locc
\n\n");
+ }
+} else {
+ $f->Output ($caption, $caption);
+
+ if (ismode ("edit")) {
+ $table = new ListBooksTable ();
+ $db->exec ("select books.pk as pk, title, author " .
+ "from books, mn_books_loccs, titles, mn_books_authors, authors " .
+ "where books.pk = mn_books_loccs.fk_books " .
+ "and books.pk = mn_books_authors.fk_books " .
+ "and authors.pk = mn_books_authors.fk_authors " .
+ "and books.pk = titles.fk_books " .
+ "and mn_books_loccs.fk_loccs = '$fk_loccs' order by author, title " .
+ $table->MkOffset ());
+ $table->PrintTable ($db, "Books for LoC Class");
+ }
+}
+
+echo (" " .
+ "Back to LoC Class List
\n\n");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/locc.php~ b/catalog/admin/locc.php~
new file mode 100644
index 0000000..1411c6a
--- /dev/null
+++ b/catalog/admin/locc.php~
@@ -0,0 +1,104 @@
+AddColumn ("#pk# ",
+ "Etext Nr.", "right", "1*");
+ $this->AddSimpleColumn ("title", "Title");
+ $this->limit = 25;
+ $this->relay = array ("fk_loccs", "mode", "filter");
+ }
+}
+
+$db = $config->db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getstr ("fk_loccs");
+getstr ("filter");
+
+if (ismode ("delete")) {
+ $db->Exec ("select count (*) as cnt from mn_books_loccs " .
+ "where fk_loccs = '$fk_loccs'");
+ $cnt = $db->get ("cnt");
+ if ($cnt > 0) {
+ $f->SubCaption ("Warning: There are $cnt books related to this LoC class. ");
+ }
+ $f->SubCaption ("You are about to delete this LoC class.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ $f->Text ("fk_loccs", "pk", "Id", SQLCHAR, 10, 10, true);
+ $f->Text ("locc", "locc", "LoC Class", SQLCHAR, 80, 240, true);
+ $f->LoadData ("select * from loccs where pk = '$fk_loccs'");
+}
+$f->Hidden ("fk_loccs");
+$f->Hidden ("filter");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into loccs " . $sql)) {
+ msg ("LoC class added !");
+ } else {
+ error_msg ("Could not add LoC class!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update loccs set " . $sql . "where pk = '$fk_loccs'")) {
+ msg ("LoC class modified !");
+ } else {
+ error_msg ("Could not modify LoC class !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->Exec ("delete from mn_books_loccs where fk_loccs = '$fk_loccs'");
+ if ($db->Exec ("delete from loccs where pk = '$fk_loccs'")) {
+ msg ("LoC class deleted !");
+ } else {
+ error_msg ("Could not delete LoC class !");
+ }
+}
+
+if (isupdate ()) {
+ if (!isupdatemode ("delete")) {
+ echo (" " .
+ "Back to Locc
\n\n");
+ }
+} else {
+ $f->Output ($caption, $caption);
+
+ if (ismode ("edit")) {
+ $table = new ListBooksTable ();
+ $db->exec ("select books.pk as pk, title, author " .
+ "from books, mn_books_loccs, titles, mn_books_authors, authors " .
+ "where books.pk = mn_books_loccs.fk_books " .
+ "and books.pk = mn_books_authors.fk_books " .
+ "and authors.pk = mn_books_authors.fk_authors " .
+ "and books.pk = titles.fk_books " .
+ "and mn_books_loccs.fk_loccs = '$fk_loccs' order by author, title " .
+ $table->MkOffset ());
+ $table->PrintTable ($db, "Books for LoC Class");
+ }
+}
+
+echo (" " .
+ "Back to LoC Class List
\n\n");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/loccs_list.php b/catalog/admin/loccs_list.php
new file mode 100644
index 0000000..78c3f9e
--- /dev/null
+++ b/catalog/admin/loccs_list.php
@@ -0,0 +1,47 @@
+AddColumn ("$prefix=edit&fk_loccs=#pk#\">Edit",
+ "$prefix=add\">Add", "left", "1%");
+ $this->AddColumn ("$prefix=delete&fk_loccs=#pk#\">Delete",
+ "", "left", "1%");
+ $this->AddSimpleColumn ("pk", "Id", "left", "1%");
+ $this->AddSimpleColumn ("locc", "LoC Class");
+ }
+}
+
+$db = $config->db ();
+
+echo ("
+Please enter the first few characters of the LoC Class (at least one).
+Search is case-sensitive.
+Use * as wildcard. (eg. *United*)
+To see everything just enter *.
+");
+
+form_open ();
+echo (" \n");
+form_submit ("Search");
+form_close ();
+
+if ($filter != "") {
+ $filt = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from loccs where locc like '$filt%' order by locc;");
+ $table = new ListLoccsTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/loccs_list.php~ b/catalog/admin/loccs_list.php~
new file mode 100644
index 0000000..3cd4ea8
--- /dev/null
+++ b/catalog/admin/loccs_list.php~
@@ -0,0 +1,46 @@
+AddColumn ("$prefix=edit&fk_loccs=#pk#\">Edit",
+ "$prefix=add\">Add", "left", "1%");
+ $this->AddColumn ("$prefix=delete&fk_loccs=#pk#\">Delete",
+ "", "left", "1%");
+ $this->AddSimpleColumn ("pk", "Id", "left", "1%");
+ $this->AddSimpleColumn ("locc", "LoC Class");
+ }
+}
+
+$db = $config->db ();
+
+echo ("
+Please enter the first few characters of the LoC Class (at least one).
+Search is case-sensitive.
+Use * as wildcard. (eg. *United*)
+To see everything just enter *.
+");
+
+form_open ();
+echo (" \n");
+form_submit ("Search");
+form_close ();
+
+if ($filter != "") {
+ $filt = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from loccs where locc like '$filt%' order by locc;");
+ $table = new ListLoccsTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/ls.php b/catalog/admin/ls.php
new file mode 100644
index 0000000..09c4195
--- /dev/null
+++ b/catalog/admin/ls.php
@@ -0,0 +1,17 @@
+
diff --git a/catalog/admin/ls.php~ b/catalog/admin/ls.php~
new file mode 100644
index 0000000..b74c052
--- /dev/null
+++ b/catalog/admin/ls.php~
@@ -0,0 +1,16 @@
+
diff --git a/catalog/admin/make-by-pages.php b/catalog/admin/make-by-pages.php
new file mode 100644
index 0000000..0e6f0ba
--- /dev/null
+++ b/catalog/admin/make-by-pages.php
@@ -0,0 +1,618 @@
+page_encoding = "UTF-8";
+
+function _navbar ($what, $dir) {
+ global $config;
+ $nav = " $what:\n";
+ foreach ($config->browse_pages as $caption => $regexp) {
+ $href = strtolower ($caption);
+ $nav .= " $caption \n";
+ }
+ $nav .= "
\n";
+ return $nav;
+}
+
+function _navbarrecent ($what, $dir) {
+ global $spans;
+ $nav .= " $what:\n";
+ foreach ($spans as $href => $caption) {
+ $nav .= " $caption \n";
+ }
+ $nav .= "
\n";
+ return $nav;
+}
+
+function _navbarlangs ($what, $where, $dir) {
+ global $db;
+ $nav = " $what:\n";
+ $db->Exec ("select pk, lang, cnt from langs join (select fk_langs, count (fk_langs) as cnt from mn_books_langs group by fk_langs having count (fk_langs) $where) as sums on pk = fk_langs order by lang;");
+ if ($db->FirstRow ()) {
+ do {
+ $pk = strtolower ($db->Get ("pk", SQLCHAR));
+ $lang = $db->Get ("lang", SQLCHAR);
+ $cnt = $db->Get ("cnt", SQLINT);
+ $nav .= " $lang \n";
+ } while ($db->NextRow ());
+ }
+ $nav .= "
\n";
+ return $nav;
+}
+
+function _navbarloccs ($what, $dir) {
+ global $db;
+ $nav = " $what:\n";
+ $db->Exec ("select pk, locc, cnt from loccs join (select fk_loccs, count (fk_loccs) as cnt from mn_books_loccs group by fk_loccs) as sums on pk = fk_loccs order by fk_loccs;");
+ if ($db->FirstRow ()) {
+ do {
+ $pk = strtolower ($db->Get ("pk", SQLCHAR));
+ $pku = strtoupper ($pk);
+ $locc = $db->Get ("locc", SQLCHAR);
+ $cnt = $db->Get ("cnt", SQLINT);
+ $nav .= " $pku \n";
+ } while ($db->NextRow ());
+ }
+ $nav .= "
\n";
+ return $nav;
+}
+
+function _navbarcategories ($what, $dir) {
+ global $db;
+ $nav = " $what:\n";
+ $db->Exec ("select pk, category, cnt from categories join (select fk_categories, count (fk_categories) as cnt from mn_books_categories group by fk_categories) as sums on pk = fk_categories order by category;");
+ if ($db->FirstRow ()) {
+ do {
+ $pk = $db->Get ("pk", SQLINT);
+ $category = $db->Get ("category", SQLCHAR);
+ $cnt = $db->Get ("cnt", SQLINT);
+ $nav .= " $category \n";
+ } while ($db->NextRow ());
+ }
+ $nav .= "
\n";
+ return $nav;
+}
+
+function navbar () {
+ global $dir_authors, $dir_titles, $dir_langs, $dir_loccs, $dir_categories, $dir_recent, $lang_thres;
+ $nav = "\n";
+ $nav .= _navbar ("Authors", $dir_authors);
+ $nav .= _navbar ("Titles", $dir_titles);
+ $nav .= _navbarlangs ("Languages with more than $lang_thres books", "> $lang_thres", $dir_langs);
+ $nav .= _navbarlangs ("Languages with up to $lang_thres books", "<= $lang_thres", $dir_langs);
+ // $nav .= _navbarloccs ("LoC Class", $dir_loccs);
+ $nav .= _navbarcategories ("Special Categories", $dir_categories);
+ $nav .= _navbarrecent ("Recent", $dir_recent);
+ $nav .= "
\n\n";
+ return $nav;
+}
+
+function pagefooterfile ($file) {
+ global $page;
+ $page->footer ();
+
+ $output = ob_get_contents ();
+ ob_clean ();
+
+ $hd = fopen ($file, "w");
+ if ($hd) {
+ fwrite ($hd, $output);
+ fclose ($hd);
+ }
+
+ $hd = gzopen ("$file.gzip", "w9");
+ if ($hd) {
+ gzwrite ($hd, $output);
+ gzclose ($hd);
+ }
+}
+
+function LoadTitles () {
+ global $db, $authors;
+
+ foreach ($authors as $fk_authors => $dummy) {
+ $authors[$fk_authors]['titles'] = array ();
+ // echo ("$fk_authors\n");
+ }
+ if ($db->FirstRow ()) {
+ do {
+ $o = array ();
+ $fk_authors = $db->get ("fk_authors", SQLINT);
+ if (empty ($fk_authors))
+ $fk_authors = 0;
+ // echo ("fk_authors: $fk_authors\n");
+ $o['title'] = str_replace ("\n", " endtag>",
+ strip_marc_subfields (htmlspecialchars ($db->get ("title", SQLCHAR))));
+ $o['lang'] = $db->get ("lang", SQLCHAR);
+ $o['etext'] = $db->get ("fk_books", SQLINT);
+ $o['is_audio'] = $db->get ("is_audio", SQLBOOL);
+ $o['role'] = $db->get ("role", SQLCHAR);
+ array_push ($authors[$fk_authors]['titles'], $o);
+ } while ($db->NextRow ());
+ }
+}
+
+function pklist ($aa) {
+ // make a list of all authors with titles
+ $pklist = array ();
+ foreach ($aa as $fk_authors => $o) {
+ if (count ($o['titles'])) {
+ $pklist[] = $fk_authors;
+ }
+ }
+ return $pklist;
+}
+
+function FormatAliases ($pklist, $mode = 0, $regex = "") {
+ global $db, $lines, $authors;
+
+ if (count ($pklist) == 0)
+ return;
+
+ $list = join (",", $pklist);
+ $db->exec ("select fk_authors, alias from aliases " .
+ "where aliases.alias_heading = 1 and fk_authors in ($list)");
+
+ if ($db->FirstRow ()) {
+ do {
+ $fk_authors = $db->get ("fk_authors", SQLINT);
+ $alias = $db->get ("alias", SQLCHAR);
+ $author = $authors[$fk_authors]['author'];
+ if ($mode == 1) {
+ if (!preg_match ("/$regex/i", $alias))
+ continue;
+ // the by-author pages need a different url
+ $href = find_browse_page ($author) . "#a$fk_authors";
+ } else {
+ $href = "#a$fk_authors";
+ }
+ $html_alias = htmlspecialchars ($alias);
+ $html_author = htmlspecialchars ($author);
+ $lines[$alias] = "$html_alias \nSee: $html_author
\n\n";
+ // echo ("$alias\n");
+ } while ($db->NextRow ());
+ }
+}
+
+function FormatAuthors ($mode = 0) {
+ global $db, $lines, $dir_etext, $authors;
+
+ foreach ($authors as $fk_authors => $o) {
+ if (count ($o['titles'])) {
+ $html_author = htmlspecialchars ($o['author']);
+ if ($mode == 1 || $fk_authors == 0) {
+ $line = "\n";
+ } else {
+ $href = "/browse/authors/" . find_browse_page ($o['author']) . "#a$fk_authors";
+ $line = "\n";
+ }
+ $line .= "\n";
+
+ if ($mode == 1) {
+ // by-author page
+ if (isset ($o['aliases'])) {
+ foreach ($o['aliases'] as $alias) {
+ $line .= " $alias \n";
+ }
+ }
+
+ if (isset ($o['urls'])) {
+ foreach ($o['urls'] as $description => $url) {
+ $line .= " $description \n";
+ }
+ }
+ }
+
+ // output list of titles
+ foreach ($o['titles'] as $t) {
+ $role = (empty ($t['role']) || $t['role'] == "Creator") ? "" : " (as {$t['role']})";
+ $cls = $t['is_audio'] ? " class=\"pgdbaudio\"" : " class=\"pgdbetext\"";
+ $line .= " {$t['title']} ({$t['lang']})$role \n";
+ }
+ $line .= " \n\n";
+ $lines[$o['author']] = $line;
+ // echo ("{$o['author']}\n");
+ }
+ }
+}
+
+$dir = "browse";
+$dir_authors = "$dir/authors";
+$dir_titles = "$dir/titles";
+$dir_langs = "$dir/languages";
+$dir_loccs = "$dir/loccs";
+$dir_subjects = "$dir/subjects";
+$dir_categories = "$dir/categories";
+$dir_recent = "$dir/recent";
+$dir_feeds = "cache/epub/feeds";
+$dir_etext = "ebooks";
+$base_url = "http://$config->domain";
+
+@mkdir ("$config->documentroot/$dir", 0755);
+@mkdir ("$config->documentroot/$dir_authors", 0755);
+@mkdir ("$config->documentroot/$dir_titles", 0755);
+@mkdir ("$config->documentroot/$dir_langs", 0755);
+@mkdir ("$config->documentroot/$dir_loccs", 0755);
+@mkdir ("$config->documentroot/$dir_subjects", 0755);
+@mkdir ("$config->documentroot/$dir_categories", 0755);
+@mkdir ("$config->documentroot/$dir_recent", 0755);
+@mkdir ("$config->documentroot/$dir_feeds", 0755);
+
+$spans[1] = 'last 24 hours';
+$spans[7] = 'last 7 days';
+$spans[30] = 'last 30 days';
+
+$db = $config->db ();
+$db2 = $config->db ();
+$authors = array ();
+
+////////////////////////////////////////////////////////////////////////
+// load authors
+
+$authors[0]['author'] = "No Author Listed";
+
+$db->exec ("select * from authors");
+if ($db->FirstRow ()) {
+ do {
+ $fk_authors = $db->get ("pk", SQLINT);
+ $authors[$fk_authors]['author'] = FormatAuthorDate ($db);
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select * from aliases where alias_heading = 1 order by alias");
+if ($db->FirstRow ()) {
+ do {
+ $fk_authors = $db->get ("fk_authors", SQLINT);
+ $alias = htmlspecialchars ($db->get ("alias", SQLCHAR));
+ $authors[$fk_authors]['aliases'][] = $alias;
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select * from author_urls order by description");
+if ($db->FirstRow ()) {
+ do {
+ $fk_authors = $db->get ("fk_authors", SQLINT);
+ $description = htmlspecialchars ($db->get ("description", SQLCHAR));
+ $url = htmlspecialchars ($db->get ("url", SQLCHAR));
+ $authors[$fk_authors]['urls'][$description] = $url;
+ } while ($db->NextRow ());
+}
+
+// echo ("$config->documentroot/$dir/navbar.html\n");
+if ($hd = fopen ("$config->documentroot/$dir/navbar.html", "w")) {
+ fputs ($hd, navbar ());
+ fclose ($hd);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+$db->exec ("create temporary table tmp_books as select * from v_books");
+
+////////////////////////////////////////////////////////////////////////////////
+// by-author
+
+// Postgres 7.3.3 at ibiblio doesn't dig multicolumn functional indexes
+$db->exec ("create index tmp_ix_books_authors on tmp_books (lower (author))");
+
+foreach ($config->browse_pages as $caption => $regexp) {
+
+ // titles for each author
+ $db->exec ("select * from tmp_books where author ~* '^$regexp' " .
+ "order by author, filing, lang");
+ LoadTitles ();
+
+ $lines = array ();
+ FormatAuthors (1);
+
+ $pklist = array ();
+ $db->exec ("select fk_authors from aliases where alias ~* '^$regexp'");
+ if ($db->FirstRow ()) {
+ do {
+ $pklist[] = $db->get ("fk_authors", SQLINT);
+ } while ($db->NextRow ());
+ }
+ FormatAliases ($pklist, 1, "^$regexp");
+ uksort ($lines, 'strcoll');
+
+ $fn = strtolower ($caption);
+
+ pageheader ("Browse By Author: $caption");
+ echo (navbar ());
+ echo ("\n\n");
+
+ foreach ($lines as $line) {
+ echo ($line);
+ }
+
+ echo ("
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_authors/$fn.html.utf8");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// by-lang
+
+$db->exec ("create index tmp_ix_books_langs on tmp_books (lang)");
+
+$db->exec ("select pk, lang from langs where pk in (select fk_langs from mn_books_langs)");
+
+if ($db->FirstRow ()) {
+ do {
+ $langs[$db->get ("lang", SQLCHAR)] = $db->get ("pk", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+foreach ($langs as $lang => $id) {
+ $caption = $lang;
+ $fn = $id;
+
+ if ($id == 'en') {
+ pageheader ("Browse By Language: $caption");
+ echo (navbar ());
+ echo ("There are too many english books to list them in one page. " .
+ "Please use the Browse-By-Author pages instead.
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_langs/$fn.html.utf8");
+ continue;
+ }
+
+ $db->exec ("select * from tmp_books where fk_books in
+(select fk_books from mn_books_langs where fk_langs = '$id'
+and tmp_books.fk_books = mn_books_langs.fk_books)
+order by lang, author, filing");
+
+ LoadTitles ();
+
+ $lines = array ();
+ FormatAuthors ();
+ FormatAliases (pklist ($authors));
+ uksort ($lines, 'strcoll');
+
+ pageheader ("Browse By Language: $caption");
+ echo (navbar ());
+ echo ("\n\n");
+
+ foreach ($lines as $line) {
+ echo ($line);
+ }
+
+ echo ("
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_langs/$fn.html.utf8");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// by-locc
+
+$db->exec ("select pk, locc from loccs where pk in (select fk_loccs from mn_books_loccs)");
+
+if ($db->FirstRow ()) {
+ do {
+ $loccs[$db->get ("locc", SQLCHAR)] = $db->get ("pk", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+foreach ($loccs as $locc => $fk_loccs) {
+ $caption = $locc;
+ $fn = strtolower ($fk_loccs);
+
+ // titles for each author
+ // $db->exec ("select * from tmp_books where fk_loccs = '$fk_loccs' " .
+ // "order by fk_loccs, author, filing");
+ $db->exec ("select * from tmp_books where fk_books in
+(select fk_books from mn_books_loccs where fk_loccs = '$fk_loccs'
+and tmp_books.fk_books = mn_books_loccs.fk_books)
+order by author, filing");
+
+ LoadTitles ();
+
+ $lines = array ();
+ FormatAuthors ();
+ FormatAliases (pklist ($authors));
+ uksort ($lines, 'strcoll');
+
+ pageheader ("Browse By Library of Congress Class: $caption");
+ echo (navbar ());
+ echo ("\n\n");
+
+ foreach ($lines as $line) {
+ echo ($line);
+ }
+
+ echo ("
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_loccs/$fn.html.utf8");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// by-category
+
+$db->exec ("select pk, category from categories");
+
+if ($db->FirstRow ()) {
+ do {
+ $categories[$db->get ("category", SQLCHAR)] = $db->get ("pk", SQLINT);
+ } while ($db->NextRow ());
+}
+
+foreach ($categories as $category => $id) {
+ $caption = $category;
+ $fn = $id;
+
+ if ($id == 0) {
+ pageheader ("Browse By Category: $caption");
+ echo (navbar ());
+ echo ("There are too many books in this category too list them in one page. " .
+ "Please use the Browse-By-Author pages instead.
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_langs/$fn.html.utf8");
+ continue;
+ }
+
+ $db->exec ("select * from tmp_books where fk_books in
+(select fk_books from mn_books_categories where fk_categories = $id
+and tmp_books.fk_books = mn_books_categories.fk_books)
+order by author, filing");
+ LoadTitles ();
+
+ $lines = array ();
+ FormatAuthors ();
+ FormatAliases (pklist ($authors));
+ uksort ($lines, 'strcoll');
+
+ pageheader ("Browse By Category: $caption");
+ echo (navbar ());
+ echo ("\n\n");
+
+ foreach ($lines as $line) {
+ echo ($line);
+ }
+
+ echo ("
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_categories/$fn.html.utf8");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// by-title
+
+$db->exec ("create index tmp_ix_books_titles on tmp_books (lower (filing))");
+
+foreach ($config->browse_pages as $caption => $regexp) {
+ $fn = strtolower ($caption);
+ pageheader ("Browse By Title: $caption");
+ echo (navbar ());
+ echo ("\n\n");
+
+ // titles
+ $db->exec ("select * from tmp_books where lower (filing) ~ '^$regexp' order by lower (filing), author, lang");
+
+ if ($db->FirstRow ()) {
+ do {
+ $etext = $db->get ("fk_books", SQLINT);
+ $fk_authors = $db->get ("fk_authors", SQLINT);
+ $title = str_replace ("\n", "
endtag>", $db->get ("title", SQLCHAR));
+ $author = $db->get ("author", SQLCHAR);
+ $lang = $db->get ("lang", SQLCHAR);
+ $is_audio = $db->get ("is_audio", SQLBOOL);
+ // echo ("$title\n");
+ $icon = $is_audio ? "
endtag>" : "";
+ echo ("
$title ($lang)$icon\n");
+ $href = "/$dir_authors/" . find_browse_page ($author) . "#a$fk_authors";
+ echo ("
by $author
\n\n");
+ } while ($db->NextRow ());
+ }
+
+ echo ("
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_titles/$fn.html.utf8");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// recent books
+
+$db->exec ("create index tmp_ix_books_fk_books on tmp_books (fk_books)");
+$rssbuffer = "";
+$books_output = array ();
+
+// clear titles
+foreach ($authors as $fk_authors => $dummy) {
+ $authors[$fk_authors]['titles'] = array ();
+}
+
+foreach ($spans as $span => $caption) {
+
+ $recents = array ();
+ $cutoff = date ("Y-m-d", time () - $span * 86400);
+
+ $db->exec ("select distinct fk_books from files " .
+ "where fk_books is not null and diskstatus = 0 and filename !~ '^cache' and filemtime >= '$cutoff 00:00:00'");
+ if ($db->FirstRow ()) {
+ do {
+ $recents[] = $db->get ("fk_books", SQLINT);
+ } while ($db->NextRow ());
+ }
+
+ $lines = array ();
+
+ if (count ($recents)) {
+ $recent = join (", ", $recents);
+
+ // titles for each author
+ $db->exec ("select * from tmp_books where fk_books in ($recent) order by author, filing, lang");
+ LoadTitles ();
+
+ FormatAuthors ();
+ FormatAliases (pklist ($authors));
+ uksort ($lines, 'strcoll');
+ }
+
+ $config->htmlheaderlinks[] = " ";
+ pageheader ("Books Posted or Updated Since: $cutoff");
+ echo (navbar ());
+ echo ("\n\n");
+
+ if (!count ($recents)) {
+ echo ("
No books posted.
\n\n");
+ }
+ foreach ($lines as $line) {
+ echo ($line);
+ }
+ if ($span == 1) {
+ // build rss
+ foreach ($authors as $author => $o) {
+ if (count ($o['titles'])) {
+ // output list of titles
+ foreach ($o['titles'] as $t) {
+ // avoid duplicates in rss
+ if (!isset ($books_output[$t['etext']])) {
+ $books_output[$t['etext']] = 1;
+ $friendlytitle = htmlspecialchars (friendlytitle ($t['etext'], 100));
+ $rssbuffer .= "
- \n";
+ $rssbuffer .= "
$friendlytitle \n";
+ $rssbuffer .= " $base_url/$dir_etext/{$t['etext']}\n";
+ $rssbuffer .= " Language: {$t['lang']} \n";
+ $rssbuffer .= " \n\n";
+ }
+ }
+ }
+ }
+ }
+ echo ("
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_recent/last$span.html.utf8");
+
+ $config->htmlheaderlinks = array ();
+}
+
+// write rss feed
+if ($hd = fopen ($file = "$config->documentroot/$dir_feeds/today.rss", "w")) {
+ $pubdate = date ("r");
+
+ fputs ($hd, <<
+
+
+ Project Gutenberg Recently Posted or Updated EBooks
+ $base_url
+
+ EBooks posted or updated today on Project Gutenberg.
+ This feed is regenerated every night.
+
+ en-us
+ webmaster@gutenberg.org (Marcello Perathoner)
+ $pubdate
+ $pubdate
+
+EOF
+);
+
+ fputs ($hd, $rssbuffer);
+ fputs ($hd, " \n \n");
+ fclose ($hd);
+}
+
+?>
diff --git a/catalog/admin/make-by-pages.php~ b/catalog/admin/make-by-pages.php~
new file mode 100644
index 0000000..d9311fe
--- /dev/null
+++ b/catalog/admin/make-by-pages.php~
@@ -0,0 +1,617 @@
+page_encoding = "UTF-8";
+
+function _navbar ($what, $dir) {
+ global $config;
+ $nav = " $what:\n";
+ foreach ($config->browse_pages as $caption => $regexp) {
+ $href = strtolower ($caption);
+ $nav .= " $caption \n";
+ }
+ $nav .= "
\n";
+ return $nav;
+}
+
+function _navbarrecent ($what, $dir) {
+ global $spans;
+ $nav .= " $what:\n";
+ foreach ($spans as $href => $caption) {
+ $nav .= " $caption \n";
+ }
+ $nav .= "
\n";
+ return $nav;
+}
+
+function _navbarlangs ($what, $where, $dir) {
+ global $db;
+ $nav = " $what:\n";
+ $db->Exec ("select pk, lang, cnt from langs join (select fk_langs, count (fk_langs) as cnt from mn_books_langs group by fk_langs having count (fk_langs) $where) as sums on pk = fk_langs order by lang;");
+ if ($db->FirstRow ()) {
+ do {
+ $pk = strtolower ($db->Get ("pk", SQLCHAR));
+ $lang = $db->Get ("lang", SQLCHAR);
+ $cnt = $db->Get ("cnt", SQLINT);
+ $nav .= " $lang \n";
+ } while ($db->NextRow ());
+ }
+ $nav .= "
\n";
+ return $nav;
+}
+
+function _navbarloccs ($what, $dir) {
+ global $db;
+ $nav = " $what:\n";
+ $db->Exec ("select pk, locc, cnt from loccs join (select fk_loccs, count (fk_loccs) as cnt from mn_books_loccs group by fk_loccs) as sums on pk = fk_loccs order by fk_loccs;");
+ if ($db->FirstRow ()) {
+ do {
+ $pk = strtolower ($db->Get ("pk", SQLCHAR));
+ $pku = strtoupper ($pk);
+ $locc = $db->Get ("locc", SQLCHAR);
+ $cnt = $db->Get ("cnt", SQLINT);
+ $nav .= " $pku \n";
+ } while ($db->NextRow ());
+ }
+ $nav .= "
\n";
+ return $nav;
+}
+
+function _navbarcategories ($what, $dir) {
+ global $db;
+ $nav = " $what:\n";
+ $db->Exec ("select pk, category, cnt from categories join (select fk_categories, count (fk_categories) as cnt from mn_books_categories group by fk_categories) as sums on pk = fk_categories order by category;");
+ if ($db->FirstRow ()) {
+ do {
+ $pk = $db->Get ("pk", SQLINT);
+ $category = $db->Get ("category", SQLCHAR);
+ $cnt = $db->Get ("cnt", SQLINT);
+ $nav .= " $category \n";
+ } while ($db->NextRow ());
+ }
+ $nav .= "
\n";
+ return $nav;
+}
+
+function navbar () {
+ global $dir_authors, $dir_titles, $dir_langs, $dir_loccs, $dir_categories, $dir_recent, $lang_thres;
+ $nav = "\n";
+ $nav .= _navbar ("Authors", $dir_authors);
+ $nav .= _navbar ("Titles", $dir_titles);
+ $nav .= _navbarlangs ("Languages with more than $lang_thres books", "> $lang_thres", $dir_langs);
+ $nav .= _navbarlangs ("Languages with up to $lang_thres books", "<= $lang_thres", $dir_langs);
+ // $nav .= _navbarloccs ("LoC Class", $dir_loccs);
+ $nav .= _navbarcategories ("Special Categories", $dir_categories);
+ $nav .= _navbarrecent ("Recent", $dir_recent);
+ $nav .= "
\n\n";
+ return $nav;
+}
+
+function pagefooterfile ($file) {
+ global $page;
+ $page->footer ();
+
+ $output = ob_get_contents ();
+ ob_clean ();
+
+ $hd = fopen ($file, "w");
+ if ($hd) {
+ fwrite ($hd, $output);
+ fclose ($hd);
+ }
+
+ $hd = gzopen ("$file.gzip", "w9");
+ if ($hd) {
+ gzwrite ($hd, $output);
+ gzclose ($hd);
+ }
+}
+
+function LoadTitles () {
+ global $db, $authors;
+
+ foreach ($authors as $fk_authors => $dummy) {
+ $authors[$fk_authors]['titles'] = array ();
+ // echo ("$fk_authors\n");
+ }
+ if ($db->FirstRow ()) {
+ do {
+ $o = array ();
+ $fk_authors = $db->get ("fk_authors", SQLINT);
+ if (empty ($fk_authors))
+ $fk_authors = 0;
+ // echo ("fk_authors: $fk_authors\n");
+ $o['title'] = str_replace ("\n", " endtag>",
+ strip_marc_subfields (htmlspecialchars ($db->get ("title", SQLCHAR))));
+ $o['lang'] = $db->get ("lang", SQLCHAR);
+ $o['etext'] = $db->get ("fk_books", SQLINT);
+ $o['is_audio'] = $db->get ("is_audio", SQLBOOL);
+ $o['role'] = $db->get ("role", SQLCHAR);
+ array_push ($authors[$fk_authors]['titles'], $o);
+ } while ($db->NextRow ());
+ }
+}
+
+function pklist ($aa) {
+ // make a list of all authors with titles
+ $pklist = array ();
+ foreach ($aa as $fk_authors => $o) {
+ if (count ($o['titles'])) {
+ $pklist[] = $fk_authors;
+ }
+ }
+ return $pklist;
+}
+
+function FormatAliases ($pklist, $mode = 0, $regex = "") {
+ global $db, $lines, $authors;
+
+ if (count ($pklist) == 0)
+ return;
+
+ $list = join (",", $pklist);
+ $db->exec ("select fk_authors, alias from aliases " .
+ "where aliases.alias_heading = 1 and fk_authors in ($list)");
+
+ if ($db->FirstRow ()) {
+ do {
+ $fk_authors = $db->get ("fk_authors", SQLINT);
+ $alias = $db->get ("alias", SQLCHAR);
+ $author = $authors[$fk_authors]['author'];
+ if ($mode == 1) {
+ if (!preg_match ("/$regex/i", $alias))
+ continue;
+ // the by-author pages need a different url
+ $href = find_browse_page ($author) . "#a$fk_authors";
+ } else {
+ $href = "#a$fk_authors";
+ }
+ $html_alias = htmlspecialchars ($alias);
+ $html_author = htmlspecialchars ($author);
+ $lines[$alias] = "$html_alias \nSee: $html_author
\n\n";
+ // echo ("$alias\n");
+ } while ($db->NextRow ());
+ }
+}
+
+function FormatAuthors ($mode = 0) {
+ global $db, $lines, $dir_etext, $authors;
+
+ foreach ($authors as $fk_authors => $o) {
+ if (count ($o['titles'])) {
+ $html_author = htmlspecialchars ($o['author']);
+ if ($mode == 1 || $fk_authors == 0) {
+ $line = "\n";
+ } else {
+ $href = "/browse/authors/" . find_browse_page ($o['author']) . "#a$fk_authors";
+ $line = "\n";
+ }
+ $line .= "\n";
+
+ if ($mode == 1) {
+ // by-author page
+ if (isset ($o['aliases'])) {
+ foreach ($o['aliases'] as $alias) {
+ $line .= " $alias \n";
+ }
+ }
+
+ if (isset ($o['urls'])) {
+ foreach ($o['urls'] as $description => $url) {
+ $line .= " $description \n";
+ }
+ }
+ }
+
+ // output list of titles
+ foreach ($o['titles'] as $t) {
+ $role = (empty ($t['role']) || $t['role'] == "Creator") ? "" : " (as {$t['role']})";
+ $cls = $t['is_audio'] ? " class=\"pgdbaudio\"" : " class=\"pgdbetext\"";
+ $line .= " {$t['title']} ({$t['lang']})$role \n";
+ }
+ $line .= " \n\n";
+ $lines[$o['author']] = $line;
+ // echo ("{$o['author']}\n");
+ }
+ }
+}
+
+$dir = "browse";
+$dir_authors = "$dir/authors";
+$dir_titles = "$dir/titles";
+$dir_langs = "$dir/languages";
+$dir_loccs = "$dir/loccs";
+$dir_subjects = "$dir/subjects";
+$dir_categories = "$dir/categories";
+$dir_recent = "$dir/recent";
+$dir_feeds = "cache/epub/feeds";
+$dir_etext = "ebooks";
+$base_url = "http://$config->domain";
+
+@mkdir ("$config->documentroot/$dir", 0755);
+@mkdir ("$config->documentroot/$dir_authors", 0755);
+@mkdir ("$config->documentroot/$dir_titles", 0755);
+@mkdir ("$config->documentroot/$dir_langs", 0755);
+@mkdir ("$config->documentroot/$dir_loccs", 0755);
+@mkdir ("$config->documentroot/$dir_subjects", 0755);
+@mkdir ("$config->documentroot/$dir_categories", 0755);
+@mkdir ("$config->documentroot/$dir_recent", 0755);
+@mkdir ("$config->documentroot/$dir_feeds", 0755);
+
+$spans[1] = 'last 24 hours';
+$spans[7] = 'last 7 days';
+$spans[30] = 'last 30 days';
+
+$db = $config->db ();
+$db2 = $config->db ();
+$authors = array ();
+
+////////////////////////////////////////////////////////////////////////
+// load authors
+
+$authors[0]['author'] = "No Author Listed";
+
+$db->exec ("select * from authors");
+if ($db->FirstRow ()) {
+ do {
+ $fk_authors = $db->get ("pk", SQLINT);
+ $authors[$fk_authors]['author'] = FormatAuthorDate ($db);
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select * from aliases where alias_heading = 1 order by alias");
+if ($db->FirstRow ()) {
+ do {
+ $fk_authors = $db->get ("fk_authors", SQLINT);
+ $alias = htmlspecialchars ($db->get ("alias", SQLCHAR));
+ $authors[$fk_authors]['aliases'][] = $alias;
+ } while ($db->NextRow ());
+}
+
+$db->exec ("select * from author_urls order by description");
+if ($db->FirstRow ()) {
+ do {
+ $fk_authors = $db->get ("fk_authors", SQLINT);
+ $description = htmlspecialchars ($db->get ("description", SQLCHAR));
+ $url = htmlspecialchars ($db->get ("url", SQLCHAR));
+ $authors[$fk_authors]['urls'][$description] = $url;
+ } while ($db->NextRow ());
+}
+
+// echo ("$config->documentroot/$dir/navbar.html\n");
+if ($hd = fopen ("$config->documentroot/$dir/navbar.html", "w")) {
+ fputs ($hd, navbar ());
+ fclose ($hd);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+$db->exec ("create temporary table tmp_books as select * from v_books");
+
+////////////////////////////////////////////////////////////////////////////////
+// by-author
+
+// Postgres 7.3.3 at ibiblio doesn't dig multicolumn functional indexes
+$db->exec ("create index tmp_ix_books_authors on tmp_books (lower (author))");
+
+foreach ($config->browse_pages as $caption => $regexp) {
+
+ // titles for each author
+ $db->exec ("select * from tmp_books where author ~* '^$regexp' " .
+ "order by author, filing, lang");
+ LoadTitles ();
+
+ $lines = array ();
+ FormatAuthors (1);
+
+ $pklist = array ();
+ $db->exec ("select fk_authors from aliases where alias ~* '^$regexp'");
+ if ($db->FirstRow ()) {
+ do {
+ $pklist[] = $db->get ("fk_authors", SQLINT);
+ } while ($db->NextRow ());
+ }
+ FormatAliases ($pklist, 1, "^$regexp");
+ uksort ($lines, 'strcoll');
+
+ $fn = strtolower ($caption);
+
+ pageheader ("Browse By Author: $caption");
+ echo (navbar ());
+ echo ("\n\n");
+
+ foreach ($lines as $line) {
+ echo ($line);
+ }
+
+ echo ("
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_authors/$fn.html.utf8");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// by-lang
+
+$db->exec ("create index tmp_ix_books_langs on tmp_books (lang)");
+
+$db->exec ("select pk, lang from langs where pk in (select fk_langs from mn_books_langs)");
+
+if ($db->FirstRow ()) {
+ do {
+ $langs[$db->get ("lang", SQLCHAR)] = $db->get ("pk", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+foreach ($langs as $lang => $id) {
+ $caption = $lang;
+ $fn = $id;
+
+ if ($id == 'en') {
+ pageheader ("Browse By Language: $caption");
+ echo (navbar ());
+ echo ("There are too many english books to list them in one page. " .
+ "Please use the Browse-By-Author pages instead.
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_langs/$fn.html.utf8");
+ continue;
+ }
+
+ $db->exec ("select * from tmp_books where fk_books in
+(select fk_books from mn_books_langs where fk_langs = '$id'
+and tmp_books.fk_books = mn_books_langs.fk_books)
+order by lang, author, filing");
+
+ LoadTitles ();
+
+ $lines = array ();
+ FormatAuthors ();
+ FormatAliases (pklist ($authors));
+ uksort ($lines, 'strcoll');
+
+ pageheader ("Browse By Language: $caption");
+ echo (navbar ());
+ echo ("\n\n");
+
+ foreach ($lines as $line) {
+ echo ($line);
+ }
+
+ echo ("
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_langs/$fn.html.utf8");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// by-locc
+
+$db->exec ("select pk, locc from loccs where pk in (select fk_loccs from mn_books_loccs)");
+
+if ($db->FirstRow ()) {
+ do {
+ $loccs[$db->get ("locc", SQLCHAR)] = $db->get ("pk", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+foreach ($loccs as $locc => $fk_loccs) {
+ $caption = $locc;
+ $fn = strtolower ($fk_loccs);
+
+ // titles for each author
+ // $db->exec ("select * from tmp_books where fk_loccs = '$fk_loccs' " .
+ // "order by fk_loccs, author, filing");
+ $db->exec ("select * from tmp_books where fk_books in
+(select fk_books from mn_books_loccs where fk_loccs = '$fk_loccs'
+and tmp_books.fk_books = mn_books_loccs.fk_books)
+order by author, filing");
+
+ LoadTitles ();
+
+ $lines = array ();
+ FormatAuthors ();
+ FormatAliases (pklist ($authors));
+ uksort ($lines, 'strcoll');
+
+ pageheader ("Browse By Library of Congress Class: $caption");
+ echo (navbar ());
+ echo ("\n\n");
+
+ foreach ($lines as $line) {
+ echo ($line);
+ }
+
+ echo ("
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_loccs/$fn.html.utf8");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// by-category
+
+$db->exec ("select pk, category from categories");
+
+if ($db->FirstRow ()) {
+ do {
+ $categories[$db->get ("category", SQLCHAR)] = $db->get ("pk", SQLINT);
+ } while ($db->NextRow ());
+}
+
+foreach ($categories as $category => $id) {
+ $caption = $category;
+ $fn = $id;
+
+ if ($id == 0) {
+ pageheader ("Browse By Category: $caption");
+ echo (navbar ());
+ echo ("There are too many books in this category too list them in one page. " .
+ "Please use the Browse-By-Author pages instead.
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_langs/$fn.html.utf8");
+ continue;
+ }
+
+ $db->exec ("select * from tmp_books where fk_books in
+(select fk_books from mn_books_categories where fk_categories = $id
+and tmp_books.fk_books = mn_books_categories.fk_books)
+order by author, filing");
+ LoadTitles ();
+
+ $lines = array ();
+ FormatAuthors ();
+ FormatAliases (pklist ($authors));
+ uksort ($lines, 'strcoll');
+
+ pageheader ("Browse By Category: $caption");
+ echo (navbar ());
+ echo ("\n\n");
+
+ foreach ($lines as $line) {
+ echo ($line);
+ }
+
+ echo ("
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_categories/$fn.html.utf8");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// by-title
+
+$db->exec ("create index tmp_ix_books_titles on tmp_books (lower (filing))");
+
+foreach ($config->browse_pages as $caption => $regexp) {
+ $fn = strtolower ($caption);
+ pageheader ("Browse By Title: $caption");
+ echo (navbar ());
+ echo ("\n\n");
+
+ // titles
+ $db->exec ("select * from tmp_books where lower (filing) ~ '^$regexp' order by lower (filing), author, lang");
+
+ if ($db->FirstRow ()) {
+ do {
+ $etext = $db->get ("fk_books", SQLINT);
+ $fk_authors = $db->get ("fk_authors", SQLINT);
+ $title = str_replace ("\n", "
endtag>", $db->get ("title", SQLCHAR));
+ $author = $db->get ("author", SQLCHAR);
+ $lang = $db->get ("lang", SQLCHAR);
+ $is_audio = $db->get ("is_audio", SQLBOOL);
+ // echo ("$title\n");
+ $icon = $is_audio ? "
endtag>" : "";
+ echo ("
$title ($lang)$icon\n");
+ $href = "/$dir_authors/" . find_browse_page ($author) . "#a$fk_authors";
+ echo ("
by $author
\n\n");
+ } while ($db->NextRow ());
+ }
+
+ echo ("
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_titles/$fn.html.utf8");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// recent books
+
+$db->exec ("create index tmp_ix_books_fk_books on tmp_books (fk_books)");
+$rssbuffer = "";
+$books_output = array ();
+
+// clear titles
+foreach ($authors as $fk_authors => $dummy) {
+ $authors[$fk_authors]['titles'] = array ();
+}
+
+foreach ($spans as $span => $caption) {
+
+ $recents = array ();
+ $cutoff = date ("Y-m-d", time () - $span * 86400);
+
+ $db->exec ("select distinct fk_books from files " .
+ "where fk_books is not null and diskstatus = 0 and filename !~ '^cache' and filemtime >= '$cutoff 00:00:00'");
+ if ($db->FirstRow ()) {
+ do {
+ $recents[] = $db->get ("fk_books", SQLINT);
+ } while ($db->NextRow ());
+ }
+
+ $lines = array ();
+
+ if (count ($recents)) {
+ $recent = join (", ", $recents);
+
+ // titles for each author
+ $db->exec ("select * from tmp_books where fk_books in ($recent) order by author, filing, lang");
+ LoadTitles ();
+
+ FormatAuthors ();
+ FormatAliases (pklist ($authors));
+ uksort ($lines, 'strcoll');
+ }
+
+ $config->htmlheaderlinks[] = " ";
+ pageheader ("Books Posted or Updated Since: $cutoff");
+ echo (navbar ());
+ echo ("\n\n");
+
+ if (!count ($recents)) {
+ echo ("
No books posted.
\n\n");
+ }
+ foreach ($lines as $line) {
+ echo ($line);
+ }
+ if ($span == 1) {
+ // build rss
+ foreach ($authors as $author => $o) {
+ if (count ($o['titles'])) {
+ // output list of titles
+ foreach ($o['titles'] as $t) {
+ // avoid duplicates in rss
+ if (!isset ($books_output[$t['etext']])) {
+ $books_output[$t['etext']] = 1;
+ $friendlytitle = htmlspecialchars (friendlytitle ($t['etext'], 100));
+ $rssbuffer .= "
- \n";
+ $rssbuffer .= "
$friendlytitle \n";
+ $rssbuffer .= " $base_url/$dir_etext/{$t['etext']}\n";
+ $rssbuffer .= " Language: {$t['lang']} \n";
+ $rssbuffer .= " \n\n";
+ }
+ }
+ }
+ }
+ }
+ echo ("
\n\n");
+ pagefooterfile ("$config->documentroot/$dir_recent/last$span.html.utf8");
+
+ $config->htmlheaderlinks = array ();
+}
+
+// write rss feed
+if ($hd = fopen ($file = "$config->documentroot/$dir_feeds/today.rss", "w")) {
+ $pubdate = date ("r");
+
+ fputs ($hd, <<
+
+
+ Project Gutenberg Recently Posted or Updated EBooks
+ $base_url
+
+ EBooks posted or updated today on Project Gutenberg.
+ This feed is regenerated every night.
+
+ en-us
+ webmaster@gutenberg.org (Marcello Perathoner)
+ $pubdate
+ $pubdate
+
+EOF
+);
+
+ fputs ($hd, $rssbuffer);
+ fputs ($hd, " \n \n");
+ fclose ($hd);
+}
+
+?>
diff --git a/catalog/admin/make-rdf.php b/catalog/admin/make-rdf.php
new file mode 100644
index 0000000..d4f3d1e
--- /dev/null
+++ b/catalog/admin/make-rdf.php
@@ -0,0 +1,384 @@
+ 1) {
+ $s .= " <$tag>\n \n";
+ foreach ($a as $val) {
+ $s .= " $val \n";
+ }
+ $s .= " \n $tag>\n";
+ } else {
+ $val = $a[0];
+ $s .= " <$tag rdf:parseType=\"Literal\">$val$tag>\n";
+ }
+ } else {
+ $val = $a;
+ $s .= " <$tag rdf:parseType=\"Literal\">$val$tag>\n";
+ }
+ }
+ return $s;
+}
+
+function qout (&$book, $name, $tag, $tag2) {
+ if (!isset ($book[$name])) {
+ return "";
+ }
+ $a = $book[$name];
+ if (is_array ($a)) {
+ if (count ($a) > 1) {
+ $s = " <$tag>\n \n";
+ foreach ($a as $val) {
+ $s .= " <$tag2>$val $tag2> \n";
+ }
+ $s .= " \n $tag>\n";
+ return $s;
+ } else {
+ $val = $a[0];
+ return " <$tag><$tag2>$val $tag2>$tag>\n";
+ }
+ }
+ $val = $a;
+ return " <$tag><$tag2>$val $tag2>$tag>\n";
+}
+
+_log ("Initializing ...");
+
+$db = $config->db ();
+
+_log (" Connected to Database ...");
+
+$base_url = "http://www.gutenberg.org";
+$file_base = "$base_url";
+
+$now = date ("Y-m-d");
+
+$books = array ();
+
+_log (" Done\n");
+
+_log ("Loading data from database ...");
+
+_log (" Books");
+
+$db->exec ("select * from books");
+if ($db->FirstRow ()) {
+ do {
+ $pk = $db->get ("pk", SQLINT);
+ if ($reldate = $db->get ("release_date", SQLDATE)) {
+ $books[$pk]['release_date'] = date ("Y-m-d", $reldate);
+ $books[$pk]['downloads'] = $db->get ("downloads", SQLINT);
+ }
+ if ($db->get ("copyrighted", SQLINT)) {
+ $books[$pk]['copyrighted'] = 1;
+ }
+ } while ($db->NextRow ());
+}
+
+_log (" Authors");
+
+$db->exec ("select * from v_books_authors order by fk_books");
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $role = $db->get ("role", SQLCHAR);
+ if ($role == "Creator" || $role == "Author") {
+ $val = htmlspecialchars (FormatAuthorDate ($db));
+ $books[$fk_books]['creators'][] = $val;
+ } else {
+ $val = htmlspecialchars (FormatAuthorDateRole ($db));
+ $books[$fk_books]['contributors'][] = $val;
+ }
+ } while ($db->NextRow ());
+}
+
+_log (" FriendlyTitles");
+
+foreach ($books as $fk_books => $dummy) {
+ $books[$fk_books]['friendlytitle'][] = htmlspecialchars (friendlytitle ($fk_books));
+}
+
+/* _log (" Titles");
+
+$db->exec ("select * from titles");
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $title = htmlspecialchars ($db->get ("title", SQLCHAR));
+ // $title = preg_replace ("/\s*\n/", " ", $title);
+ switch ($db->get ("title_order", SQLINT)) {
+ case 1:
+ $books[$fk_books]['240'][] = $title; break;
+ case 2:
+ case 4:
+ case 5:
+ $books[$fk_books]['246'][] = $title; break;
+ case 3:
+ $books[$fk_books]['505'][] = $title; break;
+ }
+ } while ($db->NextRow ());
+} */
+
+_log (" Attributes");
+
+$db->exec ("select * from attributes");
+
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $fk_attriblist = (string) $db->get ("fk_attriblist", SQLINT);
+ $text = htmlspecialchars ($db->get ("text", SQLCHAR));
+ $books[$fk_books][$fk_attriblist][] = $text;
+ } while ($db->NextRow ());
+}
+
+_log (" Categories");
+
+$db->exec ("select * from mn_books_categories, categories where fk_categories = pk");
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $books[$fk_books]['categories'][] = $db->get ("category", SQLCHAR);
+ } while ($db->NextRow ());
+} else {
+ $books[$fk_books]['categories'][] = 'eBook';
+}
+
+_log (" Languages");
+
+$db->exec ("select * from mn_books_langs");
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $books[$fk_books]['languages'][] = $db->get ("fk_langs", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+_log (" Subjects");
+
+$db->exec ("select * from mn_books_subjects, subjects where fk_subjects = pk");
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $subject = htmlspecialchars ($db->get ("subject", SQLCHAR));
+ $books[$fk_books]['subjects'][] = $subject;
+ } while ($db->NextRow ());
+}
+
+_log (" LoCC");
+
+$db->exec ("select * from mn_books_loccs");
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $books[$fk_books]['loccs'][] = $db->get ("fk_loccs", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+_log (" Done\n");
+
+$fp = fopen ("php://stdout", "w");
+
+$s = <<< EOF
+
+
+
+
+
+]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $now
+
+
+
+EOF;
+
+fputs ($fp, $s);
+
+// debug
+// $books = array_slice ($books, 0, 500);
+
+reset ($books);
+
+while (list ($fk_books, $book) = each ($books)) {
+ $s = "\n";
+ $s .= " &pg; \n";
+
+ $s .= lout ($book, '240', 'dc:title');
+ $s .= lout ($book, '245', 'dc:title');
+ $s .= lout ($book, '246', 'dc:alternative');
+ $s .= lout ($book, '500', 'dc:description');
+ $s .= lout ($book, '505', 'dc:tableOfContents');
+
+ $s .= lout ($book, 'creators', 'dc:creator');
+ $s .= lout ($book, 'contributors', 'dc:contributor');
+ $s .= lout ($book, 'friendlytitle', 'pgterms:friendlytitle');
+
+ $s .= qout ($book, 'languages', 'dc:language', 'dcterms:ISO639-2');
+ $s .= qout ($book, 'subjects', 'dc:subject', 'dcterms:LCSH');
+ $s .= qout ($book, 'loccs', 'dc:subject', 'dcterms:LCC');
+ $s .= qout ($book, 'release_date', 'dc:created', 'dcterms:W3CDTF');
+ $s .= qout ($book, 'downloads', 'pgterms:downloads', 'xsd:nonNegativeInteger');
+ $s .= qout ($book, 'categories', 'dc:type', 'pgterms:category');
+
+ if (isset ($book['copyrighted'])) {
+ $s .= " Copyrighted work. See license inside work. \n";
+ } else {
+ $s .= " \n";
+ }
+
+ $s .= " \n\n";
+ fputs ($fp, $s);
+}
+
+$books = null;
+
+// files
+
+$db->exec ("select fk_books, mediatype, filetype, fk_filetypes, fk_compressions, fk_encodings, " .
+ "edition, filename, filesize, filemtime " .
+ "from files " .
+ "left join filetypes on files.fk_filetypes = filetypes.pk " .
+ "where fk_books is not null and obsoleted = 0 and diskstatus = 0 " .
+ "order by fk_books, filename;");
+
+
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $filename = $db->get ("filename", SQLCHAR);
+ $filesize = $db->get ("filesize", SQLINT);
+ $filetype = $db->get ("filetype", SQLCHAR);
+ $fk_filetypes = $db->get ("fk_filetypes", SQLCHAR);
+ $filemtime = $db->get ("filemtime", SQLDATE);
+ $mediatype = $db->get ("mediatype", SQLCHAR);
+ $fk_encodings = $db->get ("fk_encodings", SQLCHAR);
+ $fk_compressions = $db->get ("fk_compressions", SQLCHAR);
+
+ if (!strncmp ($filename, "cache/", 6)) {
+ $filename = "&f;$filename";
+ } else {
+ $filename = "&f;dirs/$filename";
+ }
+
+ $mtime = date ("Y-m-d", $filemtime);
+
+ if (!empty ($fk_encodings) && !strncmp ($mediatype, "text/", 5)) {
+ $mediatype .= "; charset=\"$fk_encodings\"";
+ }
+ if (empty ($mediatype)) {
+ $mediatype = "application/octet-stream";
+ if (!empty ($fk_filetypes)) {
+ $mediatype .= "; type=\"$filetype ($fk_filetypes)\"";
+ }
+ }
+ $compression = "";
+ if ($fk_compressions == "zip") {
+ $compression = "\n application/zip ";
+ }
+
+ $s = "
+
+ $mediatype $compression
+ $filesize
+ $mtime
+
+
+";
+ fputs ($fp, $s);
+
+ } while ($db->NextRow ());
+}
+
+fputs ($fp, "\n \n");
+
+fclose ($fp);
+
+_log (" Done!\n");
+
+?>
diff --git a/catalog/admin/make-rdf.php~ b/catalog/admin/make-rdf.php~
new file mode 100644
index 0000000..1ecccd1
--- /dev/null
+++ b/catalog/admin/make-rdf.php~
@@ -0,0 +1,383 @@
+ 1) {
+ $s .= " <$tag>\n \n";
+ foreach ($a as $val) {
+ $s .= " $val \n";
+ }
+ $s .= " \n $tag>\n";
+ } else {
+ $val = $a[0];
+ $s .= " <$tag rdf:parseType=\"Literal\">$val$tag>\n";
+ }
+ } else {
+ $val = $a;
+ $s .= " <$tag rdf:parseType=\"Literal\">$val$tag>\n";
+ }
+ }
+ return $s;
+}
+
+function qout (&$book, $name, $tag, $tag2) {
+ if (!isset ($book[$name])) {
+ return "";
+ }
+ $a = $book[$name];
+ if (is_array ($a)) {
+ if (count ($a) > 1) {
+ $s = " <$tag>\n \n";
+ foreach ($a as $val) {
+ $s .= " <$tag2>$val $tag2> \n";
+ }
+ $s .= " \n $tag>\n";
+ return $s;
+ } else {
+ $val = $a[0];
+ return " <$tag><$tag2>$val $tag2>$tag>\n";
+ }
+ }
+ $val = $a;
+ return " <$tag><$tag2>$val $tag2>$tag>\n";
+}
+
+_log ("Initializing ...");
+
+$db = $config->db ();
+
+_log (" Connected to Database ...");
+
+$base_url = "http://www.gutenberg.org";
+$file_base = "$base_url";
+
+$now = date ("Y-m-d");
+
+$books = array ();
+
+_log (" Done\n");
+
+_log ("Loading data from database ...");
+
+_log (" Books");
+
+$db->exec ("select * from books");
+if ($db->FirstRow ()) {
+ do {
+ $pk = $db->get ("pk", SQLINT);
+ if ($reldate = $db->get ("release_date", SQLDATE)) {
+ $books[$pk]['release_date'] = date ("Y-m-d", $reldate);
+ $books[$pk]['downloads'] = $db->get ("downloads", SQLINT);
+ }
+ if ($db->get ("copyrighted", SQLINT)) {
+ $books[$pk]['copyrighted'] = 1;
+ }
+ } while ($db->NextRow ());
+}
+
+_log (" Authors");
+
+$db->exec ("select * from v_books_authors order by fk_books");
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $role = $db->get ("role", SQLCHAR);
+ if ($role == "Creator" || $role == "Author") {
+ $val = htmlspecialchars (FormatAuthorDate ($db));
+ $books[$fk_books]['creators'][] = $val;
+ } else {
+ $val = htmlspecialchars (FormatAuthorDateRole ($db));
+ $books[$fk_books]['contributors'][] = $val;
+ }
+ } while ($db->NextRow ());
+}
+
+_log (" FriendlyTitles");
+
+foreach ($books as $fk_books => $dummy) {
+ $books[$fk_books]['friendlytitle'][] = htmlspecialchars (friendlytitle ($fk_books));
+}
+
+/* _log (" Titles");
+
+$db->exec ("select * from titles");
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $title = htmlspecialchars ($db->get ("title", SQLCHAR));
+ // $title = preg_replace ("/\s*\n/", " ", $title);
+ switch ($db->get ("title_order", SQLINT)) {
+ case 1:
+ $books[$fk_books]['240'][] = $title; break;
+ case 2:
+ case 4:
+ case 5:
+ $books[$fk_books]['246'][] = $title; break;
+ case 3:
+ $books[$fk_books]['505'][] = $title; break;
+ }
+ } while ($db->NextRow ());
+} */
+
+_log (" Attributes");
+
+$db->exec ("select * from attributes");
+
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $fk_attriblist = (string) $db->get ("fk_attriblist", SQLINT);
+ $text = htmlspecialchars ($db->get ("text", SQLCHAR));
+ $books[$fk_books][$fk_attriblist][] = $text;
+ } while ($db->NextRow ());
+}
+
+_log (" Categories");
+
+$db->exec ("select * from mn_books_categories, categories where fk_categories = pk");
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $books[$fk_books]['categories'][] = $db->get ("category", SQLCHAR);
+ } while ($db->NextRow ());
+} else {
+ $books[$fk_books]['categories'][] = 'eBook';
+}
+
+_log (" Languages");
+
+$db->exec ("select * from mn_books_langs");
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $books[$fk_books]['languages'][] = $db->get ("fk_langs", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+_log (" Subjects");
+
+$db->exec ("select * from mn_books_subjects, subjects where fk_subjects = pk");
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $subject = htmlspecialchars ($db->get ("subject", SQLCHAR));
+ $books[$fk_books]['subjects'][] = $subject;
+ } while ($db->NextRow ());
+}
+
+_log (" LoCC");
+
+$db->exec ("select * from mn_books_loccs");
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $books[$fk_books]['loccs'][] = $db->get ("fk_loccs", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+_log (" Done\n");
+
+$fp = fopen ("php://stdout", "w");
+
+$s = <<< EOF
+
+
+
+
+
+]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $now
+
+
+
+EOF;
+
+fputs ($fp, $s);
+
+// debug
+// $books = array_slice ($books, 0, 500);
+
+reset ($books);
+
+while (list ($fk_books, $book) = each ($books)) {
+ $s = "\n";
+ $s .= " &pg; \n";
+
+ $s .= lout ($book, '240', 'dc:title');
+ $s .= lout ($book, '245', 'dc:title');
+ $s .= lout ($book, '246', 'dc:alternative');
+ $s .= lout ($book, '500', 'dc:description');
+ $s .= lout ($book, '505', 'dc:tableOfContents');
+
+ $s .= lout ($book, 'creators', 'dc:creator');
+ $s .= lout ($book, 'contributors', 'dc:contributor');
+ $s .= lout ($book, 'friendlytitle', 'pgterms:friendlytitle');
+
+ $s .= qout ($book, 'languages', 'dc:language', 'dcterms:ISO639-2');
+ $s .= qout ($book, 'subjects', 'dc:subject', 'dcterms:LCSH');
+ $s .= qout ($book, 'loccs', 'dc:subject', 'dcterms:LCC');
+ $s .= qout ($book, 'release_date', 'dc:created', 'dcterms:W3CDTF');
+ $s .= qout ($book, 'downloads', 'pgterms:downloads', 'xsd:nonNegativeInteger');
+ $s .= qout ($book, 'categories', 'dc:type', 'pgterms:category');
+
+ if (isset ($book['copyrighted'])) {
+ $s .= " Copyrighted work. See license inside work. \n";
+ } else {
+ $s .= " \n";
+ }
+
+ $s .= " \n\n";
+ fputs ($fp, $s);
+}
+
+$books = null;
+
+// files
+
+$db->exec ("select fk_books, mediatype, filetype, fk_filetypes, fk_compressions, fk_encodings, " .
+ "edition, filename, filesize, filemtime " .
+ "from files " .
+ "left join filetypes on files.fk_filetypes = filetypes.pk " .
+ "where fk_books is not null and obsoleted = 0 and diskstatus = 0 " .
+ "order by fk_books, filename;");
+
+
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $filename = $db->get ("filename", SQLCHAR);
+ $filesize = $db->get ("filesize", SQLINT);
+ $filetype = $db->get ("filetype", SQLCHAR);
+ $fk_filetypes = $db->get ("fk_filetypes", SQLCHAR);
+ $filemtime = $db->get ("filemtime", SQLDATE);
+ $mediatype = $db->get ("mediatype", SQLCHAR);
+ $fk_encodings = $db->get ("fk_encodings", SQLCHAR);
+ $fk_compressions = $db->get ("fk_compressions", SQLCHAR);
+
+ if (!strncmp ($filename, "cache/", 6)) {
+ $filename = "&f;$filename";
+ } else {
+ $filename = "&f;dirs/$filename";
+ }
+
+ $mtime = date ("Y-m-d", $filemtime);
+
+ if (!empty ($fk_encodings) && !strncmp ($mediatype, "text/", 5)) {
+ $mediatype .= "; charset=\"$fk_encodings\"";
+ }
+ if (empty ($mediatype)) {
+ $mediatype = "application/octet-stream";
+ if (!empty ($fk_filetypes)) {
+ $mediatype .= "; type=\"$filetype ($fk_filetypes)\"";
+ }
+ }
+ $compression = "";
+ if ($fk_compressions == "zip") {
+ $compression = "\n application/zip ";
+ }
+
+ $s = "
+
+ $mediatype $compression
+ $filesize
+ $mtime
+
+
+";
+ fputs ($fp, $s);
+
+ } while ($db->NextRow ());
+}
+
+fputs ($fp, "\n \n");
+
+fclose ($fp);
+
+_log (" Done!\n");
+
+?>
\ No newline at end of file
diff --git a/catalog/admin/make-topten.php b/catalog/admin/make-topten.php
new file mode 100644
index 0000000..607e26c
--- /dev/null
+++ b/catalog/admin/make-topten.php
@@ -0,0 +1,263 @@
+page_encoding = \"UTF-8\";
+ pageheader (\"$title\");
+?>\n\n";
+}
+
+$dir = "browse";
+$dir_scores = "$dir/scores";
+
+@mkdir ("$config->documentroot/$dir", 0755);
+@mkdir ("$config->documentroot/$dir_scores", 0755);
+
+$db = $config->db ();
+$db2 = $config->db ();
+
+////////////////////////////////////////////////////////////////////////////////
+// top scores
+
+// disqualified because they are mp3 files and have "House" in title
+// its amazing how many kids try to download these
+// moreover "Usher" seems to be a rap artist
+$disqualifiedbooks = "0, 6550, 6557, 9280, 9695, 9714";
+// unknown, anonymous and various
+$disqualifiedauthors = "49, 116, 216";
+
+function downloads ($where = "") {
+ global $db2, $config, $disqualifiedbooks;
+ $s = "";
+
+ $db2->exec ("
+SELECT SUM (downloads) AS downloads
+FROM dl
+WHERE $where");
+
+ if ($db2->FirstRow ()) {
+ return $db2->get ("downloads", SQLINT);
+ }
+
+ return 0;
+}
+
+function topbooks ($num, $where = "") {
+ global $db2, $config, $disqualifiedbooks;
+ $s = "";
+
+ $db2->exec ("
+SELECT fk_books, SUM (downloads) AS downloads
+FROM dl
+WHERE $where
+GROUP BY fk_books
+ORDER BY downloads DESC LIMIT $num");
+
+ $s .= "\n";
+
+ if ($db2->FirstRow ()) {
+ do {
+ $fk_books = $db2->get ("fk_books", SQLINT);
+ $downloads = $db2->get ("downloads", SQLINT);
+ $friendlytitle = friendlytitle ($fk_books, 100);
+ $s .= "etext/$fk_books\">$friendlytitle ($downloads) \n";
+ } while ($db2->NextRow ());
+ }
+
+ $s .= " \n";
+ return $s;
+}
+
+function topauthors ($num, $where = "") {
+ global $db2, $config, $disqualifiedbooks, $disqualifiedauthors;
+ $s = "";
+
+ $db2->exec ("
+SELECT author, fk_authors, SUM (dl.downloads) as downloads
+FROM authors, mn_books_authors, dl
+WHERE $where
+ AND authors.pk = mn_books_authors.fk_authors
+ AND mn_books_authors.fk_books = dl.fk_books
+ AND fk_authors NOT IN ($disqualifiedauthors)
+GROUP BY author, fk_authors
+ORDER BY downloads DESC LIMIT $num");
+
+ $s .= "\n";
+
+ if ($db2->FirstRow ()) {
+ do {
+ $author = $db2->get ("author", SQLCHAR);
+ $fk_authors = $db2->get ("fk_authors", SQLINT);
+ $downloads = $db2->get ("downloads", SQLINT);
+ $href = find_browse_page ($author) . "#a$fk_authors";
+
+ $s .= ("$author ($downloads) \n");
+ } while ($db2->NextRow ());
+ }
+
+ $s .= " \n";
+ return $s;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// start main
+
+echo ("creating temp table ...");
+
+$db2->exec ("CREATE TEMP TABLE dl AS
+SELECT scores.book_downloads.fk_books, scores.book_downloads.date,
+ scores.book_downloads.downloads, fk_langs
+FROM scores.book_downloads, mn_books_langs
+WHERE scores.book_downloads.fk_books = mn_books_langs.fk_books
+AND scores.book_downloads.fk_books NOT IN ($disqualifiedbooks)");
+
+echo (" done.\n");
+
+$langs = array ();
+
+$langs[] = array ("", 100); // Top 100 all languages
+$langs[] = array ("", 1000); // Top 1000 all languages
+
+$db2->exec ("select fk_langs, count (fk_langs) as cnt from mn_books_langs group by fk_langs order by cnt desc;");
+if ($db2->FirstRow ()) {
+ do {
+ $fk_langs = $db2->get ("fk_langs", SQLCHAR);
+ $langs[] = array ($fk_langs, 100); // Top 100 this language
+ } while ($db2->NextRow ());
+}
+
+echo (" done.\n");
+
+$db2->exec ("select max (date) as latest, min (date) as earliest from scores.book_downloads");
+$latest = date ("Y-m-d", $db2->get ("latest", SQLDATE));
+$earliest = date ("Y-m-d", $db2->get ("earliest", SQLDATE));
+
+// start output
+
+foreach ($langs as $l) {
+ $lang = $l[0];
+ $num = $l[1];
+
+ $filesuffix = "";
+ $titlesuffix = "$num";
+ $langwhere = "";
+
+ if ($num != 100) {
+ $filesuffix .= "$num";
+ }
+
+ if (!empty ($lang)) {
+ $filesuffix .= "-$lang";
+ $titlesuffix .= " ($lang)";
+ $langwhere = "fk_langs = '$lang' AND ";
+ }
+
+ if ($hd = fopen ($file = "$config->documentroot/$dir_scores/top$filesuffix.php", "w")) {
+ echo ("writing $file ... downloads ...\n");
+
+ $d1 = downloads ("$langwhere date >= current_date - interval '1 days'");
+ $d7 = downloads ("$langwhere date >= current_date - interval '7 days'");
+ $d30 = downloads ("$langwhere date >= current_date - interval '30 days'");
+
+ fputs ($hd, mk_header ("Top $titlesuffix"));
+
+ $s = <<< EOF
+To determine the ranking we count the times each file gets downloaded.
+Both HTTP and FTP transfers are counted.
+Only transfers from ibiblio.org are counted as we have no access to our mirrors log files.
+Multiple downloads from the same IP address on the same day count as one download.
+IP addresses that download more than 100 files a day are considered
+robots and are not considered.
+Books made out of multiple files like most audio books are counted
+if any file is downloaded.
+
+
+ Downloaded Books
+ $latest $d1
+ last 7 days $d7
+ last 30 days $d30
+
+
+Pretty Pictures
+
+EOF;
+
+ fputs ($hd, $s);
+
+ $links = "
+ Top $num EBooks yesterday —
+ Top $num Authors yesterday —
+ Top $num EBooks last 7 days —
+ Top $num Authors last 7 days —
+ Top $num EBooks last 30 days —
+ Top $num Authors last 30 days
+
+
+";
+
+ // Yesterday
+
+ echo (" yesterday ... books ...");
+
+ fputs ($hd, $links);
+ fputs ($hd, "Top $num EBooks yesterday \n\n");
+
+ fputs ($hd, topbooks ($num, "$langwhere date >= current_date - interval '1 days'"));
+
+ echo (" authors ...");
+
+ fputs ($hd, $links);
+ fputs ($hd, "Top $num Authors yesterday \n\n");
+
+ fputs ($hd, topauthors ($num, "$langwhere date >= current_date - interval '1 days'"));
+
+ // Last 7 days
+
+ echo (" last 7 days ... books ...");
+
+ fputs ($hd, $links);
+ fputs ($hd, "Top $num EBooks last 7 days \n\n");
+
+ fputs ($hd, topbooks ($num, "$langwhere date >= current_date - interval '7 days'"));
+
+ echo (" authors ...");
+
+ fputs ($hd, $links);
+ fputs ($hd, "Top $num Authors last 7 days \n\n");
+
+ fputs ($hd, topauthors ($num, "$langwhere date >= current_date - interval '7 days'"));
+
+ // Last 30 days
+
+ echo (" last 30 days ... books ...");
+
+ fputs ($hd, $links);
+ fputs ($hd, "Top $num EBooks last 30 days \n\n");
+
+ fputs ($hd, topbooks ($num, "$langwhere date >= current_date - interval '30 days'"));
+
+ echo (" authors ...");
+
+ fputs ($hd, $links);
+ fputs ($hd, "Top $num Authors last 30 days \n\n");
+
+ fputs ($hd, topauthors ($num, "$langwhere date >= current_date - interval '30 days'"));
+
+ fputs ($hd, $links);
+
+ fputs ($hd, "\n");
+ fclose ($hd);
+
+ echo (" done.\n");
+ }
+}
+
+?>
diff --git a/catalog/admin/make-topten.php~ b/catalog/admin/make-topten.php~
new file mode 100644
index 0000000..73e7f2f
--- /dev/null
+++ b/catalog/admin/make-topten.php~
@@ -0,0 +1,262 @@
+page_encoding = \"UTF-8\";
+ pageheader (\"$title\");
+?>\n\n";
+}
+
+$dir = "browse";
+$dir_scores = "$dir/scores";
+
+@mkdir ("$config->documentroot/$dir", 0755);
+@mkdir ("$config->documentroot/$dir_scores", 0755);
+
+$db = $config->db ();
+$db2 = $config->db ();
+
+////////////////////////////////////////////////////////////////////////////////
+// top scores
+
+// disqualified because they are mp3 files and have "House" in title
+// its amazing how many kids try to download these
+// moreover "Usher" seems to be a rap artist
+$disqualifiedbooks = "0, 6550, 6557, 9280, 9695, 9714";
+// unknown, anonymous and various
+$disqualifiedauthors = "49, 116, 216";
+
+function downloads ($where = "") {
+ global $db2, $config, $disqualifiedbooks;
+ $s = "";
+
+ $db2->exec ("
+SELECT SUM (downloads) AS downloads
+FROM dl
+WHERE $where");
+
+ if ($db2->FirstRow ()) {
+ return $db2->get ("downloads", SQLINT);
+ }
+
+ return 0;
+}
+
+function topbooks ($num, $where = "") {
+ global $db2, $config, $disqualifiedbooks;
+ $s = "";
+
+ $db2->exec ("
+SELECT fk_books, SUM (downloads) AS downloads
+FROM dl
+WHERE $where
+GROUP BY fk_books
+ORDER BY downloads DESC LIMIT $num");
+
+ $s .= "\n";
+
+ if ($db2->FirstRow ()) {
+ do {
+ $fk_books = $db2->get ("fk_books", SQLINT);
+ $downloads = $db2->get ("downloads", SQLINT);
+ $friendlytitle = friendlytitle ($fk_books, 100);
+ $s .= "etext/$fk_books\">$friendlytitle ($downloads) \n";
+ } while ($db2->NextRow ());
+ }
+
+ $s .= " \n";
+ return $s;
+}
+
+function topauthors ($num, $where = "") {
+ global $db2, $config, $disqualifiedbooks, $disqualifiedauthors;
+ $s = "";
+
+ $db2->exec ("
+SELECT author, fk_authors, SUM (dl.downloads) as downloads
+FROM authors, mn_books_authors, dl
+WHERE $where
+ AND authors.pk = mn_books_authors.fk_authors
+ AND mn_books_authors.fk_books = dl.fk_books
+ AND fk_authors NOT IN ($disqualifiedauthors)
+GROUP BY author, fk_authors
+ORDER BY downloads DESC LIMIT $num");
+
+ $s .= "\n";
+
+ if ($db2->FirstRow ()) {
+ do {
+ $author = $db2->get ("author", SQLCHAR);
+ $fk_authors = $db2->get ("fk_authors", SQLINT);
+ $downloads = $db2->get ("downloads", SQLINT);
+ $href = find_browse_page ($author) . "#a$fk_authors";
+
+ $s .= ("$author ($downloads) \n");
+ } while ($db2->NextRow ());
+ }
+
+ $s .= " \n";
+ return $s;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// start main
+
+echo ("creating temp table ...");
+
+$db2->exec ("CREATE TEMP TABLE dl AS
+SELECT scores.book_downloads.fk_books, scores.book_downloads.date,
+ scores.book_downloads.downloads, fk_langs
+FROM scores.book_downloads, mn_books_langs
+WHERE scores.book_downloads.fk_books = mn_books_langs.fk_books
+AND scores.book_downloads.fk_books NOT IN ($disqualifiedbooks)");
+
+echo (" done.\n");
+
+$langs = array ();
+
+$langs[] = array ("", 100); // Top 100 all languages
+$langs[] = array ("", 1000); // Top 1000 all languages
+
+$db2->exec ("select fk_langs, count (fk_langs) as cnt from mn_books_langs group by fk_langs order by cnt desc;");
+if ($db2->FirstRow ()) {
+ do {
+ $fk_langs = $db2->get ("fk_langs", SQLCHAR);
+ $langs[] = array ($fk_langs, 100); // Top 100 this language
+ } while ($db2->NextRow ());
+}
+
+echo (" done.\n");
+
+$db2->exec ("select max (date) as latest, min (date) as earliest from scores.book_downloads");
+$latest = date ("Y-m-d", $db2->get ("latest", SQLDATE));
+$earliest = date ("Y-m-d", $db2->get ("earliest", SQLDATE));
+
+// start output
+
+foreach ($langs as $l) {
+ $lang = $l[0];
+ $num = $l[1];
+
+ $filesuffix = "";
+ $titlesuffix = "$num";
+ $langwhere = "";
+
+ if ($num != 100) {
+ $filesuffix .= "$num";
+ }
+
+ if (!empty ($lang)) {
+ $filesuffix .= "-$lang";
+ $titlesuffix .= " ($lang)";
+ $langwhere = "fk_langs = '$lang' AND ";
+ }
+
+ if ($hd = fopen ($file = "$config->documentroot/$dir_scores/top$filesuffix.php", "w")) {
+ echo ("writing $file ... downloads ...\n");
+
+ $d1 = downloads ("$langwhere date >= current_date - interval '1 days'");
+ $d7 = downloads ("$langwhere date >= current_date - interval '7 days'");
+ $d30 = downloads ("$langwhere date >= current_date - interval '30 days'");
+
+ fputs ($hd, mk_header ("Top $titlesuffix"));
+
+ $s = <<< EOF
+To determine the ranking we count the times each file gets downloaded.
+Both HTTP and FTP transfers are counted.
+Only transfers from ibiblio.org are counted as we have no access to our mirrors log files.
+Multiple downloads from the same IP address on the same day count as one download.
+IP addresses that download more than 100 files a day are considered
+robots and are not considered.
+Books made out of multiple files like most audio books are counted
+if any file is downloaded.
+
+
+ Downloaded Books
+ $latest $d1
+ last 7 days $d7
+ last 30 days $d30
+
+
+Pretty Pictures
+
+EOF;
+
+ fputs ($hd, $s);
+
+ $links = "
+ Top $num EBooks yesterday —
+ Top $num Authors yesterday —
+ Top $num EBooks last 7 days —
+ Top $num Authors last 7 days —
+ Top $num EBooks last 30 days —
+ Top $num Authors last 30 days
+
+
+";
+
+ // Yesterday
+
+ echo (" yesterday ... books ...");
+
+ fputs ($hd, $links);
+ fputs ($hd, "Top $num EBooks yesterday \n\n");
+
+ fputs ($hd, topbooks ($num, "$langwhere date >= current_date - interval '1 days'"));
+
+ echo (" authors ...");
+
+ fputs ($hd, $links);
+ fputs ($hd, "Top $num Authors yesterday \n\n");
+
+ fputs ($hd, topauthors ($num, "$langwhere date >= current_date - interval '1 days'"));
+
+ // Last 7 days
+
+ echo (" last 7 days ... books ...");
+
+ fputs ($hd, $links);
+ fputs ($hd, "Top $num EBooks last 7 days \n\n");
+
+ fputs ($hd, topbooks ($num, "$langwhere date >= current_date - interval '7 days'"));
+
+ echo (" authors ...");
+
+ fputs ($hd, $links);
+ fputs ($hd, "Top $num Authors last 7 days \n\n");
+
+ fputs ($hd, topauthors ($num, "$langwhere date >= current_date - interval '7 days'"));
+
+ // Last 30 days
+
+ echo (" last 30 days ... books ...");
+
+ fputs ($hd, $links);
+ fputs ($hd, "Top $num EBooks last 30 days \n\n");
+
+ fputs ($hd, topbooks ($num, "$langwhere date >= current_date - interval '30 days'"));
+
+ echo (" authors ...");
+
+ fputs ($hd, $links);
+ fputs ($hd, "Top $num Authors last 30 days \n\n");
+
+ fputs ($hd, topauthors ($num, "$langwhere date >= current_date - interval '30 days'"));
+
+ fputs ($hd, $links);
+
+ fputs ($hd, "\n");
+ fclose ($hd);
+
+ echo (" done.\n");
+ }
+}
+
+?>
diff --git a/catalog/admin/mirror.php b/catalog/admin/mirror.php
new file mode 100644
index 0000000..4c22e80
--- /dev/null
+++ b/catalog/admin/mirror.php
@@ -0,0 +1,77 @@
+db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getstr ("fk_mirrors");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this mirror.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ $f->Text ("continent", "continent", "Continent", SQLCHAR, 80, 80, false);
+ $f->Text ("nation", "nation", "Nation", SQLCHAR, 80, 80, false);
+ $f->Text ("location", "location", "Location", SQLCHAR, 80, 80, false);
+ $f->Text ("provider", "provider", "Provider", SQLCHAR, 80, 240, true);
+ $f->Text ("url", "url", "URL", SQLCHAR, 80, 240, true);
+ $f->TextArea ("note", "note", "Note", SQLCHAR, 4, 80, false);
+
+ $f->LoadData ("select * from mirrors where pk = '$fk_mirrors'");
+}
+$f->Hidden ("fk_mirrors");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into mirrors " . $sql)) {
+ msg ("Mirror added !");
+ } else {
+ error_msg ("Could not add mirror!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update mirrors set " . $sql . "where pk = '$fk_mirrors'")) {
+ msg ("Mirror modified !");
+ } else {
+ error_msg ("Could not modify mirror !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from mirrors where pk = '$fk_mirrors'")) {
+ msg ("Mirror deleted !");
+ } else {
+ error_msg ("Could not delete mirror !");
+ }
+}
+
+if (isupdate ()) {
+ if (!isupdatemode ("delete")) {
+ p ("" .
+ "Back to Mirror ");
+ }
+} else {
+ $f->Output ($caption, $caption);
+}
+
+p ("Back to Mirror List ");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mirror.php~ b/catalog/admin/mirror.php~
new file mode 100644
index 0000000..1088f6e
--- /dev/null
+++ b/catalog/admin/mirror.php~
@@ -0,0 +1,76 @@
+db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getstr ("fk_mirrors");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this mirror.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ $f->Text ("continent", "continent", "Continent", SQLCHAR, 80, 80, false);
+ $f->Text ("nation", "nation", "Nation", SQLCHAR, 80, 80, false);
+ $f->Text ("location", "location", "Location", SQLCHAR, 80, 80, false);
+ $f->Text ("provider", "provider", "Provider", SQLCHAR, 80, 240, true);
+ $f->Text ("url", "url", "URL", SQLCHAR, 80, 240, true);
+ $f->TextArea ("note", "note", "Note", SQLCHAR, 4, 80, false);
+
+ $f->LoadData ("select * from mirrors where pk = '$fk_mirrors'");
+}
+$f->Hidden ("fk_mirrors");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into mirrors " . $sql)) {
+ msg ("Mirror added !");
+ } else {
+ error_msg ("Could not add mirror!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update mirrors set " . $sql . "where pk = '$fk_mirrors'")) {
+ msg ("Mirror modified !");
+ } else {
+ error_msg ("Could not modify mirror !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from mirrors where pk = '$fk_mirrors'")) {
+ msg ("Mirror deleted !");
+ } else {
+ error_msg ("Could not delete mirror !");
+ }
+}
+
+if (isupdate ()) {
+ if (!isupdatemode ("delete")) {
+ p ("" .
+ "Back to Mirror ");
+ }
+} else {
+ $f->Output ($caption, $caption);
+}
+
+p ("Back to Mirror List ");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mirrors_list.php b/catalog/admin/mirrors_list.php
new file mode 100644
index 0000000..ecc2a7d
--- /dev/null
+++ b/catalog/admin/mirrors_list.php
@@ -0,0 +1,33 @@
+AddColumn ("$prefix=edit&fk_mirrors=#pk#\">Edit",
+ "$prefix=add\">Add", "narrow");
+ $this->AddColumn ("$prefix=delete&fk_mirrors=#pk#\">Delete", "", "narrow");
+ // $this->AddSimpleColumn ("continent", "Continent");
+ $this->AddSimpleColumn ("nation", "Nation");
+ $this->AddSimpleColumn ("location", "Location");
+ $this->AddSimpleColumn ("provider", "Provider");
+ $this->AddSimpleColumn ("url", "URL");
+ $this->AddSimpleColumn ("note", "Note");
+ }
+}
+
+$db = $config->db ();
+
+$db->exec ("select * from mirrors order by nation, location, provider;");
+$table = new ListMirrorsTable ();
+$table->PrintTable ($db, $caption);
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mirrors_list.php~ b/catalog/admin/mirrors_list.php~
new file mode 100644
index 0000000..92ef326
--- /dev/null
+++ b/catalog/admin/mirrors_list.php~
@@ -0,0 +1,32 @@
+AddColumn ("$prefix=edit&fk_mirrors=#pk#\">Edit",
+ "$prefix=add\">Add", "narrow");
+ $this->AddColumn ("$prefix=delete&fk_mirrors=#pk#\">Delete", "", "narrow");
+ // $this->AddSimpleColumn ("continent", "Continent");
+ $this->AddSimpleColumn ("nation", "Nation");
+ $this->AddSimpleColumn ("location", "Location");
+ $this->AddSimpleColumn ("provider", "Provider");
+ $this->AddSimpleColumn ("url", "URL");
+ $this->AddSimpleColumn ("note", "Note");
+ }
+}
+
+$db = $config->db ();
+
+$db->exec ("select * from mirrors order by nation, location, provider;");
+$table = new ListMirrorsTable ();
+$table->PrintTable ($db, $caption);
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mn_books_authors.php b/catalog/admin/mn_books_authors.php
new file mode 100644
index 0000000..0ae4122
--- /dev/null
+++ b/catalog/admin/mn_books_authors.php
@@ -0,0 +1,80 @@
+db ();
+$db->logger = new logger ();
+
+getint ("fk_books");
+getint ("fk_authors");
+getstr ("fk_roles");
+getint ("heading");
+$sql_fk_roles = $db->f ($fk_roles, SQLCHAR);
+
+$caption = MNCaption ("Author", "Book");
+
+$f->KeySelect ("fk_roles", "fk_roles", "Author Role", SQLCHAR, 40, 40, true);
+$f->last->LoadSQL ("select pk as key, role as caption from roles order by role");
+$f->last->DefValue ("cr");
+$f->last->ToolTip ("In which role did this author contribute to the book?");
+
+$f->KeySelect ("heading", "heading", "Heading", SQLINT, 10, 2, true);
+$f->last->PushOptions ($titles_heading);
+$f->last->DefValue (1);
+$f->last->ToolTip ("Should this author generate a user-visible heading?");
+
+$f->LoadData ("select * from mn_books_authors " .
+ "where fk_books = $fk_books and fk_authors = $fk_authors and fk_roles = $sql_fk_roles");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to unlink this book author. " .
+ "Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+}
+
+$f->Hidden ("fk_books");
+$f->Hidden ("fk_authors");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ if ($db->Exec ("insert into mn_books_authors (fk_books, fk_authors, fk_roles, heading) " .
+ "values ($fk_books, $fk_authors, $sql_fk_roles, $heading)")) {
+ $msg = "msg=Book author linked !";
+ } else {
+ $msg = "errormsg=Could not link book author !";
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ if ($db->Exec ("update mn_books_authors " .
+ "set fk_roles = $sql_fk_roles, heading = $heading " .
+ "where fk_books = $fk_books and fk_authors = $fk_authors")) {
+ $msg = "msg=Author link modified !";
+ } else {
+ $msg = "errormsg=Could not modify author link !";
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from mn_books_authors " .
+ "where fk_books = $fk_books and fk_authors = $fk_authors and fk_roles = $sql_fk_roles")) {
+ $msg = "msg=Book author unlinked !";
+ } else {
+ $msg = "errormsg=Could not unlink book author !";
+ }
+}
+
+if (isupdate ()) {
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+pageheader ($caption);
+$f->Output ($caption, $caption);
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mn_books_authors.php~ b/catalog/admin/mn_books_authors.php~
new file mode 100644
index 0000000..e226edc
--- /dev/null
+++ b/catalog/admin/mn_books_authors.php~
@@ -0,0 +1,75 @@
+f ($fk_roles, SQLCHAR);
+
+$caption = MNCaption ("Author", "Book");
+
+$f->KeySelect ("fk_roles", "fk_roles", "Author Role", SQLCHAR, 40, 40, true);
+$f->last->LoadSQL ("select pk as key, role as caption from roles order by role");
+$f->last->DefValue ("cr");
+$f->last->ToolTip ("In which role did this author contribute to the book?");
+
+$f->KeySelect ("heading", "heading", "Heading", SQLINT, 10, 2, true);
+$f->last->PushOptions ($titles_heading);
+$f->last->DefValue (1);
+$f->last->ToolTip ("Should this author generate a user-visible heading?");
+
+$f->LoadData ("select * from mn_books_authors " .
+ "where fk_books = $fk_books and fk_authors = $fk_authors and fk_roles = $sql_fk_roles");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to unlink this book author. " .
+ "Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+}
+
+$f->Hidden ("fk_books");
+$f->Hidden ("fk_authors");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ if ($db->Exec ("insert into mn_books_authors (fk_books, fk_authors, fk_roles, heading) " .
+ "values ($fk_books, $fk_authors, $sql_fk_roles, $heading)")) {
+ $msg = "msg=Book author linked !";
+ } else {
+ $msg = "errormsg=Could not link book author !";
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ if ($db->Exec ("update mn_books_authors " .
+ "set fk_roles = $sql_fk_roles, heading = $heading " .
+ "where fk_books = $fk_books and fk_authors = $fk_authors")) {
+ $msg = "msg=Author link modified !";
+ } else {
+ $msg = "errormsg=Could not modify author link !";
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from mn_books_authors " .
+ "where fk_books = $fk_books and fk_authors = $fk_authors and fk_roles = $sql_fk_roles")) {
+ $msg = "msg=Book author unlinked !";
+ } else {
+ $msg = "errormsg=Could not unlink book author !";
+ }
+}
+
+if (isupdate ()) {
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+pageheader ($caption);
+$f->Output ($caption, $caption);
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mn_books_authors_list.php b/catalog/admin/mn_books_authors_list.php
new file mode 100644
index 0000000..8663e19
--- /dev/null
+++ b/catalog/admin/mn_books_authors_list.php
@@ -0,0 +1,50 @@
+db ();
+$db->logger = new logger ();
+
+pageheader ($caption = MNCaption ("Author", "Book"));
+
+getint ("fk_books");
+
+class ListAuthorsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $this->AddColumn ("Link ", "", null, "1%");
+ $this->AddSimpleColumn ("author", "Name");
+ $this->AddSimpleColumn ("born_floor", "Born", "narrow right");
+ $this->AddSimpleColumn ("died_floor", "Died", "narrow right");
+ }
+}
+
+echo ("
+Please enter the first few characters of the authors name (at least one).
+Use * as wildcard.
+
+\n");
+
+if ($filter != "") {
+ $filter = str_replace ('*', '%', $filter);
+ $sql_filter = $db->f ("$filter%", SQLCHAR);
+ $db->exec ("select * from authors where author ilike $sql_filter order by author;");
+ $table = new ListAuthorsTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+p ("Add Author ");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mn_books_authors_list.php~ b/catalog/admin/mn_books_authors_list.php~
new file mode 100644
index 0000000..52b633c
--- /dev/null
+++ b/catalog/admin/mn_books_authors_list.php~
@@ -0,0 +1,45 @@
+AddColumn ("Link ", "", null, "1%");
+ $this->AddSimpleColumn ("author", "Name");
+ $this->AddSimpleColumn ("born_floor", "Born", "narrow right");
+ $this->AddSimpleColumn ("died_floor", "Died", "narrow right");
+ }
+}
+
+echo ("
+Please enter the first few characters of the authors name (at least one).
+Use * as wildcard.
+
+\n");
+
+if ($filter != "") {
+ $filter = str_replace ('*', '%', $filter);
+ $sql_filter = $db->f ("$filter%", SQLCHAR);
+ $db->exec ("select * from authors where author ilike $sql_filter order by author;");
+ $table = new ListAuthorsTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+p ("Add Author ");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mn_books_categories.php b/catalog/admin/mn_books_categories.php
new file mode 100644
index 0000000..6ace4f9
--- /dev/null
+++ b/catalog/admin/mn_books_categories.php
@@ -0,0 +1,65 @@
+db ();
+$db->logger = new logger ();
+
+getint ("fk_books");
+getint ("fk_categories");
+
+if (isupdatemode ("add")) {
+ if ($db->Exec ("insert into mn_books_categories (fk_books, fk_categories) " .
+ "values ($fk_books, '$fk_categories')")) {
+ $msg = "msg=Book Category linked !";
+ } else {
+ $msg = "errormsg=Could not link book Category !";
+ }
+}
+
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from mn_books_categories " .
+ "where fk_books = $fk_books and fk_categories = '$fk_categories'")) {
+ $msg = "msg=Book Category unlinked !";
+ } else {
+ $msg = "errormsg=Could not unlink book Category !";
+ }
+}
+
+if (isupdate ()) {
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+pageheader ($caption = MNCaption ("Category", "Book"));
+
+class ListCategoriesTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $this->AddColumn ("Link ", "", null, "1%");
+ $this->AddSimpleColumn ("category", "Category");
+ }
+}
+
+if (isfirstmode ("add")) {
+ $db->exec ("select * from categories order by category;");
+ $table = new ListCategoriesTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+if (isfirstmode ("delete")) {
+ $f->Hidden ("fk_books");
+ $f->Hidden ("fk_categories");
+ $f->SubCaption ("You are about to unlink this book Category.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mn_books_categories.php~ b/catalog/admin/mn_books_categories.php~
new file mode 100644
index 0000000..d817447
--- /dev/null
+++ b/catalog/admin/mn_books_categories.php~
@@ -0,0 +1,60 @@
+Exec ("insert into mn_books_categories (fk_books, fk_categories) " .
+ "values ($fk_books, '$fk_categories')")) {
+ $msg = "msg=Book Category linked !";
+ } else {
+ $msg = "errormsg=Could not link book Category !";
+ }
+}
+
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from mn_books_categories " .
+ "where fk_books = $fk_books and fk_categories = '$fk_categories'")) {
+ $msg = "msg=Book Category unlinked !";
+ } else {
+ $msg = "errormsg=Could not unlink book Category !";
+ }
+}
+
+if (isupdate ()) {
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+pageheader ($caption = MNCaption ("Category", "Book"));
+
+class ListCategoriesTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $this->AddColumn ("Link ", "", null, "1%");
+ $this->AddSimpleColumn ("category", "Category");
+ }
+}
+
+if (isfirstmode ("add")) {
+ $db->exec ("select * from categories order by category;");
+ $table = new ListCategoriesTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+if (isfirstmode ("delete")) {
+ $f->Hidden ("fk_books");
+ $f->Hidden ("fk_categories");
+ $f->SubCaption ("You are about to unlink this book Category.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mn_books_langs.php b/catalog/admin/mn_books_langs.php
new file mode 100644
index 0000000..cfbd1da
--- /dev/null
+++ b/catalog/admin/mn_books_langs.php
@@ -0,0 +1,79 @@
+db ();
+$db->logger = new logger ();
+
+getint ("fk_books");
+getstr ("fk_langs");
+
+if (isupdatemode ("add")) {
+ if ($db->Exec ("insert into mn_books_langs (fk_books, fk_langs) " .
+ "values ($fk_books, '$fk_langs')")) {
+ $msg = "msg=Book language linked !";
+ } else {
+ $msg = "errormsg=Could not link book language !";
+ }
+}
+
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from mn_books_langs " .
+ "where fk_books = $fk_books and fk_langs = '$fk_langs'")) {
+ $msg = "msg=Book language unlinked !";
+ } else {
+ $msg = "errormsg=Could not unlink book language !";
+ }
+}
+
+if (isupdate ()) {
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+pageheader ($caption = MNCaption ("Language", "Book"));
+
+class ListLangsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $this->AddColumn ("Link ", "", null, "1%");
+ $this->AddSimpleColumn ("lang", "Language");
+ }
+}
+
+if (isfirstmode ("add")) {
+ $f->OutputFormHeader ();
+ echo (" Please enter the first few characters of " .
+ "the language name (at least one). Use * as wildcard.
\n" .
+ " \n");
+ form_submit ("Search");
+
+ form_relay ("mode");
+ form_relay ("fk_books");
+ form_relay ("fk_langs");
+ form_close ();
+
+ if ($filter != "") {
+ $filter = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from langs where lang like '$filter%' order by lang;");
+ $table = new ListLangsTable ();
+ $table->PrintTable ($db, $caption);
+ }
+}
+
+if (isfirstmode ("delete")) {
+ $f->Hidden ("fk_books");
+ $f->Hidden ("fk_langs");
+ $f->SubCaption ("You are about to unlink this book language.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mn_books_langs.php~ b/catalog/admin/mn_books_langs.php~
new file mode 100644
index 0000000..7938f71
--- /dev/null
+++ b/catalog/admin/mn_books_langs.php~
@@ -0,0 +1,74 @@
+Exec ("insert into mn_books_langs (fk_books, fk_langs) " .
+ "values ($fk_books, '$fk_langs')")) {
+ $msg = "msg=Book language linked !";
+ } else {
+ $msg = "errormsg=Could not link book language !";
+ }
+}
+
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from mn_books_langs " .
+ "where fk_books = $fk_books and fk_langs = '$fk_langs'")) {
+ $msg = "msg=Book language unlinked !";
+ } else {
+ $msg = "errormsg=Could not unlink book language !";
+ }
+}
+
+if (isupdate ()) {
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+pageheader ($caption = MNCaption ("Language", "Book"));
+
+class ListLangsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $this->AddColumn ("Link ", "", null, "1%");
+ $this->AddSimpleColumn ("lang", "Language");
+ }
+}
+
+if (isfirstmode ("add")) {
+ $f->OutputFormHeader ();
+ echo (" Please enter the first few characters of " .
+ "the language name (at least one). Use * as wildcard.
\n" .
+ " \n");
+ form_submit ("Search");
+
+ form_relay ("mode");
+ form_relay ("fk_books");
+ form_relay ("fk_langs");
+ form_close ();
+
+ if ($filter != "") {
+ $filter = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from langs where lang like '$filter%' order by lang;");
+ $table = new ListLangsTable ();
+ $table->PrintTable ($db, $caption);
+ }
+}
+
+if (isfirstmode ("delete")) {
+ $f->Hidden ("fk_books");
+ $f->Hidden ("fk_langs");
+ $f->SubCaption ("You are about to unlink this book language.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mn_books_loccs.php b/catalog/admin/mn_books_loccs.php
new file mode 100644
index 0000000..3b4cd79
--- /dev/null
+++ b/catalog/admin/mn_books_loccs.php
@@ -0,0 +1,92 @@
+db ();
+$db->logger = new logger ();
+
+getint ("fk_books");
+getstr ("fk_loccs");
+
+$locc_name = "Unknown";
+if ($db->Exec("select locc from loccs where pk = '$fk_loccs'")) {
+#it will make life nicer if the message includes *what* LoC was linked.
+ $locc_name = $db->Get("locc");
+ }
+
+if (isupdatemode ("add")) {
+ if ($db->Exec ("insert into mn_books_loccs (fk_books, fk_loccs) " .
+ "values ($fk_books, '$fk_loccs')")) {
+ $msg = "msg=LoCC '$fk_loccs : $locc_name' linked!";
+ } else {
+ $msg = "errormsg=Could not link LoCC '$fk_loccs : $locc_name'!";
+ }
+}
+
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from mn_books_loccs " .
+ "where fk_books = $fk_books and fk_loccs = '$fk_loccs'")) {
+ $msg = "msg=LoCC '$fk_loccs : $locc_name' unlinked!";
+ } else {
+ $msg = "errormsg=Could not unlink LoCC '$fk_loccs : $locc_name'!";
+ }
+}
+
+if (isupdate ()) {
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+$db->Exec("select text from attributes where fk_books = $fk_books " .
+ "and fk_attriblist=245");
+$book_name=$db->Get("text");
+
+pageheader ($caption = MNCaption ("LoC Class", "'$book_name'"));
+
+class ListLoccsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $this->AddColumn ("Link ", "", null, "1%");
+ $this->AddColumn("#pk#", "Code", "narrow");
+ $this->AddSimpleColumn ("locc", "LoC Class");
+ }
+}
+
+if (isfirstmode ("add")) {
+ $f->OutputFormHeader ();
+ echo (" Please enter the first few characters of " .
+ "the LoC class description (at least one). Use * as wildcard.
\n" .
+ " \n");
+ form_submit ("Search");
+
+ form_relay ("mode");
+ form_relay ("fk_books");
+ form_relay ("fk_loccs");
+ form_close ();
+
+ if ($filter != "") {
+ $filter = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from loccs where locc like '$filter%' order by locc;");
+ $table = new ListLoccsTable ();
+ $table->PrintTable ($db, $caption);
+ }
+}
+
+if (isfirstmode ("delete")) {
+
+ $f->Hidden ("fk_books");
+ $f->Hidden ("fk_loccs");
+ $f->SubCaption ("You are about to unlink LoCC '$fk_loccs : $locc_name' from " .
+ "'$book_name'.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mn_books_loccs.php~ b/catalog/admin/mn_books_loccs.php~
new file mode 100644
index 0000000..faff2b0
--- /dev/null
+++ b/catalog/admin/mn_books_loccs.php~
@@ -0,0 +1,87 @@
+Exec("select locc from loccs where pk = '$fk_loccs'")) {
+#it will make life nicer if the message includes *what* LoC was linked.
+ $locc_name = $db->Get("locc");
+ }
+
+if (isupdatemode ("add")) {
+ if ($db->Exec ("insert into mn_books_loccs (fk_books, fk_loccs) " .
+ "values ($fk_books, '$fk_loccs')")) {
+ $msg = "msg=LoCC '$fk_loccs : $locc_name' linked!";
+ } else {
+ $msg = "errormsg=Could not link LoCC '$fk_loccs : $locc_name'!";
+ }
+}
+
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from mn_books_loccs " .
+ "where fk_books = $fk_books and fk_loccs = '$fk_loccs'")) {
+ $msg = "msg=LoCC '$fk_loccs : $locc_name' unlinked!";
+ } else {
+ $msg = "errormsg=Could not unlink LoCC '$fk_loccs : $locc_name'!";
+ }
+}
+
+if (isupdate ()) {
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+$db->Exec("select text from attributes where fk_books = $fk_books " .
+ "and fk_attriblist=245");
+$book_name=$db->Get("text");
+
+pageheader ($caption = MNCaption ("LoC Class", "'$book_name'"));
+
+class ListLoccsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $this->AddColumn ("Link ", "", null, "1%");
+ $this->AddColumn("#pk#", "Code", "narrow");
+ $this->AddSimpleColumn ("locc", "LoC Class");
+ }
+}
+
+if (isfirstmode ("add")) {
+ $f->OutputFormHeader ();
+ echo (" Please enter the first few characters of " .
+ "the LoC class description (at least one). Use * as wildcard.
\n" .
+ " \n");
+ form_submit ("Search");
+
+ form_relay ("mode");
+ form_relay ("fk_books");
+ form_relay ("fk_loccs");
+ form_close ();
+
+ if ($filter != "") {
+ $filter = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from loccs where locc like '$filter%' order by locc;");
+ $table = new ListLoccsTable ();
+ $table->PrintTable ($db, $caption);
+ }
+}
+
+if (isfirstmode ("delete")) {
+
+ $f->Hidden ("fk_books");
+ $f->Hidden ("fk_loccs");
+ $f->SubCaption ("You are about to unlink LoCC '$fk_loccs : $locc_name' from " .
+ "'$book_name'.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mn_books_subjects.php b/catalog/admin/mn_books_subjects.php
new file mode 100644
index 0000000..df7d565
--- /dev/null
+++ b/catalog/admin/mn_books_subjects.php
@@ -0,0 +1,93 @@
+db ();
+$db->logger = new logger ();
+
+getint ("fk_books");
+getint ("fk_subjects");
+
+$subject_name = "";
+if ($db->Exec("select subject from subjects where pk = $fk_subjects")) {
+#it will make life nicer if the message includes *what* subject was linked.
+ $subject_name = $db->Get("subject");
+ }
+if (!$subject_name) {
+ /* if getting the actual name fails for some reason, use the internal number instead;
+ at least it is something...*/
+ $subject_name = "Internal #: $fk_subjects";
+ }
+if (isupdatemode ("add")) {
+ if ($db->Exec ("insert into mn_books_subjects (fk_books, fk_subjects) " .
+ "values ($fk_books, '$fk_subjects')")) {
+ $msg = "msg=Subject '$subject_name' linked!";
+ } else {
+ $msg = "errormsg=Could not link Subject '$subject_name'!";
+ }
+}
+
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from mn_books_subjects " .
+ "where fk_books = $fk_books and fk_subjects = '$fk_subjects'")) {
+ $msg = "msg=Subject '$subject_name' unlinked !";
+ } else {
+ $msg = "errormsg=Could not unlink Subject '$subject_name'!";
+ }
+}
+
+if (isupdate ()) {
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+pageheader ($caption = MNCaption ("Subject", "Book"));
+
+class ListSubjectsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $this->AddColumn ("Link ", "Add ", null, "1%");
+ $this->AddColumn ("#subject# ", "Subject");
+ }
+}
+
+if (isfirstmode ("add")) {
+ $f->OutputFormHeader ();
+ echo (" Please enter the first few characters of " .
+ "the Subject description (at least one). Use * as wildcard.
\n" .
+ " \n");
+ form_submit ("Search");
+
+ form_relay ("mode");
+ form_relay ("fk_books");
+ form_relay ("fk_subjects");
+ form_close ();
+
+ if ($filter != "") {
+ $filter = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from subjects where subject like '$filter%' order by subject;");
+ $table = new ListSubjectsTable ();
+ $table->PrintTable ($db, $caption);
+ }
+}
+
+if (isfirstmode ("delete")) {
+ $db->Exec("select text from attributes where fk_books = $fk_books " .
+ "and fk_attriblist=245");
+ $book_name=$db->Get("text");
+ $f->Hidden ("fk_books");
+ $f->Hidden ("fk_subjects");
+ $f->SubCaption ("You are about to unlink the Subject '$subject_name' " .
+ "from the book entitled '$book_name'.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/mn_books_subjects.php~ b/catalog/admin/mn_books_subjects.php~
new file mode 100644
index 0000000..d54f1da
--- /dev/null
+++ b/catalog/admin/mn_books_subjects.php~
@@ -0,0 +1,88 @@
+Exec("select subject from subjects where pk = $fk_subjects")) {
+#it will make life nicer if the message includes *what* subject was linked.
+ $subject_name = $db->Get("subject");
+ }
+if (!$subject_name) {
+ /* if getting the actual name fails for some reason, use the internal number instead;
+ at least it is something...*/
+ $subject_name = "Internal #: $fk_subjects";
+ }
+if (isupdatemode ("add")) {
+ if ($db->Exec ("insert into mn_books_subjects (fk_books, fk_subjects) " .
+ "values ($fk_books, '$fk_subjects')")) {
+ $msg = "msg=Subject '$subject_name' linked!";
+ } else {
+ $msg = "errormsg=Could not link Subject '$subject_name'!";
+ }
+}
+
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from mn_books_subjects " .
+ "where fk_books = $fk_books and fk_subjects = '$fk_subjects'")) {
+ $msg = "msg=Subject '$subject_name' unlinked !";
+ } else {
+ $msg = "errormsg=Could not unlink Subject '$subject_name'!";
+ }
+}
+
+if (isupdate ()) {
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+pageheader ($caption = MNCaption ("Subject", "Book"));
+
+class ListSubjectsTable extends ListTable {
+ function __construct () {
+ global $fk_books;
+ $this->AddColumn ("Link ", "Add ", null, "1%");
+ $this->AddColumn ("#subject# ", "Subject");
+ }
+}
+
+if (isfirstmode ("add")) {
+ $f->OutputFormHeader ();
+ echo (" Please enter the first few characters of " .
+ "the Subject description (at least one). Use * as wildcard.
\n" .
+ " \n");
+ form_submit ("Search");
+
+ form_relay ("mode");
+ form_relay ("fk_books");
+ form_relay ("fk_subjects");
+ form_close ();
+
+ if ($filter != "") {
+ $filter = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from subjects where subject like '$filter%' order by subject;");
+ $table = new ListSubjectsTable ();
+ $table->PrintTable ($db, $caption);
+ }
+}
+
+if (isfirstmode ("delete")) {
+ $db->Exec("select text from attributes where fk_books = $fk_books " .
+ "and fk_attriblist=245");
+ $book_name=$db->Get("text");
+ $f->Hidden ("fk_books");
+ $f->Hidden ("fk_subjects");
+ $f->SubCaption ("You are about to unlink the Subject '$subject_name' " .
+ "from the book entitled '$book_name'.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+ $f->Output ($caption, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/password.php b/catalog/admin/password.php
new file mode 100644
index 0000000..05e6e2c
--- /dev/null
+++ b/catalog/admin/password.php
@@ -0,0 +1,82 @@
+db ();
+$db->logger = new logger ();
+
+include_once ("sqlform.phh");
+
+if ($admin) {
+ // changing other people's passwords requires createuser permission
+ authenticate ("createuser");
+ getint ("fk_users");
+ $db->exec ("select login from users where pk = $fk_users");
+ if ($db->FirstRow ()) {
+ $login = $db->get ("login", SQLCHAR);
+ } else {
+ error_msg ("No such user");
+ }
+ pageheader ("Administrator Change Password For: $login");
+} else {
+ authenticate ();
+ $login = $_SERVER['PHP_AUTH_USER'];
+ $sql_login = $db->f ($login, SQLCHAR);
+ $db->exec ("select pk from users where login = $sql_login");
+ if ($db->FirstRow ()) {
+ $fk_users = $db->get ("pk", SQLINT);
+ }
+ pageheader ("Change Password For: $login");
+}
+
+getstr ("filter");
+
+if (!isupdate ()) {
+ form_open ();
+ if ($admin) {
+ p ("Enter password for user {$_SERVER['PHP_AUTH_USER']}: ");
+ } else {
+ p ("Enter old password for user $login: ");
+ }
+ p ("Do not use the same password as for other important services!");
+ p ("Enter new password for user $login: at least 8 characters");
+ p ("Reenter new password for user $login: ");
+ form_hidden ("admin", $admin);
+ form_hidden ("fk_users", $fk_users);
+ form_hidden ("filter", $filter);
+ form_submit ("Change password");
+ form_close ();
+} else {
+ // make sure you got the old password
+ getstr ("oldpassword");
+ $sql_login = $db->f ($_SERVER['PHP_AUTH_USER'], SQLCHAR);
+ $sql_password = $db->f (md5 ($oldpassword), SQLCHAR);
+ $db->exec ("select pk from users where login = $sql_login and password = $sql_password");
+ if (!$db->FirstRow ()) {
+ error_msg ("Incorrect old password!");
+ die ();
+ }
+ getstr ("newpassword1");
+ getstr ("newpassword2");
+ if ($newpassword1 != $newpassword2) {
+ error_msg ("You entered 2 different passwords!");
+ }
+ if (strlen ($newpassword1) < 8) {
+ error_msg ("New password must be at least 8 characters long.");
+ }
+ $sql_password = $db->f (md5 ($newpassword1), SQLCHAR);
+ if ($db->exec ("update users set password = $sql_password where pk = $fk_users")) {
+ msg ("Password changed");
+ } else {
+ error_msg ("Could not change password");
+ }
+}
+
+p ("Back to User ");
+p ("Back to User List ");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/password.php~ b/catalog/admin/password.php~
new file mode 100644
index 0000000..12ef1f6
--- /dev/null
+++ b/catalog/admin/password.php~
@@ -0,0 +1,81 @@
+db ();
+$db->logger = new logger ();
+
+include_once ("sqlform.phh");
+
+if ($admin) {
+ // changing other people's passwords requires createuser permission
+ authenticate ("createuser");
+ getint ("fk_users");
+ $db->exec ("select login from users where pk = $fk_users");
+ if ($db->FirstRow ()) {
+ $login = $db->get ("login", SQLCHAR);
+ } else {
+ error_msg ("No such user");
+ }
+ pageheader ("Administrator Change Password For: $login");
+} else {
+ authenticate ();
+ $login = $_SERVER['PHP_AUTH_USER'];
+ $sql_login = $db->f ($login, SQLCHAR);
+ $db->exec ("select pk from users where login = $sql_login");
+ if ($db->FirstRow ()) {
+ $fk_users = $db->get ("pk", SQLINT);
+ }
+ pageheader ("Change Password For: $login");
+}
+
+getstr ("filter");
+
+if (!isupdate ()) {
+ form_open ();
+ if ($admin) {
+ p ("Enter password for user {$_SERVER['PHP_AUTH_USER']}: ");
+ } else {
+ p ("Enter old password for user $login: ");
+ }
+ p ("Do not use the same password as for other important services!");
+ p ("Enter new password for user $login: at least 8 characters");
+ p ("Reenter new password for user $login: ");
+ form_hidden ("admin", $admin);
+ form_hidden ("fk_users", $fk_users);
+ form_hidden ("filter", $filter);
+ form_submit ("Change password");
+ form_close ();
+} else {
+ // make sure you got the old password
+ getstr ("oldpassword");
+ $sql_login = $db->f ($_SERVER['PHP_AUTH_USER'], SQLCHAR);
+ $sql_password = $db->f (md5 ($oldpassword), SQLCHAR);
+ $db->exec ("select pk from users where login = $sql_login and password = $sql_password");
+ if (!$db->FirstRow ()) {
+ error_msg ("Incorrect old password!");
+ die ();
+ }
+ getstr ("newpassword1");
+ getstr ("newpassword2");
+ if ($newpassword1 != $newpassword2) {
+ error_msg ("You entered 2 different passwords!");
+ }
+ if (strlen ($newpassword1) < 8) {
+ error_msg ("New password must be at least 8 characters long.");
+ }
+ $sql_password = $db->f (md5 ($newpassword1), SQLCHAR);
+ if ($db->exec ("update users set password = $sql_password where pk = $fk_users")) {
+ msg ("Password changed");
+ } else {
+ error_msg ("Could not change password");
+ }
+}
+
+p ("Back to User ");
+p ("Back to User List ");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/phpinfo.php~ b/catalog/admin/phpinfo.php~
new file mode 100644
index 0000000..65901f3
--- /dev/null
+++ b/catalog/admin/phpinfo.php~
@@ -0,0 +1,8 @@
+
diff --git a/catalog/admin/ps.php b/catalog/admin/ps.php
new file mode 100644
index 0000000..93c6d71
--- /dev/null
+++ b/catalog/admin/ps.php
@@ -0,0 +1,17 @@
+
diff --git a/catalog/admin/ps.php~ b/catalog/admin/ps.php~
new file mode 100644
index 0000000..f21f9eb
--- /dev/null
+++ b/catalog/admin/ps.php~
@@ -0,0 +1,16 @@
+
diff --git a/catalog/admin/review.php b/catalog/admin/review.php
new file mode 100644
index 0000000..745dc26
--- /dev/null
+++ b/catalog/admin/review.php
@@ -0,0 +1,79 @@
+logger = new logger ();
+$db = $config->db ();
+
+getstr ("mode");
+getint ("fk_reviews");
+getint ("fk_books");
+$caption = ucfirst ($mode) . " Review";
+
+$f = new SQLForm ();
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this review.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ if (ismode ("add")) {
+ $f->SQLInject ("fk_books", "fk_books", SQLINT);
+ }
+ $f->SQLSelect ("fk_reviewers", "fk_reviewers", "Reviewer", SQLINT, 10, 2, true,
+ "select pk as value, name as caption from reviews.reviewers order by caption");
+ $f->ToolTip ("Name of the reviewer.");
+
+ $f->Text ("title", "title", "Title", SQLCHAR, 80, 80, true);
+ $f->ToolTip ("Enter a title for the review, eg. Summary, Review, Excerpts, Critique");
+
+ $f->TextArea ("review", "review", "Review", SQLCHAR, 20, 80, true);
+ $f->ToolTip ("Enter a review for the work.");
+
+ $f->LoadData ("select * from reviews.reviews where pk = $fk_reviews");
+}
+$f->Hidden ("fk_reviews");
+$f->Hidden ("fk_books");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into reviews.reviews " . $sql)) {
+ $msg = "msg=Review added !";
+ } else {
+ $msg = "errormsg=Could not add review!";
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update reviews.reviews set " . $sql . "where pk = $fk_reviews")) {
+ $msg = "msg=Review modified !";
+ } else {
+ $msg = "errormsg=Could not modify review !";
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from reviews.reviews where pk = $fk_reviews")) {
+ $msg = "msg=Review deleted !";
+ } else {
+ $msg = "errormsg=Could not delete review !";
+ }
+}
+
+if (isupdate ()) {
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+pageheader ($caption);
+$f->Output ($caption, $caption);
+pagefooter ();
+
+?>
diff --git a/catalog/admin/review.php~ b/catalog/admin/review.php~
new file mode 100644
index 0000000..0d54fd0
--- /dev/null
+++ b/catalog/admin/review.php~
@@ -0,0 +1,78 @@
+logger = new logger ();
+$db = $config->db ();
+
+getstr ("mode");
+getint ("fk_reviews");
+getint ("fk_books");
+$caption = ucfirst ($mode) . " Review";
+
+$f = new SQLForm ();
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this review.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ if (ismode ("add")) {
+ $f->SQLInject ("fk_books", "fk_books", SQLINT);
+ }
+ $f->SQLSelect ("fk_reviewers", "fk_reviewers", "Reviewer", SQLINT, 10, 2, true,
+ "select pk as value, name as caption from reviews.reviewers order by caption");
+ $f->ToolTip ("Name of the reviewer.");
+
+ $f->Text ("title", "title", "Title", SQLCHAR, 80, 80, true);
+ $f->ToolTip ("Enter a title for the review, eg. Summary, Review, Excerpts, Critique");
+
+ $f->TextArea ("review", "review", "Review", SQLCHAR, 20, 80, true);
+ $f->ToolTip ("Enter a review for the work.");
+
+ $f->LoadData ("select * from reviews.reviews where pk = $fk_reviews");
+}
+$f->Hidden ("fk_reviews");
+$f->Hidden ("fk_books");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into reviews.reviews " . $sql)) {
+ $msg = "msg=Review added !";
+ } else {
+ $msg = "errormsg=Could not add review!";
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update reviews.reviews set " . $sql . "where pk = $fk_reviews")) {
+ $msg = "msg=Review modified !";
+ } else {
+ $msg = "errormsg=Could not modify review !";
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ if ($db->Exec ("delete from reviews.reviews where pk = $fk_reviews")) {
+ $msg = "msg=Review deleted !";
+ } else {
+ $msg = "errormsg=Could not delete review !";
+ }
+}
+
+if (isupdate ()) {
+ header ("Location: book?mode=edit&fk_books=$fk_books&$msg");
+ return;
+}
+
+pageheader ($caption);
+$f->Output ($caption, $caption);
+pagefooter ();
+
+?>
diff --git a/catalog/admin/rm-rf.php b/catalog/admin/rm-rf.php
new file mode 100644
index 0000000..698946d
--- /dev/null
+++ b/catalog/admin/rm-rf.php
@@ -0,0 +1,17 @@
+
diff --git a/catalog/admin/rm-rf.php~ b/catalog/admin/rm-rf.php~
new file mode 100644
index 0000000..d573d4a
--- /dev/null
+++ b/catalog/admin/rm-rf.php~
@@ -0,0 +1,16 @@
+
diff --git a/catalog/admin/robot-activity.php b/catalog/admin/robot-activity.php
new file mode 100644
index 0000000..61fbd5e
--- /dev/null
+++ b/catalog/admin/robot-activity.php
@@ -0,0 +1,246 @@
+host ($ip);
+}
+
+class CalcFieldHost {
+ function f ($db) {
+ $ip = $db->get ("ip", SQLCHAR);
+ $host = hr_host ($ip);
+ $host = preg_replace ("/[^.]+\.[^.]+$/", "\xE2\x80\x8B\\0 ", $host);
+ return $host;
+ }
+}
+
+class CalcFieldDuration {
+ function f ($db) {
+ return hr_time_diff ($db->get ("firstseen", SQLDATE), $db->get ("lastseen", SQLDATE));
+ }
+}
+
+class CalcFieldRate {
+ function f ($db) {
+ return round (3600 * $db->get ("hits", SQLINT) / ($db->get ("lastseen", SQLDATE) - $db->get ("firstseen", SQLDATE)));
+ }
+}
+
+class CalcFieldLastSeen {
+ function f ($db) {
+ return hr_ago ($db->get ("lastseen", SQLDATE));
+ }
+}
+
+class CalcFieldBlocked {
+ function f ($db) {
+ $ip = htmlspecialchars ($db->get ("ip", SQLCHAR));
+ $b = "block ";
+ return $db->get ("blocked", SQLBOOL) ? "blocked" : $b;
+ }
+}
+
+class CalcFieldExpires {
+ function f ($db) {
+ return hr_in ($db->get ("expires", SQLDATE));
+ }
+}
+
+class CalcFieldRBL {
+ function __construct ($list) {
+ $this->list = $list;
+ }
+ function f ($db) {
+ $ip = fixnetwork ($db->get ("ip", SQLCHAR));
+ $reverse_ip = join (".", array_reverse (explode (".", $ip)));
+ $host = gethostbyname ("$reverse_ip.$this->list");
+ // return $host; // debug
+ return strncmp ($host, "127.", 4) ? "" : "Yes";
+ }
+}
+
+class RobotHitTable extends ListTable {
+ function __construct () {
+ $this->AddSimpleColumn ("c_blocked", "Block", "narrow");
+ $this->lastcolumn->raw = 1;
+ $this->lastcolumn->SetTitle ("Block this IP.");
+
+ $this->AddColumn ("delete ", "Delete", "narrow");
+ $this->lastcolumn->SetTitle ("Delete this robot from watch list.");
+
+ $this->AddSimpleColumn ("c_last", "Seen");
+ $this->lastcolumn->SetTitle ("Last access.");
+
+ $this->AddSimpleColumn ("c_dur", "For");
+ $this->lastcolumn->SetTitle ("Total duration of access.");
+
+ $this->AddSimpleColumn ("ip", "IP");
+ $this->lastcolumn->SetTitle ("IP address.");
+
+ $this->AddSimpleColumn ("c_host", "Host");
+ $this->lastcolumn->f = create_function ('$raw', 'return $raw;');
+ $this->lastcolumn->raw = 1;
+ $this->lastcolumn->SetTitle ("Host name. ??? if reverse lookup failed.");
+
+ $this->AddColumn ("whois ", "Whois", "narrow");
+ $this->lastcolumn->SetTitle ("Start a whois query.");
+
+ $this->AddSimpleColumn ("c_rate", "Rate", "narrow right");
+ $this->lastcolumn->SetTitle ("Total hit rate / hour.");
+
+ $this->AddSimpleColumn ("hits", "Total", "narrow right");
+ $this->lastcolumn->SetTitle ("Total hits.");
+
+ $this->AddSimpleColumn ("rhits", "Res.", "narrow right");
+ $this->lastcolumn->SetTitle ("Hits in robot-restricted area. Should be zero.");
+
+ $this->AddSimpleColumn ("hhits", "Hp", "narrow right");
+ $this->lastcolumn->SetTitle ("Hits in honeypot. Should be zero.");
+
+ $this->AddSimpleColumn ("ua", "User-Agent");
+ $this->lastcolumn->SetTitle ("User Agent");
+
+ }
+ function startrow ($db) {
+ $blocked = $db->get ("blocked", SQLBOOL);
+ $style = $blocked ? " style=\"color: gray;\"" : "";
+ echo (" ");
+ }
+}
+
+class RobotBlockedTable extends ListTable {
+ function __construct () {
+ $this->AddColumn ("unblock ", "Unblock", "narrow");
+ $this->lastcolumn->SetTitle ("Unblock this IP.");
+
+ $this->AddSimpleColumn ("ip", "IP");
+ $this->lastcolumn->SetTitle ("IP address.");
+
+ $this->AddSimpleColumn ("c_host", "Host");
+ $this->lastcolumn->f = create_function ('$raw', 'return $raw;');
+ $this->lastcolumn->raw = 1;
+ $this->lastcolumn->SetTitle ("Host name. ??? if reverse lookup failed.");
+
+ $this->AddColumn ("whois ", "Whois", "narrow");
+ $this->lastcolumn->SetTitle ("Start a whois query.");
+
+ $this->AddSimpleColumn ("c_expires", "Expires");
+ $this->lastcolumn->SetTitle ("Block expires.");
+
+ }
+}
+
+$db = $config->db ();
+$r = new robots ();
+
+getstr ("block");
+getstr ("unblock");
+getstr ("delete");
+
+if ($block) {
+ $ip = long2ip (ip2long ($block));
+ $r->block ($ip);
+ $host = hr_host ($ip);
+ $msg = "Robot $host ($ip) blocked";
+ // redirect else we would block again on page refresh
+ header ("Location: robot-activity?msg=$msg");
+ return;
+}
+
+if ($unblock) {
+ $ip = long2ip (ip2long ($unblock));
+ $r->unblock ($ip);
+ $host = hr_host ($ip);
+ $msg = "Robot $host ($ip) unblocked";
+ header ("Location: robot-activity?msg=$msg");
+ return;
+}
+
+if ($delete) {
+ $ip = long2ip (ip2long ($delete));
+ $r->delete ($ip);
+ $host = hr_host ($ip);
+ $msg = "Robot $host ($ip) deleted";
+ header ("Location: robot-activity?msg=$msg");
+ return;
+}
+
+pageheader ($caption = "Robot Activity Monitor");
+
+getstr ("msg");
+getstr ("errormsg");
+
+if (!empty ($msg)) msg ($msg);
+if (!empty ($errormsg)) error_msg ($msg);
+
+p ("Time: " . date ("Y-m-d H:i:s"));
+
+$db->exec ("select robots.ips.*, robots.blocks.expires > timestamp 'now' as blocked from robots.ips
+left join robots.blocks on robots.ips.ip = robots.blocks.ip
+where
+ (robots.blocks.expires > timestamp 'now')
+ or ((hits > 1000) and (lastseen - firstseen) / hits < interval '2 seconds')
+ or ((rhits > 100) and (lastseen - firstseen) / (rhits + 1) < interval '20 seconds')
+ or (hhits > 10)
+order by not (robots.blocks.expires > timestamp 'now'), ((lastseen - firstseen) / hits) limit 100;
+");
+
+$db->calcfields ["c_host"] = new CalcFieldHost ();
+$db->calcfields ["c_dur"] = new CalcFieldDuration ();
+$db->calcfields ["c_last"] = new CalcFieldLastSeen ();
+$db->calcfields ["c_blocked"] = new CalcFieldBlocked ();
+$db->calcfields ["c_rate"] = new CalcFieldRate ();
+
+// $db->calcfields ["c_isdialup"] = new CalcFieldRBL ("dul.dnsbl.sorbs.net");
+// $db->calcfields ["c_spews"] = new CalcFieldRBL ("l2.spews.dnsbl.sorbs.net");
+
+$table = new RobotHitTable ();
+$table->PrintTable ($db, "Recently Active Robots");
+
+$db->exec ("select * from robots.blocks where expires > timestamp 'now' order by ip;");
+
+$db->calcfields ["c_host"] = new CalcFieldHost ();
+$db->calcfields ["c_expires"] = new CalcFieldExpires ();
+
+$table = new RobotBlockedTable ();
+$table->PrintTable ($db, "Blocked Robots");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/robot-activity.php~ b/catalog/admin/robot-activity.php~
new file mode 100644
index 0000000..650f0e4
--- /dev/null
+++ b/catalog/admin/robot-activity.php~
@@ -0,0 +1,245 @@
+host ($ip);
+}
+
+class CalcFieldHost {
+ function f ($db) {
+ $ip = $db->get ("ip", SQLCHAR);
+ $host = hr_host ($ip);
+ $host = preg_replace ("/[^.]+\.[^.]+$/", "\xE2\x80\x8B\\0 ", $host);
+ return $host;
+ }
+}
+
+class CalcFieldDuration {
+ function f ($db) {
+ return hr_time_diff ($db->get ("firstseen", SQLDATE), $db->get ("lastseen", SQLDATE));
+ }
+}
+
+class CalcFieldRate {
+ function f ($db) {
+ return round (3600 * $db->get ("hits", SQLINT) / ($db->get ("lastseen", SQLDATE) - $db->get ("firstseen", SQLDATE)));
+ }
+}
+
+class CalcFieldLastSeen {
+ function f ($db) {
+ return hr_ago ($db->get ("lastseen", SQLDATE));
+ }
+}
+
+class CalcFieldBlocked {
+ function f ($db) {
+ $ip = htmlspecialchars ($db->get ("ip", SQLCHAR));
+ $b = "block ";
+ return $db->get ("blocked", SQLBOOL) ? "blocked" : $b;
+ }
+}
+
+class CalcFieldExpires {
+ function f ($db) {
+ return hr_in ($db->get ("expires", SQLDATE));
+ }
+}
+
+class CalcFieldRBL {
+ function __construct ($list) {
+ $this->list = $list;
+ }
+ function f ($db) {
+ $ip = fixnetwork ($db->get ("ip", SQLCHAR));
+ $reverse_ip = join (".", array_reverse (explode (".", $ip)));
+ $host = gethostbyname ("$reverse_ip.$this->list");
+ // return $host; // debug
+ return strncmp ($host, "127.", 4) ? "" : "Yes";
+ }
+}
+
+class RobotHitTable extends ListTable {
+ function __construct () {
+ $this->AddSimpleColumn ("c_blocked", "Block", "narrow");
+ $this->lastcolumn->raw = 1;
+ $this->lastcolumn->SetTitle ("Block this IP.");
+
+ $this->AddColumn ("delete ", "Delete", "narrow");
+ $this->lastcolumn->SetTitle ("Delete this robot from watch list.");
+
+ $this->AddSimpleColumn ("c_last", "Seen");
+ $this->lastcolumn->SetTitle ("Last access.");
+
+ $this->AddSimpleColumn ("c_dur", "For");
+ $this->lastcolumn->SetTitle ("Total duration of access.");
+
+ $this->AddSimpleColumn ("ip", "IP");
+ $this->lastcolumn->SetTitle ("IP address.");
+
+ $this->AddSimpleColumn ("c_host", "Host");
+ $this->lastcolumn->f = create_function ('$raw', 'return $raw;');
+ $this->lastcolumn->raw = 1;
+ $this->lastcolumn->SetTitle ("Host name. ??? if reverse lookup failed.");
+
+ $this->AddColumn ("whois ", "Whois", "narrow");
+ $this->lastcolumn->SetTitle ("Start a whois query.");
+
+ $this->AddSimpleColumn ("c_rate", "Rate", "narrow right");
+ $this->lastcolumn->SetTitle ("Total hit rate / hour.");
+
+ $this->AddSimpleColumn ("hits", "Total", "narrow right");
+ $this->lastcolumn->SetTitle ("Total hits.");
+
+ $this->AddSimpleColumn ("rhits", "Res.", "narrow right");
+ $this->lastcolumn->SetTitle ("Hits in robot-restricted area. Should be zero.");
+
+ $this->AddSimpleColumn ("hhits", "Hp", "narrow right");
+ $this->lastcolumn->SetTitle ("Hits in honeypot. Should be zero.");
+
+ $this->AddSimpleColumn ("ua", "User-Agent");
+ $this->lastcolumn->SetTitle ("User Agent");
+
+ }
+ function startrow ($db) {
+ $blocked = $db->get ("blocked", SQLBOOL);
+ $style = $blocked ? " style=\"color: gray;\"" : "";
+ echo (" ");
+ }
+}
+
+class RobotBlockedTable extends ListTable {
+ function __construct () {
+ $this->AddColumn ("unblock ", "Unblock", "narrow");
+ $this->lastcolumn->SetTitle ("Unblock this IP.");
+
+ $this->AddSimpleColumn ("ip", "IP");
+ $this->lastcolumn->SetTitle ("IP address.");
+
+ $this->AddSimpleColumn ("c_host", "Host");
+ $this->lastcolumn->f = create_function ('$raw', 'return $raw;');
+ $this->lastcolumn->raw = 1;
+ $this->lastcolumn->SetTitle ("Host name. ??? if reverse lookup failed.");
+
+ $this->AddColumn ("whois ", "Whois", "narrow");
+ $this->lastcolumn->SetTitle ("Start a whois query.");
+
+ $this->AddSimpleColumn ("c_expires", "Expires");
+ $this->lastcolumn->SetTitle ("Block expires.");
+
+ }
+}
+
+$db = $config->db ();
+$r = new robots ();
+
+getstr ("block");
+getstr ("unblock");
+getstr ("delete");
+
+if ($block) {
+ $ip = long2ip (ip2long ($block));
+ $r->block ($ip);
+ $host = hr_host ($ip);
+ $msg = "Robot $host ($ip) blocked";
+ // redirect else we would block again on page refresh
+ header ("Location: robot-activity?msg=$msg");
+ return;
+}
+
+if ($unblock) {
+ $ip = long2ip (ip2long ($unblock));
+ $r->unblock ($ip);
+ $host = hr_host ($ip);
+ $msg = "Robot $host ($ip) unblocked";
+ header ("Location: robot-activity?msg=$msg");
+ return;
+}
+
+if ($delete) {
+ $ip = long2ip (ip2long ($delete));
+ $r->delete ($ip);
+ $host = hr_host ($ip);
+ $msg = "Robot $host ($ip) deleted";
+ header ("Location: robot-activity?msg=$msg");
+ return;
+}
+
+pageheader ($caption = "Robot Activity Monitor");
+
+getstr ("msg");
+getstr ("errormsg");
+
+if (!empty ($msg)) msg ($msg);
+if (!empty ($errormsg)) error_msg ($msg);
+
+p ("Time: " . date ("Y-m-d H:i:s"));
+
+$db->exec ("select robots.ips.*, robots.blocks.expires > timestamp 'now' as blocked from robots.ips
+left join robots.blocks on robots.ips.ip = robots.blocks.ip
+where
+ (robots.blocks.expires > timestamp 'now')
+ or ((hits > 1000) and (lastseen - firstseen) / hits < interval '2 seconds')
+ or ((rhits > 100) and (lastseen - firstseen) / (rhits + 1) < interval '20 seconds')
+ or (hhits > 10)
+order by not (robots.blocks.expires > timestamp 'now'), ((lastseen - firstseen) / hits) limit 100;
+");
+
+$db->calcfields ["c_host"] = new CalcFieldHost ();
+$db->calcfields ["c_dur"] = new CalcFieldDuration ();
+$db->calcfields ["c_last"] = new CalcFieldLastSeen ();
+$db->calcfields ["c_blocked"] = new CalcFieldBlocked ();
+$db->calcfields ["c_rate"] = new CalcFieldRate ();
+
+// $db->calcfields ["c_isdialup"] = new CalcFieldRBL ("dul.dnsbl.sorbs.net");
+// $db->calcfields ["c_spews"] = new CalcFieldRBL ("l2.spews.dnsbl.sorbs.net");
+
+$table = new RobotHitTable ();
+$table->PrintTable ($db, "Recently Active Robots");
+
+$db->exec ("select * from robots.blocks where expires > timestamp 'now' order by ip;");
+
+$db->calcfields ["c_host"] = new CalcFieldHost ();
+$db->calcfields ["c_expires"] = new CalcFieldExpires ();
+
+$table = new RobotBlockedTable ();
+$table->PrintTable ($db, "Blocked Robots");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/robot-block.php b/catalog/admin/robot-block.php
new file mode 100644
index 0000000..5c41fb1
--- /dev/null
+++ b/catalog/admin/robot-block.php
@@ -0,0 +1,147 @@
+documentroot/.htaccess";
+
+function fixnetwork ($ip) {
+ if (($pos = strpos ($ip, "/")) !== false) {
+ $ip = substr ($ip, 0, $pos);
+ $ip = long2ip (ip2long ($ip) + 1);
+ }
+ return $ip;
+}
+
+function hr_time_diff ($t1, $t2) {
+ $diff = $t2 - $t1;
+ if ($diff < 60)
+ return "";
+ if ($diff < 3600)
+ return round ($diff / 60) . " m";
+ if ($diff < 36000)
+ return round ($diff / 3600, 1) . " h";
+ return round ($diff / 3600, 0) . " h";
+}
+
+function hr_ago ($t1) {
+ $d = hr_time_diff ($t1, time ());
+ return $d ? "$d ago" : "now";
+}
+
+class CalcFieldHost {
+ function f ($db) {
+ $ip = $db->get ("ip", SQLCHAR);
+ $host = @gethostbyaddr ($ip);
+ if ($host == $ip)
+ return "";
+
+ $ipcheck = @gethostbyname ($host);
+ $host = preg_replace ("/[^.]+\.[^.]+$/", '\0 ', $host);
+ if ($ip != $ipcheck)
+ $host = "??? $host ???";
+
+ return $host;
+ }
+}
+
+class CalcFieldDuration {
+ function f ($db) {
+ return hr_time_diff ($db->get ("firstseen", SQLDATE), $db->get ("lastseen", SQLDATE));
+ }
+}
+
+class CalcFieldLastSeen {
+ function f ($db) {
+ return hr_ago ($db->get ("lastseen", SQLDATE));
+ }
+}
+
+class CalcFieldBlocked {
+ function f ($db) {
+ global $blocked;
+ return in_array ($db->get ("ip", SQLCHAR), $blocked[1]) ? "B" : "";
+ }
+}
+
+class CalcFieldRBL {
+ function __construct ($list) {
+ $this->list = $list;
+ }
+ function f ($db) {
+ $ip = fixnetwork ($db->get ("ip", SQLCHAR));
+ $reverse_ip = join (".", array_reverse (explode (".", $ip)));
+ $host = gethostbyname ("$reverse_ip.$this->list");
+ // return $host; // debug
+ return strncmp ($host, "127.", 4) ? "" : "Yes";
+ }
+}
+
+class RobotHitTable extends ListTable {
+ function __construct () {
+ $this->AddSimpleColumn ("c_last", "Seen");
+ $this->lastcolumn->SetTitle ("Last access.");
+
+ $this->AddSimpleColumn ("c_dur", "For");
+ $this->lastcolumn->SetTitle ("Total duration of access.");
+
+ $this->AddSimpleColumn ("ip", "IP");
+ $this->lastcolumn->SetTitle ("IP address.");
+
+ $this->AddSimpleColumn ("c_blocked", "B", "narrow");
+ $this->lastcolumn->SetTitle ("'B' if blocked.");
+
+ $this->AddSimpleColumn ("c_host", "Host");
+ $this->lastcolumn->f = create_function ('$raw', 'return $raw;');
+ $this->lastcolumn->raw = 1;
+ $this->lastcolumn->SetTitle ("Host name. ??? if reverse lookup failed.");
+
+ $this->AddColumn ("whois ", "Whois", "narrow");
+ $this->lastcolumn->SetTitle ("Start a whois query.");
+
+ $this->AddSimpleColumn ("hits", "Total", "narrow right");
+ $this->lastcolumn->SetTitle ("Total hits.");
+
+ $this->AddSimpleColumn ("rhits", "Restricted", "narrow right");
+ $this->lastcolumn->SetTitle ("Hits in robot-restricted area. Should be zero.");
+
+ $this->AddSimpleColumn ("hhits", "Honeypot", "narrow right");
+ $this->lastcolumn->SetTitle ("Hits in honeypot. Should be zero.");
+ }
+}
+
+$db = $config->db ();
+
+pageheader ($caption = "Robot Activity Monitor");
+
+$htaccess = file_get_contents ($htaccess);
+preg_match_all ("/^Deny\s+From\s+([\d.]+)$/im", $htaccess, $blocked, PREG_PATTERN_ORDER);
+
+/*
+foreach ($blocked[1] as $ip) {
+ p ($ip);
+}
+*/
+
+p ("Time: " . date ("Y-m-d H:i:s"));
+
+$db->exec ("select * from robots.ips
+order by hits + hhits * 100 desc limit 20;
+");
+
+$db->calcfields ["c_host"] = new CalcFieldHost ();
+$db->calcfields ["c_dur"] = new CalcFieldDuration ();
+$db->calcfields ["c_last"] = new CalcFieldLastSeen ();
+$db->calcfields ["c_blocked"] = new CalcFieldBlocked ();
+
+// $db->calcfields ["c_isdialup"] = new CalcFieldRBL ("dul.dnsbl.sorbs.net");
+// $db->calcfields ["c_spews"] = new CalcFieldRBL ("l2.spews.dnsbl.sorbs.net");
+
+$table = new RobotHitTable ();
+$table->PrintTable ($db, "Recently Active Robots");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/robot-block.php~ b/catalog/admin/robot-block.php~
new file mode 100644
index 0000000..5ab73cc
--- /dev/null
+++ b/catalog/admin/robot-block.php~
@@ -0,0 +1,146 @@
+documentroot/.htaccess";
+
+function fixnetwork ($ip) {
+ if (($pos = strpos ($ip, "/")) !== false) {
+ $ip = substr ($ip, 0, $pos);
+ $ip = long2ip (ip2long ($ip) + 1);
+ }
+ return $ip;
+}
+
+function hr_time_diff ($t1, $t2) {
+ $diff = $t2 - $t1;
+ if ($diff < 60)
+ return "";
+ if ($diff < 3600)
+ return round ($diff / 60) . " m";
+ if ($diff < 36000)
+ return round ($diff / 3600, 1) . " h";
+ return round ($diff / 3600, 0) . " h";
+}
+
+function hr_ago ($t1) {
+ $d = hr_time_diff ($t1, time ());
+ return $d ? "$d ago" : "now";
+}
+
+class CalcFieldHost {
+ function f ($db) {
+ $ip = $db->get ("ip", SQLCHAR);
+ $host = @gethostbyaddr ($ip);
+ if ($host == $ip)
+ return "";
+
+ $ipcheck = @gethostbyname ($host);
+ $host = preg_replace ("/[^.]+\.[^.]+$/", '\0 ', $host);
+ if ($ip != $ipcheck)
+ $host = "??? $host ???";
+
+ return $host;
+ }
+}
+
+class CalcFieldDuration {
+ function f ($db) {
+ return hr_time_diff ($db->get ("firstseen", SQLDATE), $db->get ("lastseen", SQLDATE));
+ }
+}
+
+class CalcFieldLastSeen {
+ function f ($db) {
+ return hr_ago ($db->get ("lastseen", SQLDATE));
+ }
+}
+
+class CalcFieldBlocked {
+ function f ($db) {
+ global $blocked;
+ return in_array ($db->get ("ip", SQLCHAR), $blocked[1]) ? "B" : "";
+ }
+}
+
+class CalcFieldRBL {
+ function __construct ($list) {
+ $this->list = $list;
+ }
+ function f ($db) {
+ $ip = fixnetwork ($db->get ("ip", SQLCHAR));
+ $reverse_ip = join (".", array_reverse (explode (".", $ip)));
+ $host = gethostbyname ("$reverse_ip.$this->list");
+ // return $host; // debug
+ return strncmp ($host, "127.", 4) ? "" : "Yes";
+ }
+}
+
+class RobotHitTable extends ListTable {
+ function __construct () {
+ $this->AddSimpleColumn ("c_last", "Seen");
+ $this->lastcolumn->SetTitle ("Last access.");
+
+ $this->AddSimpleColumn ("c_dur", "For");
+ $this->lastcolumn->SetTitle ("Total duration of access.");
+
+ $this->AddSimpleColumn ("ip", "IP");
+ $this->lastcolumn->SetTitle ("IP address.");
+
+ $this->AddSimpleColumn ("c_blocked", "B", "narrow");
+ $this->lastcolumn->SetTitle ("'B' if blocked.");
+
+ $this->AddSimpleColumn ("c_host", "Host");
+ $this->lastcolumn->f = create_function ('$raw', 'return $raw;');
+ $this->lastcolumn->raw = 1;
+ $this->lastcolumn->SetTitle ("Host name. ??? if reverse lookup failed.");
+
+ $this->AddColumn ("whois ", "Whois", "narrow");
+ $this->lastcolumn->SetTitle ("Start a whois query.");
+
+ $this->AddSimpleColumn ("hits", "Total", "narrow right");
+ $this->lastcolumn->SetTitle ("Total hits.");
+
+ $this->AddSimpleColumn ("rhits", "Restricted", "narrow right");
+ $this->lastcolumn->SetTitle ("Hits in robot-restricted area. Should be zero.");
+
+ $this->AddSimpleColumn ("hhits", "Honeypot", "narrow right");
+ $this->lastcolumn->SetTitle ("Hits in honeypot. Should be zero.");
+ }
+}
+
+$db = $config->db ();
+
+pageheader ($caption = "Robot Activity Monitor");
+
+$htaccess = file_get_contents ($htaccess);
+preg_match_all ("/^Deny\s+From\s+([\d.]+)$/im", $htaccess, $blocked, PREG_PATTERN_ORDER);
+
+/*
+foreach ($blocked[1] as $ip) {
+ p ($ip);
+}
+*/
+
+p ("Time: " . date ("Y-m-d H:i:s"));
+
+$db->exec ("select * from robots.ips
+order by hits + hhits * 100 desc limit 20;
+");
+
+$db->calcfields ["c_host"] = new CalcFieldHost ();
+$db->calcfields ["c_dur"] = new CalcFieldDuration ();
+$db->calcfields ["c_last"] = new CalcFieldLastSeen ();
+$db->calcfields ["c_blocked"] = new CalcFieldBlocked ();
+
+// $db->calcfields ["c_isdialup"] = new CalcFieldRBL ("dul.dnsbl.sorbs.net");
+// $db->calcfields ["c_spews"] = new CalcFieldRBL ("l2.spews.dnsbl.sorbs.net");
+
+$table = new RobotHitTable ();
+$table->PrintTable ($db, "Recently Active Robots");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/robot-terminator.php b/catalog/admin/robot-terminator.php
new file mode 100644
index 0000000..c18c40d
--- /dev/null
+++ b/catalog/admin/robot-terminator.php
@@ -0,0 +1,88 @@
+db ();
+$db->exec ("update robots.blocks set expires = null where expires <= timestamp 'now'");
+$db->exec ("delete from robots.ips where lastseen < (timestamp 'now' - interval '1 days');");
+$db->exec ("vacuum robots.ips;");
+
+$db2 = $config->db ();
+
+$db2->exec ("select robots.ips.*, robots.blocks.expires > timestamp 'now' as blocked from robots.ips
+left join robots.blocks on robots.ips.ip = robots.blocks.ip
+
+where
+ (robots.blocks.expires is null)
+ and
+ (
+ (hhits > 10)
+ or
+ (
+ (rhits > 150)
+ and
+ (((lastseen - firstseen) / (rhits + 1)) < interval '10 seconds')
+ )
+ )
+");
+
+
+if ($db2->FirstRow ()) {
+ $r = new robots ();
+ do {
+ $ip = $db2->get ("ip", SQLCHAR);
+ $r->block ($ip);
+ $host = $r->host ($ip);
+
+ $to = $config->email_webmaster;
+ $subject = 'Blocked IP address';
+ $message = "Robot $host ($ip) blocked.";
+ $headers = "From: robot-terminator@gutenberg.org\r\n" .
+ "Reply-To: $config->email_webmaster\r\n";
+
+ // echo "$message\n";
+
+ if (!mail ($to, $subject, $message, $headers)) {
+ echo ("could not send email\n");
+ }
+
+ } while ($db2->NextRow ());
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+$s = "# this file is auto-generated by robot-terminator.php. do not edit.\n\n";
+$s .= "# permanent bans\n\n";
+
+$s .= `grep -i '^Deny From [0-9]' $config->documentroot/.htaccess`;
+
+$s .= "\n# temporary bans\n\n";
+
+$db->exec ("select * from robots.blocks where expires > timestamp 'now' order by ip");
+if ($db->FirstRow ()) {
+ do {
+ $ip = $db->get ("ip", SQLCHAR);
+ $s .= "Deny From $ip\n";
+ } while ($db->NextRow ());
+}
+
+$s .= "\n# end of file\n";
+
+// echo ($s);
+
+$file = "$config->documentroot/catalog/.htaccess";
+
+$fp = fopen ($file, "w");
+if ($fp) {
+ fwrite ($fp, $s);
+ fclose ($fp);
+} else {
+ echo ("Cannot write to $file\n");
+}
+
+?>
diff --git a/catalog/admin/robot-terminator.php~ b/catalog/admin/robot-terminator.php~
new file mode 100644
index 0000000..d5769fc
--- /dev/null
+++ b/catalog/admin/robot-terminator.php~
@@ -0,0 +1,87 @@
+db ();
+$db->exec ("update robots.blocks set expires = null where expires <= timestamp 'now'");
+$db->exec ("delete from robots.ips where lastseen < (timestamp 'now' - interval '1 days');");
+$db->exec ("vacuum robots.ips;");
+
+$db2 = $config->db ();
+
+$db2->exec ("select robots.ips.*, robots.blocks.expires > timestamp 'now' as blocked from robots.ips
+left join robots.blocks on robots.ips.ip = robots.blocks.ip
+
+where
+ (robots.blocks.expires is null)
+ and
+ (
+ (hhits > 10)
+ or
+ (
+ (rhits > 150)
+ and
+ (((lastseen - firstseen) / (rhits + 1)) < interval '10 seconds')
+ )
+ )
+");
+
+
+if ($db2->FirstRow ()) {
+ $r = new robots ();
+ do {
+ $ip = $db2->get ("ip", SQLCHAR);
+ $r->block ($ip);
+ $host = $r->host ($ip);
+
+ $to = $config->email_webmaster;
+ $subject = 'Blocked IP address';
+ $message = "Robot $host ($ip) blocked.";
+ $headers = "From: robot-terminator@gutenberg.org\r\n" .
+ "Reply-To: $config->email_webmaster\r\n";
+
+ // echo "$message\n";
+
+ if (!mail ($to, $subject, $message, $headers)) {
+ echo ("could not send email\n");
+ }
+
+ } while ($db2->NextRow ());
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+$s = "# this file is auto-generated by robot-terminator.php. do not edit.\n\n";
+$s .= "# permanent bans\n\n";
+
+$s .= `grep -i '^Deny From [0-9]' $config->documentroot/.htaccess`;
+
+$s .= "\n# temporary bans\n\n";
+
+$db->exec ("select * from robots.blocks where expires > timestamp 'now' order by ip");
+if ($db->FirstRow ()) {
+ do {
+ $ip = $db->get ("ip", SQLCHAR);
+ $s .= "Deny From $ip\n";
+ } while ($db->NextRow ());
+}
+
+$s .= "\n# end of file\n";
+
+// echo ($s);
+
+$file = "$config->documentroot/catalog/.htaccess";
+
+$fp = fopen ($file, "w");
+if ($fp) {
+ fwrite ($fp, $s);
+ fclose ($fp);
+} else {
+ echo ("Cannot write to $file\n");
+}
+
+?>
\ No newline at end of file
diff --git a/catalog/admin/stats.php b/catalog/admin/stats.php
new file mode 100644
index 0000000..e05a53b
--- /dev/null
+++ b/catalog/admin/stats.php
@@ -0,0 +1,173 @@
+db ();
+$db->logger = new logger ();
+
+class AuthorsTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "#author# ", "Author");
+ }
+}
+
+pageheader("Various Statistics");
+
+echo("Author Stats \n");
+
+echo("Note that there is still considerable error in the database of " .
+ "authors, due to incorrect spliting and merging of authors with " .
+ "similar or varying names.
\n");
+
+echo("");
+$db->Exec("select count(*) from authors");
+echo(" Total Authors: " . $db->Get("count") . " \n") ;
+$db->Exec("select count(*) from authors where born_floor is null and " .
+ "born_ceil is null and died_floor is null and died_ceil is null");
+echo(" Authors with no birth or death dates: " . $db->Get("count") .
+ " \n") ;
+$db->Exec("select count(*) from authors where born_floor is not null " .
+ "and born_ceil is null and died_floor is null " .
+ "and died_ceil is null;");
+echo(" Authors with only a earliest birth year: " . $db->Get("count") .
+ " \n") ;
+$db->Exec("select count(*) from authors where born_floor is null " .
+ "and born_ceil is null and died_floor is not null " .
+ "and died_ceil is null;");
+echo(" Authors with only a earliest death year: " . $db->Get("count") .
+ " \n") ;
+echo (" ");
+
+$table = new AuthorsTable ();
+$db->Exec("select pk, author from authors where born_floor is null " .
+ "and died_floor is null and (born_ceil is not null or " .
+ "died_ceil is not null) order by author");
+$table->PrintTable($db, "Authors with only latest birth or death dates");
+
+echo("");
+$db->Exec("select count(note) from authors;");
+echo(" # of Author entries with internal notes: " . $db->Get("count") . " \n") ;
+echo (" ");
+
+$table = new AuthorsTable ();
+$db->Exec("select pk, author from authors " .
+ "order by char_length(author) desc limit 20");
+$table->PrintTable($db, "20 longest Authors names");
+
+$table = new AuthorsTable ();
+$db->Exec("select pk, author from authors " .
+ "order by char_length(author) limit 20");
+$table->PrintTable($db, "20 shortest Authors names");
+
+class AuthorsBirthDeathTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "#author# ", "Author");
+ $this->AddSimpleColumn("born_floor", "Birth");
+ $this->AddSimpleColumn("died_floor", "Death");
+ }
+}
+
+p("As a way to see what authors we have whose works are more likely to be " .
+ "in copyright, this is a list of all the authors born after the " .
+ "critical year of 1923.");
+$table = new AuthorsBirthDeathTable ();
+$db->Exec("select pk, author, born_floor, died_floor " .
+ "from authors where born_floor>1923 order by born_floor");
+$table->PrintTable($db, "Authors born after 1923");
+
+$table = new AuthorsBirthDeathTable ();
+$db->Exec("select pk, author, born_floor, died_floor from authors " .
+ "where died_floor-born_floor>100 order by author");
+$table->PrintTable($db, "Authors who lived more than 100 years");
+
+$table = new AuthorsBirthDeathTable ();
+$db->Exec("select pk, author, born_floor, died_floor from authors " .
+ "where died_floor-born_floor<20 order by author");
+$table->PrintTable($db, "Authors who lived less than 20 years");
+
+$table = new AuthorsBirthDeathTable ();
+$db->Exec("select pk, author, born_floor, died_floor from authors " .
+ "where died_floorPrintTable($db, "Authors born before they died");
+
+echo("Author URLs \n"); /* Author URLs section */
+
+echo("");
+$db->Exec("select count(authors.pk) as count from authors " .
+ "left join author_urls on authors.pk=author_urls.fk_authors " .
+ "where fk_authors is null");
+echo(" Author entries with no URLs attached: " . $db->Get("count") .
+ " \n") ;
+$db->Exec("select count(*) as count from (select fk_authors " .
+ "from author_urls group by fk_authors having " .
+ "count(fk_authors)=1) as foo");
+echo(" Author entries with a single URL: " . $db->Get("count") .
+ " \n");
+$db->Exec("select count(*) as count from (select fk_authors " .
+ "from author_urls group by fk_authors having " .
+ "count(fk_authors)=2) as foo");
+echo(" Author entries with two URLs: " . $db->Get("count") .
+ " \n");
+echo (" ");
+
+class AuthorsWithMoreThan2URLsTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "#author# ", "Author");
+ $this->AddSimpleColumn("count", "# of URLs");
+ }
+}
+$table = new AuthorsWithMoreThan2URLsTable ();
+$db->Exec("select fk_authors as pk, author, count(fk_authors) as count " .
+ "from author_urls join authors on fk_authors=authors.pk " .
+ "group by fk_authors, author having count(fk_authors)>2 " .
+ "order by count(fk_authors), author");
+$table->PrintTable($db, "Authors with more than 2 URLs attached");
+
+echo("");
+$db->Exec("select count(*) from author_urls");
+echo(" Total # of URLs: " . $db->Get("count") . " \n") ;
+$db->Exec("select count(*) from " .
+ "(select distinct description from author_urls) as foo");
+echo(" # of different URL descriptions: " . $db->Get("count") . " \n") ;
+echo (" ");
+class URLDescriptionsTable extends ListTable {
+ function __construct () {
+ $this->AddSimpleColumn("description", "URL Description");
+ $this->AddSimpleColumn("count", "# of Uses");
+ }
+}
+$table = new URLDescriptionsTable ();
+$db->Exec("select description, count(description) from author_urls group by description having count(description)>1 order by count(description) desc");
+$table->PrintTable($db, "URL descriptions used multiple times");
+
+class RepeatedURLsTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "#author# ", "Author");
+ $this->AddSimpleColumn("url", "URL");
+ }
+}
+$table = new RepeatedURLsTable ();
+$db->Exec("select fk_authors, author, url from author_urls " .
+ "join authors on fk_authors=authors.pk " .
+ "where url in (select url from author_urls " .
+ "group by url having count(url)>1) order by url;");
+$table->PrintTable($db, "URLs used multiple times");
+
+pagefooter();
+
+/*
+echo("");
+$db->Exec("");
+echo(" : " . $db->Get("") . " \n") ;
+echo (" ");
+$table = new AuthorsTable ();
+$db->Exec("");
+$table->PrintTable($db, "Authors ");
+*/
diff --git a/catalog/admin/stats.php~ b/catalog/admin/stats.php~
new file mode 100644
index 0000000..6219fcf
--- /dev/null
+++ b/catalog/admin/stats.php~
@@ -0,0 +1,172 @@
+db ();
+$db->logger = new logger ();
+
+class AuthorsTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "#author# ", "Author");
+ }
+}
+
+pageheader("Various Statistics");
+
+echo("Author Stats \n");
+
+echo("Note that there is still considerable error in the database of " .
+ "authors, due to incorrect spliting and merging of authors with " .
+ "similar or varying names.
\n");
+
+echo("");
+$db->Exec("select count(*) from authors");
+echo(" Total Authors: " . $db->Get("count") . " \n") ;
+$db->Exec("select count(*) from authors where born_floor is null and " .
+ "born_ceil is null and died_floor is null and died_ceil is null");
+echo(" Authors with no birth or death dates: " . $db->Get("count") .
+ " \n") ;
+$db->Exec("select count(*) from authors where born_floor is not null " .
+ "and born_ceil is null and died_floor is null " .
+ "and died_ceil is null;");
+echo(" Authors with only a earliest birth year: " . $db->Get("count") .
+ " \n") ;
+$db->Exec("select count(*) from authors where born_floor is null " .
+ "and born_ceil is null and died_floor is not null " .
+ "and died_ceil is null;");
+echo(" Authors with only a earliest death year: " . $db->Get("count") .
+ " \n") ;
+echo (" ");
+
+$table = new AuthorsTable ();
+$db->Exec("select pk, author from authors where born_floor is null " .
+ "and died_floor is null and (born_ceil is not null or " .
+ "died_ceil is not null) order by author");
+$table->PrintTable($db, "Authors with only latest birth or death dates");
+
+echo("");
+$db->Exec("select count(note) from authors;");
+echo(" # of Author entries with internal notes: " . $db->Get("count") . " \n") ;
+echo (" ");
+
+$table = new AuthorsTable ();
+$db->Exec("select pk, author from authors " .
+ "order by char_length(author) desc limit 20");
+$table->PrintTable($db, "20 longest Authors names");
+
+$table = new AuthorsTable ();
+$db->Exec("select pk, author from authors " .
+ "order by char_length(author) limit 20");
+$table->PrintTable($db, "20 shortest Authors names");
+
+class AuthorsBirthDeathTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "#author# ", "Author");
+ $this->AddSimpleColumn("born_floor", "Birth");
+ $this->AddSimpleColumn("died_floor", "Death");
+ }
+}
+
+p("As a way to see what authors we have whose works are more likely to be " .
+ "in copyright, this is a list of all the authors born after the " .
+ "critical year of 1923.");
+$table = new AuthorsBirthDeathTable ();
+$db->Exec("select pk, author, born_floor, died_floor " .
+ "from authors where born_floor>1923 order by born_floor");
+$table->PrintTable($db, "Authors born after 1923");
+
+$table = new AuthorsBirthDeathTable ();
+$db->Exec("select pk, author, born_floor, died_floor from authors " .
+ "where died_floor-born_floor>100 order by author");
+$table->PrintTable($db, "Authors who lived more than 100 years");
+
+$table = new AuthorsBirthDeathTable ();
+$db->Exec("select pk, author, born_floor, died_floor from authors " .
+ "where died_floor-born_floor<20 order by author");
+$table->PrintTable($db, "Authors who lived less than 20 years");
+
+$table = new AuthorsBirthDeathTable ();
+$db->Exec("select pk, author, born_floor, died_floor from authors " .
+ "where died_floorPrintTable($db, "Authors born before they died");
+
+echo("Author URLs \n"); /* Author URLs section */
+
+echo("");
+$db->Exec("select count(authors.pk) as count from authors " .
+ "left join author_urls on authors.pk=author_urls.fk_authors " .
+ "where fk_authors is null");
+echo(" Author entries with no URLs attached: " . $db->Get("count") .
+ " \n") ;
+$db->Exec("select count(*) as count from (select fk_authors " .
+ "from author_urls group by fk_authors having " .
+ "count(fk_authors)=1) as foo");
+echo(" Author entries with a single URL: " . $db->Get("count") .
+ " \n");
+$db->Exec("select count(*) as count from (select fk_authors " .
+ "from author_urls group by fk_authors having " .
+ "count(fk_authors)=2) as foo");
+echo(" Author entries with two URLs: " . $db->Get("count") .
+ " \n");
+echo (" ");
+
+class AuthorsWithMoreThan2URLsTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "#author# ", "Author");
+ $this->AddSimpleColumn("count", "# of URLs");
+ }
+}
+$table = new AuthorsWithMoreThan2URLsTable ();
+$db->Exec("select fk_authors as pk, author, count(fk_authors) as count " .
+ "from author_urls join authors on fk_authors=authors.pk " .
+ "group by fk_authors, author having count(fk_authors)>2 " .
+ "order by count(fk_authors), author");
+$table->PrintTable($db, "Authors with more than 2 URLs attached");
+
+echo("");
+$db->Exec("select count(*) from author_urls");
+echo(" Total # of URLs: " . $db->Get("count") . " \n") ;
+$db->Exec("select count(*) from " .
+ "(select distinct description from author_urls) as foo");
+echo(" # of different URL descriptions: " . $db->Get("count") . " \n") ;
+echo (" ");
+class URLDescriptionsTable extends ListTable {
+ function __construct () {
+ $this->AddSimpleColumn("description", "URL Description");
+ $this->AddSimpleColumn("count", "# of Uses");
+ }
+}
+$table = new URLDescriptionsTable ();
+$db->Exec("select description, count(description) from author_urls group by description having count(description)>1 order by count(description) desc");
+$table->PrintTable($db, "URL descriptions used multiple times");
+
+class RepeatedURLsTable extends ListTable {
+ function __construct () {
+ $this->AddColumn("" .
+ "#author# ", "Author");
+ $this->AddSimpleColumn("url", "URL");
+ }
+}
+$table = new RepeatedURLsTable ();
+$db->Exec("select fk_authors, author, url from author_urls " .
+ "join authors on fk_authors=authors.pk " .
+ "where url in (select url from author_urls " .
+ "group by url having count(url)>1) order by url;");
+$table->PrintTable($db, "URLs used multiple times");
+
+pagefooter();
+
+/*
+echo("");
+$db->Exec("");
+echo(" : " . $db->Get("") . " \n") ;
+echo (" ");
+$table = new AuthorsTable ();
+$db->Exec("");
+$table->PrintTable($db, "Authors ");
+*/
diff --git a/catalog/admin/subj_locc_by_etext.php b/catalog/admin/subj_locc_by_etext.php
new file mode 100644
index 0000000..00df345
--- /dev/null
+++ b/catalog/admin/subj_locc_by_etext.php
@@ -0,0 +1,68 @@
+db ();
+$db->logger = new logger ();
+if ($within_the_last) {
+ pageheader("List of Books released within the last $within_the_last days lacking a Subject and/or a LoCC");
+ } else {
+ pageheader("List of Books lacking a Subject and/or a LoCC");
+ }
+class SubjLoccByEtextTable extends MoreTable {
+ function __construct () {
+ $this->AddColumn ("#pk# ",
+ "Etext Nr. (edit link)", "right");
+ $this->AddSimpleColumn ("author", "Author");
+ $this->AddColumn ("#title# ",
+ "Title (bibrec link)");
+ $this->AddColumn ("" .
+ " ",
+ "No Subj", "narrow");
+ $this->AddColumn ("" .
+ " ",
+ "No LoCC", "narrow");
+ $this->limit = 30;
+ $this->relay = array ();
+ }
+}
+$table = new SubjLoccByEtextTable ();
+$sql="select distinct on (fk_books) fk_books as pk, text as title, author, " .
+ "(case when fk_subjects is null then 'black' end) as nosubj, " .
+ "(case when fk_loccs is null then 'black' end) as nolocc " .
+ "from attributes left join mn_books_subjects using (fk_books) " .
+ "left join mn_books_loccs using (fk_books) " .
+ "join mn_books_authors using (fk_books) " .
+ "join authors on authors.pk=fk_authors ";
+
+if ($within_the_last) {
+ $sql=$sql . "join books on books.pk=fk_books ";
+}
+
+// gbn: the fk_roles skips records that don't have an Author or Creator:
+ $sql=$sql . "where fk_attriblist=245 and "; // .
+// "fk_roles in ('aut', 'cre') and heading=1 and ";
+
+if ($within_the_last) {
+ $sql=$sql . "books.release_date >= current_date - interval '$within_the_last days' and ";
+}
+
+$sql=$sql . "((fk_subjects is null) or (fk_loccs is null)) " .
+ "order by fk_books, text, author" .
+ $table->MkOffset ();
+
+// echo ("$sql
");
+
+$db->Exec($sql);
+# gbn: 20091213
+print "Last day only
\n";
+
+
+$table->PrintTable($db, "Books lacking a Subject and/or a LoCC");
+
+pagefooter();
diff --git a/catalog/admin/subj_locc_by_etext.php.20090831 b/catalog/admin/subj_locc_by_etext.php.20090831
new file mode 100644
index 0000000..5e7ff9d
--- /dev/null
+++ b/catalog/admin/subj_locc_by_etext.php.20090831
@@ -0,0 +1,55 @@
+db ();
+$db->logger = new logger ();
+if ($within_the_last) {
+ pageheader("List of Books released within the last $within_the_last days lacking a Subject and/or a LoCC");
+ } else {
+ pageheader("List of Books lacking a Subject and/or a LoCC");
+ }
+class SubjLoccByEtextTable extends MoreTable {
+ function SubjLoccByEtextTable () {
+ $this->AddColumn ("#pk# ",
+ "Etext Nr. (edit link)", "right");
+ $this->AddSimpleColumn ("author", "Author");
+ $this->AddColumn ("#title# ",
+ "Title (bibrec link)");
+ $this->AddColumn ("" .
+ " ",
+ "No Subj", "narrow");
+ $this->AddColumn ("" .
+ " ",
+ "No LoCC", "narrow");
+ $this->limit = 30;
+ $this->relay = array ();
+ }
+}
+$table = new SubjLoccByEtextTable ();
+$sql="select distinct on (fk_books) fk_books as pk, text as title, author, " .
+ "(case when fk_subjects is null then 'black' end) as nosubj, " .
+ "(case when fk_loccs is null then 'black' end) as nolocc " .
+ "from attributes left join mn_books_subjects using (fk_books) " .
+ "left join mn_books_loccs using (fk_books) " .
+ "join mn_books_authors using (fk_books) " .
+ "join authors on authors.pk=fk_authors ";
+if ($within_the_last) {
+ $sql=$sql . "join books on books.pk=fk_books ";
+ }
+$sql=$sql . "where fk_attriblist=245 and " .
+ "fk_roles='aut' and heading=1 and ";
+if ($within_the_last) {
+ $sql=$sql . "release_date>=(current_date-integer '$within_the_last') and ";
+ }
+$sql=$sql . "((fk_subjects is null) or (fk_loccs is null)) " .
+ "order by fk_books, text, author" .
+ $table->MkOffset ();
+$db->Exec($sql);
+$table->PrintTable($db, "Books lacking a Subject and/or a LoCC");
+
+pagefooter();
\ No newline at end of file
diff --git a/catalog/admin/subj_locc_by_etext.php~ b/catalog/admin/subj_locc_by_etext.php~
new file mode 100644
index 0000000..a9c0bb3
--- /dev/null
+++ b/catalog/admin/subj_locc_by_etext.php~
@@ -0,0 +1,67 @@
+db ();
+$db->logger = new logger ();
+if ($within_the_last) {
+ pageheader("List of Books released within the last $within_the_last days lacking a Subject and/or a LoCC");
+ } else {
+ pageheader("List of Books lacking a Subject and/or a LoCC");
+ }
+class SubjLoccByEtextTable extends MoreTable {
+ function __construct () {
+ $this->AddColumn ("#pk# ",
+ "Etext Nr. (edit link)", "right");
+ $this->AddSimpleColumn ("author", "Author");
+ $this->AddColumn ("#title# ",
+ "Title (bibrec link)");
+ $this->AddColumn ("" .
+ " ",
+ "No Subj", "narrow");
+ $this->AddColumn ("" .
+ " ",
+ "No LoCC", "narrow");
+ $this->limit = 30;
+ $this->relay = array ();
+ }
+}
+$table = new SubjLoccByEtextTable ();
+$sql="select distinct on (fk_books) fk_books as pk, text as title, author, " .
+ "(case when fk_subjects is null then 'black' end) as nosubj, " .
+ "(case when fk_loccs is null then 'black' end) as nolocc " .
+ "from attributes left join mn_books_subjects using (fk_books) " .
+ "left join mn_books_loccs using (fk_books) " .
+ "join mn_books_authors using (fk_books) " .
+ "join authors on authors.pk=fk_authors ";
+
+if ($within_the_last) {
+ $sql=$sql . "join books on books.pk=fk_books ";
+}
+
+// gbn: the fk_roles skips records that don't have an Author or Creator:
+ $sql=$sql . "where fk_attriblist=245 and "; // .
+// "fk_roles in ('aut', 'cre') and heading=1 and ";
+
+if ($within_the_last) {
+ $sql=$sql . "books.release_date >= current_date - interval '$within_the_last days' and ";
+}
+
+$sql=$sql . "((fk_subjects is null) or (fk_loccs is null)) " .
+ "order by fk_books, text, author" .
+ $table->MkOffset ();
+
+// echo ("$sql
");
+
+$db->Exec($sql);
+# gbn: 20091213
+print "Last day only
\n";
+
+
+$table->PrintTable($db, "Books lacking a Subject and/or a LoCC");
+
+pagefooter();
diff --git a/catalog/admin/subject.php b/catalog/admin/subject.php
new file mode 100644
index 0000000..9429dad
--- /dev/null
+++ b/catalog/admin/subject.php
@@ -0,0 +1,136 @@
+AddColumn ("#pk# ",
+ "Etext Nr.", "right", "1*");
+ $this->AddSimpleColumn ("author", "Author");
+ $this->AddSimpleColumn ("title", "Title");
+ $this->limit = 25;
+ $this->relay = array ("fk_subjects", "mode", "filter");
+ }
+}
+
+$db = $config->db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_subjects");
+getstr ("filter");
+
+$subject_name = "";
+if ($db->Exec("select subject from subjects where pk = $fk_subjects")) {
+#it will make life nicer if the message includes *what* subject was linked.
+ $subject_name = $db->Get("subject");
+ }
+if (!$subject_name) {
+ /* if getting the actual name fails for some reason, use the internal number instead;
+ at least it is something...*/
+ $subject_name = "Internal #: $fk_subjects";
+ }
+
+if (ismode ("delete")) {
+ $db->Exec ("select count (*) as cnt from mn_books_subjects " .
+ "where fk_subjects = $fk_subjects");
+ $cnt = $db->get ("cnt");
+ if ($cnt > 0) {
+ $f->SubCaption ("Warning: There are $cnt books related to \"$subject_name\". ");
+ }
+ $f->SubCaption ("You are about to delete \"$subject_name\".");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ $f->Text ("subject", "subject", "Subject", SQLCHAR, 80, 240, true);
+ $f->LoadData ("select * from subjects where pk = $fk_subjects");
+
+}
+$f->Hidden ("fk_subjects");
+$f->Hidden ("filter");
+
+if (isupdatemode ("add")) {
+ $subject_name=htmlspecialchars(urldecode($_POST["subject"]));
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into subjects " . $sql)) {
+ msg ("Subject '$subject_name' added !");
+ } else {
+ error_msg ("Could not add subject '$subject_name'!");
+ }
+ $db->Exec ("select last_value from subjects_pk_seq");
+ $fk_subjects=$db->Get("last_value");
+ }
+}
+if (isupdatemode ("edit")) {
+ $subject_name=htmlspecialchars(urldecode($_POST["subject"]));
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update subjects set " . $sql . "where pk = $fk_subjects")) {
+ msg ("Subject '$subject_name' modified !");
+ } else {
+ error_msg ("Could not modify subject '$subject_name'!");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->Exec ("delete from mn_books_subjects where fk_subjects = $fk_subjects");
+ if ($db->Exec ("delete from subjects where pk = $fk_subjects")) {
+ msg ("Subject '$subject_name' deleted !");
+ } else {
+ error_msg ("Could not delete subject '$subject_name'!");
+ }
+}
+
+if ($fk_subjects) {
+ echo("Internal Subject #: $fk_subjects ");
+ //Only display the Internal # when it exists. ;-)
+}
+if (isupdate ()) {
+ if (!isupdatemode ("delete")) {
+ echo (" " .
+ "Back to Subject \"$subject_name\"
\n\n");
+ }
+} else {
+ $f->Output ($caption, $caption);
+
+ if (ismode ("edit")) {
+ echo (" " .
+ "" .
+ "Delete Subject \n");
+
+ $table = new ListBooksTable ();
+ $db->Exec ("select fk_books as pk, text as title, author " .
+ "from (mn_books_subjects join attributes using (fk_books)) " .
+ "left join mn_books_authors using (fk_books) " .
+ "left join authors on authors.pk = fk_authors " .
+ "where fk_subjects=$fk_subjects and fk_attriblist in (240, 245, 246) " .
+ "order by author, title " .
+ $table->MkOffset ());
+ if ($db->Get("pk")) {
+ $table->PrintTable ($db, "Books for Subject");
+ } else {
+ echo ("There are no books with this Subject!
\n");
+ }
+ }
+}
+
+echo (" " .
+ "Back to Subject List
\n");
+echo (" " .
+ "Add a new Subject
\n\n");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/subject.php~ b/catalog/admin/subject.php~
new file mode 100644
index 0000000..0c05678
--- /dev/null
+++ b/catalog/admin/subject.php~
@@ -0,0 +1,135 @@
+AddColumn ("#pk# ",
+ "Etext Nr.", "right", "1*");
+ $this->AddSimpleColumn ("author", "Author");
+ $this->AddSimpleColumn ("title", "Title");
+ $this->limit = 25;
+ $this->relay = array ("fk_subjects", "mode", "filter");
+ }
+}
+
+$db = $config->db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_subjects");
+getstr ("filter");
+
+$subject_name = "";
+if ($db->Exec("select subject from subjects where pk = $fk_subjects")) {
+#it will make life nicer if the message includes *what* subject was linked.
+ $subject_name = $db->Get("subject");
+ }
+if (!$subject_name) {
+ /* if getting the actual name fails for some reason, use the internal number instead;
+ at least it is something...*/
+ $subject_name = "Internal #: $fk_subjects";
+ }
+
+if (ismode ("delete")) {
+ $db->Exec ("select count (*) as cnt from mn_books_subjects " .
+ "where fk_subjects = $fk_subjects");
+ $cnt = $db->get ("cnt");
+ if ($cnt > 0) {
+ $f->SubCaption ("Warning: There are $cnt books related to \"$subject_name\". ");
+ }
+ $f->SubCaption ("You are about to delete \"$subject_name\".");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ $f->Text ("subject", "subject", "Subject", SQLCHAR, 80, 240, true);
+ $f->LoadData ("select * from subjects where pk = $fk_subjects");
+
+}
+$f->Hidden ("fk_subjects");
+$f->Hidden ("filter");
+
+if (isupdatemode ("add")) {
+ $subject_name=htmlspecialchars(urldecode($_POST["subject"]));
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into subjects " . $sql)) {
+ msg ("Subject '$subject_name' added !");
+ } else {
+ error_msg ("Could not add subject '$subject_name'!");
+ }
+ $db->Exec ("select last_value from subjects_pk_seq");
+ $fk_subjects=$db->Get("last_value");
+ }
+}
+if (isupdatemode ("edit")) {
+ $subject_name=htmlspecialchars(urldecode($_POST["subject"]));
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update subjects set " . $sql . "where pk = $fk_subjects")) {
+ msg ("Subject '$subject_name' modified !");
+ } else {
+ error_msg ("Could not modify subject '$subject_name'!");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->Exec ("delete from mn_books_subjects where fk_subjects = $fk_subjects");
+ if ($db->Exec ("delete from subjects where pk = $fk_subjects")) {
+ msg ("Subject '$subject_name' deleted !");
+ } else {
+ error_msg ("Could not delete subject '$subject_name'!");
+ }
+}
+
+if ($fk_subjects) {
+ echo("Internal Subject #: $fk_subjects ");
+ //Only display the Internal # when it exists. ;-)
+}
+if (isupdate ()) {
+ if (!isupdatemode ("delete")) {
+ echo (" " .
+ "Back to Subject \"$subject_name\"
\n\n");
+ }
+} else {
+ $f->Output ($caption, $caption);
+
+ if (ismode ("edit")) {
+ echo (" " .
+ "" .
+ "Delete Subject \n");
+
+ $table = new ListBooksTable ();
+ $db->Exec ("select fk_books as pk, text as title, author " .
+ "from (mn_books_subjects join attributes using (fk_books)) " .
+ "left join mn_books_authors using (fk_books) " .
+ "left join authors on authors.pk = fk_authors " .
+ "where fk_subjects=$fk_subjects and fk_attriblist in (240, 245, 246) " .
+ "order by author, title " .
+ $table->MkOffset ());
+ if ($db->Get("pk")) {
+ $table->PrintTable ($db, "Books for Subject");
+ } else {
+ echo ("There are no books with this Subject!
\n");
+ }
+ }
+}
+
+echo (" " .
+ "Back to Subject List
\n");
+echo (" " .
+ "Add a new Subject
\n\n");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/subjects_list.php b/catalog/admin/subjects_list.php
new file mode 100644
index 0000000..5d66039
--- /dev/null
+++ b/catalog/admin/subjects_list.php
@@ -0,0 +1,47 @@
+AddColumn ("$prefix=edit&fk_subjects=#pk#\">Edit",
+ "$prefix=add\">Add", "left", "1%");
+ $this->AddColumn ("$prefix=delete&fk_subjects=#pk#\">Delete",
+ "", "left", "1%");
+ $this->AddSimpleColumn ("subject", "Subject");
+ $this->AddSimpleColumn("pk", "Internal #");
+ }
+}
+
+$db = $config->db ();
+
+echo ("
+Please enter the first few characters of the subject (at least one).
+Search is case-sensitive.
+Use * as wildcard. (eg. *Fiction)
+To see everything just enter *.
+");
+
+form_open ();
+echo (" \n");
+form_submit ("Search");
+form_close ();
+
+if ($filter != "") {
+ $filt = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from subjects where subject like '$filt%' order by subject;");
+ $table = new ListSubjectsTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/subjects_list.php~ b/catalog/admin/subjects_list.php~
new file mode 100644
index 0000000..63dae96
--- /dev/null
+++ b/catalog/admin/subjects_list.php~
@@ -0,0 +1,46 @@
+AddColumn ("$prefix=edit&fk_subjects=#pk#\">Edit",
+ "$prefix=add\">Add", "left", "1%");
+ $this->AddColumn ("$prefix=delete&fk_subjects=#pk#\">Delete",
+ "", "left", "1%");
+ $this->AddSimpleColumn ("subject", "Subject");
+ $this->AddSimpleColumn("pk", "Internal #");
+ }
+}
+
+$db = $config->db ();
+
+echo ("
+Please enter the first few characters of the subject (at least one).
+Search is case-sensitive.
+Use * as wildcard. (eg. *Fiction)
+To see everything just enter *.
+");
+
+form_open ();
+echo (" \n");
+form_submit ("Search");
+form_close ();
+
+if ($filter != "") {
+ $filt = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from subjects where subject like '$filt%' order by subject;");
+ $table = new ListSubjectsTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/swish-prog.php b/catalog/admin/swish-prog.php
new file mode 100644
index 0000000..1f09acf
--- /dev/null
+++ b/catalog/admin/swish-prog.php
@@ -0,0 +1,106 @@
+db ();
+$db2 = $config->db ();
+
+function cmp ($a, $b) {
+ // sort on score descending
+ if ($a->score == $b->score) {
+ return 0;
+ }
+ return ($a->score > $b->score) ? -1 : 1;
+}
+
+function book ($fk_books) {
+ global $config, $db2;
+
+ // find best indexing candidate
+
+ $db2->exec ("select pk, filename, fk_filetypes, fk_encodings from files " .
+ "where fk_books = $fk_books and fk_compressions = 'none' and obsoleted = 0 and " .
+ "fk_filetypes in ('txt', 'html', 'tex')");
+
+ if ($db2->FirstRow ()) {
+ do {
+ $o->filename = $db2->get ("filename", SQLCHAR);
+ $o->fk_filetypes = $db2->get ("fk_filetypes", SQLCHAR);
+ $o->fk_encodings = $db2->get ("fk_encodings", SQLCHAR);
+ $o->fk_files = $db2->get ("pk", SQLINT);
+ $o->score = 0;
+ $o->type = "TXT*";
+ $files[] = $o;
+ } while ($db2->NextRow ());
+ }
+
+ for ($i = 0; $i < count ($files); $i++) {
+ $o =& $files[$i];
+ if ($o->fk_filetypes == 'html') {
+ $o->score = 16;
+ $o->type = "HTML*";
+ }
+ if ($o->fk_filetypes == 'tex') {
+ $o->score = 0;
+ }
+ if ($o->fk_filetypes == 'txt') {
+ // swish-e supports iso-8859-* only, exclude everything else from indexing
+ if (!isset ($o->fk_encodings) || $o->fk_encodings == "us-ascii") {
+ $o->score = 1;
+ }
+ if (!strncmp ($o->fk_encodings, "iso-", 4)) {
+ $o->score = 2;
+ }
+ if (!strncmp ($o->fk_encodings, "windows-", 8)) {
+ $o->score = 3;
+ }
+ }
+ }
+ if (count ($files) == 0)
+ return;
+
+ usort ($files, "cmp");
+ $maxscore = $files[0]->score;
+
+ // careful! there may be more than one file per book to scan
+
+ for ($i = 0; $i < count ($files); $i++) {
+ $o =& $files[$i];
+ if ($o->score != $maxscore) {
+ continue;
+ }
+ if (is_link ("$config->filesroot/$o->filename")) {
+ continue;
+ }
+ if (!is_readable ("$config->filesroot/$o->filename")) {
+ continue;
+ }
+ $s = @stat ("$config->filesroot/$o->filename");
+ if (!$s) {
+ continue;
+ }
+
+ // ok, send it out
+ echo ("Path-Name: $fk_books/$o->fk_files/$o->fk_filetypes/$o->fk_encodings\n" .
+ "Content-Length: {$s['size']}\n" .
+ "Document-Type: $o->type\n\n");
+
+ readfile ("$config->filesroot/$o->filename");
+ }
+}
+
+$db->exec ("select pk from books order by pk");
+
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("pk", SQLINT);
+ book ($fk_books);
+ } while ($db->NextRow ());
+}
+
+?>
diff --git a/catalog/admin/swish-prog.php~ b/catalog/admin/swish-prog.php~
new file mode 100644
index 0000000..377cd08
--- /dev/null
+++ b/catalog/admin/swish-prog.php~
@@ -0,0 +1,105 @@
+db ();
+$db2 = $config->db ();
+
+function cmp ($a, $b) {
+ // sort on score descending
+ if ($a->score == $b->score) {
+ return 0;
+ }
+ return ($a->score > $b->score) ? -1 : 1;
+}
+
+function book ($fk_books) {
+ global $config, $db2;
+
+ // find best indexing candidate
+
+ $db2->exec ("select pk, filename, fk_filetypes, fk_encodings from files " .
+ "where fk_books = $fk_books and fk_compressions = 'none' and obsoleted = 0 and " .
+ "fk_filetypes in ('txt', 'html', 'tex')");
+
+ if ($db2->FirstRow ()) {
+ do {
+ $o->filename = $db2->get ("filename", SQLCHAR);
+ $o->fk_filetypes = $db2->get ("fk_filetypes", SQLCHAR);
+ $o->fk_encodings = $db2->get ("fk_encodings", SQLCHAR);
+ $o->fk_files = $db2->get ("pk", SQLINT);
+ $o->score = 0;
+ $o->type = "TXT*";
+ $files[] = $o;
+ } while ($db2->NextRow ());
+ }
+
+ for ($i = 0; $i < count ($files); $i++) {
+ $o =& $files[$i];
+ if ($o->fk_filetypes == 'html') {
+ $o->score = 16;
+ $o->type = "HTML*";
+ }
+ if ($o->fk_filetypes == 'tex') {
+ $o->score = 0;
+ }
+ if ($o->fk_filetypes == 'txt') {
+ // swish-e supports iso-8859-* only, exclude everything else from indexing
+ if (!isset ($o->fk_encodings) || $o->fk_encodings == "us-ascii") {
+ $o->score = 1;
+ }
+ if (!strncmp ($o->fk_encodings, "iso-", 4)) {
+ $o->score = 2;
+ }
+ if (!strncmp ($o->fk_encodings, "windows-", 8)) {
+ $o->score = 3;
+ }
+ }
+ }
+ if (count ($files) == 0)
+ return;
+
+ usort ($files, "cmp");
+ $maxscore = $files[0]->score;
+
+ // careful! there may be more than one file per book to scan
+
+ for ($i = 0; $i < count ($files); $i++) {
+ $o =& $files[$i];
+ if ($o->score != $maxscore) {
+ continue;
+ }
+ if (is_link ("$config->filesroot/$o->filename")) {
+ continue;
+ }
+ if (!is_readable ("$config->filesroot/$o->filename")) {
+ continue;
+ }
+ $s = @stat ("$config->filesroot/$o->filename");
+ if (!$s) {
+ continue;
+ }
+
+ // ok, send it out
+ echo ("Path-Name: $fk_books/$o->fk_files/$o->fk_filetypes/$o->fk_encodings\n" .
+ "Content-Length: {$s['size']}\n" .
+ "Document-Type: $o->type\n\n");
+
+ readfile ("$config->filesroot/$o->filename");
+ }
+}
+
+$db->exec ("select pk from books order by pk");
+
+if ($db->FirstRow ()) {
+ do {
+ $fk_books = $db->get ("pk", SQLINT);
+ book ($fk_books);
+ } while ($db->NextRow ());
+}
+
+?>
diff --git a/catalog/admin/tail.php b/catalog/admin/tail.php
new file mode 100644
index 0000000..1314807
--- /dev/null
+++ b/catalog/admin/tail.php
@@ -0,0 +1,17 @@
+
diff --git a/catalog/admin/tail.php~ b/catalog/admin/tail.php~
new file mode 100644
index 0000000..1a2216c
--- /dev/null
+++ b/catalog/admin/tail.php~
@@ -0,0 +1,16 @@
+
diff --git a/catalog/admin/title-checker.php b/catalog/admin/title-checker.php
new file mode 100644
index 0000000..f524455
--- /dev/null
+++ b/catalog/admin/title-checker.php
@@ -0,0 +1,68 @@
+db ();
+$db2 = $config->db ();
+
+$pks = array ();
+$gutindex = array ();
+
+$db->exec ("select * from titles where title_order = 1 order by fk_books");
+
+if ($db->FirstRow ()) {
+ do {
+ $pk = $db->get ("pk", SQLINT);
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $title = $db->get ("title", SQLCHAR);
+
+ $db2->exec ("select gutindex from books where pk = $fk_books");
+ $gutindex = $db2->get ("gutindex", SQLCHAR);
+
+ if (empty ($gutindex)) {
+ continue;
+ }
+
+ $gutindex = preg_replace ("/^\w+\s+\d+\s+/", "", $gutindex);
+ $title = preg_replace ("/\s*—.*/", "", $title);
+ $title = preg_replace ("/\s*--.*/", "", $title);
+
+ $s = array ('The ', 'A ', 'An ');
+ $r = array ('', '', '');
+
+ $gutindex = str_replace ($s, $r, $gutindex);
+ $title = str_replace ($s, $r, $title);
+
+
+ if (!strncasecmp ($title, $gutindex, strlen ($title))) continue;
+
+ $t = strtr ($title, ",.:;-_'", " ");
+ $awords = preg_split ("/\s+/", $t);
+
+ $i = 0;
+ $words = 0;
+ $matched = 0;
+
+ foreach ($awords as $word) {
+ if (strlen ($word) >= 5) {
+ if (!strncasecmp ($word, "Vol", 3)) continue;
+ if ($word == "Part") continue;
+ $words++;
+ if (strpos ($gutindex, $word) !== false) {
+ $matched++;
+ }
+ }
+ $i++;
+ }
+ if ($matched < 1) {
+ echo ("$fk_books\n\n$title\n\n$gutindex\n\n----------\n\n");
+ }
+ } while ($db->NextRow ());
+}
+
+
+?>
diff --git a/catalog/admin/title-checker.php~ b/catalog/admin/title-checker.php~
new file mode 100644
index 0000000..2058014
--- /dev/null
+++ b/catalog/admin/title-checker.php~
@@ -0,0 +1,67 @@
+db ();
+$db2 = $config->db ();
+
+$pks = array ();
+$gutindex = array ();
+
+$db->exec ("select * from titles where title_order = 1 order by fk_books");
+
+if ($db->FirstRow ()) {
+ do {
+ $pk = $db->get ("pk", SQLINT);
+ $fk_books = $db->get ("fk_books", SQLINT);
+ $title = $db->get ("title", SQLCHAR);
+
+ $db2->exec ("select gutindex from books where pk = $fk_books");
+ $gutindex = $db2->get ("gutindex", SQLCHAR);
+
+ if (empty ($gutindex)) {
+ continue;
+ }
+
+ $gutindex = preg_replace ("/^\w+\s+\d+\s+/", "", $gutindex);
+ $title = preg_replace ("/\s*—.*/", "", $title);
+ $title = preg_replace ("/\s*--.*/", "", $title);
+
+ $s = array ('The ', 'A ', 'An ');
+ $r = array ('', '', '');
+
+ $gutindex = str_replace ($s, $r, $gutindex);
+ $title = str_replace ($s, $r, $title);
+
+
+ if (!strncasecmp ($title, $gutindex, strlen ($title))) continue;
+
+ $t = strtr ($title, ",.:;-_'", " ");
+ $awords = preg_split ("/\s+/", $t);
+
+ $i = 0;
+ $words = 0;
+ $matched = 0;
+
+ foreach ($awords as $word) {
+ if (strlen ($word) >= 5) {
+ if (!strncasecmp ($word, "Vol", 3)) continue;
+ if ($word == "Part") continue;
+ $words++;
+ if (strpos ($gutindex, $word) !== false) {
+ $matched++;
+ }
+ }
+ $i++;
+ }
+ if ($matched < 1) {
+ echo ("$fk_books\n\n$title\n\n$gutindex\n\n----------\n\n");
+ }
+ } while ($db->NextRow ());
+}
+
+
+?>
\ No newline at end of file
diff --git a/catalog/admin/titles.php b/catalog/admin/titles.php
new file mode 100644
index 0000000..f3982ef
--- /dev/null
+++ b/catalog/admin/titles.php
@@ -0,0 +1,91 @@
+db ();
+getstr ("titlemask");
+getint ("maxcnt", 25);
+
+pageheader ("Batch-Edit Attributes");
+
+$marcs = array ();
+
+$db->exec ("select * from attriblist order by pk");
+if ($db->FirstRow ()) {
+ do {
+ $marcs[$db->get ("pk", SQLINT)] = $db->get ("name", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+function mk_options ($name, $options, $option) {
+ $ret = "";
+ foreach ($options as $value => $opt) {
+ $selected = ($value == $option) ? " selected=\"selected\"" : "";
+ $ret .= "$opt \n";
+ }
+ return "\n" . $ret . " \n";
+}
+
+class TypeColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "Type", "narrow");
+ }
+ function Data ($db) {
+ global $marcs;
+ return "" . mk_options ("marcs", $marcs, $db->get ("fk_attriblist")) . " ";
+ }
+}
+
+class TextAreaColumn extends dbtSimpleColumn {
+ function __construct ($dbfield, $caption, $class = null) {
+ parent::__construct ($dbfield, $caption, $class);
+ }
+ function Data ($db) {
+ global $config;
+ return "" . preg_replace ("/#(\w+)#/e",
+ "htmlspecialchars (\$db->get('\\1'))", $this->dbfield) . " ";
+ }
+}
+
+
+form_open_get ();
+p ("Enter Perl RegExp :
+ eg. Commedia");
+p ("Max. No.: ");
+form_submit ("Reload");
+form_close ();
+
+$t = new ListTable ();
+$t->AddColumn (" ", "", "narrow");
+$t->AddColumn (" ", "Nonfiling");
+$t->AddColumnObject (new TextAreaColumn ("" .
+ " ", "Title"));
+$t->AddColumnObject (new TypeColumn ());
+$t->AddColumn ("etext/#fk_books#\">#fk_books# ", "eBook");
+
+/////////////////////////////////////////////////////////////////////////////////
+
+if (!empty ($titlemask)) {
+ form_open ("titles2");
+ $sql = "select * from attributes where text ~ '$titlemask' order by text";
+ $db->exec ($sql);
+ $t->limit = $maxcnt;
+ $t->PrintTable ($db, "Attributes Matching RegExp: $titlemask", "pgdbfiles");
+ form_relay ("titlemask");
+ form_relay ("maxcnt");
+ form_submit ("Update Checked Attribute Entries");
+ form_close ();
+}
+
+pagefooter ();
+
+// Local Variables:
+// mode:php
+// coding:utf-8-unix
+// fill-column: 75
+// End:
+
+?>
diff --git a/catalog/admin/titles.php~ b/catalog/admin/titles.php~
new file mode 100644
index 0000000..37def11
--- /dev/null
+++ b/catalog/admin/titles.php~
@@ -0,0 +1,90 @@
+db ();
+getstr ("titlemask");
+getint ("maxcnt", 25);
+
+pageheader ("Batch-Edit Attributes");
+
+$marcs = array ();
+
+$db->exec ("select * from attriblist order by pk");
+if ($db->FirstRow ()) {
+ do {
+ $marcs[$db->get ("pk", SQLINT)] = $db->get ("name", SQLCHAR);
+ } while ($db->NextRow ());
+}
+
+function mk_options ($name, $options, $option) {
+ $ret = "";
+ foreach ($options as $value => $opt) {
+ $selected = ($value == $option) ? " selected=\"selected\"" : "";
+ $ret .= "$opt \n";
+ }
+ return "\n" . $ret . " \n";
+}
+
+class TypeColumn extends dbtSimpleColumn {
+ function __construct () {
+ parent::__construct (null, "Type", "narrow");
+ }
+ function Data ($db) {
+ global $marcs;
+ return "" . mk_options ("marcs", $marcs, $db->get ("fk_attriblist")) . " ";
+ }
+}
+
+class TextAreaColumn extends dbtSimpleColumn {
+ function __construct ($dbfield, $caption, $class = null) {
+ parent::__construct ($dbfield, $caption, $class);
+ }
+ function Data ($db) {
+ global $config;
+ return "" . preg_replace ("/#(\w+)#/e",
+ "htmlspecialchars (\$db->get('\\1'))", $this->dbfield) . " ";
+ }
+}
+
+
+form_open_get ();
+p ("Enter Perl RegExp :
+ eg. Commedia");
+p ("Max. No.: ");
+form_submit ("Reload");
+form_close ();
+
+$t = new ListTable ();
+$t->AddColumn (" ", "", "narrow");
+$t->AddColumn (" ", "Nonfiling");
+$t->AddColumnObject (new TextAreaColumn ("" .
+ " ", "Title"));
+$t->AddColumnObject (new TypeColumn ());
+$t->AddColumn ("etext/#fk_books#\">#fk_books# ", "eBook");
+
+/////////////////////////////////////////////////////////////////////////////////
+
+if (!empty ($titlemask)) {
+ form_open ("titles2");
+ $sql = "select * from attributes where text ~ '$titlemask' order by text";
+ $db->exec ($sql);
+ $t->limit = $maxcnt;
+ $t->PrintTable ($db, "Attributes Matching RegExp: $titlemask", "pgdbfiles");
+ form_relay ("titlemask");
+ form_relay ("maxcnt");
+ form_submit ("Update Checked Attribute Entries");
+ form_close ();
+}
+
+pagefooter ();
+
+// Local Variables:
+// mode:php
+// coding:utf-8-unix
+// fill-column: 75
+// End:
+
+?>
diff --git a/catalog/admin/titles2.php b/catalog/admin/titles2.php
new file mode 100644
index 0000000..2420046
--- /dev/null
+++ b/catalog/admin/titles2.php
@@ -0,0 +1,55 @@
+db ();
+$db->logger = new logger ();
+
+getstr ("titlemask");
+getint ("maxcnt");
+
+getarray ("pks_update");
+getarray ("pks");
+
+getarray ("titles_a");
+getarray ("nonfilings");
+getarray ("marcs");
+
+foreach ($pks as $pk) {
+ $title = array_shift ($titles_a);
+ $nonfiling = array_shift ($nonfilings);
+ $marc = array_shift ($marcs);
+
+ if (!in_array ($pk, $pks_update))
+ continue;
+
+ $sql_pk = $db->f ($pk, SQLINT);
+ $sql_title = $db->f ($title, SQLCHAR);
+ $sql_nonfiling = $db->f ($nonfiling, SQLINT);
+ $sql_marc = $db->f ($marc, SQLINT);
+
+ $sql = "update attributes set " .
+ "text = $sql_title, " .
+ "nonfiling = $sql_nonfiling, " .
+ "fk_attriblist = $sql_marc " .
+ "where pk = $sql_pk";
+
+ p ($sql);
+
+ if ($db->exec ($sql)) {
+ msg ("Attribute '$title' updated !");
+ } else {
+ error_msg ("Could not update attribute '$title' !");
+ }
+}
+
+p ("Back to Batch-Edit Attributes ");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/titles2.php~ b/catalog/admin/titles2.php~
new file mode 100644
index 0000000..41f2987
--- /dev/null
+++ b/catalog/admin/titles2.php~
@@ -0,0 +1,54 @@
+db ();
+$db->logger = new logger ();
+
+getstr ("titlemask");
+getint ("maxcnt");
+
+getarray ("pks_update");
+getarray ("pks");
+
+getarray ("titles_a");
+getarray ("nonfilings");
+getarray ("marcs");
+
+foreach ($pks as $pk) {
+ $title = array_shift ($titles_a);
+ $nonfiling = array_shift ($nonfilings);
+ $marc = array_shift ($marcs);
+
+ if (!in_array ($pk, $pks_update))
+ continue;
+
+ $sql_pk = $db->f ($pk, SQLINT);
+ $sql_title = $db->f ($title, SQLCHAR);
+ $sql_nonfiling = $db->f ($nonfiling, SQLINT);
+ $sql_marc = $db->f ($marc, SQLINT);
+
+ $sql = "update attributes set " .
+ "text = $sql_title, " .
+ "nonfiling = $sql_nonfiling, " .
+ "fk_attriblist = $sql_marc " .
+ "where pk = $sql_pk";
+
+ p ($sql);
+
+ if ($db->exec ($sql)) {
+ msg ("Attribute '$title' updated !");
+ } else {
+ error_msg ("Could not update attribute '$title' !");
+ }
+}
+
+p ("Back to Batch-Edit Attributes ");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/unzip b/catalog/admin/unzip
new file mode 100755
index 0000000..3791314
Binary files /dev/null and b/catalog/admin/unzip differ
diff --git a/catalog/admin/user.php b/catalog/admin/user.php
new file mode 100644
index 0000000..9c88027
--- /dev/null
+++ b/catalog/admin/user.php
@@ -0,0 +1,76 @@
+db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_users");
+getstr ("filter");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this user.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ $f->Text ("user", "user", "User", SQLCHAR, 80, 240, true);
+ $f->Text ("login", "login", "Login", SQLCHAR, 80, 240, true);
+ $f->TextArea ("note", "note", "Note", SQLCHAR, 4, 80, false);
+
+ $f->LoadData ("select * from users where pk = $fk_users");
+}
+$f->Hidden ("fk_users");
+$f->Hidden ("filter");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into users " . $sql)) {
+ msg ("User added !");
+ } else {
+ error_msg ("Could not add user!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update users set " . $sql . "where pk = $fk_users")) {
+ msg ("User modified !");
+ } else {
+ error_msg ("Could not modify user !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->Exec ("delete from mn_users_permissions where fk_users = $fk_users");
+ if ($db->Exec ("delete from users where pk = $fk_users")) {
+ msg ("User deleted !");
+ } else {
+ error_msg ("Could not delete user !");
+ }
+}
+
+if (isupdate ()) {
+ if (!isupdatemode ("delete")) {
+ p ("Back to User ");
+ }
+} else {
+ $f->Output ($caption, $caption);
+}
+
+p ("Back to User List ");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/user.php~ b/catalog/admin/user.php~
new file mode 100644
index 0000000..aba9376
--- /dev/null
+++ b/catalog/admin/user.php~
@@ -0,0 +1,75 @@
+db ();
+$db->logger = new logger ();
+$f = new SQLForm ();
+getint ("fk_users");
+getstr ("filter");
+
+if (ismode ("delete")) {
+ $f->SubCaption ("You are about to delete this user.");
+ $f->SubCaption ("Press the '$caption' button to continue or " .
+ "hit the back button on your browser to dismiss.");
+} else {
+ $f->Text ("user", "user", "User", SQLCHAR, 80, 240, true);
+ $f->Text ("login", "login", "Login", SQLCHAR, 80, 240, true);
+ $f->TextArea ("note", "note", "Note", SQLCHAR, 4, 80, false);
+
+ $f->LoadData ("select * from users where pk = $fk_users");
+}
+$f->Hidden ("fk_users");
+$f->Hidden ("filter");
+
+if (isupdatemode ("add")) {
+ if ($f->Check ()) {
+ $sql = $f->mkInsert ($db->GetFormatter ());
+ if ($db->Exec ("insert into users " . $sql)) {
+ msg ("User added !");
+ } else {
+ error_msg ("Could not add user!");
+ }
+ }
+}
+if (isupdatemode ("edit")) {
+ if ($f->Check ()) {
+ $sql = $f->mkUpdate ($db->GetFormatter ());
+ if ($db->Exec ("update users set " . $sql . "where pk = $fk_users")) {
+ msg ("User modified !");
+ } else {
+ error_msg ("Could not modify user !");
+ }
+ }
+}
+if (isupdatemode ("delete")) {
+ $db->Exec ("delete from mn_users_permissions where fk_users = $fk_users");
+ if ($db->Exec ("delete from users where pk = $fk_users")) {
+ msg ("User deleted !");
+ } else {
+ error_msg ("Could not delete user !");
+ }
+}
+
+if (isupdate ()) {
+ if (!isupdatemode ("delete")) {
+ p ("Back to User ");
+ }
+} else {
+ $f->Output ($caption, $caption);
+}
+
+p ("Back to User List ");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/users_list.php b/catalog/admin/users_list.php
new file mode 100644
index 0000000..35d0f6f
--- /dev/null
+++ b/catalog/admin/users_list.php
@@ -0,0 +1,48 @@
+AddColumn ("$prefix=edit&fk_users=#pk#\">Edit", "$prefix=add\">Add", "narrow");
+ $this->AddColumn ("$prefix=delete&fk_users=#pk#\">Delete", "", "narrow");
+ $this->AddColumn ("Password ", "", "narrow");
+ $this->AddSimpleColumn ("pk", "Id", "narrow");
+ $this->AddSimpleColumn ("user", "User");
+ $this->AddSimpleColumn ("login", "Login");
+ $this->AddSimpleColumn ("password", "Password");
+ }
+}
+
+$db = $config->db ();
+
+echo ("
+Please enter the first few characters of the user name (at least one).
+Search is case-sensitive.
+Use * as wildcard. (eg. Marcello*)
+To see everything just enter *.
+");
+
+form_open ();
+echo (" \n");
+form_submit ("Search");
+form_close ();
+
+if ($filter != "") {
+ $filt = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from users where user like '$filt%' order by user;");
+ $table = new ListUsersTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/users_list.php~ b/catalog/admin/users_list.php~
new file mode 100644
index 0000000..c07c0a8
--- /dev/null
+++ b/catalog/admin/users_list.php~
@@ -0,0 +1,47 @@
+AddColumn ("$prefix=edit&fk_users=#pk#\">Edit", "$prefix=add\">Add", "narrow");
+ $this->AddColumn ("$prefix=delete&fk_users=#pk#\">Delete", "", "narrow");
+ $this->AddColumn ("Password ", "", "narrow");
+ $this->AddSimpleColumn ("pk", "Id", "narrow");
+ $this->AddSimpleColumn ("user", "User");
+ $this->AddSimpleColumn ("login", "Login");
+ $this->AddSimpleColumn ("password", "Password");
+ }
+}
+
+$db = $config->db ();
+
+echo ("
+Please enter the first few characters of the user name (at least one).
+Search is case-sensitive.
+Use * as wildcard. (eg. Marcello*)
+To see everything just enter *.
+");
+
+form_open ();
+echo (" \n");
+form_submit ("Search");
+form_close ();
+
+if ($filter != "") {
+ $filt = preg_replace ('/\*/', '%', $filter);
+ $db->exec ("select * from users where user like '$filt%' order by user;");
+ $table = new ListUsersTable ();
+ $table->PrintTable ($db, $caption);
+}
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/whois.php b/catalog/admin/whois.php
new file mode 100644
index 0000000..db14724
--- /dev/null
+++ b/catalog/admin/whois.php
@@ -0,0 +1,20 @@
+\n");
+
+echo `whois $ip`;
+
+echo ("\n");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/whois.php~ b/catalog/admin/whois.php~
new file mode 100644
index 0000000..627ee4f
--- /dev/null
+++ b/catalog/admin/whois.php~
@@ -0,0 +1,19 @@
+\n");
+
+echo `whois $ip`;
+
+echo ("\n");
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/zipdir.php b/catalog/admin/zipdir.php
new file mode 100644
index 0000000..ad70f45
--- /dev/null
+++ b/catalog/admin/zipdir.php
@@ -0,0 +1,59 @@
+\n" . shell_exec ("./unzip -lv $file") . "\n\n");
+
+/*
+class ZipdirTable extends ListTable {
+ function __construct () {
+ $this->AddSimpleColumn ("", "Filename");
+ $this->AddSimpleColumn ("", "Original Size");
+ $this->AddSimpleColumn ("", "Compressed Size");
+ $this->AddSimpleColumn ("", "Compression Method");
+ $this->limit = -1;
+ }
+}
+
+$array = array ();
+
+$zip = zip_open ($file);
+
+if ($zip) {
+ while ($zip_entry = zip_read ($zip)) {
+ $array[] = zip_entry_name ($zip_entry);
+ $array[] = zip_entry_filesize ($zip_entry);
+ $array[] = zip_entry_compressedsize ($zip_entry);
+ $array[] = zip_entry_compressionmethod ($zip_entry);
+ }
+ zip_close($zip);
+}
+
+$table = new ZipdirTable ();
+$table->summary = "Contents of zip file.";
+$table->toprows = $array;
+$table->PrintTable (null, "Zip Directory");
+*/
+
+pagefooter ();
+
+?>
diff --git a/catalog/admin/zipdir.php~ b/catalog/admin/zipdir.php~
new file mode 100644
index 0000000..55a3828
--- /dev/null
+++ b/catalog/admin/zipdir.php~
@@ -0,0 +1,58 @@
+\n" . shell_exec ("./unzip -lv $file") . "\n\n");
+
+/*
+class ZipdirTable extends ListTable {
+ function __construct () {
+ $this->AddSimpleColumn ("", "Filename");
+ $this->AddSimpleColumn ("", "Original Size");
+ $this->AddSimpleColumn ("", "Compressed Size");
+ $this->AddSimpleColumn ("", "Compression Method");
+ $this->limit = -1;
+ }
+}
+
+$array = array ();
+
+$zip = zip_open ($file);
+
+if ($zip) {
+ while ($zip_entry = zip_read ($zip)) {
+ $array[] = zip_entry_name ($zip_entry);
+ $array[] = zip_entry_filesize ($zip_entry);
+ $array[] = zip_entry_compressedsize ($zip_entry);
+ $array[] = zip_entry_compressionmethod ($zip_entry);
+ }
+ zip_close($zip);
+}
+
+$table = new ZipdirTable ();
+$table->summary = "Contents of zip file.";
+$table->toprows = $array;
+$table->PrintTable (null, "Zip Directory");
+*/
+
+pagefooter ();
+
+?>
diff --git a/catalog/index.md b/catalog/index.md
new file mode 100644
index 0000000..aaf7ac9
--- /dev/null
+++ b/catalog/index.md
@@ -0,0 +1,12 @@
+---
+layout: default
+title: Online Book Catalog | Project Gutenberg
+permalink: /catalog/index.html
+---
+
+Page not correct
+================
+
+This is the old address for searching.
+
+Please instead use the new location: [book search](/ebooks).
diff --git a/catalog/osd-books.xml b/catalog/osd-books.xml
new file mode 100644
index 0000000..ec6c3fc
--- /dev/null
+++ b/catalog/osd-books.xml
@@ -0,0 +1,36 @@
+
+
+
+ Project Gutenberg
+ Gutenberg
+ Search the Project Gutenberg ebook catalog.
+ free ebooks books public domain
+ Marcello Perathoner
+ webmaster@gutenberg.org
+
+
+
+
+
+
+
+
+
+
+
+
+ Search Data Copyright 1971-2012, Project Gutenberg, All Rights Reserved.
+ open
+ en-us
+ UTF-8
+ UTF-8
+
diff --git a/catalog/test_index.php b/catalog/test_index.php
new file mode 100644
index 0000000..fdcd632
--- /dev/null
+++ b/catalog/test_index.php
@@ -0,0 +1,10 @@
+Testing php
+
+Phpinfo output:
+
+
+Output ends.
+
+
diff --git a/catalog/test_index.php~ b/catalog/test_index.php~
new file mode 100644
index 0000000..87a4b70
--- /dev/null
+++ b/catalog/test_index.php~
@@ -0,0 +1,17 @@
+---
+layout: default
+title: Free eBooks | Project Gutenberg
+permalink: /test_index.html
+---
+
+Testing php
+===========
+
+Phpinfo output:
+
+
+Output ends.
+
+