]> git.mjollnir.org Git - moodle.git/commitdiff
Initial revision
authormartin <martin>
Thu, 22 Nov 2001 06:23:56 +0000 (06:23 +0000)
committermartin <martin>
Thu, 22 Nov 2001 06:23:56 +0000 (06:23 +0000)
175 files changed:
.htaccess [new file with mode: 0644]
README [new file with mode: 0644]
admin/cron.php [new file with mode: 0644]
admin/index.php [new file with mode: 0644]
admin/log.php [new file with mode: 0644]
admin/moodle-core.sql [new file with mode: 0755]
admin/site.html [new file with mode: 0644]
admin/site.php [new file with mode: 0644]
admin/teacher.php [new file with mode: 0644]
admin/user.html [new file with mode: 0644]
admin/user.php [new file with mode: 0644]
config.php [new file with mode: 0644]
course/edit.html [new file with mode: 0644]
course/edit.php [new file with mode: 0644]
course/editweek.html [new file with mode: 0644]
course/editweek.php [new file with mode: 0644]
course/email.html [new file with mode: 0644]
course/email.php [new file with mode: 0644]
course/index.php [new file with mode: 0644]
course/lib.php [new file with mode: 0644]
course/log.php [new file with mode: 0644]
course/login.html [new file with mode: 0644]
course/login.php [new file with mode: 0644]
course/loginas.php [new file with mode: 0644]
course/loglive.php [new file with mode: 0644]
course/mod.php [new file with mode: 0644]
course/mod_delete.html [new file with mode: 0644]
course/new.php [new file with mode: 0644]
course/noweeks.php [new file with mode: 0644]
course/user.php [new file with mode: 0644]
course/view.php [new file with mode: 0644]
course/weeks.php [new file with mode: 0644]
doc/CHANGES [new file with mode: 0644]
doc/COPYRIGHT [new file with mode: 0644]
doc/INSTALL [new file with mode: 0644]
doc/LICENCE [new file with mode: 0644]
doc/NOTES [new file with mode: 0644]
doc/ROADMAP [new file with mode: 0644]
error/index.php [new file with mode: 0644]
file.php [new file with mode: 0644]
files/index.php [new file with mode: 0644]
files/mimetypes.php [new file with mode: 0644]
files/pix/audio.gif [new file with mode: 0755]
files/pix/edit.gif [new file with mode: 0644]
files/pix/env.gif [new file with mode: 0644]
files/pix/excel.gif [new file with mode: 0644]
files/pix/explore.gif [new file with mode: 0644]
files/pix/files.gif [new file with mode: 0755]
files/pix/folder.gif [new file with mode: 0755]
files/pix/help.gif [new file with mode: 0644]
files/pix/html.gif [new file with mode: 0644]
files/pix/image.gif [new file with mode: 0644]
files/pix/move.gif [new file with mode: 0644]
files/pix/parent.gif [new file with mode: 0755]
files/pix/pdf.gif [new file with mode: 0644]
files/pix/text.gif [new file with mode: 0644]
files/pix/unknown.gif [new file with mode: 0644]
files/pix/word.gif [new file with mode: 0644]
files/pix/zip.gif [new file with mode: 0755]
index.php [new file with mode: 0644]
lib/class.phpmailer.php [new file with mode: 0644]
lib/class.smtp.php [new file with mode: 0644]
lib/fonts/arial.ttf [new file with mode: 0755]
lib/fonts/vixar.ttf [new file with mode: 0755]
lib/graphlib.php [new file with mode: 0644]
lib/javascript.php [new file with mode: 0644]
lib/moodlelib.php [new file with mode: 0644]
lib/psxlsgen.php [new file with mode: 0644]
lib/setup.php [new file with mode: 0644]
lib/weblib.php [new file with mode: 0644]
lib/wordlist.txt [new file with mode: 0644]
login/change_password.php [new file with mode: 0644]
login/change_password_form.html [new file with mode: 0644]
login/confirm.php [new file with mode: 0644]
login/countries.php [new file with mode: 0644]
login/forgot_password.php [new file with mode: 0644]
login/forgot_password_change.html [new file with mode: 0644]
login/forgot_password_form.html [new file with mode: 0644]
login/index.php [new file with mode: 0644]
login/index_confirm.html [new file with mode: 0644]
login/index_form.html [new file with mode: 0644]
login/logout.php [new file with mode: 0644]
login/signup.php [new file with mode: 0644]
login/signup_confirm.html [new file with mode: 0644]
login/signup_form.php [new file with mode: 0644]
mod/assignment/README [new file with mode: 0644]
mod/assignment/module.php [new file with mode: 0644]
mod/choice/icon.gif [new file with mode: 0644]
mod/choice/index.php [new file with mode: 0644]
mod/choice/install.sql [new file with mode: 0755]
mod/choice/mod.html [new file with mode: 0644]
mod/choice/mod.php [new file with mode: 0644]
mod/choice/module.php [new file with mode: 0644]
mod/choice/report.php [new file with mode: 0644]
mod/choice/view.html [new file with mode: 0644]
mod/choice/view.php [new file with mode: 0644]
mod/journal/edit.html [new file with mode: 0644]
mod/journal/edit.php [new file with mode: 0644]
mod/journal/icon.gif [new file with mode: 0755]
mod/journal/index.php [new file with mode: 0644]
mod/journal/install.sql [new file with mode: 0755]
mod/journal/lib.php [new file with mode: 0644]
mod/journal/mod.html [new file with mode: 0644]
mod/journal/mod.php [new file with mode: 0644]
mod/journal/module.php [new file with mode: 0644]
mod/journal/new.php [new file with mode: 0644]
mod/journal/report.php [new file with mode: 0644]
mod/journal/user.php [new file with mode: 0644]
mod/journal/view.php [new file with mode: 0644]
mod/survey/details.php [new file with mode: 0644]
mod/survey/download.php [new file with mode: 0644]
mod/survey/edit.php [new file with mode: 0644]
mod/survey/edit_form.html [new file with mode: 0644]
mod/survey/edit_form.phtml [new file with mode: 0644]
mod/survey/edit_new.html [new file with mode: 0644]
mod/survey/edit_new.phtml [new file with mode: 0644]
mod/survey/graph.php [new file with mode: 0644]
mod/survey/icon.gif [new file with mode: 0755]
mod/survey/icon2.gif [new file with mode: 0644]
mod/survey/index.php [new file with mode: 0644]
mod/survey/install.sql [new file with mode: 0755]
mod/survey/lib.php [new file with mode: 0644]
mod/survey/login_form.html [new file with mode: 0644]
mod/survey/mod.html [new file with mode: 0644]
mod/survey/mod.php [new file with mode: 0644]
mod/survey/module.php [new file with mode: 0644]
mod/survey/report.php [new file with mode: 0644]
mod/survey/save.php [new file with mode: 0644]
mod/survey/test.php [new file with mode: 0644]
mod/survey/view.php [new file with mode: 0644]
pix/b.gif [new file with mode: 0755]
pix/i/ICONS-16x16 [new file with mode: 0644]
pix/i/email.gif [new file with mode: 0755]
pix/i/log.gif [new file with mode: 0644]
pix/i/new.gif [new file with mode: 0755]
pix/i/news.gif [new file with mode: 0755]
pix/i/settings.gif [new file with mode: 0755]
pix/madewithmoodle.gif [new file with mode: 0755]
pix/madewithmoodle1.gif [new file with mode: 0755]
pix/madewithmoodle2.gif [new file with mode: 0644]
pix/poo.html [new file with mode: 0644]
pix/s/SMILEYS [new file with mode: 0644]
pix/s/biggrin.gif [new file with mode: 0755]
pix/s/cool.gif [new file with mode: 0755]
pix/s/cross.gif [new file with mode: 0755]
pix/s/mixed.gif [new file with mode: 0755]
pix/s/sad.gif [new file with mode: 0755]
pix/s/smiley.gif [new file with mode: 0755]
pix/s/surprise.gif [new file with mode: 0755]
pix/s/tongueout.gif [new file with mode: 0755]
pix/s/wideeyes.gif [new file with mode: 0755]
pix/s/wink.gif [new file with mode: 0755]
pix/spacer.gif [new file with mode: 0755]
pix/t/TINY-ICONS [new file with mode: 0644]
pix/t/delete.gif [new file with mode: 0644]
pix/t/down.gif [new file with mode: 0644]
pix/t/edit.gif [new file with mode: 0644]
pix/t/search.gif [new file with mode: 0755]
pix/t/up.gif [new file with mode: 0644]
pix/webding.png [new file with mode: 0755]
theme/standard/config.php [new file with mode: 0644]
theme/standard/footer.html [new file with mode: 0644]
theme/standard/header.html [new file with mode: 0644]
theme/standard/styles.css [new file with mode: 0644]
user/default/f1.jpg [new file with mode: 0755]
user/default/f2.jpg [new file with mode: 0755]
user/edit.html [new file with mode: 0644]
user/edit.php [new file with mode: 0644]
user/index.php [new file with mode: 0644]
user/lib.php [new file with mode: 0644]
user/new.php [new file with mode: 0644]
user/pix.php [new file with mode: 0644]
user/user.gif [new file with mode: 0755]
user/users.gif [new file with mode: 0755]
user/view.php [new file with mode: 0644]

diff --git a/.htaccess b/.htaccess
new file mode 100644 (file)
index 0000000..6a8d444
--- /dev/null
+++ b/.htaccess
@@ -0,0 +1 @@
+All the documention is in the "doc" subdirectory.  :-)
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..6a8d444
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+All the documention is in the "doc" subdirectory.  :-)
diff --git a/admin/cron.php b/admin/cron.php
new file mode 100644 (file)
index 0000000..7b2851c
--- /dev/null
@@ -0,0 +1,48 @@
+<?PHP // $Id$
+
+// This script looks through all the module directories for cron.php files
+// and runs them.  These files can contain cleanup functions, email functions
+// or anything that needs to be run on a regular basis.
+//
+// This file is best run from cron on the host system (ie outside PHP).
+// The script can either be invoked via the web server or via a standalone
+// version of PHP compiled for CGI.
+//
+// The script does not require a valid Moodle login, but has it's own unique
+// password, set below.   These are passed to this script as parameters.
+// 
+// eg   wget -q -O /dev/null 'http://moodle.dougiamas.net/admin/cron.php?p=password'
+// or   php /web/moodle/admin/cron.php password
+
+    $PASSWORD = "fr0o6y";
+
+    require("../config.php");
+
+    echo "<PRE>\n";
+
+    if (!isset($p)) {
+        $p = $GLOBALS[argv][1];
+    }
+
+    if ($p <> $PASSWORD) {
+        add_to_log("Error: bad cron password!");
+        echo "Error: bad password.\n";
+        die;
+    }
+
+    $timenow  = time();
+
+    if ($mods = get_records_sql("SELECT * FROM modules WHERE cron > 0 AND (($timenow - lastcron) > cron)")) {
+        foreach ($mods as $mod) {
+            $cronfile = "$CFG->dirroot/mod/$mod->name/cron.php";
+            if (file_exists($cronfile)) {
+                include($cronfile);
+                if (! set_field("modules", "lastcron", $timenow, "id", $mod->id)) {
+                    echo "Error: could not update timestamp for $mod->fullname\n";
+                }
+            }
+        }
+    }
+    echo "Cron script completed correctly\n";
+
+?>
diff --git a/admin/index.php b/admin/index.php
new file mode 100644 (file)
index 0000000..7a9bb9d
--- /dev/null
@@ -0,0 +1,97 @@
+<?PHP // $Id$
+
+    require("../config.php");
+
+
+    if (! $CFG->wwwroot == "http://example.com") {
+        error("Moodle has not been configured yet.  You need to to edit config.php first.");
+    }
+
+    // Check databases and modules and install as needed.
+    if (! $db->Metatables() ) { 
+        print_header("Setting up database", "Setting up database", "Setting up databases for the first time", "");
+        if (modify_database("$CFG->dirroot/admin/moodle-core.sql")) {
+            notify("Main databases set up successfully");
+        } else {
+            error("Error: Main databases NOT set up successfully");
+        }
+        print_heading("<A HREF=\"index.php\">Continue</A>");
+        die;
+    }
+
+    // Find and check all modules and load them up.
+    $dir = opendir("$CFG->dirroot/mod");
+    while ($mod = readdir($dir)) {
+        if ($mod == "." || $mod == "..") {
+            continue;
+        }
+
+        $fullmod = "$CFG->dirroot/mod/$mod";
+        if (filetype($fullmod) != "dir") {
+            continue;
+        }
+
+        unset($module);
+
+        include_once("$CFG->dirroot/mod/$mod/module.php");  # defines $module
+
+        if (!isset($module)) {
+            continue;
+        }
+
+        $module->name = $mod;   // The name MUST match the directory
+        
+        if ($currmodule = get_record("modules", "name", $module->name)) {
+            if ($currmodule->version == $module->version) {
+                // do nothing
+            } else if ($currmodule->version < $module->version) {
+                notify("$module->name module needs upgrading");  // XXX do the upgrade here
+            } else {
+                error("Version mismatch: $module->name can't downgrade $currmodule->version -> $module->version !");
+            }
+    
+        } else {    // module not installed yet, so install it
+            if (modify_database("$fullmod/install.sql")) {
+                if ($module->id = insert_record("modules", $module)) {
+                    notify("$module->name tables have been set up correctly");
+                } else {
+                    error("$module->name module could not be added to the module list!");
+                }
+            } else {
+                error("$module->name tables could NOT be set up successfully!");
+            }
+        }
+    }
+
+    // Set up the overall site name etc.
+    if (! $course = get_record("course", "category", 0)) {
+        redirect("site.php");
+    }
+
+    if (!isadmin()) {
+        if (record_exists_sql("SELECT * FROM user_admins")) {
+            require_login();
+        } else {
+            redirect("user.php");
+        }
+    }
+
+
+    // At this point, the databases exist, and the user is an admin
+
+    print_header("$course->fullname: Administration Page","$course->fullname: Administration Page", "Admin");
+
+    echo "<UL>";
+    echo "<LI><B><A HREF=\"site.php\">Site settings</A></B>";
+    echo "<LI><B><A HREF=\"../course/edit.php\">Create a new course</A></B>";
+    echo "<LI><B><A HREF=\"user.php\">Edit a user's account</A></B>";
+    echo "<LI><B>Assign teachers to courses</B>";
+    echo "<LI><B>Delete a course</B>";
+    echo "<LI><B>View Logs</B>";
+    echo "</UL>";
+
+
+    print_footer();
+?>
+
+
diff --git a/admin/log.php b/admin/log.php
new file mode 100644 (file)
index 0000000..539881f
--- /dev/null
@@ -0,0 +1,22 @@
+<?PHP // $Id$
+
+    $logs = $db->Execute("SELECT l.*, u.firstname, u.lastname, u.email FROM log l, user u WHERE l.user = u.id ORDER BY l.time ASC");
+
+    echo "<TABLE>"
+    while (! $logs->EOF) {
+        $log = (object)$logs->fields;
+
+        echo "<TR>";
+        echo "<TD>".date("l, j F Y, g:i A T", $log->time);
+        echo "<TD><A HREF=\"mailto:$log->email\">$log->firstname $log->lastname</A>";
+        echo "<TD>$log->ip";
+        echo "<TD>$log->url";
+        echo "<TD>$log->message";
+        echo "</TR>";
+
+        $logs->MoveNext();
+    }
+
+    echo "</TABLE>";
+
+?>
diff --git a/admin/moodle-core.sql b/admin/moodle-core.sql
new file mode 100755 (executable)
index 0000000..8ba2123
--- /dev/null
@@ -0,0 +1,189 @@
+# phpMyAdmin MySQL-Dump\r
+# version 2.2.1\r
+# http://phpwizard.net/phpMyAdmin/\r
+# http://phpmyadmin.sourceforge.net/ (download page)\r
+#\r
+# Host: localhost\r
+# Generation Time: Nov 14, 2001 at 05:04 PM\r
+# Server version: 3.23.36\r
+# PHP Version: 4.0.6\r
+# Database : `moodle`\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `course`\r
+#\r
+\r
+CREATE TABLE course (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  category int(10) unsigned NOT NULL default '0',\r
+  password varchar(50) NOT NULL default '',\r
+  fullname varchar(254) NOT NULL default '',\r
+  shortname varchar(15) NOT NULL default '',\r
+  summary text NOT NULL,\r
+  format tinyint(4) NOT NULL default '1',\r
+  teacher varchar(100) NOT NULL default 'Teacher',\r
+  startdate int(10) unsigned NOT NULL default '0',\r
+  enddate int(10) unsigned NOT NULL default '0',\r
+  timemodified int(10) unsigned NOT NULL default '0',\r
+  PRIMARY KEY  (id)\r
+) TYPE=MyISAM;\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `course_categories`\r
+#\r
+\r
+CREATE TABLE course_categories (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  name varchar(255) NOT NULL default '',\r
+  PRIMARY KEY  (id),\r
+  UNIQUE KEY id (id)\r
+) TYPE=MyISAM COMMENT='Course categories';\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `course_modules`\r
+#\r
+\r
+CREATE TABLE course_modules (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  course int(10) unsigned NOT NULL default '0',\r
+  module int(10) unsigned NOT NULL default '0',\r
+  instance int(10) unsigned NOT NULL default '0',\r
+  week int(10) unsigned NOT NULL default '0',\r
+  added int(10) unsigned NOT NULL default '0',\r
+  deleted tinyint(1) unsigned NOT NULL default '0',\r
+  score tinyint(4) NOT NULL default '0',\r
+  PRIMARY KEY  (id),\r
+  UNIQUE KEY id (id)\r
+) TYPE=MyISAM;\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `course_weeks`\r
+#\r
+\r
+CREATE TABLE course_weeks (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  course int(10) unsigned NOT NULL default '0',\r
+  week int(10) unsigned NOT NULL default '0',\r
+  summary varchar(255) NOT NULL default '',\r
+  sequence varchar(255) NOT NULL default '',\r
+  PRIMARY KEY  (id)\r
+) TYPE=MyISAM;\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `logs`\r
+#\r
+\r
+CREATE TABLE logs (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  time int(10) unsigned NOT NULL default '0',\r
+  user int(10) unsigned NOT NULL default '0',\r
+  course int(10) unsigned NOT NULL default '0',\r
+  ip varchar(15) NOT NULL default '',\r
+  url varchar(200) NOT NULL default '',\r
+  message varchar(255) NOT NULL default '',\r
+  PRIMARY KEY  (id)\r
+) TYPE=MyISAM;\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `modules`\r
+#\r
+\r
+CREATE TABLE modules (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  name varchar(20) NOT NULL default '',\r
+  fullname varchar(255) NOT NULL default '',\r
+  version int(10) NOT NULL default '0',\r
+  cron int(10) unsigned NOT NULL default '0',\r
+  lastcron int(10) unsigned NOT NULL default '0',\r
+  search varchar(255) NOT NULL default '',\r
+  PRIMARY KEY  (id),\r
+  UNIQUE KEY id (id)\r
+) TYPE=MyISAM;\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `user`\r
+#\r
+\r
+CREATE TABLE user (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  confirmed tinyint(1) NOT NULL default '0',\r
+  username varchar(100) NOT NULL default '',\r
+  password varchar(32) NOT NULL default '',\r
+  idnumber varchar(12) default NULL,\r
+  firstname varchar(20) NOT NULL default '',\r
+  lastname varchar(20) NOT NULL default '',\r
+  email varchar(100) NOT NULL default '',\r
+  icq varchar(15) default NULL,\r
+  phone1 varchar(20) default NULL,\r
+  phone2 varchar(20) default NULL,\r
+  institution varchar(40) default NULL,\r
+  department varchar(30) default NULL,\r
+  address varchar(70) default NULL,\r
+  city varchar(20) default NULL,\r
+  country char(2) default NULL,\r
+  firstaccess int(10) unsigned NOT NULL default '0',\r
+  lastaccess int(10) unsigned NOT NULL default '0',\r
+  lastlogin int(10) unsigned NOT NULL default '0',\r
+  currentlogin int(10) unsigned NOT NULL default '0',\r
+  lastIP varchar(15) default NULL,\r
+  personality varchar(5) default NULL,\r
+  picture tinyint(1) default NULL,\r
+  url varchar(255) default NULL,\r
+  description text,\r
+  research tinyint(1) unsigned NOT NULL default '0',\r
+  forwardmail tinyint(1) unsigned NOT NULL default '0',\r
+  timemodified int(10) unsigned NOT NULL default '0',\r
+  PRIMARY KEY  (id),\r
+  UNIQUE KEY username (username),\r
+  UNIQUE KEY id (id)\r
+) TYPE=MyISAM COMMENT='One record for each person';\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `user_admins`\r
+#\r
+\r
+CREATE TABLE user_admins (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  user int(10) unsigned NOT NULL default '0',\r
+  PRIMARY KEY  (id),\r
+  UNIQUE KEY id (id)\r
+) TYPE=MyISAM COMMENT='One record per administrator user';\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `user_students`\r
+#\r
+\r
+CREATE TABLE user_students (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  user int(10) unsigned NOT NULL default '0',\r
+  course int(10) unsigned NOT NULL default '0',\r
+  start int(10) unsigned NOT NULL default '0',\r
+  end int(10) unsigned NOT NULL default '0',\r
+  time int(10) unsigned NOT NULL default '0',\r
+  PRIMARY KEY  (id),\r
+  UNIQUE KEY id (id)\r
+) TYPE=MyISAM;\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `user_teachers`\r
+#\r
+\r
+CREATE TABLE user_teachers (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  user int(10) unsigned NOT NULL default '0',\r
+  course int(10) unsigned NOT NULL default '0',\r
+  authority varchar(10) default NULL,\r
+  PRIMARY KEY  (id),\r
+  UNIQUE KEY id (id)\r
+) TYPE=MyISAM COMMENT='One record per teacher per course';\r
+\r
diff --git a/admin/site.html b/admin/site.html
new file mode 100644 (file)
index 0000000..9bb796f
--- /dev/null
@@ -0,0 +1,28 @@
+<FORM METHOD="post" action="site.php" NAME="form">
+<TABLE cellpadding=9 cellspacing=0 >
+<tr valign=top>
+       <td><P>Full site name:</td>
+       <td><input type="text" name="fullname" size=50 value="<? p($form->fullname) ?>">
+       <? formerr($err["fullname"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Short name for site (eg single word):</td>
+       <td><input type="text" name="shortname" size=50 value="<? p($form->shortname) ?>">
+       <? formerr($err["shortname"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+    <td><P>Front page description:</td>
+    <td><TEXTAREA NAME=summary COLS=50 ROWS=10 WRAP=virtual><? p($form->summary) ?></TEXTAREA>
+    <? formerr($err["summary"]) ?>
+    </td>
+</tr>
+<tr>
+    <td></td>
+       <td><input type="submit" value="Update the site"></td>
+</tr>
+</TABLE>
+<INPUT type="hidden" name="id" value="<?=$form->id ?>">
+<INPUT type="hidden" name="category" value="<?=$form->category ?>">
+</FORM>
diff --git a/admin/site.php b/admin/site.php
new file mode 100644 (file)
index 0000000..0ef80da
--- /dev/null
@@ -0,0 +1,84 @@
+<?PHP // $Id$
+
+       require("../config.php");
+
+    $course = get_record("course", "category", 0);
+
+/// If data submitted, then process and store.
+
+       if (match_referer() && isset($HTTP_POST_VARS)) {
+
+        $form = (object)$HTTP_POST_VARS;
+
+        validate_form($form, $err);
+
+        if (count($err) == 0) {
+
+            $form->timemodified = time();
+
+            if ($form->id) {
+                if (update_record("course", $form)) {
+                    add_to_log("Updated site settings", $course->id);
+                           redirect("$CFG->wwwroot/admin/", "Changes saved");
+                } else {
+                    error("Serious Error! Could not update the course record! (id = $form->id)");
+                }
+            } else {
+                if ($newid = insert_record("course", $form)) {
+                    $cat->name = "General";
+                    if (insert_record("course_categories", $cat)) {
+                        add_to_log("Inserted a new course # $newid", $newid);
+                               redirect("$CFG->wwwroot/admin/", "Changes saved", "1");
+                    } else {
+                        error("Serious Error! Could not set up the default categories!");
+                    }
+                } else {
+                    error("Serious Error! Could not set up the site!");
+                }
+            }
+                   die;
+        } else {
+            foreach ($err as $key => $value) {
+                $focus = "form.$key";
+            }
+            
+        }
+       }
+
+/// Otherwise fill and print the form.
+
+    if ($course && !$form) {
+        $form = $course;
+    } else {
+        $form->category = 0;
+    }
+
+    print_header("Admin: Setting up site", "Administration: Setting up site",
+                  "<A HREF=\"$CFG->wwwroot/admin/\">Admin</A> -> Setting up site", "$focus");
+
+    print_simple_box_start("center", "", "$THEME->cellheading");
+    print_heading("Editing site settings");
+       include("site.html");
+    print_simple_box_end();
+    print_footer();
+
+    exit;
+
+/// Functions /////////////////////////////////////////////////////////////////
+
+function validate_form(&$form, &$err) {
+
+    if (empty($form->fullname))
+        $err["fullname"] = "Missing site name";
+
+    if (empty($form->shortname))
+        $err["shortname"] = "Missing short site name";
+
+    if (empty($form->summary))
+        $err["summary"] = "Missing site description";
+
+    return;
+}
+
+
+?>
diff --git a/admin/teacher.php b/admin/teacher.php
new file mode 100644 (file)
index 0000000..4aec93f
--- /dev/null
@@ -0,0 +1,108 @@
+<?PHP // $Id$
+
+       require("../config.php");
+       require("../user/lib.php");
+
+    optional_variable($id);       // course id
+
+    if (! $site = get_site()) {
+        redirect("$CFG->wwwroot/admin/");
+    }
+
+    require_login();
+
+    if (!isadmin()) {
+        error("You must be an administrator to edit users this way.");
+    }
+
+    if (!$id) {
+        $courses = get_records_sql("SELECT * from course WHERE category > 0 ORDER BY fullname");
+
+           print_header("Add teachers to a course", "Add teachers to a course", "<A HREF=\"$CFG->wwwroot/admin\">Admin</A> -> Add teachers", "");
+        print_heading("Choose a course to add teachers to");
+        print_simple_box_start("CENTER");
+        foreach ($courses as $course) {
+            echo "<A HREF=\"teacher.php?id=$course->id\">$course->fullname</A><BR>";
+        }
+        print_simple_box_end();
+        print_footer();
+        exit;
+    }
+
+    if (! $course = get_record("course", "id", $id)) {
+        error("Course ID was incorrect (can't find it)");
+    }
+
+
+/// If data submitted, then process and store.
+
+       if (match_referer() && isset($HTTP_POST_VARS)) {
+
+        $usernew = (object)$HTTP_POST_VARS;
+
+        if (find_form_errors($user, $usernew, $err) ) {
+            $user = $usernew;
+
+        } else {
+
+            $usernew->timemodified = time();
+
+            if (update_record("user", $usernew)) {
+                       redirect("index.php", "Changes saved");
+            } else {
+                error("Could not update the user record ($user->id)");
+            }
+           }
+    }
+    
+/// Otherwise fill and print the form.
+
+    XXXXXXX
+
+       print_header("Edit user profile", "Edit user profile", "<A HREF=\"$CFG->wwwroot/admin\">Admin</A> -> Edit user", "");
+
+    print_simple_box_start("center", "", "$THEME->cellheading");
+    echo "<H2>User profile for $usernew->firstname $usernew->lastname</H2>";
+       include("user.html");
+    print_simple_box_end();
+
+    print_footer();
+
+
+
+
+/// FUNCTIONS ////////////////////
+
+function find_form_errors(&$user, &$usernew, &$err) {
+
+    if (empty($usernew->email))
+        $err["email"] = "Missing email address";
+
+    else if (! validate_email($usernew->email))
+        $err["email"] = "Invalid email address, check carefully";
+
+    else if ($otheruser = get_record("user", "email", $usernew->email)) {
+        if ($otheruser->id <> $user->id) {
+            $err["email"] = "Email address already in use by someone else.";
+        }
+    }
+    $user->email = $usernew->email;
+
+    if (empty($user->password) && empty($usernew->password)) {
+        $err["password"] = "Must have a password";
+    }
+
+    if (empty($usernew->username))
+        $err["username"] = "Must have a username";
+
+    if (empty($usernew->firstname))
+        $err["firstname"] = "Must enter your first name";
+
+    if (empty($usernew->lastname))
+        $err["lastname"] = "Must enter your last name";
+
+    return count($err);
+}
+
+
+?>
diff --git a/admin/user.html b/admin/user.html
new file mode 100644 (file)
index 0000000..deba34a
--- /dev/null
@@ -0,0 +1,82 @@
+<FORM METHOD="post" ENCTYPE="multipart/form-data" action="user.php">
+<table cellpadding=9 cellspacing=0 >
+<tr valign=top>
+       <td><P>First name:</td>
+       <td><input type="text" name="firstname" size=25 value="<?=$usernew->firstname ?>">
+       <? formerr($err["firstname"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Last name:</td>
+       <td><input type="text" name="lastname" size=25 value="<?=$usernew->lastname ?>">
+       <? formerr($err["lastname"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Username:</td>
+       <td><input type="text" name="username" size=25 value="<?=$usernew->username ?>">
+       <? formerr($err["username"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>New Password:</td>
+       <td><input type="text" name="password" size=25 value="<?=$usernew->password ?>">
+       <? formerr($err["password"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Email:</td>
+       <td><input type="text" name="email" size=25 value="<?=$usernew->email ?>">
+       <? formerr($err["email"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>ICQ Number:</td>
+       <td><input type="text" name="icq" size=25 value="<?=$usernew->icq ?>">
+       <? formerr($err["icq"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Phone Number 1:</td>
+       <td><input type="text" name="phone1" size=25 value="<?=$usernew->phone1 ?>">
+       <? formerr($err["phone1"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Phone Number 2:</td>
+       <td><input type="text" name="phone2" size=25 value="<?=$usernew->phone2 ?>">
+       <? formerr($err["phone2"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Address:</td>
+       <td><input type="text" name="address" size=25 value="<?=$usernew->address ?>">
+       <? formerr($err["address"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Web Address:</td>
+       <td><input type="text" name="url" size=25 value="<?=$usernew->url ?>">
+       <? formerr($err["url"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Description:</td>
+       <td><TEXTAREA NAME=description COLS=50 ROWS=10 WRAP=virtual><?=$usernew->description ?></TEXTAREA>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>New picture:</td>
+       <td>
+    <INPUT type="hidden" name="MAX_FILE_SIZE" value="4000000">
+    <input type="file" name="imagefile">
+    ( .jpg or .png )
+       <? formerr($err["firstname"]) ?>
+       </td>
+</tr>
+<tr>
+       <td></td>
+       <td><input type="submit" value="Update this user"></td>
+</TABLE>
+<INPUT type="hidden" name="id" value="<?=$usernew->id ?>">
+</FORM>
diff --git a/admin/user.php b/admin/user.php
new file mode 100644 (file)
index 0000000..4132173
--- /dev/null
@@ -0,0 +1,211 @@
+<?PHP // $Id$
+
+       require("../config.php");
+       require("../user/lib.php");
+
+    optional_variable($id);       // user id
+
+    if (! record_exists_sql("SELECT * FROM user_admins")) {
+        $user->firstname = "Admin";
+        $user->lastname  = "User";
+        $user->username  = "admin";
+        $user->password  = "";
+        $user->email     = "root@localhost";
+        $user->confirmed = 1;
+        $user->timemodified = time();
+
+        if (! $id = insert_record("user", $user)) {
+            error("Could not create admin user record !!!");
+        }
+
+        $admin->user = $id;
+
+        if (! insert_record("user_admins", $admin)) {
+            error("Could not make user $id an admin !!!");
+        }
+
+        if (! $user = get_record("user", "id", $id)) {
+            error("User ID was incorrect (can't find it)");
+        }
+
+        if (! $course = get_record("course", "category", 0)) {
+            error("Could not find site-level course");
+        }
+
+        $teacher->user = $user->id;
+        $teacher->course = $course->id;
+        $teacher->authority = 1;
+        if (! insert_record("user_teachers", $teacher)) {
+            error("Could not make user $id a teacher of site-level course !!!");
+        }
+
+        $USER = $user;
+        $USER->loggedin = true;
+        $USER->admin = true;
+        $USER->teacher["$course->id"] = true;
+    }
+
+    require_login();
+
+    if (!isadmin()) {
+        error("You must be an administrator to edit users this way.");
+    }
+
+    if (!$id) {
+        $users = get_records_sql("SELECT * from user ORDER BY firstname");
+
+           print_header("Edit users", "Edit users", "<A HREF=\"$CFG->wwwroot/admin\">Admin</A> -> Edit users", "");
+        echo "<CENTER>";
+        foreach ($users as $user) {
+            echo "<A HREF=\"user.php?id=$user->id\">$user->firstname $user->lastname</A><BR>";
+        }
+        echo "</CENTER>";
+        print_footer();
+        exit;
+    }
+
+    if (! $user = get_record("user", "id", $id)) {
+        error("User ID was incorrect (can't find it)");
+    }
+
+
+/// If data submitted, then process and store.
+
+       if (match_referer() && isset($HTTP_POST_VARS)) {
+
+        $usernew = (object)$HTTP_POST_VARS;
+
+        if (find_form_errors($user, $usernew, $err) ) {
+            $user = $usernew;
+
+        } else {
+
+                   $timenow = time();
+
+            if ($imagefile && $imagefile!="none") { 
+                $imageinfo = GetImageSize($imagefile);
+                $image->width  = $imageinfo[0];
+                $image->height = $imageinfo[1];
+                $image->type   = $imageinfo[2];
+    
+                switch ($image->type) {
+                    case 2: $im = ImageCreateFromJPEG($imagefile); break;
+                    case 3: $im = ImageCreateFromPNG($imagefile); break;
+                    default: error("Image must be in JPG or PNG format");
+                }
+                if (function_exists("ImageCreateTrueColor")) {
+                    $im1 = ImageCreateTrueColor(100,100);
+                    $im2 = ImageCreateTrueColor(35,35);
+                } else {
+                    $im1 = ImageCreate(100,100);
+                    $im2 = ImageCreate(35,35);
+                }
+                
+                $cx = $image->width / 2;
+                $cy = $image->height / 2;
+    
+                if ($image->width < $image->height) {
+                    $half = floor($image->width / 2.0);
+                } else {
+                    $half = floor($image->height / 2.0);
+                }
+    
+                if (!file_exists("$CFG->dataroot/users")) {
+                    mkdir("$CFG->dataroot/users", 0777);
+                }
+                if (!file_exists("$CFG->dataroot/users/$USER->id")) {
+                    mkdir("$CFG->dataroot/users/$USER->id", 0777);
+                }
+                
+                ImageCopyBicubic($im1, $im, 0, 0, $cx-$half, $cy-$half, 100, 100, $half*2, $half*2);
+                ImageCopyBicubic($im2, $im, 0, 0, $cx-$half, $cy-$half, 35, 35, $half*2, $half*2);
+    
+                // Draw borders over the top.
+                $black1 = ImageColorAllocate ($im1, 0, 0, 0);
+                $black2 = ImageColorAllocate ($im2, 0, 0, 0);
+                ImageLine ($im1, 0, 0, 0, 99, $black1);
+                ImageLine ($im1, 0, 99, 99, 99, $black1);
+                ImageLine ($im1, 99, 99, 99, 0, $black1);
+                ImageLine ($im1, 99, 0, 0, 0, $black1);
+                ImageLine ($im2, 0, 0, 0, 34, $black2);
+                ImageLine ($im2, 0, 34, 34, 34, $black2);
+                ImageLine ($im2, 34, 34, 34, 0, $black2);
+                ImageLine ($im2, 34, 0, 0, 0, $black2);
+            
+                ImageJpeg($im1, "$CFG->dataroot/users/$USER->id/f1.jpg", 90);
+                ImageJpeg($im2, "$CFG->dataroot/users/$USER->id/f2.jpg", 95);
+                $usernew->picture = "1";
+            } else {
+                $usernew->picture = $user->picture;
+            }
+    
+            if ($usernew->password) {
+                $usernew->password = md5($usernew->password);
+            } else {
+                unset($usernew->password);
+            }
+
+            $usernew->timemodified = time();
+
+            if (update_record("user", $usernew)) {
+                       redirect("index.php", "Changes saved");
+            } else {
+                error("Could not update the user record ($user->id)");
+            }
+           }
+    }
+    
+/// Otherwise fill and print the form.
+
+    if (!$usernew) {
+        $usernew = $user;
+        $usernew->password = "";
+    }
+
+       print_header("Edit user profile", "Edit user profile", "<A HREF=\"$CFG->wwwroot/admin\">Admin</A> -> Edit user", "");
+
+    print_simple_box_start("center", "", "$THEME->cellheading");
+    echo "<H2>User profile for $usernew->firstname $usernew->lastname</H2>";
+       include("user.html");
+    print_simple_box_end();
+
+    print_footer();
+
+
+
+
+/// FUNCTIONS ////////////////////
+
+function find_form_errors(&$user, &$usernew, &$err) {
+
+    if (empty($usernew->email))
+        $err["email"] = "Missing email address";
+
+    else if (! validate_email($usernew->email))
+        $err["email"] = "Invalid email address, check carefully";
+
+    else if ($otheruser = get_record("user", "email", $usernew->email)) {
+        if ($otheruser->id <> $user->id) {
+            $err["email"] = "Email address already in use by someone else.";
+        }
+    }
+    $user->email = $usernew->email;
+
+    if (empty($user->password) && empty($usernew->password)) {
+        $err["password"] = "Must have a password";
+    }
+
+    if (empty($usernew->username))
+        $err["username"] = "Must have a username";
+
+    if (empty($usernew->firstname))
+        $err["firstname"] = "Must enter your first name";
+
+    if (empty($usernew->lastname))
+        $err["lastname"] = "Must enter your last name";
+
+    return count($err);
+}
+
+
+?>
diff --git a/config.php b/config.php
new file mode 100644 (file)
index 0000000..e9dfee8
--- /dev/null
@@ -0,0 +1,46 @@
+<?PHP // $Id$
+///////////////////////////////////////////////////////////////////////////
+//
+// Moodle configuration file
+//
+///////////////////////////////////////////////////////////////////////////
+
+// Site configuration variables are all stored in the CFG object.
+
+// First, we need to configure the database where all Moodle data 
+// will be stored.  This database must already have been created
+// and a username/password created to access it.   See INSTALL doc.
+
+$CFG->dbtype    = "mysql";       // eg mysql, postgres, oracle, access etc 
+$CFG->dbhost    = "localhost";   // eg localhost 
+$CFG->dbname    = "moodle";      // eg moodle
+$CFG->dbuser    = "moodle";
+$CFG->dbpass    = "moodle";
+
+
+// Next you need to tell Moodle where it is, and where it can save files.
+
+$CFG->wwwroot   = "http://server.dougiamas.net/moodle";
+$CFG->dirroot   = "/web/server/moodle";
+$CFG->dataroot  = "/web/moodledata";    // Web-server writeable
+
+
+// Choose a theme from the "themes" folder.  Default theme is "standard".
+
+$CFG->theme     = "standard";
+
+
+// Give the full name (eg mail.example.com) of an SMTP server that the 
+// web server machine has access to (to send mail).  Default: "localhost".
+
+$CFG->smtphost  = "dougiamas.com";
+
+
+// You should not need to change anything below this line
+///////////////////////////////////////////////////////////////////////////
+
+$CFG->libdir    = "$CFG->dirroot/lib";
+
+require("$CFG->libdir/setup.php");  // Sets up all libraries, sessions etc
+
+?>
diff --git a/course/edit.html b/course/edit.html
new file mode 100644 (file)
index 0000000..d6c4782
--- /dev/null
@@ -0,0 +1,72 @@
+<FORM METHOD="post" action="edit.php" NAME="form">
+<table cellpadding=9 cellspacing=0 >
+<tr valign=top>
+       <td><P>Full name:</td>
+       <td><input type="text" name="fullname" size=50 value="<? p($form->fullname) ?>">
+       <? formerr($err["fullname"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Short name:</td>
+       <td><input type="text" name="shortname" size=10 value="<? p($form->shortname) ?>">
+       <? formerr($err["shortname"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Password:</td>
+       <td><input type="text" name="password" size=25 value="<? p($form->password) ?>">
+       <? formerr($err["password"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Summary:</td>
+       <td><TEXTAREA NAME=summary COLS=50 ROWS=10 WRAP=virtual><? p($form->summary) ?></TEXTAREA>
+       <? formerr($err["summary"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Category:</td>
+       <td><? 
+           choose_from_menu ($form->categories, "category", "$form->category");
+              formerr($err["category"]);
+        ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Format:</td>
+       <td><? 
+           choose_from_menu ($FORMATS, "format", "$form->format");
+              formerr($err["format"]);
+        ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Word used to refer<BR>to your role:</td>
+       <td><input type="text" name="teacher" size=25 value="<? p($form->teacher) ?>">
+       <? formerr($err["teacher"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Start date:</td>
+       <td><?
+           choose_from_menu ($form->days, "startday", "$form->startday");
+           choose_from_menu ($form->months, "startmonth", "$form->startmonth");
+           choose_from_menu ($form->years, "startyear", "$form->startyear");
+              formerr($err["startdate"]);
+       ?></td>
+</tr>
+<tr valign=top>
+       <td><P>End date:</td>
+       <td><?
+           choose_from_menu ($form->days, "endday", "$form->endday");
+           choose_from_menu ($form->months, "endmonth", "$form->endmonth");
+           choose_from_menu ($form->years, "endyear", "$form->endyear");
+              formerr($err["enddate"]);
+       ?></td>
+</tr>
+<tr>
+       <td></td>
+       <td><input type="submit" value="Update this course"></td>
+</TABLE>
+<INPUT type="hidden" name="id" value="<?=$course->id ?>">
+</FORM>
diff --git a/course/edit.php b/course/edit.php
new file mode 100644 (file)
index 0000000..3f4977f
--- /dev/null
@@ -0,0 +1,168 @@
+<?PHP // $Id$
+
+       require("../config.php");
+       require("lib.php");
+
+    optional_variable($id, 0);   // course id
+
+    if ($id) {
+        if (! $course = get_record("course", "id", $id)) {
+            error("Course ID was incorrect");
+        }
+
+           require_login($course->id);
+
+        if (!isteacher($course->id)) {
+            error("Only teachers can edit the course!");
+        }
+    } else {  // Admin is creating a new course
+        require_login();
+
+        if (!isadmin()) {
+            error("Only administrators can use this page");
+        }
+    }
+
+
+/// If data submitted, then process and store.
+
+       if (match_referer() && isset($HTTP_POST_VARS)) {
+
+        $form = (object)$HTTP_POST_VARS;
+
+        $form->startdate = mktime(0,0,0,(int)$form->startmonth,(int)$form->startday,(int)$form->startyear);
+        $form->enddate   = mktime(0,0,0,(int)$form->endmonth,(int)$form->endday,(int)$form->endyear);
+
+        validate_form($course, $form, $err);
+
+
+        if (count($err) == 0) {
+
+            $form->timemodified = time();
+
+            if ($course) {
+                if (update_record("course", $form)) {
+                    add_to_log("Updated course settings", $course->id);
+                           redirect("view.php?id=$course->id", "Changes saved");
+                } else {
+                    error("Serious Error! Could not update the course record! (id = $form->id)");
+                }
+            } else {
+                if ($newid = insert_record("course", $form)) {  // Set up new course
+                    $week->course = $newid;   // Create a default week.
+                    $week->week = 0;
+                    $week->timemodified = time();
+                    $week->id = insert_record("course_weeks", $week);
+
+                    add_to_log("Inserted a new course # $newid", $newid);
+                           redirect("$CFG->wwwroot/admin/teacher.php?id=$newid", "Changes saved");
+                } else {
+                    error("Serious Error! Could not create the new course!");
+                }
+            }
+                   die;
+        } else {
+            foreach ($err as $key => $value) {
+                $focus = "form.$key";
+            }
+            
+        }
+       }
+
+/// Otherwise fill and print the form.
+
+    if (!$form) {
+        if ($course) {
+            $form = $course;
+            $ts = getdate($course->startdate);
+            $te = getdate($course->enddate);
+        } else {
+            $ts = getdate(time() + 3600 * 24);
+            $te = getdate(time() + 3600 * 24 * 7 * 16);
+        }
+
+        $form->startday = $ts[mday];
+        $form->startmonth = $ts[mon];
+        $form->startyear = $ts[year];
+
+        $form->endday = $te[mday];
+        $form->endmonth = $te[mon];
+        $form->endyear = $te[year];
+
+        if (!$course) {
+            $form->teacher = "Facilitator";
+            $form->fullname = "Course Fullname 101";
+            $form->shortname = "CF101";
+            $form->summary = "Write a concise and interesting paragraph here that explains what this course is about.";
+            $form->format = 0;
+            $form->category = 1;
+        }
+    }
+
+    for ($i=1;$i<=31;$i++) {
+        $form->days[$i] = "$i";
+    }
+    for ($i=1;$i<=12;$i++) {
+        $form->months[$i] = date("F", mktime(0,0,0,$i,1,2000));
+    }
+    for ($i=2000;$i<=2005;$i++) {
+        $form->years[$i] = $i;
+    }
+
+    $form->categories = get_records_sql_menu("SELECT id,name FROM course_categories");
+
+    //$form->owners   = get_records_sql_menu("SELECT u.id, CONCAT(u.firstname, " ", u.lastname) FROM users u, teachers t WHERE t.user = u.id");
+
+    if (isadmin()) {
+        print_header("Admin: Creating a new course", "$CFG->sitename: Administration",
+                     "<A HREF=\"$CFG->wwwroot/admin/\">Admin</A> 
+                      -> Create a new course", $focus);
+
+    } else {
+           print_header("Edit course settings", "$course->fullname", 
+                     "<A HREF=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</A> 
+                      -> Edit course settings", $focus);
+    }
+
+    print_simple_box_start("center", "", "$THEME->cellheading");
+    print_heading("Editing course settings");
+       include("edit.html");
+    print_simple_box_end();
+
+    print_footer($course);
+
+    exit;
+
+/// Functions /////////////////////////////////////////////////////////////////
+
+function validate_form($course, &$form, &$err) {
+
+    if (empty($form->fullname))
+        $err["fullname"] = "Missing full name";
+
+    if (empty($form->shortname))
+        $err["shortname"] = "Missing short name";
+
+    if (empty($form->summary))
+        $err["summary"] = "Missing summary";
+
+    if (empty($form->teacher))
+        $err["teacher"] = "Missing Teacher/Tutor/Instructor/Facilitator";
+
+
+    if ($form->startdate > $form->enddate)
+        $err["startdate"] = "Starts after it ends!";
+
+    if (($form->startdate < time()) && ($course->format <> $form->format)) {
+        $err["format"] = "Can't change the format now";
+        $form->format = $course->format;
+    }
+
+    if (! $form->category)
+        $err["category"] = "You need to choose a category";
+
+    return;
+}
+
+
+?>
diff --git a/course/editweek.html b/course/editweek.html
new file mode 100644 (file)
index 0000000..5a041e9
--- /dev/null
@@ -0,0 +1,12 @@
+<BLOCKQUOTE>
+<FORM name="form" method="post" action="editweek.php">
+<P><B>Summary of week <?=$form->week ?></B></P>
+<TEXTAREA NAME=summary COLS=60 ROWS=4 WRAP=virtual><?=$form->summary ?></TEXTAREA>
+<BR><FONT SIZE=1>(Maximum of 255 characters)</FONT>
+<P>
+<INPUT type="hidden" name=id value="<?=$form->id ?>">
+<INPUT type="submit" value="Save all changes">
+<INPUT type="reset" value="Revert">
+</P>
+</FORM>
+</BLOCKQUOTE>
diff --git a/course/editweek.php b/course/editweek.php
new file mode 100644 (file)
index 0000000..7684ef1
--- /dev/null
@@ -0,0 +1,50 @@
+<?PHP // $Id$
+
+    require("../config.php");
+
+    require_variable($id);    // Week ID
+
+    if (! $week = get_record("course_weeks", "id", $id)) {
+        error("Course week is incorrect");
+    }
+
+    if (! $course = get_record("course", "id", $week->course)) {
+        error("Could not find the course!");
+    }
+
+    require_login($course->id);
+
+    add_to_log("Edit week", $course->id);
+    
+    if (!isteacher($course->id)) {
+        error("Only teachers can edit this!");
+    }
+
+
+/// If data submitted, then process and store.
+
+    if (match_referer() && isset($HTTP_POST_VARS)) {
+
+        $timenow = time();
+
+        if (! set_field("course_weeks", "summary", $summary, "id", $week->id)) {
+            error("Could not update the summary!");
+        }
+        
+        redirect("view.php?id=$course->id");
+        exit;
+    }
+
+/// Otherwise fill and print the form.
+
+    if (! $form ) {
+        $form = $week;
+    }
+
+    print_header("Edit week $week->week", "Edit week $week->week", "", "form.summary");
+
+    include("editweek.html");
+
+    print_footer($course);
+
+?>
diff --git a/course/email.html b/course/email.html
new file mode 100644 (file)
index 0000000..919acff
--- /dev/null
@@ -0,0 +1,32 @@
+<FORM name="form" method="post" action="email.php">
+<TABLE cellpadding=10 CELLSPACING=0 ALIGN=CENTER>
+<TR>
+<TD valign=top align=right BGCOLOR="<?=$THEME->cellheading?>">
+    <P>Subject:</P>
+</TD>
+<TD valign=top align=left BGCOLOR="<?=$THEME->cellheading?>">
+<FONT SIZE=2><INPUT TYPE=text SIZE=60 NAME=subject VALUE="<? p($form->subject); ?>">
+</TD>
+</TR>
+<TR>
+<TD valign=top align=right BGCOLOR="<?=$THEME->cellheading?>">
+    <P>Email:</P>
+</TD>
+<TD BGCOLOR="<?=$THEME->cellheading?>">
+<FONT SIZE=2><TEXTAREA NAME=message COLS=60 ROWS=15 WRAP=hard><? p($form->message); ?></TEXTAREA>
+</TD>
+</TR>
+<TR>
+<TD BGCOLOR="<?=$THEME->cellheading?>">
+&nbsp;
+</TD>
+<TD BGCOLOR="<?=$THEME->cellheading?>">
+    <P>
+    <INPUT type="hidden" name=id value="<?=$form->id ?>">
+    <INPUT type="submit" value="Send this email to everyone now">
+    <INPUT type="reset" value="Revert">
+    </P>
+</TD>
+</TABLE>
+
+</FORM>
diff --git a/course/email.php b/course/email.php
new file mode 100644 (file)
index 0000000..c8f220c
--- /dev/null
@@ -0,0 +1,48 @@
+<?PHP // $Id$
+
+    require("../config.php");
+
+    require_variable($id);    // Course ID
+
+    if (! $course = get_record("course", "id", $id)) {
+        error("Could not find the course!");
+    }
+
+    require_login($course->id);
+
+    if (!isteacher($course->id)) {
+        error("Only teachers can send mail this way!");
+    }
+
+
+/// If data submitted, then process and store.
+
+    if (match_referer() && isset($HTTP_POST_VARS)) {
+
+        $link = "$CFG->wwwroot/course/view.php?id=$course->id";
+
+
+        if (! email_to_course($USER, $course, true, $subject, $message, "$link")) {
+            error("An error occurred while trying to send mail!");
+        }
+
+        add_to_log("Sent mail to everyone", $course->id);
+        
+        redirect("view.php?id=$course->id", "Email sent", 1);
+        exit;
+    }
+
+
+    $form->id = $course->id;
+
+    print_header("$course->shortname: Mail", "$course->fullname", 
+                 "<A HREF=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</A> -> Send mail");
+    
+    print_heading("Send an email to all participants");
+        
+    include("email.html");
+
+    print_footer($course);
+
+
+?>
diff --git a/course/index.php b/course/index.php
new file mode 100644 (file)
index 0000000..21a6679
--- /dev/null
@@ -0,0 +1,25 @@
+<?PHP // $Id$
+
+    require("../config.php");
+    require("lib.php");
+
+    print_header("Courses", "Courses", "Courses", "");
+
+    optional_variable($cat, 1);
+
+    if ($courses = get_records("course", "category", $cat, "fullname ASC")) {
+   
+        foreach ($courses as $key => $course) {
+            print_course($course);
+            echo "<BR>\n";
+        }
+
+    } else {
+        echo "<H3>No courses have been defined yet</H3>";
+    }
+
+    print_footer();
+
+?>
+
+
diff --git a/course/lib.php b/course/lib.php
new file mode 100644 (file)
index 0000000..cdc5235
--- /dev/null
@@ -0,0 +1,131 @@
+<? // $Id$
+
+$MAXNEWSDISPLAY = 4;
+
+$FORMATS = array (
+             "0" => "Non-weekly layout",
+             "1" => "Weekly layout"
+           );
+
+
+function logdate($date) {
+    return date("l, j F Y, g:i A", $date);
+}
+
+function print_log_selector_form($course, $selecteduser=0, $selecteddate="today") {
+
+    // Get all the possible users
+    $users = array();
+    if ($students = get_records_sql("SELECT u.* FROM user u, user_students s 
+                                     WHERE s.course = '$course->id' AND s.user = u.id
+                                     ORDER BY u.lastaccess DESC")) {
+        foreach ($students as $student) {
+            $users["$student->id"] = "$student->firstname $student->lastname";
+        }
+    }
+    if ($teachers = get_records_sql("SELECT u.* FROM user u, user_teachers t 
+                                     WHERE t.course = '$course->id' AND t.user = u.id
+                                     ORDER BY u.lastaccess DESC")) {
+        foreach ($teachers as $teacher) {
+            $users["$teacher->id"] = "$teacher->firstname $teacher->lastname";
+        }
+    }
+
+    asort($users);
+
+    // Get all the possible dates
+    $tt = getdate(time());
+    $timemidnight = $today = mktime (0, 0, 0, $tt["mon"], $tt["mday"], $tt["year"]);
+    $dates = array("$today" => "Today, ".date("j F Y", $today) );
+
+    while ($timemidnight > $course->startdate) {
+        $timemidnight = $timemidnight - 86400;
+        $dates["$timemidnight"] = date("l, j F Y", $timemidnight);
+    }
+
+    if ($selecteddate == "today") {
+        $selecteddate = $today;
+    }
+
+    echo "<CENTER>";
+    echo "<FORM ACTION=log.php METHOD=get>";
+    echo "<INPUT TYPE=hidden NAME=id VALUE=\"$course->id\">";
+    choose_from_menu ($users, "user", $selecteduser, "All participants");
+    choose_from_menu ($dates, "date", $selecteddate, "Any day");
+    echo "<INPUT TYPE=submit VALUE=\"Show these logs\">";
+    echo "</FORM>";
+    echo "</CENTER>";
+}
+
+function print_log($course, $user=0, $date=0, $order="ORDER BY l.time ASC") {
+
+    $selector = "WHERE l.course='$course->id' AND l.user = u.id";
+
+    if ($user) {
+        $selector .= " AND l.user = '$user'";
+    }
+
+    if ($date) {
+        $enddate = $date + 86400;
+        $selector .= " AND l.time > '$date' AND l.time < '$enddate'";
+    }
+
+    if (!$logs = get_records_sql("SELECT l.*, u.firstname, u.lastname, u.picture 
+                                  FROM logs l, user u $selector $order")){
+        notify("No logs found!");
+        print_footer($course);
+        exit;
+    }
+
+    $count=0;
+    $tt = getdate(time());
+    $today = mktime (0, 0, 0, $tt["mon"], $tt["mday"], $tt["year"]);
+    echo "<P ALIGN=CENTER>Displaying ".count($logs)." records</P>";
+    echo "<TABLE BORDER=0 ALIGN=center CELLPADDING=3 CELLSPACING=3>";
+    foreach ($logs as $log) {
+        $count++;
+        
+        echo "<TR>";
+        echo "<TD ALIGN=right><FONT SIZE=2>".date("l", $log->time)."</TD>";
+        echo "<TD><FONT SIZE=2>".date("j M Y, h:i A", $log->time)."</TD>";
+        echo "<TD><FONT SIZE=2><B>$log->firstname $log->lastname</B></TD>";
+        echo "<TD><FONT SIZE=2>";
+        $log->message = addslashes($log->message);
+        link_to_popup_window("$log->url","popup","$log->message", 400, 600);
+        echo "</TD>";
+        echo "</TR>";
+    }
+    echo "</TABLE>";
+}
+
+
+function print_course($course) {
+
+    if (! $site = get_record("course", "category", "0") ) {
+        error("Could not find a site!");
+    }
+
+    print_simple_box_start("CENTER", "80%");
+
+    echo "<TABLE WIDTH=100%>";
+    echo "<TR VALIGN=top><TD VALIGN=top WIDTH=50%>";
+    echo "<P><FONT SIZE=3><B><A HREF=\"view.php?id=$course->id\">$course->fullname</A></B></FONT></P>";
+    if ($teachers = get_records_sql("SELECT u.* FROM user u, user_teachers t 
+                                     WHERE u.id = t.user AND t.course = '$course->id' 
+                                     ORDER BY t.authority DESC")) {
+
+        echo "<P><FONT SIZE=1>\n";
+        foreach ($teachers as $teacher) {
+            echo "$course->teacher: <A HREF=\"../user/view.php?id=$teacher->id&course=$site->id\">$teacher->firstname $teacher->lastname</A><BR>";
+        }
+        echo "</FONT></P>";
+     }
+     echo "</TD><TD VALIGN=top WIDTH=50%>";
+     echo "<P><FONT SIZE=2>".text_to_html($course->summary)."</FONT></P>";
+     echo "</TD></TR>";
+     echo "</TABLE>";
+
+     print_simple_box_end();
+}
+
+?>
diff --git a/course/log.php b/course/log.php
new file mode 100644 (file)
index 0000000..2153f4d
--- /dev/null
@@ -0,0 +1,65 @@
+<?PHP // $Id$
+
+//  log.php - displays different views of the logs.
+
+    require("../config.php");
+    require("lib.php");
+
+    require_login($id);
+
+    if (! $course = get_record("course", "id", $id) ) {
+        error("That's an invalid course id");
+    }
+
+    if ( ! isteacher($course->id)) {
+        error("Only teachers can view logs");
+    }
+
+
+    if (isset($user) || isset($date)) {
+
+        $userinfo = "all users";
+        $dateinfo = "any day";
+
+        if ($user) {
+            if (!$u = get_record("user", "id", $user) ) {
+                error("That's an invalid user!");
+            }
+            $userinfo = "$u->firstname $u->lastname";
+        }
+        if ($date) {
+            $dateinfo = date("l, j F Y", $date);
+        }
+
+        print_header("$course->shortname: Logs", "$course->shortname : Logs", 
+                     "<A HREF=\"view.php?id=$course->id\">$course->shortname</A> ->
+                      <A HREF=\"log.php?id=$course->id\">Logs</A> -> Logs for $userinfo, $dateinfo", "");
+        
+        print_heading("Logs for $userinfo, $dateinfo");
+
+        print_log_selector_form($course, $user, $date);
+
+        print_log($course, $user, $date, "ORDER BY l.time DESC");
+
+
+    } else {
+        print_header("$course->shortname: Logs", "$course->shortname : Logs", 
+                 "<A HREF=\"view.php?id=$course->id\">$course->shortname</A> -> Logs", "");
+
+        print_heading("Choose which logs you want to look at");
+
+        print_log_selector_form($course);
+
+        print_heading("Or see what is happening right now");
+
+        echo "<CENTER><H3>";
+        link_to_popup_window("/course/loglive.php?id=$course->id","livelog","Live logs", 500, 800);
+        echo "</H3></CENTER>";
+
+    }
+
+    print_footer($course);
+
+    exit;
+
+?>
diff --git a/course/login.html b/course/login.html
new file mode 100644 (file)
index 0000000..47d6083
--- /dev/null
@@ -0,0 +1,34 @@
+<CENTER>\r
+\r
+<table cellpadding=20>\r
+  <tr valign=top> \r
+    <td>\r
+    <P ALIGN=CENTER>This course requires a "course entry key" - a one-time<BR>\r
+       password that you should have got from <A HREF="../user/view.php?id=<?=$teacher->id?>&course=<?=$site->id?>"><? p("$teacher->firstname $teacher->lastname") ?></A>.</P>\r
+    </td>\r
+  </tr>\r
+  <tr valign=top> \r
+    <td bgcolor="<?=$THEME->cellheading?>"> <CENTER><? formerr($errormsg) ?> </CENTER>\r
+      <form name="form" method="post" action="login.php">\r
+        <table>\r
+          <tr> \r
+            <td width=50% align=right><P>Entry Key:</P></td>\r
+            <td width=50% > \r
+              <input type="password" name="password" size=20 value="<? p($password) ?>" >\r
+              <input type="hidden" name="id" value="<? p($id) ?>" >\r
+            </td>\r
+          <tr> \r
+            <td width=50%>&nbsp;</td>\r
+            <td width=50%> \r
+              <table cellpadding=1 cellspacing=0><tr>\r
+              <td><input type=submit value=Login></form></td>\r
+              <td><form action="<?=$CFG->wwwroot?>/" method=post>\r
+                  <input type=submit value=Cancel></form></td>\r
+              </tr></table>\r
+\r
+            </td>\r
+        </table>\r
+    </td>\r
+  </tr>\r
+</table>\r
+\r
diff --git a/course/login.php b/course/login.php
new file mode 100644 (file)
index 0000000..b0db697
--- /dev/null
@@ -0,0 +1,93 @@
+<?PHP // $Id$
+
+//  Asks for a course pass key, once only
+
+    require("../config.php");
+    require("lib.php");
+
+    require_login();
+    require_variable($id);
+
+
+    if (match_referer() && isset($HTTP_POST_VARS)) {    // form submitted
+
+        $actual_password = get_field("course", "password", "id", $id);
+
+        if ($password == $actual_password) {
+
+            enrol_student_in_course($USER->id, $id);
+            add_to_log("Enrolled in course", $id);
+
+            $USER->student["$id"] = true;
+            
+            if ($SESSION->wantsurl) {
+                $destination = $SESSION->wantsurl;
+                unset($SESSION->wantsurl);
+            } else {
+                $destination = "$CFG->wwwroot/course/view.php?id=$id";
+            }
+
+           redirect($destination);
+    
+        } else {
+            $errormsg = "That entry key was incorrect, please try again".
+                        "<BR>(Here's a hint - it starts with \"".substr($actual_password,0,1)."\")";
+        }
+    }
+
+    if (! $course = get_record("course", "id", $id) ) {
+        error("That's an invalid course id");
+    }
+
+    if (! $site = get_record("course", "category", "0") ) {
+        error("Could not find a site!");
+    }
+
+    if ($course->password == "") {   // no password, so enrol
+        if (! enrol_student_in_course($USER->id, $course->id)) {
+            error("An error occurred while trying to enrol you.");
+        }
+
+        add_to_log("Enrolled in course", $id);
+
+        $USER->student["$id"] = true;
+        
+        if ($SESSION->wantsurl) {
+            $destination = $SESSION->wantsurl;
+            unset($SESSION->wantsurl);
+        } else {
+            $destination = "$CFG->wwwroot/course/view.php?id=$id";
+        }
+
+        redirect($destination);
+    }
+
+    $teacher = get_teacher($course->id);
+
+    print_header("Login to $course->shortname", "Login to $course->shortname", "<A HREF=\".\">Courses</A> -> Login to $course->shortname", "form.password"); 
+
+    print_course($course); 
+
+    include("login.html");
+
+    print_footer();
+
+
+//// FUNCTIONS /////////////////////////////////////////////
+
+function enrol_student_in_course($user, $course) {
+    
+    global $db;
+
+       $timenow = time();
+
+       $rs = $db->Execute("INSERT INTO user_students (user, course, start, end, time) 
+                        VALUES ($user, $course, 0, 0, $timenow)");
+       if ($rs) {
+               return true;
+       } else {
+           return false;
+       }
+}
+
+?>
diff --git a/course/loginas.php b/course/loginas.php
new file mode 100644 (file)
index 0000000..97024a6
--- /dev/null
@@ -0,0 +1,40 @@
+<?PHP // $Id$
+
+       require("../config.php");
+       require("lib.php");
+
+    require_variable($id);     // course id
+    require_variable($user);   // login as this user
+
+    if (! $course = get_record("course", "id", $id)) {
+        error("Course ID was incorrect");
+    }
+
+       require_login($course->id);
+
+    if (!isteacher($course->id)) {
+        error("Only teachers can use this page!");
+    }
+
+    if (!isstudent($course->id, $user)) {
+        error("This student is not in your course!");
+    }
+
+    // Login as this student and return to course home page.
+
+    $teacher_name = "$USER->firstname $USER->lastname";
+
+    $USER = get_user_info_from_db("id", $user);
+    $USER->loggedin = true;
+
+    set_moodle_cookie($USER->username);
+
+    $student_name = "$USER->firstname $USER->lastname";
+    
+    add_to_log("$teacher_name logged in as $student_name", $course->id);
+
+    notice("You are now logged in as $student_name", "$CFG->wwwroot/course/view.php?id=$course->id");
+
+    die;
+
+?>
diff --git a/course/loglive.php b/course/loglive.php
new file mode 100644 (file)
index 0000000..a3e22ff
--- /dev/null
@@ -0,0 +1,29 @@
+<?PHP // $Id$
+
+//  loglive.php - displays different views of the logs.
+
+    require("../config.php");
+    require("lib.php");
+
+    require_login($id);
+
+    if (! $course = get_record("course", "id", $id) ) {
+        error("That's an invalid course id");
+    }
+
+    if ( ! isteacher($course->id)) {
+        error("Only teachers can view logs");
+    }
+
+    print_header("Activity within the last hour (updates every 60 secs)", 
+                  "Activity within the last hour (updates every 60 secs)", 
+                  "", "", "<META HTTP-EQUIV='Refresh' CONTENT='60; URL=loglive.php?id=$id'>");
+
+    $user=0;
+    $date=time() - 3600;
+
+    print_log($course, $user, $date, "ORDER BY l.time DESC");
+
+    exit;
+
+?>
diff --git a/course/mod.php b/course/mod.php
new file mode 100644 (file)
index 0000000..5558853
--- /dev/null
@@ -0,0 +1,423 @@
+<?PHP // $Id$
+
+//  Moves, adds, updates or deletes modules in a course
+
+    require("../config.php");
+
+    if (isset($course) && isset($HTTP_POST_VARS)) {    // add or update form submitted
+        $mod = (object)$HTTP_POST_VARS;
+
+        require_login($mod->course);
+
+        if (!isteacher($mod->course)) {
+            error("You can't modify this course!");
+        }
+
+        $modcode = "../mod/$mod->modulename/mod.php";
+        if (file_exists($modcode)) {
+            include($modcode);
+        } else {
+            error("This module is missing important code! (mod.php)");
+        }
+
+        switch ($mod->mode) {
+            case "update":
+                if (! update_instance($mod)) {
+                    error("Could not update the $mod->modulename");
+                }
+                add_to_log("Updated $mod->modulename $mod->instance", $mod->course);
+                break;
+
+            case "add":
+                if (! $mod->instance = add_instance($mod)) {
+                    error("Could not add a new instance of $mod->modulename");
+                }
+                // course_modules and course_weeks each contain a reference 
+                // to each other, so we have to update one of them twice.
+
+                if (! $mod->course_module = add_course_module($mod) ) {
+                    error("Could not add a new course module");
+                }
+                if (! $weekid = add_mod_to_week($mod) ) {
+                    error("Could not add the new course module to that week");
+                }
+                if (! set_field("course_modules", "week", $weekid, "id", $mod->course_module)) {
+                    error("Could not update the course module with the correct week");
+                }   
+                add_to_log("Added $mod->modulename $mod->instance", $mod->course);
+                break;
+            case "delete":
+                if (! delete_instance($mod->instance)) {
+                    error("Could not delete the $mod->modulename");
+                }
+                if (! delete_course_module($mod->coursemodule)) {
+                    error("Could not delete the $mod->modulename");
+                }
+                if (! delete_mod_from_week($mod->coursemodule, "$mod->week")) {
+                    error("Could not delete the $mod->modulename from that week");
+                }
+                add_to_log("Deleted $mod->modulename $mod->instance", $mod->course);
+                break;
+            default:
+                error("No mode defined");
+
+        }
+
+        redirect("view.php?id=$mod->course");
+        exit;
+    }
+
+
+    if (isset($move)) {  
+
+        require_variable($id);   
+
+        move_module($id, $move);
+
+        redirect($HTTP_REFERER);
+        exit;
+
+    } else if (isset($delete)) {   // value = course module
+
+        if (! $cm = get_record("course_modules", "id", $delete)) {
+            error("This course module doesn't exist");
+        }
+
+        if (! $course = get_record("course", "id", $cm->course)) {
+            error("This course doesn't exist");
+        }
+
+        if (! $module = get_record("modules", "id", $cm->module)) {
+            error("This module doesn't exist");
+        }
+
+        require_login($course->id);
+
+        if (!isteacher($course->id)) {
+            error("You can't modify this course!");
+        }
+
+        $form->coursemodule = $cm->id;
+        $form->week         = $cm->week;
+        $form->course       = $cm->course;
+        $form->instance     = $cm->instance;
+        $form->modulename   = $module->name;
+
+        include("mod_delete.html");
+
+        exit;
+
+
+    } else if (isset($update)) {   // value = course module
+
+        if (! $cm = get_record("course_modules", "id", $update)) {
+            error("This course module doesn't exist");
+        }
+
+        if (! $course = get_record("course", "id", $cm->course)) {
+            error("This course doesn't exist");
+        }
+
+        if (! $module = get_record("modules", "id", $cm->module)) {
+            error("This module doesn't exist");
+        }
+
+        if (! $form = get_record($module->name, "id", $cm->instance)) {
+            error("The required instance of this module doesn't exist");
+        }
+        
+        if (! $cw = get_record("course_weeks", "id", $cm->week)) {
+            error("This course week doesn't exist");
+        }
+
+        $form->week       = $cm->week;     // The week ID
+        $form->course     = $course->id;
+        $form->module     = $module->id;
+        $form->modulename = $module->name;
+        $form->instance   = $cm->instance;
+        $form->mode       = "update";
+
+        $pageheading = "Updating a $module->fullname in Week $cw->week";
+
+        
+    } else if (isset($add)) {
+
+        if (!$add) {
+            redirect($HTTP_REFERER);
+            die;
+        }
+
+        require_variable($id);
+        require_variable($week);
+
+        if (! $course = get_record("course", "id", $id)) {
+            error("This course doesn't exist");
+        }
+
+        if (! $module = get_record("modules", "name", $add)) {
+            error("This module type doesn't exist");
+        }
+
+        $form->week       = $week;         // The week number itself
+        $form->course     = $course->id;
+        $form->module     = $module->id;
+        $form->modulename = $module->name;
+        $form->instance   = $cm->instance;
+        $form->mode       = "add";
+
+        if ($form->week) {
+            $pageheading = "Adding a new $module->fullname to Week $form->week";
+        } else {
+            $pageheading = "Adding a new $module->fullname";
+        }
+
+    } else {
+        error("No action was specfied");
+    }
+
+    require_login($course->id);
+
+    if (!isteacher($course->id)) {
+        error("You can't modify this course!");
+    }
+
+    print_header("$course->shortname: Editing a $module->fullname", "$course->shortname: Editing a $module->fullname",
+                 "<A HREF=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</A> -> 
+                  Editing a $module->fullname", "form.name");
+
+    $modform = "../mod/$module->name/mod.html";
+
+    if (file_exists($modform)) {
+
+        print_heading($pageheading);
+        print_simple_box_start("center", "", "$THEME->cellheading");
+        include($modform);
+        print_simple_box_end();
+
+    } else {
+        notice("This module cannot be added to this course yet!", "$CFG->wwwroot/course/view.php?id=$course->id");
+    }
+
+    print_footer($course);
+
+    exit;
+
+
+/// FUNCTIONS //////////////////////////////////////////////////////////////////////
+
+function add_course_module($mod) {
+    GLOBAL $db;
+
+    $timenow = time();
+
+    if (!$rs = $db->Execute("INSERT into course_modules 
+                                SET course   = '$mod->course', 
+                                    module   = '$mod->module',
+                                    instance = '$mod->instance',
+                                    week     = '$mod->week',
+                                    added    = '$timenow' ")) {
+        return 0;
+    }
+    
+    // Get it out again - this is the most compatible way to determine the ID
+    if ($rs = $db->Execute("SELECT id FROM course_modules 
+                            WHERE module = $mod->module AND added = $timenow")) {
+        return $rs->fields[0];
+    } else {
+        return 0;
+    }
+
+}
+
+function add_mod_to_week($mod) {
+// Returns the course_weeks ID where the mod is inserted
+    GLOBAL $db;
+
+    if ($cw = get_record_sql("SELECT * FROM course_weeks 
+                              WHERE course = '$mod->course' AND week = '$mod->week'") ) {
+
+        if ($cw->sequence) {
+            $newsequence = "$cw->sequence,$mod->course_module";
+        } else {
+            $newsequence = "$mod->course_module";
+        }
+        if (!$rs = $db->Execute("UPDATE course_weeks SET sequence = '$newsequence' WHERE id = '$cw->id'")) {
+            return 0;
+        } else {
+            return $cw->id;     // Return course_weeks ID that was used.
+        }
+       
+    } else {  // Insert a new record
+        if (!$rs = $db->Execute("INSERT into course_weeks 
+                                 SET course   = '$mod->course', 
+                                     week     = '$mod->week',
+                                     summary  = '',
+                                     sequence = '$mod->course_module' ")) {
+            return 0;
+        }
+        // Get it out again - this is the most compatible way to determine the ID
+        if ($rs = $db->Execute("SELECT id FROM course_weeks 
+                                WHERE course = '$mod->course' AND week = '$mod->week'")) {
+            return $rs->fields[0];
+        } else {
+            return 0;
+        }
+    }
+}
+
+function delete_course_module($mod) {
+    return set_field("course_modules", "deleted", 1, "id", $mod);
+}
+
+function delete_mod_from_week($mod, $week) {
+    GLOBAL $db;
+
+    if ($cw = get_record("course_weeks", "id", "$week") ) {
+
+        $modarray = explode(",", $cw->sequence);
+
+        if ($key = array_keys ($modarray, $mod)) {
+            array_splice($modarray, $key[0], 1);
+            $newsequence = implode(",", $modarray);
+            return set_field("course_weeks", "sequence", $newsequence, "id", $cw->id);
+        } else {
+            return false;
+        }
+       
+    } else {  
+        return false;
+    }
+}
+
+
+function move_module($id, $move) {
+    GLOBAL $db;
+
+    if (!$move) {
+        return true;
+    }
+
+    if (! $cm = get_record("course_modules", "id", $id)) {
+        error("This course module doesn't exist");
+    }
+    
+    if (! $thisweek = get_record("course_weeks", "id", $cm->week)) {
+        error("This course week doesn't exist");
+    }
+
+    $mods = explode(",", $thisweek->sequence);
+
+    $len = count($mods);
+    $pos = array_keys($mods, $cm->id);
+    $thepos = $pos[0];
+
+    if ($len == 0 || count($pos) == 0 ) {
+        error("Very strange. Could not find the required module in this week.");
+    }
+
+    if ($len == 1) {
+        $first = true;
+        $last = true;
+    } else {
+        $first = ($thepos == 0);
+        $last  = ($thepos == $len - 1);
+    }
+
+    if ($move < 0) {    // Moving the module up
+
+        if ($first) {
+            if ($thisweek->week == 1) {  // First week, do nothing
+                return true;
+            } else {               // Push onto end of previous week
+                $prevweeknumber = $thisweek->week - 1;
+                if (! $prevweek = get_record_sql("SELECT * FROM course_weeks 
+                                                  WHERE course='$thisweek->course'
+                                                  AND week='$prevweeknumber' ")) {
+                    error("Previous week ($prevweek->id) doesn't exist");
+                }
+
+                if ($prevweek->sequence) {
+                    $newsequence = "$prevweek->sequence,$cm->id";
+                } else {
+                    $newsequence = "$cm->id";
+                }
+
+                if (! set_field("course_weeks", "sequence", $newsequence, "id", $prevweek->id)) {
+                    error("Previous week could not be updated");
+                }
+
+                if (! set_field("course_modules", "week", $prevweek->id, "id", $cm->id)) {
+                    error("Module could not be updated");
+                }
+
+                array_splice($mods, 0, 1);
+                $newsequence = implode(",", $mods);
+                if (! set_field("course_weeks", "sequence", $newsequence, "id", $thisweek->id)) {
+                    error("Module could not be updated");
+                }
+
+                return true;
+
+            }
+        } else {        // move up within this week
+            $swap = $mods[$thepos-1];
+            $mods[$thepos-1] = $mods[$thepos];
+            $mods[$thepos] = $swap;
+            
+            $newsequence = implode(",", $mods);
+            if (! set_field("course_weeks", "sequence", $newsequence, "id", $thisweek->id)) {
+                error("This week could not be updated");
+            }
+            return true;
+        }
+
+    } else {            // Moving the module down
+
+        if ($last) {
+            $nextweeknumber = $thisweek->week + 1;
+            if ($nextweek = get_record_sql("SELECT * FROM course_weeks 
+                                            WHERE course='$thisweek->course'
+                                            AND week='$nextweeknumber' ")) {
+
+                if ($nextweek->sequence) {
+                    $newsequence = "$cm->id,$nextweek->sequence";
+                } else {
+                    $newsequence = "$cm->id";
+                }
+
+                if (! set_field("course_weeks", "sequence", $newsequence, "id", $nextweek->id)) {
+                    error("Next week could not be updated");
+                }
+
+                if (! set_field("course_modules", "week", $nextweek->id, "id", $cm->id)) {
+                    error("Module could not be updated");
+                }
+
+                array_splice($mods, $thepos, 1);
+                $newsequence = implode(",", $mods);
+                if (! set_field("course_weeks", "sequence", $newsequence, "id", $thisweek->id)) {
+                    error("This week could not be updated");
+                }
+                return true;
+
+            } else {        // There is no next week, so just return
+                return true;
+
+            }
+        } else {      // move down within this week
+            $swap = $mods[$thepos+1];
+            $mods[$thepos+1] = $mods[$thepos];
+            $mods[$thepos] = $swap;
+            
+            $newsequence = implode(",", $mods);
+            if (! set_field("course_weeks", "sequence", $newsequence, "id", $thisweek->id)) {
+                error("This week could not be updated");
+            }
+            return true;
+        }
+    }
+}
+
+?>
+
+
diff --git a/course/mod_delete.html b/course/mod_delete.html
new file mode 100644 (file)
index 0000000..c7ca08a
--- /dev/null
@@ -0,0 +1,16 @@
+<table align=center cellpadding=20> <tr> <td colspan=2 bgcolor=#ffaaaa>
+
+<CENTER>
+<FORM name="form" method="post" action="<?=$ME ?>">
+<? print_heading("Are you absolutely sure you want to delete the $form->modulename ?") ?>
+<input type="hidden" name=mode         value="delete">
+<input type="hidden" name=week         value="<? echo $form->week; ?>">
+<input type="hidden" name=course       value="<? p($form->course) ?>">
+<input type="hidden" name=coursemodule value="<? p($form->coursemodule) ?>">
+<input type="hidden" name=modulename   value="<? p($form->modulename) ?>">
+<input type="hidden" name=instance     value="<? p($form->instance) ?>">
+<input type="submit" value=" Yes "> <input type=button value=" No " onclick="javascript:history.go(-1);">
+</FORM>
+
+</td></tr></table>
+
diff --git a/course/new.php b/course/new.php
new file mode 100644 (file)
index 0000000..1e6b3cd
--- /dev/null
@@ -0,0 +1,44 @@
+<?PHP // $Id$
+
+// This script prints all the new things that have happened since the last login
+// To do this, it calls new.php in each module.  It relies on $USER->lastlogin
+
+    require("../config.php");
+    require("lib.php");
+
+    require_variable($id);    // Course ID
+
+    if (! $course = get_record("course", "id", $id)) {
+        error("Could not find the course!");
+    }
+
+    require_login($course->id);
+
+    add_to_log("View Whats New", $course->id);
+
+    print_header("$course->shortname: What's new", "$course->fullname",
+                 "<A HREF=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</A> -> What's new");
+
+    print_heading("Recent activity since your last login"); 
+    print_heading(logdate($USER->lastlogin)); 
+    
+    print_simple_box_start("center");
+    $modules = array ("users");
+
+    $mods = get_records_sql("SELECT * FROM modules");
+
+    foreach ($mods as $mod) {
+        $modules[] = "mod/$mod->name";
+    }
+
+    foreach ($modules as $module) {
+        $newfile = "$CFG->dirroot/$module/new.php";
+        if (file_exists($newfile)) {
+            include($newfile);
+        }
+    }
+
+    print_simple_box_end();
+    print_footer($course);
+
+?>
diff --git a/course/noweeks.php b/course/noweeks.php
new file mode 100644 (file)
index 0000000..d22b675
--- /dev/null
@@ -0,0 +1,158 @@
+<?PHP // $Id$
+
+//  This course doesn't contain weeks.  Everything should be 
+//  found under week 0.  Present in non-weekly layout.
+//
+//  Included from "view.php"
+
+    // Layout the whole page as two big columns.
+    echo "<TABLE BORDER=0 CELLPADDING=4>";
+    echo "<TR VALIGN=top><TD VALIGN=top WIDTH=200>";
+    echo "<IMG SRC=\"../pix/spacer.gif\" WIDTH=180 HEIGHT=1><BR>";
+    
+    // Layout the left column
+
+    print_side_block("<A HREF=\"new.php?id=$course->id\">What's New!</A>", 
+                     "", "<FONT SIZE=1>...since your last login</FONT>");
+
+    // Then, print all the news items.
+
+    // XXXXX
+
+    // Admin links and controls
+
+    if ($USER->teacher[$course->id]) {
+        $admindata[]="<A HREF=\"edit.php?id=$course->id\">Course settings</A>";
+        $adminicon[]="<IMG SRC=\"../pix/i/settings.gif\" HEIGHT=16 WIDTH=16 ALT=\"Course\">";
+        $admindata[]="<A HREF=\"log.php?id=$course->id\">Logs</A>";
+        $adminicon[]="<IMG SRC=\"../pix/i/log.gif\" HEIGHT=16 WIDTH=16 ALT=\"Log\">";
+        $admindata[]="<A HREF=\"email.php?id=$course->id\">Send mail</A>";
+        $adminicon[]="<IMG SRC=\"../pix/i/email.gif\" HEIGHT=16 WIDTH=16 ALT=\"Email\">";
+        $admindata[]="<A HREF=\"../files/index.php?id=$course->id\">Files</A>";
+        $adminicon[]="<IMG SRC=\"../files/pix/files.gif\" HEIGHT=16 WIDTH=16 ALT=\"Files\">";
+        print_side_block("Administration", $admindata, "", $adminicon);
+    }
+
+
+    // Start main column
+    echo "</TD><TD WIDTH=100%>";
+
+    echo "<P><IMG SRC=\"../pix/spacer.gif\" WIDTH=100% HEIGHT=3><BR>";
+    echo "<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0 WIDTH=100%>";
+    echo "<TR>";
+    echo "<TD NOWRAP ALIGN=RIGHT><P><FONT SIZE=1>";
+    if ($USER->teacher[$course->id]) {
+        if ($USER->editing) {
+            echo "<A HREF=\"view.php?id=$course->id&edit=off\">Turn editing off</A>";
+        } else {
+            echo "<A HREF=\"view.php?id=$course->id&edit=on\">Turn editing on</A>";
+        }
+    }
+    //if ($USER->help) {
+        //echo "&nbsp;&nbsp;&nbsp;<A HREF=\"view.php?id=$course->id&help=off\">Turn help off</A>";
+    //} else {
+        //echo "&nbsp;&nbsp;&nbsp;<A HREF=\"view.php?id=$course->id&help=on\">Turn help on</A>";
+    //}
+    echo "</TD></TR></TABLE>";
+
+    echo "<TABLE WIDTH=100% CELLPADDING=5 CELLSPACING=20 BORDER=0>";
+
+    // Forums
+    echo "<TR><TD VALIGN=top WIDTH=33% BGCOLOR=\"$THEME->cellheading\">";
+    echo "<H4>Forums</H4>";
+
+    echo "<TABLE BORDER=0>";
+    if ($forums = get_all_instances_in_course("forum", $course->id)) {
+        foreach ($forums as $key => $ff) {
+            $forum = (object)$ff;
+            echo "<TR><TD WIDTH=16 VALIGN=top>";
+            echo "<A HREF=\"../mod/forum/view.php?id=$forum->coursemodule\">";
+            echo "<IMG SRC=\"../mod/forum/icon.gif\" HEIGHT=16 WIDTH=16 ALT=\"Forum\" BORDER=0></A>";
+            echo "</TD><TD WIDTH=100%><P>";
+            echo "<A HREF=\"../mod/forum/view.php?id=$forum->coursemodule\">$forum->name</A>";
+            if ($USER->editing) {
+                echo "&nbsp;&nbsp;<A HREF=mod.php?delete=$forum->coursemodule><IMG 
+                         SRC=../pix/t/delete.gif BORDER=0 ALT=Delete></A>
+                      <A HREF=mod.php?update=$forum->coursemodule><IMG 
+                         SRC=../pix/t/edit.gif BORDER=0 ALT=Update></A>";
+            }
+            echo "</TD></TR>\n";
+        }
+    }
+
+    if ($USER->editing) {
+        echo "<TR><TD>&nbsp;</TD><TD><P>";
+        echo "<FONT SIZE=1><A HREF=\"mod.php?id=$course->id&week=0&add=forum\">Add forum...</A></FONT>";
+        echo "</TD></TR>";
+    }
+    echo "</TABLE>";
+
+
+    // Readings 
+    echo "</TD><TD VALIGN=top WIDTH=33% BGCOLOR=\"$THEME->cellheading\">";
+    echo "<H4>Readings</H4>";
+
+    echo "<TABLE BORDER=0>";
+    if ($readings = get_all_instances_in_course("reading", $course->id, "m.timemodified DESC")) {
+        
+        $count = 0;
+        foreach ($readings as $key => $rr) {
+            $reading = (object)$rr;
+            echo "<TR><TD WIDTH=16 VALIGN=top>";
+            echo "<A HREF=\"../mod/reading/view.php?id=$reading->coursemodule\">";
+            echo "<IMG SRC=\"../mod/reading/icon.gif\" HEIGHT=16 WIDTH=16 ALT=\"Forum\" BORDER=0></A>";
+            echo "</TD><TD WIDTH=100%><P>";
+            echo "<A HREF=\"../mod/reading/view.php?id=$reading->coursemodule\">$reading->name</A>";
+            if ($USER->editing) {
+                echo "&nbsp;&nbsp;<A HREF=mod.php?delete=$reading->coursemodule><IMG 
+                         SRC=../pix/t/delete.gif BORDER=0 ALT=Delete></A>
+                      <A HREF=mod.php?update=$reading->coursemodule><IMG 
+                         SRC=../pix/t/edit.gif BORDER=0 ALT=Update></A>";
+            }
+            echo "</TD></TR>\n";
+            if ($count++ > 5) {
+                echo "<TR><TD>&nbsp;</TD><TD><P>";
+                echo "<A HREF=\"../mod/reading/index.php?id=$course->id\">See all readings...</A></FONT>";
+                echo "</TD></TR>";
+                break;
+            }
+        }
+    }
+
+    if ($USER->editing) {
+        echo "<TR><TD>&nbsp;</TD><TD><P>";
+        echo "<FONT SIZE=1><A HREF=\"mod.php?id=$course->id&week=0&add=reading\">Add reading...</A></FONT>";
+        echo "</TD></TR>";
+    }
+    echo "</TABLE>";
+
+
+    // Participants
+    echo "</TD><TD VALIGN=top WIDTH=33% BGCOLOR=\"$THEME->cellheading\">";
+    echo "<H4>Participants</H4>";
+
+    echo "<TABLE BORDER=0>";
+    echo "<TR><TD WIDTH=16 VALIGN=top>";
+    echo "<A HREF=\"../user/index.php?id=$course->id\">";
+    echo "<IMG SRC=\"../user/users.gif\" HEIGHT=16 WIDTH=16 ALT=\"Participants\" BORDER=0></A>";
+    echo "</TD><TD WIDTH=100%><P>";
+    echo "<A HREF=\"../user/index.php?id=$course->id\">List of all participants</A>";
+    echo "</TD></TR>\n";
+    echo "<TR><TD WIDTH=16>";
+    echo "<A HREF=\"../user/view.php?id=$USER->id&course=$course->id\">";
+    echo "<IMG SRC=\"../user/user.gif\" HEIGHT=16 WIDTH=16 ALT=\"Participants\" BORDER=0></A>";
+    echo "</TD><TD WIDTH=100%><P>";
+    echo "<A HREF=\"../user/view.php?id=$USER->id&course=$course->id\">My details</A>";
+    echo "</TD></TR>\n";
+    echo "</TABLE>";
+
+    // Then all the links to module types
+
+    echo "</TABLE>";
+    echo "</TABLE>";
+    
+
+    echo "</TD></TR></TABLE>";
+
+
+?>
diff --git a/course/user.php b/course/user.php
new file mode 100644 (file)
index 0000000..6029181
--- /dev/null
@@ -0,0 +1,46 @@
+<?PHP // $Id$
+
+    require("../config.php");
+
+    require_variable($id);       // course id
+    require_variable($user);     // user id
+
+    if (! $course = get_record("course", "id", $id)) {
+        error("Course id is incorrect.");
+    }
+
+    require_login($course->id);
+
+    if (!isteacher($course->id)) {
+        error("Only teachers can look at this page");
+    }
+
+    if (! $user = get_record("user", "id", $user)) {
+        error("User ID is incorrect");
+    }
+
+    add_to_log("View total report of $user->firstname $user->lastname", $course->id);
+
+    print_header("$course->shortname: Report", "$course->fullname",
+                 "<A HREF=\"../course/view.php?id=$course->id\">$course->shortname</A> ->
+                  <A HREF=\"../user/index.php?id=$course->id\">Participants</A> ->
+                  <A HREF=\"../user/view.php?id=$user->id&course=$course->id\">$user->firstname $user->lastname</A> -> 
+                  Full Report", "");
+
+    if ($mods = get_records_sql("SELECT * FROM modules ORDER BY fullname")) {
+        foreach ($mods as $mod) {
+            $userfile = "$CFG->dirroot/mod/$mod->name/user.php";
+            if (file_exists($userfile)) {
+                echo "<H2>".$mod->fullname."s</H2>";
+                echo "<BLOCKQUOTE>";
+                include($userfile);
+                echo "</BLOCKQUOTE>";
+                echo "<HR WIDTH=100%>";
+            }
+        }
+    }
+
+    print_footer($course);
+
+?>
+
diff --git a/course/view.php b/course/view.php
new file mode 100644 (file)
index 0000000..3044a7b
--- /dev/null
@@ -0,0 +1,102 @@
+<?PHP // $Id$
+
+//  Display the course home page.
+
+    require("../config.php");
+    require("lib.php");
+
+
+    require_login($id);
+
+    if (! $course = get_record("course", "id", $id) ) {
+        error("That's an invalid course id");
+    }
+
+    if (! $course->category) {      // This course is not a real course.
+        redirect("$CFG->wwwroot");
+    }
+
+    add_to_log("View course: $course->shortname", $id);
+
+    if ( $USER->teacher[$course->id] ) {
+        if ($edit == "on") {
+            $USER->editing = true;
+        } else if ($edit == "off") {
+            $USER->editing = false;
+        }
+    }
+    if ($help == "on") {
+        $USER->help = true;
+    } else if ($help == "off") {
+        $USER->help = false;
+    }
+
+    print_header("Course: $course->fullname", "$course->fullname", "$course->shortname", "");
+
+    if (! $modtypes = get_records_sql_menu("SELECT name,fullname FROM modules ORDER BY fullname") ) {
+        error("No modules are installed!");
+    }
+
+    if ( $rawmods = get_records_sql("SELECT cm.*, m.name as modname, m.fullname as modfullname
+                                   FROM modules m, course_modules cm
+                                   WHERE cm.course = '$course->id' 
+                                     AND cm.deleted = '0'
+                                     AND cm.module = m.id") ) {
+
+        foreach($rawmods as $mod) {    // Index the mods
+            $mods[$mod->id] = $mod;
+            $modtype[$mod->modname] = $mod->modfullname;
+        }
+    }
+
+    switch ($course->format) {
+        case 0:
+            include("noweeks.php");
+            break;
+        case 1:
+            include("weeks.php");
+            break;
+    }
+
+    print_footer($course);
+
+
+/// FUNCTIONS ////////
+
+
+function make_editing_buttons($moduleid) {
+    return "&nbsp; &nbsp; 
+          <A HREF=mod.php?delete=$moduleid><IMG 
+             SRC=../pix/t/delete.gif BORDER=0 ALT=Delete></A>
+          <A HREF=mod.php?id=$moduleid&move=-1><IMG 
+             SRC=../pix/t/up.gif BORDER=0 ALT=\"Move up\"></A>
+          <A HREF=mod.php?id=$moduleid&move=1><IMG 
+             SRC=../pix/t/down.gif BORDER=0 ALT=\"Move down\"></A>
+          <A HREF=mod.php?update=$moduleid><IMG 
+             SRC=../pix/t/edit.gif BORDER=0 ALT=Update></A>";
+}
+
+function print_side_block($heading="", $list=NULL, $footer="", $icons=NULL) {
+    
+    echo "<TABLE WIDTH=100%>\n";
+    echo "<TR><TD COLSPAN=2><P><B><FONT SIZE=2>$heading</TD></TR>\n";
+    if ($list) {
+        foreach($list as $key => $string) {
+            echo "<TR><TD VALIGN=top WIDTH=12>";
+            if ($icons[$key]) {
+                echo $icons[$key];
+            } else {
+                echo "";
+            }
+            echo "</TD>\n<TD WIDTH=100%>";
+            echo "<P><FONT SIZE=1>$string</FONT></P>";
+            echo "</TD></TR>\n";
+        }
+    }
+    if ($footer) {
+        echo "<TR><TD></TD><TD ALIGN=left><P><FONT SIZE=2>$footer</TD></TR>\n";
+    }
+    echo "</TABLE><BR>\n\n";
+}
+
+?>
diff --git a/course/weeks.php b/course/weeks.php
new file mode 100644 (file)
index 0000000..85b07c2
--- /dev/null
@@ -0,0 +1,184 @@
+<?PHP // $Id$
+
+//  Display the whole course as "weeks" made of of modules
+//  Included from "view.php"
+
+    if (! $rawweeks = get_records("course_weeks", "course", $course->id) ) {
+        $week->course = $course->id;   // Create a default week.
+        $week->week = 0;
+        $week->id = insert_record("course_weeks", $week);
+        if (! $rawweeks = get_records("course_weeks", "course", $course->id) ) {
+            error("Error finding or creating week structures for this course");
+        }
+    }
+    
+    foreach($rawweeks as $cw) {  //Index the weeks
+        $weeks[$cw->week] = $cw;
+    }
+
+    // Layout the whole page as two big columns.
+    echo "<TABLE BORDER=0 CELLPADDING=4>";
+    echo "<TR VALIGN=top><TD VALIGN=top WIDTH=200>";
+    echo "<IMG SRC=\"../pix/spacer.gif\" WIDTH=180 HEIGHT=1><BR>";
+    
+    // Layout the left column
+
+    print_side_block("<A HREF=\"new.php?id=$course->id\">What's New!</A>", 
+                     "", "<FONT SIZE=1>...since your last login</FONT>");
+
+    // Then, print all the news items.
+
+    include("../mod/discuss/lib.php");
+    if ($news = get_course_news_forum($course->id)) {
+        print_simple_box_start("CENTER", "100%", "#FFFFFF", 5);
+        echo "<P><B><FONT SIZE=2>Latest News</FONT></B><BR>";
+        echo "<FONT SIZE=1>";
+        forum_latest_topics($news->id, 5, "minimal", "DESC", false);
+        echo "</FONT>";
+        print_simple_box_end();
+    }
+
+    // Now, print all the course links on the side
+
+    // Then all the links to module types
+
+    $moddata = array();
+    $modicon = array();
+
+    if ($modtype) {
+        foreach ($modtype as $modname => $modfullname) {
+            $moddata[] = "<A HREF=\"../mod/$modname/index.php?id=$course->id\">".$modfullname."s</A>";
+            $modicon[] = "<IMG SRC=\"../mod/$modname/icon.gif\" HEIGHT=16 WIDTH=16 ALT=\"$modfullname\">";
+        }
+    }
+
+    $moddata[]="<A HREF=\"../user/index.php?id=$course->id\">Participants</A>";
+    $modicon[]="<IMG SRC=\"../user/users.gif\" HEIGHT=16 WIDTH=16 ALT=\"Participants\">";
+
+    print_side_block("Activities", $moddata, "", $modicon);
+
+    // Admin links and controls
+
+    $admindata[]="<A HREF=\"../user/view.php?id=$USER->id&course=$course->id\">My details</A>";
+    $adminicon[]="<IMG SRC=\"../user/user.gif\" HEIGHT=16 WIDTH=16 ALT=\"About me\">";
+
+    if ($USER->teacher[$course->id]) {
+        $admindata[]="<A HREF=\"edit.php?id=$course->id\">Course settings</A>";
+        $adminicon[]="<IMG SRC=\"../pix/i/settings.gif\" HEIGHT=16 WIDTH=16 ALT=\"Course\">";
+        $admindata[]="<A HREF=\"log.php?id=$course->id\">Logs</A>";
+        $adminicon[]="<IMG SRC=\"../pix/i/log.gif\" HEIGHT=16 WIDTH=16 ALT=\"Log\">";
+        $admindata[]="<A HREF=\"email.php?id=$course->id\">Send mail</A>";
+        $adminicon[]="<IMG SRC=\"../pix/i/email.gif\" HEIGHT=16 WIDTH=16 ALT=\"Email\">";
+        $admindata[]="<A HREF=\"../files/index.php?id=$course->id\">Files</A>";
+        $adminicon[]="<IMG SRC=\"../files/pix/files.gif\" HEIGHT=16 WIDTH=16 ALT=\"Files\">";
+    }
+    print_side_block("Administration", $admindata, "", $adminicon);
+
+
+    // Start main column
+    echo "</TD><TD WIDTH=100%>";
+
+    // Now all the weekly modules
+
+
+    $timenow = time();
+    $weekdate = $course->startdate;    // this should be 0:00 Monday of that week
+    $week = 1;
+    $weekofseconds = 604800;
+
+    echo "<P><IMG SRC=\"../pix/spacer.gif\" WIDTH=100% HEIGHT=3><BR>";
+    echo "<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0 WIDTH=100%>";
+    echo "<TR><TD>";
+    echo "<B><FONT SIZE=2>Weekly Outline</FONT></B>\n";
+    
+    // Global switches
+    echo "</TD><TD NOWRAP ALIGN=RIGHT><P><FONT SIZE=1>";
+    if ($USER->teacher[$course->id]) {
+        if ($USER->editing) {
+            echo "<A HREF=\"view.php?id=$course->id&edit=off\">Turn editing off</A>";
+        } else {
+            echo "<A HREF=\"view.php?id=$course->id&edit=on\">Turn editing on</A>";
+        }
+    }
+    if ($USER->help) {
+        echo "&nbsp;&nbsp;&nbsp;<A HREF=\"view.php?id=$course->id&help=off\">Turn help off</A>";
+    } else {
+        echo "&nbsp;&nbsp;&nbsp;<A HREF=\"view.php?id=$course->id&help=on\">Turn help on</A>";
+    }
+    echo "</FONT></P></TD></TR></TABLE>";
+
+    echo "<TABLE BORDER=0 CELLPADDING=8 CELLSPACING=0 WIDTH=100%>";
+    while ($weekdate < $course->enddate) {
+        echo "<TR>";
+
+        $nextweekdate = $weekdate + ($weekofseconds);
+        $thisweek = (($weekdate <= $timenow) && ($timenow < $nextweekdate));
+
+        $weekday = date("j F", $weekdate);
+        $endweekday = date("j F", $weekdate+(6*24*3600));
+
+        if ($thisweek) {
+            $highlightcolor = $THEME->cellheading2;
+        } else {
+            $highlightcolor = $THEME->cellheading;
+        }
+
+        echo "<TD NOWRAP BGCOLOR=\"$highlightcolor\" VALIGN=top>";
+        echo "<P ALIGN=CENTER><FONT SIZE=3><B>$week</B></FONT></P>";
+        echo "</TD>";
+
+        echo "<TD VALIGN=top BGCOLOR=\"$THEME->cellcontent\">";
+        echo "<P><FONT SIZE=3 COLOR=\"$THEME->cellheading2\">$weekday - $endweekday</FONT></P>";
+
+        if (! $thisweek = $weeks[$week]) {
+            $thisweek->course = $course->id;   // Create a new week structure
+            $thisweek->week = $week;
+            $thisweek->summary = "";
+            $thisweek->id = insert_record("course_weeks", $thisweek);
+        }
+
+        if ($USER->editing) {
+            $thisweek->summary .= "&nbsp;<A HREF=editweek.php?id=$thisweek->id><IMG SRC=\"../pix/t/edit.gif\" BORDER=0 ALT=\"Edit summary\"></A></P>";
+        }
+
+        echo text_to_html($thisweek->summary);
+
+        echo "<P>";
+        if ($thisweek->sequence) {
+
+            $thisweekmods = explode(",", $thisweek->sequence);
+
+            foreach ($thisweekmods as $modnumber) {
+                $mod = $mods[$modnumber];
+                $instancename = get_field("$mod->modname", "name", "id", "$mod->instance");
+                echo "<IMG SRC=\"../mod/$mod->modname/icon.gif\" HEIGHT=16 WIDTH=16 ALT=\"$mod->modfullname\"> <A HREF=\"../mod/$mod->modname/view.php?id=$mod->id\">$instancename</A>";
+                if ($USER->editing) {
+                    echo make_editing_buttons($mod->id);
+                }
+                echo "<BR>\n";
+            }
+        }
+        echo "</UL></P>\n";
+
+        if ($USER->editing) {
+            echo "<DIV ALIGN=right>";
+            popup_form("$CFG->wwwroot/course/mod.php?id=$course->id&week=$week&add=", 
+                        $modtypes, "week$week", "", "Add...");
+            echo "</DIV>";
+        }
+
+        echo "</TD>";
+        echo "<TD NOWRAP BGCOLOR=\"$highlightcolor\" VALIGN=top>&nbsp;</TD>";
+        echo "</TR>";
+        echo "<TR><TD COLSPAN=3><IMG SRC=../pix/spacer.gif WIDTH=1 HEIGHT=1></TD></TR>";
+
+        $week++;
+        $weekdate = $nextweekdate;
+    }
+    echo "</TABLE>";
+    echo "</TABLE>";
+    
+
+    echo "</TD></TR></TABLE>";
+
+?>
diff --git a/doc/CHANGES b/doc/CHANGES
new file mode 100644 (file)
index 0000000..de3a654
--- /dev/null
@@ -0,0 +1,8 @@
+0.1
+---
+
+Starting to look more complete.
+Added news posting and email forwarding of news items.
+Changed listing of modules to A,B,C,D
+
+
diff --git a/doc/COPYRIGHT b/doc/COPYRIGHT
new file mode 100644 (file)
index 0000000..74c484d
--- /dev/null
@@ -0,0 +1,20 @@
+Moodle - Modular Object-Oriented Dynamic Learning Environment
+http://moodle.com
+
+Copyright (C) 2000, 2001  Martin Dougiamas  martin@dougiamas.com
+http://dougiamas.com
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+                
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
diff --git a/doc/INSTALL b/doc/INSTALL
new file mode 100644 (file)
index 0000000..871d481
--- /dev/null
@@ -0,0 +1,95 @@
+===========================================================================
+==  MOODLE
+== 
+==  OPEN-SOURCE SOFTWARE FOR INTERNET-BASED EDUCATION
+==
+==  Copyright (c) Martin Dougiamas, 2001 
+==
+==  Freely available under the GNU License
+==
+===========================================================================
+
+
+Directory structure
+===================
+
+config.php  - the only file you need to edit to get started
+
+lib         - libraries of core Moodle code
+
+user        - code to display and manage users
+course      - code to display and manage courses 
+login       - code to handle login and account creation
+admin       - code to administrate the whole server
+pix         - Generic site graphics are in here
+
+mod         - All Moodle modules are in here
+theme       - All Moodle themes are in here
+
+
+
+HOW TO INSTALL MOODLE
+=====================
+
+1.  SET UP A DATABASE
+
+    Create an empty database (eg "moodle") in your database system
+    along with a special user (eg "moodle") that has access to that 
+    database.  (Don't use the "root" user for the moodle database - 
+    it's a security hazard).
+
+    eg for MySQL under a Unix system:
+
+    # mysql -u root -p 
+    > CREATE DATABASE moodle;
+    > GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,ALTER ON moodle.* 
+      TO moodle@localhost IDENTIFIED BY 'yourpassword';
+    > quit
+    # mysqladmin -p reload
+
+
+2.  EDIT config.php
+    Edit the configuration file, putting in the database details that you 
+    just defined, as well as changing the site address and so on.
+
+    Make sure you specify what type of database you are using.
+
+    eg:
+
+    $CFG->wwwroot   = "http://example.com"; 
+    $CFG->dbtype    = "mysqlt";      // eg mysql, mysqlt, postgres ... etc
+    $CFG->dbhost    = "localhost";   // eg localhost 
+    $CFG->dbname    = "moodle";      // eg moodle
+    $CFG->dbuser    = "moodle";
+    $CFG->dbpass    = "yourpassword";
+    
+
+3.  GO TO THE ADMIN PAGE
+
+    The admin page should now be working at:  http://example.com/admin  
+
+    The first time you access this page, Moodle will automagically 
+    create all the tables it needs within your database.
+
+    You will then be asked to create an administration user for
+    future access to the admin pages..  
+    
+    All your further configuration of Moodle can now be done using the
+    administration web pages, including:
+      
+        - creating and deleting courses
+        - administering teacher accounts
+        - changing site-wide settings
+        - adding/deleting modules
+    
+    Configuration of each course is done by the teachers of that course.
+    See the teacher documentation for more information about that.
+    
+    Have fun and send me feedback so we can continue improving Moodle!
+        
+
+Cheers!
+
+Martin Dougiamas
+martin@moodle.com
diff --git a/doc/LICENCE b/doc/LICENCE
new file mode 100644 (file)
index 0000000..5d18622
--- /dev/null
@@ -0,0 +1,281 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
diff --git a/doc/NOTES b/doc/NOTES
new file mode 100644 (file)
index 0000000..b373186
--- /dev/null
+++ b/doc/NOTES
@@ -0,0 +1,3 @@
+weeks dates start from 0:00 Monday morning
+
+
diff --git a/doc/ROADMAP b/doc/ROADMAP
new file mode 100644 (file)
index 0000000..1096744
--- /dev/null
@@ -0,0 +1,15 @@
+Roadmap
+-------
+
+Here are some of the directions I would like to take
+Moodle now it has been released.
+
+- Code audit and clean up.  Standardise tabs, wordwrap.
+  Refactor a few bits.
+
+- Full internationalisation.  To start with I've hardcoded 
+  all the strings just to get things started and reduce 
+  obfuscation during development.  Modular "language packs"
+  need to implemented instead. eg using STPhp.
+
+
diff --git a/error/index.php b/error/index.php
new file mode 100644 (file)
index 0000000..5e48d3f
--- /dev/null
@@ -0,0 +1,37 @@
+<?PHP // $Id$
+
+    require("../config.php");
+
+    if (isset($text)) {    // form submitted
+        if (!$user = get_record("users", "id", 1)) {
+            error("Could not find the admin user to mail to!");
+        }
+
+        email_to_user($user, $USER, "Error: $referer -> $requested", "$text");
+
+        redirect("$CFG->wwwroot/course/", "Message sent, thanks", 3);
+        die;
+    }
+    
+    print_header("$CFG->sitename:Error", "$CFG->sitename: Error 404", "", "form.text");
+
+    add_to_log("Error: $HTTP_REFERER -> $REQUEST_URI");
+
+    print_simple_box("An unusual error occurred (tried to reach a page that doesn't exist).<P align=center>$REQUEST_URI", "center", "", "$THEME->cellheading");
+  
+?>
+  
+  <CENTER>
+  <P>If you have time, please let us know what you were trying 
+     to do when the error occurred:
+  <P><FORM action="<?=$CFG->wwwroot ?>/error/index.php" name=form method=post>
+     <TEXTAREA ROWS=3 COLS=50 NAME=text></TEXTAREA><BR>
+     <INPUT TYPE=hidden NAME=referer VALUE="<?=$HTTP_REFERER ?>">
+     <INPUT TYPE=hidden NAME=requested VALUE="<?=$REQUEST_URI ?>">
+     <INPUT TYPE=submit VALUE="Send this off">
+     </FORM>
+<?
+
+  print_footer();
+
+?>
diff --git a/file.php b/file.php
new file mode 100644 (file)
index 0000000..bd78762
--- /dev/null
+++ b/file.php
@@ -0,0 +1,43 @@
+<?PHP // $Id$
+      // This function fetches files from the data directory
+      // Syntax:   file.php/courseid/dir/.../dir/filename.ext
+
+    require("config.php");
+    require("files/mimetypes.php");
+
+    $lifetime = 86400;
+
+    if (!$PATH_INFO) {
+        error("This script DEPENDS on $PATH_INFO being available.  Read the README.");
+    }
+
+    $args = get_slash_arguments();
+    $numargs = count($args);
+
+    $courseid = (integer)$args[0];
+
+    if ($courseid > 0) {
+        require_login($courseid);
+    }
+
+    $pathname = "$CFG->dataroot$PATH_INFO";
+    $filename = $args[$numargs-1];
+
+    $mimetype = mimeinfo("type", $filename);
+
+    if (file_exists($pathname)) {
+        $lastmodified = filemtime($pathname);
+
+        header("Last-Modified: " . gmdate("D, d M Y H:i:s", $lastmodified) . " GMT");
+        header("Expires: " . gmdate("D, d M Y H:i:s", time() + $lifetime) . " GMT");
+        header("Cache-control: max_age = $lifetime"); // a day
+        header("Pragma: ");
+        header("Content-Length: ".filesize($pathname));
+        header("Content-type: $mimetype");
+        readfile("$pathname");
+    } else {
+        error("Sorry, but the file you are looking for was not found", "/course/view.php?id=$courseid");
+    }
+
+    exit;
+?>
diff --git a/files/index.php b/files/index.php
new file mode 100644 (file)
index 0000000..03cfc25
--- /dev/null
@@ -0,0 +1,646 @@
+<?PHP // $Id$
+
+//  Manage all uploaded files in a course file area
+
+//  All the Moodle-specific stuff is in this top section
+//  Configuration and access control occurs here.
+//  Must define:  USER, basedir, baseweb, html_header and html_footer
+//  USER is a persistent variable using sessions
+
+    require("../config.php");
+
+    require_variable($id);
+
+    if (! $course = get_record("course", "id", $id) ) {
+        error("That's an invalid course id");
+    }
+
+    require_login($course->id);
+    add_to_log("Files area", $course->id);
+
+    if (! isteacher($course->id) ) {
+        error("Only teachers can edit files");
+    }
+
+    function html_footer() {
+        global $course;
+        echo "</td></tr></table></body></html>";
+        print_footer($course);
+    }
+    
+    function html_header($formfield=""){
+        global $course;
+    
+        print_header("$course->shortname: Files", "$course->shortname: Files", 
+                    "<A HREF=\"../course/view.php?id=$course->id\">$course->shortname</A> -> Files", $formfield);
+        echo "<table border=0 align=center cellspacing=3 cellpadding=3 width=640>";
+        echo "<tr>";
+        echo "<td colspan=\"2\">";
+    }
+
+    if (! file_exists($CFG->dataroot)) {
+        if (! mkdir($CFG->dataroot, 0750)) {
+            error("You need to create the directory $CFG->dataroot with web server write access");
+        }
+    }
+    $basedir = "$CFG->dataroot/$course->id";
+
+    if (! file_exists($basedir)) {
+        if (! mkdir($basedir, 0750)) {
+            error("Could not create a directory for this course ($basedir)");
+        }
+    }
+    $baseweb = $CFG->wwwroot;
+
+//  End of configuration and access control
+
+
+    require("mimetypes.php");
+
+    $regexp="\\.\\.";
+    if (ereg( $regexp, $file, $regs )| ereg( $regexp, $wdir,$regs )) {           
+        $message = "Error: Directories can not contain \"..\"";
+        $wdir = "/";
+        $action = "";
+    }    
+
+
+    if (!match_referer("$baseweb/files/index.php")) {   // To stop spoofing 
+        $action="cancel";
+        $wdir="/";
+    }
+
+    if (!$wdir) {
+        $wdir="/";
+    }
+
+
+
+    switch ($action) {
+
+        case "upload":
+            html_header();
+            if ($save) {
+                if ($userfile == "none" || $userfile_size==0) {
+                    echo "<P>Error: That was not a valid file.";
+                } else {
+                    $userfile_name = clean_filename($userfile_name);
+                    if ($userfile_name != "") {
+                        $newfile = "$basedir$wdir/$userfile_name";
+                        copy ($userfile, $newfile); 
+                        chmod ($newfile, 0750);
+                        echo "Uploaded $userfile_name ($userfile_type) to $wdir";
+                    }
+                }
+                displaydir($wdir);
+                    
+            } else {
+                echo "<P>Upload a file into <B>$wdir</B>:";
+                echo "<TABLE><TR><TD COLSPAN=2>";
+                echo "<FORM ENCTYPE=\"multipart/form-data\" METHOD=\"post\" ACTION=index.php>";
+                echo " <INPUT TYPE=hidden NAME=MAX_FILE_SIZE value=5000000>";
+                echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+                echo " <INPUT TYPE=hidden NAME=wdir VALUE=$wdir>";
+                echo " <INPUT TYPE=hidden NAME=action VALUE=upload>";
+                echo " <INPUT NAME=\"userfile\" TYPE=\"file\" size=\"50\">";
+                echo " </TD><TR><TD WIDTH=10>";
+                echo " <INPUT TYPE=submit NAME=save VALUE=\"Upload this file\">";
+                echo "</FORM>";
+                echo "</TD><TD WIDTH=100%>";
+                echo "<FORM ACTION=index.php METHOD=get>";
+                echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+                echo " <INPUT TYPE=hidden NAME=wdir VALUE=$wdir>";
+                echo " <INPUT TYPE=hidden NAME=action VALUE=cancel>";
+                echo " <INPUT TYPE=submit VALUE=\"Cancel\">";
+                echo "</FORM>";
+                echo "</TD></TR></TABLE>";
+            }
+            html_footer();
+            break;
+
+        case "delete":
+            if ($confirm) {
+                html_header();
+                foreach ($USER->filelist as $file) {
+                    $fullfile = $basedir.$file;
+                    if (! fulldelete($fullfile)) {
+                        echo "<BR>Error: Could not delete: $fullfile";
+                    }
+                }
+                clearfilelist();
+                displaydir($wdir);
+                html_footer();
+
+            } else {
+                html_header();
+                if (setfilelist($HTTP_POST_VARS)) {
+                    echo "<P ALIGN=CENTER>You are about to delete:</P>";
+                    print_simple_box_start("center");
+                    printfilelist($USER->filelist);
+                    print_simple_box_end();
+                    echo "<BR>";
+                    notice_yesno ("Are you sure you want to delete these?", 
+                                "index.php?id=$id&wdir=$wdir&action=delete&confirm=1",
+                                "index.php?id=$id&wdir=$wdir&action=cancel");
+                } else {
+                    displaydir($wdir);
+                }
+                html_footer();
+            }
+            break;
+
+        case "move":
+            html_header();
+            if ($count = setfilelist($HTTP_POST_VARS)) {
+                $USER->fileop     = $action;
+                $USER->filesource = $wdir;
+                echo "<P align=center>$count files selected for moving. Now go to the destination and press \"Move files to here\".</P>";
+            }
+            displaydir($wdir);
+            html_footer();
+            break;
+
+        case "paste":
+            html_header();
+            if ($USER->fileop == "move") {
+                foreach ($USER->filelist as $file) {
+                    $shortfile = basename($file);
+                    $oldfile = $basedir.$file;
+                    $newfile = $basedir.$wdir."/".$shortfile;
+                    if (!rename($oldfile, $newfile)) {
+                        echo "<P>Error: $shortfile not moved";
+                    }
+                }
+            }
+            clearfilelist();
+            displaydir($wdir);
+            html_footer();
+            break;
+
+        case "rename":
+            if ($name) {
+                html_header();
+                $name = clean_filename($name);
+                if (file_exists($basedir.$wdir."/".$name)) {
+                    echo "Error: $name already exists!";
+                } else if (!rename($basedir.$wdir."/".$oldname, $basedir.$wdir."/".$name)) {
+                    echo "Error: could not rename $oldname to $name";
+                }
+                displaydir($wdir);
+                    
+            } else {
+                html_header("form.name");
+                echo "<P>Rename <B>$file</B> to:";
+                echo "<TABLE><TR><TD>";
+                echo "<FORM ACTION=index.php METHOD=post NAME=form>";
+                echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+                echo " <INPUT TYPE=hidden NAME=wdir VALUE=$wdir>";
+                echo " <INPUT TYPE=hidden NAME=action VALUE=rename>";
+                echo " <INPUT TYPE=hidden NAME=oldname VALUE=\"$file\">";
+                echo " <INPUT TYPE=text NAME=name SIZE=35 VALUE=\"$file\">";
+                echo " <INPUT TYPE=submit VALUE=\"Rename\">";
+                echo "</FORM>";
+                echo "</TD><TD>";
+                echo "<FORM ACTION=index.php METHOD=get>";
+                echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+                echo " <INPUT TYPE=hidden NAME=wdir VALUE=$wdir>";
+                echo " <INPUT TYPE=hidden NAME=action VALUE=cancel>";
+                echo " <INPUT TYPE=submit VALUE=\"Cancel\">";
+                echo "</FORM>";
+                echo "</TD></TR></TABLE>";
+            }
+            html_footer();
+            break;
+
+        case "mkdir":
+            if ($name) {
+                html_header();
+                $name = clean_filename($name);
+                if (file_exists($basedir.$wdir."/".$name)) {
+                    echo "Error: $name already exists!";
+                } else if (!mkdir($basedir.$wdir."/".$name, 0750)) {
+                    echo "Error: could not create $name";
+                }
+                displaydir($wdir);
+                    
+            } else {
+                html_header("form.name");
+                echo "<P>Create folder in $wdir:";
+                echo "<TABLE><TR><TD>";
+                echo "<FORM ACTION=index.php METHOD=post NAME=form>";
+                echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+                echo " <INPUT TYPE=hidden NAME=wdir VALUE=$wdir>";
+                echo " <INPUT TYPE=hidden NAME=action VALUE=mkdir>";
+                echo " <INPUT TYPE=text NAME=name SIZE=35>";
+                echo " <INPUT TYPE=submit VALUE=\"Create\">";
+                echo "</FORM>";
+                echo "</TD><TD>";
+                echo "<FORM ACTION=index.php METHOD=get>";
+                echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+                echo " <INPUT TYPE=hidden NAME=wdir VALUE=$wdir>";
+                echo " <INPUT TYPE=hidden NAME=action VALUE=cancel>";
+                echo " <INPUT TYPE=submit VALUE=\"Cancel\">";
+                echo "</FORM>";
+                echo "</TD></TR></TABLE>";
+            }
+            html_footer();
+            break;
+
+        case "edit":
+            html_header();
+            if (isset($text)) {
+                $fileptr = fopen($basedir.$file,"w");
+                fputs($fileptr, stripslashes($text));
+                fclose($fileptr);
+                displaydir($wdir);
+                    
+            } else {
+                $fileptr  = fopen($basedir.$file, "r");
+                $contents = fread($fileptr, filesize($basedir.$file));
+                fclose($fileptr);
+
+                echo "<P>Editing <B>$file</B>:";
+                echo "<TABLE><TR><TD COLSPAN=2>";
+                echo "<FORM ACTION=index.php METHOD=post NAME=form>";
+                echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+                echo " <INPUT TYPE=hidden NAME=wdir VALUE=\"$wdir\">";
+                echo " <INPUT TYPE=hidden NAME=file VALUE=\"$file\">";
+                echo " <INPUT TYPE=hidden NAME=action VALUE=edit>";
+                echo "<TEXTAREA ROWS=20 COLS=60 NAME=text>";
+                echo htmlspecialchars($contents);
+                echo "</TEXTAREA>";
+                echo "</TD></TR><TR><TD>";
+                echo " <INPUT TYPE=submit VALUE=\"Save changes\">";
+                echo "</FORM>";
+                echo "</TD><TD>";
+                echo "<FORM ACTION=index.php METHOD=get>";
+                echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+                echo " <INPUT TYPE=hidden NAME=wdir VALUE=$wdir>";
+                echo " <INPUT TYPE=hidden NAME=action VALUE=cancel>";
+                echo " <INPUT TYPE=submit VALUE=\"Cancel\">";
+                echo "</FORM>";
+                echo "</TD></TR></TABLE>";
+            }
+            html_footer();
+            break;
+
+        case "zip":
+            if ($name) {
+                html_header();
+                $name = clean_filename($name);
+                $files = "";
+                foreach ($USER->filelist as $file) {
+                    $files .= basename($file);
+                    $files .= " ";
+                }
+                $command = "cd $basedir/$wdir ; /usr/bin/zip -r $name $files";
+                Exec($command);
+                clearfilelist();
+                displaydir($wdir);
+                    
+            } else {
+                html_header("form.name");
+                if (setfilelist($HTTP_POST_VARS)) {
+                    echo "<P ALIGN=CENTER>You are about create a zip file containing:</P>";
+                    print_simple_box_start("center");
+                    printfilelist($USER->filelist);
+                    print_simple_box_end();
+                    echo "<BR>";
+                    echo "<P ALIGN=CENTER>What do you want to call the zip file?";
+                    echo "<TABLE><TR><TD>";
+                    echo "<FORM ACTION=index.php METHOD=post NAME=form>";
+                    echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+                    echo " <INPUT TYPE=hidden NAME=wdir VALUE=\"$wdir\">";
+                    echo " <INPUT TYPE=hidden NAME=action VALUE=zip>";
+                    echo " <INPUT TYPE=text NAME=name SIZE=35 VALUE=\"new.zip\">";
+                    echo " <INPUT TYPE=submit VALUE=\"Create zip file\">";
+                    echo "</FORM>";
+                    echo "</TD><TD>";
+                    echo "<FORM ACTION=index.php METHOD=get>";
+                    echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+                    echo " <INPUT TYPE=hidden NAME=wdir VALUE=$wdir>";
+                    echo " <INPUT TYPE=hidden NAME=action VALUE=cancel>";
+                    echo " <INPUT TYPE=submit VALUE=\"Cancel\">";
+                    echo "</FORM>";
+                    echo "</TD></TR></TABLE>";
+                } else {
+                    displaydir($wdir);
+                    clearfilelist();
+                }
+            }
+            html_footer();
+            break;
+
+        case "unzip":
+            html_header();
+            if ($file) {
+                echo "<P ALIGN=CENTER>Unzipping $file:</P>";
+                print_simple_box_start("center");
+                echo "<PRE>";
+                $file = basename($file);
+                $command = "cd $basedir/$wdir ; /usr/bin/unzip -o $file 2>&1";
+                passthru($command);
+                echo "</PRE>";
+                print_simple_box_end();
+                echo "<CENTER><FORM ACTION=index.php METHOD=get>";
+                echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+                echo " <INPUT TYPE=hidden NAME=wdir VALUE=$wdir>";
+                echo " <INPUT TYPE=hidden NAME=action VALUE=cancel>";
+                echo " <INPUT TYPE=submit VALUE=\"OK\">";
+                echo "</FORM>";
+                echo "</CENTER>";
+            } else {
+                displaydir($wdir);
+            }
+            html_footer();
+            break;
+
+        case "cancel";
+            clearfilelist();
+
+        default:
+            html_header();
+            displaydir($wdir);
+            html_footer();
+            break;
+}
+
+
+/// FILE FUNCTIONS ///////////////////////////////////////////////////////////
+
+
+function fulldelete($location) { 
+    if (is_dir($location)) {
+        $currdir = opendir($location);
+        while ($file = readdir($currdir)) { 
+            if ($file <> ".." && $file <> ".") {
+                $fullfile = $location."/".$file;
+                if (is_dir($fullfile)) { 
+                    if (!fulldelete($fullfile)) {
+                        return false;
+                    }
+                } else {
+                    if (!unlink($fullfile)) {
+                        return false;
+                    }
+                } 
+            }
+        } 
+        closedir($currdir);
+        if (! rmdir($location)) {
+            return false;
+        }
+
+    } else {
+        if (!unlink($location)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+function clean_filename($string) {
+    $string = eregi_replace("\.\.", "", $string);
+    $string = eregi_replace("[^([:alnum:]|\.)]", "_", $string);
+    return    eregi_replace("_+", "_", $string);
+}
+
+
+
+function setfilelist($VARS) {
+    global $USER;
+
+    $USER->filelist = array ();
+    $USER->fileop = "";
+
+    $count = 0;
+    foreach ($VARS as $key => $val) {
+        if (substr($key,0,4) == "file") {
+            $count++;
+            $USER->filelist[] = rawurldecode($val);
+        }
+    }
+
+    return $count;
+}
+
+function clearfilelist() {
+    global $USER;
+
+    $USER->filelist = array ();
+    $USER->fileop = "";
+}
+
+
+function printfilelist($filelist) {
+    global $basedir;
+
+    foreach ($filelist as $file) {
+        if (is_dir($basedir.$file)) {
+            echo "<IMG SRC=\"pix/folder.gif\" HEIGHT=16 WIDTH=16> $file<BR>";
+            $subfilelist = array();
+            $currdir = opendir($basedir.$file);
+            while ($subfile = readdir($currdir)) { 
+                if ($subfile <> ".." && $subfile <> ".") {
+                    $subfilelist[] = $file."/".$subfile;
+                }
+            }
+            printfilelist($subfilelist);
+
+        } else { 
+            $icon = mimeinfo("icon", $file);
+            echo "<IMG SRC=\"pix/$icon\"  HEIGHT=16 WIDTH=16> $file<BR>";
+        }
+    }
+}
+
+
+function display_size($file) {
+    $file_size = filesize($file);
+    if ($file_size >= 1073741824) {
+        $file_size = round($file_size / 1073741824 * 100) / 100 . "g";
+    } else if ($file_size >= 1048576) {
+        $file_size = round($file_size / 1048576 * 100) / 100 . "m";
+    } else if ($file_size >= 1024) {
+        $file_size = round($file_size / 1024 * 100) / 100 . "k";
+    } else { 
+        $file_size = $file_size . "b";
+    }
+    return $file_size;
+}
+
+
+function print_cell($alignment="center", $text="&nbsp;") {
+    echo "<TD ALIGN=\"$alignment\" NOWRAP>";
+    echo "<FONT SIZE=\"-1\" FACE=\"Arial, Helvetica\">";
+    echo "$text";
+    echo "</FONT>";
+    echo "</TD>\n";
+}
+
+function displaydir ($wdir) {
+//  $wdir == / or /a or /a/b/c/d  etc
+
+    global $basedir;
+    global $id;
+    global $USER;
+
+    $fullpath = $basedir.$wdir;
+
+    $directory = opendir($fullpath);             // Find all files
+    while ($file = readdir($directory)) {
+        if ($file == "." || $file == "..") {
+            continue;
+        }
+        
+        if (is_dir($fullpath."/".$file)) {
+            $dirlist[] = $file;
+        } else {
+            $filelist[] = $file;
+        }
+    }
+    closedir($directory);
+
+
+    echo "<FORM ACTION=\"index.php\" METHOD=post NAME=dirform>";
+    echo "<HR WIDTH=640 ALIGN=CENTER NOSHADE SIZE=1>";
+    echo "<TABLE BORDER=0 cellspacing=2 cellpadding=2 width=640>";    
+    echo "<TR><TD>&nbsp;</TD><TD COLSPAN=5><P><B>Current folder: $wdir</B></P>";
+    echo "<TR>";
+    echo "<TH WIDTH=5></TH>";
+    echo "<TH ALIGN=left>Name</TH>";
+    echo "<TH ALIGN=right>Size</TH>";
+    echo "<TH ALIGN=right>Modified</TH>";
+    echo "<TH ALIGN=right>Action</TH>";
+    echo "</TR>\n";
+
+    if ($wdir == "/") {
+        $wdir = "";
+    } else {
+        $updir = dirname($wdir);
+        echo "<TR>";
+        print_cell("center", "");
+        print_cell("left", "<A HREF=\"index.php?id=$id&wdir=$updir\"><IMG SRC=\"pix/parent.gif\" HEIGHT=16 WIDTH=16 BORDER=0 ALT=\"Parent folder\"></A> <A HREF=\"index.php?id=$id&wdir=$updir\">Up to $updir</A>");
+        echo "</TR>\n";
+    }
+
+
+    $count = 0;
+
+    if ($dirlist) {
+        asort($dirlist);
+        foreach ($dirlist as $dir) {
+
+            $count++;
+
+            $filename = $fullpath."/".$dir;
+            $fileurl  = rawurlencode($wdir."/".$dir);
+            $filesafe = rawurlencode($dir);
+            $filedate = date("d-m-Y H:i:s", filectime($filename));
+    
+            echo "<TR>";
+
+            print_cell("center", "<INPUT TYPE=checkbox NAME=\"file$count\" VALUE=\"$fileurl\">");
+            print_cell("left", "<A HREF=\"index.php?id=$id&wdir=$fileurl\"><IMG SRC=\"pix/folder.gif\" HEIGHT=16 WIDTH=16 BORDER=0 ALT=\"Folder\"></A> <A HREF=\"index.php?id=$id&wdir=$fileurl\">".htmlspecialchars($dir)."</A>");
+            print_cell("right", "-");
+            print_cell("right", $filedate);
+            print_cell("right", "<A HREF=\"index.php?id=$id&wdir=$wdir&file=$filesafe&action=rename\">rename</A>");
+    
+            echo "</TR>";
+        }
+    }
+
+
+    if ($filelist) {
+        asort($filelist);
+        foreach ($filelist as $file) {
+
+            $icon = mimeinfo("icon", $file);
+
+            $count++;
+            $filename    = $fullpath."/".$file;
+            $fileurl     = "$wdir/$file";
+            $filesafe    = rawurlencode($file);
+            $fileurlsafe = rawurlencode($fileurl);
+            $filedate    = date("d-m-Y H:i:s", filectime($filename));
+
+            echo "<TR>";
+
+            print_cell("center", "<INPUT TYPE=checkbox NAME=\"file$count\" VALUE=\"$fileurl\">");
+            echo "<TD ALIGN=left NOWRAP>";
+            link_to_popup_window ("/file.php/$id$fileurl", "display", 
+                                  "<IMG SRC=\"pix/$icon\" HEIGHT=16 WIDTH=16 BORDER=0 ALT=\"File\">", 
+                                  480, 640);
+            echo "<FONT SIZE=\"-1\" FACE=\"Arial, Helvetica\">";
+            link_to_popup_window ("/file.php/$id$fileurl", "display", 
+                                  htmlspecialchars($file),
+                                  480, 640);
+            echo "</FONT></TD>";
+
+            print_cell("right", display_size($filename));
+            print_cell("right", $filedate);
+            if ($icon == "text.gif" || $icon == "html.gif") {
+                $edittext = "<A HREF=\"index.php?id=$id&wdir=$wdir&file=$fileurl&action=edit\">edit</A>";
+            } else if ($icon == "zip.gif") {
+                $edittext = "<A HREF=\"index.php?id=$id&wdir=$wdir&file=$fileurl&action=unzip\">unzip</A>";
+            } else {
+                $edittext = "";
+            }
+            print_cell("right", "$edittext <A HREF=\"index.php?id=$id&wdir=$wdir&file=$filesafe&action=rename\">rename</A>");
+    
+            echo "</TR>";
+        }
+    }
+    echo "</TABLE>";
+    echo "<HR WIDTH=640 ALIGN=CENTER NOSHADE SIZE=1>";
+
+    if (!$wdir) {
+        $wdir = "/";
+    }
+
+    echo "<TABLE BORDER=0 cellspacing=2 cellpadding=2 width=640>";    
+    echo "<TR><TD>";
+    echo "<INPUT TYPE=hidden NAME=id VALUE=\"$id\">";
+    echo "<INPUT TYPE=hidden NAME=wdir VALUE=\"$wdir\"> ";
+    $options = array (
+                   "move" => "Move to another folder",
+                   "delete" => "Delete completely",
+                   "zip" => "Create zip archive"
+               );
+    if ($count) {
+        choose_from_menu ($options, "action", "", $nothing="With chosen files...", "javascript:document.dirform.submit()");
+        //echo "<INPUT TYPE=submit VALUE=Go>";
+    }
+
+    echo "</FORM>";
+    echo "<TD ALIGN=center>";
+    if (($USER->fileop == "move") && $USER->filesource <> $wdir) {
+        echo "<FORM ACTION=index.php METHOD=get>";
+        echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+        echo " <INPUT TYPE=hidden NAME=wdir VALUE=\"$wdir\">";
+        echo " <INPUT TYPE=hidden NAME=action VALUE=paste>";
+        echo " <INPUT TYPE=submit VALUE=\"Move files to here\">";
+        echo "</FORM>";
+    }
+    echo "<TD ALIGN=right>";
+        echo "<FORM ACTION=index.php METHOD=get>";
+        echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+        echo " <INPUT TYPE=hidden NAME=wdir VALUE=\"$wdir\">";
+        echo " <INPUT TYPE=hidden NAME=action VALUE=mkdir>";
+        echo " <INPUT TYPE=submit VALUE=\"Make a folder\">";
+        echo "</FORM>";
+    echo "</TD>";
+    echo "<TD ALIGN=right>";
+        echo "<FORM ACTION=index.php METHOD=get>";
+        echo " <INPUT TYPE=hidden NAME=id VALUE=$id>";
+        echo " <INPUT TYPE=hidden NAME=wdir VALUE=\"$wdir\">";
+        echo " <INPUT TYPE=hidden NAME=action VALUE=upload>";
+        echo " <INPUT TYPE=submit VALUE=\"Upload a file\">";
+        echo "</FORM>";
+    echo "</TD></TR>";
+    echo "</TABLE>";
+    echo "<HR WIDTH=640 ALIGN=CENTER NOSHADE SIZE=1>";
+
+}
+
+?>
diff --git a/files/mimetypes.php b/files/mimetypes.php
new file mode 100644 (file)
index 0000000..1c0826a
--- /dev/null
@@ -0,0 +1,37 @@
+<? // $Id$
+
+    $mimeinfo = array (
+        "xxx"  => array ("type"=>"document/unknown", "icon"=>"unknown.gif"),
+        "zip"  => array ("type"=>"application/zip", "icon"=>"zip.gif"),
+        "jpeg" => array ("type"=>"image/jpeg", "icon"=>"image.gif"),
+        "jpg"  => array ("type"=>"image/jpeg", "icon"=>"image.gif"),
+        "gif"  => array ("type"=>"image/gif", "icon"=>"image.gif"),
+        "png"  => array ("type"=>"image/png", "icon"=>"image.gif"),
+        "bmp"  => array ("type"=>"image/bmp", "icon"=>"image.gif"),
+        "html" => array ("type"=>"text/html", "icon"=>"html.gif"),
+        "htm"  => array ("type"=>"text/html", "icon"=>"html.gif"),
+        "txt"  => array ("type"=>"text/plain", "icon"=>"text.gif"),
+        "wav"  => array ("type"=>"audio/wav", "icon"=>"audio.gif"),
+        "mp3"  => array ("type"=>"audio/mp3", "icon"=>"audio.gif"),
+        "au"   => array ("type"=>"audio/au", "icon"=>"audio.gif"),
+        "swf"  => array ("type"=>"application/x-shockwave-flash", "icon"=>"image.gif"),
+        "pdf"  => array ("type"=>"application/pdf", "icon"=>"pdf.gif"),
+        "doc"  => array ("type"=>"application/msword", "icon"=>"word.gif"),
+        "xls"  => array ("type"=>"application/vnd.ms-excel", "icon"=>"excel.gif")
+    );
+
+function mimeinfo($element, $filename) {
+    global $mimeinfo;
+
+    if (eregi("\.([a-z0-9]+)$", $filename, $match)) {
+        $result = $mimeinfo[strtolower($match[1])][$element];
+    }
+
+    if ($result) {
+        return $result;
+    } else {
+        return $mimeinfo["xxx"][$element];   // By default
+    }
+}
+
+?>
diff --git a/files/pix/audio.gif b/files/pix/audio.gif
new file mode 100755 (executable)
index 0000000..7b4e7cc
Binary files /dev/null and b/files/pix/audio.gif differ
diff --git a/files/pix/edit.gif b/files/pix/edit.gif
new file mode 100644 (file)
index 0000000..cd3aaec
Binary files /dev/null and b/files/pix/edit.gif differ
diff --git a/files/pix/env.gif b/files/pix/env.gif
new file mode 100644 (file)
index 0000000..3f82213
Binary files /dev/null and b/files/pix/env.gif differ
diff --git a/files/pix/excel.gif b/files/pix/excel.gif
new file mode 100644 (file)
index 0000000..86c5e13
Binary files /dev/null and b/files/pix/excel.gif differ
diff --git a/files/pix/explore.gif b/files/pix/explore.gif
new file mode 100644 (file)
index 0000000..a19c9be
Binary files /dev/null and b/files/pix/explore.gif differ
diff --git a/files/pix/files.gif b/files/pix/files.gif
new file mode 100755 (executable)
index 0000000..fee2f9a
Binary files /dev/null and b/files/pix/files.gif differ
diff --git a/files/pix/folder.gif b/files/pix/folder.gif
new file mode 100755 (executable)
index 0000000..4e18389
Binary files /dev/null and b/files/pix/folder.gif differ
diff --git a/files/pix/help.gif b/files/pix/help.gif
new file mode 100644 (file)
index 0000000..1600716
Binary files /dev/null and b/files/pix/help.gif differ
diff --git a/files/pix/html.gif b/files/pix/html.gif
new file mode 100644 (file)
index 0000000..550df5d
Binary files /dev/null and b/files/pix/html.gif differ
diff --git a/files/pix/image.gif b/files/pix/image.gif
new file mode 100644 (file)
index 0000000..deb1347
Binary files /dev/null and b/files/pix/image.gif differ
diff --git a/files/pix/move.gif b/files/pix/move.gif
new file mode 100644 (file)
index 0000000..776d89e
Binary files /dev/null and b/files/pix/move.gif differ
diff --git a/files/pix/parent.gif b/files/pix/parent.gif
new file mode 100755 (executable)
index 0000000..885b2f9
Binary files /dev/null and b/files/pix/parent.gif differ
diff --git a/files/pix/pdf.gif b/files/pix/pdf.gif
new file mode 100644 (file)
index 0000000..fbead2f
Binary files /dev/null and b/files/pix/pdf.gif differ
diff --git a/files/pix/text.gif b/files/pix/text.gif
new file mode 100644 (file)
index 0000000..dc681dd
Binary files /dev/null and b/files/pix/text.gif differ
diff --git a/files/pix/unknown.gif b/files/pix/unknown.gif
new file mode 100644 (file)
index 0000000..fd34f38
Binary files /dev/null and b/files/pix/unknown.gif differ
diff --git a/files/pix/word.gif b/files/pix/word.gif
new file mode 100644 (file)
index 0000000..ca4feca
Binary files /dev/null and b/files/pix/word.gif differ
diff --git a/files/pix/zip.gif b/files/pix/zip.gif
new file mode 100755 (executable)
index 0000000..854946f
Binary files /dev/null and b/files/pix/zip.gif differ
diff --git a/index.php b/index.php
new file mode 100644 (file)
index 0000000..a54aa6b
--- /dev/null
+++ b/index.php
@@ -0,0 +1,50 @@
+<?  // $Id$
+    // index.php - the front page.
+    
+    require("config.php");
+
+    if (! $site = get_record("course", "category", 0)) {
+        redirect("$CFG->wwwroot/admin/");
+    }
+
+    print_header("$site->fullname", "$site->fullname", "", "");
+
+?>
+
+<TABLE WIDTH="100%" BORDER="0" CELLSPACING="5" CELLPADDING="5">
+  <TR>
+    <TD WIDTH="15%" VALIGN="TOP" NOWRAP>
+      <? print_simple_box("Main Menu", $align="CENTER", $width="100%", $color="$THEME->cellheading"); ?>
+
+         <LI>Home</LI>
+      <LI><A TITLE="Available courses on this server" HREF="course/">Courses</A></LI>
+
+      <? include("mod/reading/lib.php"); 
+         list_all_readings();
+      ?>
+
+    </TD>
+
+    <TD WIDTH="55%" VALIGN="TOP">
+      <? print_simple_box("Site News", $align="CENTER", $width="100%", $color="$THEME->cellheading"); ?>
+
+      <BR>
+
+      <? include("mod/discuss/lib.php");
+         forum_latest_topics();
+      ?>
+    
+    </TD>
+    <TD WIDTH="30%" VALIGN="TOP"> 
+      <? print_simple_box($site->summary, $align="", $width="100%", $color="$THEME->cellheading"); ?>
+    </TD>
+  </TR>
+</TABLE>
+
+<HR SIZE=1 NOSHADE>
+
+
+<P ALIGN=center>
+<A WIDTH=85 HEIGHT=25 HREF="http://moodle.com/"><IMG SRC="pix/madewithmoodle.gif" BORDER=0></A>
+</P>
+
diff --git a/lib/class.phpmailer.php b/lib/class.phpmailer.php
new file mode 100644 (file)
index 0000000..2a5bc36
--- /dev/null
@@ -0,0 +1,983 @@
+<?php
+////////////////////////////////////////////////////
+// phpmailer - PHP email class
+//
+// Version 1.25, Created 07/02/2001
+//
+// Class for sending email using either
+// sendmail, PHP mail(), or SMTP.  Methods are
+// based upon the standard AspEmail(tm) classes.
+//
+// Author: Brent R. Matzelle <bmatzelle@yahoo.com>
+//
+// License: LGPL, see LICENSE
+////////////////////////////////////////////////////
+
+/**
+ * phpmailer - PHP email transport class
+ * @author Brent R. Matzelle
+ */
+class phpmailer
+{
+   /////////////////////////////////////////////////
+   // PUBLIC VARIABLES
+   /////////////////////////////////////////////////
+
+   /**
+    * Email priority (1 = High, 3 = Normal, 5 = low). Default value is 3.
+    * @public
+    * @type int
+    */
+   var $Priority         = 3;
+
+   /**
+    * Sets the CharSet of the message. Default value is "iso-8859-1".
+    * @public
+    * @type string
+    */
+   var $CharSet          = "iso-8859-1";
+
+   /**
+    * Sets the Content-type of the message. Default value is "text/plain".
+    * @public
+    * @type string
+    */
+   var $ContentType      = "text/plain";
+
+   /**
+    * Sets the Encoding of the message. Options for this are "8bit" (default),
+    * "7bit", "binary", "base64", and "quoted-printable".
+    * @public
+    * @type string
+    */
+   var $Encoding         = "8bit";
+
+   /**
+    * Holds the most recent mailer error message. Default value is "".
+    * @public
+    * @type string
+    */
+   var $ErrorInfo        = "";
+
+   /**
+    * Sets the From email of the message. Default value is "root@localhost".
+    * @public
+    * @type string
+    */
+   var $From             = "root@localhost";
+
+   /**
+    * Sets the From name of the message. Default value is "Root User".
+    * @public
+    * @type string
+    */
+   var $FromName         = "Root User";
+
+   /**
+    * Sets the Sender email of the message. If not empty, will be sent via -f to sendmail
+    * or as 'MAIL FROM' in smtp mode. Default value is "".
+    * @public
+    * @type string
+    */
+   var $Sender           = "";
+
+   /**
+    * Sets the Subject of the message. Default value is "".
+    * @public
+    * @type string
+    */
+   var $Subject          = "";
+
+   /**
+    * Sets the Body of the message. Default value is "".
+    * @public
+    * @type string
+    */
+   var $Body             = "";
+
+   /**
+    * Sets word wrapping on the message. Default value is false (off).
+    * @public
+    * @type string
+    */
+   var $WordWrap         = false;
+
+   /**
+    * Method to send mail: ("mail", "sendmail", or "smtp").
+    * Default value is "mail".
+    * @public
+    * @type string
+    */
+   var $Mailer           = "mail";
+
+   /**
+    * Sets the path of the sendmail program. Default value is
+    * "/usr/sbin/sendmail".
+    * @public
+    * @type string
+    */
+   var $Sendmail         = "/usr/sbin/sendmail";
+
+   /**
+    *  Turns Microsoft mail client headers on and off. Default value is false (off).
+    *  @public
+    *  @type bool
+    */
+   var $UseMSMailHeaders = false;
+
+   /**
+    *  Holds phpmailer version.
+    *  @public
+    *  @type string
+    */
+   var $Version       = "phpmailer [version 1.25]";
+
+
+   /////////////////////////////////////////////////
+   // SMTP VARIABLES
+   /////////////////////////////////////////////////
+
+   /**
+    *  Sets the SMTP host. Default value is "localhost".
+    *  @public
+    *  @type string
+    */
+   var $Host        = "localhost";
+
+   /**
+    *  Sets the SMTP server port. Default value is 25.
+    *  @public
+    *  @type int
+    */
+   var $Port        = 25;
+
+   /**
+    *  Sets the CharSet of the message. Default value is "localhost.localdomain".
+    *  @public
+    *  @type string
+    */
+   var $Helo        = "localhost.localdomain";
+
+   /**
+    *  Sets the SMTP server timeout. Default value is 10.
+    *  @public
+    *  @type int
+    */
+   var $Timeout     = 10; // Socket timeout in sec.
+
+   /**
+    *  Sets SMTP class debugging on or off. Default value is false (off).
+    *  @public
+    *  @type bool
+    */
+   var $SMTPDebug   = false;
+
+
+   /////////////////////////////////////////////////
+   // PRIVATE VARIABLES
+   /////////////////////////////////////////////////
+
+   /**
+    *  Holds all "To" addresses.
+    *  @type array
+    */
+   var $to            = array();
+
+   /**
+    *  Holds all "CC" addresses.
+    *  @type array
+    */
+   var $cc            = array();
+
+   /**
+    *  Holds all "BCC" addresses.
+    *  @type array
+    */
+   var $bcc           = array();
+
+   /**
+    *  Holds all "Reply-To" addresses.
+    *  @type array
+    */
+   var $ReplyTo       = array();
+
+   /**
+    *  Holds all attachments.
+    *  @type array
+    */
+   var $attachment    = array();
+
+   /**
+    *  Holds all custom headers.
+    *  @type array
+    */
+   var $CustomHeader  = array();
+
+   /**
+    *  Holds the message boundary. Default is false.
+    *  @type string
+    */
+   var $boundary      = false;
+
+   /////////////////////////////////////////////////
+   // VARIABLE METHODS
+   /////////////////////////////////////////////////
+
+   /**
+    * Sets message type to HTML.  Returns void.
+    * @public
+    * @returns void
+    */
+   function IsHTML($bool) {
+      if($bool == true)
+         $this->ContentType = "text/html";
+      else
+         $this->ContentType = "text/plain";
+   }
+
+   /**
+    * Sets Mailer to use SMTP.  Returns void.
+    * @public
+    * @returns void
+    */
+   function IsSMTP() {
+      $this->Mailer = "smtp";
+   }
+
+   /**
+    * Sets Mailer to use PHP mail() function.  Returns void.
+    * @public
+    * @returns void
+    */
+   function IsMail() {
+      $this->Mailer = "mail";
+   }
+
+   /**
+    * Sets Mailer to use $Sendmail program.  Returns void.
+    * @public
+    * @returns void
+    */
+   function IsSendmail() {
+      $this->Mailer = "sendmail";
+   }
+
+   /**
+    * Sets Mailer to use qmail MTA.  Returns void.
+    * @public
+    * @returns void
+    */
+   function IsQmail() {
+      //$this->Sendmail = "/var/qmail/bin/qmail-inject";
+      $this->Sendmail = "/var/qmail/bin/sendmail";
+      $this->Mailer = "sendmail";
+   }
+
+
+   /////////////////////////////////////////////////
+   // RECIPIENT METHODS
+   /////////////////////////////////////////////////
+
+   /**
+    * Adds a "to" address.  Returns void.
+    * @public
+    * @returns void
+    */
+   function AddAddress($address, $name = "") {
+      $cur = count($this->to);
+      $this->to[$cur][0] = trim($address);
+      $this->to[$cur][1] = $name;
+   }
+
+   /**
+    * Adds a "Cc" address. Returns void.
+    * @public
+    * @returns void
+    */
+   function AddCC($address, $name = "") {
+      $cur = count($this->cc);
+      $this->cc[$cur][0] = trim($address);
+      $this->cc[$cur][1] = $name;
+   }
+
+   /**
+    * Adds a "Bcc" address. Note: this function works 
+    * with the SMTP mailer on win32, not with the "mail" 
+    * mailer.  This is a PHP bug that has been submitted 
+    * on the Zend web site. The UNIX version of PHP 
+    * functions correctly. 
+    * Returns void.
+    * @public
+    * @returns void
+    */
+   function AddBCC($address, $name = "") {
+      $cur = count($this->bcc);
+      $this->bcc[$cur][0] = trim($address);
+      $this->bcc[$cur][1] = $name;
+   }
+
+   /**
+    * Adds a "Reply-to" address.  Returns void.
+    * @public
+    * @returns void
+    */
+   function AddReplyTo($address, $name = "") {
+      $cur = count($this->ReplyTo);
+      $this->ReplyTo[$cur][0] = trim($address);
+      $this->ReplyTo[$cur][1] = $name;
+   }
+
+
+   /////////////////////////////////////////////////
+   // MAIL SENDING METHODS
+   /////////////////////////////////////////////////
+
+   /**
+    * Creates message and assigns Mailer. If the message is 
+    * not sent successfully then it returns false.  Returns bool.
+    * @public
+    * @returns bool
+    */
+   function Send() {
+      if(count($this->to) < 1)
+      {
+         $this->error_handler("You must provide at least one recipient email address");
+         return false;
+      }
+
+      $header = $this->create_header();
+      if(!$body = $this->create_body())
+         return false;
+
+      // Choose the mailer
+      if($this->Mailer == "sendmail")
+      {
+         if(!$this->sendmail_send($header, $body))
+            return false;
+      }
+      elseif($this->Mailer == "mail")
+      {
+         if(!$this->mail_send($header, $body))
+            return false;
+      }
+      elseif($this->Mailer == "smtp")
+      {
+         if(!$this->smtp_send($header, $body))
+            return false;
+      }
+      else
+      {
+         $this->error_handler(sprintf("%s mailer is not supported", $this->Mailer));
+         return false;
+      }
+
+      return true;
+   }
+
+   /**
+    * Sends mail using the $Sendmail program.  Returns bool.
+    * @private
+    * @returns bool
+    */
+   function sendmail_send($header, $body) {
+      if ($this->Sender != "")
+         $sendmail = sprintf("%s -f %s -t", $this->Sendmail, $this->Sender);
+      else
+         $sendmail = sprintf("%s -t", $this->Sendmail);
+
+      if(!@$mail = popen($sendmail, "w"))
+      {
+         $this->error_handler(sprintf("Could not execute %s", $this->Sendmail));
+         return false;
+      }
+
+      fputs($mail, $header);
+      fputs($mail, $body);
+      pclose($mail);
+
+      return true;
+   }
+
+   /**
+    * Sends mail using the PHP mail() function.  Returns bool.
+    * @private
+    * @returns bool
+    */
+   function mail_send($header, $body) {
+      //$to = substr($this->addr_append("To", $this->to), 4, -2);
+
+      // Cannot add Bcc's to the $to
+      $to = $this->to[0][0]; // no extra comma
+      for($i = 1; $i < count($this->to); $i++)
+         $to .= sprintf(",%s", $this->to[$i][0]);
+
+      if ($this->Sender != "" && PHP_VERSION >= "4.0")
+      {
+         $old_from = ini_get("sendmail_from");
+         ini_set("sendmail_from", $this->Sender);
+      }
+
+      if ($this->Sender != "" && PHP_VERSION >= "4.0.5")
+      {
+         // The fifth parameter to mail is only available in PHP >= 4.0.5
+         $params = sprintf("-f %s", $this->Sender);
+         $rt = @mail($to, $this->Subject, $body, $header, $params);
+      }
+      else
+      {
+         $rt = @mail($to, $this->Subject, $body, $header);
+      }
+
+      if (isset($old_from))
+         ini_set("sendmail_from", $old_from);
+
+      if(!$rt)
+      {
+         $this->error_handler("Could not instantiate mail()");
+         return false;
+      }
+
+      return true;
+   }
+
+   /**
+    * Sends mail via SMTP using PhpSMTP (Author:
+    * Chris Ryan).  Returns bool.
+    * @private
+    * @returns bool
+    */
+   function smtp_send($header, $body) {
+      // Include SMTP class code, but not twice
+      //include_once("class.smtp.php"); // Load code only if asked
+
+      $smtp = new SMTP;
+      $smtp->do_debug = $this->SMTPDebug;
+
+      // Try to connect to all SMTP servers
+      $hosts = explode(";", $this->Host);
+      $index = 0;
+      $connection = false;
+
+      // Retry while there is no connection
+      while($index < count($hosts) && $connection == false)
+      {
+         if($smtp->Connect($hosts[$index], $this->Port, $this->Timeout))
+            $connection = true;
+         //printf("%s host could not connect<br>", $hosts[$index]); //debug only
+         $index++;
+      }
+      if(!$connection)
+      {
+         $this->error_handler("SMTP Error: could not connect to SMTP host server(s)");
+         return false;
+      }
+
+      $smtp->Hello($this->Helo);
+      if ($this->Sender == "")
+         $smtp->Mail(sprintf("<%s>", $this->From));
+      else
+         $smtp->Mail(sprintf("<%s>", $this->Sender));
+
+      for($i = 0; $i < count($this->to); $i++)
+         $smtp->Recipient(sprintf("<%s>", $this->to[$i][0]));
+      for($i = 0; $i < count($this->cc); $i++)
+         $smtp->Recipient(sprintf("<%s>", $this->cc[$i][0]));
+      for($i = 0; $i < count($this->bcc); $i++)
+         $smtp->Recipient(sprintf("<%s>", $this->bcc[$i][0]));
+
+      if(!$smtp->Data(sprintf("%s%s", $header, $body)))
+      {
+         $this->error_handler("SMTP Error: Data not accepted");
+         return false;
+      }
+      $smtp->Quit();
+
+      return true;
+   }
+
+
+   /////////////////////////////////////////////////
+   // MESSAGE CREATION METHODS
+   /////////////////////////////////////////////////
+
+   /**
+    * Creates recipient headers.  Returns string.
+    * @private
+    * @returns string
+    */
+   function addr_append($type, $addr) {
+      $addr_str = "";
+      $addr_str .= sprintf("%s: %s <%s>", $type, $addr[0][1], $addr[0][0]);
+      if(count($addr) > 1)
+      {
+         for($i = 1; $i < count($addr); $i++)
+         {
+            $addr_str .= sprintf(", %s <%s>", $addr[$i][1], $addr[$i][0]);
+         }
+         $addr_str .= "\r\n";
+      }
+      else
+         $addr_str .= "\r\n";
+
+      return($addr_str);
+   }
+
+   /**
+    * Wraps message for use with mailers that don't
+    * automatically perform wrapping and for quoted-printable.
+    * Original written by philippe.  Returns string.
+    * @private
+    * @returns string
+    */
+   function wordwrap($message, $length, $qp_mode = false) {
+      if ($qp_mode)
+        $soft_break = " =\r\n";
+      else
+        $soft_break = "\r\n";
+
+      $message = $this->fix_eol($message);
+      if (substr($message, -1) == "\r\n")
+        $message = substr($message, 0, -2);
+
+      $line = explode("\r\n", $message);
+      $message = "";
+      for ($i=0 ;$i < count($line); $i++)
+      {
+         $line_part = explode(" ", trim($line[$i]));
+         $buf = "";
+         for ($e = 0; $e<count($line_part); $e++)
+         {
+            $word = $line_part[$e];
+            if ($qp_mode and (strlen($word) > $length))
+            {
+               $space_left = $length - strlen($buf) - 1;
+               if ($e != 0)
+               {
+                  if ($space_left > 20)
+                  {
+                     $len = $space_left;
+                     if (substr($word, $len - 1, 1) == "=")
+                        $len--;
+                     elseif (substr($word, $len - 2, 1) == "=")
+                        $len -= 2;
+                     $part = substr($word, 0, $len);
+                     $word = substr($word, $len);
+                     $buf .= " " . $part;
+                     $message .= $buf . "=\r\n";
+                  }
+                  else
+                  {
+                     $message .= $buf . $soft_break;
+                  }
+                  $buf = "";
+               }
+               while (strlen($word) > 0)
+               {
+                  $len = $length;
+                  if (substr($word, $len - 1, 1) == "=")
+                     $len--;
+                  elseif (substr($word, $len - 2, 1) == "=")
+                     $len -= 2;
+                  $part = substr($word, 0, $len);
+                  $word = substr($word, $len);
+
+                  if (strlen($word) > 0)
+                     $message .= $part . "=\r\n";
+                  else
+                     $buf = $part;
+               }
+            }
+            else
+            {
+               $buf_o = $buf;
+               if ($e == 0)
+                  $buf .= $word;
+               else
+                  $buf .= " " . $word;
+               if (strlen($buf) > $length and $buf_o != "")
+               {
+                  $message .= $buf_o . $soft_break;
+                  $buf = $word;
+               }
+            }
+         }
+         $message .= $buf . "\r\n";
+      }
+
+      return ($message);
+   }
+
+   /**
+    * Assembles message header.  Returns a string if successful
+    * or false if unsuccessful.
+    * @private
+    * @returns string
+    */
+   function create_header() {
+      $header = array();
+      $header[] = sprintf("Date: %s\r\n", $this->rfc_date());
+
+      // To be created automatically by mail()
+      if($this->Mailer != "mail")
+         $header[] = $this->addr_append("To", $this->to);
+
+      $header[] = sprintf("From: %s <%s>\r\n", $this->FromName, trim($this->From));
+      if(count($this->cc) > 0)
+         $header[] = $this->addr_append("Cc", $this->cc);
+
+      // sendmail and mail() extract Bcc from the header before sending
+      if((($this->Mailer == "sendmail") || ($this->Mailer == "mail")) && (count($this->bcc) > 0))
+         $header[] = $this->addr_append("Bcc", $this->bcc);
+
+      if(count($this->ReplyTo) > 0)
+         $header[] = $this->addr_append("Reply-to", $this->ReplyTo);
+
+      // mail() sets the subject itself
+      if($this->Mailer != "mail")
+         $header[] = sprintf("Subject: %s\r\n", trim($this->Subject));
+
+      $header[] = sprintf("X-Priority: %d\r\n", $this->Priority);
+      $header[] = sprintf("X-Mailer: %s\r\n", $this->Version);
+      $header[] = sprintf("Return-Path: %s\r\n", trim($this->From));
+
+      // Add custom headers
+      for($index = 0; $index < count($this->CustomHeader); $index++)
+         $header[] = sprintf("%s\r\n", $this->CustomHeader[$index]);
+
+      if($this->UseMSMailHeaders)
+         $header[] = $this->AddMSMailHeaders();
+
+      // Add all attachments
+      if(count($this->attachment) > 0)
+      {
+         // Set message boundary
+         $this->boundary = "_b" . md5(uniqid(time()));
+
+         $header[] = sprintf("Content-Type: Multipart/Mixed; charset = \"%s\";\r\n", $this->CharSet);
+         $header[] = sprintf(" boundary=\"Boundary-=%s\"\r\n", $this->boundary);
+      }
+      else
+      {
+         $header[] = sprintf("Content-Transfer-Encoding: %s\r\n", $this->Encoding);
+         $header[] = sprintf("Content-Type: %s; charset = \"%s\";\r\n", $this->ContentType, $this->CharSet);
+      }
+
+      $header[] = "MIME-Version: 1.0\r\n";
+
+      return(join("", $header));
+   }
+
+   /**
+    * Assembles the message body.  Returns a string if successful
+    * or false if unsuccessful.
+    * @private
+    * @returns string
+    */
+   function create_body() {
+      // wordwrap the message body if set
+      if($this->WordWrap)
+         $this->Body = $this->wordwrap($this->Body, $this->WordWrap);
+
+      $this->Body = $this->encode_string($this->Body, $this->Encoding);
+
+      if(count($this->attachment) > 0)
+      {
+         if(!$body = $this->attach_all())
+            return false;
+      }
+      else
+         $body = $this->Body;
+
+      return($body);
+   }
+
+
+   /////////////////////////////////////////////////
+   // ATTACHMENT METHODS
+   /////////////////////////////////////////////////
+
+   /**
+    * Checks if attachment is valid and then adds 
+    * the attachment to the list. 
+    * Returns false if the file was not found.
+    * @public
+    * @returns bool
+    */
+   function AddAttachment($path, $name = "", $encoding = "base64", $type = "application/octet-stream") {
+      if(!@is_file($path))
+      {
+         $this->error_handler(sprintf("Could not find %s file on filesystem", $path));
+         return false;
+      }
+
+      $filename = basename($path);
+      if($name == "")
+         $name = $filename;
+
+      // Append to $attachment array
+      $cur = count($this->attachment);
+      $this->attachment[$cur][0] = $path;
+      $this->attachment[$cur][1] = $filename;
+      $this->attachment[$cur][2] = $name;
+      $this->attachment[$cur][3] = $encoding;
+      $this->attachment[$cur][4] = $type;
+
+      return true;
+   }
+
+   /**
+    * Attaches text and binary attachments to body.  Returns a
+    * string if successful or false if unsuccessful.
+    * @private
+    * @returns string
+    */
+   function attach_all() {
+      // Return text of body
+      $mime = array();
+      $mime[] = "This is a MIME message. If you are reading this text, you\r\n";
+      $mime[] = "might want to consider changing to a mail reader that\r\n";
+      $mime[] = "understands how to properly display MIME multipart messages.\r\n\r\n";
+      $mime[] = sprintf("--Boundary-=%s\r\n", $this->boundary);
+      $mime[] = sprintf("Content-Type: %s; charset = \"%s\";\r\n", $this->ContentType, $this->CharSet);
+      $mime[] = sprintf("Content-Transfer-Encoding: %s\r\n\r\n", $this->Encoding);
+      $mime[] = sprintf("%s\r\n", $this->Body);
+
+      // Add all attachments
+      for($i = 0; $i < count($this->attachment); $i++)
+      {
+         $path = $this->attachment[$i][0];
+         $filename = $this->attachment[$i][1];
+         $name = $this->attachment[$i][2];
+         $encoding = $this->attachment[$i][3];
+         $type = $this->attachment[$i][4];
+         $mime[] = sprintf("--Boundary-=%s\r\n", $this->boundary);
+         $mime[] = sprintf("Content-Type: %s;\r\n", $type);
+         $mime[] = sprintf("name=\"%s\"\r\n", $name);
+         $mime[] = sprintf("Content-Transfer-Encoding: %s\r\n", $encoding);
+         $mime[] = sprintf("Content-Disposition: attachment; filename=\"%s\"\r\n\r\n", $name);
+         if(!$mime[] = sprintf("%s\r\n\r\n", $this->encode_file($path, $encoding)))
+            return false;
+      }
+      $mime[] = sprintf("\r\n--Boundary-=%s--\r\n", $this->boundary);
+
+      return(join("", $mime));
+   }
+
+   /**
+    * Encodes attachment in requested format.  Returns a
+    * string if successful or false if unsuccessful.
+    * @private
+    * @returns string
+    */
+   function encode_file ($path, $encoding = "base64") {
+      if(!@$fd = fopen($path, "r"))
+      {
+         $this->error_handler(sprintf("File Error: Could not open file %s", $path));
+         return false;
+      }
+      $file = fread($fd, filesize($path));
+      $encoded = $this->encode_string($file, $encoding);
+      fclose($fd);
+
+      return($encoded);
+   }
+
+   /**
+    * Encodes string to requested format. Returns a
+    * string if successful or false if unsuccessful.
+    * @private
+    * @returns string
+    */
+   function encode_string ($str, $encoding = "base64") {
+      switch(strtolower($encoding)) {
+         case "base64":
+            // chunk_split is found in PHP >= 3.0.6
+            $encoded = chunk_split(base64_encode($str));
+            break;
+
+         case "7bit":
+         case "8bit":
+            $encoded = $this->fix_eol($str);
+            if (substr($encoded, -2) != "\r\n")
+               $encoded .= "\r\n";
+            break;
+
+         case "binary":
+            $encoded = $str;
+            break;
+
+         case "quoted-printable":
+            $encoded = $this->encode_qp($str);
+            break;
+
+         default:
+            $this->error_handler(sprintf("Unknown encoding: %s", $encoding));
+            return false;
+      }
+      return($encoded);
+   }
+
+   /**
+    * Encode string to quoted-printable.  Returns a string.
+    * @private
+    * @returns string
+    */
+   function encode_qp ($str) {
+      $encoded = $this->fix_eol($str);
+      if (substr($encoded, -2) != "\r\n")
+         $encoded .= "\r\n";
+
+      // Replace every high ascii, control and = characters
+      $encoded = preg_replace("/([\001-\010\013\014\016-\037\075\177-\377])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
+      // Replace every spaces and tabs when it's the last character on a line
+      $encoded = preg_replace("/([\011\040])\r\n/e", "'='.sprintf('%02X', ord('\\1')).'\r\n'", $encoded);
+
+      // Maximum line length of 76 characters before CRLF (74 + space + '=')
+      $encoded = $this->WordWrap($encoded, 74, true);
+
+      return $encoded;
+   }
+
+   /////////////////////////////////////////////////
+   // MESSAGE RESET METHODS
+   /////////////////////////////////////////////////
+
+   /**
+    * Clears all recipients assigned in the TO array.  Returns void.
+    * @public
+    * @returns void
+    */
+   function ClearAddresses() {
+      $this->to = array();
+   }
+
+   /**
+    * Clears all recipients assigned in the CC array.  Returns void.
+    * @public
+    * @returns void
+    */
+   function ClearCCs() {
+      $this->cc = array();
+   }
+
+   /**
+    * Clears all recipients assigned in the BCC array.  Returns void.
+    * @public
+    * @returns void
+    */
+   function ClearBCCs() {
+      $this->bcc = array();
+   }
+
+   /**
+    * Clears all recipients assigned in the ReplyTo array.  Returns void.
+    * @public
+    * @returns void
+    */
+   function ClearReplyTos() {
+      $this->ReplyTo = array();
+   }
+
+   /**
+    * Clears all recipients assigned in the TO, CC and BCC
+    * array.  Returns void.
+    * @public
+    * @returns void
+    */
+   function ClearAllRecipients() {
+      $this->to = array();
+      $this->cc = array();
+      $this->bcc = array();
+   }
+
+   /**
+    * Clears all previously set attachments.  Returns void.
+    * @public
+    * @returns void
+    */
+   function ClearAttachments() {
+      $this->attachment = array();
+   }
+
+   /**
+    * Clears all custom headers.  Returns void.
+    * @public
+    * @returns void
+    */
+   function ClearCustomHeaders() {
+      $this->CustomHeader = array();
+   }
+
+
+   /////////////////////////////////////////////////
+   // MISCELLANEOUS METHODS
+   /////////////////////////////////////////////////
+
+   /**
+    * Adds the error message to the error container.
+    * Returns void.
+    * @private
+    * @returns void
+    */
+   function error_handler($msg) {
+        $this->ErrorInfo = $msg;
+   }
+   
+   /**
+    * Returns the proper RFC 822 formatted date. Returns string.
+    * @private
+    * @returns string
+    */
+   function rfc_date() {
+        $tz = date("Z");
+        $tzs = ($tz < 0) ? "-" : "+";
+        $tz = abs($tz);
+        $tz = $tz/36 + $tz % 3600;
+        $date = sprintf("%s %s%04d", date("D, j M Y H:i:s"), $tzs, $tz);
+        return $date;
+   }
+
+   /**
+    * Changes every end of line from CR or LF to CRLF.  Returns string.
+    * @private
+    * @returns string
+    */
+   function fix_eol($str) {
+      $str = str_replace("\r\n", "\n", $str);
+      $str = str_replace("\r", "\n", $str);
+      $str = str_replace("\n", "\r\n", $str);
+      return $str;
+   }
+
+   /**
+    * Adds a custom header.  Returns void.
+    * @public
+    * @returns void
+    */
+   function AddCustomHeader($custom_header) {
+      $this->CustomHeader[] = $custom_header;
+   }
+
+   /**
+    * Adds all the Microsoft message headers.  Returns string.
+    * @private
+    * @returns string
+    */
+   function AddMSMailHeaders() {
+      $MSHeader = "";
+      if($this->Priority == 1)
+         $MSPriority = "High";
+      elseif($this->Priority == 5)
+         $MSPriority = "Low";
+      else
+         $MSPriority = "Medium";
+
+      $MSHeader .= sprintf("X-MSMail-Priority: %s\r\n", $MSPriority);
+      $MSHeader .= sprintf("Importance: %s\r\n", $MSPriority);
+
+      return($MSHeader);
+   }
+
+}
+// End of class
+?>
diff --git a/lib/class.smtp.php b/lib/class.smtp.php
new file mode 100644 (file)
index 0000000..a0ce998
--- /dev/null
@@ -0,0 +1,939 @@
+<?php\r
+    /*\r
+     * File: smtp.php\r
+     *\r
+     * Description: Define an SMTP class that can be used to connect\r
+     *              and communicate with any SMTP server. It implements\r
+     *              all the SMTP functions defined in RFC821 except TURN.\r
+     *\r
+     * Creator: Chris Ryan <chris@greatbridge.com>\r
+     * Created: 03/26/2001\r
+     *\r
+     * TODO:\r
+     *     - Move all the duplicate code to a utility function\r
+     *           Most of the functions have the first lines of\r
+     *           code do the same processing. If this can be moved\r
+     *           into a utility function then it would reduce the\r
+     *           overall size of the code significantly.\r
+     */\r
+\r
+    /*\r
+     * STMP is rfc 821 compliant and implements all the rfc 821 SMTP\r
+     * commands except TURN which will always return a not implemented\r
+     * error. SMTP also provides some utility methods for sending mail\r
+     * to an SMTP server.\r
+     */\r
+    class SMTP {\r
+        var $SMTP_PORT = 25; # the default SMTP PORT\r
+        var $CRLF = "\r\n";  # CRLF pair\r
+\r
+        var $smtp_conn;      # the socket to the server\r
+        var $error;          # error if any on the last call\r
+        var $helo_rply;      # the reply the server sent to us for HELO\r
+\r
+        var $do_debug;       # the level of debug to perform\r
+\r
+        /*\r
+         * SMTP()\r
+         *\r
+         * Initialize the class so that the data is in a known state.\r
+         */\r
+        function SMTP() {\r
+            $this->smtp_conn = 0;\r
+            $this->error = null;\r
+            $this->helo_rply = null;\r
+\r
+            $this->do_debug = 0;\r
+        }\r
+\r
+        /************************************************************\r
+         *                    CONNECTION FUNCTIONS                  *\r
+         ***********************************************************/\r
+\r
+        /*\r
+         * Connect($host, $port=0, $tval=30)\r
+         *\r
+         * Connect to the server specified on the port specified.\r
+         * If the port is not specified use the default SMTP_PORT.\r
+         * If tval is specified then a connection will try and be\r
+         * established with the server for that number of seconds.\r
+         * If tval is not specified the default is 30 seconds to\r
+         * try on the connection.\r
+         *\r
+         * SMTP CODE SUCCESS: 220\r
+         * SMTP CODE FAILURE: 421\r
+         */\r
+        function Connect($host,$port=0,$tval=30) {\r
+            # set the error val to null so there is no confusion\r
+            $this->error = null;\r
+\r
+            # make sure we are __not__ connected\r
+            if($this->connected()) {\r
+                # ok we are connected! what should we do?\r
+                # for now we will just give an error saying we\r
+                # are already connected\r
+                $this->error =\r
+                    array("error" => "Already connected to a server");\r
+                return false;\r
+            }\r
+\r
+            if(empty($port)) {\r
+                $port = $this->SMTP_PORT;\r
+            }\r
+\r
+            #connect to the smtp server\r
+            $this->smtp_conn = fsockopen($host,    # the host of the server\r
+                                         $port,    # the port to use\r
+                                         $errno,   # error number if any\r
+                                         $errstr,  # error message if any\r
+                                         $tval);   # give up after ? secs\r
+            # verify we connected properly\r
+            if(empty($this->smtp_conn)) {\r
+                $this->error = array("error" => "Failed to connect to server",\r
+                                     "errno" => $errno,\r
+                                     "errstr" => $errstr);\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": $errstr ($errno)" . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+\r
+            # sometimes the SMTP server takes a little longer to respond\r
+            # so we will give it a longer timeout for the first read\r
+            //if(function_exists("socket_set_timeout"))\r
+            //   socket_set_timeout($this->smtp_conn, 1, 0);\r
+\r
+            # get any announcement stuff\r
+            $announce = $this->get_lines();\r
+\r
+            # set the timeout  of any socket functions at 1/10 of a second\r
+            //if(function_exists("socket_set_timeout"))\r
+            //   socket_set_timeout($this->smtp_conn, 0, 100000);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $announce;\r
+            }\r
+\r
+            return true;\r
+        }\r
+\r
+        /*\r
+         * Connected()\r
+         *\r
+         * Returns true if connected to a server otherwise false\r
+         */\r
+        function Connected() {\r
+            if(!empty($this->smtp_conn)) {\r
+                $sock_status = socket_get_status($this->smtp_conn);\r
+                if($sock_status["eof"]) {\r
+                    # hmm this is an odd situation... the socket is\r
+                    # valid but we aren't connected anymore\r
+                    if($this->do_debug >= 1) {\r
+                        echo "SMTP -> NOTICE:" . $this->CRLF .\r
+                             "EOF caught while checking if connected";\r
+                    }\r
+                    $this->Close();\r
+                    return false;\r
+                }\r
+                return true; # everything looks good\r
+            } \r
+            return false;\r
+        }\r
+\r
+        /*\r
+         * Close()\r
+         *\r
+         * Closes the socket and cleans up the state of the class.\r
+         * It is not considered good to use this function without\r
+         * first trying to use QUIT.\r
+         */\r
+        function Close() {\r
+            $this->error = null; # so there is no confusion\r
+            $this->helo_rply = null;\r
+            if(!empty($this->smtp_conn)) { \r
+                # close the connection and cleanup\r
+                fclose($this->smtp_conn);\r
+                $this->smtp_conn = 0;\r
+            }\r
+        }\r
+\r
+\r
+        /**************************************************************\r
+         *                        SMTP COMMANDS                       *\r
+         *************************************************************/\r
+\r
+        /*\r
+         * Data($msg_data)\r
+         *\r
+         * Issues a data command and sends the msg_data to the server\r
+         * finializing the mail transaction. $msg_data is the message\r
+         * that is to be send with the headers. Each header needs to be\r
+         * on a single line followed by a <CRLF> with the message headers\r
+         * and the message body being seperated by and additional <CRLF>.\r
+         *\r
+         * Implements rfc 821: DATA <CRLF>\r
+         *\r
+         * SMTP CODE INTERMEDIATE: 354\r
+         *     [data]\r
+         *     <CRLF>.<CRLF>\r
+         *     SMTP CODE SUCCESS: 250\r
+         *     SMTP CODE FAILURE: 552,554,451,452\r
+         * SMTP CODE FAILURE: 451,554\r
+         * SMTP CODE ERROR  : 500,501,503,421\r
+         */\r
+        function Data($msg_data) {\r
+            $this->error = null; # so no confusion is caused\r
+\r
+            if(!$this->connected()) {\r
+                $this->error = array(\r
+                        "error" => "Called Data() without being connected");\r
+                return false;\r
+            }\r
+\r
+            fputs($this->smtp_conn,"DATA" . $this->CRLF);\r
+\r
+            $rply = $this->get_lines();\r
+            $code = substr($rply,0,3);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;\r
+            }\r
+\r
+            if($code != 354) {\r
+                $this->error =\r
+                    array("error" => "DATA command not accepted from server",\r
+                          "smtp_code" => $code,\r
+                          "smtp_msg" => substr($rply,4));\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": " . $rply . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+\r
+            # the server is ready to accept data!\r
+            # according to rfc 821 we should not send more than 1000\r
+            # including the CRLF\r
+            # characters on a single line so we will break the data up\r
+            # into lines by \r and/or \n then if needed we will break\r
+            # each of those into smaller lines to fit within the limit.\r
+            # in addition we will be looking for lines that start with\r
+            # a period '.' and append and additional period '.' to that\r
+            # line. NOTE: this does not count towards are limit.\r
+\r
+            # normalize the line breaks so we know the explode works\r
+            $msg_data = str_replace("\r\n","\n",$msg_data);\r
+            $msg_data = str_replace("\r","\n",$msg_data);\r
+            $lines = explode("\n",$msg_data);\r
+\r
+            # we need to find a good way to determine is headers are\r
+            # in the msg_data or if it is a straight msg body\r
+            # currently I'm assuming rfc 822 definitions of msg headers\r
+            # and if the first field of the first line (':' sperated)\r
+            # does not contain a space then it _should_ be a header\r
+            # and we can process all lines before a blank "" line as\r
+            # headers.\r
+            $field = substr($lines[0],0,strpos($lines[0],":"));\r
+            $in_headers = false;\r
+            if(!empty($field) && !strstr($field," ")) {\r
+                $in_headers = true;\r
+            }\r
+\r
+            $max_line_length = 998; # used below; set here for ease in change\r
+\r
+            while(list(,$line) = @each($lines)) {\r
+                $lines_out = null;\r
+                if($line == "" && $in_headers) {\r
+                    $in_headers = false;\r
+                }\r
+                # ok we need to break this line up into several\r
+                # smaller lines\r
+                while(strlen($line) > $max_line_length) {\r
+                    $pos = strrpos(substr($line,0,$max_line_length)," ");\r
+                    $lines_out[] = substr($line,0,$pos);\r
+                    $line = substr($line,$pos + 1);\r
+                    # if we are processing headers we need to\r
+                    # add a LWSP-char to the front of the new line\r
+                    # rfc 822 on long msg headers\r
+                    if($in_headers) {\r
+                        $line = "\t" . $line;\r
+                    }\r
+                }\r
+                $lines_out[] = $line;\r
+\r
+                # now send the lines to the server\r
+                while(list(,$line_out) = @each($lines_out)) {\r
+                    if($line_out[0] == ".") {\r
+                        $line_out = "." . $line_out;\r
+                    }\r
+                    fputs($this->smtp_conn,$line_out . $this->CRLF);\r
+                }\r
+            }\r
+\r
+            # ok all the message data has been sent so lets get this\r
+            # over with aleady\r
+            fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);\r
+\r
+            $rply = $this->get_lines();\r
+            $code = substr($rply,0,3);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;\r
+            }\r
+\r
+            if($code != 250) {\r
+                $this->error =\r
+                    array("error" => "DATA not accepted from server",\r
+                          "smtp_code" => $code,\r
+                          "smtp_msg" => substr($rply,4));\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": " . $rply . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+            return true;\r
+        }\r
+\r
+        /*\r
+         * Expand($name)\r
+         *\r
+         * Expand takes the name and asks the server to list all the\r
+         * people who are members of the _list_. Expand will return\r
+         * back and array of the result or false if an error occurs.\r
+         * Each value in the array returned has the format of:\r
+         *     [ <full-name> <sp> ] <path>\r
+         * The definition of <path> is defined in rfc 821\r
+         *\r
+         * Implements rfc 821: EXPN <SP> <string> <CRLF>\r
+         *\r
+         * SMTP CODE SUCCESS: 250\r
+         * SMTP CODE FAILURE: 550\r
+         * SMTP CODE ERROR  : 500,501,502,504,421\r
+         */\r
+        function Expand($name) {\r
+            $this->error = null; # so no confusion is caused\r
+\r
+            if(!$this->connected()) {\r
+                $this->error = array(\r
+                        "error" => "Called Expand() without being connected");\r
+                return false;\r
+            }\r
+\r
+            fputs($this->smtp_conn,"EXPN " . $name . $this->CRLF);\r
+\r
+            $rply = $this->get_lines();\r
+            $code = substr($rply,0,3);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;\r
+            }\r
+\r
+            if($code != 250) {\r
+                $this->error =\r
+                    array("error" => "EXPN not accepted from server",\r
+                          "smtp_code" => $code,\r
+                          "smtp_msg" => substr($rply,4));\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": " . $rply . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+\r
+            # parse the reply and place in our array to return to user\r
+            $entries = explode($this->CRLF,$rply);\r
+            while(list(,$l) = @each($entries)) {\r
+                $list[] = substr($l,4);\r
+            }\r
+\r
+            return $rval;\r
+        }\r
+\r
+        /*\r
+         * Hello($host="")\r
+         *\r
+         * Sends the HELO command to the smtp server.\r
+         * This makes sure that we and the server are in\r
+         * the same known state.\r
+         *\r
+         * Implements from rfc 821: HELO <SP> <domain> <CRLF>\r
+         *\r
+         * SMTP CODE SUCCESS: 250\r
+         * SMTP CODE ERROR  : 500, 501, 504, 421\r
+         */\r
+        function Hello($host="") {\r
+            $this->error = null; # so no confusion is caused\r
+\r
+            if(!$this->connected()) {\r
+                $this->error = array(\r
+                        "error" => "Called Hello() without being connected");\r
+                return false;\r
+            }\r
+\r
+            # if a hostname for the HELO wasn't specified determine\r
+            # a suitable one to send\r
+            if(empty($host)) {\r
+                # we need to determine some sort of appopiate default\r
+                # to send to the server\r
+                $host = "localhost";\r
+            }\r
+\r
+            fputs($this->smtp_conn,"HELO " . $host . $this->CRLF);\r
+\r
+            $rply = $this->get_lines();\r
+            $code = substr($rply,0,3);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;\r
+            }\r
+\r
+            if($code != 250) {\r
+                $this->error =\r
+                    array("error" => "HELO not accepted from server",\r
+                          "smtp_code" => $code,\r
+                          "smtp_msg" => substr($rply,4));\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": " . $rply . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+\r
+            $this->helo_rply = $rply;\r
+\r
+            return true;\r
+        }\r
+\r
+        /*\r
+         * Help($keyword="")\r
+         *\r
+         * Gets help information on the keyword specified. If the keyword\r
+         * is not specified then returns generic help, ussually contianing\r
+         * A list of keywords that help is available on. This function\r
+         * returns the results back to the user. It is up to the user to\r
+         * handle the returned data. If an error occurs then false is\r
+         * returned with $this->error set appropiately.\r
+         *\r
+         * Implements rfc 821: HELP [ <SP> <string> ] <CRLF>\r
+         *\r
+         * SMTP CODE SUCCESS: 211,214\r
+         * SMTP CODE ERROR  : 500,501,502,504,421\r
+         *\r
+        function Help($keyword="") {\r
+            $this->error = null; # to avoid confusion\r
+\r
+            if(!$this->connected()) {\r
+                $this->error = array(\r
+                        "error" => "Called Help() without being connected");\r
+                return false;\r
+            }\r
+\r
+            $extra = "";\r
+            if(!empty($keyword)) {\r
+                $extra = " " . $keyword;\r
+            }\r
+\r
+            fputs($this->smtp_conn,"HELP" . $extra . $this->CRLF);\r
+\r
+            $rply = $this->get_lines();\r
+            $code = substr($rply,0,3);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;\r
+            }\r
+\r
+            if($code != 211 && $code != 214) {\r
+                $this->error =\r
+                    array("error" => "HELP not accepted from server",\r
+                          "smtp_code" => $code,\r
+                          "smtp_msg" => substr($rply,4));\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": " . $rply . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+\r
+            return $rply;\r
+        }\r
+\r
+        /*\r
+         * Mail($from)\r
+         *\r
+         * Starts a mail transaction from the email address specified in\r
+         * $from. Returns true if successful or false otherwise. If True\r
+         * the mail transaction is started and then one or more Recipient\r
+         * commands may be called followed by a Data command.\r
+         *\r
+         * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>\r
+         *\r
+         * SMTP CODE SUCCESS: 250\r
+         * SMTP CODE SUCCESS: 552,451,452\r
+         * SMTP CODE SUCCESS: 500,501,421\r
+         */\r
+        function Mail($from) {\r
+            $this->error = null; # so no confusion is caused\r
+\r
+            if(!$this->connected()) {\r
+                $this->error = array(\r
+                        "error" => "Called Mail() without being connected");\r
+                return false;\r
+            }\r
+\r
+            fputs($this->smtp_conn,"MAIL FROM:" . $from . $this->CRLF);\r
+\r
+            $rply = $this->get_lines();\r
+            $code = substr($rply,0,3);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;\r
+            }\r
+\r
+            if($code != 250) {\r
+                $this->error =\r
+                    array("error" => "MAIL not accepted from server",\r
+                          "smtp_code" => $code,\r
+                          "smtp_msg" => substr($rply,4));\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": " . $rply . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+            return true;\r
+        }\r
+\r
+        /*\r
+         * Noop()\r
+         *\r
+         * Sends the command NOOP to the SMTP server.\r
+         *\r
+         * Implements from rfc 821: NOOP <CRLF>\r
+         *\r
+         * SMTP CODE SUCCESS: 250\r
+         * SMTP CODE ERROR  : 500, 421\r
+         */\r
+        function Noop() {\r
+            $this->error = null; # so no confusion is caused\r
+\r
+            if(!$this->connected()) {\r
+                $this->error = array(\r
+                        "error" => "Called Noop() without being connected");\r
+                return false;\r
+            }\r
+\r
+            fputs($this->smtp_conn,"NOOP" . $this->CRLF);\r
+\r
+            $rply = $this->get_lines();\r
+            $code = substr($rply,0,3);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;\r
+            }\r
+\r
+            if($code != 250) {\r
+                $this->error =\r
+                    array("error" => "NOOP not accepted from server",\r
+                          "smtp_code" => $code,\r
+                          "smtp_msg" => substr($rply,4));\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": " . $rply . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+            return true;\r
+        }\r
+\r
+        /*\r
+         * Quit($close_on_error=true)\r
+         *\r
+         * Sends the quit command to the server and then closes the socket\r
+         * if there is no error or the $close_on_error argument is true.\r
+         *\r
+         * Implements from rfc 821: QUIT <CRLF>\r
+         *\r
+         * SMTP CODE SUCCESS: 221\r
+         * SMTP CODE ERROR  : 500\r
+         */\r
+        function Quit($close_on_error=true) {\r
+            $this->error = null; # so there is no confusion\r
+\r
+            if(!$this->connected()) {\r
+                $this->error = array(\r
+                        "error" => "Called Quit() without being connected");\r
+                return false;\r
+            }\r
+\r
+            # send the quit command to the server\r
+            fputs($this->smtp_conn,"quit" . $this->CRLF);\r
+\r
+            # get any good-bye messages\r
+            $byemsg = $this->get_lines();\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $byemsg;\r
+            }\r
+\r
+            $rval = true;\r
+            $e = null;\r
+\r
+            $code = substr($byemsg,0,3);\r
+            if($code != 221) {\r
+                # use e as a tmp var cause Close will overwrite $this->error\r
+                $e = array("error" => "SMTP server rejected quit command",\r
+                           "smtp_code" => $code,\r
+                           "smtp_rply" => substr($byemsg,4));\r
+                $rval = false;\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $e["error"] . ": " .\r
+                             $byemsg . $this->CRLF;\r
+                }\r
+            }\r
+\r
+            if(empty($e) || $close_on_error) {\r
+                $this->Close();\r
+            }\r
+\r
+            return $rval;\r
+        }\r
+\r
+        /*\r
+         * Recipient($to)\r
+         *\r
+         * Sends the command RCPT to the SMTP server with the TO: argument of $to.\r
+         * Returns true if the recipient was accepted false if it was rejected.\r
+         *\r
+         * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>\r
+         *\r
+         * SMTP CODE SUCCESS: 250,251\r
+         * SMTP CODE FAILURE: 550,551,552,553,450,451,452\r
+         * SMTP CODE ERROR  : 500,501,503,421\r
+         */\r
+        function Recipient($to) {\r
+            $this->error = null; # so no confusion is caused\r
+\r
+            if(!$this->connected()) {\r
+                $this->error = array(\r
+                        "error" => "Called Recipient() without being connected");\r
+                return false;\r
+            }\r
+\r
+            fputs($this->smtp_conn,"RCPT TO:" . $to . $this->CRLF);\r
+\r
+            $rply = $this->get_lines();\r
+            $code = substr($rply,0,3);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;\r
+            }\r
+\r
+            if($code != 250 && $code != 251) {\r
+                $this->error =\r
+                    array("error" => "RCPT not accepted from server",\r
+                          "smtp_code" => $code,\r
+                          "smtp_msg" => substr($rply,4));\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": " . $rply . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+            return true;\r
+        }\r
+\r
+        /*\r
+         * Reset()\r
+         *\r
+         * Sends the RSET command to abort and transaction that is\r
+         * currently in progress. Returns true if successful false\r
+         * otherwise.\r
+         *\r
+         * Implements rfc 821: RSET <CRLF>\r
+         *\r
+         * SMTP CODE SUCCESS: 250\r
+         * SMTP CODE ERROR  : 500,501,504,421\r
+         */\r
+        function Reset() {\r
+            $this->error = null; # so no confusion is caused\r
+\r
+            if(!$this->connected()) {\r
+                $this->error = array(\r
+                        "error" => "Called Reset() without being connected");\r
+                return false;\r
+            }\r
+\r
+            fputs($this->smtp_conn,"RSET" . $this->CRLF);\r
+\r
+            $rply = $this->get_lines();\r
+            $code = substr($rply,0,3);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;\r
+            }\r
+\r
+            if($code != 250) {\r
+                $this->error =\r
+                    array("error" => "RSET failed",\r
+                          "smtp_code" => $code,\r
+                          "smtp_msg" => substr($rply,4));\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": " . $rply . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+\r
+            return true;\r
+        }\r
+\r
+        /*\r
+         * Send($from)\r
+         *\r
+         * Starts a mail transaction from the email address specified in\r
+         * $from. Returns true if successful or false otherwise. If True\r
+         * the mail transaction is started and then one or more Recipient\r
+         * commands may be called followed by a Data command. This command\r
+         * will send the message to the users terminal if they are logged\r
+         * in.\r
+         *\r
+         * Implements rfc 821: SEND <SP> FROM:<reverse-path> <CRLF>\r
+         *\r
+         * SMTP CODE SUCCESS: 250\r
+         * SMTP CODE SUCCESS: 552,451,452\r
+         * SMTP CODE SUCCESS: 500,501,502,421\r
+         */\r
+        function Send($from) {\r
+            $this->error = null; # so no confusion is caused\r
+\r
+            if(!$this->connected()) {\r
+                $this->error = array(\r
+                        "error" => "Called Send() without being connected");\r
+                return false;\r
+            }\r
+\r
+            fputs($this->smtp_conn,"SEND FROM:" . $from . $this->CRLF);\r
+\r
+            $rply = $this->get_lines();\r
+            $code = substr($rply,0,3);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;\r
+            }\r
+\r
+            if($code != 250) {\r
+                $this->error =\r
+                    array("error" => "SEND not accepted from server",\r
+                          "smtp_code" => $code,\r
+                          "smtp_msg" => substr($rply,4));\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": " . $rply . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+            return true;\r
+        }\r
+\r
+        /*\r
+         * SendAndMail($from)\r
+         *\r
+         * Starts a mail transaction from the email address specified in\r
+         * $from. Returns true if successful or false otherwise. If True\r
+         * the mail transaction is started and then one or more Recipient\r
+         * commands may be called followed by a Data command. This command\r
+         * will send the message to the users terminal if they are logged\r
+         * in and send them an email.\r
+         *\r
+         * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>\r
+         *\r
+         * SMTP CODE SUCCESS: 250\r
+         * SMTP CODE SUCCESS: 552,451,452\r
+         * SMTP CODE SUCCESS: 500,501,502,421\r
+         */\r
+        function SendAndMail($from) {\r
+            $this->error = null; # so no confusion is caused\r
+\r
+            if(!$this->connected()) {\r
+                $this->error = array(\r
+                    "error" => "Called SendAndMail() without being connected");\r
+                return false;\r
+            }\r
+\r
+            fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);\r
+\r
+            $rply = $this->get_lines();\r
+            $code = substr($rply,0,3);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;\r
+            }\r
+\r
+            if($code != 250) {\r
+                $this->error =\r
+                    array("error" => "SAML not accepted from server",\r
+                          "smtp_code" => $code,\r
+                          "smtp_msg" => substr($rply,4));\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": " . $rply . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+            return true;\r
+        }\r
+\r
+        /*\r
+         * SendOrMail($from)\r
+         *\r
+         * Starts a mail transaction from the email address specified in\r
+         * $from. Returns true if successful or false otherwise. If True\r
+         * the mail transaction is started and then one or more Recipient\r
+         * commands may be called followed by a Data command. This command\r
+         * will send the message to the users terminal if they are logged\r
+         * in or mail it to them if they are not.\r
+         *\r
+         * Implements rfc 821: SOML <SP> FROM:<reverse-path> <CRLF>\r
+         *\r
+         * SMTP CODE SUCCESS: 250\r
+         * SMTP CODE SUCCESS: 552,451,452\r
+         * SMTP CODE SUCCESS: 500,501,502,421\r
+         */\r
+        function SendOrMail($from) {\r
+            $this->error = null; # so no confusion is caused\r
+\r
+            if(!$this->connected()) {\r
+                $this->error = array(\r
+                    "error" => "Called SendOrMail() without being connected");\r
+                return false;\r
+            }\r
+\r
+            fputs($this->smtp_conn,"SOML FROM:" . $from . $this->CRLF);\r
+\r
+            $rply = $this->get_lines();\r
+            $code = substr($rply,0,3);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;\r
+            }\r
+\r
+            if($code != 250) {\r
+                $this->error =\r
+                    array("error" => "SOML not accepted from server",\r
+                          "smtp_code" => $code,\r
+                          "smtp_msg" => substr($rply,4));\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": " . $rply . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+            return true;\r
+        }\r
+\r
+        /*\r
+         * Turn()\r
+         *\r
+         * This is an optional command for SMTP that this class does not\r
+         * support. This method is here to make the RFC821 Definition\r
+         * complete for this class and __may__ be implimented in the future\r
+         *\r
+         * Implements from rfc 821: TURN <CRLF>\r
+         *\r
+         * SMTP CODE SUCCESS: 250\r
+         * SMTP CODE FAILURE: 502\r
+         * SMTP CODE ERROR  : 500, 503\r
+         */\r
+        function Turn() {\r
+            $this->error = array("error" => "This method, TURN, of the SMTP ".\r
+                                            "is not implemented");\r
+            if($this->do_debug >= 1) {\r
+                echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF;\r
+            }\r
+            return false;\r
+        }\r
+\r
+        /*\r
+         * Verify($name)\r
+         *\r
+         * Verifies that the name is recognized by the server.\r
+         * Returns false if the name could not be verified otherwise\r
+         * the response from the server is returned.\r
+         *\r
+         * Implements rfc 821: VRFY <SP> <string> <CRLF>\r
+         *\r
+         * SMTP CODE SUCCESS: 250,251\r
+         * SMTP CODE FAILURE: 550,551,553\r
+         * SMTP CODE ERROR  : 500,501,502,421\r
+         */\r
+        function Verify($name) {\r
+            $this->error = null; # so no confusion is caused\r
+\r
+            if(!$this->connected()) {\r
+                $this->error = array(\r
+                        "error" => "Called Verify() without being connected");\r
+                return false;\r
+            }\r
+\r
+            fputs($this->smtp_conn,"VRFY " . $name . $this->CRLF);\r
+\r
+            $rply = $this->get_lines();\r
+            $code = substr($rply,0,3);\r
+\r
+            if($this->do_debug >= 2) {\r
+                echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;\r
+            }\r
+\r
+            if($code != 250 && $code != 251) {\r
+                $this->error =\r
+                    array("error" => "VRFY failed on name '$name'",\r
+                          "smtp_code" => $code,\r
+                          "smtp_msg" => substr($rply,4));\r
+                if($this->do_debug >= 1) {\r
+                    echo "SMTP -> ERROR: " . $this->error["error"] .\r
+                             ": " . $rply . $this->CRLF;\r
+                }\r
+                return false;\r
+            }\r
+            return $rply;\r
+        }\r
+\r
+        /******************************************************************\r
+         *                       INTERNAL FUNCTIONS                       *\r
+         ******************************************************************/\r
+\r
+        /*\r
+         * get_lines()\r
+         *\r
+         * __internal_use_only__: read in as many lines as possible\r
+         * either before eof or socket timeout occurs on the operation.\r
+         * With SMTP we can tell if we have more lines to read if the\r
+         * 4th character is '-' symbol. If it is a space then we don't\r
+         * need to read anything else.\r
+         */\r
+        function get_lines() {\r
+            $data = "";\r
+            while($str = fgets($this->smtp_conn,515)) {\r
+                if($this->do_debug >= 4) {\r
+                    echo "SMTP -> get_lines(): \$data was \"$data\"" .\r
+                             $this->CRLF;\r
+                    echo "SMTP -> get_lines(): \$str is \"$str\"" .\r
+                             $this->CRLF;\r
+                }\r
+                $data .= $str;\r
+                if($this->do_debug >= 4) {\r
+                    echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF;\r
+                }\r
+                # if the 4th character is a space then we are done reading\r
+                # so just break the loop\r
+                if(substr($str,3,1) == " ") { break; }\r
+            }\r
+            return $data;\r
+        }\r
+\r
+    }\r
+\r
+\r
+ ?>\r
diff --git a/lib/fonts/arial.ttf b/lib/fonts/arial.ttf
new file mode 100755 (executable)
index 0000000..7e28e41
Binary files /dev/null and b/lib/fonts/arial.ttf differ
diff --git a/lib/fonts/vixar.ttf b/lib/fonts/vixar.ttf
new file mode 100755 (executable)
index 0000000..7e690c5
Binary files /dev/null and b/lib/fonts/vixar.ttf differ
diff --git a/lib/graphlib.php b/lib/graphlib.php
new file mode 100644 (file)
index 0000000..8cfbee9
--- /dev/null
@@ -0,0 +1,1704 @@
+<?php\r
+/*\r
+Graph Class. PHP Class to draw line, point, bar, and area graphs, including numeric x-axis and double y-axis.\r
+Version: 1.6.3\r
+Copyright (C) 2000  Herman Veluwenkamp\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+\r
+Copy of GNU Lesser General Public License at: http://www.gnu.org/copyleft/lesser.txt\r
+Contact author at: hermanV@mindless.com\r
+*/\r
+\r
+\r
+class graph {\r
+  var $image;\r
+  var $debug             =   FALSE;        // be careful!!\r
+  var $calculated        =   array();      // array of computed values for chart\r
+  var $parameter         =   array(        // input parameters\r
+    'width'              =>  320,          // default width of image\r
+    'height'             =>  240,          // default height of image\r
+    'file_name'          => 'none',        // name of file for file to be saved as.\r
+                                           //  NOTE: no suffix required. this is determined from output_format below.\r
+    'output_format'      => 'PNG',         // image output format. 'GIF', 'PNG', 'JPEG'. default 'PNG'.\r
+\r
+    'seconds_to_live'    =>  0,            // expiry time in seconds (for HTTP header)\r
+    'hours_to_live'      =>  0,            // expiry time in hours (for HTTP header)\r
+    'path_to_fonts'      => 'fonts/',      // path to fonts folder. don't forget *trailing* slash!!\r
+                                           //   for WINDOZE this may need to be the full path, not relative.\r
+\r
+    'title'              => 'Graph Title', // text for graph title\r
+    'title_font'         => 'arial.ttf',   // title text font. don't forget to set 'path_to_fonts' above.\r
+    'title_size'         =>  16,           // title text point size\r
+    'title_colour'       => 'black',       // colour for title text\r
+\r
+    'x_label'            => '',            // if this is set then this text is printed on bottom axis of graph.\r
+    'y_label_left'       => '',            // if this is set then this text is printed on left axis of graph.\r
+    'y_label_right'      => '',            // if this is set then this text is printed on right axis of graph.\r
+\r
+    'label_size'         =>  12,           // label text point size\r
+    'label_font'         => 'arial.ttf', // label text font. don't forget to set 'path_to_fonts' above.\r
+    'label_colour'       => 'gray33',      // label text colour\r
+    'y_label_angle'      =>  90,           // rotation of y axis label\r
+\r
+    'x_label_angle'      =>  90,            // rotation of y axis label\r
+\r
+    'outer_padding'      =>  8,            // padding around outer text. i.e. title, y label, and x label.\r
+    'inner_padding'      =>  6,            // padding beteen axis text and graph.\r
+    'outer_border'       => 'none',        // colour of border aound image, or 'none'.\r
+    'inner_border'       => 'black',       // colour of border around actual graph, or 'none'.\r
+    'inner_border_type'  => 'box',         // 'box' for all four sides, 'axis' for x/y axis only,\r
+                                           // 'y' or 'y-left' for y axis only, 'y-right' for right y axis only,\r
+                                           // 'x' for x axis only, 'u' for both left and right y axis and x axis.\r
+    'outer_background'   => 'none',        // background colour of entire image.\r
+    'inner_background'   => 'none',        // background colour of plot area.\r
+\r
+    'y_min_left'         =>  0,            // this will be reset to minimum value if there is a value lower than this.\r
+    'y_max_left'         =>  0,            // this will be reset to maximum value if there is a value higher than this.\r
+    'y_min_right'        =>  0,            // this will be reset to minimum value if there is a value lower than this.\r
+    'y_max_right'        =>  0,            // this will be reset to maximum value if there is a value higher than this.\r
+    'x_min'              =>  0,            // only used if x axis is numeric.\r
+    'x_max'              =>  0,            // only used if x axis is numeric.\r
+\r
+    'y_resolution_left'  =>  1,            // scaling for rounding of y axis max value.\r
+                                           // if max y value is 8645 then\r
+                                           // if y_resolution is 0, then y_max becomes 9000.\r
+                                           // if y_resolution is 1, then y_max becomes 8700.\r
+                                           // if y_resolution is 2, then y_max becomes 8650.\r
+                                           // if y_resolution is 3, then y_max becomes 8645.\r
+                                           // get it?\r
+    'y_decimal_left'     =>  0,            // number of decimal places for y_axis text.\r
+    'y_resolution_right' =>  2,            // ... same for right hand side\r
+    'y_decimal_right'    =>  0,            // ... same for right hand side\r
+    'x_resolution'       =>  2,            // only used if x axis is numeric.\r
+    'x_decimal'          =>  0,            // only used if x axis is numeric.\r
+\r
+    'point_size'         =>  4,            // default point size. use even number for diamond or triangle to get nice look.\r
+    'brush_size'         =>  4,            // default brush size for brush line.\r
+    'brush_type'         => 'circle',      // type of brush to use to draw line. choose from the following\r
+                                           //   'circle', 'square', 'horizontal', 'vertical', 'slash', 'backslash'\r
+    'bar_size'           =>  0.8,          // size of bar to draw. <1 bars won't touch\r
+                                           //   1 is full width - i.e. bars will touch.\r
+                                           //   >1 means bars will overlap.\r
+    'bar_spacing'        =>  10,           // space in pixels between group of bars for each x value.\r
+    'shadow_offset'      =>  3,            // draw shadow at this offset, unless overidden by data parameter.\r
+    'shadow'             => 'grayCC',      // 'none' or colour of shadow.\r
+    'shadow_below_axis'  => true,         // whether to draw shadows of bars and areas below the x/zero axis.\r
+\r
+\r
+    'x_axis_gridlines'   => 'auto',        // if set to a number then x axis is treated as numeric.\r
+    'y_axis_gridlines'   =>  6,            // number of gridlines on y axis.\r
+    'zero_axis'          => 'none',        // colour to draw zero-axis, or 'none'.\r
+\r
+\r
+    'axis_font'          => 'arial.ttf', // axis text font. don't forget to set 'path_to_fonts' above.\r
+    'axis_size'          =>  12,            // axis text font size in points\r
+    'axis_colour'        => 'gray33',      // colour of axis text.\r
+    'y_axis_angle'       =>  0,            // rotation of axis text.\r
+    'x_axis_angle'       =>  90,           // rotation of axis text.\r
+\r
+    'y_axis_text_left'   =>  1,            // whether to print left hand y axis text. if 0 no text, if 1 all ticks have text,\r
+    'x_axis_text'        =>  1,            //   if 4 then print every 4th tick and text, etc...\r
+    'y_axis_text_right'  =>  0,            // behaviour same as above for right hand y axis.\r
+\r
+    'x_offset'           =>  0.5,          // x axis tick offset from y axis as fraction of tick spacing.\r
+    'y_ticks_colour'     => 'black',       // colour to draw y ticks, or 'none'.\r
+    'x_ticks_colour'     => 'black',       // colour to draw x ticks, or 'none'.\r
+    'y_grid'             => 'line',        // grid lines. set to 'line' or 'dash'...\r
+    'x_grid'             => 'line',        //   or if set to 'none' print nothing.\r
+    'grid_colour'        => 'grayEE',      // default grid colour.\r
+    'tick_length'        =>  4,            // length of ticks in pixels. can be negative. i.e. outside data drawing area.\r
+\r
+    'legend'             => 'none',        // default. no legend.\r
+                                          // otherwise: 'top-left', 'top-right', 'bottom-left', 'bottom-right',\r
+                                          //   'outside-top', 'outside-bottom', 'outside-left', or 'outside-right'.\r
+    'legend_offset'      =>  10,           // offset in pixels from graph or outside border.\r
+    'legend_padding'     =>  5,            // padding around legend text.\r
+    'legend_font'        => 'arial.ttf',   // legend text font. don't forget to set 'path_to_fonts' above.\r
+    'legend_size'        =>  9,            // legend text point size.\r
+    'legend_colour'      => 'black',       // legend text colour.\r
+    'legend_border'      => 'none',        // legend border colour, or 'none'.\r
+\r
+    'decimal_point'      => '.',           // symbol for decimal separation  '.' or ',' *european support.\r
+    'thousand_sep'       => ',',           // symbol for thousand separation ',' or ''\r
+\r
+  );\r
+\r
+\r
+\r
+// init all text - title, labels, and axis text.\r
+function init() {\r
+  global $CFG;\r
+  $this->parameter['path_to_fonts'] = $CFG->dirroot."/lib/fonts/";  // Added for Moodle\r
+\r
+  $this->calculated['outer_border'] = $this->calculated['boundary_box'];\r
+\r
+  // outer padding\r
+  $this->calculated['boundary_box']['left']   += $this->parameter['outer_padding'];\r
+  $this->calculated['boundary_box']['top']    += $this->parameter['outer_padding'];\r
+  $this->calculated['boundary_box']['right']  -= $this->parameter['outer_padding'];\r
+  $this->calculated['boundary_box']['bottom'] -= $this->parameter['outer_padding'];\r
+\r
+  $this->init_x_axis();\r
+  $this->init_y_axis();\r
+  $this->init_legend();\r
+  $this->init_labels();\r
+\r
+  //  take into account tick lengths\r
+  $this->calculated['bottom_inner_padding'] = $this->parameter['inner_padding'];\r
+  if (($this->parameter['x_ticks_colour'] != 'none') && ($this->parameter['tick_length'] < 0))\r
+    $this->calculated['bottom_inner_padding'] -= $this->parameter['tick_length'];\r
+  $this->calculated['boundary_box']['bottom'] -= $this->calculated['bottom_inner_padding'];\r
+\r
+  $this->calculated['left_inner_padding'] = $this->parameter['inner_padding'];\r
+  if ($this->parameter['y_axis_text_left']) {\r
+    if (($this->parameter['y_ticks_colour'] != 'none') && ($this->parameter['tick_length'] < 0))\r
+      $this->calculated['left_inner_padding'] -= $this->parameter['tick_length'];\r
+  }\r
+  $this->calculated['boundary_box']['left'] += $this->calculated['left_inner_padding'];\r
+\r
+  $this->calculated['right_inner_padding'] = $this->parameter['inner_padding'];\r
+  if ($this->parameter['y_axis_text_right']) {\r
+    if (($this->parameter['y_ticks_colour'] != 'none') && ($this->parameter['tick_length'] < 0))\r
+      $this->calculated['right_inner_padding'] -= $this->parameter['tick_length'];\r
+  }\r
+  $this->calculated['boundary_box']['right'] -= $this->calculated['right_inner_padding'];\r
+\r
+  // boundaryBox now has coords for plotting area.\r
+  $this->calculated['inner_border'] = $this->calculated['boundary_box'];\r
+\r
+  $this->init_data();\r
+  $this->init_x_ticks();\r
+  $this->init_y_ticks();\r
+}\r
+\r
+\r
+function draw_text() {\r
+  $colour = $this->parameter['outer_background'];\r
+  if ($colour != 'none') $this->draw_rectangle($this->calculated['outer_border'], $colour, 'fill'); // graph background\r
+\r
+  // draw border around image\r
+  $colour = $this->parameter['outer_border'];\r
+  if ($colour != 'none') $this->draw_rectangle($this->calculated['outer_border'], $colour, 'box'); // graph border\r
+\r
+  $this->draw_title();\r
+  $this->draw_x_label();\r
+  $this->draw_y_label_left();\r
+  $this->draw_y_label_right();\r
+  $this->draw_x_axis();\r
+  $this->draw_y_axis();\r
+  if      ($this->calculated['y_axis_left']['has_data'])  $this->draw_zero_axis_left();  // either draw zero axis on left\r
+  else if ($this->calculated['y_axis_right']['has_data']) $this->draw_zero_axis_right(); // ... or right.\r
+  $this->draw_legend();\r
+\r
+  // draw border around plot area\r
+  $colour = $this->parameter['inner_background'];\r
+  if ($colour != 'none') $this->draw_rectangle($this->calculated['inner_border'], $colour, 'fill'); // graph background\r
+\r
+  // draw border around image\r
+  $colour = $this->parameter['inner_border'];\r
+  if ($colour != 'none') $this->draw_rectangle($this->calculated['inner_border'], $colour, $this->parameter['inner_border_type']); // graph border\r
+}\r
+\r
+function draw_stack() {\r
+  $this->init();\r
+  $this->draw_text();\r
+\r
+  $yOrder = $this->y_order; // save y_order data.\r
+  // iterate over each data set. order is very important if you want to see data correctly. remember shadows!!\r
+  foreach ($yOrder as $set) {\r
+    $this->y_order = array($set);\r
+    $this->init_data();\r
+    $this->draw_data();\r
+  }\r
+  $this->y_order = $yOrder; // revert y_order data.\r
+\r
+  $this->output();\r
+}\r
+\r
+function draw() {\r
+  $this->init();\r
+  $this->draw_text();\r
+  $this->draw_data();\r
+  $this->output();\r
+}\r
+\r
+// draw a data set\r
+function draw_set($order, $set, $offset) {\r
+  if ($offset) @$this->init_variable($colour, $this->y_format[$set]['shadow'], $this->parameter['shadow']);\r
+  else $colour  = $this->y_format[$set]['colour'];\r
+  @$this->init_variable($point,      $this->y_format[$set]['point'],      'none');\r
+  @$this->init_variable($pointSize,  $this->y_format[$set]['point_size'],  $this->parameter['point_size']);\r
+  @$this->init_variable($line,       $this->y_format[$set]['line'],       'none');\r
+  @$this->init_variable($brushType,  $this->y_format[$set]['brush_type'],  $this->parameter['brush_type']);\r
+  @$this->init_variable($brushSize,  $this->y_format[$set]['brush_size'],  $this->parameter['brush_size']);\r
+  @$this->init_variable($bar,        $this->y_format[$set]['bar'],        'none');\r
+  @$this->init_variable($barSize,    $this->y_format[$set]['bar_size'],    $this->parameter['bar_size']);\r
+  @$this->init_variable($area,       $this->y_format[$set]['area'],       'none');\r
+\r
+  $lastX = 0;\r
+  $lastY = 'none';\r
+  $fromX = 0;\r
+  $fromY = 'none';\r
+\r
+  //print "set $set<BR>";\r
+  //expand_pre($this->calculated['y_plot']);\r
+\r
+  foreach ($this->x_data as $index => $x) {\r
+    //print "index $index<BR>";\r
+    $thisY = $this->calculated['y_plot'][$set][$index];\r
+    $thisX = $this->calculated['x_plot'][$index];\r
+\r
+    //print "$thisX, $thisY <BR>";\r
+\r
+    if (($bar!='none') && (string)$thisY != 'none') {\r
+        // Moodle addition - next 5 lines and last parameter yoffset\r
+        if ($relatedset = $this->offset_relation[$set]) {\r
+            $yoffset = $this->calculated['y_plot'][$relatedset][$index];\r
+        } else {\r
+            $yoffset = 0;\r
+        }\r
+        $this->bar($thisX, $thisY, $bar, $barSize, $colour, $offset, $set, $yoffset);\r
+    }\r
+\r
+    if (($area!='none') && (((string)$lastY != 'none') && ((string)$thisY != 'none')))\r
+      $this->area($lastX, $lastY, $thisX, $thisY, $area, $colour, $offset);\r
+\r
+    if (($point!='none') && (string)$thisY != 'none') $this->plot($thisX, $thisY, $point, $pointSize, $colour, $offset);\r
+\r
+    if (($line!='none') && ((string)$thisY != 'none')) {\r
+      if ((string)$fromY != 'none')\r
+        $this->line($fromX, $fromY, $thisX, $thisY, $line, $brushType, $brushSize, $colour, $offset);\r
+\r
+      $fromY = $thisY; // start next line from here\r
+      $fromX = $thisX; // ...\r
+    } else {\r
+      $fromY = 'none';\r
+      $fromX = 'none';\r
+    }\r
+\r
+    $lastX = $thisX;\r
+    $lastY = $thisY;\r
+  }\r
+}\r
+\r
+function draw_data() {\r
+  // cycle thru y data to be plotted\r
+  // first check for drop shadows...\r
+  foreach ($this->y_order as $order => $set) {\r
+    @$this->init_variable($offset, $this->y_format[$set]['shadow_offset'], $this->parameter['shadow_offset']);\r
+    @$this->init_variable($colour, $this->y_format[$set]['shadow'], $this->parameter['shadow']);\r
+    if ($colour != 'none') $this->draw_set($order, $set, $offset);\r
+\r
+  }\r
+\r
+  // then draw data\r
+  foreach ($this->y_order as $order => $set) {\r
+    $this->draw_set($order, $set, 0);\r
+  }\r
+}\r
+\r
+function draw_legend() {\r
+  $position      = $this->parameter['legend'];\r
+  if ($position == 'none') return; // abort if no border\r
+\r
+  $borderColour  = $this->parameter['legend_border'];\r
+  $offset        = $this->parameter['legend_offset'];\r
+  $padding       = $this->parameter['legend_padding'];\r
+  $height        = $this->calculated['legend']['boundary_box_all']['height'];\r
+  $width         = $this->calculated['legend']['boundary_box_all']['width'];\r
+  $graphTop      = $this->calculated['boundary_box']['top'];\r
+  $graphBottom   = $this->calculated['boundary_box']['bottom'];\r
+  $graphLeft     = $this->calculated['boundary_box']['left'];\r
+  $graphRight    = $this->calculated['boundary_box']['right'];\r
+  $outsideRight  = $this->calculated['outer_border']['right'];\r
+  $outsideBottom = $this->calculated['outer_border']['bottom'];\r
+  switch ($position) {\r
+    case 'top-left':\r
+      $top    = $graphTop  + $offset;\r
+      $bottom = $graphTop  + $height + $offset;\r
+      $left   = $graphLeft + $offset;\r
+      $right  = $graphLeft + $width + $offset;\r
+\r
+      break;\r
+    case 'top-right':\r
+      $top    = $graphTop   + $offset;\r
+      $bottom = $graphTop   + $height + $offset;\r
+      $left   = $graphRight - $width - $offset;\r
+      $right  = $graphRight - $offset;\r
+\r
+      break;\r
+    case 'bottom-left':\r
+      $top    = $graphBottom - $height - $offset;\r
+      $bottom = $graphBottom - $offset;\r
+      $left   = $graphLeft   + $offset;\r
+      $right  = $graphLeft   + $width + $offset;\r
+\r
+      break;\r
+    case 'bottom-right':\r
+      $top    = $graphBottom - $height - $offset;\r
+      $bottom = $graphBottom - $offset;\r
+      $left   = $graphRight  - $width - $offset;\r
+      $right  = $graphRight  - $offset;\r
+      break;\r
+\r
+    case 'outside-top' :\r
+      $top    = $graphTop;\r
+      $bottom = $graphTop     + $height;\r
+      $left   = $outsideRight - $width - $offset;\r
+      $right  = $outsideRight - $offset;\r
+      break;\r
+\r
+    case 'outside-bottom' :\r
+      $top    = $graphBottom  - $height;\r
+      $bottom = $graphBottom;\r
+      $left   = $outsideRight - $width - $offset;\r
+      $right  = $outsideRight - $offset;\r
+     break;\r
+\r
+    case 'outside-left' :\r
+      $top    = $outsideBottom - $height - $offset;\r
+      $bottom = $outsideBottom - $offset;\r
+      $left   = $graphLeft;\r
+      $right  = $graphLeft     + $width;\r
+     break;\r
+\r
+    case 'outside-right' :\r
+      $top    = $outsideBottom - $height - $offset;\r
+      $bottom = $outsideBottom - $offset;\r
+      $left   = $graphRight    - $width;\r
+      $right  = $graphRight;\r
+      break;\r
+    default: // default is top left. no particular reason.\r
+      $top    = $this->calculated['boundary_box']['top'];\r
+      $bottom = $this->calculated['boundary_box']['top'] + $this->calculated['legend']['boundary_box_all']['height'];\r
+      $left   = $this->calculated['boundary_box']['left'];\r
+      $right  = $this->calculated['boundary_box']['right'] + $this->calculated['legend']['boundary_box_all']['width'];\r
+\r
+}\r
+  // legend border\r
+  if($borderColour!='none') $this->draw_rectangle(array('top' => $top,\r
+                                                        'left' => $left,\r
+                                                        'bottom' => $bottom,\r
+                                                        'right' => $right), $this->parameter['legend_border'], 'box');\r
+\r
+  // legend text\r
+  $legendText = array('points' => $this->parameter['legend_size'],\r
+                      'angle'  => 0,\r
+                      'font'   => $this->parameter['legend_font'],\r
+                      'colour' => $this->parameter['legend_colour']);\r
+\r
+  $box = $this->calculated['legend']['boundary_box_max']['height']; // use max height for legend square size.\r
+  $x = $left + $padding;\r
+  $x_text = $x + $box * 2;\r
+  $y = $top + $padding;\r
+\r
+  foreach ($this->y_order as $set) {\r
+    $legendText['text'] = $this->calculated['legend']['text'][$set];\r
+    if ($legendText['text'] != 'none') {\r
+      // if text exists then draw box and text\r
+      $boxColour = $this->colour[$this->y_format[$set]['colour']];\r
+\r
+      // draw box\r
+      ImageFilledRectangle($this->image, $x, $y, $x + $box, $y + $box, $boxColour);\r
+\r
+      // draw text\r
+      $coords = array('x' => $x + $box * 2, 'y' => $y, 'reference' => 'top-left');\r
+      $legendText['boundary_box'] = $this->calculated['legend']['boundary_box'][$set];\r
+      $this->update_boundaryBox($legendText['boundary_box'], $coords);\r
+      $this->print_TTF($legendText);\r
+      $y += $padding + $box;\r
+    }\r
+  }\r
+\r
+}\r
+\r
+function draw_y_label_right() {\r
+  if (!$this->parameter['y_label_right']) return;\r
+  $x = $this->calculated['boundary_box']['right'] + $this->parameter['inner_padding'];\r
+  if ($this->parameter['y_axis_text_right']) $x += $this->calculated['y_axis_right']['boundary_box_max']['width']\r
+                                           + $this->calculated['right_inner_padding'];\r
+  $y = ($this->calculated['boundary_box']['bottom'] + $this->calculated['boundary_box']['top']) / 2;\r
+\r
+  $label = $this->calculated['y_label_right'];\r
+  $coords = array('x' => $x, 'y' => $y, 'reference' => 'left-center');\r
+  $this->update_boundaryBox($label['boundary_box'], $coords);\r
+  $this->print_TTF($label);\r
+}\r
+\r
+\r
+function draw_y_label_left() {\r
+  if (!$this->parameter['y_label_left']) return;\r
+  $x = $this->calculated['boundary_box']['left'] - $this->parameter['inner_padding'];\r
+  if ($this->parameter['y_axis_text_left']) $x -= $this->calculated['y_axis_left']['boundary_box_max']['width']\r
+                                           + $this->calculated['left_inner_padding'];\r
+  $y = ($this->calculated['boundary_box']['bottom'] + $this->calculated['boundary_box']['top']) / 2;\r
+\r
+  $label = $this->calculated['y_label_left'];\r
+  $coords = array('x' => $x, 'y' => $y, 'reference' => 'right-center');\r
+  $this->update_boundaryBox($label['boundary_box'], $coords);\r
+  $this->print_TTF($label);\r
+}\r
+\r
+function draw_title() {\r
+  if (!$this->parameter['title']) return;\r
+  //$y = $this->calculated['outside_border']['top'] + $this->parameter['outer_padding'];\r
+  $y = $this->calculated['boundary_box']['top'] - $this->parameter['outer_padding'];\r
+  $x = ($this->calculated['boundary_box']['right'] + $this->calculated['boundary_box']['left']) / 2;\r
+  $label = $this->calculated['title'];\r
+  $coords = array('x' => $x, 'y' => $y, 'reference' => 'bottom-center');\r
+  $this->update_boundaryBox($label['boundary_box'], $coords);\r
+  $this->print_TTF($label);\r
+}\r
+\r
+function draw_x_label() {\r
+  if (!$this->parameter['x_label']) return;\r
+  $y = $this->calculated['boundary_box']['bottom'] + $this->parameter['inner_padding'];\r
+  if ($this->parameter['x_axis_text']) $y += $this->calculated['x_axis']['boundary_box_max']['height']\r
+                                          + $this->calculated['bottom_inner_padding'];\r
+  $x = ($this->calculated['boundary_box']['right'] + $this->calculated['boundary_box']['left']) / 2;\r
+  $label = $this->calculated['x_label'];\r
+  $coords = array('x' => $x, 'y' => $y, 'reference' => 'top-center');\r
+  $this->update_boundaryBox($label['boundary_box'], $coords);\r
+ $this->print_TTF($label);\r
+}\r
+\r
+function draw_zero_axis_left() {\r
+  $colour = $this->parameter['zero_axis'];\r
+  if ($colour == 'none') return;\r
+  // draw zero axis on left hand side\r
+  $this->calculated['zero_axis'] = round($this->calculated['boundary_box']['top']  + ($this->calculated['y_axis_left']['max'] * $this->calculated['y_axis_left']['factor']));\r
+  ImageLine($this->image, $this->calculated['boundary_box']['left'], $this->calculated['zero_axis'], $this->calculated['boundary_box']['right'], $this->calculated['zero_axis'], $this->colour[$colour]);\r
+}\r
+\r
+function draw_zero_axis_right() {\r
+  $colour = $this->parameter['zero_axis'];\r
+  if ($colour == 'none') return;\r
+  // draw zero axis on right hand side\r
+  $this->calculated['zero_axis'] = round($this->calculated['boundary_box']['top']  + ($this->calculated['y_axis_right']['max'] * $this->calculated['y_axis_right']['factor']));\r
+  ImageLine($this->image, $this->calculated['boundary_box']['left'], $this->calculated['zero_axis'], $this->calculated['boundary_box']['right'], $this->calculated['zero_axis'], $this->colour[$colour]);\r
+}\r
+\r
+function draw_x_axis() {\r
+  $gridColour  = $this->colour[$this->parameter['grid_colour']];\r
+  $tickColour  = $this->colour[$this->parameter['x_ticks_colour']];\r
+  $axis_colour  = $this->parameter['axis_colour'];\r
+  $xGrid       = $this->parameter['x_grid'];\r
+  $gridTop     = $this->calculated['boundary_box']['top'];\r
+  $gridBottom  = $this->calculated['boundary_box']['bottom'];\r
+\r
+  if ($this->parameter['tick_length'] >= 0) {\r
+    $tickTop     = $this->calculated['boundary_box']['bottom'] - $this->parameter['tick_length'];\r
+    $tickBottom  = $this->calculated['boundary_box']['bottom'];\r
+    $textBottom  = $tickBottom + $this->calculated['bottom_inner_padding'];\r
+  } else {\r
+    $tickTop     = $this->calculated['boundary_box']['bottom'];\r
+    $tickBottom  = $this->calculated['boundary_box']['bottom'] - $this->parameter['tick_length'];\r
+    $textBottom  = $tickBottom + $this->calculated['bottom_inner_padding'];\r
+  }\r
+\r
+  $axis_font    = $this->parameter['axis_font'];\r
+  $axis_size    = $this->parameter['axis_size'];\r
+  $axis_angle   = $this->parameter['x_axis_angle'];\r
+\r
+  if ($axis_angle == 0)  $reference = 'top-center';\r
+  if ($axis_angle > 0)   $reference = 'top-right';\r
+  if ($axis_angle < 0)   $reference = 'top-left';\r
+  if ($axis_angle == 90) $reference = 'top-center';\r
+\r
+  //generic tag information. applies to all axis text.\r
+  $axisTag = array('points' => $axis_size, 'angle' => $axis_angle, 'font' => $axis_font, 'colour' => $axis_colour);\r
+\r
+  foreach ($this->calculated['x_axis']['tick_x'] as $set => $tickX) {\r
+    // draw x grid if colour specified\r
+    if ($xGrid != 'none') {\r
+      switch ($xGrid) {\r
+        case 'line':\r
+          ImageLine($this->image, round($tickX), round($gridTop), round($tickX), round($gridBottom), $gridColour);\r
+          break;\r
+         case 'dash':\r
+          ImageDashedLine($this->image, round($tickX), round($gridTop), round($tickX), round($gridBottom), $gridColour);\r
+          break;\r
+      }\r
+    }\r
+\r
+    if ($this->parameter['x_axis_text'] && !($set % $this->parameter['x_axis_text'])) { // test if tick should be displayed\r
+      // draw tick\r
+      if ($tickColour != 'none')\r
+        ImageLine($this->image, round($tickX), round($tickTop), round($tickX), round($tickBottom), $tickColour);\r
+\r
+      // draw axis text\r
+      $coords = array('x' => $tickX, 'y' => $textBottom, 'reference' => $reference);\r
+      $axisTag['text'] = $this->calculated['x_axis']['text'][$set];\r
+      $axisTag['boundary_box'] = $this->calculated['x_axis']['boundary_box'][$set];\r
+      $this->update_boundaryBox($axisTag['boundary_box'], $coords);\r
+      $this->print_TTF($axisTag);\r
+    }\r
+  }\r
+}\r
+\r
+function draw_y_axis() {\r
+  $gridColour  = $this->colour[$this->parameter['grid_colour']];\r
+  $tickColour  = $this->colour[$this->parameter['y_ticks_colour']];\r
+  $axis_colour  = $this->parameter['axis_colour'];\r
+  $yGrid       = $this->parameter['y_grid'];\r
+  $gridLeft    = $this->calculated['boundary_box']['left'];\r
+  $gridRight   = $this->calculated['boundary_box']['right'];\r
+\r
+  // axis font information\r
+  $axis_font    = $this->parameter['axis_font'];\r
+  $axis_size    = $this->parameter['axis_size'];\r
+  $axis_angle   = $this->parameter['y_axis_angle'];\r
+  $axisTag = array('points' => $axis_size, 'angle' => $axis_angle, 'font' => $axis_font, 'colour' => $axis_colour);\r
+\r
+\r
+  if ($this->calculated['y_axis_left']['has_data']) {\r
+    // LEFT HAND SIDE\r
+    // left and right coords for ticks\r
+    if ($this->parameter['tick_length'] >= 0) {\r
+      $tickLeft     = $this->calculated['boundary_box']['left'];\r
+      $tickRight    = $this->calculated['boundary_box']['left'] + $this->parameter['tick_length'];\r
+    } else {\r
+      $tickLeft     = $this->calculated['boundary_box']['left'] + $this->parameter['tick_length'];\r
+      $tickRight    = $this->calculated['boundary_box']['left'];\r
+    }\r
+    $textRight      = $tickLeft - $this->calculated['left_inner_padding'];\r
+\r
+    if ($axis_angle == 0)  $reference = 'right-center';\r
+    if ($axis_angle > 0)   $reference = 'right-top';\r
+    if ($axis_angle < 0)   $reference = 'right-bottom';\r
+    if ($axis_angle == 90) $reference = 'right-center';\r
+\r
+    foreach ($this->calculated['y_axis']['tick_y'] as $set => $tickY) {\r
+      // draw y grid if colour specified\r
+      if ($yGrid != 'none') {\r
+        switch ($yGrid) {\r
+          case 'line':\r
+            ImageLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour);\r
+            break;\r
+           case 'dash':\r
+            ImageDashedLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour);\r
+            break;\r
+        }\r
+      }\r
+\r
+      // y axis text\r
+      if ($this->parameter['y_axis_text_left'] && !($set % $this->parameter['y_axis_text_left'])) { // test if tick should be displayed\r
+        // draw tick\r
+        if ($tickColour != 'none')\r
+          ImageLine($this->image, round($tickLeft), round($tickY), round($tickRight), round($tickY), $tickColour);\r
+\r
+        // draw axis text...\r
+        $coords = array('x' => $textRight, 'y' => $tickY, 'reference' => $reference);\r
+        $axisTag['text'] = $this->calculated['y_axis_left']['text'][$set];\r
+        $axisTag['boundary_box'] = $this->calculated['y_axis_left']['boundary_box'][$set];\r
+        $this->update_boundaryBox($axisTag['boundary_box'], $coords);\r
+        $this->print_TTF($axisTag);\r
+      }\r
+    }\r
+  }\r
+\r
+  if ($this->calculated['y_axis_right']['has_data']) {\r
+    // RIGHT HAND SIDE\r
+    // left and right coords for ticks\r
+    if ($this->parameter['tick_length'] >= 0) {\r
+      $tickLeft     = $this->calculated['boundary_box']['right'] - $this->parameter['tick_length'];\r
+      $tickRight    = $this->calculated['boundary_box']['right'];\r
+    } else {\r
+      $tickLeft     = $this->calculated['boundary_box']['right'];\r
+      $tickRight    = $this->calculated['boundary_box']['right'] - $this->parameter['tick_length'];\r
+    }\r
+    $textLeft       = $tickRight+ $this->calculated['left_inner_padding'];\r
+\r
+    if ($axis_angle == 0)  $reference = 'left-center';\r
+    if ($axis_angle > 0)   $reference = 'left-bottom';\r
+    if ($axis_angle < 0)   $reference = 'left-top';\r
+    if ($axis_angle == 90) $reference = 'left-center';\r
+\r
+    foreach ($this->calculated['y_axis']['tick_y'] as $set => $tickY) {\r
+      if (!$this->calculated['y_axis_left']['has_data'] && $yGrid != 'none') { // draw grid if not drawn already (above)\r
+        switch ($yGrid) {\r
+          case 'line':\r
+            ImageLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour);\r
+            break;\r
+           case 'dash':\r
+            ImageDashedLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour);\r
+            break;\r
+        }\r
+      }\r
+\r
+      if ($this->parameter['y_axis_text_right'] && !($set % $this->parameter['y_axis_text_right'])) { // test if tick should be displayed\r
+        // draw tick\r
+        if ($tickColour != 'none')\r
+          ImageLine($this->image, round($tickLeft), round($tickY), round($tickRight), round($tickY), $tickColour);\r
+\r
+        // draw axis text...\r
+        $coords = array('x' => $textLeft, 'y' => $tickY, 'reference' => $reference);\r
+        $axisTag['text'] = $this->calculated['y_axis_right']['text'][$set];\r
+        $axisTag['boundary_box'] = $this->calculated['y_axis_left']['boundary_box'][$set];\r
+        $this->update_boundaryBox($axisTag['boundary_box'], $coords);\r
+        $this->print_TTF($axisTag);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+function init_data() {\r
+  $this->calculated['y_plot'] = array(); // array to hold pixel plotting coords for y axis\r
+  $height = $this->calculated['boundary_box']['bottom'] - $this->calculated['boundary_box']['top'];\r
+  $width  = $this->calculated['boundary_box']['right'] - $this->calculated['boundary_box']['left'];\r
+\r
+  // calculate pixel steps between axis ticks.\r
+  $this->calculated['y_axis']['step'] = $height / ($this->parameter['y_axis_gridlines'] - 1);\r
+\r
+  // calculate x ticks spacing taking into account x offset for ticks.\r
+  $extraTick  = 2 * $this->parameter['x_offset']; // extra tick to account for padding\r
+  $numTicks = $this->calculated['x_axis']['num_ticks'] - 1;    // number of x ticks\r
+\r
+  $this->calculated['x_axis']['step'] = $width / ($numTicks + $extraTick);\r
+  $widthPlot = $width - ($this->calculated['x_axis']['step'] * $extraTick);\r
+  $this->calculated['x_axis']['step'] = $widthPlot / $numTicks;\r
+\r
+  //calculate factor for transforming x,y physical coords to logical coords for right hand y_axis.\r
+  $y_range = $this->calculated['y_axis_right']['max'] - $this->calculated['y_axis_right']['min'];\r
+  $y_range = ($y_range ? $y_range : 1);\r
+  $this->calculated['y_axis_right']['factor'] = $height / $y_range;\r
+\r
+  //calculate factor for transforming x,y physical coords to logical coords for left hand axis.\r
+  $yRange = $this->calculated['y_axis_left']['max'] - $this->calculated['y_axis_left']['min'];\r
+  $yRange = ($yRange ? $yRange : 1);\r
+  $this->calculated['y_axis_left']['factor'] = $height / $yRange;\r
+  if ($this->parameter['x_axis_gridlines'] != 'auto') {\r
+    $xRange = $this->calculated['x_axis']['max'] - $this->calculated['x_axis']['min'];\r
+    $xRange = ($xRange ? $xRange : 1);\r
+    $this->calculated['x_axis']['factor'] = $widthPlot / $xRange;\r
+  }\r
+\r
+  //expand_pre($this->calculated['boundary_box']);\r
+  // cycle thru all data sets...\r
+  $this->calculated['num_bars'] = 0;\r
+  foreach ($this->y_order as $order => $set) {\r
+    // determine how many bars there are\r
+    if (isset($this->y_format[$set]['bar']) && ($this->y_format[$set]['bar'] != 'none')) {\r
+      $this->calculated['bar_offset_index'][$set] = $this->calculated['num_bars']; // index to relate bar with data set.\r
+      $this->calculated['num_bars']++;\r
+    }\r
+\r
+    // calculate y coords for plotting data\r
+    foreach ($this->x_data as $index => $x) {\r
+      $this->calculated['y_plot'][$set][$index] = $this->y_data[$set][$index];\r
+\r
+      if ((string)$this->y_data[$set][$index] != 'none') {\r
+\r
+        if (isset($this->y_format[$set]['y_axis']) && $this->y_format[$set]['y_axis'] == 'right') {\r
+          $this->calculated['y_plot'][$set][$index] =\r
+            round(($this->y_data[$set][$index] - $this->calculated['y_axis_right']['min'])\r
+              * $this->calculated['y_axis_right']['factor']);\r
+        } else {\r
+          //print "$set $index<BR>";\r
+          $this->calculated['y_plot'][$set][$index] =\r
+            round(($this->y_data[$set][$index] - $this->calculated['y_axis_left']['min'])\r
+              * $this->calculated['y_axis_left']['factor']);\r
+        }\r
+\r
+      }\r
+    }\r
+  }\r
+  //print "factor ".$this->calculated['x_axis']['factor']."<BR>";\r
+  //expand_pre($this->calculated['x_plot']);\r
+\r
+  // calculate bar parameters if bars are to be drawn.\r
+  if ($this->calculated['num_bars']) {\r
+    $xStep       = $this->calculated['x_axis']['step'];\r
+    $totalWidth  = $this->calculated['x_axis']['step'] - $this->parameter['bar_spacing'];\r
+    $barWidth    = $totalWidth / $this->calculated['num_bars'];\r
+\r
+    $barX = ($barWidth - $totalWidth) / 2; // starting x offset\r
+    for ($i=0; $i < $this->calculated['num_bars']; $i++) {\r
+      $this->calculated['bar_offset_x'][$i] = $barX;\r
+      $barX += $barWidth; // add width of bar to x offset.\r
+    }\r
+    $this->calculated['bar_width'] = $barWidth;\r
+  }\r
+\r
+\r
+}\r
+\r
+function init_x_ticks() {\r
+  // get coords for x axis ticks and data plots\r
+  //$xGrid       = $this->parameter['x_grid'];\r
+  $xStep       = $this->calculated['x_axis']['step'];\r
+  $ticksOffset = $this->parameter['x_offset']; // where to start drawing ticks relative to y axis.\r
+  $gridLeft    = $this->calculated['boundary_box']['left'] + ($xStep * $ticksOffset); // grid x start\r
+  $tickX       = $gridLeft; // tick x coord\r
+\r
+  foreach ($this->calculated['x_axis']['text'] as $set => $value) {\r
+    //print "index: $set<BR>";\r
+    // x tick value\r
+    $this->calculated['x_axis']['tick_x'][$set] = $tickX;\r
+    // if num ticks is auto then x plot value is same as x  tick\r
+    if ($this->parameter['x_axis_gridlines'] == 'auto') $this->calculated['x_plot'][$set] = round($tickX);\r
+    //print $this->calculated['x_plot'][$set].'<BR>';\r
+    $tickX += $xStep;\r
+  }\r
+\r
+  //print "xStep: $xStep <BR>";\r
+  // if numeric x axis then calculate x coords for each data point. this is seperate from x ticks.\r
+  $gridX = $gridLeft;\r
+  $factor = $this->calculated['x_axis']['factor'];\r
+  $min = $this->calculated['x_axis']['min'];\r
+\r
+  if ($this->parameter['x_axis_gridlines'] != 'auto') {\r
+    foreach ($this->x_data as $index => $x) {\r
+      //print "index: $index, x: $x<BR>";\r
+      $offset = $x - $this->calculated['x_axis']['min'];\r
+\r
+      //$gridX = ($offset * $this->calculated['x_axis']['factor']);\r
+      //print "offset: $offset <BR>";\r
+      //$this->calculated['x_plot'][$set] = $gridLeft + ($offset * $this->calculated['x_axis']['factor']);\r
+\r
+      $this->calculated['x_plot'][$index] = $gridLeft + ($x - $min) * $factor;\r
+\r
+      //print $this->calculated['x_plot'][$set].'<BR>';\r
+    }\r
+  }\r
+  //expand_pre($this->calculated['boundary_box']);\r
+  //print "factor ".$this->calculated['x_axis']['factor']."<BR>";\r
+  //expand_pre($this->calculated['x_plot']);\r
+}\r
+\r
+function init_y_ticks() {\r
+  // get coords for y axis ticks\r
+\r
+  $yStep      = $this->calculated['y_axis']['step'];\r
+  $gridBottom = $this->calculated['boundary_box']['bottom'];\r
+  $tickY      = $gridBottom; // tick y coord\r
+\r
+  for ($i = 0; $i < $this->parameter['y_axis_gridlines']; $i++) {\r
+    $this->calculated['y_axis']['tick_y'][$i] = $tickY;\r
+    $tickY   -= $yStep;\r
+  }\r
+\r
+}\r
+\r
+function init_labels() {\r
+  if ($this->parameter['title']) {\r
+    $size = $this->get_boundaryBox(\r
+      array('points' => $this->parameter['title_size'],\r
+            'angle'  => 0,\r
+            'font'   => $this->parameter['title_font'],\r
+            'text'   => $this->parameter['title']));\r
+    $this->calculated['title']['boundary_box']  = $size;\r
+    $this->calculated['title']['text']         = $this->parameter['title'];\r
+    $this->calculated['title']['font']         = $this->parameter['title_font'];\r
+    $this->calculated['title']['points']       = $this->parameter['title_size'];\r
+    $this->calculated['title']['colour']       = $this->parameter['title_colour'];\r
+    $this->calculated['title']['angle']        = 0;\r
+\r
+    $this->calculated['boundary_box']['top'] += $size['height'] + $this->parameter['outer_padding'];\r
+    //$this->calculated['boundary_box']['top'] += $size['height'];\r
+\r
+  } else $this->calculated['title']['boundary_box'] = $this->get_null_size();\r
+\r
+  if ($this->parameter['y_label_left']) {\r
+    $this->calculated['y_label_left']['text']    = $this->parameter['y_label_left'];\r
+    $this->calculated['y_label_left']['angle']   = $this->parameter['y_label_angle'];\r
+    $this->calculated['y_label_left']['font']    = $this->parameter['label_font'];\r
+    $this->calculated['y_label_left']['points']  = $this->parameter['label_size'];\r
+    $this->calculated['y_label_left']['colour']  = $this->parameter['label_colour'];\r
+\r
+    $size = $this->get_boundaryBox($this->calculated['y_label_left']);\r
+    $this->calculated['y_label_left']['boundary_box']  = $size;\r
+    //$this->calculated['boundary_box']['left'] += $size['width'] + $this->parameter['inner_padding'];\r
+    $this->calculated['boundary_box']['left'] += $size['width'];\r
+\r
+  } else $this->calculated['y_label_left']['boundary_box'] = $this->get_null_size();\r
+\r
+  if ($this->parameter['y_label_right']) {\r
+    $this->calculated['y_label_right']['text']    = $this->parameter['y_label_right'];\r
+    $this->calculated['y_label_right']['angle']   = $this->parameter['y_label_angle'];\r
+    $this->calculated['y_label_right']['font']    = $this->parameter['label_font'];\r
+    $this->calculated['y_label_right']['points']  = $this->parameter['label_size'];\r
+    $this->calculated['y_label_right']['colour']  = $this->parameter['label_colour'];\r
+\r
+    $size = $this->get_boundaryBox($this->calculated['y_label_right']);\r
+    $this->calculated['y_label_right']['boundary_box']  = $size;\r
+    //$this->calculated['boundary_box']['right'] -= $size['width'] + $this->parameter['inner_padding'];\r
+    $this->calculated['boundary_box']['right'] -= $size['width'];\r
+\r
+  } else $this->calculated['y_label_right']['boundary_box'] = $this->get_null_size();\r
+\r
+  if ($this->parameter['x_label']) {\r
+    $this->calculated['x_label']['text']         = $this->parameter['x_label'];\r
+    $this->calculated['x_label']['angle']        = $this->parameter['x_label_angle'];\r
+    $this->calculated['x_label']['font']         = $this->parameter['label_font'];\r
+    $this->calculated['x_label']['points']       = $this->parameter['label_size'];\r
+    $this->calculated['x_label']['colour']       = $this->parameter['label_colour'];\r
+\r
+    $size = $this->get_boundaryBox($this->calculated['x_label']);\r
+    $this->calculated['x_label']['boundary_box']  = $size;\r
+    //$this->calculated['boundary_box']['bottom'] -= $size['height'] + $this->parameter['inner_padding'];\r
+    $this->calculated['boundary_box']['bottom'] -= $size['height'];\r
+\r
+  } else $this->calculated['x_label']['boundary_box'] = $this->get_null_size();\r
+\r
+}\r
+\r
+\r
+function init_legend() {\r
+  $this->calculated['legend'] = array(); // array to hold calculated values for legend.\r
+  //$this->calculated['legend']['boundary_box_max'] = array('height' => 0, 'width' => 0);\r
+  $this->calculated['legend']['boundary_box_max'] = $this->get_null_size();\r
+  if ($this->parameter['legend'] == 'none') return;\r
+\r
+  $position = $this->parameter['legend'];\r
+  $numSets = 0; // number of data sets with legends.\r
+  $sumTextHeight = 0; // total of height of all legend text items.\r
+  $width = 0;\r
+  $height = 0;\r
+\r
+  foreach ($this->y_order as $set) {\r
+   $text = isset($this->y_format[$set]['legend']) ? $this->y_format[$set]['legend'] : 'none';\r
+   $size = $this->get_boundaryBox(\r
+     array('points' => $this->parameter['legend_size'],\r
+           'angle'  => 0,\r
+           'font'   => $this->parameter['legend_font'],\r
+           'text'   => $text));\r
+\r
+   $this->calculated['legend']['boundary_box'][$set] = $size;\r
+   $this->calculated['legend']['text'][$set]        = $text;\r
+   //$this->calculated['legend']['font'][$set]        = $this->parameter['legend_font'];\r
+   //$this->calculated['legend']['points'][$set]      = $this->parameter['legend_size'];\r
+   //$this->calculated['legend']['angle'][$set]       = 0;\r
+\r
+   if ($text && $text!='none') {\r
+     $numSets++;\r
+     $sumTextHeight += $size['height'];\r
+   }\r
+\r
+   if ($size['width'] > $this->calculated['legend']['boundary_box_max']['width'])\r
+     $this->calculated['legend']['boundary_box_max'] = $size;\r
+  }\r
+\r
+  $offset  = $this->parameter['legend_offset'];  // offset in pixels of legend box from graph border.\r
+  $padding = $this->parameter['legend_padding']; // padding in pixels around legend text.\r
+  $textWidth = $this->calculated['legend']['boundary_box_max']['width']; // width of largest legend item.\r
+  $textHeight = $this->calculated['legend']['boundary_box_max']['height']; // use height as size to use for colour square in legend.\r
+  $width = $padding * 2 + $textWidth + $textHeight * 2;  // left and right padding + maximum text width + space for square\r
+  $height = $padding * ($numSets + 1) + $sumTextHeight; // top and bottom padding + padding between text + text.\r
+\r
+\r
+  $this->calculated['legend']['boundary_box_all'] = array('width'     => $width,\r
+                                                        'height'    => $height,\r
+                                                        'offset'    => $offset,\r
+                                                        'reference' => $position);\r
+\r
+  switch ($position) { // move in right or bottom if legend is outside data plotting area.\r
+    case 'outside-top' :\r
+      $this->calculated['boundary_box']['right']      -= $offset + $width; // move in right hand side\r
+      break;\r
+\r
+    case 'outside-bottom' :\r
+      $this->calculated['boundary_box']['right']      -= $offset + $width; // move in right hand side\r
+      break;\r
+\r
+    case 'outside-left' :\r
+      $this->calculated['boundary_box']['bottom']      -= $offset + $height; // move in right hand side\r
+      break;\r
+\r
+    case 'outside-right' :\r
+      $this->calculated['boundary_box']['bottom']      -= $offset + $height; // move in right hand side\r
+      break;\r
+  }\r
+}\r
+\r
+function init_y_axis() {\r
+  $this->calculated['y_axis_left'] = array(); // array to hold calculated values for y_axis on left.\r
+  $this->calculated['y_axis_left']['boundary_box_max'] = $this->get_null_size();\r
+  $this->calculated['y_axis_right'] = array(); // array to hold calculated values for y_axis on right.\r
+  $this->calculated['y_axis_right']['boundary_box_max'] = $this->get_null_size();\r
+\r
+  $axis_font       = $this->parameter['axis_font'];\r
+  $axis_size       = $this->parameter['axis_size'];\r
+  $axis_colour     = $this->parameter['axis_colour'];\r
+  $axis_angle      = $this->parameter['y_axis_angle'];\r
+\r
+  $this->calculated['y_axis_left']['has_data'] = FALSE;\r
+  $this->calculated['y_axis_right']['has_data'] = FALSE;\r
+\r
+  // find min and max y values.\r
+  $minLeft = $this->parameter['y_min_left'];\r
+  $maxLeft = $this->parameter['y_max_left'];\r
+  $minRight = $this->parameter['y_min_right'];\r
+  $maxRight = $this->parameter['y_max_right'];\r
+  $dataLeft = array();\r
+  $dataRight = array();\r
+  foreach ($this->y_order as $order => $set) {\r
+    if (isset($this->y_format[$set]['y_axis']) && $this->y_format[$set]['y_axis'] == 'right') {\r
+      $this->calculated['y_axis_right']['has_data'] = TRUE;\r
+      $dataRight = array_merge($dataRight, $this->y_data[$set]);\r
+    } else {\r
+      $this->calculated['y_axis_left']['has_data'] = TRUE;\r
+      $dataLeft = array_merge($dataLeft, $this->y_data[$set]);\r
+    }\r
+  }\r
+  $dataLeftRange = $this->find_range($dataLeft, $minLeft, $maxLeft, $this->parameter['y_resolution_left']);\r
+  $dataRightRange = $this->find_range($dataRight, $minRight, $maxRight, $this->parameter['y_resolution_right']);\r
+  $minLeft = $dataLeftRange['min'];\r
+  $maxLeft = $dataLeftRange['max'];\r
+  $minRight = $dataRightRange['min'];\r
+  $maxRight = $dataRightRange['max'];\r
+\r
+  $this->calculated['y_axis_left']['min']  = $minLeft;\r
+  $this->calculated['y_axis_left']['max']  = $maxLeft;\r
+  $this->calculated['y_axis_right']['min'] = $minRight;\r
+  $this->calculated['y_axis_right']['max'] = $maxRight;\r
+\r
+  $stepLeft = ($maxLeft - $minLeft) / ($this->parameter['y_axis_gridlines'] - 1);\r
+  $startLeft = $minLeft;\r
+  $step_right = ($maxRight - $minRight) / ($this->parameter['y_axis_gridlines'] - 1);\r
+  $start_right = $minRight;\r
+\r
+  if ($this->parameter['y_axis_text_left']) {\r
+    for ($i = 0; $i < $this->parameter['y_axis_gridlines']; $i++) { // calculate y axis text sizes\r
+      // left y axis\r
+      $value = number_format($startLeft, $this->parameter['y_decimal_left'], $this->parameter['decimal_point'], $this->parameter['thousand_sep']);\r
+      $this->calculated['y_axis_left']['data'][$i]  = $startLeft;\r
+      $this->calculated['y_axis_left']['text'][$i]  = $value; // text is formatted raw data\r
+\r
+      $size = $this->get_boundaryBox(\r
+        array('points' => $axis_size,\r
+              'font'   => $axis_font,\r
+              'angle'  => $axis_angle,\r
+              'colour' => $axis_colour,\r
+              'text'   => $value));\r
+      $this->calculated['y_axis_left']['boundary_box'][$i] = $size;\r
+\r
+      if ($size['height'] > $this->calculated['y_axis_left']['boundary_box_max']['height'])\r
+        $this->calculated['y_axis_left']['boundary_box_max']['height'] = $size['height'];\r
+      if ($size['width'] > $this->calculated['y_axis_left']['boundary_box_max']['width'])\r
+        $this->calculated['y_axis_left']['boundary_box_max']['width'] = $size['width'];\r
+\r
+      $startLeft += $stepLeft;\r
+    }\r
+    $this->calculated['boundary_box']['left'] += $this->calculated['y_axis_left']['boundary_box_max']['width']\r
+                                                + $this->parameter['inner_padding'];\r
+  }\r
+\r
+  if ($this->parameter['y_axis_text_right']) {\r
+    for ($i = 0; $i < $this->parameter['y_axis_gridlines']; $i++) { // calculate y axis text sizes\r
+      // right y axis\r
+      $value = number_format($start_right, $this->parameter['y_decimal_right'], $this->parameter['decimal_point'], $this->parameter['thousand_sep']);\r
+      $this->calculated['y_axis_right']['data'][$i]  = $start_right;\r
+      $this->calculated['y_axis_right']['text'][$i]  = $value; // text is formatted raw data\r
+      $size = $this->get_boundaryBox(\r
+        array('points' => $axis_size,\r
+              'font'   => $axis_font,\r
+              'angle'  => $axis_angle,\r
+              'colour' => $axis_colour,\r
+              'text'   => $value));\r
+      $this->calculated['y_axis_right']['boundary_box'][$i] = $size;\r
+\r
+      if ($size['height'] > $this->calculated['y_axis_right']['boundary_box_max']['height'])\r
+        $this->calculated['y_axis_right']['boundary_box_max'] = $size;\r
+      if ($size['width'] > $this->calculated['y_axis_right']['boundary_box_max']['width'])\r
+        $this->calculated['y_axis_right']['boundary_box_max']['width'] = $size['width'];\r
+\r
+      $start_right += $step_right;\r
+    }\r
+    $this->calculated['boundary_box']['right'] -= $this->calculated['y_axis_right']['boundary_box_max']['width']\r
+                                                + $this->parameter['inner_padding'];\r
+  }\r
+}\r
+\r
+function init_x_axis() {\r
+  $this->calculated['x_axis'] = array(); // array to hold calculated values for x_axis.\r
+  $this->calculated['x_axis']['boundary_box_max'] = array('height' => 0, 'width' => 0);\r
+\r
+  $axis_font       = $this->parameter['axis_font'];\r
+  $axis_size       = $this->parameter['axis_size'];\r
+  $axis_colour     = $this->parameter['axis_colour'];\r
+  $axis_angle      = $this->parameter['x_axis_angle'];\r
+\r
+  // check whether to treat x axis as numeric\r
+  if ($this->parameter['x_axis_gridlines'] == 'auto') { // auto means text based x_axis, not numeric...\r
+    $this->calculated['x_axis']['num_ticks'] = sizeof($this->x_data);\r
+      $data = $this->x_data;\r
+      for ($i=0; $i < $this->calculated['x_axis']['num_ticks']; $i++) {\r
+        $value = array_shift($data); // grab value from begin of array\r
+        $this->calculated['x_axis']['data'][$i]  = $value;\r
+        $this->calculated['x_axis']['text'][$i]  = $value; // raw data and text are both the same in this case\r
+        $size = $this->get_boundaryBox(\r
+          array('points' => $axis_size,\r
+                'font'   => $axis_font,\r
+                'angle'  => $axis_angle,\r
+                'colour' => $axis_colour,\r
+                'text'   => $value));\r
+        $this->calculated['x_axis']['boundary_box'][$i] = $size;\r
+        if ($size['height'] > $this->calculated['x_axis']['boundary_box_max']['height'])\r
+          $this->calculated['x_axis']['boundary_box_max'] = $size;\r
+      }\r
+\r
+  } else { // x axis is numeric so find max min values...\r
+    $this->calculated['x_axis']['num_ticks'] = $this->parameter['x_axis_gridlines'];\r
+\r
+    $min = $this->parameter['x_min'];\r
+    $max = $this->parameter['x_max'];\r
+    $data = array();\r
+    $data = $this->find_range($this->x_data, $min, $max, $this->parameter['x_resolution']);\r
+    $min = $data['min'];\r
+    $max = $data['max'];\r
+    $this->calculated['x_axis']['min'] = $min;\r
+    $this->calculated['x_axis']['max'] = $max;\r
+\r
+    $step = ($max - $min) / ($this->calculated['x_axis']['num_ticks'] - 1);\r
+    $start = $min;\r
+\r
+    for ($i = 0; $i < $this->calculated['x_axis']['num_ticks']; $i++) { // calculate x axis text sizes\r
+      $value = number_format($start, $this->parameter['xDecimal'], $this->parameter['decimal_point'], $this->parameter['thousand_sep']);\r
+      $this->calculated['x_axis']['data'][$i]  = $start;\r
+      $this->calculated['x_axis']['text'][$i]  = $value; // text is formatted raw data\r
+\r
+      $size = $this->get_boundaryBox(\r
+        array('points' => $axis_size,\r
+              'font'   => $axis_font,\r
+              'angle'  => $axis_angle,\r
+              'colour' => $axis_colour,\r
+              'text'   => $value));\r
+      $this->calculated['x_axis']['boundary_box'][$i] = $size;\r
+\r
+      if ($size['height'] > $this->calculated['x_axis']['boundary_box_max']['height'])\r
+        $this->calculated['x_axis']['boundary_box_max'] = $size;\r
+\r
+      $start += $step;\r
+    }\r
+  }\r
+  if ($this->parameter['x_axis_text'])\r
+    $this->calculated['boundary_box']['bottom'] -= $this->calculated['x_axis']['boundary_box_max']['height']\r
+                                                  + $this->parameter['inner_padding'];\r
+}\r
+\r
+// find max and min values for a data array given the resolution.\r
+function find_range($data, $min, $max, $resolution) {\r
+  if (sizeof($data) == 0 ) return array('min' => 0, 'max' => 0);\r
+  foreach ($data as $key => $value) {\r
+    if ($value=='none') continue;\r
+    if ($value > $max) $max = $value;\r
+    if ($value < $min) $min = $value;\r
+  }\r
+\r
+  if ($max == 0) {\r
+    $factor = 1;\r
+  } else {\r
+    if ($max < 0) $factor = - pow(10, (floor(log10(abs($max))) + $resolution) );\r
+    else $factor = pow(10, (floor(log10(abs($max))) - $resolution) );\r
+  }\r
+\r
+  $max = $factor * @ceil($max / $factor);\r
+  $min = $factor * @floor($min / $factor);\r
+\r
+  //print "max=$max, min=$min<BR>";\r
+\r
+  return array('min' => $min, 'max' => $max);\r
+}\r
+\r
+function graph() {\r
+  if (func_num_args() == 2) {\r
+    $this->parameter['width']  = func_get_arg(0);\r
+    $this->parameter['height'] = func_get_arg(1);\r
+  }\r
+  //$this->boundaryBox  = array(\r
+  $this->calculated['boundary_box'] = array(\r
+    'left'      =>  0,\r
+    'top'       =>  0,\r
+    'right'     =>  $this->parameter['width'] - 1,\r
+    'bottom'    =>  $this->parameter['height'] - 1);\r
+\r
+  $this->init_colours();\r
+\r
+  //ImageColorTransparent($this->image, $this->colour['white']); // colour for transparency\r
+}\r
+\r
+function print_TTF($message) {\r
+  $points    = $message['points'];\r
+  $angle     = $message['angle'];\r
+  $text      = $message['text'];\r
+  $colour    = $this->colour[$message['colour']];\r
+  $font      = $this->parameter['path_to_fonts'].$message['font'];\r
+\r
+  $x         = $message['boundary_box']['x'];\r
+  $y         = $message['boundary_box']['y'];\r
+  $offsetX   = $message['boundary_box']['offsetX'];\r
+  $offsetY   = $message['boundary_box']['offsetY'];\r
+  $height    = $message['boundary_box']['height'];\r
+  $width     = $message['boundary_box']['width'];\r
+  $reference = $message['boundary_box']['reference'];\r
+\r
+  switch ($reference) {\r
+    case 'top-left':\r
+    case 'left-top':\r
+      $y += $height - $offsetY;\r
+      //$y += $offsetY;\r
+      $x += $offsetX;\r
+      break;\r
+    case 'left-center':\r
+      $y += ($height / 2) - $offsetY;\r
+      $x += $offsetX;\r
+      break;\r
+    case 'left-bottom':\r
+      $y -= $offsetY;\r
+      $x += $offsetX;\r
+     break;\r
+    case 'top-center':\r
+      $y += $height - $offsetY;\r
+      $x -= ($width / 2) - $offsetX;\r
+     break;\r
+    case 'top-right':\r
+    case 'right-top':\r
+      $y += $height - $offsetY;\r
+      $x -= $width  - $offsetX;\r
+      break;\r
+    case 'right-center':\r
+      $y += ($height / 2) - $offsetY;\r
+      $x -= $width  - $offsetX;\r
+      break;\r
+    case 'right-bottom':\r
+      $y -= $offsetY;\r
+      $x -= $width  - $offsetX;\r
+      break;\r
+    case 'bottom-center':\r
+      $y -= $offsetY;\r
+      $x -= ($width / 2) - $offsetX;\r
+     break;\r
+    default:\r
+      $y = 0;\r
+      $x = 0;\r
+      break;\r
+  }\r
+  ImageTTFText($this->image, $points, $angle, $x, $y, $colour, $font, $text);\r
+}\r
+\r
+// move boundaryBox to coordinates specified\r
+function update_boundaryBox(&$boundaryBox, $coords) {\r
+  $width      = $boundaryBox['width'];\r
+  $height     = $boundaryBox['height'];\r
+  $x          = $coords['x'];\r
+  $y          = $coords['y'];\r
+  $reference  = $coords['reference'];\r
+  switch ($reference) {\r
+    case 'top-left':\r
+    case 'left-top':\r
+      $top    = $y;\r
+      $bottom = $y + $height;\r
+      $left   = $x;\r
+      $right  = $x + $width;\r
+      break;\r
+    case 'left-center':\r
+      $top    = $y - ($height / 2);\r
+      $bottom = $y + ($height / 2);\r
+      $left   = $x;\r
+      $right  = $x + $width;\r
+      break;\r
+    case 'left-bottom':\r
+      $top    = $y - $height;\r
+      $bottom = $y;\r
+      $left   = $x;\r
+      $right  = $x + $width;\r
+      break;\r
+    case 'top-center':\r
+      $top    = $y;\r
+      $bottom = $y + $height;\r
+      $left   = $x - ($width / 2);\r
+      $right  = $x + ($width / 2);\r
+      break;\r
+    case 'right-top':\r
+    case 'top-right':\r
+      $top    = $y;\r
+      $bottom = $y + $height;\r
+      $left   = $x - $width;\r
+      $right  = $x;\r
+      break;\r
+    case 'right-center':\r
+      $top    = $y - ($height / 2);\r
+      $bottom = $y + ($height / 2);\r
+      $left   = $x - $width;\r
+      $right  = $x;\r
+      break;\r
+    case 'bottom=right':\r
+    case 'right-bottom':\r
+      $top    = $y - $height;\r
+      $bottom = $y;\r
+      $left   = $x - $width;\r
+      $right  = $x;\r
+      break;\r
+    default:\r
+      $top    = 0;\r
+      $bottom = $height;\r
+      $left   = 0;\r
+      $right  = $width;\r
+      break;\r
+  }\r
+\r
+  $boundaryBox = array_merge($boundaryBox, array('top'       => $top,\r
+                                                 'bottom'    => $bottom,\r
+                                                 'left'      => $left,\r
+                                                 'right'     => $right,\r
+                                                 'x'         => $x,\r
+                                                 'y'         => $y,\r
+                                                 'reference' => $reference));\r
+}\r
+\r
+function get_null_size() {\r
+       return array('width'      => 0,\r
+                    'height'     => 0,\r
+                    'offsetX'    => 0,\r
+                    'offsetY'    => 0,\r
+                    //'fontHeight' => 0\r
+                    );\r
+}\r
+\r
+function get_boundaryBox($message) {\r
+  $points  = $message['points'];\r
+  $angle   = $message['angle'];\r
+  $font    = $this->parameter['path_to_fonts'].$message['font'];\r
+  $text    = $message['text'];\r
+\r
+  //print ('get_boundaryBox');\r
+  //expandPre($message);\r
+\r
+  // get font size\r
+       $bounds = ImageTTFBBox($points, $angle, $font, "W");\r
+       if ($angle < 0) {\r
+               $fontHeight = abs($bounds[7]-$bounds[1]);\r
+       } else if ($angle > 0) {\r
+               $fontHeight = abs($bounds[1]-$bounds[7]);\r
+       } else {\r
+               $fontHeight = abs($bounds[7]-$bounds[1]);\r
+       }\r
+\r
+       // get boundary box and offsets for printing at an angle\r
+       $bounds = ImageTTFBBox($points, $angle, $font, $text);\r
+\r
+       if ($angle < 0) {\r
+               $width = abs($bounds[4]-$bounds[0]);\r
+               $height = abs($bounds[3]-$bounds[7]);\r
+               $offsetY = abs($bounds[3]-$bounds[1]);\r
+               $offsetX = 0;\r
+\r
+       } else if ($angle > 0) {\r
+               $width = abs($bounds[2]-$bounds[6]);\r
+               $height = abs($bounds[1]-$bounds[5]);\r
+               $offsetY = 0;\r
+               $offsetX = abs($bounds[0]-$bounds[6]);\r
+\r
+       } else {\r
+               $width = abs($bounds[4]-$bounds[6]);\r
+               $height = abs($bounds[7]-$bounds[1]);\r
+               $offsetY = 0;\r
+               $offsetX = 0;\r
+       }\r
+\r
+       //return values\r
+       return array('width'      => $width,\r
+                    'height'     => $height,\r
+                    'offsetX'    => $offsetX,\r
+                    'offsetY'    => $offsetY,\r
+                    //'fontHeight' => $fontHeight\r
+                    );\r
+}\r
+\r
+function draw_rectangle($border, $colour, $type) {\r
+  $colour = $this->colour[$colour];\r
+  switch ($type) {\r
+    case 'fill':    // fill the rectangle\r
+      ImageFilledRectangle($this->image, $border['left'], $border['top'], $border['right'], $border['bottom'], $colour);\r
+      break;\r
+    case 'box':     // all sides\r
+      ImageRectangle($this->image, $border['left'], $border['top'], $border['right'], $border['bottom'], $colour);\r
+      break;\r
+    case 'axis':    // bottom x axis and left y axis\r
+      ImageLine($this->image, $border['left'], $border['top'], $border['left'], $border['bottom'], $colour);\r
+      ImageLine($this->image, $border['left'], $border['bottom'], $border['right'], $border['bottom'], $colour);\r
+      break;\r
+    case 'y':       // left y axis only\r
+    case 'y-left':\r
+      ImageLine($this->image, $border['left'], $border['top'], $border['left'], $border['bottom'], $colour);\r
+      break;\r
+    case 'y-right': // right y axis only\r
+      ImageLine($this->image, $border['right'], $border['top'], $border['right'], $border['bottom'], $colour);\r
+      break;\r
+    case 'x':       // bottom x axis only\r
+      ImageLine($this->image, $border['left'], $border['bottom'], $border['right'], $border['bottom'], $colour);\r
+      break;\r
+    case 'u':       // u shaped. bottom x axis and both left and right y axis.\r
+      ImageLine($this->image, $border['left'], $border['top'], $border['left'], $border['bottom'], $colour);\r
+      ImageLine($this->image, $border['right'], $border['top'], $border['right'], $border['bottom'], $colour);\r
+      ImageLine($this->image, $border['left'], $border['bottom'], $border['right'], $border['bottom'], $colour);\r
+      break;\r
+\r
+  }\r
+}\r
+\r
+function init_colours() {\r
+  $this->image              = ImageCreate($this->parameter['width'], $this->parameter['height']);\r
+  // standard colours\r
+  $this->colour['white']    = ImageColorAllocate ($this->image, 0xFF, 0xFF, 0xFF); // first colour is background colour.\r
+  $this->colour['black']    = ImageColorAllocate ($this->image, 0x00, 0x00, 0x00);\r
+  $this->colour['maroon']   = ImageColorAllocate ($this->image, 0x80, 0x00, 0x00);\r
+  $this->colour['green']    = ImageColorAllocate ($this->image, 0x00, 0x80, 0x00);\r
+  $this->colour['ltgreen']  = ImageColorAllocate ($this->image, 0x52, 0xF1, 0x7F);\r
+  $this->colour['ltltgreen']= ImageColorAllocate ($this->image, 0x99, 0xFF, 0x99);\r
+  $this->colour['olive']    = ImageColorAllocate ($this->image, 0x80, 0x80, 0x00);\r
+  $this->colour['navy']     = ImageColorAllocate ($this->image, 0x00, 0x00, 0x80);\r
+  $this->colour['purple']   = ImageColorAllocate ($this->image, 0x80, 0x00, 0x80);\r
+  $this->colour['gray']     = ImageColorAllocate ($this->image, 0x80, 0x80, 0x80);\r
+  $this->colour['red']      = ImageColorAllocate ($this->image, 0xFF, 0x00, 0x00);\r
+  $this->colour['lime']     = ImageColorAllocate ($this->image, 0x00, 0xFF, 0x00);\r
+  $this->colour['yellow']   = ImageColorAllocate ($this->image, 0xFF, 0xFF, 0x00);\r
+  $this->colour['blue']     = ImageColorAllocate ($this->image, 0x00, 0x00, 0xFF);\r
+  $this->colour['ltblue']   = ImageColorAllocate ($this->image, 0x00, 0xCC, 0xFF);\r
+  $this->colour['ltltblue'] = ImageColorAllocate ($this->image, 0x99, 0xFF, 0xFF);\r
+  $this->colour['fuchsia']  = ImageColorAllocate ($this->image, 0xFF, 0x00, 0xFF);\r
+  $this->colour['aqua']     = ImageColorAllocate ($this->image, 0x00, 0xFF, 0xFF);\r
+  //$this->colour['white']    = ImageColorAllocate ($this->image, 0xFF, 0xFF, 0xFF);\r
+  // shades of gray\r
+  $this->colour['grayF0']   = ImageColorAllocate ($this->image, 0xF0, 0xF0, 0xF0);\r
+  $this->colour['grayEE']   = ImageColorAllocate ($this->image, 0xEE, 0xEE, 0xEE);\r
+  $this->colour['grayDD']   = ImageColorAllocate ($this->image, 0xDD, 0xDD, 0xDD);\r
+  $this->colour['grayCC']   = ImageColorAllocate ($this->image, 0xCC, 0xCC, 0xCC);\r
+  $this->colour['gray33']   = ImageColorAllocate ($this->image, 0x33, 0x33, 0x33);\r
+  $this->colour['gray66']   = ImageColorAllocate ($this->image, 0x66, 0x66, 0x66);\r
+  $this->colour['gray99']   = ImageColorAllocate ($this->image, 0x99, 0x99, 0x99);\r
+\r
+  $this->colour['none']   = 'none';\r
+  return true;\r
+}\r
+\r
+function output() {\r
+  if ($this->debug) { // for debugging purposes.\r
+    //expandPre($this->graph);\r
+    //expandPre($this->y_data);\r
+    //expandPre($this->x_data);\r
+    //expandPre($this->parameter);\r
+  } else {\r
+\r
+    $expiresSeconds = $this->parameter['seconds_to_live'];\r
+    $expiresHours = $this->parameter['hours_to_live'];\r
+\r
+    if ($expiresHours || $expiresSeconds) {\r
+      $now = mktime (date("H"),date("i"),date("s"),date("m"),date("d"),date("Y"));\r
+      $expires = mktime (date("H")+$expiresHours,date("i"),date("s")+$expiresSeconds,date("m"),date("d"),date("Y"));\r
+      $expiresGMT = gmdate('D, d M Y H:i:s', $expires).' GMT';\r
+      $lastModifiedGMT  = gmdate('D, d M Y H:i:s', $now).' GMT';\r
+\r
+      Header('Last-modified: '.$lastModifiedGMT);\r
+      Header('Expires: '.$expiresGMT);\r
+    }\r
+\r
+    if ($this->parameter['file_name'] == 'none') {\r
+      switch ($this->parameter['output_format']) {\r
+        case 'GIF':\r
+          Header("Content-type: image/gif");  // GIF??. switch to PNG guys!!\r
+          ImageGIF($this->image);\r
+          break;\r
+        case 'JPEG':\r
+          Header("Content-type: image/jpeg"); // JPEG for line art??. included for completeness.\r
+          ImageJPEG($this->image);\r
+          break;\r
+       default:\r
+          Header("Content-type: image/png");  // preferred output format\r
+          ImagePNG($this->image);\r
+          break;\r
+      }\r
+    } else {\r
+       switch ($this->parameter['output_format']) {\r
+        case 'GIF':\r
+          ImageGIF($this->image, $this->parameter['file_name'].'.gif');\r
+          break;\r
+        case 'JPEG':\r
+          ImageJPEG($this->image, $this->parameter['file_name'].'.jpg');\r
+          break;\r
+       default:\r
+          ImagePNG($this->image, $this->parameter['file_name'].'.png');\r
+          break;\r
+      }\r
+    }\r
+\r
+    ImageDestroy($this->image);\r
+  }\r
+} // function output\r
+\r
+function init_variable(&$variable, $value, $default) {\r
+       if (!empty($value)) $variable = $value;\r
+       else if (isset($default)) $variable = $default;\r
+       else unset($variable);\r
+}\r
+\r
+// plot a point. options include square, circle, diamond, triangle, and dot. offset is used for drawing shadows.\r
+// for diamonds and triangles the size should be an even number to get nice look. if odd the points are crooked.\r
+function plot($x, $y, $type, $size, $colour, $offset) {\r
+  //print("drawing point of type: $type, at offset: $offset");\r
+  $u = $x + $offset;\r
+  $v = $this->calculated['inner_border']['bottom'] - $y + $offset;\r
+  $half = $size / 2;\r
+\r
+  switch ($type) {\r
+    case 'square':\r
+      ImageFilledRectangle($this->image, $u-$half, $v-$half, $u+$half, $v+$half, $this->colour[$colour]);\r
+      break;\r
+    case 'square-open':\r
+      ImageRectangle($this->image, $u-$half, $v-$half, $u+$half, $v+$half, $this->colour[$colour]);\r
+      break;\r
+    case 'circle':\r
+      ImageArc($this->image, $u, $v, $size, $size, 0, 360, $this->colour[$colour]);\r
+      ImageFillToBorder($this->image, $u, $v, $this->colour[$colour], $this->colour[$colour]);\r
+      break;\r
+    case 'circle-open':\r
+      ImageArc($this->image, $u, $v, $size, $size, 0, 360, $this->colour[$colour]);\r
+      break;\r
+    case 'diamond':\r
+      ImageFilledPolygon($this->image, array($u, $v-$half, $u+$half, $v, $u, $v+$half, $u-$half, $v), 4, $this->colour[$colour]);\r
+      break;\r
+    case 'diamond-open':\r
+      ImagePolygon($this->image, array($u, $v-$half, $u+$half, $v, $u, $v+$half, $u-$half, $v), 4, $this->colour[$colour]);\r
+      break;\r
+    case 'triangle':\r
+      ImageFilledPolygon($this->image, array($u, $v-$half, $u+$half, $v+$half, $u-$half, $v+$half), 3, $this->colour[$colour]);\r
+      break;\r
+    case 'triangle-open':\r
+      ImagePolygon($this->image, array($u, $v-$half, $u+$half, $v+$half, $u-$half, $v+$half), 3, $this->colour[$colour]);\r
+      break;\r
+    case 'dot':\r
+      ImageSetPixel($this->image, $u, $v, $this->colour[$colour]);\r
+      break;\r
+  }\r
+}\r
+\r
+function bar($x, $y, $type, $size, $colour, $offset, $index, $yoffset) {\r
+  $index_offset = $this->calculated['bar_offset_index'][$index];\r
+  if ( $yoffset ) {\r
+    $bar_offsetx = 0;\r
+  } else {\r
+    $bar_offsetx = $this->calculated['bar_offset_x'][$index_offset];\r
+  }\r
+  //$this->dbug("drawing bar at offset = $offset : index = $index: bar_offsetx = $bar_offsetx");\r
+\r
+  $span = ($this->calculated['bar_width'] * $size) / 2;\r
+  $x_left  = $x + $bar_offsetx - $span;\r
+  $x_right = $x + $bar_offsetx + $span;\r
+\r
+  if ($this->parameter['zero_axis'] != 'none') {\r
+    $zero = $this->calculated['zero_axis'];\r
+    if ($this->parameter['shadow_below_axis'] ) $zero  += $offset;\r
+    $u_left  = $x_left + $offset;\r
+    $u_right = $x_right + $offset - 1;\r
+    $v       = $this->calculated['boundary_box']['bottom'] - $y + $offset;\r
+\r
+    if ($v > $zero) {\r
+      $top = $zero +1;\r
+      $bottom = $v;\r
+    } else {\r
+      $top = $v;\r
+      $bottom = $zero - 1;\r
+    }\r
+\r
+    switch ($type) {\r
+      case 'open':\r
+        //ImageRectangle($this->image, round($u_left), $top, round($u_right), $bottom, $this->colour[$colour]);\r
+        if ($v > $zero)\r
+          ImageRectangle($this->image, round($u_left), $bottom, round($u_right), $bottom, $this->colour[$colour]);\r
+        else\r
+          ImageRectangle($this->image, round($u_left), $top, round($u_right), $top, $this->colour[$colour]);\r
+        ImageRectangle($this->image, round($u_left), $top, round($u_left), $bottom, $this->colour[$colour]);\r
+        ImageRectangle($this->image, round($u_right), $top, round($u_right), $bottom, $this->colour[$colour]);\r
+        break;\r
+      case 'fill':\r
+        ImageFilledRectangle($this->image, round($u_left), $top, round($u_right), $bottom, $this->colour[$colour]);\r
+        break;\r
+    }\r
+\r
+  } else {\r
+\r
+    $bottom = $this->calculated['boundary_box']['bottom'];\r
+    if ($this->parameter['shadow_below_axis'] ) $bottom  += $offset;\r
+    if ($this->parameter['inner_border'] != 'none') $bottom -= 1; // 1 pixel above bottom if border is to be drawn.\r
+    $u_left  = $x_left + $offset;\r
+    $u_right = $x_right + $offset - 1;\r
+    $v       = $this->calculated['boundary_box']['bottom'] - $y + $offset;\r
+\r
+    // Moodle addition, plus the function parameter yoffset\r
+    if ($yoffset) {\r
+        $yoffset = $yoffset - round(($bottom - $v) / 2.0);\r
+        $bottom -= $yoffset;\r
+        $v      -= $yoffset;\r
+    }\r
+\r
+    switch ($type) {\r
+      case 'open':\r
+        ImageRectangle($this->image, round($u_left), $v, round($u_right), $bottom, $this->colour[$colour]);\r
+        break;\r
+      case 'fill':\r
+        ImageFilledRectangle($this->image, round($u_left), $v, round($u_right), $bottom, $this->colour[$colour]);\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+function area($x_start, $y_start, $x_end, $y_end, $type, $colour, $offset) {\r
+  //dbug("drawing area type: $type, at offset: $offset");\r
+  if ($this->parameter['zero_axis'] != 'none') {\r
+    $bottom = $this->calculated['boundary_box']['bottom'];\r
+    $zero   = $this->calculated['zero_axis'];\r
+    if ($this->parameter['shadow_below_axis'] ) $zero  += $offset;\r
+    $u_start = $x_start + $offset;\r
+    $u_end   = $x_end + $offset;\r
+    $v_start = $bottom - $y_start + $offset;\r
+    $v_end   = $bottom - $y_end + $offset;\r
+    switch ($type) {\r
+      case 'fill':\r
+        // draw it this way 'cos the FilledPolygon routine seems a bit buggy.\r
+        ImageFilledPolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $zero, $u_start, $zero), 4, $this->colour[$colour]);\r
+        ImagePolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $zero, $u_start, $zero), 4, $this->colour[$colour]);\r
+       break;\r
+      case 'open':\r
+        //ImagePolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $zero, $u_start, $zero), 4, $this->colour[$colour]);\r
+        ImageLine($this->image, $u_start, $v_start, $u_end, $v_end, $this->colour[$colour]);\r
+        ImageLine($this->image, $u_start, $v_start, $u_start, $zero, $this->colour[$colour]);\r
+        ImageLine($this->image, $u_end, $v_end, $u_end, $zero, $this->colour[$colour]);\r
+       break;\r
+    }\r
+  } else {\r
+    $bottom = $this->calculated['boundary_box']['bottom'];\r
+    $u_start = $x_start + $offset;\r
+    $u_end   = $x_end + $offset;\r
+    $v_start = $bottom - $y_start + $offset;\r
+    $v_end   = $bottom - $y_end + $offset;\r
+\r
+    if ($this->parameter['shadow_below_axis'] ) $bottom  += $offset;\r
+    if ($this->parameter['inner_border'] != 'none') $bottom -= 1; // 1 pixel above bottom if border is to be drawn.\r
+    switch ($type) {\r
+      case 'fill':\r
+        ImageFilledPolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $bottom, $u_start, $bottom), 4, $this->colour[$colour]);\r
+       break;\r
+      case 'open':\r
+        ImagePolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $bottom, $u_start, $bottom), 4, $this->colour[$colour]);\r
+       break;\r
+    }\r
+  }\r
+}\r
+\r
+function line($x_start, $y_start, $x_end, $y_end, $type, $brush_type, $brush_size, $colour, $offset) {\r
+  //dbug("drawing line of type: $type, at offset: $offset");\r
+  $u_start = $x_start + $offset;\r
+  $v_start = $this->calculated['boundary_box']['bottom'] - $y_start + $offset;\r
+  $u_end   = $x_end + $offset;\r
+  $v_end   = $this->calculated['boundary_box']['bottom'] - $y_end + $offset;\r
+\r
+  switch ($type) {\r
+    case 'brush':\r
+      $this->draw_brush_line($u_start, $v_start, $u_end, $v_end, $brush_size, $brush_type, $colour);\r
+     break;\r
+    case 'line' :\r
+      ImageLine($this->image, $u_start, $v_start, $u_end, $v_end, $this->colour[$colour]);\r
+      break;\r
+    case 'dash':\r
+      ImageDashedLine($this->image, $u_start, $v_start, $u_end, $v_end, $this->colour[$colour]);\r
+      break;\r
+  }\r
+}\r
+\r
+// function to draw line. would prefer to use gdBrush but this is not supported yet.\r
+function draw_brush_line($x0, $y0, $x1, $y1, $size, $type, $colour) {\r
+  //$this->dbug("line: $x0, $y0, $x1, $y1");\r
+  $dy = $y1 - $y0;\r
+  $dx = $x1 - $x0;\r
+  $t = 0;\r
+  $watchdog = 1024; // precaution to prevent infinite loops.\r
+\r
+  $this->draw_brush($x0, $y0, $size, $type, $colour);\r
+  if (abs($dx) > abs($dy)) { // slope < 1\r
+    //$this->dbug("slope < 1");\r
+    $m = $dy / $dx; // compute slope\r
+    $t += $y0;\r
+    $dx = ($dx < 0) ? -1 : 1;\r
+    $m *= $dx;\r
+    while (round($x0) != round($x1)) {\r
+      if (!$watchdog--) break;\r
+      $x0 += $dx; // step to next x value\r
+      $t += $m;   // add slope to y value\r
+      $y = round($t);\r
+      //$this->dbug("x0=$x0, x1=$x1, y=$y watchdog=$watchdog");\r
+      $this->draw_brush($x0, $y, $size, $type, $colour);\r
+\r
+    }\r
+  } else { // slope >= 1\r
+    //$this->dbug("slope >= 1");\r
+    $m = $dx / $dy; // compute slope\r
+    $t += $x0;\r
+    $dy = ($dy < 0) ? -1 : 1;\r
+    $m *= $dy;\r
+    while (round($y0) != round($y1)) {\r
+      if (!$watchdog--) break;\r
+      $y0 += $dy; // step to next y value\r
+      $t += $m;   // add slope to x value\r
+      $x = round($t);\r
+      //$this->dbug("x=$x, y0=$y0, y1=$y1 watchdog=$watchdog");\r
+      $this->draw_brush($x, $y0, $size, $type, $colour);\r
+\r
+    }\r
+  }\r
+}\r
+\r
+function draw_brush($x, $y, $size, $type, $colour) {\r
+  $x = round($x);\r
+  $y = round($y);\r
+  $half = round($size / 2);\r
+  switch ($type) {\r
+    case 'circle':\r
+      ImageArc($this->image, $x, $y, $size, $size, 0, 360, $this->colour[$colour]);\r
+      ImageFillToBorder($this->image, $x, $y, $this->colour[$colour], $this->colour[$colour]);\r
+      break;\r
+    case 'square':\r
+      ImageFilledRectangle($this->image, $x-$half, $y-$half, $x+$half, $y+$half, $this->colour[$colour]);\r
+      break;\r
+    case 'vertical':\r
+      ImageFilledRectangle($this->image, $x, $y-$half, $x+1, $y+$half, $this->colour[$colour]);\r
+      break;\r
+    case 'horizontal':\r
+      ImageFilledRectangle($this->image, $x-$half, $y, $x+$half, $y+1, $this->colour[$colour]);\r
+      break;\r
+    case 'slash':\r
+      ImageFilledPolygon($this->image, array($x+$half, $y-$half,\r
+                                             $x+$half+1, $y-$half,\r
+                                             $x-$half+1, $y+$half,\r
+                                             $x-$half, $y+$half\r
+                                             ), 4, $this->colour[$colour]);\r
+      break;\r
+    case 'backslash':\r
+      ImageFilledPolygon($this->image, array($x-$half, $y-$half,\r
+                                             $x-$half+1, $y-$half,\r
+                                             $x+$half+1, $y+$half,\r
+                                             $x+$half, $y+$half\r
+                                             ), 4, $this->colour[$colour]);\r
+      break;\r
+    default:\r
+      @eval($type); // user can create own brush script.\r
+  }\r
+}\r
+\r
+} // class graph\r
+\r
+\r
+?>\r
diff --git a/lib/javascript.php b/lib/javascript.php
new file mode 100644 (file)
index 0000000..8d74d4e
--- /dev/null
@@ -0,0 +1,19 @@
+\r
+<SCRIPT LANGUAGE="JavaScript">\r
+<!-- //hide\r
+function fillmessagebox(text) {\r
+  document.form.message.value = text;\r
+}\r
+\r
+function openpopup(url,name,height,width) {\r
+fullurl = "<?=$CFG->wwwroot ?>" + url;\r
+options = "menubar=0,location=0,scrollbars,resizable,width="+width+",height="+height;\r
+windowobj = window.open(fullurl,"name", options);\r
+windowobj.focus();\r
+}\r
+\r
+<? if ($focus) { echo "function setfocus() { document.$focus.focus() }\n"; } ?>\r
+\r
+// done hiding -->\r
+</SCRIPT>\r
+\r
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
new file mode 100644 (file)
index 0000000..a8c181a
--- /dev/null
@@ -0,0 +1,1163 @@
+<?PHP // $Id$
+
+//
+// moodlelib.php
+//
+// Large collection of useful functions used by many parts of Moodle.
+//
+// Martin Dougiamas, 2000
+//
+
+
+/// STANDARD WEB PAGE PARTS ///////////////////////////////////////////////////
+
+function print_header ($title="", $heading="", $navigation="", $focus="", $meta="",$cache=true) {
+// $title - appears top of window
+// $heading - appears top of page
+// $navigation - premade navigation string
+// $focus - indicates form element eg  inputform.password
+// $meta - meta tags in the header
+    global $USER, $CFG, $THEME;
+
+    if (file_exists("$CFG->dirroot/theme/$CFG->theme/styles.css")) {
+        $styles = "$CFG->wwwroot/theme/$CFG->theme/styles.css";
+    } else {
+        $styles = "$CFG->wwwroot/theme/standard/styles.css";
+    }
+    if (!$cache) {   // Do everything we can to prevent clients and proxies caching
+        @header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
+        @header("Pragma: no-cache");
+        $meta .= "\n<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">";
+        $meta .= "\n<META HTTP-EQUIV=\"Expires\" CONTENT=\"0\">";
+    }
+    include ("$CFG->dirroot/theme/$CFG->theme/header.html");
+}
+
+function print_footer ($course=NULL) {
+// Can provide a course object to make the footer contain a link to 
+// to the course home page, otherwise the link will go to the site home
+    global $USER, $CFG, $THEME;
+
+    if ($course) {
+        $homelink = "<A TARGET=_top HREF=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</A>";
+    } else {
+        $homelink = "<A TARGET=_top HREF=\"$CFG->wwwroot\">Home</A>";
+    }
+    include ("$CFG->dirroot/theme/$CFG->theme/footer.html");
+}
+
+function print_navigation ($navigation) {
+   global $CFG;
+
+   if ($navigation) {
+       echo "<A TARGET=_top HREF=\"$CFG->wwwroot/\">Home</A> -> $navigation";
+   }
+}
+
+function print_heading($heading) {
+    echo "<P ALIGN=CENTER><FONT SIZE=4><B>$heading</B></FONT></P>";
+}
+
+function print_simple_box($message, $align="", $width="", $color="#FFFFFF", $padding=5) {
+    print_simple_box_start($align, $width, $color, $padding);
+    echo "<P>$message</P>";
+    print_simple_box_end();
+}
+
+function print_simple_box_start($align="", $width="", $color="#FFFFFF", $padding=5) {
+    global $THEME;
+
+    if ($align) {
+        $tablealign = "ALIGN=\"$align\"";
+    }
+    if ($width) {
+        $tablewidth = "WIDTH=\"$width\"";
+        $innertablewidth = "WIDTH=\"100%\"";
+    }
+    echo "<TABLE $tablealign $tablewidth BORDER=0 CELLPADDING=1 CELLSPACING=0>";
+    echo "<TR><TD BGCOLOR=\"$THEME->borders\">\n";
+    echo "<TABLE $innertablewidth BORDER=0 CELLPADDING=\"$padding\" CELLSPACING=0><TR><TD BGCOLOR=\"$color\">";
+}
+
+function print_simple_box_end() {
+    echo "</TD></TR></TABLE>";
+    echo "</TD></TR></TABLE>";
+}
+
+function print_single_button($link, $options, $label="OK") {
+    echo "<FORM ACTION=\"$link\" METHOD=GET>";
+    foreach ($options as $name => $value) {
+        echo "<INPUT TYPE=hidden NAME=\"$name\" VALUE=\"$value\">";
+    }
+    echo "<INPUT TYPE=submit VALUE=\"$label\"></FORM>";
+}
+
+function print_user_picture($userid, $courseid, $picture, $large=false) {
+    global $CFG;
+
+    echo "<A HREF=\"$CFG->wwwroot/user/view.php?id=$userid&course=$courseid\">";
+    if ($large) {
+        $file = "f1.jpg";
+        $size = 100;
+    } else {
+        $file = "f2.jpg";
+        $size = 35;
+    }
+    if ($picture) {
+        echo "<IMG SRC=\"$CFG->wwwroot/user/pix.php/$userid/$file\" BORDER=0 WIDTH=$size HEIGHT=$size ALT=\"\">";
+    } else {
+        echo "<IMG SRC=\"$CFG->wwwroot/user/default/$file\" BORDER=0 WIDTH=$size HEIGHT=$size ALT=\"\">";
+    }
+    echo "</A>";
+}
+
+function print_table($table) {
+// Prints a nicely formatted table.
+// $table is an object with three properties.
+//     $table->head      is an array of heading names.
+//     $table->align     is an array of column alignments
+//     $table->data[]    is an array of arrays containing the data.
+
+    if ( $table->align) {
+        foreach ($table->align as $key => $aa) {
+            if ($aa) {
+                $align[$key] = "ALIGN=\"$aa\"";
+            } else {
+                $align[$key] = "";
+            }
+        }
+    }
+
+    echo "<BR>";
+
+    print_simple_box_start("CENTER","","#FFFFFF",0);
+    echo "<TABLE BORDER=0 valign=top align=center cellpadding=10 cellspacing=1>\n";
+
+    if ($table->head) {
+        echo "<TR>";
+        foreach ($table->head as $heading) {
+            echo "<TH>$heading</TH>";
+        }
+        echo "</TR>\n";
+    }
+
+    foreach ($table->data as $row) {
+        echo "<TR VALIGN=TOP>";
+        foreach ($row as $key => $item) {
+            echo "<TD ".$align[$key].">$item</TD>";
+        }
+        echo "</TR>\n";
+    }
+    echo "</TABLE>\n";
+    print_simple_box_end();
+
+    return true;
+}
+
+
+function moodledate($date) {
+    return date("l, j F Y, g:i A T", $date);
+}
+
+
+function error ($message, $link="") {
+    global $CFG, $SESSION;
+
+    print_header("Error");
+    echo "<BR>";
+    print_simple_box($message, "center", "", "#FFBBBB");
+   
+    if (!$link) {
+        if ( !empty($SESSION->fromurl) ) {
+            $link = "$SESSION->fromurl";
+            unset($SESSION->fromurl);
+        } else {
+            $link = "$CFG->wwwroot";
+        }
+    }
+    print_heading("<A HREF=\"$link\">Continue</A>");
+    print_footer();
+    die;
+}
+
+function notice ($message, $link="") {
+    global $THEME, $HTTP_REFERER;
+
+    if (!$link) {
+        $link = $HTTP_REFERER;
+    }
+
+    echo "<BR>";
+    print_simple_box($message, "center", "", "$THEME->cellheading");
+    print_heading("<A HREF=\"$link\">Continue</A>");
+    print_footer();
+    die;
+}
+
+function notice_yesno ($message, $linkyes, $linkno) {
+    global $THEME;
+
+    print_simple_box_start("center", "", "$THEME->cellheading");
+    echo "<P ALIGN=CENTER><FONT SIZE=3>$message</FONT></P>";
+    echo "<P ALIGN=CENTER><FONT SIZE=3><B>";
+    echo "<A HREF=\"$linkyes\">Yes</A>";
+    echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
+    echo "<A HREF=\"$linkno\">No</A>";
+    echo "</B></FONT></P>";
+    print_simple_box_end();
+}
+
+function redirect($url, $message="", $delay=0) {
+// Uses META tags to redirect the user, after printing a notice
+    global $THEME;
+
+    echo "<META HTTP-EQUIV='Refresh' CONTENT='$delay; URL=$url'>";
+
+    if (!empty($message)) {
+        print_header();
+        echo "<CENTER>";
+        echo "<P>$message</P>";
+        echo "<P>( <A HREF=\"$url\">Continue</A> )</P>";
+        echo "</CENTER>";
+    }
+    die; 
+}
+
+function notify ($message) {
+    echo "<P align=center><B><FONT COLOR=#FF0000>$message</FONT></B></P>\n";
+}
+
+
+
+/// PARAMETER HANDLING ////////////////////////////////////////////////////
+
+function require_variable($var) {
+
+    if (! isset($var)) {
+        error("A required parameter was missing");
+    }
+}
+
+function optional_variable(&$var, $default=0) {
+    if (! isset($var)) {
+        $var = $default;
+    }
+}
+
+
+
+
+/// DATABASE HANDLING ////////////////////////////////////////////////
+
+function execute_sql($command) {
+// Completely general
+
+    global $db;
+    
+    $result = $db->Execute("$command");
+
+    if ($result) {
+        echo "<P><FONT COLOR=green>SUCCESS: $command</FONT></P>";
+        return true;
+    } else {
+        echo "<P><FONT COLOR=red>ERROR: $command </FONT></P>";
+        return false;
+    }
+}
+
+function modify_database($sqlfile) {
+// Assumes that the input text file consists of a number 
+// of SQL statements ENDING WITH SEMICOLONS.  The semicolons
+// MUST be the last character in a line.
+// Lines that are blank or that start with "#" are ignored.
+// Only tested with mysql dump files (mysqldump -p -d moodle)
+
+
+    if (file_exists($sqlfile)) {
+        $success = true;
+        $lines = file($sqlfile);
+        $command = "";
+
+        while ( list($i, $line) = each($lines) ) {
+            $line = chop($line);
+            $length = strlen($line);
+
+            if ($length  &&  substr($line, 0, 1) <> "#") { 
+                if (substr($line, $length-1, 1) == ";") {
+                    $line = substr($line, 0, $length-1);   // strip ;
+                    $command .= $line;
+                    if (! execute_sql($command)) {
+                        $success = false;
+                    }
+                    $command = "";
+                } else {
+                    $command .= $line;
+                }
+            }
+        }
+
+    } else {
+        $success = false;
+        echo "<P>Tried to modify database, but \"$sqlfile\" doesn't exist!</P>";
+    }
+
+    return $success;
+}
+
+
+function record_exists($table, $field, $value) {
+    global $db;
+
+    $rs = $db->Execute("SELECT * FROM $table WHERE $field = '$value' LIMIT 1");
+    if (!$rs) return false;
+
+    if ( $rs->RecordCount() ) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+function record_exists_sql($sql) {
+    global $db;
+
+    $rs = $db->Execute($sql);
+    if (!$rs) return false;
+
+    if ( $rs->RecordCount() ) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+
+function count_records($table, $selector, $value) {
+// Get all the records and count them
+    global $db;
+
+    $rs = $db->Execute("SELECT COUNT(*) FROM $table WHERE $selector = '$value'");
+    if (!$rs) return 0;
+
+    return $rs->fields[0];
+}
+
+function count_records_sql($sql) {
+// Get all the records and count them
+    global $db;
+
+    $rs = $db->Execute("$sql");
+    if (!$rs) return 0;
+
+    return $rs->fields[0];
+}
+
+function get_record($table, $selector, $value) {
+// Get a single record as an object
+    global $db;
+
+    $rs = $db->Execute("SELECT * FROM $table WHERE $selector = '$value'");
+    if (!$rs) return false;
+
+    if ( $rs->RecordCount() == 1 ) {
+        return (object)$rs->fields;
+    } else {
+        return false;
+    }
+}
+
+function get_record_sql($sql) {
+// Get a single record as an object
+// The sql statement is provided as a string.
+
+    global $db;
+
+    $rs = $db->Execute("$sql");
+    if (!$rs) return false;
+
+    if ( $rs->RecordCount() == 1 ) {
+        return (object)$rs->fields;
+    } else {
+        return false;
+    }
+}
+
+function get_records($table, $selector, $value, $sort="") {
+// Get a number of records as an array of objects
+// Can optionally be sorted eg "time ASC" or "time DESC"
+// The "key" is the first column returned, eg usually "id"
+    global $db;
+
+    if ($sort) {
+        $sortorder = "ORDER BY $sort";
+    }
+    $sql = "SELECT * FROM $table WHERE $selector = '$value' $sortorder";
+
+    return get_records_sql($sql);
+}
+
+function get_records_sql($sql) {
+// Get a number of records as an array of objects
+// The "key" is the first column returned, eg usually "id"
+// The sql statement is provided as a string.
+
+    global $db;
+
+    $rs = $db->Execute("$sql");
+    if (!$rs) return false;
+
+    if ( $rs->RecordCount() > 0 ) {
+        $records = $rs->GetAssoc(true);
+        foreach ($records as $key => $record) {
+            $objects[$key] = (object) $record;
+        }
+        return $objects;
+    } else {
+        return false;
+    }
+}
+
+function get_records_sql_menu($sql) {
+// Given an SQL select, this function returns an associative 
+// array of the first two columns.  This is most useful in 
+// combination with the choose_from_menu function to create 
+// a form menu.
+
+    global $db;
+
+    $rs = $db->Execute("$sql");
+    if (!$rs) return false;
+
+    if ( $rs->RecordCount() > 0 ) {
+        while (!$rs->EOF) {
+            $menu[$rs->fields[0]] = $rs->fields[1];
+            $rs->MoveNext();
+        }
+        return $menu;
+        
+    } else {
+        return false;
+    }
+}
+
+function get_field($table, $field, $selector, $value) {
+    global $db;
+
+    $rs = $db->Execute("SELECT $field FROM $table WHERE $selector = '$value'");
+    if (!$rs) return false;
+
+    if ( $rs->RecordCount() == 1 ) {
+        return $rs->fields["$field"];
+    } else {
+        return false;
+    }
+}
+
+function set_field($table, $field, $newvalue, $selector, $value) {
+    global $db;
+
+    return $db->Execute("UPDATE $table SET $field = '$newvalue' WHERE $selector = '$value'");
+}
+
+
+function delete_records($table, $selector, $value) {
+// Delete one or more records from a table
+    global $db;
+
+    return $db->Execute("DELETE FROM $table WHERE $selector = '$value'");
+}
+
+function insert_record($table, $dataobject) {
+// Insert a record into a table and return the "id" field
+// $dataobject is an object containing needed data
+
+    global $db;
+
+    // Determine all the fields needed
+    if (! $columns = $db->MetaColumns("$table")) {
+        return false;
+    }
+
+    $data = (array)$dataobject;
+
+    // Pull out data matching these fields
+    foreach ($columns as $column) {
+        if ($column->name <> "id" && $data[$column->name] ) {
+            $ddd[$column->name] = $data[$column->name];
+        }
+    }
+
+    // Construct SQL queries
+    if (! $numddd = count($ddd)) {
+        return 0;
+    }
+
+    $count = 0;
+    $insert = "";
+    $select = "";
+
+    foreach ($ddd as $key => $value) {
+        $count++;
+        $insert .= "$key = '$value'";
+        $select .= "$key = '$value'";
+        if ($count < $numddd) {
+            $insert .= ", ";
+            $select .= " AND ";
+        }
+    }
+
+    if (! $rs = $db->Execute("INSERT INTO $table SET $insert")) {
+        return false;
+    } 
+
+    // Pull it out again to find the id.  This is the most cross-platform method.
+    if ($rs = $db->Execute("SELECT id FROM $table WHERE $select")) {
+        return $rs->fields[0];
+    } else {
+        return false;
+    }
+}
+
+
+function update_record($table, $dataobject) {
+// Update a record in a table
+// $dataobject is an object containing needed data
+
+    global $db;
+
+    if (! $dataobject->id) {
+        return false;
+    }
+
+    // Determine all the fields in the table
+    $columns = $db->MetaColumns($table);
+    $data = (array)$dataobject;
+
+    // Pull out data matching these fields
+    foreach ($columns as $column) {
+        if ($column->name <> "id" && $data[$column->name] ) {
+            $ddd[$column->name] = $data[$column->name];
+        }
+    }
+
+    // Construct SQL queries
+    $numddd = count($ddd);
+    $count = 0;
+    $update = "";
+
+    foreach ($ddd as $key => $value) {
+        $count++;
+        $update .= "$key = '$value'";
+        if ($count < $numddd) {
+            $update .= ", ";
+        }
+    }
+
+    if ($rs = $db->Execute("UPDATE $table SET $update WHERE id = '$dataobject->id'")) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+
+
+/// USER DATABASE ////////////////////////////////////////////////
+
+function get_user_info_from_db($field, $value) {
+
+    global $db;
+
+    if (!$field || !$value) 
+        return false;
+
+    $result = $db->Execute("SELECT * FROM user WHERE $field = '$value'");
+
+    if ( $result->RecordCount() == 1 ) {
+        $user = (object)$result->fields;
+
+        $rs = $db->Execute("SELECT course FROM user_students WHERE user = '$user->id' ");
+        while (!$rs->EOF) {
+            $course = $rs->fields["course"];
+            $user->student["$course"] = true;
+            $rs->MoveNext();
+        }
+
+        $rs = $db->Execute("SELECT course FROM user_teachers WHERE user = '$user->id' ");
+        while (!$rs->EOF) {
+            $course = $rs->fields["course"];
+            $user->teacher["$course"] = true;
+            $rs->MoveNext();
+        }
+
+        $rs = $db->Execute("SELECT * FROM user_admins WHERE user = '$user->id' ");
+        while (!$rs->EOF) {
+            $user->admin = true;
+            $rs->MoveNext();
+        }
+
+        if ($course = get_record("course", "category", 0)) {  
+            // Everyone is always a member of the top course
+            $user->student["$course->id"] = true;
+        }
+
+        return $user;
+
+    } else {
+        return false;
+    }
+}
+
+function update_user_in_db() {
+
+   global $db, $USER, $REMOTE_ADDR;
+
+   if (!isset($USER->id)) 
+       return false;
+
+   $timenow = time();
+   if ($db->Execute("UPDATE LOW_PRIORITY user SET lastIP='$REMOTE_ADDR', lastaccess='$timenow' 
+                                               WHERE id = '$USER->id' ")) {
+       return true;
+   } else {
+       return false;
+   }
+}
+
+function require_login($course=0) {
+// if they aren't already logged in, then send them off to login
+// $course is optional - if left out then it just requires that 
+// that they have an account on the system.
+
+    global $CFG, $SESSION, $USER, $FULLME, $HTTP_REFERER, $PHPSESSID;
+      
+    if (! (isset( $USER->loggedin ) && $USER->confirmed) ) { 
+        $SESSION->wantsurl = $FULLME;
+        $SESSION->fromurl = $HTTP_REFERER;
+        if ($PHPSESSID) { // Cookies not enabled.
+            redirect("$CFG->wwwroot/login/?PHPSESSID=$PHPSESSID");
+        } else {
+            redirect("$CFG->wwwroot/login/");
+        }
+        die;
+    } else if ($course) {
+        if (! ($USER->student[$course] || $USER->teacher[$course] || $USER->admin ) ) {
+            if (!record_exists("course", "id", $course)) {
+                error("That course doesn't exist");
+            }
+
+            $SESSION->wantsurl = $FULLME;
+            redirect("$CFG->wwwroot/course/login.php?id=$course");
+            die;
+        }
+    }
+
+    update_user_in_db();
+}
+
+
+
+function update_login_count() {
+    global $SESSION;
+
+    $max_logins = 10;
+
+    if (empty($SESSION->logincount)) {
+        $SESSION->logincount = 1;
+    } else {
+        $SESSION->logincount++;
+    }
+
+    if ($SESSION->logincount > $max_logins) {
+        unset($SESSION->wantsurl);
+        error("Sorry, you have exceeded the allowed number of login attempts. Restart your browser.");
+    }
+}
+
+
+function isadmin($userid=0) {
+    global $USER;
+
+    if (!$userid) {
+        return $USER->admin;
+    }
+
+    return record_exists_sql("SELECT * FROM user_admins WHERE user='$userid'");
+}
+
+function isteacher($course, $userid=0) {
+    global $USER;
+
+    if (!$userid) {
+        return $USER->teacher[$course];
+    }
+
+    return record_exists_sql("SELECT * FROM user_teachers WHERE user='$userid' AND course='$course'");
+}
+
+
+function isstudent($course, $userid=0) {
+    global $USER;
+
+    if (!$userid) {
+        return $USER->student[$course];
+    }
+
+    $timenow = time();   // todo:  add time check below
+
+    return record_exists_sql("SELECT * FROM user_students WHERE user='$userid' AND course='$course'");
+}
+
+
+function reset_login_count() {
+    global $SESSION;
+
+    $SESSION->logincount = 0;
+}
+
+
+function set_moodle_cookie($thing) {
+
+    $days = 60;
+    $seconds = 60*60*24*$days;
+
+    setCookie ('MOODLEID');
+    setCookie ('MOODLEID', rc4encrypt($thing), time()+$seconds, "/");
+}
+
+
+function get_moodle_cookie() {
+    global $MOODLEID;
+    return rc4decrypt($MOODLEID);
+}
+
+
+
+function verify_login($username, $password) {
+
+    $user = get_user_info_from_db("username", $username);
+
+    if (! $user) {
+        return false;
+    } else if ( $user->password == md5($password) ) {
+        return $user;
+    } else {
+        return false;
+    }
+}
+
+function get_site () {
+// Returns $course object of the top-level site.
+    if ( $course = get_record("course", "category", 0)) {
+        return $course;
+    } else {
+        return false;
+    }
+}
+
+function get_admin () {
+// Returns $user object of the main admin user
+
+    if ( $admins = get_records_sql("SELECT u.* FROM user u, user_admins a WHERE a.user = u.id ORDER BY u.id ASC")) {
+        foreach ($admins as $admin) {
+            return $admin;   // ie the first one (yeah I know it's bodgy)
+        }
+    } else {
+        return false;
+    }
+}
+
+function get_teacher($courseid) {
+// Returns $user object of the main teacher for a course
+    if ( $teachers = get_records_sql("SELECT u.* FROM user u, user_teachers t 
+                                      WHERE t.user = u.id AND t.course = '$courseid' 
+                                      ORDER BY t.authority ASC")) {
+        foreach ($teachers as $teacher) {
+            return $teacher;   // ie the first one (yeah I know it's bodgy)
+        }
+    } else {
+        return false;
+    }
+}
+
+
+
+/// MODULE FUNCTIONS /////////////////////////////////////////////////
+
+function get_coursemodule_from_instance($modulename, $instance, $course) {
+// Given an instance of a module, finds the coursemodule description
+
+    return get_record_sql("SELECT cm.*, m.name
+                           FROM course_modules cm, modules md, $modulename m 
+                           WHERE cm.course = '$course' AND 
+                                 cm.deleted = '0' AND
+                                 cm.instance = m.id AND 
+                                 md.name = '$modulename' AND 
+                                 md.id = cm.module AND
+                                 m.id = '$instance'");
+
+}
+
+function get_all_instances_in_course($modulename, $course, $sort="cw.week") {
+// Returns an array of all the active instances of a particular
+// module in a given course.   Returns false on any errors.
+
+    return get_records_sql("SELECT m.*,cw.week,cm.id as coursemodule 
+                            FROM course_modules cm, course_weeks cw, modules md, $modulename m 
+                            WHERE cm.course = '$course' AND 
+                                  cm.instance = m.id AND 
+                                  cm.deleted = '0' AND
+                                  cm.week = cw.id AND 
+                                  md.name = '$modulename' AND 
+                                  md.id = cm.module
+                            ORDER BY $sort");
+
+}
+
+function print_update_module_icon($moduleid) {
+    global $CFG;
+
+    echo "&nbsp; &nbsp; 
+          <A HREF=\"$CFG->wwwroot/course/mod.php?update=$moduleid\" TARGET=_top><IMG 
+             SRC=\"$CFG->wwwroot/pix/t/edit.gif\" ALIGN=right BORDER=0 ALT=\"Update this module\"></A>";
+}
+
+
+
+
+/// CORRESPONDENCE  ////////////////////////////////////////////////
+
+
+function email_to_user($user, $from, $subject, $message) {
+    global $CFG;
+
+    include_once("$CFG->libdir/class.smtp.php");
+    include_once("$CFG->libdir/class.phpmailer.php");
+
+    $subject = stripslashes($subject);
+    $message = stripslashes($message);
+
+    $mail = new phpmailer;
+
+    $mail->IsSMTP();                                   // set mailer to use SMTP
+    $mail->From = "$from->email";
+    $mail->FromName = "$from->firstname $from->lastname";
+    $mail->Host = "$CFG->smtphost;localhost";          // specify main and backup server
+    $mail->AddReplyTo("$from->email","$from->firstname $from->lastname");
+    $mail->AddAddress("$user->email","$user->firstname $user->lastname"); 
+    $mail->WordWrap = 70;                               // set word wrap
+    $mail->IsHTML(false);                               // set email format to HTML
+    $mail->Subject =  "$subject";
+
+    $mail->Body    =  "\n\n$message";
+
+    if (!$mail->Send()) {
+        return false;
+    }
+
+    return true;
+}
+
+
+function email_to_users(&$users, $from, $subject, $message, $link, $footer="") {
+//  users is an array of user records as returned by get_records_sql
+
+    global $CFG;
+
+    include_once("$CFG->libdir/class.smtp.php");
+    include_once("$CFG->libdir/class.phpmailer.php");
+
+    if (!$users) {
+        return false;
+    }
+    
+    $subject = stripslashes($subject);
+    $message = stripslashes($message);
+
+    $mail = new phpmailer;
+
+    $mail->IsSMTP();                                   // set mailer to use SMTP
+    $mail->From = "$from->email";
+    $mail->FromName = "$from->firstname $from->lastname";
+    $mail->Host = "$CFG->smtphost;localhost";          // specify main and backup server
+    $mail->AddAddress("","Subscribers"); 
+
+    foreach ($users as $user) {
+        $mail->AddBCC("$user->email","$user->firstname $user->lastname"); 
+    }
+
+    $mail->AddReplyTo("$from->email","$from->firstname $from->lastname");
+    $mail->WordWrap = 70;                               // set word wrap
+    $mail->IsHTML(false);                               // set email format to HTML
+    $mail->Subject =  "$subject";
+
+    $message .= "\n\n--\n$from->firstname $from->lastname";
+
+    if ($footer) {
+        $message .= "\n\n$footer\n";
+    }
+
+    if ($link) {
+        $message .= "Link: $link\n";
+    }
+
+    $mail->Body    =  "\n\n$message";
+
+    if (!$mail->Send()) {
+        //echo "Message was not sent <p>";
+        //echo "Mailer Error: " . $mail->ErrorInfo;
+        return false;
+    }
+
+    return true;
+}
+
+
+
+function email_to_course($from, $course, $emailall, $subject, $message, $link, $footer="") {
+    global $CFG;
+
+    include_once("$CFG->libdir/class.smtp.php");
+    include_once("$CFG->libdir/class.phpmailer.php");
+
+
+    if (!$students = get_records_sql("SELECT u.* FROM user u, user_students s
+                                       WHERE s.course = '$course->id' 
+                                       AND s.user = u.id")) {
+        notice("Could not find any students to mail to!");
+    }
+
+    if (!$teachers = get_records_sql("SELECT u.* FROM user u, user_teachers t
+                                       WHERE t.course = '$course->id' 
+                                       AND t.user = u.id")) {
+        notice("Could not find any teachers to mail to!");
+    }
+
+    if (!$teachers && !$students) {
+        return false;
+    }
+    
+    $subject = stripslashes($subject);
+    $message = stripslashes($message);
+
+    $mail = new phpmailer;
+
+    $mail->IsSMTP();                                   // set mailer to use SMTP
+    $mail->From = "$from->email";
+    $mail->FromName = "$from->firstname $from->lastname";
+    $mail->Host = "$CFG->smtphost;localhost";          // specify main and backup server
+
+    foreach ($students as $student) {
+        if ($emailall || $student->forwardmail) {
+            $mail->AddAddress("$student->email","$student->firstname $student->lastname"); 
+        }
+    }
+    foreach ($teachers as $teacher) {
+        if ($emailall || $teacher->forwardmail) {
+            $mail->AddAddress("$teacher->email","$teacher->firstname $teacher->lastname"); 
+        }
+    }
+
+    $mail->AddReplyTo("$from->email","$from->firstname $from->lastname");
+    $mail->WordWrap = 70;                               // set word wrap
+    $mail->IsHTML(false);                               // set email format to HTML
+    $mail->Subject =  "$course->shortname: $subject";
+
+    $message .= "\n\n--\n$from->firstname $from->lastname";
+
+    if ($footer) {
+        $message .= "\n\n$footer";
+    }
+
+    if ($link) {
+        $message .= "\nLink: $link";
+    }
+
+    $mail->Body    =  "\n\n$message";
+
+    if (!$mail->Send()) {
+        //echo "Message was not sent <p>";
+        //echo "Mailer Error: " . $mail->ErrorInfo;
+        return false;
+    }
+
+    return true;
+
+}
+
+/// FILE HANDLING  /////////////////////////////////////////////
+
+function get_directory_list( $rootdir ) {
+// Returns an array with all the filenames in 
+// all subdirectories, relative to the given rootdir.
+
+    $dirs = array();
+   
+    $dir = opendir( $rootdir );
+
+    while( $file = readdir( $dir ) ) {
+        $fullfile = $rootdir."/".$file;
+        if ($file != "." and $file != "..") {
+            if (filetype($fullfile) == "dir") {
+                $subdirs = get_directory_list($fullfile);
+                foreach ($subdirs as $subdir) {
+                    $dirs[] = $file."/".$subdir;
+                }
+            } else {
+                $dirs[] = $file;
+            }
+        }
+    }
+
+    return $dirs;
+}
+
+
+
+/// ENCRYPTION  ////////////////////////////////////////////////
+
+function rc4encrypt($data) {
+    $password = "nfgjeingjk";
+    return endecrypt($password, $data, "");
+}
+
+function rc4decrypt($data) {
+    $password = "nfgjeingjk";
+    return endecrypt($password, $data, "de");
+}
+
+function endecrypt ($pwd, $data, $case) {
+// Based on a class by Mukul Sabharwal [mukulsabharwal@yahoo.com]
+
+    if ($case == 'de') {
+        $data = urldecode($data);
+    }
+
+    $key[] = "";
+    $box[] = "";
+    $temp_swap = "";
+    $pwd_length = 0;
+
+    $pwd_length = strlen($pwd);
+
+    for ($i = 0; $i <= 255; $i++) {
+        $key[$i] = ord(substr($pwd, ($i % $pwd_length), 1));
+        $box[$i] = $i;
+    }
+
+    $x = 0;
+
+    for ($i = 0; $i <= 255; $i++) {
+        $x = ($x + $box[$i] + $key[$i]) % 256;
+        $temp_swap = $box[$i];
+        $box[$i] = $box[$x];
+        $box[$x] = $temp_swap;
+    }
+
+    $temp = "";
+    $k = "";
+
+    $cipherby = "";
+    $cipher = "";
+
+    $a = 0;
+    $j = 0;
+
+    for ($i = 0; $i < strlen($data); $i++) {
+        $a = ($a + 1) % 256;
+        $j = ($j + $box[$a]) % 256;
+        $temp = $box[$a];
+        $box[$a] = $box[$j];
+        $box[$j] = $temp;
+        $k = $box[(($box[$a] + $box[$j]) % 256)];
+        $cipherby = ord(substr($data, $i, 1)) ^ $k;
+        $cipher .= chr($cipherby);
+    }
+
+    if ($case == 'de') {
+        $cipher = urldecode(urlencode($cipher));
+    } else {
+        $cipher = urlencode($cipher);
+    }
+
+    return $cipher;
+}
+
+
+/// MISCELLANEOUS ////////////////////////////////////////////////////////////////////
+
+function getweek ($startdate, $thedate) {
+// Given dates in seconds, how many weeks is the date from startdate
+// The first week is 1, the second 2 etc ... 
+    
+    if ($thedate < $startdate) {   // error
+        return 0;  
+    }
+
+    return floor(($thedate - $startdate) / 604800.0) + 1;
+}
+
+function add_to_log ($message, $course=0) {
+    global $db, $USER, $REMOTE_ADDR;
+
+    $timenow = time();
+    $me = me();
+    $message = addslashes($message);
+
+    $result = $db->Execute("INSERT DELAYED INTO logs 
+                            SET user = '$USER->id', time = '$timenow', course = '$course',
+                                ip = '$REMOTE_ADDR', url = '$me', message = '$message'");
+    if (!$result) {
+        error("Could not insert a new entry to the Moodle log");
+    }    
+}
+
+function generate_password($maxlen=10) {
+/* returns a randomly generated password of length $maxlen.  inspired by
+ * http://www.phpbuilder.com/columns/jesus19990502.php3 */
+
+    global $CFG;
+
+    $fillers = "1234567890!$-+";
+    $wordlist = file($CFG->wordlist);
+
+    srand((double) microtime() * 1000000);
+    $word1 = trim($wordlist[rand(0, count($wordlist) - 1)]);
+    $word2 = trim($wordlist[rand(0, count($wordlist) - 1)]);
+    $filler1 = $fillers[rand(0, strlen($fillers) - 1)];
+
+    return substr($word1 . $filler1 . $word2, 0, $maxlen);
+}
+
+
+function format_time($totalsecs) {
+
+    $days  = floor($totalsecs/86400);
+    $remainder = $totalsecs - ($days*86400);
+    $hours = floor($remainder/3600);
+    $remainder = $remainder - ($hours*3600);
+    $mins  = floor($remainder/60);
+    $secs = $remainder - ($mins*60);
+
+    if ($secs  != 1) $ss = "s";
+    if ($mins  != 1) $ms = "s";
+    if ($hours != 1) $hs = "s";
+    if ($days  != 1) $ds = "s";
+
+    if ($days)  $odays  = "$days day$ds";
+    if ($hours) $ohours = "$hours hr$hs";
+    if ($mins)  $omins  = "$mins min$ms";
+    if ($secs)  $osecs  = "$secs sec$ss";
+
+    if ($days)  return "$odays $ohours";
+    if ($hours) return "$ohours $omins";
+    if ($mins)  return "$omins $osecs";
+    if ($secs)  return "$osecs";
+    return "now";
+}
+
+
+?>
diff --git a/lib/psxlsgen.php b/lib/psxlsgen.php
new file mode 100644 (file)
index 0000000..e977d9c
--- /dev/null
@@ -0,0 +1,204 @@
+<?php // $Id$\r
+/****************************************************************\r
+* Script         : PHP Simple Excel File Generator - Base Class\r
+* Project        : PHP SimpleXlsGen\r
+* Author         : Erol Ozcan <eozcan@superonline.com>\r
+* Version        : 0.3\r
+* Copyright      : GNU LGPL\r
+* URL            : http://psxlsgen.sourceforge.net\r
+* Last modified  : 13 Jun 2001\r
+* Description     : This class is used to generate very simple\r
+*   MS Excel file (xls) via PHP.\r
+*   The generated xls file can be obtained by web as a stream\r
+*   file or can be written under $default_dir path. This package\r
+*   is also included mysql, pgsql, oci8 database interaction to\r
+*   generate xls files.\r
+*   Limitations:\r
+*    - Max character size of a text(label) cell is 255\r
+*    ( due to MS Excel 5.0 Binary File Format definition )\r
+*\r
+* Credits        : This class is based on Christian Novak's small\r
+*    Excel library functions.\r
+******************************************************************/\r
+\r
+if( !defined( "PHP_SIMPLE_XLS_GEN" ) ) {\r
+   define( "PHP_SIMPLE_XLS_GEN", 1 );\r
+\r
+   class  PhpSimpleXlsGen {\r
+      var  $class_ver = "0.3";    // class version\r
+      var  $xls_data   = "";      // where generated xls be stored\r
+      var  $default_dir = "";     // default directory to be saved file\r
+      var  $filename  = "psxlsgen";       // save filename\r
+      var  $fname    = "";        // filename with full path\r
+      var  $crow     = 0;         // current row number\r
+      var  $ccol     = 0;         // current column number\r
+      var  $totalcol = 0;         // total number of columns\r
+      var  $get_type = 0;         // 0=stream, 1=file\r
+      var  $errno    = 0;         // 0=no error\r
+      var  $error    = "";        // error string\r
+      var  $dirsep   = "/";       // directory separator\r
+      var  $header   = 1;         // 0=no header, 1=header line for xls table\r
+\r
+     // Default constructor\r
+     function  PhpSimpleXlsGen()\r
+     {\r
+       $os = getenv( "OS" );\r
+       $temp = getenv( "TEMP");\r
+       // check OS and set proper values for some vars.\r
+       if ( stristr( $os, "Windows" ) ) {\r
+          $this->default_dir = $temp;\r
+          $this->dirsep = "\\";\r
+       } else {\r
+         // assume that is Unix/Linux\r
+         $this->default_dir = "/tmp";\r
+         $this->dirsep =  "/";\r
+       }\r
+       // begin of the excel file header\r
+       $this->xls_data = pack( "ssssss", 0x809, 0x08, 0x00,0x10, 0x0, 0x0 );\r
+       // check header text\r
+       if ( $this->header ) {\r
+         $this->Header();\r
+       }\r
+     }\r
+\r
+     function Header( $text="" ) {\r
+        if ( $text == "" ) {\r
+           $text = "This file was generated using PSXlsGen at ".date("D, d M Y H:i:s T");\r
+        }\r
+        if ( $this->totalcol < 1 ) {\r
+          $this->totalcol = 1;\r
+        }\r
+        $this->InsertText( $text );\r
+        $this->crow += 2;\r
+        $this->ccol = 0;\r
+     }\r
+\r
+     // end of the excel file\r
+     function End()\r
+     {\r
+       $this->xls_data .= pack("sssssssC", 0x7D, 11, 3, 4, 25600,0,0,0);\r
+       $this->xls_data .= pack( "ss", 0x0A, 0x00 );\r
+       return;\r
+     }\r
+\r
+     // write a Number (double) into row, col\r
+     function WriteNumber_pos( $row, $col, $value )\r
+     {\r
+       $this->xls_data .= pack( "sssss", 0x0203, 14, $row, $col, 0x00 );\r
+       $this->xls_data .= pack( "d", $value );\r
+       return;\r
+     }\r
+\r
+     // write a label (text) into Row, Col\r
+     function WriteText_pos( $row, $col, $value )\r
+     {\r
+        $len = strlen( $value );\r
+        $this->xls_data .= pack( "s*", 0x0204, 8 + $len, $row, $col, 0x00, $len );\r
+        $this->xls_data .= $value;\r
+        return;\r
+     }\r
+\r
+     // insert a number, increment row,col automatically\r
+     function InsertNumber( $value )\r
+     {\r
+        if ( $this->ccol == $this->totalcol ) {\r
+           $this->ccol = 0;\r
+           $this->crow++;\r
+        }\r
+        $this->WriteNumber_pos( $this->crow, $this->ccol, &$value );\r
+        $this->ccol++;\r
+        return;\r
+     }\r
+\r
+     // insert text, increment row,col automatically\r
+     function InsertText( $value )\r
+     {\r
+        if ( $this->ccol == $this->totalcol ) {\r
+           $this->ccol = 0;\r
+           $this->crow++;\r
+        }\r
+        $this->WriteText_pos( $this->crow, $this->ccol, &$value );\r
+        $this->ccol++;\r
+        return;\r
+     }\r
+\r
+     // Change position of row,col\r
+     function ChangePos( $newrow, $newcol )\r
+     {\r
+        $this->crow = $newrow;\r
+        $this->ccol = $newcol;\r
+        return;\r
+     }\r
+\r
+     // new line\r
+     function NewLine()\r
+     {\r
+        $this->ccol = 0;\r
+        $this->crow++;\r
+        return;\r
+     }\r
+\r
+     // send generated xls as stream file\r
+     function SendFile( $filename )\r
+     {\r
+        $this->filename = $filename;\r
+        $this->SendFile();\r
+     }\r
+     // send generated xls as stream file\r
+     function SendFile()\r
+     {\r
+        global $HTTP_USER_AGENT;\r
+\r
+        $this->End();\r
+        header ( "Expires: Mon, 1 Apr 1974 05:00:00 GMT" );\r
+        header ( "Last-Modified: " . gmdate("D,d M YH:i:s") . " GMT" );\r
+        header ( "Pragma: no-cache" );\r
+        if (!strstr($HTTP_USER_AGENT,"MSIE")) {\r
+            $attachment=" attachment;";\r
+        }\r
+        header("Content-Type: application/x-msexcel\r\n");\r
+        header("Content-Disposition:$attachment filename=$this->filename.xls\r\n\r\n");\r
+        header("Content-Transfer-Encoding: binary\r\n"); \r
+        header("Content-Description: Excel Spreadsheet" );\r
+        print $this->xls_data;\r
+     }\r
+\r
+     // change the default saving directory\r
+     function ChangeDefaultDir( $newdir )\r
+     {\r
+       $this->default_dir = $newdir;\r
+       return;\r
+     }\r
+\r
+     // Save generated xls file\r
+     function SaveFile( $filename )\r
+     {\r
+        $this->filename = $filename;\r
+        $this->SaveFile();\r
+     }\r
+\r
+     // Save generated xls file\r
+     function SaveFile()\r
+     {\r
+        $this->End();\r
+        $this->fname = $this->default_dir."$this->dirsep".$this->filename;\r
+        if ( !stristr( $this->fname, ".xls" ) ) {\r
+          $this->fname .= ".xls";\r
+        }\r
+        $fp = fopen( $this->fname, "wb" );\r
+        fwrite( $fp, $this->xls_data );\r
+        fclose( $fp );\r
+        return;\r
+     }\r
+\r
+     // Get generated xls as specified type\r
+     function GetXls( $type = 0 ) {\r
+         if ( !$type && !$this->get_type ) {\r
+            $this->SendFile();\r
+         } else {\r
+            $this->SaveFile();\r
+         }\r
+     }\r
+   } // end of the class PHP_SIMPLE_XLS_GEN\r
+}\r
+// end of ifdef PHP_SIMPLE_XLS_GEN\r
diff --git a/lib/setup.php b/lib/setup.php
new file mode 100644 (file)
index 0000000..4989655
--- /dev/null
@@ -0,0 +1,66 @@
+<?PHP // $Id$
+//
+// setup.php
+// 
+// Sets up sessions, connects to databases and so on
+//
+// Normally this is only called by the main config.php file 
+// 
+// Normally this file does not need to be edited.
+//
+// XXX this might need some rationalisation
+//
+//////////////////////////////////////////////////////////////
+
+// Error reporting and bug hunting
+
+    error_reporting(7);   // use 0=none 7=normal 15=all 
+
+// Default editing time for discussions and the like (in seconds)
+
+    $CFG->maxeditingtime = 1800;
+
+// Location of standard files
+
+    $CFG->templatedir = "$CFG->dirroot/templates";
+    $CFG->imagedir    = "$CFG->wwwroot/images";
+    $CFG->wordlist    = "$CFG->libdir/wordlist.txt";
+    $CFG->javascript  = "$CFG->libdir/javascript.php";
+    $CFG->stylesheet  = "$CFG->wwwroot/theme/$CFG->theme/styles.css";
+    $CFG->header      = "$CFG->dirroot/theme/$CFG->theme/header.html";
+    $CFG->footer      = "$CFG->dirroot/theme/$CFG->theme/footer.html";
+
+// Load up theme variables (colours etc)
+
+    require("$CFG->dirroot/theme/$CFG->theme/config.php");
+
+
+// Load up standard libraries 
+
+    require("$CFG->libdir/weblib.php");          // Standard web page functions
+    require("$CFG->libdir/adodb/adodb.inc.php"); // Database access functions
+    require("$CFG->libdir/adodb/tohtml.inc.php");// Database display functions
+    require("$CFG->libdir/moodlelib.php");       // Various Moodle functions
+    
+// Load up global environment variables
+
+    class object {};
+    
+    session_start();
+    session_register("SESSION");    // Current session info 
+    session_register("USER");       // Current user info
+    if (! isset($SESSION)) $SESSION = new object;
+    if (! isset($USER))    $USER = new object;
+
+    $FULLME = qualified_me();
+    $ME     = strip_querystring($FULLME);
+
+// Connect to the database using adodb
+
+    ADOLoadCode($CFG->dbtype);          
+    $db = &ADONewConnection();         
+    $db->PConnect($CFG->dbhost,$CFG->dbuser,$CFG->dbpass,$CFG->dbname); 
+
+
+
+?>
diff --git a/lib/weblib.php b/lib/weblib.php
new file mode 100644 (file)
index 0000000..10e1d7c
--- /dev/null
@@ -0,0 +1,291 @@
+<?PHP // $Id$
+
+// weblib.php
+//
+// Library of useful PHP functions related to web pages.
+//
+//
+
+function nvl(&$var, $default="") {
+// if $var is undefined, return $default, otherwise return $var 
+
+       return isset($var) ? $var : $default;
+}
+
+function ov(&$var) {
+// returns $var with the HTML characters (like "<", ">", etc.) properly quoted,
+// or if $var is undefined, will return an empty string.  note this function
+// must be called with a variable, for normal strings or functions use o() 
+
+       return isset($var) ? htmlSpecialChars(stripslashes($var)) : "";
+}
+
+function pv(&$var) {
+// prints $var with the HTML characters (like "<", ">", etc.) properly quoted,
+// or if $var is undefined, will print an empty string.  note this function
+// must be called with a variable, for normal strings or functions use p()
+
+       echo isset($var) ? htmlSpecialChars(stripslashes($var)) : "";
+}
+
+function o($var) {
+// returns $var with HTML characters (like "<", ">", etc.) properly quoted,
+// or if $var is empty, will return an empty string. 
+
+       return empty($var) ? "" : htmlSpecialChars(stripslashes($var));
+}
+
+function p($var) {
+// prints $var with HTML characters (like "<", ">", etc.) properly quoted,
+// or if $var is empty, will print an empty string. 
+
+       echo empty($var) ? "" : htmlSpecialChars(stripslashes($var));
+}
+
+
+function strip_querystring($url) {
+// takes a URL and returns it without the querystring portion 
+
+       if ($commapos = strpos($url, '?')) {
+               return substr($url, 0, $commapos);
+       } else {
+               return $url;
+       }
+}
+
+function get_referer() {
+// returns the URL of the HTTP_REFERER, less the querystring portion 
+
+       $HTTP_REFERER = getenv("HTTP_REFERER");
+       return strip_querystring(nvl($HTTP_REFERER));
+}
+
+
+function me() {
+// returns the name of the current script, WITH the querystring portion.
+// this function is necessary because PHP_SELF and REQUEST_URI and PATH_INFO
+// return different things depending on a lot of things like your OS, Web
+// server, and the way PHP is compiled (ie. as a CGI, module, ISAPI, etc.) 
+
+       if (getenv("REQUEST_URI")) {
+               $me = getenv("REQUEST_URI");
+
+       } elseif (getenv("PATH_INFO")) {
+               $me = getenv("PATH_INFO");
+
+       } elseif ($GLOBALS["PHP_SELF"]) {
+               $me = $GLOBALS["PHP_SELF"];
+       }
+
+       return $me;
+}
+
+
+
+function qualified_me() {
+// like me() but returns a full URL 
+
+       $HTTPS = getenv("HTTPS");
+       $SERVER_PROTOCOL = getenv("SERVER_PROTOCOL");
+       $HTTP_HOST = getenv("HTTP_HOST");
+
+       $protocol = (isset($HTTPS) && $HTTPS == "on") ? "https://" : "http://";
+       $url_prefix = "$protocol$HTTP_HOST";
+       return $url_prefix . me();
+}
+
+
+function match_referer($good_referer = "") {
+// returns true if the referer is the same as the good_referer.  If
+// good_refer is not specified, use qualified_me as the good_referer 
+
+       if ($good_referer == "") { $good_referer = qualified_me(); }
+       return $good_referer == get_referer();
+}
+
+
+function read_template($filename, &$var) {
+// return a (big) string containing the contents of a template file with all
+// the variables interpolated.  all the variables must be in the $var[] array or
+// object (whatever you decide to use).
+//
+// WARNING: do not use this on big files!! 
+
+       $temp = str_replace("\\", "\\\\", implode(file($filename), ""));
+       $temp = str_replace('"', '\"', $temp);
+       eval("\$template = \"$temp\";");
+       return $template;
+}
+
+function checked(&$var, $set_value = 1, $unset_value = 0) {
+// if variable is set, set it to the set_value otherwise set it to the
+// unset_value.  used to handle checkboxes when you are expecting them from
+// a form 
+
+       if (empty($var)) {
+               $var = $unset_value;
+       } else {
+               $var = $set_value;
+       }
+}
+
+function frmchecked(&$var, $true_value = "checked", $false_value = "") {
+// prints the word "checked" if a variable is true, otherwise prints nothing,
+// used for printing the word "checked" in a checkbox form input 
+
+       if ($var) {
+               echo $true_value;
+       } else {
+               echo $false_value;
+       }
+}
+
+
+function link_to_popup_window ($url, $name="popup", $linkname="click here", $height=400, $width=500) {
+// This will create a HTML link that will work on both 
+// Javascript and non-javascript browsers.
+// Relies on the Javascript function openpopup in javascript.php
+// $url must be relative to home page  eg /mod/survey/stuff.php
+
+       echo "\n<SCRIPT language=\"Javascript\">";
+    echo "\n<!--";
+       echo "\ndocument.write('<A HREF=javascript:openpopup(\"$url\",\"$name\",\"$height\",\"$width\") >$linkname</A>');";
+    echo "\n//-->";
+       echo "\n</SCRIPT>";
+       echo "\n<NOSCRIPT>\n<A TARGET=\"$name\" HREF=\"$url\">$linkname</A>\n</NOSCRIPT>\n";
+
+}
+
+function close_window_button() {
+    echo "<FORM><CENTER>";
+    echo "<INPUT TYPE=button onClick=\"self.close();\" VALUE=\"Close this window\">";
+    echo "</CENTER></FORM>";
+}
+
+
+function choose_from_menu ($options, $name, $selected="", $nothing="Choose...", $script="") {
+// $options["value"]["label"]
+    
+    if ($script) {
+        $javascript = "onChange=\"$script\"";
+    }
+    echo "<SELECT NAME=$name $javascript>\n";
+    echo "   <OPTION VALUE=0>$nothing</OPTION>\n";
+    foreach ($options as $value => $label) {
+        echo "   <OPTION VALUE=\"$value\"";
+        if ($value == $selected) {
+            echo " SELECTED";
+        }
+        if ($label) {
+            echo ">$label</OPTION>\n";
+        } else {
+            echo ">$value</OPTION>\n";
+        }
+    }
+    echo "</SELECT>\n";
+}   
+
+function popup_form ($common, $options, $formname, $selected="", $nothing="Choose...") {
+//  Implements a complete little popup form
+//  $common   = the URL up to the point of the variable that changes
+//  $options  = A list of value-label pairs for the popup list
+//  $formname = name must be unique on the page
+//  $selected = the option that is already selected
+//  $nothing  = The label for the "no choice" option
+
+    echo "<FORM NAME=$formname>";
+    echo "<SELECT NAME=popup onChange=\"window.location=document.$formname.popup.options[document.$formname.popup.selectedIndex].value\">\n";
+
+    if ($nothing != "") {
+        echo "   <OPTION VALUE=\"javascript:void(0)\">$nothing</OPTION>\n";
+    }
+
+    foreach ($options as $value => $label) {
+        echo "   <OPTION VALUE=\"$common$value\"";
+        if ($value == $selected) {
+            echo " SELECTED";
+        }
+        if ($label) {
+            echo ">$label</OPTION>\n";
+        } else {
+            echo ">$value</OPTION>\n";
+        }
+    }
+    echo "</SELECT></FORM>\n";
+}
+
+
+
+function formerr($error) {
+    if (!empty($error)) {
+        echo "<font color=#ff0000>$error</font>";
+    }
+}
+
+
+function validate_email ($address) {
+// Validates an email to make it makes sense.
+    return (ereg('^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+'.
+                  '@'.
+                  '[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.
+                  '[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$',
+                  $address));
+}
+
+
+function get_slash_arguments($i=0) {
+// Extracts arguments from "/foo/bar/something"
+// eg http://mysite.com/script.php/foo/bar/something
+// Might only work on Apache
+
+    global $PATH_INFO;
+
+    if (!isset($PATH_INFO)) {
+        return false;
+    }
+
+    $args = explode("/", $PATH_INFO);
+
+    if ($i) {     // return just the required argument
+        return $args[$i];
+
+    } else {      // return the whole array
+        array_shift($args);  // get rid of the empty first one
+        return $args;
+    }
+}
+
+
+function text_to_html($text) {
+    global $CFG;
+
+// Given plain text, makes it into HTML as nicely as possible.
+
+    // Make URLs into links.   eg http://moodle.com/
+    $text = eregi_replace("([[:alnum:]]+)://([^[:space:]]*)([[:alnum:]#?/&=])", 
+                          "<A HREF=\"\\1://\\2\\3\" TARGET=\"newpage\">\\1://\\2\\3</A>", $text);
+
+    // eg www.moodle.com
+    $text = eregi_replace("([[:space:]])www.([^[:space:]]*)([[:alnum:]#?/&=])", 
+                          "\\1<A HREF=\"http://www.\\2\\3\" TARGET=\"newpage\">www.\\2\\3</A>", $text);
+
+    // Make returns into HTML newlines.
+    $text = nl2br($text);
+
+    // Turn smileys into images.
+
+    $text = ereg_replace(":-)", "<IMG ALT=smile SRC=$CFG->wwwroot/pix/s/smiley.gif>", $text);
+    $text = ereg_replace(":-D", "<IMG ALT=grin SRC=$CFG->wwwroot/pix/s/biggrin.gif>", $text);
+    $text = ereg_replace(";-)", "<IMG ALT=wink SRC=$CFG->wwwroot/pix/s/wink.gif>", $text);
+    $text = ereg_replace("8-)", "<IMG ALT=wide-eyed SRC=$CFG->wwwroot/pix/s/wideeyes.gif>", $text);
+    $text = ereg_replace(":-\(", "<IMG ALT=sad SRC=$CFG->wwwroot/pix/s/sad.gif>", $text);
+    $text = ereg_replace(":-P", "<IMG ALT=tongue-out SRC=$CFG->wwwroot/pix/s/tongueout.gif>", $text);
+    $text = ereg_replace(":-/", "<IMG ALT=mixed SRC=$CFG->wwwroot/pix/s/mixed.gif>", $text);
+    $text = ereg_replace(":-o", "<IMG ALT=surprised SRC=$CFG->wwwroot/pix/s/surprise.gif>", $text);
+    $text = ereg_replace("B-)", "<IMG ALT=cool SRC=$CFG->wwwroot/pix/s/cool.gif>", $text);
+
+    return "<P>".$text."</P>";
+}
+
+
+?>
diff --git a/lib/wordlist.txt b/lib/wordlist.txt
new file mode 100644 (file)
index 0000000..8ccb521
--- /dev/null
@@ -0,0 +1,17 @@
+baby
+bull
+camel
+car
+cat
+elephant
+fence
+flower
+frog
+gate
+grass
+music
+peg
+pillow
+rabbit
+rock
+tree
diff --git a/login/change_password.php b/login/change_password.php
new file mode 100644 (file)
index 0000000..162d785
--- /dev/null
@@ -0,0 +1,86 @@
+<?PHP // $Id$
+
+       include("../config.php");
+
+
+       if (match_referer() && isset($HTTP_POST_VARS)) {
+
+               $frm = (object) $HTTP_POST_VARS;
+
+               validate_form($frm, $err);
+
+               update_login_count();
+
+               if (!count((array)$err)) {
+                       $username = $frm->username;
+                       $password = $frm->newpassword1;
+                       
+                       if (! set_field("user", "password", md5($frm->newpassword1), "username", $frm->username)) {
+                               error("Could not set the new password");
+            }
+
+                       unset($USER);
+
+                       $USER = get_user_info_from_db("username", $username);
+                       $USER->loggedin = true;
+
+                       set_moodle_cookie($USER->username);
+
+            add_to_log("Changed password");
+                       reset_login_count();
+
+                       print_header("Changed password", "Password changed successfully", "Changed Password", "");
+                       notice("Password changed successfully", "$CFG->wwwroot/course/");
+                       print_footer();
+                       exit;
+               }
+       }
+
+
+
+       if (!$frm->username)
+       $frm->username = get_moodle_cookie();
+
+       if ($frm->username) {
+       $focus = "form.password";
+       } else {
+       $focus = "form.username";
+       }
+
+
+       print_header("Change password", "Change Password", "Change Password", "$focus");
+    print_simple_box_start("center", "", $THEME->cellheading);
+       include("change_password_form.html");
+    print_simple_box_end();
+       print_footer();
+
+
+
+
+/******************************************************************************
+ * FUNCTIONS
+ *****************************************************************************/
+function validate_form($frm, &$err) {
+
+    if (empty($frm->username))
+        $err->username = "Missing username";
+
+    else if (empty($frm->password))
+        $err->password = "Missing password";
+
+    else if (!verify_login($frm->username, $frm->password))
+               $err->password = "Incorrect password for this username";
+
+    if (empty($frm->newpassword1))
+        $err->newpassword1 = "Missing new password";
+
+    if (empty($frm->newpassword2))
+        $err->newpassword2 = "Missing new password";
+
+    else if ($frm->newpassword1 <> $frm->newpassword2)
+        $err->newpassword2 = "Passwords not the same";
+
+    return;
+}
+
+?>
diff --git a/login/change_password_form.html b/login/change_password_form.html
new file mode 100644 (file)
index 0000000..e66953c
--- /dev/null
@@ -0,0 +1,33 @@
+<P><B>All fields are required</B></P>
+
+<form name="form" method="post" action="change_password.php">
+<table cellpadding=10>
+<tr valign=top>
+       <td><P>Username:</P></td>
+       <td><input type="text" name="username" size=25 value="<? pv($frm->username) ?>">
+       <? formerr($err->username) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Password:</P></td>
+       <td><input type="text" name="password" size=25 value="<? pv($frm->password) ?>">
+       <? formerr($err->password) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>New Password:</P></td>
+       <td><input type="text" name="newpassword1" size=25 value="<? pv($frm->newpassword1) ?>">
+       <? formerr($err->newpassword1) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>New Password (again):</P></td>
+       <td><input type="text" name="newpassword2" size=25 value="<? pv($frm->newpassword2) ?>">
+       <? formerr($err->newpassword2) ?>
+       </td>
+</tr>
+<tr>
+       <td></td>
+       <td><input type="submit" value="Change Password"></td>
+</table>
+</form>
diff --git a/login/confirm.php b/login/confirm.php
new file mode 100644 (file)
index 0000000..27a9ca4
--- /dev/null
@@ -0,0 +1,54 @@
+<?PHP // $Id$
+
+       require("../config.php");
+
+       if ( isset($x) && isset($s) ) {     #  x = user.id   s = user.username
+
+               $user = get_user_info_from_db("id", "$x");
+
+               if ($user) {
+                       if ($user->username == $s) {
+
+                if ($user->confirmed) {
+                                   print_header("Registration already confirmed", "Already confirmed", "Confirmed", "");
+                                   echo "<CENTER><H3>Thanks, ". $USER->firstname ." ". $USER->lastname . "</H3>\n";
+                           echo "<H4>Your registration has already been confirmed.</H4>\n";
+                           echo "<H3><A HREF=\"$CFG->wwwroot/course/\">Proceed to the courses</A></H3>\n";
+                                   print_footer();
+                    exit;
+                }
+
+                               $USER = $user;
+
+                               $timenow = time();
+
+                               $rs = $db->Execute("UPDATE user SET confirmed=1, lastIP='$REMOTE_ADDR', 
+                                                                                                       firstaccess='$timenow', lastaccess='$timenow'
+                                                                       WHERE id = '$USER->id' ");
+                               if (!$rs) error("Could not update this user while confirming");
+
+                               set_moodle_cookie($USER->username);
+
+                               $USER->loggedin = true;
+                               $USER->confirmed = 1;
+
+                               if ( ! empty($SESSION["wantsurl"]) ) {
+                                       $goto = $SESSION["wantsurl"];
+                                       redirect("$goto");
+                       }
+                               print_header("Registration confirmed", "Confirmed", "Confirmed", "");
+                               echo "<CENTER><H3>Thanks, ". $USER->firstname ." ". $USER->lastname . "</H3>\n";
+                       echo "<H4>Your registration is now confirmed.</H4>\n";
+                       echo "<H3><A HREF=\"$CFG->wwwroot/course/\">Show me the courses</A></H3>\n";
+                               print_footer();
+                       } else {
+                               error("Invalid confirmation data");
+                       }
+               }
+
+       } else {
+       redirect("$CFG->wwwroot");
+       }
+
+?>
diff --git a/login/countries.php b/login/countries.php
new file mode 100644 (file)
index 0000000..42d86d8
--- /dev/null
@@ -0,0 +1,256 @@
+<?PHP // $Id$
+
+function print_country_menu($selected = "") {
+
+$countries = array (
+"" => "Select...",
+"AF" => "Afghanistan",
+"AL" => "Albania",
+"DZ" => "Algeria",
+"AS" => "American Samoa",
+"AD" => "Andorra",
+"AO" => "Angola",
+"AI" => "Anguilla",
+"AQ" => "Antarctica",
+"AG" => "Antigua and Barbuda",
+"AR" => "Argentina",
+"AM" => "Armenia",
+"AW" => "Aruba",
+"AU" => "Australia",
+"AT" => "Austria",
+"AZ" => "Azerbaijan",
+"BS" => "Bahamas",
+"BH" => "Bahrain",
+"BD" => "Bangladesh",
+"BB" => "Barbados",
+"BY" => "Belarus",
+"BE" => "Belgium",
+"BZ" => "Belize",
+"BJ" => "Benin",
+"BM" => "Bermuda",
+"BT" => "Bhutan",
+"BO" => "Bolivia",
+"BA" => "Bosnia and Herzegowina",
+"BW" => "Botswana",
+"BV" => "Bouvet Island",
+"BR" => "Brazil",
+"IO" => "British Indian Ocean Territory",
+"BN" => "Brunei Darussalam",
+"BG" => "Bulgaria",
+"BF" => "Burkina Faso",
+"BI" => "Burundi",
+"KH" => "Cambodia",
+"CM" => "Cameroon",
+"CA" => "Canada",
+"CV" => "Cape Verde",
+"KY" => "Cayman Islands",
+"CF" => "Central African Republic",
+"TD" => "Chad",
+"CL" => "Chile",
+"CN" => "China",
+"CX" => "Christmas Island",
+"CC" => "Cocos (Keeling) Islands",
+"CO" => "Colombia",
+"KM" => "Comoros",
+"CG" => "Congo",
+"CK" => "Cook Islands",
+"CR" => "Costa Rica",
+"CI" => "Cote D'Ivoire",
+"HR" => "Croatia (Hrvatska)",
+"CU" => "Cuba",
+"CY" => "Cyprus",
+"CZ" => "Czech Republic",
+"DK" => "Denmark",
+"DJ" => "Djibouti",
+"DM" => "Dominica",
+"DO" => "Dominican Republic",
+"TP" => "East Timor",
+"EC" => "Ecuador",
+"EG" => "Egypt",
+"SV" => "El Salvador",
+"GQ" => "Equatorial Guinea",
+"ER" => "Eritrea",
+"EE" => "Estonia",
+"ET" => "Ethiopia",
+"FK" => "Falkland Islands (Malvinas)",
+"FO" => "Faroe Islands",
+"FJ" => "Fiji",
+"FI" => "Finland",
+"FR" => "France",
+"FX" => "France, Metropolitan",
+"GF" => "French Guiana",
+"PF" => "French Polynesia",
+"TF" => "French Southern Territories",
+"GA" => "Gabon",
+"GM" => "Gambia",
+"GE" => "Georgia",
+"DE" => "Germany",
+"GH" => "Ghana",
+"GI" => "Gibraltar",
+"GR" => "Greece",
+"GL" => "Greenland",
+"GD" => "Grenada",
+"GP" => "Guadeloupe",
+"GU" => "Guam",
+"GT" => "Guatemala",
+"GN" => "Guinea",
+"GW" => "Guinea-Bissau",
+"GY" => "Guyana",
+"HT" => "Haiti",
+"HM" => "Heard and Mc Donald Islands",
+"HN" => "Honduras",
+"HK" => "Hong Kong",
+"HU" => "Hungary",
+"IS" => "Iceland",
+"IN" => "India",
+"ID" => "Indonesia",
+"IR" => "Iran (Islamic Republic of)",
+"IQ" => "Iraq",
+"IE" => "Ireland",
+"IL" => "Israel",
+"IT" => "Italy",
+"JM" => "Jamaica",
+"JP" => "Japan",
+"JO" => "Jordan",
+"KZ" => "Kazakhstan",
+"KE" => "Kenya",
+"KI" => "Kiribati",
+"KP" => "Korea, Democratic People's Republic of",
+"KR" => "Korea, Republic of",
+"KW" => "Kuwait",
+"KG" => "Kyrgyzstan",
+"LA" => "Lao People's Democratic Republic",
+"LV" => "Latvia",
+"LB" => "Lebanon",
+"LS" => "Lesotho",
+"LR" => "Liberia",
+"LY" => "Libyan Arab Jamahiriya",
+"LI" => "Liechtenstein",
+"LT" => "Lithuania",
+"LU" => "Luxembourg",
+"MO" => "Macau",
+"MK" => "Macedonia",
+"MG" => "Madagascar",
+"MW" => "Malawi",
+"MY" => "Malaysia",
+"MV" => "Maldives",
+"ML" => "Mali",
+"MT" => "Malta",
+"MH" => "Marshall Islands",
+"MQ" => "Martinique",
+"MR" => "Mauritania",
+"MU" => "Mauritius",
+"YT" => "Mayotte",
+"MX" => "Mexico",
+"FM" => "Micronesia, Federated States of",
+"MD" => "Moldova, Republic of",
+"MC" => "Monaco",
+"MN" => "Mongolia",
+"MS" => "Montserrat",
+"MA" => "Morocco",
+"MZ" => "Mozambique",
+"MM" => "Myanmar",
+"NA" => "Namibia",
+"NR" => "Nauru",
+"NP" => "Nepal",
+"NL" => "Netherlands",
+"AN" => "Netherlands Antilles",
+"NC" => "New Caledonia",
+"NZ" => "New Zealand",
+"NI" => "Nicaragua",
+"NE" => "Niger",
+"NG" => "Nigeria",
+"NU" => "Niue",
+"NF" => "Norfolk Island",
+"MP" => "Northern Mariana Islands",
+"NO" => "Norway",
+"OM" => "Oman",
+"PK" => "Pakistan",
+"PW" => "Palau",
+"PA" => "Panama",
+"PG" => "Papua New Guinea",
+"PY" => "Paraguay",
+"PE" => "Peru",
+"PH" => "Philippines",
+"PN" => "Pitcairn",
+"PL" => "Poland",
+"PT" => "Portugal",
+"PR" => "Puerto Rico",
+"QA" => "Qatar",
+"RE" => "Reunion",
+"RO" => "Romania",
+"RU" => "Russian Federation",
+"RW" => "Rwanda",
+"KN" => "Saint Kitts and Nevis",
+"LC" => "Saint Lucia",
+"VC" => "Saint Vincent and the Grenadines",
+"WS" => "Samoa",
+"SM" => "San Marino",
+"ST" => "Sao Tome and Principe",
+"SA" => "Saudi Arabia",
+"SN" => "Senegal",
+"SC" => "Seychelles",
+"SL" => "Sierra Leone",
+"SG" => "Singapore",
+"SK" => "Slovakia (Slovak Republic)",
+"SI" => "Slovenia",
+"SB" => "Solomon Islands",
+"SO" => "Somalia",
+"ZA" => "South Africa",
+"ES" => "Spain",
+"LK" => "Sri Lanka",
+"SH" => "St. Helena",
+"PM" => "St. Pierre and Miquelon",
+"SD" => "Sudan",
+"SR" => "Suriname",
+"SJ" => "Svalbard and Jan Mayen Islands",
+"SZ" => "Swaziland",
+"SE" => "Sweden",
+"CH" => "Switzerland",
+"SY" => "Syrian Arab Republic",
+"TW" => "Taiwan",
+"TJ" => "Tajikistan",
+"TZ" => "Tanzania, United Republic of",
+"TH" => "Thailand",
+"TG" => "Togo",
+"TK" => "Tokelau",
+"TO" => "Tonga",
+"TT" => "Trinidad and Tobago",
+"TN" => "Tunisia",
+"TR" => "Turkey",
+"TM" => "Turkmenistan",
+"TC" => "Turks and Caicos Islands",
+"TV" => "Tuvalu",
+"UG" => "Uganda",
+"UA" => "Ukraine",
+"AE" => "United Arab Emirates",
+"GB" => "United Kingdom",
+"US" => "United States of America",
+"UY" => "Uruguay",
+"UZ" => "Uzbekistan",
+"VU" => "Vanuatu",
+"VA" => "Vatican City State (Holy See)",
+"VE" => "Venezuela",
+"VN" => "Vietnam",
+"VG" => "Virgin Islands (British)",
+"VI" => "Virgin Islands (U.S.)",
+"WF" => "Wallis And Futuna Islands",
+"EH" => "Western Sahara",
+"YE" => "Yemen",
+"YU" => "Yugoslavia",
+"ZR" => "Zaire",
+"ZM" => "Zambia",
+"ZW" => "Zimbabwe");
+
+echo "<SELECT NAME=country>\n";
+while (list($code, $country) = each ($countries) ) {
+       echo "<OPTION VALUE=\"$code\"";
+       if ($code == $selected) {
+               echo " SELECTED";
+       }
+       echo ">$country\n";
+}
+echo "</SELECT>\n";
+
+
+}
diff --git a/login/forgot_password.php b/login/forgot_password.php
new file mode 100644 (file)
index 0000000..7d7b343
--- /dev/null
@@ -0,0 +1,102 @@
+<?PHP // $Id$
+
+       include("../config.php");
+
+       if (match_referer() && isset($HTTP_POST_VARS)) {
+
+               $frm = (object)$HTTP_POST_VARS;
+
+               validate_form($frm, $err);
+
+               update_login_count();
+
+               if (count((array)$err) == 0) {
+
+                       if (!$user = get_user_info_from_db("email", $frm->email)) {
+                error("No such user with this address:  $frm->email");
+            }
+
+                       if (! reset_password_and_mail($user)) {
+                error("Could not reset password and mail the new one to you");
+            }
+
+                       reset_login_count();
+               print_header("Password has been sent", "Password has been sent", "Password Sent", "");
+               include("forgot_password_change.html");
+                       exit;
+               }
+       }
+
+       if ( empty($frm->email) ) {
+               if ( $username = get_moodle_cookie() ) {
+                       $frm->email = get_field("user", "email", "username", "$username");
+               }
+       }
+
+       print_header("Forgot password?", "Have a new password sent to you", "", "form.email");
+
+       include("forgot_password_form.html");
+
+
+/******************************************************************************
+ * FUNCTIONS
+ *****************************************************************************/
+
+function validate_form($frm, &$err) {
+
+    if (empty($frm->email))
+        $err->email = "Missing email address";
+
+    else if (! validate_email($frm->email))
+        $err->email = "Invalid email address";
+
+    else if (! record_exists("user", "email", $frm->email))
+        $err->email = "No such email address on file";
+
+}
+
+
+function reset_password_and_mail($user) {
+
+    global $CFG;
+
+    $site  = get_site();
+    $from = get_admin();
+
+    $newpassword = generate_password();
+
+    if (! set_field("user", "password", md5($newpassword), "id", $user->id) ) {
+        error("Could not set user password!");
+    }
+
+    $message  = "Hi $user->firstname,\n\n";
+
+    $message .= "Your account password at '$site->fullname' has been reset\n";
+    $message .= "and you have been issued with a new temporary password.\n\n";
+
+    $message .= "Your current login information is now:\n\n";
+
+    $message .= "   username: $user->username\n";
+    $message .= "   password: $newpassword\n\n";
+
+    $message .= "Please go to this page to change your password:\n\n";
+
+    $message .= "$CFG->wwwroot/login/change_password.php\n\n";
+
+    $message .= "In most mail programs, this should appear as a blue link\n";
+    $message .= "which you can just click on.  If that doesn't work, \n";
+    $message .= "then cut and paste the address into the address\n";
+    $message .= "line at the top of your web browser window.\n\n";
+
+    $message .= "Cheers from the '$site->fullname' administrator,\n";
+    $message .= "$from->firstname $from->lastname ($from->email)\n";
+
+    $subject  = "$site->fullname: Changed password";
+
+    return email_to_user($user, $from, $subject, $message);
+
+}
+
+
+
+?>
diff --git a/login/forgot_password_change.html b/login/forgot_password_change.html
new file mode 100644 (file)
index 0000000..bff2199
--- /dev/null
@@ -0,0 +1,15 @@
+<CENTER>
+
+<P>An email has been sent to your address at <? pv($frm->email) ?> </P>
+
+<P><B>Please check your email for your new password</B>
+
+<P>The new password was automatically generated, so you might like to 
+   <A HREF="<?=$CFG->wwwroot ?>/login/change_password.php">change it to something easier to remember</A>.
+</P>
+
+<HR>
+<CENTER>
+<P><A HREF="<?=$CFG->wwwroot ?>">Home</A></P>
+
+
diff --git a/login/forgot_password_form.html b/login/forgot_password_form.html
new file mode 100644 (file)
index 0000000..93bacaa
--- /dev/null
@@ -0,0 +1,34 @@
+<table cellpadding=20 align=center>
+<tr valign=top>
+<td width=300 class=normal>
+       <p>Enter in your email address to reset your password, and 
+       have the new password sent to you via email.
+
+       <p>Otherwise, you can return to the 
+       <a href="<?=$CFG->wwwroot ?>/login/">login screen</a> or the
+       <a href="<?=$CFG->wwwroot ?>">home page</a> now.
+</td>
+
+<td bgcolor="<?=$THEME->cellheading?>">
+       <form name="form" method="post" action="<?=$ME?>">
+       <table>
+       <tr>
+               <td class=label>Email:</td>
+               <td><input type="text" name="email" size=25 value="<? pv($frm->email) ?>"> 
+               <? formerr($err->email); ?>
+       </tr>
+       <tr>
+               <td></td>
+               <td><input type="submit" value="Submit">
+                       <input type="button" value="Cancel" onClick="javascript: history.go(-1)">
+               </td>
+       </table>
+       </form>
+</td>
+</tr>
+</table>
+
+<HR>
+<CENTER>
+<P><A HREF="<?=$CFG->wwwroot ?>">Home</A></P>
+
diff --git a/login/index.php b/login/index.php
new file mode 100644 (file)
index 0000000..87b4314
--- /dev/null
@@ -0,0 +1,87 @@
+<?PHP // $Id$
+    require("../config.php");
+
+
+    if (match_referer() && isset($HTTP_POST_VARS)) {    // form submitted
+
+        $frm = (object)$HTTP_POST_VARS;
+        $user = verify_login($frm->username, $frm->password);
+
+           update_login_count();
+
+        if ($user) {
+            if (! $user->confirmed ) {       // they never confirmed via email 
+                print_header("Need to confirm", "Not confirmed yet", "", ""); 
+                include("index_confirm.html");
+                die;
+            }
+    
+            $USER = $user;
+            $USER->loggedin = true;
+    
+            if (!update_user_in_db()) {
+                error("Weird error: User not found");
+            }
+
+            if (!update_user_login_times()) {
+                error("Wierd error: could not update login records");
+            }
+    
+                   set_moodle_cookie($USER->username);
+
+    
+                   if (empty($SESSION->wantsurl)) {
+                   header("Location: $CFG->wwwroot");
+                   } else {
+                   header("Location: $SESSION->wantsurl");
+                           unset($SESSION->wantsurl);
+                   }
+    
+                   reset_login_count();
+            add_to_log("Logged in");
+
+            if ($CFG->smsnotify) {
+                $time = date("H:i D j M", time());
+                $smstring = "$time - $USER->firstname $USER->lastname logged in to $CFG->sitename";
+                system("echo \"$smstring   \" | /opt/bin/sendsms &> /dev/null &");
+            }
+    
+            die;
+    
+        } else {
+            $errormsg = "Invalid login, please try again";
+        }
+    }
+    
+    if (empty($SESSION->wantsurl)) {
+           $SESSION->wantsurl = $HTTP_REFERER;  
+    }
+    
+    if (!$frm->username) 
+        $frm->username = get_moodle_cookie();
+    
+    if ($frm->username) {
+        $focus = "form.password";
+    } else {
+        $focus = "form.username";
+    }
+    
+    print_header("Login to the site", "Login to the site", "Login", $focus); 
+
+    include("index_form.html");
+
+    exit;
+
+    // No footer on this page
+
+function update_user_login_times() {
+    global $db, $USER;
+
+    $USER->lastlogin = $USER->currentlogin;
+    $USER->currentlogin = time();
+
+    return $db->Execute("UPDATE user 
+                         SET lastlogin='$USER->lastlogin', currentlogin='$USER->currentlogin'
+                         WHERE id = '$USER->id'");
+}
+?>
diff --git a/login/index_confirm.html b/login/index_confirm.html
new file mode 100644 (file)
index 0000000..5a1568b
--- /dev/null
@@ -0,0 +1,20 @@
+<CENTER>
+
+<h2>Sorry, <? pv($user->firstname) ?>, but you can't log in until you have confirmed your registration</h2>
+
+<h2>Please check your email!</h2>
+
+<p class=normal>
+An email should have been sent to your address at <? pv($user->email) ?>
+
+</p>
+<p class=normal>
+It contains easy instructions to complete your registration.
+</p>
+
+<p>If you continue to have difficulty, contact the site administrator.
+
+<HR>
+<CENTER>
+<P><A HREF="<?=$CFG->wwwroot ?>">Home</A></P>
+
diff --git a/login/index_form.html b/login/index_form.html
new file mode 100644 (file)
index 0000000..8cb3a14
--- /dev/null
@@ -0,0 +1,63 @@
+<CENTER>\r
+\r
+<TABLE WIDTH="90%" BORDER="0" CELLSPACING="10" CELLPADDING="5" ALIGN="CENTER">\r
+  <TR>\r
+    <TD WIDTH="50%" bgcolor=<?=$THEME->cellheading2?>>\r
+      <P ALIGN="CENTER"><B><FONT SIZE=3>Returning to this web site?</FONT></B></P>\r
+    </TD>\r
+    <TD WIDTH="50%" bgcolor=<?=$THEME->cellheading2?>>\r
+      <P ALIGN="CENTER"><B><FONT SIZE=3>Is this your first time here?</FONT></B></P>\r
+    </TD>\r
+  </TR>\r
+  <TR>\r
+    <TD WIDTH="50%" VALIGN="TOP" bgcolor="<?=$THEME->cellheading?>"> \r
+      <FONT SIZE=2>\r
+      <P ALIGN="CENTER">Log in using your username and password:</P>\r
+      <P ALIGN="CENTER"><? formerr($errormsg) ?></P>\r
+      <FORM NAME="form" ACTION="<?=$CFG->wwwroot?>/login/" METHOD=post>\r
+      <CENTER>\r
+      <TABLE ALIGN=center>\r
+      <TR><TD align=right><P><FONT SIZE=2>Username:</FONT></P></TD>\r
+          <TD><INPUT TYPE="text" NAME="username" SIZE="15" value="<? p($frm->username) ?>">\r
+      </TD></TR>\r
+      <TR><TD align=right><P><FONT SIZE=2>Password:</FONT></P></TD>\r
+          <TD><INPUT TYPE="password" NAME="password" SIZE="15" value="<? p($frm->password) ?>">\r
+      </TD></TR>\r
+      </TABLE>\r
+      <BR>\r
+      <INPUT TYPE="submit" NAME="Submit" VALUE="Login">\r
+      </FORM>\r
+      </CENTER>\r
+\r
+      <P>&nbsp;</P>\r
+      <P>If you've logged in before but can't remember your username or password, \r
+        then you can <A HREF="forgot_password.php">have your details sent to you via email</A>.</P>\r
+      </FONT>\r
+    </TD>\r
+    <TD WIDTH="50%" VALIGN="TOP" bgcolor="<?=$THEME->cellheading?>">\r
+      <FONT SIZE=2>\r
+      <P>Hi! You need to create a new account for yourself on this server so we know who \r
+        you are. Each of the individual courses may also have a one-time \r
+        &quot;course entry key&quot;, which you won't need until later. Here are \r
+        the steps:</P>\r
+        <OL size=2>\r
+      <LI>Fill out the <A HREF="signup.php">New Account</A> form with your details.\r
+      <LI>An email will be immediately sent to your email address. \r
+      <LI>Read your email, and click on the web link it contains.\r
+      <LI>Your account will be confirmed and you will be logged in.\r
+      <LI>Now, select the course you want to participate in.\r
+      <LI>If you are prompted for a &quot;course entry key&quot; - use the one \r
+        that your teacher has given you. This will &quot;enrol&quot; you in the \r
+        course.\r
+      <LI>You can now access the full course. From now on you will only need \r
+        to enter your personal username and password (in the form on this page) \r
+        to log in and access any course you have enrolled in.\r
+      <P ALIGN="CENTER"><B><A HREF="signup.php">Start now by creating a new account!</A></B></P>\r
+      </FONT>\r
+      </TD>\r
+  </TR>\r
+</TABLE>\r
+\r
+<HR>\r
+<CENTER>\r
+<P><A HREF="<?=$CFG->wwwroot ?>">Home</A></P>\r
diff --git a/login/logout.php b/login/logout.php
new file mode 100644 (file)
index 0000000..33a8192
--- /dev/null
@@ -0,0 +1,11 @@
+<?PHP // $Id$
+// Logs the user out and sends them back where they came from
+
+    require("../config.php");
+
+    add_to_log("Logged out");
+    unset($USER);
+    redirect($HTTP_REFERER);
+    exit;
+
+?>
diff --git a/login/signup.php b/login/signup.php
new file mode 100644 (file)
index 0000000..e6ba76b
--- /dev/null
@@ -0,0 +1,129 @@
+<?PHP // $Id$
+
+       require("../config.php");
+       require("countries.php");
+
+       if (match_referer() && isset($HTTP_POST_VARS)) {
+               $user = (object) $HTTP_POST_VARS;
+
+               validate_form($user, $err);
+
+               if (count((array)$err) == 0) {
+
+            $user->password = md5($user->password);
+            $user->confirmed = 0;
+            $user->firstaccess = time();
+
+                       if (! ($user->id = insert_record("user", $user)) ) {
+                error("Could not add your record to the database!");
+            }
+
+            if (! send_confirmation_email($user)) {
+                error("Tried to send you an email but failed!");
+            }
+       
+               print_header("Check your email", "Check your email", "Confirm", "");
+                       include("signup_confirm.html");
+                       exit;
+               }
+       }
+
+       if ($err) {
+               foreach ((array)$err as $key => $value) {
+                       $focus = "form.$key";
+               }
+       }
+
+       print_header("New account", "New account", 
+                 "<A HREF=\".\">Login</A> -> New Account", $focus);
+
+       include("signup_form.php");
+
+
+
+/******************************************************************************
+ * FUNCTIONS
+ *****************************************************************************/
+
+function validate_form($user, &$err) {
+
+       if (empty($user->username))
+               $err->username = "Missing username";
+
+    else if (record_exists("user", "username", $user->username))
+        $err->username = "This username already exists, choose another";
+
+    else {
+        $string = eregi_replace("[^([:alnum:])]", "", $user->username);
+        if (strcmp($user->username, $string)) 
+            $err->username = "Must only contain alphabetical characters";
+    }
+
+
+       if (empty($user->password)) 
+               $err->password = "Missing password";
+
+    if (empty($user->firstname))
+        $err->firstname = "Missing first name";
+        
+    if (empty($user->lastname))
+        $err->lastname = "Missing last name";
+        
+
+    if (empty($user->email))
+        $err->email = "Missing email address";
+        
+    else if (! validate_email($user->email))
+        $err->email = "Invalid email address, check carefully";
+       
+    else if (record_exists("user", "email", $user->email)) 
+               $err->email = "Email address already registered. <A HREF=forgot_password.php>New password?</A>";
+
+
+       if (empty($user->phone)) 
+               $err->phone = "Missing phone number";
+
+       if (empty($user->city)) 
+               $err->city = "Missing city";
+
+       if (empty($user->country)) 
+               $err->country = "Missing country";
+
+    return;
+}
+
+
+function send_confirmation_email($user) {
+
+    global $CFG;
+
+    $site  = get_site();
+    $from = get_admin();
+
+    $message  = "Hi $user->firstname,\n\n";
+
+    $message .= "A new account has been requested at '$site->fullname'\n";
+    $message .= "using your email address.\n\n";
+
+    $message .= "To confirm your new account, please go to the \n";
+    $message .= "following web address:\n\n";
+
+    $message .= "$CFG->wwwroot/login/confirm.php?x=$user->id&s=$user->username\n\n";
+
+    $message .= "In most mail programs, this should appear as a blue link\n";
+    $message .= "which you can just click on.  If that doesn't work, \n";
+    $message .= "then cut and paste the address into the address\n";
+    $message .= "line at the top of your web browser window.\n\n";
+
+    $message .= "Cheers from the '$site->fullname' administrator,\n";
+    $message .= "$from->firstname $from->lastname ($from->email)\n";
+
+    $subject  = "$site->fullname account confirmation";
+
+    return email_to_user($user, $from, $subject, $message);
+
+}
+
+
+
+?>
diff --git a/login/signup_confirm.html b/login/signup_confirm.html
new file mode 100644 (file)
index 0000000..a4a8203
--- /dev/null
@@ -0,0 +1,19 @@
+<CENTER>
+
+<h2>Thanks, <? pv($user->firstname) ?></h2>
+<h2>Your new account is almost finished</h2>
+
+<h2>Please check your email!</h2>
+
+<p class=normal>
+An email has been sent to your address at <? pv($user->email) ?>
+
+</p>
+<p class=normal>
+It contains easy instructions to confirm your new account.
+</p>
+
+<HR>
+<CENTER>
+<P><A HREF="<?=$CFG->wwwroot ?>">Home</A></P>
+
diff --git a/login/signup_form.php b/login/signup_form.php
new file mode 100644 (file)
index 0000000..cd41e77
--- /dev/null
@@ -0,0 +1,77 @@
+<CENTER>
+<table cellpadding=20> <tr> <td bgcolor="<?=$THEME->cellheading ?>">
+
+<form name="form" method="post" action="signup.php">
+<table>
+<tr valign=top>
+       <td colspan=2><P><B>Create a new username and password to log in with:</td>
+</tr>
+<tr valign=top>
+       <td><P>New username:</td>
+       <td><input type="text" name="username" size=12 value="<? pv($user->username) ?>">
+       <? formerr($err->username) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>New password:</td>
+       <td><input type="text" name="password" size=12 value="<? pv($user->password) ?>">
+       <? formerr($err->password) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td colspan=2><BR><P><B>Please supply some information about yourself:</td>
+</tr>
+<tr valign=top>
+       <td><P>First name:</td>
+       <td><input type="text" name="firstname" size=25 value="<? pv($user->firstname) ?>">
+       <? formerr($err->firstname) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Last name:</td>
+       <td><input type="text" name="lastname" size=25 value="<? pv($user->lastname) ?>">
+       <? formerr($err->lastname) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Curtin ID Number:</td>
+       <td><input type="text" name="idnumber" size=25 value="<? pv($user->idnumber) ?>"> (optional)
+       <? formerr($err->idnumber) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Email address:</td>
+       <td><input type="text" name="email" size=25 value="<? pv($user->email) ?>">
+       <? formerr($err->email) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Phone number:</td>
+       <td><input type="text" name="phone" size=25 value="<? pv($user->phone) ?>">
+       <? formerr($err->phone) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>City or town:</td>
+       <td><input type="text" name="city" size=25 value="<? pv($user->city) ?>">
+       <? formerr($err->city) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Country:</td>
+       <td><? print_country_menu($user->country) ?>
+       <? formerr($err->country) ?>
+       </td>
+</tr>
+<tr>
+       <td></td>
+       <td><input type="submit" value="Create my new account"></td>
+</table>
+</form>
+
+</td></tr></table>
+
+<HR>
+<CENTER>
+<P><A HREF="<?=$CFG->wwwroot ?>">Home</A></P>
+
diff --git a/mod/assignment/README b/mod/assignment/README
new file mode 100644 (file)
index 0000000..0e47ab9
--- /dev/null
@@ -0,0 +1,6 @@
+Describes the assignment (eg an essay) that needs to be completed
+then collects and datestamps it.  Later, shows the grade.
+
+Teacher view, show class list, allows download and grades.
+
+
diff --git a/mod/assignment/module.php b/mod/assignment/module.php
new file mode 100644 (file)
index 0000000..9f60400
--- /dev/null
@@ -0,0 +1,10 @@
+<?PHP // $Id$
+
+////////////////////////////////////////////////////////////////////////////////
+//  Code fragment to define the module version etc.
+//  This fragment is called by /admin/index.php
+////////////////////////////////////////////////////////////////////////////////
+
+
+?>
+
diff --git a/mod/choice/icon.gif b/mod/choice/icon.gif
new file mode 100644 (file)
index 0000000..5ee2c50
Binary files /dev/null and b/mod/choice/icon.gif differ
diff --git a/mod/choice/index.php b/mod/choice/index.php
new file mode 100644 (file)
index 0000000..51f07ad
--- /dev/null
@@ -0,0 +1,62 @@
+<?PHP  // $Id$
+
+    require("../../config.php");
+
+    require_variable($id);   // course
+
+    if (! $course = get_record("course", "id", $id)) {
+        error("Course ID is incorrect");
+    }
+
+    require_login($course->id);
+
+    add_to_log("View list of all choices", $course->id);
+
+    print_header("$course->shortname: Choices", "$course->fullname",
+                 "<A HREF=../../course/view.php?id=$course->id>$course->shortname</A> -> Choices", "");
+
+
+    if (! $choices = get_all_instances_in_course("choice", $course->id, "cw.week ASC")) {
+        notice("There are no choices", "../../course/view.php?id=$course->id");
+    }
+
+    if ( $allanswers = get_records_sql("SELECT * FROM choice_answers WHERE user='$USER->id'")) {
+        foreach ($allanswers as $aa) {
+            $answers[$aa->choice] = $aa;
+        }
+
+    } else {
+        $answers = array () ;
+    }
+
+
+    $timenow = time();
+
+    $table->head  = array ("Week", "Question", "Answer");
+    $table->align = array ("CENTER", "LEFT", "CENTER");
+
+    foreach ($choices as $choice) {
+        $answer = $answers[$choice->id];
+        switch ($answer->answer) {
+            case 1:
+                $aa = "$choice->answer1";
+                break;
+            case 2:
+                $aa = "$choice->answer2";
+                break;
+            default:
+                $aa = "Undecided";
+                break;
+        }
+
+        $table->data[] = array ("<P>$choice->week</P>",
+                                "<P><A HREF=\"view.php?id=$choice->coursemodule\">$choice->name</A></P>",
+                                "<P>$aa</P>");
+    }
+    print_table($table);
+
+    print_footer($course);
+
+?>
+
diff --git a/mod/choice/install.sql b/mod/choice/install.sql
new file mode 100755 (executable)
index 0000000..6e747a4
--- /dev/null
@@ -0,0 +1,43 @@
+# phpMyAdmin MySQL-Dump\r
+# version 2.2.1\r
+# http://phpwizard.net/phpMyAdmin/\r
+# http://phpmyadmin.sourceforge.net/ (download page)\r
+#\r
+# Host: localhost\r
+# Generation Time: Nov 14, 2001 at 04:44 PM\r
+# Server version: 3.23.36\r
+# PHP Version: 4.0.6\r
+# Database : `moodle`\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `choice`\r
+#\r
+\r
+CREATE TABLE choice (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  course int(10) unsigned NOT NULL default '0',\r
+  name varchar(255) NOT NULL default '',\r
+  text text NOT NULL,\r
+  answer1 varchar(255) NOT NULL default 'Yes',\r
+  answer2 varchar(255) NOT NULL default 'No',\r
+  timemodified int(10) unsigned NOT NULL default '0',\r
+  PRIMARY KEY  (id),\r
+  UNIQUE KEY id (id)\r
+) TYPE=MyISAM;\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `choice_answers`\r
+#\r
+\r
+CREATE TABLE choice_answers (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  choice int(10) unsigned NOT NULL default '0',\r
+  user int(10) unsigned NOT NULL default '0',\r
+  answer tinyint(4) NOT NULL default '0',\r
+  timemodified int(10) NOT NULL default '0',\r
+  PRIMARY KEY  (id),\r
+  UNIQUE KEY id (id)\r
+) TYPE=MyISAM;\r
+\r
diff --git a/mod/choice/mod.html b/mod/choice/mod.html
new file mode 100644 (file)
index 0000000..2f592bd
--- /dev/null
@@ -0,0 +1,54 @@
+<FORM NAME="form" METHOD="post" ACTION="<?=$ME ?>">
+
+<table cellpadding=5>
+
+<tr valign=top>
+    <td align=right><P><B>Choice Name:</B></P></TD>
+    <td>
+        <input type="text" name="name" size=30 value="<? p($form->name) ?>">
+    </td>
+</tr>
+
+<tr valign=top>
+    <td align=right><P><B>Choice Text:</B></P></TD>
+    <td>
+        <textarea name="text" rows=15 cols=30 wrap="virtual"><? p($form->text) ?></textarea>
+    </td>
+</tr>
+
+<tr valign=top>
+    <td align=right><P><B>First choice:</B></P></TD>
+    <td>
+        <input type="text" name="answer1" size=30 value="<? 
+        if ($form->answer1) {
+            p($form->answer1);
+        } else {
+            echo "Yes";
+        } ?>">
+    </td>
+</tr>
+
+<tr valign=top>
+    <td align=right><P><B>Second choice:</B></P></TD>
+    <td>
+        <input type="text" name="answer2" size=30 value="<? 
+        if ($form->answer2) {
+            p($form->answer2);
+        } else {
+            echo "No";
+        } ?>">
+    </td>
+</tr>
+
+</table>
+
+<CENTER>
+<input type="hidden" name=course     value="<? p($form->course) ?>">
+<input type="hidden" name=week       value="<? p($form->week) ?>">
+<input type="hidden" name=module     value="<? p($form->module) ?>">
+<input type="hidden" name=modulename value="<? p($form->modulename) ?>">
+<input type="hidden" name=instance   value="<? p($form->instance) ?>">
+<input type="hidden" name=mode       value="<? p($form->mode) ?>">
+<input type="submit" value="Save these settings">
+</CENTER>
+</FORM>
diff --git a/mod/choice/mod.php b/mod/choice/mod.php
new file mode 100644 (file)
index 0000000..59374eb
--- /dev/null
@@ -0,0 +1,81 @@
+<?PHP  // $Id$
+
+/////////////////////////////////////////////////////////////
+//
+// MOD.PHP - contains functions to add, update and delete
+//           an instance of this module
+//           
+//           Generally called from /course/mod.php
+//
+/////////////////////////////////////////////////////////////
+
+function add_instance($form) {
+// Given an object containing all the necessary data, 
+// (defined by the form in mod.html) this function 
+// will create a new instance and return the id number 
+// of the new instance.
+//
+    GLOBAL $db;
+
+    $timenow = time();
+
+    if (!$rs = $db->Execute("INSERT into choice
+                                SET course   = '$form->course', 
+                                    name     = '$form->name',
+                                    text     = '$form->text',
+                                    answer1  = '$form->answer1',
+                                    answer2  = '$form->answer2',
+                                    timemodified = '$timenow'")) {
+        return 0;
+    }
+    
+    // Get it out again - this is the most compatible way to determine the ID
+    if ($rs = $db->Execute("SELECT id FROM choice
+                            WHERE course = $form->course AND timemodified = '$timenow'")) {
+        return $rs->fields[0];
+    } else {
+        return 0;
+    }
+}
+
+
+function update_instance($form) {
+// Given an object containing all the necessary data, 
+// (defined by the form in mod.html) this function 
+// will update an existing instance with new data.
+//
+    GLOBAL $db;
+
+    $timenow = time();
+
+    if (!$rs = $db->Execute("UPDATE choice
+                                SET course   = '$form->course', 
+                                    name     = '$form->name',
+                                    text     = '$form->text',
+                                    answer1  = '$form->answer1',
+                                    answer2  = '$form->answer2',
+                                    timemodified = '$timenow'
+                              WHERE id = '$form->instance' ")) {
+        return false;
+    }
+    return true;
+}
+
+
+function delete_instance($id) {
+// Given an ID of an instance of this module, 
+// this function will permanently delete the instance 
+// and any data that depends on it.  
+//
+    GLOBAL $db;
+
+    if (!$rs = $db->Execute("DELETE from choice WHERE id = '$id' ")) {
+        return false;
+    }
+
+    return true;
+    
+}
+
+
+?>
diff --git a/mod/choice/module.php b/mod/choice/module.php
new file mode 100644 (file)
index 0000000..6256b8d
--- /dev/null
@@ -0,0 +1,14 @@
+<?PHP // $Id$
+
+////////////////////////////////////////////////////////////////////////////////
+//  Code fragment to define the module version etc.
+//  This fragment is called by /admin/index.php
+////////////////////////////////////////////////////////////////////////////////
+
+    $module->fullname = "Choice";
+    $module->version  = "20011110";
+    $module->cron     = 0;
+    $module->search   = "";
+
+?>
+
diff --git a/mod/choice/report.php b/mod/choice/report.php
new file mode 100644 (file)
index 0000000..7c4049c
--- /dev/null
@@ -0,0 +1,94 @@
+<?PHP  // $Id$
+
+    require("../../config.php");
+
+    require_variable($id);   // course module
+
+    if (! $cm = get_record("course_modules", "id", $id)) {
+        error("Course Module ID was incorrect");
+    }
+
+    if (! $course = get_record("course", "id", $cm->course)) {
+        error("Course module is misconfigured");
+    }
+
+    require_login($course->id);
+
+    if (!isteacher($course->id)) {
+        error("Only teachers can look at this page");
+    }
+
+    if (! $choice = get_record("choice", "id", $cm->instance)) {
+        error("Course module is incorrect");
+    }
+
+    add_to_log("View choices report", $course->id);
+
+    print_header("$course->shortname: $choice->name: Responses", "$course->fullname",
+                 "<A HREF=/course/view.php?id=$course->id>$course->shortname</A> ->
+                  <A HREF=index.php?id=$course->id>Choices</A> ->
+                  <A HREF=view.php?id=$cm->id>$choice->name</A> -> Responses", "");
+
+
+    if (! $participants = get_records_sql("SELECT u.* FROM user u, user_students s, user_teachers t
+                                       WHERE (s.course = '$course->id' AND s.user = u.id) 
+                                          OR (t.course = '$course->id' AND t.user = u.id)
+                                       ORDER BY u.lastaccess DESC")) {
+
+        notify("No participants (strange)", "/course/view.php?id=$course->id");
+        die;
+    }
+
+    if ( $allanswers = get_records_sql("SELECT * FROM choice_answers WHERE choice='$choice->id'")) {
+        foreach ($allanswers as $aa) {
+            $answers[$aa->user] = $aa;
+        }
+        
+    } else {
+        $answers = array () ;
+    }
+    
+
+
+    $timenow = time();
+
+    echo "<TABLE BORDER=1 CELLSPACING=0 valign=top align=center cellpadding=10>";
+    foreach ($participants as $user) {
+        $answer = $answers[$user->id];
+
+        echo "<TR>";
+
+        echo "<TD BGCOLOR=\"$THEME->body\" WIDTH=35 VALIGN=TOP>";
+        print_user_picture($user->id, $course->id, $user->picture);
+        echo "</TD>";
+
+        echo "<TD NOWRAP BGCOLOR=\"$THEME->cellheading\">$user->firstname $user->lastname</TD>";
+        echo "<TD><P>&nbsp;";
+        if ($answer->timemodified) {
+            echo moodledate($answer->timemodified);
+        } 
+        
+        echo "</P> </TD>";
+
+        echo "<TD ALIGN=CENTER BGCOLOR=\"$THEME->cellcontent\"><P>";
+        switch ($answer->answer) {
+            case 1:
+                echo "$choice->answer1";
+                break;
+            case 2:
+                echo "$choice->answer2";
+                break;
+            default:
+                echo "Undecided";
+                break;
+                
+        }
+        echo "</P></TD></TR>";
+    }
+    echo "</TABLE>";
+
+    print_footer($course);
+
+?>
+
diff --git a/mod/choice/view.html b/mod/choice/view.html
new file mode 100644 (file)
index 0000000..286232c
--- /dev/null
@@ -0,0 +1,19 @@
+<CENTER>
+<P>
+<FORM name="form" method="post" action="view.php">
+<TABLE WIDTH=70% CELLPADDING=20 CELLSPACING=20><TR>
+<TD ALIGN=CENTER NOWRAP WIDTH=50%>
+<INPUT type="radio" name=answer value="1" <?=$answer1checked ?> >
+  <? p($choice->answer1) ?>
+</TD>
+<TD ALIGN=CENTER NOWRAP WIDTH=50%>
+<INPUT type="radio" name=answer value="2" <?=$answer2checked ?> >
+  <? p($choice->answer2) ?>
+</TD>
+</TR></TABLE>
+<P>
+<INPUT type="hidden" name=id value="<?=$cm->id ?>">
+<INPUT type="submit" value="Save my choice">
+</P>
+</FORM>
+</CENTER>
diff --git a/mod/choice/view.php b/mod/choice/view.php
new file mode 100644 (file)
index 0000000..901d928
--- /dev/null
@@ -0,0 +1,92 @@
+<?PHP  // $Id$
+
+    require("../../config.php");
+
+    require_variable($id);    // Course Module ID
+
+    if (! $cm = get_record("course_modules", "id", $id)) {
+        error("Course Module ID was incorrect");
+    }
+
+    if (! $course = get_record("course", "id", $cm->course)) {
+        error("Course is misconfigured");
+    }
+
+    require_login($course->id);
+
+    if (! $choice = get_record("choice", "id", $cm->instance)) {
+        error("Course module is incorrect");
+    }
+
+    if ($current = get_record_sql("SELECT * FROM choice_answers
+                                     WHERE choice='$choice->id' AND user='$USER->id'")) {
+        if ($current->answer == "1") {
+            $answer1checked = "CHECKED";
+        } else if ($current->answer == "2") {
+            $answer2checked = "CHECKED";
+        }
+    }
+
+    if (match_referer() && isset($HTTP_POST_VARS)) {    // form submitted
+        $form = (object)$HTTP_POST_VARS;
+        if ($current) {
+            add_to_log("Update choice: $choice->name", $course->id);
+            if (! update_choice_in_database($current, $form->answer)) {
+                error("Could not update your choice");
+            }
+        } else {
+            add_to_log("Save choice: $choice->name", $course->id);
+            if (! add_new_choice_to_database($choice, $form->answer)) {
+                error("Could not save your choice");
+            }
+        }
+        redirect("$CFG->wwwroot/course/view.php?id=$course->id");
+        exit;
+    }
+
+    add_to_log("View choice: $choice->name", $course->id);
+    print_header("$course->shortname: $choice->name", "$course->fullname",
+                 "<A HREF=../../course/view.php?id=$course->id>$course->shortname</A> -> 
+                  <A HREF=index.php?id=$course->id>Choices</A> -> $choice->name", "");
+
+    if ($USER->editing) {
+        print_update_module_icon($cm->id);
+    }
+
+    if (isteacher($course->id)) {
+        echo "<P align=right><A HREF=\"report.php?id=$cm->id\">View all responses</A></P>";
+    }
+
+    print_simple_box( text_to_html($choice->text) , "center");
+
+    require("view.html");
+
+    print_footer($course);
+
+
+
+// Functions /////////////////////////////////////////////////
+
+function add_new_choice_to_database($choice, $answer) {
+    global $db;
+    global $USER;
+
+    $timenow = time();
+
+    $rs = $db->Execute("INSERT INTO choice_answers (choice, user, answer, timemodified)
+                        VALUES ( '$choice->id', '$USER->id', '$answer', '$timenow')");
+    return $rs;
+}
+
+function update_choice_in_database($current, $answer) {
+    global $db;
+
+    $timenow = time();
+
+    $rs = $db->Execute("UPDATE choice_answers
+                        SET answer='$answer', timemodified='$timenow' 
+                        WHERE id = '$current->id'");
+    return $rs;
+}
+
+?>
diff --git a/mod/journal/edit.html b/mod/journal/edit.html
new file mode 100644 (file)
index 0000000..b554b4f
--- /dev/null
@@ -0,0 +1,10 @@
+<BLOCKQUOTE>
+<FORM name="form" method="post" action="edit.php">
+<TEXTAREA NAME=text COLS=60 ROWS=10 WRAP="virtual"><? p($entry->text) ?></TEXTAREA>
+<P>
+<INPUT type="hidden" name=id value="<?=$cm->id ?>">
+<INPUT type="submit" value="Save and continue">
+<INPUT type="reset" value="Revert">
+</P>
+</FORM>
+</BLOCKQUOTE>
diff --git a/mod/journal/edit.php b/mod/journal/edit.php
new file mode 100644 (file)
index 0000000..ea2cfc3
--- /dev/null
@@ -0,0 +1,75 @@
+<?PHP // $Id$
+
+       require("../../config.php");
+
+    require_variable($id);    // Course Module ID
+
+    if (! $cm = get_record("course_modules", "id", $id)) {
+        error("Course Module ID was incorrect");
+    }
+
+    if (! $course = get_record("course", "id", $cm->course)) {
+        error("Course is misconfigured");
+    }
+
+    require_login($course->id);
+
+    if (! $journal = get_record("journal", "id", $cm->instance)) {
+        error("Course module is incorrect");
+    }
+
+    $entry = get_record_sql("SELECT * FROM journal_entries 
+                             WHERE user='$USER->id' AND journal='$journal->id'");
+
+
+/// If data submitted, then process and store.
+
+       if (match_referer() && isset($HTTP_POST_VARS)) {
+
+               $timenow = time();
+
+               if ($entry) {
+            $newentry->id = $entry->id;
+            $newentry->text = $text;
+            $newentry->modified = $timenow;
+                       if (! update_record("journal_entries", $newentry)) {
+                               error("Could not update your journal");
+                       }
+            add_to_log("Update journal: $journal->name", $course->id);
+               } else {
+            $newentry->user = $USER->id;
+            $newentry->journal = $journal->id;
+            $newentry->modified = $timenow;
+            $newentry->text = $text;
+                       if (! insert_record("journal_entries", $newentry)) {
+                               error("Could not insert a new journal entry");
+                       }
+            add_to_log("Add journal: $journal->name", $course->id);
+               } 
+               
+               redirect("view.php?id=$cm->id");
+               die;
+       }
+
+/// Otherwise fill and print the form.
+
+    if (! $entry ) {
+        $entry->text = "";
+    }
+
+    print_header("$course->shortname: $journal->name", "$course->fullname",
+                 "<A HREF=/course/view.php?id=$course->id>$course->shortname</A> -> 
+                  <A HREF=/mod/journal/index.php?id=$course->id>Journals</A> -> 
+                  <A HREF=\"view.php?id=$cm->id\">$journal->name</A> -> Edit", "form.text");
+
+    echo "<CENTER>\n";
+
+    print_simple_box( text_to_html($journal->intro) , "center");
+
+    echo "<BR>";
+
+       include("edit.html");
+
+    print_footer($course);
+
+?>
diff --git a/mod/journal/icon.gif b/mod/journal/icon.gif
new file mode 100755 (executable)
index 0000000..a32d346
Binary files /dev/null and b/mod/journal/icon.gif differ
diff --git a/mod/journal/index.php b/mod/journal/index.php
new file mode 100644 (file)
index 0000000..014f249
--- /dev/null
@@ -0,0 +1,60 @@
+<?PHP // $Id$
+
+    require("../../config.php");
+    require("lib.php");
+
+    require_variable($id);   // course
+
+    if (! $course = get_record("course", "id", $id)) {
+        error("Course ID is incorrect");
+    }
+
+    require_login($course->id);
+    add_to_log("View all journals", $course->id);
+
+    print_header("$course->shortname: Journals", "$course->fullname",
+                 "<A HREF=../../course/view.php?id=$course->id>$course->shortname</A> -> Journals", "");
+
+
+    if (! $journals = get_all_instances_in_course("journal", $course->id, "cw.week ASC")) {
+        notice("There are no journals", "../../course/view.php?id=$course->id");
+        die;
+    }
+
+    $timenow = time();
+
+    $table->head  = array ("Week", "Question", "Answer");
+    $table->align = array ("CENTER", "LEFT", "LEFT");
+
+    foreach ($journals as $journal) {
+
+        $entry = get_record_sql("SELECT text FROM journal_entries 
+                                 WHERE user='$USER->id' AND journal='$journal->id'");
+
+        $journal->timestart  = $course->startdate + (($journal->week - 1) * 608400);
+        if ($journal->daysopen) {
+            $journal->timefinish = $journal->timestart + (3600 * 24 * $journal->daysopen);
+        } else {
+            $journal->timefinish = 9999999999;
+        }
+        $journalopen = ($journal->timestart < $timenow && $timenow < $journal->timefinish);
+
+
+        $text = text_to_html($entry->text)."<P ALIGN=right><A HREF=\"view.php?id=$journal->coursemodule\">";
+        if ($journalopen) {
+            $text .= "Edit</A></P>";
+        } else {
+            $text .= "View</A></P>";
+        }
+        $table->data[] = array ("$journal->week",
+                                text_to_html($journal->intro),
+                                $text);
+    }
+
+    print_table($table);
+
+    print_footer($course);
+
+?>
+
diff --git a/mod/journal/install.sql b/mod/journal/install.sql
new file mode 100755 (executable)
index 0000000..d33e36f
--- /dev/null
@@ -0,0 +1,45 @@
+# phpMyAdmin MySQL-Dump\r
+# version 2.2.1\r
+# http://phpwizard.net/phpMyAdmin/\r
+# http://phpmyadmin.sourceforge.net/ (download page)\r
+#\r
+# Host: localhost\r
+# Generation Time: Nov 14, 2001 at 04:44 PM\r
+# Server version: 3.23.36\r
+# PHP Version: 4.0.6\r
+# Database : `moodle`\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `journal`\r
+#\r
+\r
+CREATE TABLE journal (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  course int(10) unsigned NOT NULL default '0',\r
+  name varchar(255) default NULL,\r
+  intro text,\r
+  days smallint(5) unsigned NOT NULL default '7',\r
+  assessed tinyint(1) NOT NULL default '1',\r
+  timemodified int(10) unsigned NOT NULL default '0',\r
+  PRIMARY KEY  (id)\r
+) TYPE=MyISAM;\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `journal_entries`\r
+#\r
+\r
+CREATE TABLE journal_entries (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  journal int(10) unsigned NOT NULL default '0',\r
+  user int(10) unsigned NOT NULL default '0',\r
+  modified int(10) unsigned NOT NULL default '0',\r
+  text text NOT NULL,\r
+  rating tinyint(4) default '0',\r
+  comment text,\r
+  teacher int(10) unsigned NOT NULL default '0',\r
+  timemarked int(10) unsigned NOT NULL default '0',\r
+  PRIMARY KEY  (id)\r
+) TYPE=MyISAM COMMENT='All the journal entries of all people';\r
+\r
diff --git a/mod/journal/lib.php b/mod/journal/lib.php
new file mode 100644 (file)
index 0000000..952b36b
--- /dev/null
@@ -0,0 +1,11 @@
+<?PHP // $Id$
+
+$RATING = array ("3" => "Outstanding",
+                 "2" => "Satisfactory",
+                 "1" => "Not satisfactory");
+
+function journaldate($date) {
+    return date("l, j F Y, g:i A T", $date);
+}
+
+?>
diff --git a/mod/journal/mod.html b/mod/journal/mod.html
new file mode 100644 (file)
index 0000000..6ee349e
--- /dev/null
@@ -0,0 +1,46 @@
+<form name="form" method="post" action="<?=$ME ?>">
+<table cellpadding=5>
+<tr valign=top>
+    <td align=right><P><B>Journal Name:</B></P></TD>
+    <td>
+        <input type="text" name="name" size=30 value="<? p($form->name) ?>">
+    </td>
+</tr>
+<tr valign=top>
+    <td align=right><P><B>Journal Question:</B></P></TD>
+    <td>
+        <textarea name="intro" rows=15 cols=30 wrap="virtual"><? p($form->intro) ?></textarea>
+    </td>
+</tr>
+<tr valign=top>
+    <TD align=right><P><B>Days available:</B></P></TD>
+    <TD>
+    <?
+        $options = array();
+        for ($i=0;$i<=13;$i++) {
+            $options[$i] = "$i days";
+        }
+        for ($i=2;$i<=16;$i++) {
+            $days = $i * 7;
+            $options[$days] = "$i weeks";
+        }
+        $options[365] = "1 year";
+        if ($form->days == "") {
+            $form->days == "14";
+        }
+        choose_from_menu($options, "days", "$form->days");
+     ?>
+    </TD>
+</tr>
+
+</table>
+<CENTER>
+<input type="hidden" name=course     value="<? p($form->course) ?>">
+<input type="hidden" name=week       value="<? p($form->week) ?>">
+<input type="hidden" name=module     value="<? p($form->module) ?>">
+<input type="hidden" name=modulename value="<? p($form->modulename) ?>">
+<input type="hidden" name=instance   value="<? p($form->instance) ?>">
+<input type="hidden" name=mode       value="<? p($form->mode) ?>">
+<input type="submit" value="Save these settings">
+</CENTER>
+</FORM>
diff --git a/mod/journal/mod.php b/mod/journal/mod.php
new file mode 100644 (file)
index 0000000..7de31ca
--- /dev/null
@@ -0,0 +1,83 @@
+<?PHP  // $Id$
+
+/////////////////////////////////////////////////////////////
+//
+// MOD.PHP - contains functions to add, update and delete
+//           an instance of this module
+//           
+//           Generally called from /course/mod.php
+//
+/////////////////////////////////////////////////////////////
+
+function add_instance($form) {
+// Given an object containing all the necessary data, 
+// (defined by the form in mod.html) this function 
+// will create a new instance and return the id number 
+// of the new instance.
+//
+    GLOBAL $db;
+
+    $timenow = time();
+
+    if (!$rs = $db->Execute("INSERT into journal
+                                SET course   = '$form->course', 
+                                    name     = '$form->name',
+                                    intro    = '$form->intro',
+                                    days     = '$form->days',
+                                    timemodified = '$timenow'")) {
+        return 0;
+    }
+    
+    // Get it out again - this is the most compatible way to determine the ID
+    if ($rs = $db->Execute("SELECT id FROM journal
+                            WHERE course = $form->course AND timemodified = '$timenow'")) {
+        return $rs->fields[0];
+    } else {
+        return 0;
+    }
+}
+
+
+function update_instance($form) {
+// Given an object containing all the necessary data, 
+// (defined by the form in mod.html) this function 
+// will update an existing instance with new data.
+//
+    GLOBAL $db;
+
+    $timenow = time();
+
+    if (!$rs = $db->Execute("UPDATE journal
+                                SET course   = '$form->course', 
+                                    name     = '$form->name',
+                                    intro    = '$form->intro',
+                                    days     = '$form->days',
+                                    timemodified = '$timenow'
+                              WHERE id = '$form->instance' ")) {
+        return false;
+    }
+    return true;
+}
+
+
+function delete_instance($id) {
+// Given an ID of an instance of this module, 
+// this function will permanently delete the instance 
+// and any data that depends on it.  
+//
+    GLOBAL $db;
+
+    if (!$rs = $db->Execute("DELETE from journal_entries WHERE journal = '$id' ")) {
+        return false;
+    }
+
+    if (!$rs = $db->Execute("DELETE from journal WHERE id = '$id' ")) {
+        return false;
+    }
+
+    return true;
+    
+}
+
+
+?>
diff --git a/mod/journal/module.php b/mod/journal/module.php
new file mode 100644 (file)
index 0000000..608216d
--- /dev/null
@@ -0,0 +1,14 @@
+<?PHP // $Id$
+
+////////////////////////////////////////////////////////////////////////////////
+//  Code fragment to define the module version etc.
+//  This fragment is called by /admin/index.php
+////////////////////////////////////////////////////////////////////////////////
+
+    $module->fullname = "Journal";
+    $module->version  = "20011110";
+    $module->cron     = 0;
+    $module->search   = "";
+
+?>
+
diff --git a/mod/journal/new.php b/mod/journal/new.php
new file mode 100644 (file)
index 0000000..fe00064
--- /dev/null
@@ -0,0 +1,39 @@
+<?PHP // $Id$
+
+// Code fragment called by /courses/new.php
+// Prints out a formatted table of all the new things that have happened 
+// with this module (since the user's last login).  Suitable for students.
+
+// Assumes $course and $USER are defined and page has been started.
+
+    if ($journals = get_all_instances_in_course("journal", $course->id)) {
+
+        foreach ($journals as $journal) {
+            if ($entry = get_record_sql("SELECT * FROM journal_entries
+                                          WHERE timemarked > '$USER->lastlogin' 
+                                                AND journal = '$journal->id'
+                                                AND user = $USER->id")) {
+                echo "<P><B>Journal feedback: $journal->name</B></P>";
+                echo "<FONT SIZE=2><UL>";
+                echo "<LI><A HREF=\"/mod/journal/view.php?id=$journal->coursemodule\">Your journal entry</A> has some feedback!";
+                echo ", ".moodledate($entry->timemarked);
+                echo "</UL></FONT>";
+            }
+
+            if ($entries = get_records_sql("SELECT j.*, u.id as userid, u.firstname, u.lastname 
+                                            FROM journal_entries j, user u
+                                            WHERE modified > '$USER->lastlogin' 
+                                                  AND journal = '$journal->id'
+                                                  AND j.user = u.id  ORDER by j.modified")) {
+                echo "<P><B>Journal entries: <A HREF=\"/mod/journal/view.php?id=$journal->coursemodule\">$journal->name</A></B></P>";
+                echo "<FONT SIZE=2><UL>";
+                foreach ($entries as $entry) {
+                    echo "<LI>$entry->firstname $entry->lastname edited their journal";
+                    echo ", ".moodledate($entry->modified);
+                }
+                echo "</UL></FONT>";
+            }
+        }
+    }
+
+?>
diff --git a/mod/journal/report.php b/mod/journal/report.php
new file mode 100644 (file)
index 0000000..3ae4513
--- /dev/null
@@ -0,0 +1,151 @@
+<?PHP // $Id$
+
+    require("../../config.php");
+    require("lib.php");
+
+    require_variable($id);   // course module
+
+    if (! $cm = get_record("course_modules", "id", $id)) {
+        error("Course Module ID was incorrect");
+    }
+
+    if (! $course = get_record("course", "id", $cm->course)) {
+        error("Course module is misconfigured");
+    }
+
+    require_login($course->id);
+
+    if (!isteacher($course->id)) {
+        error("Only teachers can look at this page");
+    }
+
+    if (! $journal = get_record("journal", "id", $cm->instance)) {
+        error("Course module is incorrect");
+    }
+
+    // make some easy ways to access the entries.
+    if ( $eee = get_records_sql("SELECT * FROM journal_entries WHERE journal='$journal->id'")) {
+        foreach ($eee as $ee) {
+            $entrybystudent[$ee->user] = $ee;
+            $entrybyentry[$ee->id]     = $ee;
+        }
+        
+    } else {
+        $entrybystudent = array () ;
+        $entrybyentry   = array () ;
+    }
+
+    print_header("$course->shortname: Journals", "$course->fullname",
+                 "<A HREF=/course/view.php?id=$course->id>$course->shortname</A> ->
+                  <A HREF=index.php?id=$course->id>Journals</A> ->
+                  <A HREF=view.php?id=$cm->id>$journal->name</A> -> Responses", "",
+                  "", true);
+
+    if (match_referer() && isset($HTTP_POST_VARS)) { // Feedback submitted
+       
+        $feedback = array();
+
+        // Peel out all the data from variable names.
+        foreach ($HTTP_POST_VARS as $key => $val) {
+            if ($key <> "id") {
+                $type = substr($key,0,1);
+                $num  = substr($key,1); 
+                $feedback[$num][$type] = $val;
+            }
+        }
+
+        $timenow = time();
+        $count = 0;
+        foreach ($feedback as $num => $vals) {
+            $entry = $entrybyentry[$num];
+            // Only update entries where feedback has actually changed.
+            if (($vals[r] <> $entry->rating) || ($vals[c] <> addslashes($entry->comment))) {
+                if (!$rs = $db->Execute("UPDATE journal_entries
+                                         SET rating='$vals[r]',   comment='$vals[c]',
+                                            teacher='$USER->id', timemarked='$timenow'
+                                         WHERE id = '$num'")) {
+                    error("Failed to update the journal feedback!");
+                }
+                $entrybystudent[$entry->user]->comment = $vals[c];
+                $entrybystudent[$entry->user]->rating = $vals[r];
+                $entrybystudent[$entry->user]->timemarked = $timenow;
+                $entrybystudent[$entry->user]->teacher = $USER->id;
+                $count++;
+            }
+        }
+        add_to_log("Updated journal feedback: $journal->name ($count students)", $course->id);
+        notify("Journal feedback updated for $count students.");
+    } else {
+        add_to_log("View journal responses: $journal->name", $course->id);
+    }
+
+
+    if (! $students = get_records_sql("SELECT u.* FROM user u, user_students s 
+                                       WHERE s.course = '$course->id' AND s.user = u.id
+                                       ORDER BY u.lastaccess DESC")) {
+        notify("No students", "/course/view.php?id=$course->id");
+        die;
+    }
+
+    if (! $teachers = get_records_sql("SELECT u.* FROM user u, user_teachers t 
+                                       WHERE t.course = '$course->id' AND t.user = u.id
+                                       ORDER BY u.lastaccess DESC")) {
+        notify("No teachers", "/course/view.php?id=$course->id");
+        die;
+    }
+
+    echo "<FORM ACTION=report.php METHOD=post>\n";
+    foreach ($students as $student) {
+        $entry = $entrybystudent[$student->id];
+
+        echo "\n<TABLE BORDER=1 CELLSPACING=0 valign=top cellpadding=10>";
+
+        echo "\n<TR>";
+        echo "\n<TD ROWSPAN=2 BGCOLOR=\"$THEME->body\" WIDTH=35 VALIGN=TOP>";
+        print_user_picture($student->id, $course->id, $student->picture);
+        echo "</TD>";
+        echo "<TD NOWRAP WIDTH=100% BGCOLOR=\"$THEME->cellheading\">$student->firstname $student->lastname";
+        if ($entry) {
+            echo "&nbsp;&nbsp;<FONT SIZE=1>Last edited: ".journaldate($entry->modified)."</FONT>";
+        }
+        echo "</TR>";
+
+        echo "\n<TR><TD WIDTH=100% BGCOLOR=\"$THEME->cellcontent\">";
+        if ($entry) {
+            echo text_to_html($entry->text);
+        } else {
+            echo "No entry";
+        }
+        echo "</TD></TR>";
+
+        if ($entry) {
+            echo "\n<TR>";
+            echo "<TD WIDTH=35 VALIGN=TOP>";
+            if (!$entry->teacher) {
+                $entry->teacher = $USER->id;
+            }
+            print_user_picture($entry->teacher, $course->id, $teachers[$entry->teacher]->picture);
+            echo "<TD BGCOLOR=\"$THEME->cellheading\">Teacher Feedback:";
+            choose_from_menu($RATING, "r$entry->id", $entry->rating, "Rate...");
+            if ($entry->timemarked) {
+                echo "&nbsp;&nbsp;<FONT SIZE=1>".journaldate($entry->timemarked)."</FONT>";
+            }
+            echo "<BR><TEXTAREA NAME=\"c$entry->id\" ROWS=4 COLS=60 WRAP=virtual>";
+            p($entry->comment);
+            echo "</TEXTAREA><BR>";
+            echo "</TD></TR>";
+        }
+        echo "</TABLE><BR CLEAR=ALL>\n";
+
+    }
+    echo "<CENTER>";
+    echo "<INPUT TYPE=hidden NAME=id VALUE=\"$cm->id\">";
+    echo "<INPUT TYPE=submit VALUE=\"Save all my feedback\">";
+    echo "</CENTER>";
+    echo "</FORM>";
+
+    print_footer($course);
+
+?>
+
diff --git a/mod/journal/user.php b/mod/journal/user.php
new file mode 100644 (file)
index 0000000..7e12fb2
--- /dev/null
@@ -0,0 +1,67 @@
+<?PHP // $Id$
+
+// Code fragment to list all the journals in a course by a particular user.
+// Assumes $course, $user and $mod are all defined (see /course/user.php)
+
+    include("$CFG->dirroot/mod/journal/lib.php");
+
+    if (! $journals = get_all_instances_in_course("journal", $course->id)) {
+        notify("There are no journals");
+        die;
+    }
+
+    if (! $teachers = get_records_sql("SELECT u.* FROM user u, user_teachers t 
+                                       WHERE t.course = '$course->id' AND t.user = u.id
+                                       ORDER BY u.lastaccess DESC")) {
+        notify("No teachers");
+        die;
+    }
+
+    $timenow = time();
+
+    echo "<TABLE BORDER=1 CELLSPACING=0 valign=top align=center cellpadding=10>";
+    echo "<TR><TH>Week<TH>Journal</TR>";
+    foreach ($journals as $journal) {
+
+        $journal->timestart  = $course->startdate + (($journal->week - 1) * 608400);
+        if ($journal->daysopen) {
+            $journal->timefinish = $journal->timestart + (3600 * 24 * $journal->daysopen);
+        } else {
+            $journal->timefinish = 9999999999;
+        }
+
+        $entry = get_record_sql("SELECT * FROM journal_entries 
+                                 WHERE user='$user->id' AND journal='$journal->id'");
+
+        if ($entry->text) {
+            echo "<TR VALIGN=TOP>";
+            $journalopen = ($journal->timestart < $timenow && $timenow < $journal->timefinish);
+            if ($journalopen) {
+                echo "<TD BGCOLOR=\"$THEME->cellheading2\">";
+            } else {
+                echo "<TD BGCOLOR=\"$THEME->cellheading\">";
+            }
+            echo "$journal->week</TD>";
+            echo "<TD BGCOLOR=\"$THEME->cellcontent\">";
+            echo "<P><A HREF=\"$CFG->wwwroot/mod/journal/view.php?id=$journal->coursemodule\">$journal->name</A></P>";
+            echo text_to_html($entry->text);
+            if ($entry->teacher) {
+                echo "\n<BR CLEAR=ALL><TABLE><TR>";
+                echo "<TD WIDTH=35 VALIGN=TOP>";
+                print_user_picture($entry->teacher, $course->id, $teachers[$entry->teacher]->picture);
+                echo "<TD BGCOLOR=\"$THEME->cellheading\">".$RATING[$entry->rating];
+                if ($entry->timemarked) {
+                    echo "&nbsp;&nbsp;<FONT SIZE=1>".moodledate($entry->timemarked)."</FONT>";
+                }
+                echo "<BR><FONT COLOR=#000055>";
+                echo text_to_html($entry->comment);
+                echo "</FONT><BR>";
+                echo "</TD></TR></TABLE>";
+            }
+            echo "</TD></TR>";
+        }
+    }
+    echo "</TABLE>";
+?>
+
diff --git a/mod/journal/view.php b/mod/journal/view.php
new file mode 100644 (file)
index 0000000..75d603a
--- /dev/null
@@ -0,0 +1,141 @@
+<?PHP  // $Id$
+
+    require("../../config.php");
+    require("lib.php");
+
+    require_variable($id);    // Course Module ID
+
+    if (! $cm = get_record("course_modules", "id", $id)) {
+        error("Course Module ID was incorrect");
+    }
+
+    if (! $course = get_record("course", "id", $cm->course)) {
+        error("Course is misconfigured");
+    }
+
+    require_login($course->id);
+
+
+    if (! $journal = get_record("journal", "id", $cm->instance)) {
+        error("Course module is incorrect");
+    }
+
+    add_to_log("View journal: $journal->name", $course->id);
+
+    if (! $cw = get_record("course_weeks", "id", $cm->week)) {
+        error("Course module is incorrect");
+    }
+
+    print_header("$course->shortname: $journal->name", "$course->fullname",
+                 "<A HREF=../../course/view.php?id=$course->id>$course->shortname</A> -> 
+                  <A HREF=index.php?id=$course->id>Journals</A> -> $journal->name", "");
+
+    if ($USER->editing) {
+        print_update_module_icon($cm->id);
+    }
+
+    if (isteacher($course->id)) {
+        echo "<P align=right><A HREF=\"report.php?id=$cm->id\">View all responses</A></P>";
+    }
+
+    echo "<CENTER>\n";
+    
+    print_simple_box( text_to_html($journal->intro) , "center");
+
+    echo "<BR>";
+
+    $timenow = time();
+    $timestart = $course->startdate + (($cw->week - 1) * 608400);
+    if ($journal->days) {
+        $timefinish = $timestart + (3600 * 24 * $journal->days);
+    } else {
+        $timefinish = $course->enddate;
+    }
+
+    if ($timenow > $timestart) {
+
+
+        print_simple_box_start("center");
+
+        if ($timenow < $timefinish) {
+            $options = array ("id" => "$cm->id");
+            echo "<CENTER>";
+            print_single_button("edit.php", $options, "Start or edit my journal entry");
+            echo "</CENTER>";
+        }
+
+        if ($entry = get_record_sql("SELECT * FROM journal_entries 
+                                     WHERE user='$USER->id' AND journal='$journal->id'")) {
+
+            if (empty($entry->text)) {
+                echo "<P ALIGN=center><B>Blank entry</B></P>";
+            } else {
+                echo text_to_html($entry->text);
+            }
+            
+        } else {
+            echo "<B><I>You have not started this journal yet.</I></B>";
+        }
+
+        print_simple_box_end();
+
+        if ($timenow < $timefinish) {
+            if ($entry->modified) {
+                echo "<P><FONT SIZE=-2><B>Last edited:</B> ";
+                echo journaldate($entry->modified)."</FONT></P>";
+            }
+            if ($journal->days) {
+                echo "<P><FONT SIZE=-2><B>Editing period ends:</B> ";
+                echo journaldate($timefinish)."</FONT></P>";
+            }
+        } else {
+            echo "<P><FONT SIZE=-2><B>Editing period has ended:</B> ";
+            echo journaldate($timefinish)."</P>";
+        }
+
+        if ($entry->comment || $entry->rating) {
+            print_heading("Feedback");
+            print_feedback($course, $entry);
+        }
+
+
+    } else {
+        echo "<P><B>This journal won't be open until: ";
+        echo journaldate($timestart)."</B></P>";
+    }
+
+    print_footer($course);
+
+// Functions
+
+function print_feedback($course, $entry) {
+    global $CFG, $THEME, $RATING;
+
+    if (! $teacher = get_record("user", "id", $entry->teacher)) {
+        error("Weird journal error");
+    }
+
+    echo "\n<TABLE BORDER=1 CELLSPACING=0 valign=top cellpadding=10>";
+
+    echo "\n<TR>";
+    echo "\n<TD ROWSPAN=3 BGCOLOR=\"$THEME->body\" WIDTH=35 VALIGN=TOP>";
+    print_user_picture($teacher->id, $course->id, $teacher->picture);
+    echo "</TD>";
+    echo "<TD NOWRAP WIDTH=100% BGCOLOR=\"$THEME->cellheading\">$teacher->firstname $teacher->lastname";
+    echo "&nbsp;&nbsp;<FONT SIZE=2><I>".journaldate($entry->timemarked)."</I>";
+    echo "</TR>";
+
+    echo "\n<TR><TD WIDTH=100% BGCOLOR=\"$THEME->cellcontent\">";
+    echo "<P>Overall: ";
+    if ($RATING[$entry->rating]) {
+        echo $RATING[$entry->rating];
+    } else {
+        echo "Error";
+    }
+    echo "</P>";
+    echo text_to_html($entry->comment);
+    echo "</TD></TR></TABLE>";
+
+}
+
+?>
diff --git a/mod/survey/details.php b/mod/survey/details.php
new file mode 100644 (file)
index 0000000..189d796
--- /dev/null
@@ -0,0 +1,63 @@
+<?PHP // $Id$
+
+    require("../../config.php");
+
+    if (match_referer("$destination") && isset($HTTP_POST_VARS)) {    // form submitted
+        $form = (object)$HTTP_POST_VARS;
+
+        if (! $course = get_record("course", "id", $form->course)) {
+            error("This course doesn't exist");
+        }
+
+        require_login($course->id);
+
+        if (!isteacher($course->id)) {
+            error("You can't modify this course!");
+        }
+
+        print_header("$course->shortname: Editing a survey", "$course->shortname: Editing a survey",
+                      "<A HREF=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</A> -> 
+                      Editing a survey", "");
+
+        print_simple_box_start("center", "", "$THEME->cellheading");
+        ?>
+        <FORM NAME=form METHOD=post ACTION="<? p($form->destination)?>">
+        <TABLE CELLPADDING=5 ALIGN=CENTER>
+        <TR><TD ALIGN=right NOWRAP><P><B>Name:</B></P></TD>
+            <TD><P><? p($form->name) ?></P></A></TD></TR>
+
+        <TR VALIGN=top>
+            <TD ALIGN=right NOWRAP>
+                <P><B>Introduction Text:</B></P>
+            </TD>
+            <TD>
+                <TEXTAREA NAME="intro" ROWS=20 COLS=50 WRAP="virtual"><? 
+                if ($form->intro) {
+                    p($form->intro);
+                } else {
+                    p(get_field("survey", "intro", "id", $form->template));
+                }
+                ?></TEXTAREA>
+            </TD>
+        </TR>
+        </TABLE>
+        <input type="hidden" name=name       value="<? p($form->name) ?>">
+        <input type="hidden" name=template   value="<? p($form->template) ?>">
+
+        <input type="hidden" name=course     value="<? p($form->course) ?>">
+        <input type="hidden" name=week       value="<? p($form->week) ?>">
+        <input type="hidden" name=module     value="<? p($form->module) ?>">
+        <input type="hidden" name=modulename value="<? p($form->modulename) ?>">
+        <input type="hidden" name=instance   value="<? p($form->instance) ?>">
+        <input type="hidden" name=mode       value="<? p($form->mode) ?>">
+        <CENTER>
+        <input type="submit" value="Save these settings">
+        </CENTER>
+        </FORM>
+        <?
+        print_simple_box_end();
+        print_footer($course);
+
+     }
+
+?>
diff --git a/mod/survey/download.php b/mod/survey/download.php
new file mode 100644 (file)
index 0000000..83fc256
--- /dev/null
@@ -0,0 +1,214 @@
+<?PHP // $Id$
+
+    require ("../../config.php");
+
+// Check that all the parameters have been provided.
+
+    require_variable($id);    // Course Module ID
+    optional_variable($type, "xls");
+
+    if (! $cm = get_record("course_modules", "id", $id)) {
+        error("Course Module ID was incorrect");
+    }
+
+    if (! $course = get_record("course", "id", $cm->course)) {
+        error("Course is misconfigured");
+    }
+
+    require_login($course->id);
+
+    if (!isteacher($course->id)) {
+        error("Sorry, only teachers can see this.");
+    }
+
+    if (! $survey = get_record("survey", "id", $cm->instance)) {
+        error("Survey ID was incorrect");
+    }
+
+    add_to_log("Downloaded report as $type:  $survey->name", $course->id);
+
+
+// Get all the questions and their proper order
+
+    $questions = get_records_sql("SELECT * FROM survey_questions WHERE id in ($survey->questions)");
+    $order = explode(",", $survey->questions);
+
+    foreach ($order as $key => $qid) {  // Do we have virtual scales?
+        $question = $questions[$qid];
+        if ($question->type < 0) { 
+            $virtualscales = true;
+            break;
+        }
+    }
+
+    $fullorderlist = "";
+    foreach ($order as $key => $qid) {    // build up list of actual questions
+        $question = $questions[$qid];
+
+        if (!(empty($fullorderlist))) {
+            $fullorderlist .= ",";
+        }
+
+        if ($question->multi) {
+            $addlist = $question->multi;
+        } else {
+            $addlist = $qid;
+        }
+        
+        if ($virtualscales && ($question->type < 0)) {        // only use them
+            $fullorderlist .= $addlist;
+
+        } else if (!$virtualscales && ($question->type >= 0)){   // ignore them
+            $fullorderlist .= $addlist;
+        }
+    }
+
+    $fullquestions = get_records_sql("SELECT * FROM survey_questions WHERE id in ($fullorderlist)");
+
+//  Question type of multi-questions overrides the type of single questions
+    foreach ($order as $key => $qid) {
+        $question = $questions[$qid];
+
+        if ($question->multi) {
+            $subs = explode(",", $question->multi);
+            while (list ($skey, $sqid) = each ($subs)) {
+                $fullquestions["$sqid"]->type = $question->type;
+            }
+        }
+    }
+
+    $order     = explode(",", $fullorderlist);
+    $questions = $fullquestions;
+
+
+// Get and collate all the results in one big array
+
+    if (! $aaa = get_records("survey_answers", "survey", "$survey->id", "time ASC")) {
+        error("There are no answers for this survey yet.");
+    }
+   
+    foreach ($aaa as $a) {
+        if (!$results["$a->user"]) { // init new array
+            $results["$a->user"]["time"] = $a->time;
+            foreach ($order as $key => $qid) {
+                $results["$a->user"]["$qid"]["answer1"] = "";
+                $results["$a->user"]["$qid"]["answer2"] = "";
+            }
+        }
+        $results["$a->user"]["$a->question"]["answer1"] = $a->answer1;
+        $results["$a->user"]["$a->question"]["answer2"] = $a->answer2;
+    }
+
+
+// Output the file as a valid Excel spreadsheet if required
+
+    if ($type == "xls") {
+        include( "$CFG->libdir/psxlsgen.php" );
+
+
+        $myxls = new PhpSimpleXlsGen();
+        $myxls->totalcol = count($order) + 100;
+        $header = array("surveyid","surveyname","userid","firstname","lastname","email","idnumber","time", "notes");
+        $myxls->ChangePos(0,0);
+        foreach ($header as $item) {
+            $myxls->InsertText($item);
+        }
+        foreach ($order as $key => $qid) {
+            $question = $questions["$qid"];
+            if ($question->type == "0" || $question->type == "1" || $question->type == "3")  {
+                $myxls->InsertText("$question->text");
+            }
+            if ($question->type == "2" || $question->type == "3")  {
+                $myxls->InsertText("$question->text (preferred)");
+            }
+        }
+
+        $i = 0;
+        foreach ($results as $user => $rest) {
+            $i++;
+            $myxls->ChangePos($i,0);
+            if (! $u = get_record("user", "id", $user)) {
+                error("Error finding student # $user");
+            }
+            if ($n = get_record_sql("SELECT * FROM survey_analysis WHERE survey='$survey->id' AND user='$user'")) {
+                $notes = $n->notes;
+            } else {
+                $notes = "No notes made";
+            }
+            $myxls->InsertText($survey->id);
+            $myxls->InsertText($survey->name);
+            $myxls->InsertText($user);
+            $myxls->InsertText($u->firstname);
+            $myxls->InsertText($u->lastname);
+            $myxls->InsertText($u->email);
+            $myxls->InsertText($u->idnumber);
+            $myxls->InsertText( date("d-M-Y h:i:s A", $results["$user"]["time"]) );
+            $myxls->InsertText($notes);
+    
+            foreach ($order as $key => $qid) {
+                $question = $questions["$qid"];
+                if ($question->type == "0" || $question->type == "1" || $question->type == "3")  {
+                    $myxls->InsertText( $results["$user"]["$qid"]["answer1"] );
+                }
+                if ($question->type == "2" || $question->type == "3")  {
+                    $myxls->InsertText( $results["$user"]["$qid"]["answer2"] );
+                }
+            }
+        }
+        $myxls->SendFile("surveyreport");
+
+        exit;
+    }
+
+// Otherwise, return the text file.
+
+// Print header to force download
+
+    header("Content-Type: application/download\n"); 
+    header("Content-Disposition: attachment; filename=\"$survey->name results.txt\"");
+
+// Print names of all the fields
+
+    echo "surveyid    surveyname    userid    firstname    lastname    email    idnumber    time    ";
+    foreach ($order as $key => $qid) {
+        $question = $questions["$qid"];
+        if ($question->type == "0" || $question->type == "1" || $question->type == "3")  {
+            echo "$question->text    ";
+        }
+        if ($question->type == "2" || $question->type == "3")  {
+             echo "$question->text (preferred)    ";
+        }
+    }
+    echo "\n";
+
+// Print all the lines of data.
+
+    foreach ($results as $user => $rest) {
+        if (! $u = get_record_sql("SELECT firstname,lastname,email,idnumber FROM user WHERE id = '$user'")) {
+            error("Error finding student # $user");
+        }
+        echo $survey->id."    ";
+        echo $survey->name."    ";
+        echo $user."    ";
+        echo $u->firstname."    ";
+        echo $u->lastname."    ";
+        echo $u->email."    ";
+        echo $u->idnumber."    ";
+        echo date("d-M-Y h:i:s A", $results["$user"]["time"])."    ";
+
+        foreach ($order as $key => $qid) {
+            $question = $questions["$qid"];
+            if ($question->type == "0" || $question->type == "1" || $question->type == "3")  {
+                echo $results["$user"]["$qid"]["answer1"]."    ";
+            }
+            if ($question->type == "2" || $question->type == "3")  {
+                echo $results["$user"]["$qid"]["answer2"]."    ";
+            }
+        }
+        echo "\n";
+    }
+    exit;
+
+
+?>
+
diff --git a/mod/survey/edit.php b/mod/survey/edit.php
new file mode 100644 (file)
index 0000000..40e97d3
--- /dev/null
@@ -0,0 +1,288 @@
+<?PHP // $Id$
+       require("../../config.php");
+       require("surveylib.php");
+
+       require_login();
+
+       print_header("Edit my surveys", "Edit my surveys", "Edit my surveys", "");
+
+       if ($edit == "new") {
+               include("edit_new.phtml");
+               print_footer($course);
+               die;
+       } 
+
+       if ($edit == "release") {
+               release_survey($id);
+               add_to_log("Survey released: $id");
+               unset($edit);
+       }
+
+       if ($edit == "update") {
+               if (match_referer() && isset($HTTP_POST_VARS)) {
+                       $survey = (object)$HTTP_POST_VARS;
+                       validate_form($survey, $err);
+                       if (count($err) == 0) {
+                               update_survey($survey);
+                               notify("The survey \"$survey->name\" was updated.");
+                               add_to_log("Survey update: $survey->name");
+                               unset($edit);
+                       }
+               } else {
+                       notify("Error: This page was called wrongly.");
+               }
+       }
+
+       if ($edit == "delete") {
+               if ($id) {
+
+                       if (get_responses_for_survey($id) > 0) {
+                               notify("Could not delete survey as it has responses");
+
+                       } else if ($ss = $db->Execute("DELETE FROM surveys WHERE owner = $USER->id AND id = $id")) {
+                               notify("The survey was deleted.");
+                               add_to_log("Survey deleted: $id");
+
+                       } else {
+                               notify("Serious error: could not find any templates.");
+                       }
+
+               } else {
+                       notify("Serious error: could not find any templates.");
+               }
+               unset($edit);
+       } 
+
+
+       if ($edit == "add") {
+               if ($template) {
+                       if ($tt = $db->Execute("SELECT * FROM surveys WHERE id = $template")) {
+                               $survey = (object)$tt->fields;
+                               $survey->owner = $USER->id;
+                $survey->name = "";
+                               $survey->template = $template;
+                               add_survey($survey);
+                               add_to_log("Survey added: $survey->name");
+                       } else {
+                               notify("Serious error: could not find template $template");
+                       }
+               } else {
+                       unset($edit);
+               }
+       }
+
+       if ($edit == "edit") {
+               if ($id) {
+                       $survey = get_survey($id);
+               } else {
+                       notify("Error: script called badly.");
+                       die;
+               }
+       }
+       
+       if ($edit) {
+           $survey->status = get_survey_status($survey);
+               include("edit_form.phtml");
+
+       } else {
+        clean_up_surveys();
+           print_list_of_my_surveys();
+        print_additional_commands();
+       }
+       print_footer($course);
+
+
+
+
+/// FUNCTIONS //////////////////
+
+function print_additional_commands() {
+    echo "<HR><P ALIGN=center><A HREF=\"edit.php?edit=new\">Add a new survey</A></P>";
+}
+
+function validate_form(&$survey, &$err) {
+
+       if (empty($survey->id)) {
+               notify("A serious error occurred.");
+               die;
+       }
+
+       if (empty($survey->name))
+               $err["name"] = "Missing name";
+
+       if (empty($survey->password))
+               $err["password"] = "Missing password";
+
+       else if ($survey->password == "changeme")
+               $err["password"] = "You should change this password";
+
+    settype($survey->days, "integer");
+
+       if ($survey->days < 0 || $survey->days > 365)
+               $err["days"] = "Must be a number between 0 and 365";
+
+
+}
+
+function add_survey(&$survey) {
+
+       global $db, $USER;
+
+       $timenow = time();
+
+       $survey->intro = addslashes($survey->intro);     // to make sure
+
+       $rs = $db->Execute("INSERT INTO surveys SET
+                                               timecreated = $timenow,
+                                               timemodified = $timenow,
+                                               template  = '$survey->template',
+                                               course    = '$survey->course', 
+                                               owner     = '$survey->owner', 
+                                               name      = '$survey->name', 
+                                               password  = '$survey->password',
+                                               intro     = '$survey->intro', 
+                                               url       = '$survey->url', 
+                                               questions = '$survey->questions' ");
+        
+       if (!$rs) {
+               notify("Could not insert a record");
+               die;
+       }
+
+//  Now get it out again (most compatible way to get the id)
+
+       $rs = $db->Execute("SELECT * FROM surveys WHERE owner = $survey->owner AND timecreated = $timenow");
+       if ($rs) {
+               $survey = (object) $rs->fields;
+               $survey->intro = stripslashes($survey->intro);
+       } else {
+               notify("Error: Could not find the record I just inserted!");
+               die;
+       }
+}
+
+function release_survey($id) {
+
+       global $db;
+
+       if ($ss = $db->Execute("SELECT * FROM surveys WHERE id = $id")) {
+               $survey = (object)$ss->fields;
+       } else {
+               notify("Serious error: could not find survey $id");
+               die;
+       }
+
+       $timenow = time();
+       $timeend = $timenow + ($survey->days * 86400);
+
+       if ($ss = $db->Execute("UPDATE surveys SET locked=1, timeopen = $timenow, timeclose = $timeend 
+                                                                                  WHERE id = $survey->id")) {
+               notify("The survey \"$survey->name\" was released and can no longer be edited.");
+       } else {
+               notify("An error occurred while releasing \"$survey->name\"");
+       }
+}
+
+
+function update_survey($survey) {
+
+       global $db, $USER;
+
+       $timenow = time();
+
+       $rs = $db->Execute("UPDATE surveys SET
+                                                       timemodified = $timenow,
+                                                       name      = '$survey->name', 
+                                                       password  = '$survey->password',
+                                                       intro     = '$survey->intro', 
+                                                       url       = '$survey->url',
+                                                       days      =  $survey->days
+                                               WHERE
+                                                       id        =  $survey->id AND
+                                                       owner     =  $USER->id ");
+        
+       if ($rs) {
+               return true;
+       } else {
+               notify("Could not update the survey!");
+               die;
+       }
+}
+
+function get_survey($id) {
+       global $db, $USER;
+
+       if ($ss = $db->Execute("SELECT * FROM surveys WHERE id = $id AND owner = $USER->id")) {
+               $survey = (object)$ss->fields;
+               $survey->intro = stripslashes($survey->intro);
+               $survey->name = stripslashes($survey->name);
+               $survey->password = stripslashes($survey->password);
+               return $survey;
+       } else {
+               notify("Serious error: could not find specified survey.");
+               die;
+       }
+}
+
+
+function make_survey_menu($chosenid) {
+       global $db;
+
+       $chosenname = get_template_name($chosenid);
+       if ($ss = $db->Execute("SELECT name,id FROM surveys WHERE owner = 0 ORDER BY id")) {
+               print $ss->GetMenu("template", $chosenname, true);
+       } else {
+               notify("Serious error: could not find any templates.");
+       }
+}
+
+function clean_up_surveys() {
+       global $db, $USER;
+
+    if (!$rs = $db->Execute("DELETE FROM surveys WHERE owner = $USER->id AND name = ''")) {
+               notify("Error: could not clean up surveys");
+    }
+}
+
+function print_list_of_my_surveys() {
+       global $db, $USER;
+       
+       if ($rs = $db->Execute("SELECT * FROM surveys WHERE owner = $USER->id ORDER BY id")) {
+               if ($rs->RowCount()) {
+                       echo "<H3 ALIGN=center>Existing surveys</H3>";
+                       echo "<TABLE align=center cellpadding=6>";
+                       echo "<TR><TD><B><P>Survey name<TD><B><P>Survey type<TD><B><P>Details<TD><B><P>Status<TD><B><P></TR>";
+                       while (!$rs->EOF) {
+                               $survey = (object)$rs->fields;
+
+                               $numresponses = get_responses_for_survey($survey->id);
+                               $templatename = get_template_name($survey->template);
+                               $status = get_survey_status($survey);
+
+                               echo "<TR bgcolor=#f0f0f0>";
+                               echo "<TD><P><B><A HREF=\"view.php?id=$survey->id\">$survey->name</A>";
+                               echo "<TD><P>$templatename";
+                               if ($status == "editing") {
+                                       echo "<TD><P><B><A HREF=\"edit.php?edit=edit&id=$survey->id\">Edit</A>";
+                                       echo "<TD><P><B><FONT COLOR=#990000>$status";
+                                       echo "<TD><P><A HREF=\"edit.php?edit=release&id=$survey->id\">Release to students</A>";
+                               } else {
+                                       echo "<TD><P><B><A HREF=\"edit.php?edit=edit&id=$survey->id\">View</A>";
+                                       echo "<TD><P><B><FONT COLOR=#009900>$status";
+                                       echo "<TD><P><A HREF=\"report.php?id=$survey->id\">$numresponses responses</A>";
+                               }
+                               echo "</TR>";
+                               $rs->MoveNext();
+                       }
+                       echo "</TABLE>";
+               } else {
+                       echo "<H3 align=center>You don't have any surveys yet</H3>";
+               }
+       } else {
+               notify("Error: could not list surveys");
+       }
+
+}
+
+?>
diff --git a/mod/survey/edit_form.html b/mod/survey/edit_form.html
new file mode 100644 (file)
index 0000000..00e8afe
--- /dev/null
@@ -0,0 +1,66 @@
+<table align=center cellpadding=20> <tr> <td bgcolor=#f0f0f0>
+
+<form name="form" method="post" action="edit.php">
+<table cellpadding=5>
+<tr valign=top>
+    <td><P><? link_to_popup_window("/mod/survey/docs/surveytype.html", "info", "Survey type") ?>:</td>
+    <td><? print get_template_name($survey->template) ?>
+        <input type="hidden" name=template value="<? pv($survey->template) ?>">
+    </td>
+</tr>
+<tr valign=top>
+    <td><P><? link_to_popup_window("/mod/survey/docs/name.html", "info", "Survey name") ?>:</td>
+    <td><input type="text" name="name" size=40 value="<? pv($survey->name) ?>">
+    <? formerr($err["name"]) ?>
+    </td>
+</tr>
+<tr valign=top>
+    <td><P><? link_to_popup_window("/mod/survey/docs/password.html", "info", "Password") ?>:</td>
+    <td><input type="text" name="password" size=20 value="<? pv($survey->password) ?>">
+    <? formerr($err["password"]) ?>
+    </td>
+</tr>
+<tr valign=top>
+    <td><P><? link_to_popup_window("/mod/survey/docs/days.html", "info", "Available Days") ?>:</td>
+    <td><input type="text" name="days" size=3 value="<? pv($survey->days) ?>">
+    <? formerr($err["days"]) ?>
+    </td>
+</tr>
+<tr valign=top>
+    <td><P><? link_to_popup_window("/mod/survey/docs/url.html", "info", "Course URL") ?>:</td>
+    <td><input type="text" name="url" size=50 value="<? pv($survey->url) ?>">
+    <? formerr($err["url"]) ?>
+    </td>
+</tr>
+<tr valign=top>
+    <td><P><? link_to_popup_window("/mod/survey/docs/intro.html", "info", "Introduction") ?>:</td>
+    <td><textarea name=intro rows=15 cols=50 wrap=virtual><? pv($survey->intro) ?></textarea>
+    </td>
+</tr>
+<tr>
+    <td></td>
+    <td>
+       <table><tr><td valign=top>
+           <input type="hidden" name=id value="<? pv($survey->id) ?>">
+        <input type="hidden" name=edit value="update">
+           <? if ($survey->status == "editing") { ?>
+                  <input type="submit" value="Save changes">
+               <? } ?>
+               </FORM>
+               <td valign=top>
+           <? if (get_responses_for_survey($survey->id) == 0) { ?>
+               <FORM name="delete" method="post" action="edit.php">
+       <input type="hidden" name=id value="<? pv($survey->id) ?>">
+        <input type="hidden" name=edit value="delete">
+               <input type="submit" value="Delete this survey">
+               </FORM>
+               <? } ?>
+               <td valign=top>
+               <FORM name="cancel" method="post" action="edit.php">
+               <input type="submit" value="Cancel">
+               </FORM>
+       </td></tr></table>
+</table>
+
+</td></tr></table>
+
diff --git a/mod/survey/edit_form.phtml b/mod/survey/edit_form.phtml
new file mode 100644 (file)
index 0000000..a0e5ebc
--- /dev/null
@@ -0,0 +1,70 @@
+<table align=center cellpadding=20> <tr> <td bgcolor=#f0f0f0>
+
+<form name="form" method="post" action="edit.php">
+<table cellpadding=5>
+<tr valign=top>
+    <td><P><FONT SIZE=-3>(Click on the links below<BR>for help on each field)</FONT></P></td>
+    <td>&nbsp;</td>
+</tr>
+<tr valign=top>
+    <td><P>Survey type:</td>
+    <td><? print get_template_name($survey->template) ?>
+        <input type="hidden" name=template value="<? pv($survey->template) ?>">
+    </td>
+</tr>
+<tr valign=top>
+    <td><P><? link_to_popup_window("/mod/survey/docs/name.phtml", "info", "Survey name") ?>:</td>
+    <td><input type="text" name="name" size=40 value="<? pv($survey->name) ?>">
+    <? formerr($err["name"]) ?>
+    </td>
+</tr>
+<tr valign=top>
+    <td><P><? link_to_popup_window("/mod/survey/docs/password.phtml", "info", "Password") ?>:</td>
+    <td><input type="text" name="password" size=20 value="<? pv($survey->password) ?>">
+    <? formerr($err["password"]) ?>
+    </td>
+</tr>
+<tr valign=top>
+    <td><P><? link_to_popup_window("/mod/survey/docs/days.phtml", "info", "Available Days") ?>:</td>
+    <td><input type="text" name="days" size=3 value="<? pv($survey->days) ?>">
+    <? formerr($err["days"]) ?>
+    </td>
+</tr>
+<tr valign=top>
+    <td><P><? link_to_popup_window("/mod/survey/docs/url.phtml", "info", "Course URL") ?>:</td>
+    <td><input type="text" name="url" size=50 value="<? pv($survey->url) ?>">
+    <? formerr($err["url"]) ?>
+    </td>
+</tr>
+<tr valign=top>
+    <td><P><? link_to_popup_window("/mod/survey/docs/intro.phtml", "info", "Introduction") ?>:</td>
+    <td><textarea name=intro rows=15 cols=50 wrap=hard><? pv($survey->intro) ?></textarea>
+    </td>
+</tr>
+<tr>
+    <td></td>
+    <td>
+       <table><tr><td valign=top>
+           <input type="hidden" name=id value="<? pv($survey->id) ?>">
+        <input type="hidden" name=edit value="update">
+           <? if ($survey->status == "editing") { ?>
+                  <input type="submit" value="Save changes">
+               <? } ?>
+               </FORM>
+               <td valign=top>
+           <? if (get_responses_for_survey($survey->id) == 0) { ?>
+               <FORM name="delete" method="post" action="edit.php">
+       <input type="hidden" name=id value="<? pv($survey->id) ?>">
+        <input type="hidden" name=edit value="delete">
+               <input type="submit" value="Delete this survey">
+               </FORM>
+               <? } ?>
+               <td valign=top>
+               <FORM name="cancel" method="post" action="edit.php">
+               <input type="submit" value="Cancel">
+               </FORM>
+       </td></tr></table>
+</table>
+
+</td></tr></table>
+
diff --git a/mod/survey/edit_new.html b/mod/survey/edit_new.html
new file mode 100644 (file)
index 0000000..ff37e05
--- /dev/null
@@ -0,0 +1,14 @@
+<CENTER>
+<H3>Choose a template for your new survey</H3>
+
+<P><? link_to_popup_window("/mod/survey/docs/surveytype.html", "info", "About the different survey types") ?></P>
+
+<FORM METHOD=post ACTION=edit.php>
+<INPUT TYPE=hidden NAME=edit VALUE=add>
+<? make_survey_menu("") ?>
+
+<INPUT TYPE=submit VALUE=OK>
+<P>
+
+</FORM>
+</CENTER>
diff --git a/mod/survey/edit_new.phtml b/mod/survey/edit_new.phtml
new file mode 100644 (file)
index 0000000..9d86be8
--- /dev/null
@@ -0,0 +1,14 @@
+<CENTER>
+<H3>Choose a template for your new survey</H3>
+
+<P><? link_to_popup_window("/surveys/", "info", "About the different survey types") ?></P>
+
+<FORM METHOD=post ACTION=edit.php>
+<INPUT TYPE=hidden NAME=edit VALUE=add>
+<? make_survey_menu("") ?>
+
+<INPUT TYPE=submit VALUE=OK>
+<P>
+
+</FORM>
+</CENTER>
diff --git a/mod/survey/graph.php b/mod/survey/graph.php
new file mode 100644 (file)
index 0000000..1f41e97
--- /dev/null
@@ -0,0 +1,620 @@
+<?PHP // $Id$
+
+    require("../../config.php");
+    require("$CFG->libdir/graphlib.php");
+    require("lib.php");
+
+    require_variable($id);    // Course Module ID
+
+    if (! $cm = get_record("course_modules", "id", $id)) {
+        error("Course Module ID was incorrect");
+    }
+
+    if (! $course = get_record("course", "id", $cm->course)) {
+        error("Course is misconfigured");
+    }
+
+    require_login($course->id);
+
+    if (!isteacher($course->id)) {
+        error("Sorry, only teachers can see this.");
+    }
+
+    if (! $survey = get_record("survey", "id", $cm->instance)) {
+        error("Survey ID was incorrect");
+    }
+
+    switch ($type) {
+
+     case "question.png":
+
+       $question = get_record("survey_questions", "id", $qid);
+  
+       $options = explode(",",$question->options);
+
+       while (list($key,) = each($options)) {
+           $buckets1[$key] = 0;
+           $buckets2[$key] = 0;
+       }
+
+       $aa = $db->Execute("SELECT * FROM survey_answers WHERE survey = $cm->instance AND question = $qid");
+
+       while (!$aa->EOF) {
+           if ($a1 = $aa->fields["answer1"]) {
+               $buckets1[$a1 - 1]++;
+           }
+           if ($a2 = $aa->fields["answer2"]) {
+               $buckets2[$a2 - 1]++;
+           }
+           $aa->MoveNext();
+       }
+       
+       $maxbuckets1 = max($buckets1);
+       $maxbuckets2 = max($buckets2);
+       $maxbuckets = ($maxbuckets1 > $maxbuckets2) ? $maxbuckets1 : $maxbuckets2;
+
+       $graph = new graph($GWIDTH,$GHEIGHT);
+       $graph->parameter['title'] = "$question->text";
+
+       $graph->x_data               = $options;
+
+       $graph->y_data['answers1']   = $buckets1;
+       $graph->y_format['answers1'] = array('colour' => 'blue','bar' => 'fill','legend' =>'actual','bar_size' => 0.4);
+       $graph->y_data['answers2']   = $buckets2;
+       $graph->y_format['answers2'] = array('colour'=>'green','bar' => 'fill','legend' =>'preferred','bar_size' => 0.2);
+
+       $graph->parameter['legend']        = 'outside-top';
+       $graph->parameter['legend_border'] = 'black';
+       $graph->parameter['legend_offset'] = 4;
+
+       if (($maxbuckets1 > 0.0) && ($maxbuckets2 > 0.0)) {
+           $graph->y_order = array('answers1', 'answers2');
+       } else if ($maxbuckets1 > 0.0) {
+           $graph->y_order = array('answers1');
+       } else {
+           $graph->y_order = array('answers2');
+       }
+       
+       $graph->parameter['y_axis_gridlines']= $maxbuckets + 1;
+       $graph->parameter['y_resolution_left']= 1;
+       $graph->parameter['y_decimal_left']  = 0;
+       $graph->parameter['x_axis_angle']    = 0;
+       $graph->parameter['shadow']          = 'none';
+
+       $graph->draw_stack();
+
+       break;
+
+
+
+     case "multiquestion.png":
+
+       $question  = get_record("survey_questions", "id", $qid);
+
+       $options = explode(",",$question->options);
+       $questionorder = explode( ",", $question->multi);
+
+       $qqq = get_records_sql("SELECT * FROM survey_questions WHERE id in ($question->multi)");
+
+       foreach ($questionorder as $i => $val) {
+           $names[$i] = shorten_name($qqq["$val"]->text, 4);
+           $buckets1[$i] = 0;
+           $buckets2[$i] = 0;
+           $count1[$i] = 0;
+           $count2[$i] = 0;
+           $indexof[$val] = $i;
+       }
+
+       $aaa = get_records_sql("SELECT * FROM survey_answers WHERE ((survey = $cm->instance) AND (question in ($question->multi)))");
+
+       foreach ($aaa as $a) {
+           $index = $indexof[$a->question];
+           if ($a->answer1) {
+               $buckets1[$index] += $a->answer1;
+               $count1[$index]++;
+           }
+           if ($a->answer2) {
+               $buckets2[$index] += $a->answer2;
+               $count2[$index]++;
+           }
+       }
+
+       foreach ($questionorder as $i => $val) {
+           if ($count1[$i]) {
+               $buckets1[$i] = (float)$buckets1[$i] / (float)$count1[$i];
+           }
+           if ($count2[$i]) {
+               $buckets2[$i] = (float)$buckets2[$i] / (float)$count2[$i];
+           }
+       }
+
+       foreach ($aaa as $a) {
+           $index = $indexof[$a->question];
+           if ($a->answer1) {
+               $difference = (float) ($a->answer1 - $buckets1[$index]);
+               $stdev1[$index] += ($difference * $difference);
+           }
+           if ($a->answer2) {
+               $difference = (float) ($a->answer2 - $buckets2[$index]);
+               $stdev2[$index] += ($difference * $difference);
+           }
+       }
+
+       foreach ($questionorder as $i => $val) {
+           if ($count1[$i]) {
+               $stdev1[$i] = sqrt( (float)$stdev1[$i] / ((float)$count1[$i]));
+           }
+           if ($count2[$i]) {
+               $stdev2[$i] = sqrt( (float)$stdev2[$i] / ((float)$count2[$i]));
+           }
+       }
+
+       
+
+       $maxbuckets1 = max($buckets1);
+       $maxbuckets2 = max($buckets2);
+
+
+       $graph = new graph($GWIDTH,$GHEIGHT);
+       $graph->parameter['title'] = "$question->text";
+
+       $graph->x_data               = $names;
+       $graph->y_data['answers1']   = $buckets1;
+       $graph->y_format['answers1'] = array('colour' => 'ltblue', 'line' => 'line',  'point' => 'square', 
+                                            'shadow_offset' => 4, 'legend' => 'actual');
+       $graph->y_data['answers2']   = $buckets2;
+       $graph->y_format['answers2'] = array('colour' => 'ltgreen', 'line' => 'line', 'point' => 'square', 
+                                                'shadow_offset' => 4, 'legend' => 'preferred');
+       $graph->y_data['stdev1']   = $stdev1;
+       $graph->y_format['stdev1'] = array('colour' => 'ltltblue', 'bar' => 'fill', 
+                                            'shadow_offset' => '4', 'legend' => 'none');
+       $graph->y_data['stdev2']   = $stdev2;
+       $graph->y_format['stdev2'] = array('colour' => 'ltltgreen', 'bar' => 'fill', 
+                                            'shadow_offset' => '4', 'legend' => 'none');
+       $graph->offset_relation['stdev1'] = 'answers1';
+       $graph->offset_relation['stdev2'] = 'answers2';
+
+       $graph->parameter['bar_size']    = 0.15;
+
+       $graph->parameter['legend']        = 'outside-top';
+       $graph->parameter['legend_border'] = 'black';
+       $graph->parameter['legend_offset'] = 4;
+
+       if (($maxbuckets1 > 0.0) && ($maxbuckets2 > 0.0)) {
+              $graph->y_order = array('stdev1', 'answers1', 'stdev2', 'answers2');
+       } else if ($maxbuckets1 > 0.0) {
+           $graph->y_order = array('stdev1', 'answers1');
+       } else {
+           $graph->y_order = array('stdev2', 'answers2');
+       }
+       
+       $graph->parameter['y_max_left']= count($options);
+       $graph->parameter['y_axis_gridlines']= count($options) + 1;
+       $graph->parameter['y_resolution_left']= 1;
+       $graph->parameter['y_decimal_left']= 1;
+       $graph->parameter['x_axis_angle']  = 0;
+
+       $graph->draw();
+
+       break;
+
+
+    
+     case "overall.png":
+
+       $qqq = get_records_sql("SELECT * FROM survey_questions WHERE id in ($survey->questions) AND multi <> ''");
+
+       foreach ($qqq as $qq) {
+           if ($qq->type < 0) {
+               $virtualscales = true;
+           }
+       }
+       foreach ($qqq as $qq) {         // if any virtual, then use JUST virtual, else use JUST nonvirtual
+           if ($virtualscales && $qq->type < 0) {
+               $question[] = $qq;
+           } else if (!$virtualscales && $qq->type > 0) {
+               $question[] = $qq;
+           }
+       }
+       $numquestions = count($question);
+
+       $options = explode(",",$question[0]->options);
+       $numoptions = count($options);
+
+       for ($i=0; $i<$numquestions; $i++) {
+           $names[$i] = $question[$i]->text;
+           $buckets1[$i] = 0.0;
+           $buckets2[$i] = 0.0;
+           $stdev1[$i] = 0.0;
+           $stdev2[$i] = 0.0;
+           $count1[$i] = 0;
+           $count2[$i] = 0;
+           $subquestions = $question[$i]->multi;   // otherwise next line doesn't work
+           $aaa = get_records_sql("SELECT * FROM survey_answers WHERE ((survey = $cm->instance) AND (question in ($subquestions)))");
+
+           foreach ($aaa as $a) {
+               if ($a->answer1) {
+                   $buckets1[$i] += $a->answer1;
+                   $count1[$i]++;
+               }
+               if ($a->answer2) {
+                   $buckets2[$i] += $a->answer2;
+                   $count2[$i]++;
+               }
+           }
+
+           if ($count1[$i]) {
+               $buckets1[$i] = (float)$buckets1[$i] / (float)$count1[$i];
+           }
+           if ($count2[$i]) {
+               $buckets2[$i] = (float)$buckets2[$i] / (float)$count2[$i];
+           }
+
+           // Calculate the standard devaiations
+           foreach ($aaa as $a) {
+               if ($a->answer1) {
+                   $difference = (float) ($a->answer1 - $buckets1[$i]);
+                   $stdev1[$i] += ($difference * $difference);
+               }
+               if ($a->answer2) {
+                   $difference = (float) ($a->answer2 - $buckets2[$i]);
+                   $stdev2[$i] += ($difference * $difference);
+               }
+           }
+
+           if ($count1[$i]) {
+               $stdev1[$i] = sqrt( (float)$stdev1[$i] / ((float)$count1[$i]));
+           }
+           if ($count2[$i]) {
+               $stdev2[$i] = sqrt( (float)$stdev2[$i] / ((float)$count2[$i]));
+           }
+
+           
+       }
+
+       $maxbuckets1 = max($buckets1);
+       $maxbuckets2 = max($buckets2);
+
+
+       $graph = new graph($GWIDTH,$GHEIGHT);
+       $graph->parameter['title'] = "$survey->name";
+
+       $graph->x_data               = $names;
+
+       $graph->y_data['answers1']   = $buckets1;
+       $graph->y_format['answers1'] = array('colour' => 'ltblue', 'line' => 'line',  'point' => 'square', 
+                                            'shadow_offset' => 4, 'legend' => 'actual');
+       $graph->y_data['answers2']   = $buckets2;
+       $graph->y_format['answers2'] = array('colour' => 'ltgreen', 'line' => 'line', 'point' => 'square', 
+                                                'shadow_offset' => 4, 'legend' => 'preferred');
+
+       $graph->y_data['stdev1']   = $stdev1;
+       $graph->y_format['stdev1'] = array('colour' => 'ltltblue', 'bar' => 'fill', 
+                                            'shadow_offset' => '4', 'legend' => 'none');
+       $graph->y_data['stdev2']   = $stdev2;
+       $graph->y_format['stdev2'] = array('colour' => 'ltltgreen', 'bar' => 'fill', 
+                                            'shadow_offset' => '4', 'legend' => 'none');
+       $graph->offset_relation['stdev1'] = 'answers1';
+       $graph->offset_relation['stdev2'] = 'answers2';
+
+       $graph->parameter['bar_size']    = 0.15;
+       $graph->parameter['legend']        = 'outside-top';
+       $graph->parameter['legend_border'] = 'black';
+       $graph->parameter['legend_offset'] = 4;
+
+       if (($maxbuckets1 > 0.0) && ($maxbuckets2 > 0.0)) {
+              $graph->y_order = array('stdev1', 'answers1', 'stdev2', 'answers2');
+       } else if ($maxbuckets1 > 0.0) {
+           $graph->y_order = array('stdev1', 'answers1');
+       } else {
+           $graph->y_order = array('stdev2', 'answers2');
+       }
+       
+       $graph->parameter['y_max_left']= $numoptions;
+       $graph->parameter['y_axis_gridlines']= $numoptions + 1;
+       $graph->parameter['y_resolution_left']= 1;
+       $graph->parameter['y_decimal_left']= 1;
+       $graph->parameter['x_axis_angle']  = 0;
+
+       $graph->draw();
+
+       break;
+
+
+
+     case "student.png":
+
+       $qqq = get_records_sql("SELECT * FROM survey_questions WHERE id in ($survey->questions) AND multi <> ''");
+
+       foreach ($qqq as $qq) {
+           if ($qq->type < 0) {
+               $virtualscales = true;
+           }
+       }
+       foreach ($qqq as $qq) {         // if any virtual, then use JUST virtual, else use JUST nonvirtual
+           if ($virtualscales && $qq->type < 0) {
+               $question[] = $qq;
+           } else if (!$virtualscales && $qq->type > 0) {
+               $question[] = $qq;
+           }
+       }
+       $numquestions= count($question);
+
+       $options = explode(",",$question[0]->options);
+       $numoptions = count($options);
+
+       for ($i=0; $i<$numquestions; $i++) {
+           $names[$i] = $question[$i]->text;
+           $buckets1[$i] = 0.0;
+           $buckets2[$i] = 0.0;
+           $count1[$i] = 0;
+           $count2[$i] = 0;
+           $studbuckets1[$i] = 0.0;
+           $studbuckets2[$i] = 0.0;
+           $studcount1[$i] = 0;
+           $studcount2[$i] = 0;
+           $subquestions = $question[$i]->multi;   // otherwise next line doesn't work
+           $aaa = get_records_sql("SELECT * FROM survey_answers WHERE ((survey = $cm->instance) AND (question in ($subquestions)))");
+
+           foreach ($aaa as $a) {
+               if ($a->user == $sid) {
+                   if ($a->answer1) {
+                       $studbuckets1[$i] += $a->answer1;
+                       $studcount1[$i]++;
+                   }
+                   if ($a->answer2) {
+                       $studbuckets2[$i] += $a->answer2;
+                       $studcount2[$i]++;
+                   }
+               }
+               if ($a->answer1) {
+                   $buckets1[$i] += $a->answer1;
+                   $count1[$i]++;
+               }
+               if ($a->answer2) {
+                   $buckets2[$i] += $a->answer2;
+                   $count2[$i]++;
+               }
+           }
+
+           if ($count1[$i]) {
+               $buckets1[$i] = (float)$buckets1[$i] / (float)$count1[$i];
+           }
+           if ($count2[$i]) {
+               $buckets2[$i] = (float)$buckets2[$i] / (float)$count2[$i];
+           }
+           if ($studcount1[$i]) {
+               $studbuckets1[$i] = (float)$studbuckets1[$i] / (float)$studcount1[$i];
+           }
+           if ($studcount2[$i]) {
+               $studbuckets2[$i] = (float)$studbuckets2[$i] / (float)$studcount2[$i];
+           }
+
+           // Calculate the standard devaiations
+           foreach ($aaa as $a) {
+               if ($a->answer1) {
+                   $difference = (float) ($a->answer1 - $buckets1[$i]);
+                   $stdev1[$i] += ($difference * $difference);
+               }
+               if ($a->answer2) {
+                   $difference = (float) ($a->answer2 - $buckets2[$i]);
+                   $stdev2[$i] += ($difference * $difference);
+               }
+           }
+
+           if ($count1[$i]) {
+               $stdev1[$i] = sqrt( (float)$stdev1[$i] / ((float)$count1[$i]));
+           }
+           if ($count2[$i]) {
+               $stdev2[$i] = sqrt( (float)$stdev2[$i] / ((float)$count2[$i]));
+           }
+
+       }
+
+       $maxbuckets1 = max($buckets1);
+       $maxbuckets2 = max($buckets2);
+
+
+       $graph = new graph($GWIDTH,$GHEIGHT);
+       $graph->parameter['title'] = "$survey->name";
+
+       $graph->x_data               = $names;
+
+       $graph->y_data['answers1']   = $buckets1;
+       $graph->y_format['answers1'] = array('colour' => 'ltblue', 'line' => 'line',  'point' => 'square', 
+                                            'shadow_offset' => 4, 'legend' => 'class actual');
+       $graph->y_data['answers2']   = $buckets2;
+       $graph->y_format['answers2'] = array('colour' => 'ltgreen', 'line' => 'line', 'point' => 'square', 
+                                                'shadow_offset' => 4, 'legend' => 'class preferred');
+       $graph->y_data['studanswers1']   = $studbuckets1;
+       $graph->y_format['studanswers1'] = array('colour' => 'blue', 'line' => 'line',  'point' => 'square', 
+                                            'shadow_offset' => 4, 'legend' => 'student actual');
+       $graph->y_data['studanswers2']   = $studbuckets2;
+       $graph->y_format['studanswers2'] = array('colour' => 'green', 'line' => 'line', 'point' => 'square', 
+                                                'shadow_offset' => 4, 'legend' => 'student preferred');
+       $graph->y_data['stdev1']   = $stdev1;
+       $graph->y_format['stdev1'] = array('colour' => 'ltltblue', 'bar' => 'fill', 
+                                            'shadow_offset' => '4', 'legend' => 'none');
+       $graph->y_data['stdev2']   = $stdev2;
+       $graph->y_format['stdev2'] = array('colour' => 'ltltgreen', 'bar' => 'fill', 
+                                            'shadow_offset' => '4', 'legend' => 'none');
+       $graph->offset_relation['stdev1'] = 'answers1';
+       $graph->offset_relation['stdev2'] = 'answers2';
+
+       $graph->parameter['bar_size']    = 0.15;
+
+       $graph->parameter['legend']        = 'outside-top';
+       $graph->parameter['legend_border'] = 'black';
+       $graph->parameter['legend_offset'] = 4;
+
+       if (($maxbuckets1 > 0.0) && ($maxbuckets2 > 0.0)) {
+              $graph->y_order = array('stdev1', 'answers1', 'stdev2', 'answers2', 'studanswers1', 'studanswers2');
+       } else if ($maxbuckets1 > 0.0) {
+           $graph->y_order = array('stdev1', 'answers1', 'studanswers1');
+       } else {
+           $graph->y_order = array('stdev2', 'answers2', 'studanswers2');
+       }
+       
+       $graph->parameter['y_max_left']= $numoptions;
+       $graph->parameter['y_axis_gridlines']= $numoptions + 1;
+       $graph->parameter['y_resolution_left']= 1;
+       $graph->parameter['y_decimal_left']= 1;
+       $graph->parameter['x_axis_angle']  = 0;
+
+       $graph->draw();
+       break;
+
+
+
+     case "studentmultiquestion.png":
+
+       $question  = get_record("survey_questions", "id", $qid);
+
+       $options = explode(",",$question->options);
+       $questionorder = explode( ",", $question->multi);
+
+       $qqq = get_records_sql("SELECT * FROM survey_questions WHERE id in ($question->multi)");
+
+       foreach ($questionorder as $i => $val) {
+           $names[$i] = shorten_name($qqq["$val"]->text, 4);
+           $buckets1[$i] = 0;
+           $buckets2[$i] = 0;
+           $count1[$i] = 0;
+           $count2[$i] = 0;
+           $indexof[$val] = $i;
+           $studbuckets1[$i] = 0.0;
+           $studbuckets2[$i] = 0.0;
+           $studcount1[$i] = 0;
+           $studcount2[$i] = 0;
+       }
+
+       $aaa = get_records_sql("SELECT * FROM survey_answers WHERE ((survey = $cm->instance) AND (question in ($question->multi)))");
+
+       foreach ($aaa as $a) {
+           $index = $indexof[$a->question];
+               if ($a->user == $sid) {
+                   if ($a->answer1) {
+                       $studbuckets1[$index] += $a->answer1;
+                       $studcount1[$index]++;
+                   }
+                   if ($a->answer2) {
+                       $studbuckets2[$index] += $a->answer2;
+                       $studcount2[$index]++;
+                   }
+               }
+           if ($a->answer1) {
+               $buckets1[$index] += $a->answer1;
+               $count1[$index]++;
+           }
+           if ($a->answer2) {
+               $buckets2[$index] += $a->answer2;
+               $count2[$index]++;
+           }
+       }
+
+       foreach ($questionorder as $i => $val) {
+           if ($count1[$i]) {
+               $buckets1[$i] = (float)$buckets1[$i] / (float)$count1[$i];
+           }
+           if ($count2[$i]) {
+               $buckets2[$i] = (float)$buckets2[$i] / (float)$count2[$i];
+           }
+           if ($studcount1[$i]) {
+               $studbuckets1[$i] = (float)$studbuckets1[$i] / (float)$studcount1[$i];
+           }
+           if ($studcount2[$i]) {
+               $studbuckets2[$i] = (float)$studbuckets2[$i] / (float)$studcount2[$i];
+           }
+       }
+
+       foreach ($aaa as $a) {
+           $index = $indexof[$a->question];
+           if ($a->answer1) {
+               $difference = (float) ($a->answer1 - $buckets1[$index]);
+               $stdev1[$index] += ($difference * $difference);
+           }
+           if ($a->answer2) {
+               $difference = (float) ($a->answer2 - $buckets2[$index]);
+               $stdev2[$index] += ($difference * $difference);
+           }
+       }
+
+       foreach ($questionorder as $i => $val) {
+           if ($count1[$i]) {
+               $stdev1[$i] = sqrt( (float)$stdev1[$i] / ((float)$count1[$i]));
+           }
+           if ($count2[$i]) {
+               $stdev2[$i] = sqrt( (float)$stdev2[$i] / ((float)$count2[$i]));
+           }
+       }
+
+       
+
+       $maxbuckets1 = max($buckets1);
+       $maxbuckets2 = max($buckets2);
+
+
+       $graph = new graph($GWIDTH,$GHEIGHT);
+       $graph->parameter['title'] = "$question->text";
+
+       $graph->x_data               = $names;
+       $graph->y_data['answers1']   = $buckets1;
+       $graph->y_format['answers1'] = array('colour' => 'ltblue', 'line' => 'line',  'point' => 'square', 
+                                            'shadow_offset' => 4, 'legend' => 'class actual');
+       $graph->y_data['answers2']   = $buckets2;
+       $graph->y_format['answers2'] = array('colour' => 'ltgreen', 'line' => 'line', 'point' => 'square', 
+                                                'shadow_offset' => 4, 'legend' => 'class preferred');
+       $graph->y_data['studanswers1']   = $studbuckets1;
+       $graph->y_format['studanswers1'] = array('colour' => 'blue', 'line' => 'line',  'point' => 'square', 
+                                            'shadow_offset' => 4, 'legend' => 'student actual');
+       $graph->y_data['studanswers2']   = $studbuckets2;
+       $graph->y_format['studanswers2'] = array('colour' => 'green', 'line' => 'line', 'point' => 'square', 
+                                                'shadow_offset' => 4, 'legend' => 'student preferred');
+       $graph->y_data['stdev1']   = $stdev1;
+       $graph->y_format['stdev1'] = array('colour' => 'ltltblue', 'bar' => 'fill', 
+                                            'shadow_offset' => '4', 'legend' => 'none');
+       $graph->y_data['stdev2']   = $stdev2;
+       $graph->y_format['stdev2'] = array('colour' => 'ltltgreen', 'bar' => 'fill', 
+                                            'shadow_offset' => '4', 'legend' => 'none');
+       $graph->offset_relation['stdev1'] = 'answers1';
+       $graph->offset_relation['stdev2'] = 'answers2';
+
+       $graph->parameter['bar_size']    = 0.15;
+
+       $graph->parameter['legend']        = 'outside-top';
+       $graph->parameter['legend_border'] = 'black';
+       $graph->parameter['legend_offset'] = 4;
+
+       if (($maxbuckets1 > 0.0) && ($maxbuckets2 > 0.0)) {
+              $graph->y_order = array('stdev1', 'answers1', 'studanswers1', 'stdev2', 'answers2', 'studanswers2');
+       } else if ($maxbuckets1 > 0.0) {
+           $graph->y_order = array('stdev1', 'answers1', 'studanswers1');
+       } else {
+           $graph->y_order = array('stdev2', 'answers2', 'studanswers2');
+       }
+       
+       $graph->parameter['y_max_left']= count($options);
+       $graph->parameter['y_axis_gridlines']= count($options) + 1;
+       $graph->parameter['y_resolution_left']= 1;
+       $graph->parameter['y_decimal_left']= 1;
+       $graph->parameter['x_axis_angle']  = 0;
+
+       $graph->draw();
+
+       break;
+
+     default:
+       break;
+   }
+
+   exit;
+
+function shorten_name ($name, $numwords) {
+    $words = explode(" ", $name);
+    for ($i=0; $i < $numwords; $i++) {
+        $output .= $words[$i]." ";
+    }
+    return $output;
+}
+         
+?>
diff --git a/mod/survey/icon.gif b/mod/survey/icon.gif
new file mode 100755 (executable)
index 0000000..732bd1e
Binary files /dev/null and b/mod/survey/icon.gif differ
diff --git a/mod/survey/icon2.gif b/mod/survey/icon2.gif
new file mode 100644 (file)
index 0000000..cda1916
Binary files /dev/null and b/mod/survey/icon2.gif differ
diff --git a/mod/survey/index.php b/mod/survey/index.php
new file mode 100644 (file)
index 0000000..1f70c70
--- /dev/null
@@ -0,0 +1,40 @@
+<?PHP // $Id$
+
+    require("../../config.php");
+    require("lib.php");
+
+    require_variable($id);   // course
+
+    if (! $course = get_record("course", "id", $id)) {
+        error("Course ID is incorrect");
+    }
+
+    require_login($course->id);
+    add_to_log("View all surveys", $course->id);
+
+    print_header("$course->shortname: Surveys", "$course->fullname",
+                 "<A HREF=../../course/view.php?id=$course->id>$course->shortname</A> -> Surveys", "");
+
+
+    if (! $surveys = get_all_instances_in_course("survey", $course->id, "cw.week ASC")) {
+        notice("There are no surveys.", "../../course/view.php?id=$course->id");
+    }
+    
+    $table->head  = array ("Week", "Name", "Status");
+    $table->align = array ("CENTER", "LEFT", "LEFT");
+
+    foreach ($surveys as $survey) {
+        if (survey_already_done($survey->id, $USER->id)) {
+            $ss = "Done";
+        } else {
+            $ss = "<A HREF=\"view.php?id=$survey->coursemodule\">Not done yet</A>";
+        }
+        $table->data[] = array ("$survey->week", 
+                                "<A HREF=\"view.php?id=$survey->coursemodule\">$survey->name</A>",
+                                "$ss");
+    }
+
+    print_table($table);
+    print_footer($course);
+
+?>
diff --git a/mod/survey/install.sql b/mod/survey/install.sql
new file mode 100755 (executable)
index 0000000..2baf771
--- /dev/null
@@ -0,0 +1,167 @@
+# phpMyAdmin MySQL-Dump\r
+# version 2.2.1\r
+# http://phpwizard.net/phpMyAdmin/\r
+# http://phpmyadmin.sourceforge.net/ (download page)\r
+#\r
+# Host: localhost\r
+# Generation Time: Nov 14, 2001 at 04:39 PM\r
+# Server version: 3.23.36\r
+# PHP Version: 4.0.6\r
+# Database : `moodle`\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `survey`\r
+#\r
+\r
+CREATE TABLE survey (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  course int(10) unsigned NOT NULL default '0',\r
+  template int(10) unsigned NOT NULL default '0',\r
+  days smallint(6) NOT NULL default '0',\r
+  timecreated int(10) unsigned NOT NULL default '0',\r
+  timemodified int(10) unsigned NOT NULL default '0',\r
+  name varchar(255) NOT NULL default '',\r
+  intro text,\r
+  questions varchar(255) default NULL,\r
+  PRIMARY KEY  (id)\r
+) TYPE=MyISAM COMMENT='all surveys';\r
+\r
+#\r
+# Dumping data for table `survey`\r
+#\r
+\r
+INSERT INTO survey VALUES (1, 0, 0, 0, 985017600, 985017600, 'COLLES (Actual)', 'The purpose of this questionnaire is to help us understand how well the online delivery of this unit enabled you to learn. \r\n\r\nEach one of the 24 statements below asks about your experience in this unit.\r\n\r\nThere are no \'right\' or \'wrong\' answers; we are interested only in your opinion. Please be assured that your responses will be treated with a high degree of confidentiality, and will not affect your assessment.\r\n\r\nYour carefully considered responses will help us improve the way this unit is presented online in the future.\r\n\r\nThanks very much.\r\n', '25,26,27,28,29,30,43,44');\r
+INSERT INTO survey VALUES (2, 0, 0, 0, 985017600, 985017600, 'COLLES (Preferred)', 'The purpose of this questionnaire is to help us understand what you value in an online learning experience.\r\n\r\nEach one of the 24 statements below asks about your <B>preferred</B> (ideal) experience in this unit.\r\n\r\nThere are no \'right\' or \'wrong\' answers; we are interested only in your opinion. Please be assured that your responses will be treated with a high degree of confidentiality, and will not affect your assessment.\r\n\r\nYour carefully considered responses will help us improve the way this unit is presented online in the future.\r\n\r\nThanks very much.\r\n', '31,32,33,34,35,36,43,44');\r
+INSERT INTO survey VALUES (3, 0, 0, 0, 985017600, 985017600, 'COLLES (Preferred and Actual)', 'The purpose of this questionnaire is to help us understand how well the online delivery of this unit enabled you to learn. \r\n\r\nEach one of the 24 statements below asks you to compare your <B>preferred</B> (ideal) and <B>actual</B> experience in this unit.\r\n\r\nThere are no \'right\' or \'wrong\' answers; we are interested only in your opinion. Please be assured that your responses will be treated with a high degree of confidentiality, and will not affect your assessment.\r\n\r\nYour carefully considered responses will help us improve the way this unit is presented online in the future.\r\n\r\nThanks very much.\r\n', '37,38,39,40,41,42,43,44');\r
+INSERT INTO survey VALUES (4, 0, 0, 0, 985017600, 985017600, 'ATTLS (20 item version)', 'The purpose of this questionnaire is to help \r\nus evaluate your attitudes towards thinking and learning.\r\n', '65,67,68');\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `survey_analysis`\r
+#\r
+\r
+CREATE TABLE survey_analysis (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  survey int(10) unsigned NOT NULL default '0',\r
+  user int(10) unsigned NOT NULL default '0',\r
+  notes text NOT NULL,\r
+  PRIMARY KEY  (id),\r
+  UNIQUE KEY id (id)\r
+) TYPE=MyISAM;\r
+\r
+#\r
+# Dumping data for table `survey_analysis`\r
+#\r
+\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `survey_answers`\r
+#\r
+\r
+CREATE TABLE survey_answers (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  user int(10) unsigned NOT NULL default '0',\r
+  survey int(10) unsigned NOT NULL default '0',\r
+  question int(10) unsigned NOT NULL default '0',\r
+  time int(10) unsigned default NULL,\r
+  answer1 char(255) default NULL,\r
+  answer2 char(255) default NULL,\r
+  PRIMARY KEY  (id),\r
+  UNIQUE KEY id (id)\r
+) TYPE=MyISAM;\r
+\r
+#\r
+# Dumping data for table `survey_answers`\r
+#\r
+\r
+# --------------------------------------------------------\r
+\r
+#\r
+# Table structure for table `survey_questions`\r
+#\r
+\r
+CREATE TABLE survey_questions (\r
+  id int(10) unsigned NOT NULL auto_increment,\r
+  owner int(10) unsigned NOT NULL default '0',\r
+  text varchar(255) NOT NULL default '',\r
+  multi varchar(100) NOT NULL default '',\r
+  intro varchar(50) default NULL,\r
+  type tinyint(3) NOT NULL default '0',\r
+  options text,\r
+  PRIMARY KEY  (id)\r
+) TYPE=MyISAM;\r
+\r
+#\r
+# Dumping data for table `survey_questions`\r
+#\r
+\r
+INSERT INTO survey_questions VALUES (1, 0, 'my learning focuses on issues that interest me.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (2, 0, 'what I learn is important for my professional practice.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (3, 0, 'I learn how to improve my professional practice.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (4, 0, 'what I learn connects well with my professional practice.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (5, 0, 'I think critically about how I learn.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (6, 0, 'I think critically about my own ideas.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (7, 0, 'I think critically about other students\' ideas.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (8, 0, 'I think critically about ideas in the readings.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (9, 0, 'I explain my ideas to other students.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (10, 0, 'I ask other students to explain their ideas.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (11, 0, 'other students ask me to explain my ideas.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (12, 0, 'other students respond to my ideas.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (13, 0, 'the tutor stimulates my thinking.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (14, 0, 'the tutor encourages me to participate.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (15, 0, 'the tutor models good discourse.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (16, 0, 'the tutor models critical self-reflection.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (17, 0, 'other students encourage my participation.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (18, 0, 'other students praise my contribution.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (19, 0, 'other students value my contribution.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (20, 0, 'other students empathise with my struggle to learn.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (21, 0, 'I make good sense of other students\' messages.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (22, 0, 'other students make good sense of my messages.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (23, 0, 'I make good sense of the tutor\'s messages.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (24, 0, 'the tutor makes good sense of my messages.', '', '', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r\n');\r
+INSERT INTO survey_questions VALUES (25, 0, 'Relevance', '1,2,3,4', 'In this online unit...', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (26, 0, 'Reflective Thinking', '5,6,7,8', 'In this online unit...', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (27, 0, 'Interactivity', '9,10,11,12', 'In this online unit...', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (28, 0, 'Tutor Support', '13,14,15,16', 'In this online unit...', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (29, 0, 'Peer Support', '17,18,19,20', 'In this online unit...', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (30, 0, 'Interpretation', '21,22,23,24', 'In this online unit...', 1, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (31, 0, 'Relevance', '1,2,3,4', 'In this online unit, I prefer that...', 2, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (32, 0, 'Reflective Thinking', '5,6,7,8', 'In this online unit, I prefer that...', 2, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (33, 0, 'Interactivity', '9,10,11,12', 'In this online unit, I prefer that...', 2, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (34, 0, 'Tutor Support', '13,14,15,16', 'In this online unit, I prefer that...', 2, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (35, 0, 'Peer Support', '17,18,19,20', 'In this online unit, I prefer that...', 2, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (36, 0, 'Interpretation', '21,22,23,24', 'In this online unit, I prefer that...', 2, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (37, 0, 'Relevance', '1,2,3,4', 'In this online unit...', 3, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (38, 0, 'Reflective Thinking', '5,6,7,8', 'In this online unit...', 3, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (39, 0, 'Interactivity', '9,10,11,12', 'In this online unit...', 3, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (40, 0, 'Tutor Support', '13,14,15,16', 'In this online unit...', 3, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (41, 0, 'Peer Support', '17,18,19,20', 'In this online unit...', 3, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (42, 0, 'Interpretation', '21,22,23,24', 'In this online unit...', 3, 'Almost Never,Seldom,Sometimes,Often,Almost Always\r');\r
+INSERT INTO survey_questions VALUES (43, 0, 'How long did this survey take you to complete?', '', '', 1, 'under 1 min,1-2 min,2-3 min,3-4 min,4-5-min,5-10 min,more than 10\r');\r
+INSERT INTO survey_questions VALUES (44, 0, 'Do you have any other comments?', '', '', 0, '\r');\r
+INSERT INTO survey_questions VALUES (64, 0, 'I spend time figuring out what\'s "wrong" with things. For example, I\'ll look for something in a literary interpretation that isn\'t argued well enough.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (58, 0, 'I try to point out weaknesses in other people\'s thinking to help them clarify their arguments.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (59, 0, 'I tend to put myself in other people\'s shoes when discussing controversial issues, to see why they think the way they do.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (60, 0, 'One could call my way of analysing things "putting them on trial" because I am careful to consider all the evidence.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (61, 0, 'I value the use of logic and reason over the incorporation of my own concerns when solving problems.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (62, 0, 'I can obtain insight into opinions that differ from mine through empathy.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (63, 0, 'When I encounter people whose opinions seem alien to me, I make a deliberate effort to "extend" myself into that person, to try to see how they could have those opinions.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (56, 0, 'I have certain criteria I use in evaluating arguments.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (57, 0, 'I\'m more likely to try to understand someone else\'s opinion that to try to evaluate it.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (55, 0, 'I try to think with people instead of against them.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (54, 0, 'It\'s important for me to remain as objective as possible when I analyze something.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (53, 0, 'I often find myself arguing with the authors of books that I read, trying to logically figure out why they\'re wrong.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (52, 0, 'I am always interested in knowing why people say and believe the things they do.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (51, 0, 'I find that I can strengthen my own position through arguing with someone who disagrees with me.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (50, 0, 'I enjoy hearing the opinions of people who come from backgrounds different to mine - it helps me to understand how the same things can be seen in such different ways.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (49, 0, 'I feel that the best way for me to achieve my own identity is to interact with a variety of other people.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (48, 0, 'The most important part of my education has been learning to understand people who are very different to me.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (47, 0, 'I like to understand where other people are "coming from", what experiences have led them to feel the way they do.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (45, 0, 'In evaluating what someone says, I focus on the quality of their argument, not on the person who\'s presenting it.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (46, 0, 'I like playing devil\'s advocate - arguing the opposite of what someone is saying.', '', '', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (65, 0, 'Attitudes Towards Thinking and Learning', '45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64', 'In discussion ...', 1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (67, 0, 'Connected Learning', '63,62,59,57,55,49,52,50,48,47', 'Connected knowers...', -1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+INSERT INTO survey_questions VALUES (68, 0, 'Separate Learning', '46,54,45,51,60,53,56,58,61,64', 'Separate knowers...', -1, 'Strongly disagree,Somewhat disagree,Neither agree nor disagree,Somewhat agree,Strongly agree');\r
+\r
diff --git a/mod/survey/lib.php b/mod/survey/lib.php
new file mode 100644 (file)
index 0000000..8320237
--- /dev/null
@@ -0,0 +1,79 @@
+<?PHP // $Id$
+
+// Graph size
+$GHEIGHT = 500;
+$GWIDTH  = 800;
+
+$QTYPE = array (
+        "-3" => "Virtual Actual and Preferred",
+        "-2" => "Virtual Preferred",
+        "-1" => "Virtual Actual",
+         "0" => "Text",
+         "1" => "Actual",
+         "2" => "Preferred",
+         "3" => "Actual and Preferred",
+        );
+
+function survey_already_done($survey, $user) {
+   return record_exists_sql("SELECT * FROM survey_answers WHERE survey='$survey' AND user='$user'");
+}
+
+function get_survey_status($survey) {
+
+    $timenow = time();
+    if ($survey->locked) {
+        if (($survey->timeopen <= $timenow) && ($timenow <= $survey->timeclose)) {
+            return "released";
+        } else if ($survey->timenow >= $survey->timeclose) {
+            return "finished";
+        } else {
+            return "error";
+        }
+    } else {
+        return "editing";
+    }
+
+}
+
+function get_responses_for_survey($surveyid) {
+        global $db;
+
+        if ($aa = $db->Execute("SELECT user FROM survey_answers WHERE survey = $surveyid GROUP BY user")) {
+                if ($aa) {
+                        return $aa->RowCount();
+                } else {
+                        return -1;
+                }
+        } else {
+                return -1;
+        }
+}
+
+
+function get_template_name($templateid) {
+    global $db;
+
+    if ($templateid) {
+        if ($ss = $db->Execute("SELECT name FROM surveys WHERE id = $templateid")) {
+            return $ss->fields["name"];
+        }
+    } else {
+        return "";
+    }
+}
+
+function update_survey_analysis($survey, $user, $notes) {
+    global $db;
+
+    return $db->Execute("UPDATE survey_analysis SET notes='$notes' WHERE survey='$survey' and user='$user'");
+}
+
+function add_survey_analysis($survey, $user, $notes) {
+    global $db;
+
+    return $db->Execute("INSERT INTO survey_analysis SET notes='$notes', survey='$survey', user='$user'");
+}
+
+
+
+?>
diff --git a/mod/survey/login_form.html b/mod/survey/login_form.html
new file mode 100644 (file)
index 0000000..871a890
--- /dev/null
@@ -0,0 +1,65 @@
+<CENTER>\r
+<H3>You need to log in before you can fill out this survey</H3>\r
+\r
+<table cellpadding=10>\r
+  <tr valign=top> \r
+    <td bgcolor=#f0f0f0> \r
+      <form name="form" method="post" action="login.php">\r
+        <table cellpadding=10>\r
+          <tr> \r
+            <td><P>Survey Password:<BR>(from your teacher)</td>\r
+            <td valign=top> \r
+              <input type="password" name="password" size=20 value="<? pv($frm["password"]) ?>" >\r
+                         <? formerr($err["password"]) ?>\r
+            </td>\r
+                 </tr>\r
+          <tr> \r
+            <td><P>Your first name:</td>\r
+            <td valign=top> \r
+              <input type="text" name="firstname" size=20 value="<? pv($frm["firstname"]) ?>">\r
+                         <? formerr($err["firstname"]) ?>\r
+            </td>\r
+          </tr>\r
+          <tr> \r
+            <td><P>Your last name:</td>\r
+            <td valign=top> \r
+              <input type="text" name="lastname" size=20 value="<? pv($frm["lastname"]) ?>">\r
+                         <? formerr($err["lastname"]) ?>\r
+            </td>\r
+          </tr>\r
+          <tr> \r
+            <td><P>Your email address:</td>\r
+            <td valign=top> \r
+              <input type="text" name="email" size=20 value="<? pv($frm["email"]) ?>">\r
+                         <? formerr($err["email"]) ?>\r
+            </td>\r
+          </tr>\r
+          <tr> \r
+            <td><P>Student ID Number:<BR>(optional)</td>\r
+            <td valign=top> \r
+              <input type="text" name="idnumber" size=20 value="<? pv($frm["idnumber"]) ?>">\r
+                         <? formerr($err["idnumber"]) ?>\r
+            </td>\r
+          </tr>\r
+          <tr> \r
+            <td>&nbsp;</td>\r
+            <td valign=bottom> \r
+                         <BR>\r
+              <input type="submit" value="Login to the survey">\r
+                         </form>\r
+                         <form name=cancel method=post action="/mod/survey/">\r
+              <input type="submit" value="Cancel">\r
+              </form>\r
+            </td>\r
+        </table>\r
+    </td>\r
+  </tr>\r
+</table>\r
+</CENTER>\r
+\r
+<HR>\r
+<CENTER>\r
+<FONT SIZE=1>\r
+<P><A HREF="<?=$CFG->wwwroot ?>">Home</A></P>\r
+</BODY>\r
+\r
diff --git a/mod/survey/mod.html b/mod/survey/mod.html
new file mode 100644 (file)
index 0000000..e9dcb4d
--- /dev/null
@@ -0,0 +1,34 @@
+<form name="form" method="post" action="<?=$CFG->wwwroot ?>/mod/survey/details.php">
+<table cellpadding=5>
+<tr valign=top>
+    <td align=right><P><B>Survey Name:</B></P></TD>
+    <td>
+        <input type="text" name="name" size=30 value="<? p($form->name) ?>">
+    </td>
+</tr>
+<tr>
+    <td align=right><P><B>Survey Type:</B></P></TD>
+    <td>
+    <?
+        if ($options = get_records_sql_menu("SELECT id, name FROM survey WHERE template='0'")) {
+            choose_from_menu($options, "template", $form->template);
+        } else {
+            echo "No surveys to choose from!";
+        }
+    ?>
+    </td>
+</tr>
+</table>
+<CENTER>
+<input type="hidden" name=intro   value="<? p($form->intro) ?>">
+<input type="hidden" name=destination value="<?=$ME ?>">
+
+<input type="hidden" name=course     value="<? p($form->course) ?>">
+<input type="hidden" name=week       value="<? p($form->week) ?>">
+<input type="hidden" name=module     value="<? p($form->module) ?>">
+<input type="hidden" name=modulename value="<? p($form->modulename) ?>">
+<input type="hidden" name=instance   value="<? p($form->instance) ?>">
+<input type="hidden" name=mode       value="<? p($form->mode) ?>">
+<input type="submit" value="Save these settings">
+</CENTER>
+</FORM>
diff --git a/mod/survey/mod.php b/mod/survey/mod.php
new file mode 100644 (file)
index 0000000..973bff3
--- /dev/null
@@ -0,0 +1,91 @@
+<?PHP  // $Id$
+
+/////////////////////////////////////////////////////////////
+//
+// MOD.PHP - contains functions to add, update and delete
+//           an instance of this module
+//           
+//           Generally called from /course/mod.php
+//
+/////////////////////////////////////////////////////////////
+
+function add_instance($survey) {
+// Given an object containing all the necessary data, 
+// (defined by the form in mod.html) this function 
+// will create a new instance and return the id number 
+// of the new instance.
+//
+    GLOBAL $db;
+
+    $timenow = time();
+
+    if (!$template = get_record("survey", "id", $survey->template)) {
+        return 0;
+    }
+
+    if (!$rs = $db->Execute("INSERT into survey
+                                SET course    = '$survey->course', 
+                                    name      = '$survey->name',
+                                    days      = '$survey->days',
+                                    intro     = '$survey->intro',
+                                    template  = '$template->id',
+                                    questions = '$template->questions',
+                                    timecreated = '$timenow',
+                                    timemodified = '$timenow' ")) {
+        return 0;
+    }
+    
+    // Get it out again - this is the most compatible way to determine the ID
+    if ($rs = $db->Execute("SELECT id FROM survey
+                            WHERE course = $survey->course AND timemodified = '$timenow'")) {
+        return $rs->fields[0];
+    } else {
+        return 0;
+    }
+}
+
+
+function update_instance($survey) {
+// Given an object containing all the necessary data, 
+// (defined by the form in mod.html) this function 
+// will update an existing instance with new data.
+//
+    GLOBAL $db;
+
+    $timenow = time();
+
+    if (!$template = get_record("survey", "id", $survey->template)) {
+        return 0;
+    }
+
+    if (!$rs = $db->Execute("UPDATE survey
+                                SET name         = '$survey->name',
+                                    days         = '$survey->days',
+                                    intro        = '$survey->intro',
+                                    template     = '$template->id',
+                                    questions    = '$template->questions',
+                                    timemodified = '$timenow'
+                              WHERE id = '$survey->instance' ")) {
+        return false;
+    }
+    return true;
+}
+
+
+function delete_instance($id) {
+// Given an ID of an instance of this module, 
+// this function will permanently delete the instance 
+// and any data that depends on it.  
+//
+    GLOBAL $db;
+
+    if (!$rs = $db->Execute("DELETE from survey WHERE id = '$id' ")) {
+        return false;
+    }
+
+    return true;
+    
+}
+
+
+?>
diff --git a/mod/survey/module.php b/mod/survey/module.php
new file mode 100644 (file)
index 0000000..82319a6
--- /dev/null
@@ -0,0 +1,14 @@
+<?PHP // $Id$
+
+////////////////////////////////////////////////////////////////////////////////
+//  Code fragment to define the module version etc.
+//  This fragment is called by /admin/index.php
+////////////////////////////////////////////////////////////////////////////////
+
+    $module->fullname = "Survey";
+    $module->version  = "20011110";
+    $module->cron     = 0;
+    $module->search   = "";
+
+?>
+
diff --git a/mod/survey/report.php b/mod/survey/report.php
new file mode 100644 (file)
index 0000000..a0a16a2
--- /dev/null
@@ -0,0 +1,356 @@
+<?PHP // $Id$
+
+    include("../../config.php");
+    include("lib.php");
+
+// Check that all the parameters have been provided.
+    require_variable($id);    // Course Module ID
+
+    if (! $cm = get_record("course_modules", "id", $id)) {
+        error("Course Module ID was incorrect");
+    }
+
+    if (! $course = get_record("course", "id", $cm->course)) {
+        error("Course is misconfigured");
+    }
+
+    require_login($course->id);
+
+    if (!isteacher($course->id)) {
+        error("Sorry, only teachers can see this.");
+    }
+
+    if (! $survey = get_record("survey", "id", $cm->instance)) {
+        error("Survey ID was incorrect");
+    }
+
+
+
+    $ME = qualified_me()."?id=$id";
+
+    if (!$action) {
+        $display = "summary";
+    }
+
+    if ($display)  { // Display the frame containing something.
+
+        add_to_log("View survey report: $survey->name", $course->id);
+        echo "<HEAD><TITLE>Report: $survey->name</TITLE>\n";
+        echo "<FRAMESET COLS=150,* BORDER=1> ";
+        echo "  <FRAME NAME=reportmenu SRC=\"report.php?action=menu&id=$id\"> \n";
+        echo "  <FRAME NAME=reportmain SRC=\"report.php?action=$display&id=$id\"> \n";
+        echo "</FRAMESET>\n";
+        exit;
+    }
+
+    switch ($action) {
+      case "menu":
+        print_header("Survey Report", "Survey Report");
+        //echo "<FONT FACE=\"Verdana,Arial,Helvetica,sans-serif\">";
+        //echo "<P><B>Survey Report</B></P>"; 
+        echo "<P><FONT SIZE=2><A TARGET=reportmain HREF=\"report.php?action=summary&id=$id\">Summary</A></FONT></P>";
+        echo "<P><FONT SIZE=2><A TARGET=reportmain HREF=\"report.php?action=scales&id=$id\">Scales</A></FONT></P>";
+        echo "<P><FONT SIZE=2><A TARGET=reportmain HREF=\"report.php?action=questions&id=$id\">Questions</A></FONT></P>";
+        echo "<P><FONT SIZE=2><A TARGET=reportmain HREF=\"report.php?action=students&id=$id\">Students</A></FONT></P>";
+        if ($users = get_survey_responses($survey->id)) {
+            foreach ($users as $user) {
+                echo "<LI><FONT SIZE=1>";
+                echo "<A TARGET=reportmain HREF=\"report.php?action=student&student=$user->id&id=$id\">";
+                echo "$user->firstname $user->lastname";
+                echo "</A></FONT></LI>";
+            }
+        }
+        echo "<P><FONT SIZE=2><A TARGET=reportmain HREF=\"report.php?action=download&id=$id\">Download</A></FONT></P>";
+        echo "<HR SIZE=1 NOSHADE>";
+        echo "<P align=center><FONT SIZE=2><A TARGET=_top HREF=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</A></FONT></P>";
+        break;
+
+      case "summary":
+        add_to_log("View survey report summary: $survey->name", $course->id);
+        print_header("Overall Summary", "$survey->name: Overall Summary", "", "");
+
+        print_heading("All scales, all students");
+
+        echo "<P ALIGN=CENTER><A HREF=\"report.php?action=scales&id=$id\"><IMG HEIGHT=$GHEIGHT WIDTH=$GWIDTH ALT=\"Click here to see the scales in more detail\" BORDER=0 SRC=\"graph.php?id=$id&type=overall.png\"></A>";
+        print_footer($course);
+        break;
+
+      case "scales":
+        add_to_log("View survey report scales: $survey->name", $course->id);
+        print_header("Scales", "$survey->name: Scales", "", "");
+
+        print_heading("All scales, all students");
+
+        $questions = get_records_sql("SELECT * FROM survey_questions WHERE id in ($survey->questions)");
+        $questionorder = explode(",", $survey->questions);
+
+        foreach ($questionorder as $key => $val) {
+            $question = $questions[$val];
+            if ($question->type < 0) {  // We have some virtual scales.  Just show them.
+                $virtualscales = true;
+                break;
+            }
+        }
+
+        foreach ($questionorder as $key => $val) {
+            $question = $questions[$val];
+            if ($question->multi) {
+                if ($virtualscales && $question->type > 0) {  // Don't show non-virtual scales if virtual
+                    continue;
+                }
+                echo "<P ALIGN=center><A HREF=report.php?action=questions&id=$id&qid=$question->multi>";
+                echo "<IMG HEIGHT=$GHEIGHT WIDTH=$GWIDTH ALT=\"Click here to see subquestions\" BORDER=0
+                       SRC=\"graph.php?id=$id&qid=$question->id&type=multiquestion.png\">";
+                echo "</A></P><BR>";
+            } 
+        }
+
+        print_footer($course);
+        break;
+
+      case "questions":
+        add_to_log("View survey report questions: $survey->name", $course->id);
+        print_header("Analysis by Question", "$survey->name: Questions", "", "");
+
+        if ($qid) {     // just get one multi-question
+            $questions = get_records_sql("SELECT * FROM survey_questions WHERE id in ($qid)");
+            $questionorder = explode(",", $qid);
+
+            print_heading("Selected questions from a scale, all students");
+
+        } else {        // get all top-level questions
+            $questions = get_records_sql("SELECT * FROM survey_questions WHERE id in ($survey->questions)");
+            $questionorder = explode(",", $survey->questions);
+
+            print_heading("All questions in order, all students");
+        }
+
+        foreach ($questionorder as $key => $val) {
+            $question = $questions[$val];
+            if ($question->type < 0) {  // We have some virtual scales.  DON'T show them.
+                $virtualscales = true;
+                break;
+            }
+        }
+
+        foreach ($questionorder as $key => $val) {
+            $question = $questions[$val];
+
+            if ($question->type < 0) {  // We have some virtual scales.  DON'T show them.
+                continue;
+            }
+
+            if ($question->multi) {
+                echo "<H3>$question->text :</H3>";
+
+                $subquestions = get_records_sql("SELECT * FROM survey_questions WHERE id in ($question->multi)");
+                $subquestionorder = explode(",", $question->multi);
+                foreach ($subquestionorder as $key => $val) {
+                    $subquestion = $subquestions[$val];
+                    if ($subquestion->type > 0) {
+                        echo "<P ALIGN=CENTER><A HREF=\"report.php?action=question&id=$id&qid=$subquestion->id\">
+                              <IMG HEIGHT=$GHEIGHT WIDTH=$GWIDTH ALT=\"Click here to see all responses\" 
+                                   BORDER=0 SRC=\"graph.php?id=$id&qid=$subquestion->id&type=question.png\"></A></P>";
+                    }
+                }
+            } else if ($question->type > 0 ) {
+                echo "<P ALIGN=CENTER><A HREF=\"report.php?action=question&id=$id&qid=$question->id\">
+                      <IMG HEIGHT=$GHEIGHT WIDTH=$GWIDTH ALT=\"Click here to see all responses\"
+                           BORDER=0 SRC=\"graph.php?id=$id&qid=$question->id&type=question.png\"></A></P>";
+            } else {
+                echo "<H3>$question->text</H3>";
+                if ($aaa = get_records_sql("SELECT sa.*, u.firstname,u.lastname FROM survey_answers sa, user u WHERE survey = '$survey->id' AND question = $question->id and sa.user = u.id")) {
+                    echo "<UL>";
+                    foreach ($aaa as $a) {
+                        echo "<LI>$a->firstname $a->lastname: $a->answer1";
+                    }
+                    echo "</UL>";
+                }
+            }
+        }
+
+        print_footer($course);
+        break;
+
+      case "question":
+        add_to_log("View survey report question: $survey->name", $course->id);
+        if (!$question = get_record("survey_questions", "id", $qid)) {
+            error("Question doesn't exist");
+        }
+
+        $answers =  explode(",", $question->options);
+
+        print_header("All answers for a particular question", "$survey->name: Question Answers", "", "");
+
+        print_heading("$question->text");
+
+        $aaa = get_records_sql("SELECT sa.*,u.firstname,u.lastname,u.picture FROM survey_answers sa, user u WHERE sa.survey = '$survey->id' AND sa.question = $question->id AND u.id = sa.user ORDER by sa.answer1,sa.answer2 ASC");
+
+        echo "<TABLE ALIGN=center CELLPADDING=0 CELLSPACING=10><TR><TD>&nbsp;<TH align=left>Name<TH align=left>Time<TH align=left>Actual<TH align=left>Preferred</TR>";
+        foreach ($aaa as $a) {
+            echo "<TR>";
+            echo "<TD WIDTH=35>";
+            print_user_picture($a->user, $course->id, $a->picture, false);
+            echo "</TD>";
+            echo "<TD><P><A HREF=\"report.php?id=$id&action=student&student=$a->user\">$a->firstname $a->lastname</A></TD>";
+            echo "<TD><P>".date("j M Y h:i A",$a->time)."</TD>";
+            echo "<TD BGCOLOR=\"$THEME->cellcontent\"><P>";
+            if ($a->answer1) {
+                echo "$a->answer1 - ".$answers[$a->answer1 - 1];
+            } else {
+                echo "&nbsp;";
+            }
+            echo "</TD><TD BGCOLOR=\"$THEME->cellcontent\"><P>";
+            if ($a->answer2) {
+                echo "$a->answer2 - ".$answers[$a->answer2 - 1];
+            } else {
+                echo "&nbsp;";
+            }
+            echo "</TD></TR>";
+
+        }
+        echo "</TABLE>";
+
+
+        print_footer($course);
+        break;
+
+      case "students":
+
+         add_to_log("View survey report students: $survey->name", $course->id);
+         print_header("Analysis by Student", "$survey->name: Students", "", "");
+        
+         if (! $results = get_survey_responses($survey->id) ) {
+             notify("There are no responses for this survey.");
+         } else {
+             print_all_responses($cm->id, $results);
+         }
+
+        print_footer($course);
+        break;
+
+      case "student":
+         if (!$user = get_record("user", "id", $student)) {
+             error("Student doesn't exist");
+         }
+
+
+         print_header("Analysis of $user->firstname $user->lastname", "$survey->name: Analysis of a student", "", "");
+         if (isset($notes)) {
+             if (record_exists_sql("SELECT * FROM survey_analysis WHERE survey='$survey->id' and user='$user->id'")) {
+                 if (! update_survey_analysis($survey->id, $user->id, $notes)) {
+                     notify("An error occurred while saving your notes.  Sorry.");
+                 }
+             } else {
+                 if (!add_survey_analysis($survey->id, $user->id, $notes)) {
+                     notify("An error occurred while saving your notes.  Sorry.");
+                 }
+             }
+             add_to_log("Update survey analysis for $user->firstname $user->lastname: $survey->name", $course->id);
+         } else {
+             add_to_log("View survey report $user->firstname $user->lastname: $survey->name", $course->id);
+         }
+
+         print_heading("$user->firstname $user->lastname");
+
+         echo "<P ALIGN=CENTER>";
+         print_user_picture($user->id, $course->id, $user->picture, true);
+         echo "</P>";
+
+         // Print overall summary
+         echo "<P ALIGN=CENTER><IMG HEIGHT=$GHEIGHT WIDTH=$GWIDTH ALIGN=CENTER SRC=\"graph.php?id=$id&sid=$student&type=student.png\"></P>";
+         
+         // Print scales
+         $questions = get_records_sql("SELECT * FROM survey_questions WHERE id in ($survey->questions)");
+         $questionorder = explode(",", $survey->questions);
+         foreach ($questionorder as $key => $val) {
+             $question = $questions[$val];
+             if ($question->type < 0) {  // We have some virtual scales.  Just show them.
+                 $virtualscales = true;
+                 break;
+             }
+         }
+         foreach ($questionorder as $key => $val) {
+             $question = $questions[$val];
+             if ($question->multi) {
+                 if ($virtualscales && $question->type > 0) {  // Don't show non-virtual scales if virtual
+                     continue;
+                 }
+                 echo "<P ALIGN=center><A HREF=report.php?action=questions&id=$id&qid=$question->multi>";
+                 echo "<IMG HEIGHT=$GHEIGHT WIDTH=$GWIDTH ALT=\"Click here to see subquestions\" BORDER=0
+                        SRC=\"graph.php?id=$id&qid=$question->id&sid=$student&type=studentmultiquestion.png\">";
+                 echo "</A></P><BR>";
+             } 
+         }
+
+         if ($rs = get_record_sql("SELECT notes from survey_analysis WHERE survey='$survey->id' and user='$user->id'")) {
+            $notes = $rs->notes;
+         } else {
+            $notes = "";
+         }
+         echo "<HR NOSHADE SIZE=1>";
+         echo "<CENTER>";
+         echo "<FORM ACTION=report.php METHOD=post NAME=form>";
+         echo "<H3>Your private analysis/notes:</H3>";
+         echo "<BLOCKQUOTE>";
+         echo "<TEXTAREA NAME=notes ROWS=10 COLS=60>";
+         p($notes);
+         echo "</TEXTAREA><BR>";
+         echo "<INPUT TYPE=hidden NAME=action VALUE=student>";
+         echo "<INPUT TYPE=hidden NAME=student VALUE=$student>";
+         echo "<INPUT TYPE=hidden NAME=id VALUE=$cm->id>";
+         echo "<INPUT TYPE=submit VALUE=\"Save these notes\">";
+         echo "</BLOCKQUOTE>";
+         echo "</FORM>";
+         echo "</CENTER>";
+
+         print_footer($course);
+         break;
+
+      case "download":
+        print_header("Download Data", "$survey->name: Download Data", "", "");
+
+        echo "<P>You can download the complete raw data for this survey in a form suitable
+                    for analysis in Excel, SPSS or other package.</P>";
+
+        echo "<H2 ALIGN=CENTER><A HREF=\"download.php?id=$id&type=xls\">Download data as Excel spreadsheet</A></H2>";
+        echo "<H2 ALIGN=CENTER><A HREF=\"download.php?id=$id&type=text\">Download data as a plain text file</A></H2>";
+
+        print_footer($course);
+        break;
+
+    }
+
+/// FUNCTIONS //////////////////////////////////////////////////////////////
+
+function print_all_responses($survey, $results) {
+
+    global $THEME;
+
+    echo "<TABLE CELLPADDING=5 CELLSPACING=2 ALIGN=CENTER>";
+    echo "<TR><TD>Name<TD>Time<TD>Answered</TR>";
+
+    foreach ($results as $a) {
+                 
+        echo "<TR>";
+        echo "<TD><A HREF=\"report.php?action=student&student=$a->id&id=$survey\">$a->firstname $a->lastname</A></TD>";
+        echo "<TD>".date("j M Y, h:i A",$a->time)."</TD>";
+        echo "<TD align=right>$a->numanswers</TD>";
+        echo "</TR>";
+    }
+    echo "</TABLE>";
+}
+
+          
+function get_survey_responses($survey) {
+    return get_records_sql("SELECT a.time as time, count(*) as numanswers, u.*
+                            FROM survey_answers AS a, user AS u
+                            WHERE a.answer1 <> '0' AND a.answer2 <> '0'
+                                  AND a.survey = $survey 
+                                  AND a.user = u.id
+                            GROUP BY a.user ORDER BY a.time ASC");
+}
diff --git a/mod/survey/save.php b/mod/survey/save.php
new file mode 100644 (file)
index 0000000..2722740
--- /dev/null
@@ -0,0 +1,82 @@
+<?PHP // $Id$
+
+       require('../../config.php');
+       require('lib.php');
+
+
+// Make sure this is a legitimate posting
+
+    if (!isset($HTTP_POST_VARS)) {
+        error("You are not supposed to use this script like that.");
+    }
+
+    require_variable($id);    // Course Module ID
+
+    if (! $cm = get_record("course_modules", "id", $id)) {
+        error("Course Module ID was incorrect");
+    }
+
+    if (! $course = get_record("course", "id", $cm->course)) {
+        error("Course is misconfigured");
+    }
+
+    require_login($course->id);
+
+    if (! $survey = get_record("survey", "id", $cm->instance)) {
+        error("Survey ID was incorrect");
+    }
+
+    add_to_log("Submit survey $survey->name", $course->id);
+
+    if (survey_already_done($survey->id, $USER->id)) {
+        notice("You've already submitted this survey!", $HTTP_REFERER);
+        exit;
+    }
+
+
+// Sort through the data and arrange it
+// This is necessary because some of the questions 
+// may have two answers, eg Question 1 -> 1 and P1
+
+    $answers = array(); 
+
+    foreach ($HTTP_POST_VARS as $key => $val) {
+        if ($key <> "userid" && $key <> "id") {
+            if ( substr($key,0,1) == "q") {  
+                $key = substr($key,1);   // keep everything but the 'q'
+            }
+            if ( substr($key,0,1) == "P") {
+                $realkey = substr($key,1);
+                $answers[$realkey][1] = $val;
+            } else {
+                $answers[$key][0] = $val;
+            }
+        }
+    }
+
+// Now store the data.
+
+    $timenow = time();
+    foreach ($answers as $key => $val) {
+        $val1 = $val[0]; $val2 = $val[1];
+        if (! $result = $db->Execute("INSERT INTO survey_answers 
+                         (time, user, survey, question, answer1, answer2) 
+                         VALUES ('$timenow', '$USER->id', '$survey->id', '$key', '$val1', '$val2')") ) {
+            error("Encountered a problem trying to store your results. Sorry.");
+        }
+    }
+
+// Print the page and finish up.
+
+       print_header("$course->shortname: Survey sent", "$course->fullname", 
+        "<A HREF=/course/view.php?id=$course->id>$course->shortname</A> ->
+         <A HREF=index.php?id=$course->id>Surveys</A> -> $survey->name -> Survey sent", "");
+
+
+    notice("Thanks for your answers, $USER->firstname.", "$CFG->wwwroot/course/view.php?id=$course->id");
+   
+    exit;
+    
+
+?>
diff --git a/mod/survey/test.php b/mod/survey/test.php
new file mode 100644 (file)
index 0000000..025a8ae
--- /dev/null
@@ -0,0 +1,10 @@
+<?PHP // $Id$\r
+include( "lib/psxlsgen.php" );\r
+\r
+$myxls = new PhpSimpleXlsGen();\r
+$myxls->totalcol = 2;\r
+for ($i=0; $i<10; $i++) {\r
+    $myxls->WriteText_pos($i, $i, "$i stuff");\r
+}\r
+$myxls->SendFile();\r
+?>\r
diff --git a/mod/survey/view.php b/mod/survey/view.php
new file mode 100644 (file)
index 0000000..2421e42
--- /dev/null
@@ -0,0 +1,245 @@
+<?PHP // $Id$
+
+    include("../../config.php");
+    include("lib.php");
+
+    require_variable($id);    // Course Module ID
+
+    if (! $cm = get_record("course_modules", "id", $id)) {
+        error("Course Module ID was incorrect");
+    }
+
+    if (! $course = get_record("course", "id", $cm->course)) {
+        error("Course is misconfigured");
+    }
+
+    require_login($course->id);
+
+    if (! $survey = get_record("survey", "id", $cm->instance)) {
+        error("Survey ID was incorrect");
+    }
+
+    add_to_log("View survey $survey->name", $course->id);
+
+    print_header("$course->shortname: $survey->name", "$course->fullname",
+                 "<A HREF=../../course/view.php?id=$course->id>$course->shortname</A> ->
+                  <A HREF=index.php?id=$course->id>Surveys</A> -> $survey->name", "");
+
+
+    if ($USER->editing) {
+        print_update_module_icon($cm->id);
+    }
+
+    if (isteacher($course->id)) {
+        echo "<P align=right><A HREF=\"report.php?id=$cm->id\">View all responses</A></P>";
+    }
+
+
+//  Check the survey hasn't already been filled out.
+
+    if (survey_already_done($survey->id, $USER->id)) {
+        notice("You've already done this survey, $USER->firstname!", $HTTP_REFERER);
+        exit;
+    }
+
+//  Start the survey form
+
+    echo "<FORM NAME=form METHOD=post ACTION=save.php>";
+    echo "<INPUT TYPE=hidden NAME=id VALUE=$id>";
+
+    print_simple_box(text_to_html($survey->intro), "center", "80%");
+
+// Get all the major questions and their proper order
+    if (! $questions = get_records_sql("SELECT * FROM survey_questions WHERE id in ($survey->questions)")) {
+        error("Couldn't find any questions in this survey!!");
+    }
+    $questionorder = explode( ",", $survey->questions);
+
+// Cycle through all the questions in order and print them
+
+    $qnum = 0;
+    foreach ($questionorder as $key => $val) {
+        $question = $questions["$val"];
+        $question->id = $val;
+        
+        if ($question->type > 0) {
+            if ($question->multi) {
+                print_multi($question);
+            } else {
+                print_single($question);
+            }
+        }
+    }
+
+
+// End the survey page
+   echo "<CENTER><P>&nbsp;</P><P>";
+   if ($ownerpreview) {
+       echo "(Because this is only a preview, the button below will not send data)<BR>\n";
+       echo "<FONT SIZE=+1><INPUT TYPE=submit VALUE=\"Click here to go back\"></FONT>";
+   } else {
+       echo "\n";
+?>
+
+<SCRIPT>
+<!-- // BEGIN
+function checkform() {
+
+    var error=false;
+
+    with (document.form) {
+    <? foreach ($checklist as $question => $default) {
+           echo "  if (".$question."[".$default."].checked) error=true;\n";
+    }?>
+    }
+
+    if (error) {
+        alert("Some of the multiple choice questions have not been answered.");
+    } else {
+        document.form.submit();
+    }
+}
+
+document.write('<INPUT TYPE="button" VALUE="Click here to check and continue" onClick="checkform()">');
+
+// END -->
+</SCRIPT>
+
+<NOSCRIPT>
+    <!-- Without Javascript, no checking is done -->
+    <INPUT TYPE="submit" VALUE="Click here to continue">
+</NOSCRIPT>
+<?
+
+   }
+   echo "</FORM>";
+
+   print_footer($course);
+
+   exit;
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+
+function print_multi($question) {
+    GLOBAL $db, $qnum, $checklist, $THEME;
+
+
+    echo "<P>&nbsp</P>\n";
+       echo "<P><FONT SIZE=4><B>$question->text</B></FONT></P>";
+
+       echo "<TABLE ALIGN=CENTER WIDTH=90% CELLPADDING=4 CELLSPACING=1 BORDER=0>";
+
+    $options = explode( ",", $question->options);
+    $numoptions = count($options);
+
+    $oneanswer = ($question->type == 1 || $question->type == 2) ? true : false;
+       if ($question->type == 2) {
+               $P = "P";
+       } else {
+               $P = "";
+       }
+   
+    if ($oneanswer) { 
+        echo "<TR WIDTH=100% ><TD COLSPAN=2><P>$question->intro</P></TD>";
+    } else {
+        echo "<TR WIDTH=100% ><TD COLSPAN=3><P>$question->intro</P></TD>"; 
+    }
+
+    while (list ($key, $val) = each ($options)) {
+        echo "<TD width=10% ALIGN=CENTER><FONT SIZE=1><P>$val</P></FONT></TD>\n";
+    }
+    echo "<TD ALIGN=CENTER BGCOLOR=\"$THEME->body\">&nbsp</TD></TR>\n";
+
+    $subquestions = get_records_sql("SELECT * FROM survey_questions WHERE id in ($question->multi) ");
+
+    foreach ($subquestions as $q) {
+        $qnum++;
+        $bgcolor = question_color($qnum);
+
+        echo "<TR BGCOLOR=$bgcolor>";
+        if ($oneanswer) {
+            echo "<TD WIDTH=10 VALIGN=top><P><B>$qnum</B></P></TD>";
+            echo "<TD VALIGN=top><P>$q->text</P></TD>";
+            for ($i=1;$i<=$numoptions;$i++) {
+                echo "<TD WIDTH=10% ALIGN=CENTER><INPUT TYPE=radio NAME=q$P$q->id VALUE=$i></TD>";
+            }
+            echo "<TD BGCOLOR=white><INPUT TYPE=radio NAME=q$P$q->id VALUE=0 checked></TD>";
+            $checklist["q$P$q->id"] = $numoptions;
+        
+        } else {
+            echo "<TD WIDTH=10 VALIGN=middle rowspan=2><P><B>$qnum</B></P></TD>";
+            echo "<TD WIDTH=10% NOWRAP><P><FONT SIZE=1>I prefer that&nbsp;</FONT></P></TD>";
+            echo "<TD WIDTH=40% VALIGN=middle rowspan=2><P>$q->text</P></TD>";
+            for ($i=1;$i<=$numoptions;$i++) {
+                echo "<TD WIDTH=10% ALIGN=CENTER><INPUT TYPE=radio NAME=qP$q->id VALUE=$i></TD>";
+            }
+            echo "<TD BGCOLOR=\"$THEME->body\"><INPUT TYPE=radio NAME=qP$q->id VALUE=0 checked></TD>";
+            echo "</TR>";
+
+            echo "<TR BGCOLOR=$bgcolor>";
+            echo "<TD WIDTH=10% NOWRAP><P><FONT SIZE=1>I found that&nbsp;</P></TD>";
+            for ($i=1;$i<=$numoptions;$i++) {
+                echo "<TD WIDTH=10% ALIGN=CENTER><INPUT TYPE=radio NAME=q$q->id VALUE=$i></TD>";
+            }
+            echo "<TD WIDTH=5% BGCOLOR=\"$THEME->body\"><INPUT TYPE=radio NAME=q$q->id VALUE=0 checked></TD>";
+            $checklist["qP$q->id"] = $numoptions;
+            $checklist["q$q->id"] = $numoptions;
+        }
+        echo "</TR>\n";
+    }
+    echo "</TABLE>";
+}
+
+
+
+function print_single($question) {
+    GLOBAL $db, $qnum;
+
+    $bgcolor = question_color(0);
+
+    $qnum++;
+
+    echo "<P>&nbsp</P>\n";
+    echo "<TABLE ALIGN=CENTER WIDTH=90% CELLPADDING=4 CELLSPACING=0>\n";
+    echo "<TR BGCOLOR=$bgcolor>";
+    echo "<TD VALIGN=top><B>$qnum</B></TD>";
+    echo "<TD WIDTH=50% VALIGN=top><P>$question->text</P></TD>\n";
+    echo "<TD WIDTH=50% VALIGN=top><P><FONT SIZE=+1>\n";
+
+
+    if ($question->type == 0) {           // Plain text field
+        echo "<TEXTAREA ROWS=3 COLS=30 WRAP=virtual NAME=\"$question->id\">$question->options</TEXTAREA>";
+
+    } else if ($question->type > 0) {     // Choose one of a number
+        echo "<SELECT NAME=$question->id>";
+        echo "<OPTION VALUE=0 SELECTED>Choose...</OPTION>";
+        $options = explode( ",", $question->options);
+        foreach ($options as $key => $val) {
+            $key++;
+            echo "<OPTION VALUE=\"$key\">$val</OPTION>";
+        }
+        echo "</SELECT>";
+
+    } else if ($question->type < 0) {     // Choose several of a number
+        $options = explode( ",", $question->options);
+        echo "<P>THIS TYPE OF QUESTION NOT SUPPORTED YET</P>";
+    }
+
+    echo "</FONT></TD></TR></TABLE>";
+
+}
+
+function question_color($qnum) {
+    global $THEME;
+
+    if ($qnum) {
+        return $qnum % 2 ? $THEME->cellcontent : $THEME->cellcontent2;
+        //return $qnum % 2 ? "#CCFFCC" : "#CCFFFF";
+    } else {
+        return $THEME->cellcontent;
+    }
+}
+
+?>
diff --git a/pix/b.gif b/pix/b.gif
new file mode 100755 (executable)
index 0000000..f7df4a3
Binary files /dev/null and b/pix/b.gif differ
diff --git a/pix/i/ICONS-16x16 b/pix/i/ICONS-16x16
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/pix/i/email.gif b/pix/i/email.gif
new file mode 100755 (executable)
index 0000000..effd0ca
Binary files /dev/null and b/pix/i/email.gif differ
diff --git a/pix/i/log.gif b/pix/i/log.gif
new file mode 100644 (file)
index 0000000..55d67fa
Binary files /dev/null and b/pix/i/log.gif differ
diff --git a/pix/i/new.gif b/pix/i/new.gif
new file mode 100755 (executable)
index 0000000..ede003b
Binary files /dev/null and b/pix/i/new.gif differ
diff --git a/pix/i/news.gif b/pix/i/news.gif
new file mode 100755 (executable)
index 0000000..33e6179
Binary files /dev/null and b/pix/i/news.gif differ
diff --git a/pix/i/settings.gif b/pix/i/settings.gif
new file mode 100755 (executable)
index 0000000..fb12c60
Binary files /dev/null and b/pix/i/settings.gif differ
diff --git a/pix/madewithmoodle.gif b/pix/madewithmoodle.gif
new file mode 100755 (executable)
index 0000000..8c75321
Binary files /dev/null and b/pix/madewithmoodle.gif differ
diff --git a/pix/madewithmoodle1.gif b/pix/madewithmoodle1.gif
new file mode 100755 (executable)
index 0000000..d9c4685
Binary files /dev/null and b/pix/madewithmoodle1.gif differ
diff --git a/pix/madewithmoodle2.gif b/pix/madewithmoodle2.gif
new file mode 100644 (file)
index 0000000..54f0547
Binary files /dev/null and b/pix/madewithmoodle2.gif differ
diff --git a/pix/poo.html b/pix/poo.html
new file mode 100644 (file)
index 0000000..8f52ae9
--- /dev/null
@@ -0,0 +1,252 @@
+<!--
+============================================================
+Script:     Amazing Interactive No-Layers Menu Script
+
+Function:   A complete menu system with fully interactive
+            functionality, separate messaging box, and
+            programmable elements, including:
+               - link color and behavior
+               - link box motion indent
+               - link box border colors
+               - link box border styles
+               - link box border width
+               - individual link messages
+               - default link message
+            Designed as an alternative to costly Java
+            applets that perform similar functions, the
+            scripting uses no layers or divisions.
+
+Browsers:   IE4 and up, NS6
+            (others degrade functionally)
+
+Author:     etLux
+============================================================
+
+INSTRUCTIONS
+
+The simplest way to present this script was to provide an
+entire page, very clearly commented with internal instruc-
+tions.  That's what you'll find below, after the double
+lines.
+
+There is *no* extraneous code on this page (other than the
+comments).  Copy-and-paste *everything* into a fresh page;
+this is complete page code.
+
+(Note that you need one image, used as a spacer.  The name
+of the spacer image file should be spacer.gif, and it should
+be placed in the same directory as the page.  A 5x5-pixel
+transparent or standard .gif is fine.)
+
+Work from the commented instructions included in the page
+code, gradually modifying it until it meets your need.
+
+============================================================
+//-->
+<html>
+<head>
+
+<!-- Notes on style set-ups...
+
+   - the <style> ... </style> goes in the <head> of the page
+   
+   - set widths in pixels (px) for Menu Items box width
+         in both .BorderOn and .BorderOff
+         
+   - set border attributes (border:width style #color) as
+         desired:
+         - width is in px
+         - style can be solid, dashed, dotted, groove, etc.
+         - color is in standard #FFFFFF format 
+         
+   - set margin-left in .BorderOn in px for mouseOver indent   
+   
+   - set link colors and text-decoration as desired in A.mXxxxxx's
+   
+   - for more on styles, attributes, and their settings, see:
+     http://msdn.microsoft.com/workshop/author/css/reference/attributes.asp
+   
+//-->
+
+<style>
+<!--
+
+.BorderOn  { width:90px;
+             margin-left:10px;
+             border:1px solid #456789 }
+.BorderOff { width:90px;
+             margin-left:0px;
+             border:1px solid #444444 }
+             
+A.mBlue:link      {color:#00CCFF; text-decoration:none;}
+A.mBlue:visited   {color:#00CCFF; text-decoration:none;}
+A.mBlue:active    {color:#00CCFF; text-decoration:none;}
+A.mBlue:hover     {color:#FF0000; text-decoration:underline;}        
+
+A.mGreen:link     {color:#00FF80; text-decoration:none;}
+A.mGreen:visited  {color:#00FF80; text-decoration:none;}
+A.mGreen:active   {color:#00FF80; text-decoration:none;}
+A.mGreen:hover    {color:#FF0000; text-decoration:underline;} 
+
+A.mYellow:link    {color:#FFFF00; text-decoration:none;}
+A.mYellow:visited {color:#FFFF00; text-decoration:none;}
+A.mYellow:active  {color:#FFFF00; text-decoration:none;}
+A.mYellow:hover   {color:#FF0000; text-decoration:underline;}          
+
+//-->             
+</style>
+
+<!-- Notes on script set-ups...
+
+   - The <script> ... </script> goes in the head of the
+         page, usually after the <style> ... </style>
+         
+   - Set the offMessage as desired
+   
+//-->
+
+<script language="JavaScript1.2">
+<!--
+
+// (C) 2000 www.CodeLifter.com
+// http://www.codelifter.com
+// Free for all users, but leave in this header
+
+offMessage = "Welcome to CodeLifter..."
+
+function boxOn(which,message){
+   if (document.all||document.getElementById){
+      which.className='BorderOn'
+      if (document.getElementById) {document.getElementById("Message").innerHTML = message}
+         else {Message.innerHTML = message}
+   }
+}
+
+function boxOff(which){
+   if (document.all||document.getElementById){
+      which.className='BorderOff'
+      if (document.getElementById) {document.getElementById("Message").innerHTML = offMessage}
+         else {Message.innerHTML = offMessage}
+   }
+}
+
+//-->
+</script>
+<title></title>
+</head>
+
+<!-- General notes on installing the HTML code...
+
+   - everything from BEGINNING OF MENU through END OF MENU is
+        required
+        
+   - in general, other than noted, you can treat the contents of 
+        table cells as you normally would; however, take care to
+        preserve all class= and id= instances and all boxOn and
+        boxOff function calls, as these do the real work
+        
+   - messages are used only in the boxOn calls, but the 'this' 
+        reference must be included in both boxOn and boxOff calls
+        
+   - messages must be enclosed within single 'quote' marks
+   
+   - remember to change <a href> target= to _top for the same
+        window, _blank or _new for a new window, or the framename
+        if you're using frames (this is standard html)
+
+//-->
+
+<body bgcolor="#000000">
+<!-- BEGINNING OF MENU //-->
+
+<!-- Outer Container Table //-->
+<!-- Set this table width to largest margin-left + largest width in <style> script //-->
+<table cellpadding="0" cellspacing="0" width="100">
+<tr>
+<td align="center">
+
+<!-- Header Table // -->
+<table cellpadding="3" cellspacing="0" bgcolor="#000000" class="BorderOff">
+  <tr>
+    <td><font color="#FEDCBA" size="2" face="Arial">Heading</font></td>
+  </tr>
+</table>
+<img src="spacer.gif" width="5" height="5"><br>
+<!-- End Header Table //-->
+
+<!-- Menu Items Tables
+
+   - To add more, just follow the pattern
+   - Note class= in each <a href> to attach link style colors
+
+//-->
+
+<!-- Menu Item One Table //-->
+<table cellpadding="3" cellspacing="0" class="BorderOff" onMouseover="boxOn(this,'Eat my giant octopus feet with relish and abandon.')" onMouseout="boxOff(this)">
+  <tr>
+    <td><font color="#00FF80" size="2" face="Arial"><a class="mBlue" href="http://www.codebrain.com" target="_blank">Thing One</a></font></td>
+  </tr>
+</table>  
+<img src="spacer.gif" width="2" height="2"><br>
+<!-- Menu Item Two Table //-->
+<table cellpadding="3" cellspacing="0" class="BorderOff" onMouseover="boxOn(this,'Beguile me senseless with your big goatly beauty.')" onMouseout="boxOff(this)">
+  <tr>
+    <td><font color="#00FF80" size="2" face="Arial"><a class="mBlue" href="http://www.codebrain.com" target="_blank">Thing Two</a></font></td>
+  </tr>
+</table>
+<img src="spacer.gif" width="5" height="5"><br>
+<!-- Menu Item Three Table //-->
+<table cellpadding="3" cellspacing="0" class="BorderOff" onMouseover="boxOn(this,'Entrance me with the odor of your ugly blue cheese.')" onMouseout="boxOff(this)">  
+  <tr>
+    <td><font color="#00FF80" size="2" face="Arial"><a class="mGreen" href="http://www.braincode.com" target="_blank">Thing Three</a></font></td>
+  </tr>
+</table>
+<img src="spacer.gif" width="2" height="2"><br>
+<!-- Menu Item Four Table //-->
+<table cellpadding="3" cellspacing="0" class="BorderOff" onMouseover="boxOn(this,'Never remember me without fresh garlic around your neck.')" onMouseout="boxOff(this)">  
+  <tr>
+    <td><font color="#00FF80" size="2" face="Arial"><a class="mYellow" href="http://www.braincode.com" target="_blank">Thing Four</a></font></td>
+  </tr>
+</table>
+<img src="spacer.gif" width="2" height="2"><br>
+<!-- Menu Item Five Table //-->
+<table cellpadding="3" cellspacing="0" class="BorderOff" onMouseover="boxOn(this,'Speak, and you shall make noise in the night of my bookshelf.')" onMouseout="boxOff(this)">  
+  <tr>
+    <td><font color="#00FF80" size="2" face="Arial"><a class="mYellow" href="http://www.braincode.com" target="_blank">Thing Five</a></font></td>
+  </tr>
+</table>
+<img src="spacer.gif" width="5" height="5"><br>
+<!-- End Menu Items Tables //-->
+
+<!-- Message Table //-->
+<!-- Set the width= of this table the same as the overall
+     width in the <style> //-->
+<table cellpadding="1" cellspacing="0" bgcolor="#444444" width="90">
+<tr>
+<td>
+<!-- Set the width= of this table to the overall width
+     in the style table minus 2x the border width; set
+     the height= long (large) enough to accommodate your
+     longest message //-->
+<table cellpadding="3" cellspacing="0" bgcolor="#000000" width="88" height="100">
+  <tr>
+    <td align="left" valign="top"><font id="Message" color="#CBA987" size="2" face="Arial">Welcome to CodeLifter...</font></td>
+  </tr>
+</table>
+</td>
+</tr>
+</table>
+<!-- End Message Table //-->
+
+
+</td>
+</tr>
+</table>
+<!-- End Outer Container Table //-->
+
+
+<!-- END OF MENU //-->
+</body>
+</html>
+
+
diff --git a/pix/s/SMILEYS b/pix/s/SMILEYS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/pix/s/biggrin.gif b/pix/s/biggrin.gif
new file mode 100755 (executable)
index 0000000..63aa5b2
Binary files /dev/null and b/pix/s/biggrin.gif differ
diff --git a/pix/s/cool.gif b/pix/s/cool.gif
new file mode 100755 (executable)
index 0000000..8446edf
Binary files /dev/null and b/pix/s/cool.gif differ
diff --git a/pix/s/cross.gif b/pix/s/cross.gif
new file mode 100755 (executable)
index 0000000..31d2995
Binary files /dev/null and b/pix/s/cross.gif differ
diff --git a/pix/s/mixed.gif b/pix/s/mixed.gif
new file mode 100755 (executable)
index 0000000..91a9838
Binary files /dev/null and b/pix/s/mixed.gif differ
diff --git a/pix/s/sad.gif b/pix/s/sad.gif
new file mode 100755 (executable)
index 0000000..bd5b8d3
Binary files /dev/null and b/pix/s/sad.gif differ
diff --git a/pix/s/smiley.gif b/pix/s/smiley.gif
new file mode 100755 (executable)
index 0000000..2438c71
Binary files /dev/null and b/pix/s/smiley.gif differ
diff --git a/pix/s/surprise.gif b/pix/s/surprise.gif
new file mode 100755 (executable)
index 0000000..2902bec
Binary files /dev/null and b/pix/s/surprise.gif differ
diff --git a/pix/s/tongueout.gif b/pix/s/tongueout.gif
new file mode 100755 (executable)
index 0000000..66d1719
Binary files /dev/null and b/pix/s/tongueout.gif differ
diff --git a/pix/s/wideeyes.gif b/pix/s/wideeyes.gif
new file mode 100755 (executable)
index 0000000..206b992
Binary files /dev/null and b/pix/s/wideeyes.gif differ
diff --git a/pix/s/wink.gif b/pix/s/wink.gif
new file mode 100755 (executable)
index 0000000..173cb0c
Binary files /dev/null and b/pix/s/wink.gif differ
diff --git a/pix/spacer.gif b/pix/spacer.gif
new file mode 100755 (executable)
index 0000000..e91556e
Binary files /dev/null and b/pix/spacer.gif differ
diff --git a/pix/t/TINY-ICONS b/pix/t/TINY-ICONS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/pix/t/delete.gif b/pix/t/delete.gif
new file mode 100644 (file)
index 0000000..dd2b01f
Binary files /dev/null and b/pix/t/delete.gif differ
diff --git a/pix/t/down.gif b/pix/t/down.gif
new file mode 100644 (file)
index 0000000..e867c01
Binary files /dev/null and b/pix/t/down.gif differ
diff --git a/pix/t/edit.gif b/pix/t/edit.gif
new file mode 100644 (file)
index 0000000..bc8382c
Binary files /dev/null and b/pix/t/edit.gif differ
diff --git a/pix/t/search.gif b/pix/t/search.gif
new file mode 100755 (executable)
index 0000000..bfbf786
Binary files /dev/null and b/pix/t/search.gif differ
diff --git a/pix/t/up.gif b/pix/t/up.gif
new file mode 100644 (file)
index 0000000..e2cab75
Binary files /dev/null and b/pix/t/up.gif differ
diff --git a/pix/webding.png b/pix/webding.png
new file mode 100755 (executable)
index 0000000..2a7ad4e
Binary files /dev/null and b/pix/webding.png differ
diff --git a/theme/standard/config.php b/theme/standard/config.php
new file mode 100644 (file)
index 0000000..6806d64
--- /dev/null
@@ -0,0 +1,10 @@
+<?PHP // $Id$
+
+$THEME->body         = "#FFEECE";  // Main page color
+$THEME->cellheading  = "#FFD991";  // Standard headings of big tables
+$THEME->cellheading2 = "#FFB62D";  // Highlight headings of tables
+$THEME->cellcontent  = "#FFFFFF";  // For areas with text
+$THEME->cellcontent2 = "#FFD991";  // Alternate colour
+$THEME->borders      = "#555555";  // Table borders
+
+?>
diff --git a/theme/standard/footer.html b/theme/standard/footer.html
new file mode 100644 (file)
index 0000000..ad8b555
--- /dev/null
@@ -0,0 +1,18 @@
+<!-- START OF FOOTER   $Id$    -->
+<CENTER>
+<HR SIZE=1 NOSHADE>
+<FONT SIZE=1><P>
+<? if ($USER->id) {
+       echo "You are logged in as $USER->firstname $USER->lastname. ";
+       if ($USER->survey) {
+           echo " (Student)<BR>To log out you need to quit the browser.";
+       } else {
+              echo " (<A HREF=$CFG->wwwroot/login/logout.php>Logout</A>)";
+          }
+   } else {
+       echo "You are not logged in.  <A HREF=$CFG->wwwroot/login/>Log in here</A>.";
+   }
+?>
+</P>
+<P><?=$homelink ?></P>
+</BODY>
diff --git a/theme/standard/header.html b/theme/standard/header.html
new file mode 100644 (file)
index 0000000..b1139c7
--- /dev/null
@@ -0,0 +1,26 @@
+<HTML>
+<HEAD>
+    <TITLE><?=$title ?></TITLE>
+    <META NAME="keywords" CONTENT="Moodle, <?=$title ?> ">
+    <?=$meta ?>
+    <LINK rel="stylesheet" HREF="<?=$styles ?>">
+    <? include("$CFG->javascript"); ?>
+</HEAD>
+
+<BODY <? if ($focus) { echo "onLoad=setfocus()"; } ?> bgcolor="<?=$THEME->body ?>" link="#000066" vlink="#222288">
+
+<?  if ($heading) { ?>
+    <FONT FACE="Trebuchet MS, Verdana, Arial, Helvetica, sans-serif" SIZE=4><B><?=$heading?></B></FONT>
+<?  } ?>
+
+<?  if ($navigation) { ?>
+    <TABLE BORDER=0 CELLPADDING=3 CELLSPACING=0 WIDTH=100%>
+    <TR><TD BGCOLOR="<?=$THEME->cellheading?>">
+    <FONT FACE="Trebuchet MS, Verdana, Arial, Helvetica, sans-serif" SIZE=2><B>
+<?  print_navigation("$navigation"); ?>
+    </B></FONT></TD></TR></TABLE>
+    <IMG SRC="$CFG->wwwroot/pix/spacer.gif" ALT="" HEIGHT=5 WIDTH=1>
+<?  } else { ?>
+    <HR SIZE=1 NOSHADE>
+<?  } ?>
+<!-- END OF HEADER  $Id$  -->
diff --git a/theme/standard/styles.css b/theme/standard/styles.css
new file mode 100644 (file)
index 0000000..c043150
--- /dev/null
@@ -0,0 +1,13 @@
+A:link    {  font-family: "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; text-decoration: none; color: blue}
+A:visited {  font-family: "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; text-decoration: none; color: blue}
+A:hover   {  font-family: "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; text-decoration: underline; color: red}
+
+BODY {font-family: "Trebuchet MS",Verdana, Arial, Helvetica, sans-serif}
+P    {font-family: "Trebuchet MS",Verdana, Arial, Helvetica, sans-serif}
+H1   {font-family: "Trebuchet MS",Verdana, Arial, Helvetica, sans-serif}
+H2   {font-family: "Trebuchet MS",Verdana, Arial, Helvetica, sans-serif}
+H3   {font-family: "Trebuchet MS",Verdana, Arial, Helvetica, sans-serif}
+H4   {font-family: "Trebuchet MS",Verdana, Arial, Helvetica, sans-serif}
+TH   {font-family: "Trebuchet MS",Verdana, Arial, Helvetica, sans-serif; font-weight: bold; background-color: #FFD991;}
+TD   {font-family: "Trebuchet MS",Verdana, Arial, Helvetica, sans-serif}
+
diff --git a/user/default/f1.jpg b/user/default/f1.jpg
new file mode 100755 (executable)
index 0000000..e92dd78
Binary files /dev/null and b/user/default/f1.jpg differ
diff --git a/user/default/f2.jpg b/user/default/f2.jpg
new file mode 100755 (executable)
index 0000000..2f05acd
Binary files /dev/null and b/user/default/f2.jpg differ
diff --git a/user/edit.html b/user/edit.html
new file mode 100644 (file)
index 0000000..1ca1848
--- /dev/null
@@ -0,0 +1,60 @@
+<P ALIGN=center>Items marked <B>private</B> will not be made visible to other students</P>
+
+<FORM METHOD="post" ENCTYPE="multipart/form-data" action="edit.php">
+<table cellpadding=9 cellspacing=0 >
+<tr valign=top>
+       <td><P>New picture:</td>
+       <td>
+    <INPUT type="hidden" name="MAX_FILE_SIZE" value="4000000">
+    <input type="file" name="imagefile"> ( .jpg or .png )
+       <? formerr($err["imagefile"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Email:</td>
+       <td><input type="text" name="email" size=25 value="<?=$user->email ?>">
+       <? formerr($err["email"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>ICQ Number:</td>
+       <td><input type="text" name="icq" size=25 value="<?=$user->icq ?>">
+       <? formerr($err["icq"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Phone Number 1:</td>
+       <td><input type="text" name="phone1" size=25 value="<?=$user->phone1 ?>"> (private)
+       <? formerr($err["phone1"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Phone Number 2:</td>
+       <td><input type="text" name="phone2" size=25 value="<?=$user->phone2 ?>"> (private)
+       <? formerr($err["phone2"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Address:</td>
+       <td><input type="text" name="address" size=25 value="<?=$user->address ?>"> (private)
+       <? formerr($err["address"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Web Address:</td>
+       <td><input type="text" name="url" size=25 value="<?=$user->url ?>">
+       <? formerr($err["url"]) ?>
+       </td>
+</tr>
+<tr valign=top>
+       <td><P>Description:</td>
+       <td><TEXTAREA NAME=description COLS=50 ROWS=10 WRAP=virtual><?=$user->description ?></TEXTAREA>
+       </td>
+</tr>
+<tr>
+       <td></td>
+       <td><input type="submit" value="Update my profile"></td>
+</TABLE>
+<INPUT type="hidden" name="course" value="<?=$course->id ?>">
+<INPUT type="hidden" name="id" value="<?=$user->id ?>"> 
+</FORM>
diff --git a/user/edit.php b/user/edit.php
new file mode 100644 (file)
index 0000000..12aac78
--- /dev/null
@@ -0,0 +1,148 @@
+<?PHP // $Id$
+
+       require("../config.php");
+       require("lib.php");
+
+    require_variable($id);       // user id
+    require_variable($course);   // course id
+
+    if (! $user = get_record("user", "id", $id)) {
+        error("User ID was incorrect");
+    }
+
+    if (! $course = get_record("course", "id", $course)) {
+        error("User ID was incorrect");
+    }
+
+       require_login($course->id);
+
+    if ($USER->id <> $user->id) {
+        error("You can only edit your own information");
+    }
+
+
+/// If data submitted, then process and store.
+
+       if (match_referer() && isset($HTTP_POST_VARS)) {
+
+        $usernew = (object)$HTTP_POST_VARS;
+
+        if (!find_form_errors($user, $usernew, $err) ) {
+
+                   $timenow = time();
+
+            if ($imagefile && $imagefile!="none") { 
+                $imageinfo = GetImageSize($imagefile);
+                $image->width  = $imageinfo[0];
+                $image->height = $imageinfo[1];
+                $image->type   = $imageinfo[2];
+    
+                switch ($image->type) {
+                    case 2: $im = ImageCreateFromJPEG($imagefile); break;
+                    case 3: $im = ImageCreateFromPNG($imagefile); break;
+                    default: error("Image must be in JPG or PNG format");
+                }
+                if (function_exists("ImageCreateTrueColor")) {
+                    $im1 = ImageCreateTrueColor(100,100);
+                    $im2 = ImageCreateTrueColor(35,35);
+                } else {
+                    $im1 = ImageCreate(100,100);
+                    $im2 = ImageCreate(35,35);
+                }
+                
+                $cx = $image->width / 2;
+                $cy = $image->height / 2;
+    
+                if ($image->width < $image->height) {
+                    $half = floor($image->width / 2.0);
+                } else {
+                    $half = floor($image->height / 2.0);
+                }
+    
+                if (!file_exists("$CFG->dataroot/users")) {
+                    mkdir("$CFG->dataroot/users", 0777);
+                }
+                if (!file_exists("$CFG->dataroot/users/$USER->id")) {
+                    mkdir("$CFG->dataroot/users/$USER->id", 0777);
+                }
+                
+                ImageCopyBicubic($im1, $im, 0, 0, $cx-$half, $cy-$half, 100, 100, $half*2, $half*2);
+                ImageCopyBicubic($im2, $im, 0, 0, $cx-$half, $cy-$half, 35, 35, $half*2, $half*2);
+    
+                // Draw borders over the top.
+                $black1 = ImageColorAllocate ($im1, 0, 0, 0);
+                $black2 = ImageColorAllocate ($im2, 0, 0, 0);
+                ImageLine ($im1, 0, 0, 0, 99, $black1);
+                ImageLine ($im1, 0, 99, 99, 99, $black1);
+                ImageLine ($im1, 99, 99, 99, 0, $black1);
+                ImageLine ($im1, 99, 0, 0, 0, $black1);
+                ImageLine ($im2, 0, 0, 0, 34, $black2);
+                ImageLine ($im2, 0, 34, 34, 34, $black2);
+                ImageLine ($im2, 34, 34, 34, 0, $black2);
+                ImageLine ($im2, 34, 0, 0, 0, $black2);
+            
+                ImageJpeg($im1, "$CFG->dataroot/users/$USER->id/f1.jpg", 90);
+                ImageJpeg($im2, "$CFG->dataroot/users/$USER->id/f2.jpg", 95);
+                $usernew->picture = "1";
+            } else {
+                $usernew->picture = $user->picture;
+            }
+    
+            $usernew->timemodified = time();
+
+            if (update_record("user", $usernew)) {
+                add_to_log("Updated own profile", $course->id);
+                       redirect("view.php?id=$user->id&course=$course->id", "Changes saved");
+            } else {
+                error("Could not update the user record ($user->id)");
+            }
+           }
+    }
+    
+/// Otherwise fill and print the form.
+
+    if ($course->category) {
+           print_header("Edit user profile", "Edit user profile", 
+                    "<A HREF=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</A> 
+                    -> <A HREF=\"index.php?id=$course->id\">Participants</A>
+                    -> <A HREF=\"view.php?id=$USER->id&course=$course->id\">$USER->firstname $USER->lastname</A> 
+                    -> Edit profile", "");
+    } else {
+           print_header("Edit user profile", "Edit user profile", 
+                     "<A HREF=\"view.php?id=$USER->id&course=$course->id\">$USER->firstname $USER->lastname</A> 
+                      -> Edit profile", "");
+    }
+
+    print_simple_box_start("center", "", "$THEME->cellheading");
+    echo "<H2>User profile for $user->firstname $user->lastname</H2>";
+       include("edit.html");
+    print_simple_box_end();
+
+    print_footer($course);
+
+
+
+
+/// FUNCTIONS ////////////////////
+
+function find_form_errors(&$user, &$usernew, &$err) {
+
+    if (empty($usernew->email))
+        $err["email"] = "Missing email address";
+
+    else if (! validate_email($usernew->email))
+        $err["email"] = "Invalid email address, check carefully";
+
+    else if ($otheruser = get_record("user", "email", $usernew->email)) {
+        if ($otheruser->id <> $user->id) {
+            $err["email"] = "Email address already in use by someone else.";
+        }
+    }
+
+    $user->email = $usernew->email;
+
+    return count($err);
+}
+
+
+?>
diff --git a/user/index.php b/user/index.php
new file mode 100644 (file)
index 0000000..23df5e5
--- /dev/null
@@ -0,0 +1,93 @@
+<?PHP // $Id$
+
+//  Lists all the users within a given course
+
+    require("../config.php");
+    require("lib.php");
+
+    require_variable($id);   //course
+
+    if (! $course = get_record("course", "id", $id)) {
+        error("Course ID is incorrect");
+    }
+
+    require_login($course->id);
+
+    add_to_log("View list of all profiles", $course->id);
+
+    if ($course->category) {
+        print_header("$course->shortname: Participants", "$course->fullname",
+                     "<A HREF=../course/view.php?id=$course->id>$course->shortname</A> -> Participants", "");
+    } else {
+        print_header("$course->shortname: Participants", "$course->fullname", "Participants", "");
+    }
+
+
+    $teacherlinks = isteacher($course->id);
+
+    echo "<H2 align=center>".$course->teacher."s</H2>";
+
+    if ( $teachers = get_records_sql("SELECT u.* FROM user u, user_teachers t 
+                                       WHERE t.course = '$course->id' AND t.user = u.id
+                                       ORDER BY t.authority")) {
+        foreach ($teachers as $teacher) {
+            print_user($teacher, $course, $teacherlinks);
+        }
+    } else {
+        notify("None yet");
+    }
+
+    echo "<H2 align=center>Students</H2>";
+    if ($students = get_records_sql("SELECT u.* FROM user u, user_students s 
+                                       WHERE s.course = '$course->id' AND s.user = u.id
+                                       ORDER BY u.lastaccess DESC")) {
+        foreach ($students as $student) {
+            print_user($student, $course, $teacherlinks);
+        }
+    } else {
+        notify("None yet");
+    }
+
+    print_footer($course);
+
+/// FUNCTIONS //////////////////
+
+function print_user($user, $course, $teacherlinks) {
+    
+    echo "<TABLE WIDTH=80% ALIGN=CENTER BORDER=0 CELLPADDING=1 CELLSPACING=1><TR><TD BGCOLOR=#888888>";
+    echo "<TABLE WIDTH=100% BORDER=0 CELLPADDING=0 CELLSPACING=0><TR>";
+    echo "<TD WIDTH=100 BGCOLOR=#FFFFFF VALIGN=top>";
+    echo "<A HREF=\"view.php?id=$user->id&course=$course->id\">";
+    if ($user->picture) {
+        echo "<IMG BORDER=0 ALIGN=left WIDTH=100 SRC=\"pix.php/$user->id/f1.jpg\">";
+    } else {
+        echo "<IMG BORDER=0 ALIGN=left WIDTH=100 SRC=\"default/f1.jpg\">";
+    }
+    echo "</A>";
+    echo "</TD><TD WIDTH=100% BGCOLOR=#FFFFFF VALIGN=top>";
+    echo "<FONT SIZE=-1>";
+    echo "<FONT SIZE=3><B>$user->firstname $user->lastname</B></FONT>";
+    echo "<P>Email: <A HREF=\"mailto:$user->email\">$user->email</A><BR>";
+    echo "Last access: ".userdate($user->lastaccess);
+    echo "&nbsp (".format_time(time() - $user->lastaccess).")";
+    echo "</TD><TD VALIGN=bottom BGCOLOR=#FFFFFF NOWRAP>";
+
+    echo "<FONT SIZE=1>";
+    if ($teacherlinks) {
+        $tt = getdate(time());
+        $today = mktime (0, 0, 0, $tt["mon"], $tt["mday"], $tt["year"]);
+        echo "<A HREF=\"../course/user.php?id=$course->id&user=$user->id\">Contributions</A><BR><BR>";
+        echo "<A HREF=\"../course/log.php?id=$course->id&user=$user->id&date=$today\">Today's logs</A><BR>";
+        echo "<A HREF=\"../course/log.php?id=$course->id&user=$user->id\">All logs</A><BR><BR>";
+        if (isstudent($course->id, $user->id)) {
+            echo "<A HREF=\"../course/loginas.php?id=$course->id&user=$user->id\">Login as</A><BR><BR>";
+        }
+    }
+    echo "<A HREF=\"view.php?id=$user->id&course=$course->id\">Full profile...</A>";
+    echo "</FONT>";
+
+    echo "</TD></TR></TABLE></TD></TR></TABLE>";
+}
+
+?>
diff --git a/user/lib.php b/user/lib.php
new file mode 100644 (file)
index 0000000..4100060
--- /dev/null
@@ -0,0 +1,51 @@
+<?PHP  // $Id$
+
+/// FUNCTIONS ///////////////////////////////////////////////////////////
+
+function userdate($date) {
+    return date("l, j F Y, g:i A T", $date);
+}
+
+function ImageCopyBicubic ($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) {
+
+    if (function_exists("ImageCopyResampled")) {   // Assumes gd >= 2.0.1 as well
+       return ImageCopyResampled($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y,
+                                 $dst_w, $dst_h, $src_w, $src_h);
+    }
+
+    $totalcolors = imagecolorstotal($src_img);
+    for ($i=0; $i<$totalcolors; $i++) { 
+        if ($colors = ImageColorsForIndex($src_img, $i)) {
+            ImageColorAllocate($dst_img, $colors['red'], $colors['green'], $colors['blue']);
+        }
+    }
+
+    $scaleX = ($src_w - 1) / $dst_w; 
+    $scaleY = ($src_h - 1) / $dst_h; 
+
+    $scaleX2 = $scaleX / 2.0; 
+    $scaleY2 = $scaleY / 2.0; 
+
+    for ($j = 0; $j < $dst_h; $j++) { 
+        $sY = $j * $scaleY; 
+
+        for ($i = 0; $i < $dst_w; $i++) { 
+            $sX = $i * $scaleX; 
+
+            $c1 = ImageColorsForIndex($src_img,ImageColorAt($src_img,(int)$sX,(int)$sY+$scaleY2)); 
+            $c2 = ImageColorsForIndex($src_img,ImageColorAt($src_img,(int)$sX,(int)$sY)); 
+            $c3 = ImageColorsForIndex($src_img,ImageColorAt($src_img,(int)$sX+$scaleX2,(int)$sY+$scaleY2)); 
+            $c4 = ImageColorsForIndex($src_img,ImageColorAt($src_img,(int)$sX+$scaleX2,(int)$sY)); 
+
+            $red = (int) (($c1['red'] + $c2['red'] + $c3['red'] + $c4['red']) / 4); 
+            $green = (int) (($c1['green'] + $c2['green'] + $c3['green'] + $c4['green']) / 4); 
+            $blue = (int) (($c1['blue'] + $c2['blue'] + $c3['blue'] + $c4['blue']) / 4); 
+
+            $color = ImageColorClosest ($dst_img, $red, $green, $blue); 
+            ImageSetPixel ($dst_img, $i + $dst_x, $j + $dst_y, $color); 
+        } 
+    } 
+}
+
+
+?>
diff --git a/user/new.php b/user/new.php
new file mode 100644 (file)
index 0000000..4beec74
--- /dev/null
@@ -0,0 +1,41 @@
+<?PHP // $Id$
+
+// Code fragment called by /courses/new.php
+// Prints out a formatted table of all the new things that have happened 
+// with this module (since the user's last login).  Suitable for students.
+
+// Assumes $course and $USER are defined and page has been started.
+
+// First, print all the users who have updated their records.
+
+    if ($users = get_records_sql("SELECT u.* FROM user u, user_students s 
+                                  WHERE u.id = s.user 
+                                        AND s.course = '$course->id' 
+                                        AND u.timemodified > '$USER->lastlogin' ")) {
+   
+        echo "<P><B>Updated User Profiles</B></P>";
+        echo "<FONT SIZE=2><UL>";
+
+        foreach ($users as $user) {
+            echo "<LI><A HREF=\"$CFG->wwwroot/user/view.php?id=$user->id&course=$course->id\">$user->firstname $user->lastname</A>";
+            echo " ".moodledate($user->timemodified);
+        }
+        echo "</UL></FONT>";
+    }
+
+    if ($users = get_records_sql("SELECT u.* FROM user u, user_students s 
+                                  WHERE u.id = s.user 
+                                        AND s.course = '$course->id' 
+                                        AND u.currentlogin > '$USER->lastlogin' ")) {
+   
+        echo "<P><B>User logins</B></P>";
+        echo "<FONT SIZE=2><UL>";
+
+        foreach ($users as $user) {
+            echo "<LI><A HREF=\"$CFG->wwwroot/user/view.php?id=$user->id&course=$course->id\">$user->firstname $user->lastname</A>";
+            echo " ".moodledate($user->currentlogin);
+        }
+        echo "</UL></FONT>";
+    }
+
+?>
diff --git a/user/pix.php b/user/pix.php
new file mode 100644 (file)
index 0000000..7c56d64
--- /dev/null
@@ -0,0 +1,36 @@
+<?PHP // $Id$
+      // This function fetches user pictures from the data directory
+      // Syntax:   file.php/userid/f1.jpg
+
+    require("../config.php");
+
+    $lifetime = 86400;
+
+    if (!$PATH_INFO) {
+        error("This script DEPENDS on $PATH_INFO being available.  Read the README.");
+    }
+
+    $args = get_slash_arguments();
+    $numargs = count($args);
+
+    if ($numargs == 2) {
+        $userid = (integer)$args[0];
+        $image  = $args[1];
+    } else {
+        $userid = 0;
+        $image  = "f1.jpg";
+    }
+
+    $pathname = "$CFG->dataroot/users/$userid/$image";
+    $lastmodified = filemtime($pathname);
+
+    header("Last-Modified: " . gmdate("D, d M Y H:i:s", $lastmodified) . " GMT");
+    header("Expires: " . gmdate("D, d M Y H:i:s", time() + $lifetime) . " GMT");
+    header("Cache-control: max_age = $lifetime"); // a day
+    header("Pragma: ");
+    header("Content-Length: ".filesize($pathname));
+    header("Content-type: image/jpeg");
+    readfile("$pathname");
+
+    exit;
+?>
diff --git a/user/user.gif b/user/user.gif
new file mode 100755 (executable)
index 0000000..33b256e
Binary files /dev/null and b/user/user.gif differ
diff --git a/user/users.gif b/user/users.gif
new file mode 100755 (executable)
index 0000000..2873352
Binary files /dev/null and b/user/users.gif differ
diff --git a/user/view.php b/user/view.php
new file mode 100644 (file)
index 0000000..8dd7855
--- /dev/null
@@ -0,0 +1,115 @@
+<?PHP // $Id$
+
+//  Display profile for a particular user
+
+    require("../config.php");
+    require("lib.php");
+
+    require_variable($id);
+    require_variable($course);
+
+
+    if (! $user = get_record("user", "id", $id) ) {
+        error("No such user in this course");
+    }
+
+    if (! $course = get_record("course", "id", $course) ) {
+        error("No such course id");
+    }
+
+    if ($course->category) {
+        require_login($course->id);
+    }
+
+    $fullname = "$user->firstname $user->lastname";
+
+    add_to_log("View profile: $fullname", $course);
+
+    if ($course->category) {
+        print_header("Personal profile: $fullname", "Personal profile: $fullname", 
+                     "<A HREF=\"../course/view.php?id=$course->id\">$course->shortname</A> -> 
+                      <A HREF=\"index.php?id=$course->id\">Participants</A> -> $fullname", "");
+    } else {
+        print_header("Personal profile: $fullname", "Personal profile: $fullname", "$fullname", "");
+    }
+
+
+    echo "<TABLE WIDTH=80% ALIGN=CENTER BORDER=0 CELLPADDING=1 CELLSPACING=1><TR><TD BGCOLOR=#888888>";
+    echo "<TABLE WIDTH=100% BORDER=0 CELLPADDING=3 CELLSPACING=0><TR>";
+    echo "<TD WIDTH=100 BGCOLOR=\"$THEME->body\" VALIGN=top>";
+    if ($user->picture) {
+        echo "<IMG BORDER=0 ALIGN=left WIDTH=100 SRC=\"pix.php/$user->id/f1.jpg\">";
+    } else {
+        echo "<IMG BORDER=0 ALIGN=left WIDTH=100 SRC=\"default/f1.jpg\">";
+    }
+    echo "</TD><TD WIDTH=100% BGCOLOR=#FFFFFF>";
+
+
+    // Print name and edit button across top
+
+    echo "<TABLE WIDTH=100% BORDER=0 CELLPADDING=0 CELLSPACING=0><TR><TD NOWRAP>";
+    echo "<H3>$user->firstname $user->lastname</H3>";
+    echo "</TD><TD align=right>";
+    if ($id == $USER->id) {
+        echo "<P><FORM ACTION=edit.php METHOD=GET>";
+        echo "<INPUT type=hidden name=id value=\"$id\">";
+        echo "<INPUT type=hidden name=course value=\"$course->id\">";
+        echo "<INPUT type=submit value=\"Edit my profile\">";
+        echo "</FORM></P>";
+    }
+    echo "</TD></TR></TABLE>";
+
+
+
+    // Print the description
+
+    if ($user->description) {
+        echo "<P>".text_to_html($user->description)."</P><HR>";
+    }
+
+
+
+    // Print all the little details in a list
+
+    echo "<TABLE BORDER=0 CELLPADDING=5 CELLSPACING=2";
+
+    print_row("Location:", "$user->city, $user->country");
+
+    if (isteacher($course->id)) {
+        if ($user->address) {
+            print_row("Address:", "$user->address");
+        }
+        if ($user->phone1) {
+            print_row("Phone:", "$user->phone1");
+        }
+        if ($user->phone2) {
+            print_row("Phone:", "$user->phone2");
+        }
+    }
+
+    print_row("Email:", "<A HREF=\"mailto:$user->email\">$user->email</A>");
+
+    if ($user->url) {
+        print_row("Web page:", "<A HREF=\"$user->url\">$user->url</A>");
+    }
+
+    if ($user->icq) {
+        print_row("ICQ:","<A HREF=\"http://wwp.icq.com/$user->icq\">$user->icq <IMG SRC=\"http://online.mirabilis.com/scripts/online.dll?icq=$user->icq&img=5\" WIDTH=18 HEIGHT=18 BORDER=0></A>");
+    }
+
+    $datestring = userdate($user->lastaccess)."&nbsp (".format_time(time() - $user->lastaccess).")";
+    print_row("Last access:", $datestring);
+
+    echo "</TABLE>";
+
+    echo "</TD></TR></TABLE></TABLE>";
+
+    print_footer($course);
+
+/// Functions ///////
+
+function print_row($left, $right) {
+    echo "<TR><TD NOWRAP ALIGN=right><P>$left</TD><TD align=left><P>$right</P></TD></TR>";
+}
+
+?>