diff -u -r ./admin/roles/tabs.php ../contrib/admin/roles/tabs.php
--- ./admin/roles/tabs.php	2008-12-31 21:31:17.000000000 -0800
+++ ../contrib/admin/roles/tabs.php	2008-12-31 21:32:04.000000000 -0800
@@ -162,6 +162,12 @@
                 }
             }
             break;
+        
+        case CONTEXT_PAGE:
+            if ($page = get_record('page', 'id', $context->instanceid)) {
+                print_header($page->fullname, $page->fullname, build_navigation(array()));
+            }
+            break;
 
         default:
             print_error('unknowncontext');
diff -u -r ./lib/accesslib.php ../contrib/lib/accesslib.php
--- ./lib/accesslib.php	2008-12-31 20:49:30.000000000 -0800
+++ ../contrib/lib/accesslib.php	2008-12-31 21:24:23.000000000 -0800
@@ -146,6 +146,7 @@
 define('CONTEXT_GROUP', 60);
 define('CONTEXT_MODULE', 70);
 define('CONTEXT_BLOCK', 80);
+define('CONTEXT_PAGE', 90);
 
 // capability risks - see http://docs.moodle.org/en/Development:Hardening_new_Roles_system
 define('RISK_MANAGETRUST', 0x0001);
@@ -2124,6 +2125,9 @@
                 } else if ($parent = get_context_instance(CONTEXT_COURSE, $bi->pageid)) {
                     $basepath  = $parent->path;
                     $basedepth = $parent->depth;
+                } else if ($parent = get_context_instance(CONTEXT_PAGE, $bi->pageid)) {
+                    $basepath  = $parent->path;
+                    $basedepth = $parent->depth;
                 } else {
                     // parent course does not exist - course blocks can not exist without a course
                     $error_message = 'parent course does not exist - course blocks can not exist without a course';
@@ -2138,6 +2142,9 @@
         case CONTEXT_USER:
             // default to basepath
             break;
+        case CONTEXT_PAGE:
+            // default to basepath
+            break;
     }
 
     // if grandparents unknown, maybe rebuild_context_path() will solve it later
@@ -2330,6 +2337,17 @@
         $DB->execute($sql);
 
     }
+    
+    if (empty($contextlevel) or $contextlevel == CONTEXT_PAGE) {
+        $sql = "INSERT INTO {$CFG->prefix}context (contextlevel, instanceid)
+                SELECT ".CONTEXT_PAGE.", p.id
+                  FROM  {page} p
+                 WHERE NOT EXISTS (SELECT 'x'
+                                     FROM {$CFG->prefix}context cx
+                                    WHERE u.id = cx.instanceid AND cx.contextlevel=".CONTEXT_PAGE.")";
+        execute_sql($sql, $feedback);
+
+    }
 
     if ($buildpaths) {
         build_context_path(false);
@@ -2385,6 +2403,13 @@
                 LEFT OUTER JOIN {groups} t
                      ON c.instanceid = t.id
                WHERE t.id IS NULL AND c.contextlevel = ".CONTEXT_GROUP."
+            UNION
+              SELECT c.contextlevel,
+                     c.instanceid
+                FROM {context} c
+                LEFT OUTER JOIN {page} t
+                     ON c.instanceid = t.id
+               WHERE t.id IS NULL AND c.contextlevel = ".CONTEXT_PAGE."
            ";
     if ($rs = $DB->get_recordset_sql($sql)) {
         $DB->begin_sql();
@@ -2462,7 +2487,7 @@
 function get_context_instance($contextlevel, $instance=0) {
 
     global $context_cache, $context_cache_id, $DB;
-    static $allowed_contexts = array(CONTEXT_SYSTEM, CONTEXT_USER, CONTEXT_COURSECAT, CONTEXT_COURSE, CONTEXT_GROUP, CONTEXT_MODULE, CONTEXT_BLOCK);
+    static $allowed_contexts = array(CONTEXT_SYSTEM, CONTEXT_USER, CONTEXT_COURSECAT, CONTEXT_COURSE, CONTEXT_GROUP, CONTEXT_MODULE, CONTEXT_BLOCK, CONTEXT_PAGE);
 
     if ($contextlevel === 'clearcache') {
         // TODO: Remove for v2.0
@@ -3404,7 +3429,8 @@
             CONTEXT_COURSECAT => get_string('category'),
             CONTEXT_COURSE => get_string('course'),
             CONTEXT_MODULE => get_string('activitymodule'),
-            CONTEXT_BLOCK => get_string('block')
+            CONTEXT_BLOCK => get_string('block'),
+            CONTEXT_PAGE => get_string('page')
         );
     }
     return $strcontextlevels[$contextlevel];
@@ -3501,6 +3527,12 @@
                 }
             }
             break;
+        
+        case CONTEXT_PAGE:
+            if($page = get_record('page', 'id', $context->instanceid)) {
+                $name = format_string($page->fullname);
+            }
+            break;
 
         default:
             print_error('unknowncontext');
@@ -3549,6 +3581,10 @@
                 $url = $CFG->wwwroot . '/mod/' . $modname . '/view.php?id=' . $context->instanceid;
             }
             break;
+        
+        case CONTEXT_PAGE:
+            $url = $CFG->wwwroot . '/page/view.php?id=' . $context->instanceid;
+            break;
 
         case CONTEXT_SYSTEM:
         case CONTEXT_GROUP:
