Index: mod/quiz/config.html
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/Attic/config.html,v
retrieving revision 1.32.2.4
diff -u -r1.32.2.4 config.html
--- mod/quiz/config.html	21 Dec 2007 14:13:54 -0000	1.32.2.4
+++ mod/quiz/config.html	8 Jun 2009 09:39:27 -0000
@@ -291,11 +291,17 @@
 </tr>
 
 <tr valign="top">
-  <td align="right"><b><?php print_string("popup", "quiz") ?>:</b></td>
+  <td align="right"><b><?php print_string('browsersecurity', 'quiz') ?>:</b></td>
   <td>
     <?php
-       choose_from_menu ($yesnooptions, "popup", $form->popup, "", "", "");
-       helpbutton("popup", get_string("popup","quiz"), "quiz");
+        $browseroptions = array(
+                0 => get_string('none', 'quiz'),
+                1 => get_string('popupwithjavascriptsupport', 'quiz'));
+        if ($CFG->enablesafebrowserintegration) { 
+            $browseroptions[2] = get_string('requiresafeexambrowser', 'quiz');
+        }
+        choose_from_menu ($browseroptions, 'popup', $form->popup, '', '', '');
+        helpbutton('browsersecurity', get_string('browsersecurity', 'quiz'), 'quiz');
     ?>
   </td>
   <td align="center">
Index: mod/quiz/view.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/view.php,v
retrieving revision 1.124.2.18
diff -u -r1.124.2.18 view.php
--- mod/quiz/view.php	27 Jan 2009 04:44:00 -0000	1.124.2.18
+++ mod/quiz/view.php	8 Jun 2009 09:39:29 -0000
@@ -57,7 +57,7 @@
 
     //only check pop ups if the user is not a teacher, and popup is set
 
-    $bodytags = (has_capability('mod/quiz:attempt', $context) && $quiz->popup)?'onload="popupchecker(\'' . get_string('popupblockerwarning', 'quiz') . '\');"':'';
+    $bodytags = (has_capability('mod/quiz:attempt', $context) && $quiz->popup == 1)?'onload="popupchecker(\'' . get_string('popupblockerwarning', 'quiz') . '\');"':'';
     $PAGE->print_header($course->shortname.': %fullname%','',$bodytags);
 
     echo '<table id="layout-table"><tr>';
@@ -405,7 +405,7 @@
             $attempturl = "attempt.php?id=$cm->id";
 
             // Prepare options depending on whether the quiz should be a popup.
-            if (!empty($quiz->popup)) {
+            if ($quiz->popup == 1) {
                 $window = 'quizpopup';
                 $windowoptions = "left=0, top=0, height='+window.screen.height+', " .
                         "width='+window.screen.width+', channelmode=yes, fullscreen=yes, " .
@@ -421,7 +421,9 @@
                     echo "if (confirm('".addslashes_js($strconfirmstartattempt)."')) ";
                 }
                 echo "window.open('$attempturl','$window','$windowoptions');", '" />';
-            } else {
+            } else if ($quiz->popup == 2 && !quiz_check_safe_browser()) {
+                notify(get_string('safebrowsererror', 'quiz'));
+            }else {
                 print_single_button("attempt.php", array('id'=>$cm->id), $buttontext, 'get', '', false, '', false, $strconfirmstartattempt);
             }
 
@@ -483,7 +485,7 @@
     }
 
     $url = "review.php?q=$quiz->id&amp;attempt=$attempt->id";
