Index: moodle/admin/uploaduser.php
--- moodle/admin/uploaduser.php Base (1.104)
+++ moodle/admin/uploaduser.php Locally Modified (Based On 1.104)
@@ -268,10 +268,8 @@
         }
 
         // normalize username
-        $user->username = $textlib->strtolower($user->username);
-        if (empty($CFG->extendedusernamechars)) {
-            $user->username = preg_replace('/[^(-\.[:alnum:])]/i', '', $user->username);
-        }
+        $user->username = clean_param($user->username, PARAM_USERNAME);
+
         if (empty($user->username)) {
             $upt->track('status', get_string('missingfield', 'error', 'username'), 'error');
             $upt->track('username', $errorstr, 'error');
@@ -754,36 +752,106 @@
 $helpicon->page = 'uploadusers2';
 echo $OUTPUT->heading_with_help($helpicon);
 
-$ci = 0;
 $ri = 0;
-
-echo '<table id="uupreview" class="generaltable boxaligncenter" summary="'.get_string('uploaduserspreview', 'admin').'">';
-echo '<tr class="heading r'.$ri++.'">';
-foreach ($columns as $col) {
-    echo '<th class="header c'.$ci++.'" scope="col">'.s($col).'</th>';
-}
-echo '</tr>';
-
 $cir->init();
+
+$filerows = array();
 while ($fields = $cir->next()) {
+    $ci = 0;
     if ($ri > $previewrows) {
-        echo '<tr class="r'.$ri++.'">';
+        $arow .= '<tr class="r'.$ri++.'">';
         foreach ($fields as $field) {
-            echo '<td class="cell c'.$ci++.'">...</td>';;
+            $arow .= '<td class="cell c'.$ci++.'">...</td>';
         }
+        $arow .= '</tr>';
         break;
     }
-    $ci = 0;
-    echo '<tr class="r'.$ri++.'">';
-    foreach ($fields as $field) {
-        echo '<td class="cell c'.$ci++.'">'.s($field).'</td>';;
+
+    $arow = '';
+    $errormsg = array();
+    $filerows[$ri] = array();
+    $arow .= '<tr class="r'.$ri.'">';
+    foreach ($fields as $key => $field) {
+        $errorclass = '';
+        if ($ci == 0) { //username field
+            $newusername = clean_param($field, PARAM_USERNAME);
+            if (strcmp($field, $newusername) != 0){
+                $errorclass = 'uuerror';
+                $errormsg[] = get_string('invalidusernameupload');
+            } else if ($DB->record_exists('user', array('username'=>$field)) || $DB->record_exists('user', array('username'=>$field)) ) {
+                $errorclass = 'uuerror';
+                $errormsg[] = get_string('usernameexists');
     }
-    echo '</tr>';
+        } else {
+            if ($ci == 4) {     //email field
+                if ($DB->record_exists('user', array('email'=>$field))) {
+                    $errorclass = 'uuerror';
+                    $errormsg[] = get_string('emailexists');
+
+                } else if (validate_email($usernew->email)) {
+                    $errorclass = 'uuerror';
+                    $errormsg[] = get_string('invalidemail');
 }
+            }
+        }
+        $arow .= '<td class="cell c'.$ci++.'">';
+        $arow .= '<div class="'.$errorclass.'">'.s($field). '</div>';
+        $arow .= '</td>';
+
+        if ($key == (count($fields) - 1) && !empty($errormsg)) {
+            $errormsg =  implode('<br />', $errormsg);
+            $arow .=  '<td>' . $errormsg . '</td>';
+            $filerows[$ri]['error'] = $errormsg;            
+        } 
+    }
+    $arow .= '</tr>';
+   $filerows[$ri]['content'] = $arow;
+   $ri++;
+}                          
 $cir->close();
 
+$validcontent = array();
+$invalidcontent = array();
+foreach ($filerows as $arow) {
+    if (array_key_exists('error', $arow)){
+        $invalidcontent[] = $arow['content'];
+        $mform = new admin_uploaduser_form3();
+    } else {
+        $validcontent[] = $arow['content'];
+    }
+}
+
+$ri = 0;
+$ci = 0;
+echo '<table id="uupreview" class="generaltable boxaligncenter" summary="'.get_string('uploaduserspreview', 'admin').'">';
+echo '<tr class="heading r'.$ri++.'">';
+foreach ($columns as $col) {
+    echo '<th class="header c'.$ci++.'" scope="col">'.s($col).'</th>';
+}
+if (!empty($invalidcontent)) {
+    echo '<th class="header c'.$ci++.'" scope="col">'.moodle_strtolower(get_string('error', 'moodle')).'</th>';
+}
+echo '</tr>';
+
+$countcontent = 0;
+if (empty($invalidcontent)) {
+    $countcontent = count($validcontent);
+    echo implode('', $validcontent);
+} else {
+    $countcontent = count($invalidcontent);
+    echo implode('', $invalidcontent);
+}
 echo '</table>';
-echo '<div class="centerpara">'.get_string('uupreprocessedcount', 'admin', $readcount).'</div>';
+
+if (!empty($invalidcontent)) {
+    echo '<div class="centerpara">'.get_string('uploadinvalidpreprocessedcount', 'moodle', $countcontent).'</div>';
+    echo '<div class="">'.get_string('invalidusername', 'moodle').'</div>';
+    echo '<div class="">'.get_string('uploadfilecontainerror', 'moodle').'</div>';
+} else {
+    echo '<div class="">'.get_string('uupreprocessedcount', 'admin', $countcontent).'</div>';
+}
+
+//echo '<div class="centerpara">'.get_string('uupreprocessedcount', 'admin', $readcount).'</div>';
 $mform->display();
 echo $OUTPUT->footer();
 die;
@@ -828,10 +896,13 @@
         }
         $ci = 0;
         $ri = 1;
-        echo '<tr class="r'.$ri++.'">';
-        foreach ($this->_row as $field) {
+        echo '<tr class="r'.$ri.'">';
+        foreach ($this->_row as $key=>$field) {
             foreach ($field as $type=>$content) {
                 if ($field[$type] !== '') {
+                    if ($key == 'username' && $type == 'normal') {
+                        $field[$type] = clean_param($field[$type], PARAM_USERNAME);
+                    }
                     $field[$type] = '<span class="uu'.$type.'">'.$field[$type].'</span>';
                 } else {
                     unset($field[$type]);
Index: moodle/admin/uploaduser_form.php
--- moodle/admin/uploaduser_form.php Base (1.15)
+++ moodle/admin/uploaduser_form.php Locally Modified (Based On 1.15)
@@ -353,3 +353,10 @@
     }
 }
 
+class admin_uploaduser_form3 extends moodleform {
+    function definition (){
+        global $CFG, $USER;
+        $mform =& $this->_form;        
+        $this->add_action_buttons(false, get_string('uploadnewfile'));
+    }
+}


Index: moodle/lang/en_utf8/moodle.php
--- moodle/lang/en_utf8/moodle.php Base (1.269)
+++ moodle/lang/en_utf8/moodle.php Locally Modified (Based On 1.269)
@@ -112,7 +112,9 @@
 $string['allparticipants'] = 'All participants';
 $string['allteachers'] = 'All teachers';
 $string['alphabet'] = 'A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z';
-$string['alphanumerical'] = 'Can only contain alphabetical letters or numbers';
+$string['alphanumerical'] = 'Can only contain alphanumeric characters, hyphen (-) or  period (.)';
+$string['invalidusername'] = 'The username can only contain alphanumeric lowercase characters, underscore (_), hyphen (-), period (.) or at symbol (@)';
+$string['invalidusernameupload'] = "Invalid username";
 $string['alreadyconfirmed'] = 'Registration has already been confirmed';
 $string['always'] = 'Always';
 $string['and'] = '$a->one and $a->two';
@@ -1677,6 +1679,9 @@
 $string['uploadserverlimit'] = 'Uploaded file exceeded the maximum size limit set by the server';
 $string['uploadthisfile'] = 'Upload this file';
 $string['uploadusers'] = 'Upload users';
+$string['uploadnewfile'] = 'Upload new file';
+$string['uploadinvalidpreprocessedcount'] = 'Number of invalid preprocessed records: $a';
+$string['uploadfilecontainerror'] = 'The uploaded file has not been submitted due to invalid information.  Please modify the file and re-upload.  ';
 $string['url'] = 'URL';
 $string['used'] = 'Used';
 $string['usedinnplaces'] = 'Used in $a places';

Index: moodle/lib/moodlelib.php
--- moodle/lib/moodlelib.php Base (1.1271)
+++ moodle/lib/moodlelib.php Locally Modified (Based On 1.1271)
@@ -219,6 +219,10 @@
  */
 define('PARAM_URL',      'url');
 
+/**
+ * PARAM_USERNAME - Clean username to only contains specified characters.
+ */
+define('PARAM_USERNAME',    'username');
 
 
 ///// DEPRECATED PARAM TYPES OR ALIASES - DO NOT USE FOR NEW CODE  /////
@@ -463,6 +467,7 @@
  * @uses PARAM_BASE64
  * @uses PARAM_TAG
  * @uses PARAM_SEQUENCE
+ * @uses PARAM_USERNAME
  * @param mixed $param the variable we are cleaning
  * @param int $type expected format of param after cleaning.
  * @return mixed
@@ -720,6 +725,17 @@
                 return '';  // Specified theme is not installed
             }
 
+        case PARAM_USERNAME:
+            $param = str_replace(" " , "", $param);
+            if (empty($CFG->extendedusernamechars)) {                                                              
+                // regular expression, eliminate all chars EXCEPT:
+                // alphanum, dash (-), underscore (_), at sign (@) and period (.) characters.
+                $param = preg_replace('/[^-\.@_a-z0-9]/', '', $param);
+            } else {
+                $param = preg_replace('/[A-Z]/', '', $param);
+            }
+            return $param;
+
         default:                 // throw error, switched parameters in optional_param or another serious problem
         print_error("unknownparamtype", '', '', $type);
     }
Index: moodle/lib/simpletest/testmoodlelib.php
--- moodle/lib/simpletest/testmoodlelib.php Base (1.29)
+++ moodle/lib/simpletest/testmoodlelib.php Locally Modified (Based On 1.29)
@@ -266,6 +266,7 @@
      * @uses PARAM_LOCALURL
      * @uses PARAM_CLEANHTML
      * @uses PARAM_SEQUENCE
+     * @uses PARAM_USERNAME
      * @param mixed $param the variable we are cleaning
      * @param int $type expected format of param after cleaning.
      * @return mixed
@@ -295,6 +296,35 @@
         $this->assertEqual(clean_param('/just/a/path', PARAM_LOCALURL), '/just/a/path');
         $this->assertEqual(clean_param('funny:thing', PARAM_LOCALURL), '');
         $this->assertEqual(clean_param('course/view.php?id=3', PARAM_LOCALURL), 'course/view.php?id=3');
+
+        $currentstatus =  $CFG->extendedusernamechars;
+        
+        // Run tests with extended character == FALSE;
+        $CFG->extendedusernamechars = FALSE;
+        $this->assertEqual(clean_param('johndoe123', PARAM_USERNAME), 'johndoe123' );
+        $this->assertEqual(clean_param('john.doe', PARAM_USERNAME), 'john.doe');
+        $this->assertEqual(clean_param('john-doe', PARAM_USERNAME), 'john-doe');
+        $this->assertEqual(clean_param('john- doe', PARAM_USERNAME), 'john-doe');
+        $this->assertEqual(clean_param('john_doe', PARAM_USERNAME), 'john_doe');
+        $this->assertEqual(clean_param('john@doe', PARAM_USERNAME), 'john@doe');
+        $this->assertEqual(clean_param('john~doe', PARAM_USERNAME), 'johndoe');
+        $this->assertEqual(clean_param('john´doe', PARAM_USERNAME), 'johndoe');
+        $this->assertEqual(clean_param('john#$%&() ', PARAM_USERNAME), 'john');
+        $this->assertEqual(clean_param('JOHNdóé ', PARAM_USERNAME), 'd');
+        $this->assertEqual(clean_param('john.,:;-_/|\ñÑ[]A_X-,D {} ~!@#$%^&*()_+ ?><[] ščřžžý ?ýá?ý??doe ', PARAM_USERNAME), 'john.-__-@_doe');
+        
+
+        // Test success condition, if extendedusernamechars == ENABLE;
+        $CFG->extendedusernamechars = TRUE;
+        $this->assertEqual(clean_param('john_doe', PARAM_USERNAME), 'john_doe');
+        $this->assertEqual(clean_param('john@doe', PARAM_USERNAME), 'john@doe');
+        $this->assertEqual(clean_param('john# $%&()+_^', PARAM_USERNAME), 'john#$%&()+_^');
+        $this->assertEqual(clean_param('john~doe', PARAM_USERNAME), 'john~doe');
+        $this->assertEqual(clean_param('joHN´doe', PARAM_USERNAME), 'jo´doe');
+        $this->assertEqual(clean_param('johnDOE', PARAM_USERNAME), 'john');
+        $this->assertEqual(clean_param('johndóé ', PARAM_USERNAME), 'johndóé');
+                
+        $CFG->extendedusernamechars = $currentstatus;
     }
 
     function test_validate_param() {
Index: moodle/login/index.php
--- moodle/login/index.php Base (1.168)
+++ moodle/login/index.php Locally Modified (Based On 1.168)
@@ -115,7 +115,7 @@
     $frm->username = trim(moodle_strtolower($frm->username));
 
     if (is_enabled_auth('none') && empty($CFG->extendedusernamechars)) {
-        $string = preg_replace("~[^(-\.[:alnum:])]~i", "", $frm->username);
+        $string = clean_param($frm->username, PARAM_USERNAME);
         if (strcmp($frm->username, $string)) {
             $errormsg = get_string('username').': '.get_string("alphanumerical");
             $errorcode = 2;

Index: moodle/login/signup_form.php
--- moodle/login/signup_form.php Base (1.44)
+++ moodle/login/signup_form.php Locally Modified (Based On 1.44)
@@ -85,7 +85,6 @@
     function definition_after_data(){
         $mform =& $this->_form;

-        $mform->applyFilter('username', 'moodle_strtolower');
         $mform->applyFilter('username', 'trim');
     }
 
@@ -98,13 +98,18 @@
         if ($DB->record_exists('user', array('username'=>$data['username'], 'mnethostid'=>$CFG->mnet_localhost_id))) {
             $errors['username'] = get_string('usernameexists');
         } else {
+            //check allowed characters            
+            if ($data['username'] !== moodle_strtolower($data['username'])) {
+                $errors['username'] = get_string('usernamelowercase');
+            } else {
             if (empty($CFG->extendedusernamechars)) {
-                $string = preg_replace("~[^(-\.[:alnum:])]~i", '', $data['username']);
+                    $string = clean_param($data['username'], PARAM_USERNAME);
                 if (strcmp($data['username'], $string)) {
-                    $errors['username'] = get_string('alphanumerical');
+                        $errors['username'] = get_string('invalidusername');
                 }
             }
         }
+        }
 
         //check if user exists in external db
         //TODO: maybe we should check all enabled plugins instead
 

Index: moodle/user/editadvanced.php
--- moodle/user/editadvanced.php Base (1.64)
+++ moodle/user/editadvanced.php Locally Modified (Based On 1.64)
@@ -136,7 +136,7 @@
         $authplugin = get_auth_plugin($usernew->auth);
     }
 
-    $usernew->username     = trim($usernew->username);
+    $usernew->username = clean_param($usernew->username, PARAM_USERNAME);
     $usernew->timemodified = time();
 
     if ($usernew->id == -1) {
Index: moodle/user/editadvanced_form.php
--- moodle/user/editadvanced_form.php Base (1.35)
+++ moodle/user/editadvanced_form.php Locally Modified (Based On 1.35)
@@ -145,9 +145,9 @@
                 $err['username'] = get_string('usernamelowercase');
             } else {
                 if (empty($CFG->extendedusernamechars)) {
-                    $string = preg_replace("/[^(-\.[:alnum:])]/i", '', $usernew->username);
+                    $string = clean_param($usernew->username, PARAM_USERNAME);
                     if ($usernew->username !== $string) {
-                        $err['username'] = get_string('alphanumerical');
+                        $err['username'] = get_string('invalidusername');
                     }
                 }
             }

Index: moodle/auth/cas/auth.php
--- moodle/auth/cas/auth.php Base (1.41)
+++ moodle/auth/cas/auth.php Locally Modified (Based On 1.41)
@@ -863,6 +863,7 @@
                     $user->lang = $CFG->lang;
                 }

+                //TODO - username required to use PARAM_USERNAME before inserting into user table (MDL-16919)
                 if ($id = $DB->insert_record('user', $user)) {
                     echo "\t"; print_string('auth_dbinsertuser', 'auth_db', array($user->username, $id)); echo "\n";
                     $userobj = $this->update_user_record($user->username);
Index: moodle/auth/db/auth.php
--- moodle/auth/db/auth.php Base (1.44)
+++ moodle/auth/db/auth.php Locally Modified (Based On 1.44)
@@ -364,6 +364,8 @@
                     $user->id = $old_user->id;
                     $DB->set_field('user', 'deleted', 0, array('username'=>$user->username));
                     echo "\t"; print_string('auth_dbreviveuser', 'auth_db', array($user->username, $user->id)); echo "\n";
+
+                //TODO - username required to use PARAM_USERNAME before inserting into user table (MDL-16919)
                 } elseif ($id = $DB->insert_record ('user',$user)) { // it is truly a new user
                     echo "\t"; print_string('auth_dbinsertuser','auth_db',array($user->username, $id)); echo "\n";
                     // if relevant, tag for password generation
Index: moodle/auth/email/auth.php
--- moodle/auth/email/auth.php Base (1.23)
+++ moodle/auth/email/auth.php Locally Modified (Based On 1.23)
@@ -79,6 +79,7 @@

         $user->password = hash_internal_user_password($user->password);

+        //TODO - username required to use PARAM_USERNAME before inserting into user table (MDL-16919)
         if (! ($user->id = $DB->insert_record('user', $user)) ) {
             print_error('auth_emailnoinsert','auth_email');
         }
@@ -94,7 +95,7 @@
         }

         if ($notify) {
-            global $CFG;
+            global $CFG, $PAGE, $OUTPUT;
             $emailconfirm = get_string('emailconfirm');
             $PAGE->navbar->add($emailconfirm);
             $PAGE->set_title($emailconfirm);
Index: moodle/auth/ldap/auth.php
--- moodle/auth/ldap/auth.php Base (1.82)
+++ moodle/auth/ldap/auth.php Locally Modified (Based On 1.82)
@@ -419,6 +419,7 @@
             print_error('auth_ldap_create_error', 'auth_ldap');
         }

+        //TODO - username required to use PARAM_USERNAME before inserting into user table (MDL-16919)
         if (! ($user->id = $DB->insert_record('user', $user)) ) {
             print_error('auth_emailnoinsert', 'auth_email');
         }
@@ -795,6 +796,7 @@
                     $user->lang = $CFG->lang;
                 }

