--- loncom/interface/lonpreferences.pm 2001/01/03 16:20:59 1.1
+++ loncom/interface/lonpreferences.pm 2007/04/13 13:39:32 1.98
@@ -1,41 +1,1635 @@
# The LearningOnline Network
# Preferences
#
-# (Internal Server Error Handler
+# $Id: lonpreferences.pm,v 1.98 2007/04/13 13:39:32 www Exp $
#
-# (Login Screen
-# 5/21/99,5/22,5/25,5/26,5/31,6/2,6/10,7/12,7/14,
-# 1/14/00,5/29,5/30,6/1,6/29,7/1,11/9 Gerd Kortemeyer)
+# Copyright Michigan State University Board of Trustees
#
-# 3/1/1 Gerd Kortemeyer)
+# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
-# 3/1 Gerd Kortemeyer
+# LON-CAPA 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.
#
+# LON-CAPA 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 LON-CAPA; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# /home/httpd/html/adm/gpl.txt
+#
+# http://www.lon-capa.org/
+#
+# This package uses the "londes.js" javascript code.
+#
+# TODOs that have to be completed:
+# interface with lonnet to change the password
+
package Apache::lonpreferences;
use strict;
+use LONCAPA;
use Apache::Constants qw(:common);
+use Apache::File;
+use Crypt::DES;
+use DynaLoader; # for Crypt::DES version
+use Apache::loncommon();
+use Apache::lonhtmlcommon();
+use Apache::lonlocal;
+use Apache::lonnet;
+use LONCAPA();
+
+#
+# Write lonnet::passwd to do the call below.
+# Use:
+# my $answer=reply("encrypt:passwd:$udom:$uname:$upass",$tryserver);
+#
+##################################################
+# password associated functions #
+##################################################
+sub des_keys {
+ # Make a new key for DES encryption.
+ # Each key has two parts which are returned separately.
+ # Please note: Each key must be passed through the &hex function
+ # before it is output to the web browser. The hex versions cannot
+ # be used to decrypt.
+ my @hexstr=('0','1','2','3','4','5','6','7',
+ '8','9','a','b','c','d','e','f');
+ my $lkey='';
+ for (0..7) {
+ $lkey.=$hexstr[rand(15)];
+ }
+ my $ukey='';
+ for (0..7) {
+ $ukey.=$hexstr[rand(15)];
+ }
+ return ($lkey,$ukey);
+}
+
+sub des_decrypt {
+ my ($key,$cyphertext) = @_;
+ my $keybin=pack("H16",$key);
+ my $cypher;
+ if ($Crypt::DES::VERSION>=2.03) {
+ $cypher=new Crypt::DES $keybin;
+ } else {
+ $cypher=new DES $keybin;
+ }
+ my $plaintext=
+ $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,0,16))));
+ $plaintext.=
+ $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,16,16))));
+ $plaintext=substr($plaintext,1,ord(substr($plaintext,0,1)) );
+ return $plaintext;
+}
+
+################################################################
+# Handler subroutines #
+################################################################
+
+################################################################
+# Language Change Subroutines #
+################################################################
+
+sub wysiwygchanger {
+ my $r = shift;
+ my %userenv = &Apache::lonnet::get
+ ('environment',['wysiwygeditor']);
+ my $onselect='checked="checked"';
+ my $offselect='';
+ if ($userenv{'wysiwygeditor'} eq 'on') {
+ $onselect='';
+ $offselect='checked="checked"';
+ }
+ my $switchoff=&mt('Disable WYSIWYG editor');
+ my $switchon=&mt('Enable WYSIWYG editor');
+ $r->print(<
+
+
+
+
+ENDLSCREEN
+ $r->print(' ');
+}
+
+
+sub verify_and_change_wysiwyg {
+ my $r = shift;
+ my $newsetting=$env{'form.wysiwyg'};
+ &Apache::lonnet::put('environment',{'wysiwygeditor' => $newsetting});
+ &Apache::lonnet::appenv('environment.wysiwygeditor' => $newsetting);
+ $r->print('
'.&mt('Some LON-CAPA users have a long list of '.$lc_role.'s. The Recent '.$role.'s Hotlist feature keeps track of the last N '.$lc_role.'s which have been visited and places a table of these at the top of the '.$lc_role.'s page. People with very few '.$lc_role.'s should leave this feature disabled.').'
+
+');
+}
+
+sub rolespref_get_role_text {
+# Get a line of text for each role
+ my ($roles) = @_;
+ my %roletext = ();
+
+ foreach my $item (@$roles) {
+# get course information
+ my ($role,$rest) = split(/\./, $item);
+ my $trole = "";
+ $trole = &Apache::lonnet::plaintext($role);
+ my ($tdomain,$other,$tsection)= split(/\//,Apache::lonnet::declutter($rest));
+ my $tother = '-';
+ if ($role =~ /^(cc|st|in|ta|ep|cr)/ ) {
+ my %newhash=&Apache::lonnet::coursedescription($tdomain."_".$other);
+ $tother = " - ".$newhash{'description'};
+ } elsif ($role =~ /dc/) {
+ $tother = "";
+ } else {
+ $tother = " - $other";
+ }
+
+ my $section="";
+ if ($tsection) {
+ $section = " - Section/Group: $tsection";
+ }
+ $roletext{$item} = $tdomain." - ".$trole.$tother.$section;
+ }
+ return %roletext;
+}
+
+sub verify_and_change_rolespref {
+ my $r = shift;
+ my $role = ($env{'user.adv'} ? 'Role' : 'Course');
+ my $user = $env{'user.name'};
+ my $domain = $env{'user.domain'};
+# Recent Roles Hotlist Flag
+ my $hotlist_flag = $env{'form.recentroles'};
+ my $hotlist_n = $env{'form.recentrolesn'};
+ my $message='';
+ if ($hotlist_flag) {
+ &Apache::lonnet::put('environment',{'recentroles' => $hotlist_flag});
+ &Apache::lonnet::appenv('environment.recentroles' => $hotlist_flag);
+ $message=&mt('Recent '.$role.'s Hotlist is Enabled');
+ } else {
+ &Apache::lonnet::del('environment',['recentroles']);
+ &Apache::lonnet::delenv('environment\.recentroles');
+ $message=&mt('Recent '.$role.'s Hotlist is Disabled');
+ }
+ if ($hotlist_n) {
+ &Apache::lonnet::put('environment',{'recentrolesn' => $hotlist_n});
+ &Apache::lonnet::appenv('environment.recentrolesn' => $hotlist_n);
+ if ($hotlist_flag) {
+ $message.=" ".
+ &mt('Display [_1] Most Recent '.$role.'s',$hotlist_n)."\n";
+ }
+ }
+
+# Get list of froze roles and list of recent roles
+ my @freeze_list = &Apache::loncommon::get_env_multiple('form.freezeroles');
+ my %freeze = ();
+ my %roletext = ();
+
+ foreach my $key (@freeze_list) {
+ $freeze{$key}='1';
+ }
+
+ my %recent_roles =
+ &Apache::lonhtmlcommon::get_recent('roles',$env{'environment.recentrolesn'});
+ my %frozen_roles =
+ &Apache::lonhtmlcommon::get_recent_frozen('roles',$env{'environment.recentrolesn'});
+ my %role_text = &rolespref_get_role_text([keys(%recent_roles)]);
+
+# Unset any roles that were previously frozen but aren't in list
+ foreach my $role_key (sort(keys(%recent_roles))) {
+ if (($frozen_roles{$role_key}) && (!exists($freeze{$role_key}))) {
+ $message .= " ".&mt('Unfreezing '.$role.': [_1]',$role_text{$role_key})."\n";
+ &Apache::lonhtmlcommon::store_recent('roles',$role_key,' ',0);
+ }
+ }
+
+# Freeze selected roles
+ foreach my $role_key (@freeze_list) {
+ if (!$frozen_roles{$role_key}) {
+ $message .= " ".&mt('Freezing '.$role.': [_1]',$role_text{$role_key})."\n";
+ &Apache::lonhtmlcommon::store_recent('roles',
+ $role_key,' ',1);
+ }
+ }
+ $message .= " \n";
+
+ $r->print(<print(<
+
+ New screenname (shown if you post anonymously):
+
+ New nickname (shown if you post non-anonymously):
+
+
+
+ENDSCREEN
+}
+
+sub verify_and_change_screenname {
+ my $r = shift;
+ my $user = $env{'user.name'};
+ my $domain = $env{'user.domain'};
+# Screenname
+ my $newscreen = $env{'form.screenname'};
+ $newscreen=~s/[^ \w]//g;
+ my $message='';
+ if ($newscreen) {
+ &Apache::lonnet::put('environment',{'screenname' => $newscreen});
+ &Apache::lonnet::appenv('environment.screenname' => $newscreen);
+ $message='Set new screenname to '.$newscreen;
+ } else {
+ &Apache::lonnet::del('environment',['screenname']);
+ &Apache::lonnet::delenv('environment\.screenname');
+ $message='Reset screenname';
+ }
+# Nickname
+ $message.=' ';
+ $newscreen = $env{'form.nickname'};
+ $newscreen=~s/[^ \w]//g;
+ if ($newscreen) {
+ &Apache::lonnet::put('environment',{'nickname' => $newscreen});
+ &Apache::lonnet::appenv('environment.nickname' => $newscreen);
+ $message.='Set new nickname to '.$newscreen;
+ } else {
+ &Apache::lonnet::del('environment',['nickname']);
+ &Apache::lonnet::delenv('environment\.nickname');
+ $message.='Reset nickname';
+ }
+ &Apache::lonnet::devalidate_cache_new('namescache',$user.':'.$domain);
+ $r->print(<print(<
+
+
+
+
+
+ENDSCREEN
+}
+
+sub verify_and_change_icons {
+ my $r = shift;
+ my $user = $env{'user.name'};
+ my $domain = $env{'user.domain'};
+ my $newicons = $env{'form.menumode'};
+ &Apache::lonnet::put('environment',{'icons' => $newicons});
+ &Apache::lonnet::appenv('environment.icons' => $newicons);
+ $r->print(&mt('Set menu mode to [_1].',$newicons));
+}
+
+################################################################
+# Message Forward #
+################################################################
+
+sub msgforwardchanger {
+ my $r = shift;
+ my $user = $env{'user.name'};
+ my $domain = $env{'user.domain'};
+ my %userenv = &Apache::lonnet::get('environment',['msgforward','notification','critnotification']);
+ my $msgforward=$userenv{'msgforward'};
+ my $notification=$userenv{'notification'};
+ my $critnotification=$userenv{'critnotification'};
+ my $forwardingHelp = Apache::loncommon::help_open_topic("Prefs_Forwarding",
+ "What are forwarding ".
+ "and notification ".
+ "addresses");
+ my $criticalMessageHelp = Apache::loncommon::help_open_topic("Course_Critical_Message",
+ "What are critical messages");
+
+ $r->print(<
+
+ENDMSG
+}
+
+sub verify_and_change_msgforward {
+ my $r = shift;
+ my $user = $env{'user.name'};
+ my $domain = $env{'user.domain'};
+ my $newscreen = '';
+ my $message='';
+ foreach (split(/\,/,$env{'form.msgforward'})) {
+ my ($msuser,$msdomain)=split(/[\@\:]/,$_);
+ $msuser = &LONCAPA::clean_username($msuser);
+ $msdomain = &LONCAPA::clean_domain($msdomain);
+ if (($msuser) && ($msdomain)) {
+ if (&Apache::lonnet::homeserver($msuser,$msdomain) ne 'no_host') {
+ $newscreen.=$msuser.':'.$msdomain.',';
+ } else {
+ $message.='No such user: '.$msuser.':'.$msdomain.' ';
+ }
+ }
+ }
+ $newscreen=~s/\,$//;
+ if ($newscreen) {
+ &Apache::lonnet::put('environment',{'msgforward' => $newscreen});
+ &Apache::lonnet::appenv('environment.msgforward' => $newscreen);
+ $message.='Set new message forwarding to '.$newscreen.' ';
+ } else {
+ &Apache::lonnet::del('environment',['msgforward']);
+ &Apache::lonnet::delenv('environment\.msgforward');
+ $message.='Reset message forwarding ';
+ }
+ my $notification=$env{'form.notification'};
+ $notification=~s/\s//gs;
+ if ($notification) {
+ &Apache::lonnet::put('environment',{'notification' => $notification});
+ &Apache::lonnet::appenv('environment.notification' => $notification);
+ $message.='Set message notification address to '.$notification.' ';
+ } else {
+ &Apache::lonnet::del('environment',['notification']);
+ &Apache::lonnet::delenv('environment\.notification');
+ $message.='Reset message notification ';
+ }
+ my $critnotification=$env{'form.critnotification'};
+ $critnotification=~s/\s//gs;
+ if ($critnotification) {
+ &Apache::lonnet::put('environment',{'critnotification' => $critnotification});
+ &Apache::lonnet::appenv('environment.critnotification' => $critnotification);
+ $message.='Set critical message notification address to '.$critnotification;
+ } else {
+ &Apache::lonnet::del('environment',['critnotification']);
+ &Apache::lonnet::delenv('environment\.critnotification');
+ $message.='Reset critical message notification ';
+ }
+ $r->print(< 'Page Background',
+ 'tabbg' => 'Header Background',
+ 'sidebg'=> 'Header Border',
+ 'font' => 'Font',
+ 'link' => 'Un-Visited Link',
+ 'vlink' => 'Visited Link',
+ 'alink' => 'Active Link');
+ my $start_data_table = &Apache::loncommon::start_data_table();
+ my $chtable='';
+ foreach my $item (sort(keys(%colortypes))) {
+ my $curcol=&Apache::loncommon::designparm($function.'.'.$item,$domain);
+ $chtable.=&Apache::loncommon::start_data_table_row().
+ '
",
+ $caller,$mailtoken);
+ return 1;
+ }
+ } else {
+ $user = $env{'user.name'};
+ $domain = $env{'user.domain'};
+ $homeserver = $env{'user.home'};
+ }
+ my $currentauth=&Apache::lonnet::queryauthenticate($user,$domain);
+ # Check for authentication types that allow changing of the password.
+ if ($currentauth !~ /^(unix|internal):/) {
+ if ($caller eq 'reset_by_email') {
+ &passwordchanger($r,"
\nERROR".
+ "Authentication type for this user can not be changed by this mechanism..\n
",
+ $caller,$mailtoken);
+ return 1;
+ } else {
+ return;
+ }
+ }
+ #
+ my $currentpass = $env{'form.currentpass'};
+ my $newpass1 = $env{'form.newpass_1'};
+ my $newpass2 = $env{'form.newpass_2'};
+ my $logtoken = $env{'form.logtoken'};
+ # Check for empty data
+ unless (defined($currentpass) &&
+ defined($newpass1) &&
+ defined($newpass2) ){
+ &passwordchanger($r,"
\nERROR".
+ "One or more password fields were blank.\n
",$caller,$mailtoken);
+ return;
+ }
+ # Get the keys
+ my $lonhost = $r->dir_config('lonHostID');
+ my $tmpinfo = Apache::lonnet::reply('tmpget:'.$logtoken,$lonhost);
+ if (($tmpinfo=~/^error/) || ($tmpinfo eq 'con_lost')) {
+ # I do not a have a better idea about how to handle this
+ my $tryagain_text = &mt('Please log out and try again.');
+ if ($caller eq 'reset_by_email') {
+ $tryagain_text = &mt('Please try again later.');
+ }
+ $r->print(<
+ERROR: Unable to retrieve stored token for
+password decryption. $tryagain_text
+
+ENDERROR
+ # Probably should log an error here
+ return 1;
+ }
+ my ($ckey,$n1key,$n2key)=split(/&/,$tmpinfo);
+ #
+ $currentpass = &des_decrypt($ckey ,$currentpass);
+ $newpass1 = &des_decrypt($n1key,$newpass1);
+ $newpass2 = &des_decrypt($n2key,$newpass2);
+ #
+ if ($caller eq 'reset_by_email') {
+ my %data = &Apache::lonnet::tmpget($mailtoken);
+ if ($currentpass ne $data{'temppasswd'}) {
+ &passwordchanger($r,
+ 'ERROR:'.
+ 'Could not verify current authentication. '.
+ 'Please try again.',$caller,$mailtoken);
+ return 1;
+ }
+ }
+ if ($newpass1 ne $newpass2) {
+ &passwordchanger($r,
+ 'ERROR:'.
+ 'The new passwords you entered do not match. '.
+ 'Please try again.',$caller,$mailtoken);
+ return 1;
+ }
+ if (length($newpass1) < 7) {
+ &passwordchanger($r,
+ 'ERROR:'.
+ 'Passwords must be a minimum of 7 characters long. '.
+ 'Please try again.',$caller,$mailtoken);
+ return 1;
+ }
+ #
+ # Check for bad characters
+ my $badpassword = 0;
+ foreach (split(//,$newpass1)) {
+ $badpassword = 1 if ((ord($_)<32)||(ord($_)>126));
+ }
+ if ($badpassword) {
+ # I can't figure out how to enter bad characters on my browser.
+ my $errormessage = <<"ENDERROR";
+ERROR:
+The password you entered contained illegal characters.
+Valid characters are: space and
+
+ENDERROR
+ &passwordchanger($r,$errormessage,$caller,$mailtoken);
+ return 1;
+ }
+ #
+ # Change the password (finally)
+ my $result = &Apache::lonnet::changepass
+ ($user,$domain,$currentpass,$newpass1,$homeserver,$caller);
+ # Inform the user the password has (not?) been changed
+ if ($result =~ /^ok$/) {
+ $r->print(<<"ENDTEXT");
+
The password for $user was successfully changed
+ENDTEXT
+ } else {
+ # error error: run in circles, scream and shout
+ $r->print(<The password for $user was not changed
+Please make sure your old password was entered correctly.
+ENDERROR
+ return 1;
+ }
+ return;
+}
+
+################################################################
+# discussion display subroutines
+################################################################
+sub discussionchanger {
+ my $r = shift;
+ my $user = $env{'user.name'};
+ my $domain = $env{'user.domain'};
+ my %userenv = &Apache::lonnet::get
+ ('environment',['discdisplay','discmarkread']);
+ my $discdisp = 'allposts';
+ my $discmark = 'onmark';
+
+ if (defined($userenv{'discdisplay'})) {
+ unless ($userenv{'discdisplay'} eq '') {
+ $discdisp = $userenv{'discdisplay'};
+ }
+ }
+ if (defined($userenv{'discmarkread'})) {
+ unless ($userenv{'discdisplay'} eq '') {
+ $discmark = $userenv{'discmarkread'};
+ }
+ }
+
+ my $newdisp = 'unread';
+ my $newmark = 'ondisp';
+
+ my $function = &Apache::loncommon::get_users_function();
+ my $color = &Apache::loncommon::designparm($function.'.tabbg',
+ $env{'user.domain'});
+ my %lt = &Apache::lonlocal::texthash(
+ 'pref' => 'Display Preference',
+ 'curr' => 'Current setting ',
+ 'actn' => 'Action',
+ 'sdpf' => 'Set display preferences for discussion posts for both bulletin boards and individual resources in all your courses.',
+ 'prca' => 'Preferences can be set that determine',
+ 'whpo' => 'Which posts are displayed when you display a bulletin board or resource, and',
+ 'unwh' => 'Under what circumstances posts are identfied as "New"',
+ 'allposts' => 'All posts',
+ 'unread' => 'New posts only',
+ 'ondisp' => 'Once displayed',
+ 'onmark' => 'Once marked as read',
+ 'disa' => 'Posts displayed?',
+ 'npmr' => 'New posts cease to be identified as "New"?',
+ 'thde' => 'The preferences you set here can be overridden within each individual discussion.',
+ 'chgt' => 'Change to '
+ );
+ my $dispchange = $lt{'unread'};
+ my $markchange = $lt{'ondisp'};
+ my $currdisp = $lt{'allposts'};
+ my $currmark = $lt{'onmark'};
+
+ if ($discdisp eq 'unread') {
+ $dispchange = $lt{'allposts'};
+ $currdisp = $lt{'unread'};
+ $newdisp = 'allposts';
+ }
+
+ if ($discmark eq 'ondisp') {
+ $markchange = $lt{'onmark'};
+ $currmark = $lt{'ondisp'};
+ $newmark = 'onmark';
+ }
+
+ $r->print(<<"END");
+
+END
+}
+
+sub verify_and_change_discussion {
+ my $r = shift;
+ my $user = $env{'user.name'};
+ my $domain = $env{'user.domain'};
+ my $message='';
+ if (defined($env{'form.discdisp'}) ) {
+ my $newdisp = $env{'form.newdisp'};
+ if ($newdisp eq 'unread') {
+ $message .='In discussions: only new posts will be displayed. ';
+ &Apache::lonnet::put('environment',{'discdisplay' => $newdisp});
+ &Apache::lonnet::appenv('environment.discdisplay' => $newdisp);
+ } else {
+ $message .= 'In discussions: all posts will be displayed. ';
+ &Apache::lonnet::del('environment',['discdisplay']);
+ &Apache::lonnet::delenv('environment\.discdisplay');
+ }
+ }
+ if (defined($env{'form.discmark'}) ) {
+ my $newmark = $env{'form.newmark'};
+ if ($newmark eq 'ondisp') {
+ $message.='In discussions: new posts will be cease to be identified as "new" after display. ';
+ &Apache::lonnet::put('environment',{'discmarkread' => $newmark});
+ &Apache::lonnet::appenv('environment.discmarkread' => $newmark);
+ } else {
+ $message.='In discussions: posts will be identified as "new" until marked as read by the reader. ';
+ &Apache::lonnet::del('environment',['discmarkread']);
+ &Apache::lonnet::delenv('environment\.discmarkread');
+ }
+ }
+ $r->print(< 'First resource',
+ whatsnew => "What's new page",
+ );
+ my $whatsnew_off=&mt('Display the [_1] in the course.','first resource');
+ my $whatsnew_on=&mt('Display the "[_1]" page - a summary of items in the course which require attention.',"What's New");
+
+ $r->print(' '.&mt('Set the default page to be displayed when you select a course role').' '.&mt('(Currently: [_1])',$pagenames{$currvalue}).' '.&mt('The global user preference you set for your courses can be overridden in an individual course by setting a course specific setting via the "[_1]" page in the course',"What's New").'