@@ -3634,6 +3670,12 @@
                       FROM {capabilities}
                      WHERE contextlevel IN (".CONTEXT_COURSE.",".CONTEXT_MODULE.",".CONTEXT_BLOCK.")";
         break;
+        
+        case CONTEXT_PAGE: // page context and below
+            $SQL = "SELECT *
+                      FROM {capabilities}
+                     WHERE contextlevel IN (".CONTEXT_PAGE.",".CONTEXT_BLOCK.")";
+        break;
 
         case CONTEXT_MODULE: // mod caps
             $cm = $DB->get_record('course_modules', array('id'=>$context->instanceid));
@@ -3809,6 +3851,7 @@
             LEFT JOIN {course} c ON ctx.contextlevel = 50 AND c.id = ctx.instanceid
             LEFT JOIN {course_modules} cm ON ctx.contextlevel = 70 AND cm.id = ctx.instanceid
             LEFT JOIN {block_instance} bi ON ctx.contextlevel = 80 AND bi.id = ctx.instanceid
+            LEFT JOIN {page} p ON ctx.contextlevel = 90 AND p.id = ctx.instanceid
             $select
             ORDER BY ctx.contextlevel, bi.position, COALESCE(cat.sortorder, c.sortorder, cm.section, bi.weight), u.lastname, u.firstname, cm.id
             ", $params);
@@ -3921,6 +3964,24 @@
 
             return $DB->get_records_sql($sql);
         break;
+        
+        case CONTEXT_PAGE:
+            // Find
+            // - blocks assigned to the page explicitly - easy
+            $sql = " SELECT ctx.*
+                     FROM {$CFG->prefix}context ctx
+                     WHERE ctx.path LIKE '{$context->path}/%'
+                           AND ctx.contextlevel IN (".CONTEXT_BLOCK.")
+            ";
+            $rs  = get_recordset_sql($sql);
+            $records = array();
+            while ($rec = rs_fetch_next_record($rs)) {
+                $records[$rec->id] = $rec;
+                $context_cache[$rec->contextlevel][$rec->instanceid] = $rec;
+            }
+            rs_close($rs);
+            return $records;
+        break;
 
         default:
             print_error('unknowcontext', '', '', $context->contextlevel);
@@ -4098,6 +4159,10 @@
                 $string = get_string('blockname', 'block_'.basename($component));
             }
         break;
+        
+        case CONTEXT_PAGE:
+            $string = get_string('page');
+        break;
 
         default:
             print_error('unknowncontext');
diff -u -r ./lib/db/access.php ../contrib/lib/db/access.php
--- ./lib/db/access.php	2009-01-04 22:05:09.000000000 -0800
+++ ../contrib/lib/db/access.php	2009-01-04 22:06:35.000000000 -0800
@@ -1315,6 +1315,52 @@
             'coursecreator' => CAP_ALLOW
         )
     )
+
+    
+    /***************************
+     **   Page System Roles   **
+     ***************************/
+    
+    'moodle/page:create' => array(
+
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'legacy' => array(
+            'admin' => CAP_ALLOW
+        )
+    ),
+
+    'moodle/page:delete' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'legacy' => array(
+            'admin' => CAP_ALLOW
+        )
+    ),
+
+    'moodle/page:update' => array(
+
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'legacy' => array(
+            'admin' => CAP_ALLOW
+        )
+    ),
+    
+    'moodle/page:visibility' => array(
+
+        'riskbitmask' => RISK_SPAM | RISK_PERSONAL,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'legacy' => array(
+            'admin' => CAP_ALLOW
+        )
+    ),
 );
 
 
diff -u -r ./lib/db/install.xml ../contrib/lib/db/install.xml
--- ./lib/db/install.xml	2009-01-04 22:05:29.000000000 -0800
+++ ../contrib/lib/db/install.xml	2009-01-04 22:08:37.000000000 -0800
@@ -245,6 +245,24 @@
         <INDEX NAME="module" UNIQUE="false" FIELDS="module" PREVIOUS="course"/>
       </INDEXES>
     </TABLE>
+    <TABLE NAME="page" COMMENT="Main Content Pages" PREVIOUS="course_allowed_modules" NEXT="event">
+      <FIELDS>
+        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" ENUM="false" NEXT="fullname"/>
+        <FIELD NAME="fullname" TYPE="char" LENGTH="254" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="id" NEXT="shortname"/>
+        <FIELD NAME="shortname" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="fullname" NEXT="content"/>
+        <FIELD NAME="content" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" ENUM="false" PREVIOUS="shortname" NEXT="visible"/>
+        <FIELD NAME="visible" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" ENUM="false" PREVIOUS="content" NEXT="lang"/>
+        <FIELD NAME="lang" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="visible" NEXT="theme"/>
+        <FIELD NAME="theme" TYPE="char" LENGTH="50" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="lang" NEXT="timecreated"/>
+        <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="theme" NEXT="timemodified"/>
+        <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="timecreated"/>
+      </FIELDS>
+      <KEYS>
+        <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
+      </KEYS>
+      <INDEXES>
+      </INDEXES>
+    </TABLE>
     <TABLE NAME="event" COMMENT="For everything with a time associated to it" PREVIOUS="course_allowed_modules" NEXT="cache_filters">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" ENUM="false" NEXT="name"/>