-    if ($quiz->popup) {
+    if ($quiz->popup == 1) {
         $windowoptions = "left=0, top=0, channelmode=yes, fullscreen=yes, scrollbars=yes, resizeable=no, directories=no, toolbar=no, titlebar=no, location=no, status=no, menubar=no";
         return link_to_popup_window('/mod/quiz/' . $url, 'quizpopup', $linktext, '+window.screen.height+', '+window.screen.width+', '', $windowoptions, true);
     } else {
Index: mod/quiz/attempt_close_js.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/Attic/attempt_close_js.php,v
retrieving revision 1.7
diff -u -r1.7 attempt_close_js.php
--- mod/quiz/attempt_close_js.php	6 Jul 2007 16:37:07 -0000	1.7
+++ mod/quiz/attempt_close_js.php	8 Jun 2009 09:39:27 -0000
@@ -2,7 +2,7 @@
 
 <div class="controls">
 <?php
-if (!empty($popup)) {
+if (!empty($popup) && $popup == 1) {
 ?>
 
 <script type="text/javascript">
Index: mod/quiz/attempt.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/attempt.php,v
retrieving revision 1.131.2.16
diff -u -r1.131.2.16 attempt.php
--- mod/quiz/attempt.php	23 Mar 2009 01:59:18 -0000	1.131.2.16
+++ mod/quiz/attempt.php	8 Jun 2009 09:39:27 -0000
@@ -77,7 +77,7 @@
 
     $strattemptnum = get_string('attempt', 'quiz', $attemptnumber);
     $strquizzes = get_string("modulenameplural", "quiz");
-    $popup = $quiz->popup && !$ispreviewing; // Controls whether this is shown in a javascript-protected window.
+    $popup = $quiz->popup && !$ispreviewing; // Controls whether this is shown in a javascript-protected window or with a safe browser.
 
 /// We intentionally do not check open and close times here. Instead we do it lower down.
 /// This is to deal with what happens when someone submits close to the exact moment when the quiz closes.
@@ -89,6 +89,11 @@
         print_error('nomoreattempts', 'quiz', "view.php?id={$cm->id}");
     }
 
+/// Check safe browser
+    if (!$ispreviewing && $quiz->popup == 2 && !quiz_check_safe_browser()) {
+        print_error('safebrowsererror', 'quiz', "view.php?id={$cm->id}");
+    }
+
 /// Check subnet access
     if (!$ispreviewing && !empty($quiz->subnet) && !address_in_subnet(getremoteaddr(), $quiz->subnet)) {
         print_error("subneterror", "quiz", "view.php?id=$cm->id");
@@ -412,10 +417,12 @@
     require_js($CFG->wwwroot . '/mod/quiz/quiz.js');
     $pagequestions = explode(',', $pagelist);
     $headtags = get_html_head_contributions($pagequestions, $questions, $states);
-    if (!empty($popup)) {
+    if (!$ispreviewing && $quiz->popup) {
         define('MESSAGE_WINDOW', true);  // This prevents the message window coming up
         print_header($course->shortname.': '.format_string($quiz->name), '', '', '', $headtags, false, '', '', false, ' class="securewindow"');
-        include('protect_js.php');
+        if ($quiz->popup == 1) {
+            include('protect_js.php');
+        }
     } else {
         $strupdatemodule = has_capability('moodle/course:manageactivities', $coursecontext)
                     ? update_module_button($cm->id, $course->id, get_string('modulename', 'quiz'))
@@ -439,8 +446,10 @@
         print_single_button($CFG->wwwroot.'/mod/quiz/attempt.php', $buttonoptions, get_string('startagain', 'quiz'));
         echo '</div>';
     /// Notices about restrictions that would affect students.
-        if ($quiz->popup) {
+        if ($quiz->popup == 1) {
             notify(get_string('popupnotice', 'quiz'));
+        } else if ($quiz->popup == 2) {
+            notify(get_string('safebrowsernotice', 'quiz'));
         }
         if ($timestamp < $quiz->timeopen || ($quiz->timeclose && $timestamp > $quiz->timeclose)) {
             notify(get_string('notavailabletostudents', 'quiz'));
Index: mod/quiz/mod_form.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/mod_form.php,v
retrieving revision 1.28.2.8
diff -u -r1.28.2.8 mod_form.php
--- mod/quiz/mod_form.php	16 Apr 2009 03:12:20 -0000	1.28.2.8
+++ mod/quiz/mod_form.php	8 Jun 2009 09:39:28 -0000
@@ -194,8 +194,14 @@
 //-------------------------------------------------------------------------------
         $mform->addElement('header', 'security', get_string('security', 'form'));
 
-        $mform->addElement('selectyesno', 'popup', get_string("popup", "quiz"));
-        $mform->setHelpButton('popup', array("popup", get_string("popup", "quiz"), "quiz"));
+        $options = array(
+                    0 => get_string('none', 'quiz'),
+                    1 => get_string('popupwithjavascriptsupport', 'quiz'));
+        if ($CFG->enablesafebrowserintegration) { 
+            $options[2] = get_string('requiresafeexambrowser', 'quiz');
+        }
+        $mform->addElement('select', 'popup', get_string('browsersecurity', 'quiz'), $options);
+        $mform->setHelpButton('popup', array('browsersecurity', get_string('browsersecurity', 'quiz'), 'quiz'));
         $mform->setAdvanced('popup', $CFG->quiz_fix_popup);
         $mform->setDefault('popup', $CFG->quiz_popup);
 
Index: mod/quiz/review.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/review.php,v
retrieving revision 1.59.2.10
diff -u -r1.59.2.10 review.php
--- mod/quiz/review.php	16 Jan 2009 04:47:35 -0000	1.59.2.10
+++ mod/quiz/review.php	8 Jun 2009 09:39:28 -0000
@@ -40,7 +40,7 @@
     $coursecontext = get_context_instance(CONTEXT_COURSE, $cm->course);
     $isteacher = has_capability('mod/quiz:preview', get_context_instance(CONTEXT_MODULE, $cm->id));
     $options = quiz_get_reviewoptions($quiz, $attempt, $context);
-    $popup = $isteacher ? 0 : $quiz->popup; // Controls whether this is shown in a javascript-protected window.
+    $popup = $isteacher ? 0 : $quiz->popup; // Controls whether this is shown in a javascript-protected window or with a safe browser.
 
     $timenow = time();
     if (!has_capability('mod/quiz:viewreports', $context)) {
@@ -68,15 +68,15 @@
             } else {
                 $message = get_string('noreview', 'quiz');
             }
-            if (empty($popup)) {
-                redirect('view.php?q=' . $quiz->id, $message);
-            } else {
+            if (!empty($popup) && $popup == 1) {
                 ?><script type="text/javascript">
                 opener.document.location.reload();
                 self.close();
                 </script><?php
                 die();
-            }
+            } else {
+                redirect('view.php?q=' . $quiz->id, $message);
+            } 
         }
     }
 
@@ -124,11 +124,12 @@
 /// Print the page header
     $pagequestions = explode(',', $pagelist);
     $headtags = get_html_head_contributions($pagequestions, $questions, $states);
-    if (!empty($popup)) {
+    if (!$ispreviewing && $quiz->popup) {
         define('MESSAGE_WINDOW', true);  // This prevents the message window coming up
         print_header($course->shortname.': '.format_string($quiz->name), '', '', '', $headtags, false, '', '', false, '');
-        /// Include Javascript protection for this page
-        include('protect_js.php');
+        if ($quiz->popup == 1) {
+            include('protect_js.php');
+        }
     } else {
         $strupdatemodule = has_capability('moodle/course:manageactivities', $coursecontext)
                     ? update_module_button($cm->id, $course->id, get_string('modulename', 'quiz'))
Index: mod/quiz/locallib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/locallib.php,v
retrieving revision 1.127.2.14
diff -u -r1.127.2.14 locallib.php
--- mod/quiz/locallib.php	18 Mar 2009 05:16:43 -0000	1.127.2.14
+++ mod/quiz/locallib.php	8 Jun 2009 09:39:28 -0000
@@ -922,4 +922,14 @@
     // return the number of successfully sent emails
     return $emailresult['good'];
 }
-?>
+
+/**
+ * Checks if browser is safe browser
+ * 
+ * @return true, if browser is safe browser else false
+ */
+function quiz_check_safe_browser() {
+    return strpos($_SERVER['HTTP_USER_AGENT'], "SEB") !== false;
+}
+
+?>
\ No newline at end of file
Index: lang/en_utf8/quiz.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lang/en_utf8/quiz.php,v
retrieving revision 1.83.2.14
diff -u -r1.83.2.14 quiz.php
--- lang/en_utf8/quiz.php	5 Jun 2009 06:54:35 -0000	1.83.2.14
+++ lang/en_utf8/quiz.php	8 Jun 2009 09:39:27 -0000
@@ -72,6 +72,7 @@
 $string['blackboard'] = 'Blackboard';
 $string['blackboard_6'] = 'Blackboard V6+';
 $string['braceerror'] = 'Could not find {...} around answers';
+$string['browsersecurity'] = 'Browser security';
 $string['bothattempts'] = 'Show students with and without attempts';
 $string['calculated'] = 'Calculated';
 $string['calculatedquestion'] = 'Calculated Question not supported at line $a. The question will be ignored';
@@ -400,6 +401,7 @@
 $string['popup'] = 'Show quiz in a &quot;secure&quot; window';
 $string['popupblockerwarning'] = 'This section of the test is in secure mode, this means that you need to take the quiz in a secure window. Please turn off your popup blocker. Thank you.';
 $string['popupnotice'] = 'Students will see this quiz in a secure window';
+$string['popupwithjavascriptsupport'] = 'Full screen pop-up with some JavaScript security';
 $string['preview'] = 'Preview';
 $string['previewquestion'] = 'Preview question';
 $string['previewquiz'] = 'Preview $a';
@@ -485,6 +487,7 @@
 $string['reportsimplestat'] = 'Simple statistics';
 $string['requirepassword'] = 'Require password';
 $string['requirepasswordmessage'] = 'To attempt this quiz you need to know the quiz password';
+$string['requiresafeexambrowser'] = 'Require the use of Safe Exam Browser';
 $string['requiresubnet'] = 'Require network address';
 $string['response'] = 'Response';
 $string['responses'] = 'Responses';
@@ -506,6 +509,8 @@
 $string['reviewresponsetoq'] = 'Review response (question $a)';
 $string['rqp'] = 'Remote Question';
 $string['rqps'] = 'Remote Questions';
+$string['safebrowsererror']='This quiz has been set up so that it may only be attempted using the Safe Exam Browser. You cannot attempt it form this web browser.';
+$string['safebrowsernotice']='This quiz has been configured so that students may only attempt it using the Safe Exam Browser.';
 $string['save'] = 'Save';
 $string['saveandedit'] = 'Save changes and edit questions';
 $string['savedfromdeletedcourse'] = 'Saved from deleted course \"$a\"';
Index: lang/en_utf8/admin.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lang/en_utf8/admin.php,v
retrieving revision 1.154.2.91
diff -u -r1.154.2.91 admin.php
--- lang/en_utf8/admin.php	3 Jun 2009 21:19:05 -0000	1.154.2.91
+++ lang/en_utf8/admin.php	8 Jun 2009 09:39:26 -0000
@@ -118,6 +118,7 @@
 $string['configenablerssfeeds'] = 'This switch will enable RSS feeds from across the site.  To actually see any change you will need to enable RSS feeds in the individual modules too - go to the Modules settings under Admin Configuration.';
 $string['configenablerssfeedsdisabled'] = 'It is not available because RSS feeds are disabled in all the Site. To enable them, go to the Variables settings under Admin Configuration.';
 $string['configenablerssfeedsdisabled2'] = 'RSS feeds are disabled at the server level. You need to enable them first in Server/RSS.';
+$string['configenablesafebrowserintegration'] = 'This adds the choice \'Require Safe Exam Browser\' to the \'Browser security\' field on the quiz settings form. See http://www.safeexambrowser.org/ for more information.';
 $string['configenablestats'] = 'If you choose \'yes\' here, Moodle\'s cronjob will process the logs and gather some statistics.  Depending on the amount of traffic on your site, this can take awhile. If you enable this, you will be able to see some interesting graphs and statistics about each of your courses, or on a sitewide basis.';
 $string['configenabletrusttext'] = 'By default Moodle will always thoroughly clean text that comes from users to remove any possible bad scripts, media etc that could be a security risk.  The Trusted Content system is a way of giving particular users that you trust the ability to include these advanced features in their content without interference.  To enable this system, you need to first enable this setting, and then grant the Trusted Content permission to a specific Moodle role.  Texts created or uploaded by such users will be marked as trusted and will not be cleaned before display.';
 $string['configenrolmentplugins'] = 'Please choose the enrolment plugins you wish to use. Don\'t forget to configure the settings properly.<br /><br />You have to indicate which plugins are enabled, and <strong>one</strong> plugin can be set as the default plugin for <em>interactive</em> enrolment. To disable interactive enrolment, set \"enrollable\" to \"No\" in required courses.';
@@ -357,6 +358,7 @@
 $string['enablehtmlpurifier'] = 'Enable HTML Purifier';
 $string['enablerecordcache'] = 'Enable Record Cache';
 $string['enablerssfeeds'] = 'Enable RSS feeds';
+$string['enablesafebrowserintegration'] = 'Enable Safe Exam Browser integration';
 $string['enablestats'] = 'Enable statistics';
 $string['enabletrusttext'] = 'Enable Trusted Content';
 $string['encoding'] = 'Encoding';
Index: admin/settings/misc.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/settings/Attic/misc.php,v
retrieving revision 1.14.2.5
diff -u -r1.14.2.5 misc.php
--- admin/settings/misc.php	9 Mar 2009 23:30:55 -0000	1.14.2.5
+++ admin/settings/misc.php	8 Jun 2009 09:39:25 -0000
@@ -16,6 +16,7 @@
     $rqsetting->plugin = 'qtype_random';
     $temp->add($rqsetting);
     $temp->add(new admin_setting_configcheckbox('experimentalsplitrestore', get_string('experimentalsplitrestore', 'admin'), get_string('configexperimentalsplitrestore', 'admin'), 0));
+    $temp->add(new admin_setting_configcheckbox('enablesafebrowserintegration', get_string('enablesafebrowserintegration', 'admin'), get_string('configenablesafebrowserintegration', 'admin'), 0));
 
     $ADMIN->add('misc', $temp);
 
Index: lang/en_utf8/help/quiz/browsersecurity.html
===================================================================
RCS file: lang/en_utf8/help/quiz/browsersecurity.html
diff -N lang/en_utf8/help/quiz/browsersecurity.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lang/en_utf8/help/quiz/browsersecurity.html	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,56 @@
+<h1>Browser security</h1>
+
+<p>This option offers various ways to try to restrict how students may try to 'cheat'
+while attempting a quiz. However, this is not a simple issue, and what in one situation
+is considered 'cheating' may, in another situation, just be effective use of information
+technology. (For example, the ability to quickly find answers using a search engine.)</p>
+
+<p>Note also that this is not just at problem of technology with a technical solution.
+Cheating has been going on since long before computers, and while computers make certain
+actions, like copy and paste, easier, they also make it easier for teachers to detect
+cheating - for example using the quiz reports. The options provided here are not fool-proof,
+and while they do make some forms of cheating harder for students, they also make it more
+inconvenient for students to attempt the quizzes, and they are not fool-proof.</p>
+
+<p>You should alos consider other ways to make it harder for students to cheat at your quiz:</p>
+<ul>
+<li>You can use a large question bank, which the quiz picking a selection of questions randomly,
+so different students see different, but similar questions.</li>
+<li>You can use the shuffle answers option, so that the right answer to question 1 is not always option A.</li>
+<li>You can ask questions that required students to analyse the given information, rather than just recalling facts.</li>
+</p>
+
+<p>With the above warnings in mind, here is the description of the available options.</p>
+
+<h3>None</h3>
+
+<p>No impediments are put in the way of students attempting the quiz.</p>
+
+<h3>Full screen pop-up with some JavaScript security</h3>
+
+<p>There is a limit to what the quiz, with runs on a web server, can do to restrict
+what the student sitting at their computer can do while attempting the quiz. However,
+this option does what is possible:</p>
+<ul>
+    <li>The quiz will only start if the student has a JavaScript-enabled web-browser.</li>
+    <li>The quiz appears in a fullscreen popup window that covers all the other windows and has no navigation controls.</li>
+    <li>The students are prevented, as far as is possible, from using facilities like copy and paste.</li>
+</ul>
+
+<h3>Require the use of Safe Exam Browser</h3>
+
+<p>This option will only appear if your adminstrator has enabled it.</p>
+
+<p><a href="http://www.safeexambrowser.org/">Safe Exam Browser</a> is a customised web browser that must be
+downloaded an installed on the computer that the student uses to attempt the quiz. The restrictions placed on
+students are similar to those in pop-up window case, but because Safe Exam Browser is software running
+on the student's computer, it can do a much more effective job of restricting their actions. If you select this option:</p>
+<ul>
+    <li>Students will only be able to attempt the quiz if they are using Safe Exam Browser.</li>
+    <li>The browser window will be fullscreen (without any navigation elements).</li>
+    <li>The window cannot be closed until the test is submitted.</li>
+    <li>Shortcuts keys such as Win, Ctrl+Alt+Del, Alt+F4, F1, Ctrl+P, Printscreen, are disabled.</li>
+    <li>Copy and paste, and the context menu, are disabled.</li>
+    <li>Switching to other applications is disabled.</li>
+    <li>Surfing to other web sites is prohibited.</li>
+</ul>