+                //TODO - username required to use PARAM_USERNAME before inserting into user table (MDL-16919)
                 if ($id = $DB->insert_record('user', $user)) {
                     echo "\t"; print_string('auth_dbinsertuser', 'auth_db', array($user->username, $id)); echo "\n";
                     $userobj = $this->update_user_record($user->username);
Index: moodle/auth/mnet/auth.php
--- moodle/auth/mnet/auth.php Base (1.64)
+++ moodle/auth/mnet/auth.php Locally Modified (Based On 1.64)
@@ -296,6 +296,8 @@
             }
             $remoteuser->mnethostid = $remotehost->id;
             $remoteuser->firstaccess = time(); // First time user in this server, grab it here
+
+            //TODO - username required to use PARAM_USERNAME before inserting into user table (MDL-16919)
             $DB->insert_record('user', $remoteuser);
             $firsttime = true;
             if (! $localuser = $DB->get_record('user', array('username'=>$remoteuser->username, 'mnethostid'=>$remotehost->id))) {

Index: moodle/enrol/imsenterprise/enrol.php
--- moodle/enrol/imsenterprise/enrol.php Base (1.29)
+++ moodle/enrol/imsenterprise/enrol.php Locally Modified (Based On 1.29)
@@ -646,6 +646,7 @@
             $person->confirmed = 1;
             $person->timemodified = time();
             $person->mnethostid = $CFG->mnet_localhost_id;
+            //TODO - username required to use PARAM_USERNAME before inserting into user table (MDL-16919)
             if($id = $DB->insert_record('user', $person)){
     /*
     Photo processing is deactivated until we hear from Moodle dev forum about modification to gdlib.
Index: moodle/enrol/mnet/enrol.php
--- moodle/enrol/mnet/enrol.php Base (1.27)
+++ moodle/enrol/mnet/enrol.php Locally Modified (Based On 1.27)
@@ -310,6 +310,7 @@
             $userrecord->lastname   = $user['lastname'];
             $userrecord->mnethostid = $MNET_REMOTE_CLIENT->id;

+            //TODO - username required to use PARAM_USERNAME before inserting into user table (MDL-16919)
             if ($userrecord->id = $DB->insert_record('user', $userrecord)) {
                 $userrecord = $DB->get_record('user', array('id'=>$userrecord->id));
             } else {