--- loncom/interface/lonpreferences.pm 2006/06/22 23:30:33 1.92 +++ loncom/interface/lonpreferences.pm 2007/04/28 23:13:56 1.100 @@ -1,7 +1,7 @@ # The LearningOnline Network # Preferences # -# $Id: lonpreferences.pm,v 1.92 2006/06/22 23:30:33 albertel Exp $ +# $Id: lonpreferences.pm,v 1.100 2007/04/28 23:13:56 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -42,6 +42,7 @@ use Apache::loncommon(); use Apache::lonhtmlcommon(); use Apache::lonlocal; use Apache::lonnet; +use LONCAPA(); # # Write lonnet::passwd to do the call below. @@ -279,6 +280,8 @@ ENDVCSCREEN ################################################################ sub rolesprefchanger { my $r = shift; + my $role = ($env{'user.adv'} ? 'Role' : 'Course'); + my $lc_role = ($env{'user.adv'} ? 'role' : 'course'); my $user = $env{'user.name'}; my $domain = $env{'user.domain'}; my %userenv = &Apache::lonnet::get @@ -307,14 +310,14 @@ sub rolesprefchanger { my %frozen_roles = &Apache::lonhtmlcommon::get_recent_frozen('roles',$env{'environment.recentrolesn'}); - my %role_text = &rolespref_get_role_text(keys(%recent_roles)); + my %role_text = &rolespref_get_role_text([keys(%recent_roles)]); my @sorted_roles = sort {$role_text{$a} cmp $role_text{$b}} keys(%role_text); $roles_check_list .= &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(). - "<th>".&mt('Freeze Role')."</th>". - "<th>".&mt('Role')."</td>". + "<th>".&mt('Freeze '.$role)."</th>". + "<th>".&mt($role)."</td>". &Apache::loncommon::end_data_table_header_row(). "\n"; my $count; @@ -338,17 +341,17 @@ sub rolesprefchanger { } $r->print(' -<p>'.&mt('Some LON-CAPA users have a long list of roles. The Recent Roles Hotlist feature keeps track of the last N roles which have been visited and places a table of these at the top of the roles page. People with very few roles should leave this feature disabled.').' +<p>'.&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.').' </p> <form name="prefs" action="/adm/preferences" method="POST"> <input type="hidden" name="action" value="verify_and_change_rolespref" /> -<br /><label>'.&mt('Enable Recent Roles Hotlist:').' +<br /><label>'.&mt('Enable Recent '.$role.'s Hotlist:').' <input type="checkbox" '.$checked.' name="recentroles" value="true" /></label> -<br />'.&mt('Number of roles in Hotlist:').' +<br />'.&mt('Number of '.$role.'s in Hotlist:').' <select name="recentrolesn" size="1"> '.$options.' </select> -<p>'.&mt('This list below can be used to <q>freeze</q> roles on your screen. Those marked as frozen will not be removed from the list, even if they have not been used recently.').' +<p>'.&mt('This list below can be used to <q>freeze</q> '.$lc_role.'s on your screen. Those marked as frozen will not be removed from the list, even if they have not been used recently.').' </p> '.$roles_check_list.' <br /> @@ -364,10 +367,11 @@ sub rolespref_get_role_text { foreach my $item (@$roles) { # get course information my ($role,$rest) = split(/\./, $item); - my $trole = &Apache::lonnet::plaintext($role); + my $trole = ""; + $trole = &Apache::lonnet::plaintext($role); my ($tdomain,$other,$tsection)= split(/\//,Apache::lonnet::declutter($rest)); my $tother = '-'; - if ($role =~ /cc|st|in|ta/ ) { + if ($role =~ /^(cc|st|in|ta|ep|cr)/ ) { my %newhash=&Apache::lonnet::coursedescription($tdomain."_".$other); $tother = " - ".$newhash{'description'}; } elsif ($role =~ /dc/) { @@ -387,6 +391,7 @@ sub rolespref_get_role_text { 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 @@ -396,18 +401,18 @@ sub verify_and_change_rolespref { if ($hotlist_flag) { &Apache::lonnet::put('environment',{'recentroles' => $hotlist_flag}); &Apache::lonnet::appenv('environment.recentroles' => $hotlist_flag); - $message=&mt('Recent Roles Hotlist is Enabled'); + $message=&mt('Recent '.$role.'s Hotlist is Enabled'); } else { &Apache::lonnet::del('environment',['recentroles']); &Apache::lonnet::delenv('environment\.recentroles'); - $message=&mt('Recent Roles Hotlist is Disabled'); + $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.="<br />". - &mt('Display [_1] Most Recent Roles',$hotlist_n)."\n"; + &mt('Display [_1] Most Recent '.$role.'s',$hotlist_n)."\n"; } } @@ -429,7 +434,7 @@ sub verify_and_change_rolespref { # 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 .= "<br />".&mt('Unfreezing Role: [_1]',$role_text{$role_key})."\n"; + $message .= "<br />".&mt('Unfreezing '.$role.': [_1]',$role_text{$role_key})."\n"; &Apache::lonhtmlcommon::store_recent('roles',$role_key,' ',0); } } @@ -437,7 +442,7 @@ sub verify_and_change_rolespref { # Freeze selected roles foreach my $role_key (@freeze_list) { if (!$frozen_roles{$role_key}) { - $message .= "<br />".&mt('Freezing Role: [_1]',$role_text{$role_key})."\n"; + $message .= "<br />".&mt('Freezing '.$role.': [_1]',$role_text{$role_key})."\n"; &Apache::lonhtmlcommon::store_recent('roles', $role_key,' ',1); } @@ -511,6 +516,52 @@ ENDVCSCREEN } ################################################################ +# Icon Subroutines # +################################################################ +sub iconchanger { + my $r = shift; + my $user = $env{'user.name'}; + my $domain = $env{'user.domain'}; + my %userenv = &Apache::lonnet::get + ('environment',['icons']); + my $iconic='checked="checked"'; + my $classic=''; + my $onlyicon=''; + if ($userenv{'icons'} eq 'classic') { + $classic='checked="checked"'; + $iconic=''; + } + if ($userenv{'icons'} eq 'iconsonly') { + $onlyicon='checked="checked"'; + $iconic=''; + } + my $useicons=&mt('Use icons and text'); + my $usebuttons=&mt('Use buttons and text'); + my $useicononly=&mt('Use icons only'); + my $change=&mt('Change'); + $r->print(<<ENDSCREEN); +<form name="prefs" action="/adm/preferences" method="post"> +<input type="hidden" name="action" value="verify_and_change_icons" /> +<label><input type="radio" name="menumode" value="iconic" $iconic /> $useicons</label><br /> +<label><input type="radio" name="menumode" value="classic" $classic /> $usebuttons</label><br /> +<label><input type="radio" name="menumode" value="iconsonly" $onlyicon /> $useicononly</label><br /> +<input type="submit" value="$change" /> +</form> +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 # ################################################################ @@ -552,8 +603,8 @@ sub verify_and_change_msgforward { my $message=''; foreach (split(/\,/,$env{'form.msgforward'})) { my ($msuser,$msdomain)=split(/[\@\:]/,$_); - $msuser=~s/\W//g; - $msdomain=~s/\W//g; + $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.','; @@ -717,14 +768,41 @@ ENDVCCOL # password handler subroutines # ###################################################### sub passwordchanger { + my ($r,$errormessage,$caller,$mailtoken) = @_; # This function is a bit of a mess.... # Passwords are encrypted using londes.js (DES encryption) - my $r = shift; - my $errormessage = shift; $errormessage = ($errormessage || ''); - my $user = $env{'user.name'}; - my $domain = $env{'user.domain'}; - my $homeserver = $env{'user.home'}; + my ($user,$domain,$currentpass,$defdom); + if ((!defined($caller)) || ($caller eq 'preferences')) { + $user = $env{'user.name'}; + $domain = $env{'user.domain'}; + if (!defined($caller)) { + $caller = 'preferences'; + } + } elsif ($caller eq 'reset_by_email') { + $defdom = $r->dir_config('lonDefDomain'); + my %data = &Apache::lonnet::tmpget($mailtoken); + if (keys(%data) == 0) { + $r->print(&mt('Sorry, the URL you provided to complete the reset of your password was invalid. Either the token included in the URL has been deleted or the URL you provided was invalid. Please submit a <a href="/adm/resetpw">new request</a> for a password reset, and follow the link to the new URL included in the e-mail that will be sent to you, to allow you to enter a new password.')); + return; + } + if (defined($data{time})) { + if (time - $data{'time'} < 7200) { + $user = $data{'username'}; + $domain = $data{'domain'}; + $currentpass = $data{'temppasswd'}; + } else { + $r->print(&mt('Sorry, the token generated when you requested a password reset has expired.').'<br />'); + return; + } + } else { + $r->print(&mt('Sorry, the URL generated when you requested reset of your password contained incomplete information.').'<br />'); + return; + } + } else { + $r->print(&mt('Page requested in unexpected context').'<br />'); + return; + } my $currentauth=&Apache::lonnet::queryauthenticate($user,$domain); # Check for authentication types that allow changing of the password. return if ($currentauth !~ /^(unix|internal):/); @@ -741,12 +819,13 @@ sub passwordchanger { .$ukey_npass2 . $lkey_npass2, $lonhost); # Hexify the keys for output as javascript variables - $ukey_cpass = hex($ukey_cpass); - $lkey_cpass = hex($lkey_cpass); - $ukey_npass1= hex($ukey_npass1); - $lkey_npass1= hex($lkey_npass1); - $ukey_npass2= hex($ukey_npass2); - $lkey_npass2= hex($lkey_npass2); + my %hexkey; + $hexkey{'ukey_cpass'} = hex($ukey_cpass); + $hexkey{'lkey_cpass'} = hex($lkey_cpass); + $hexkey{'ukey_npass1'} = hex($ukey_npass1); + $hexkey{'lkey_npass1'} = hex($lkey_npass1); + $hexkey{'ukey_npass2'} = hex($ukey_npass2); + $hexkey{'lkey_npass2'} = hex($lkey_npass2); # Output javascript to deal with passwords # Output DES javascript { @@ -754,7 +833,25 @@ sub passwordchanger { my $jsh=Apache::File->new($include."/londes.js"); $r->print(<$jsh>); } + $r->print(&jscript_send($caller)); $r->print(<<ENDFORM); +$errormessage + +<p> +<!-- We separate the forms into 'server' and 'client' in order to + ensure that unencrypted passwords will not be sent out by a + crappy browser --> +ENDFORM + $r->print(&server_form($logtoken,$caller,$mailtoken)); + $r->print(&client_form($caller,\%hexkey,$currentpass,$defdom)); + + # + return; +} + +sub jscript_send { + my ($caller) = @_; + my $output = qq| <script language="JavaScript"> function send() { @@ -776,58 +873,145 @@ sub passwordchanger { initkeys(); this.document.pserver.elements.newpass_2.value =crypted(this.document.client.elements.newpass_2.value); - +|; + if ($caller eq 'reset_by_email') { + $output .= qq| + this.document.pserver.elements.uname.value = + this.document.client.elements.uname.value; + this.document.pserver.elements.udom.value = + this.document.client.elements.udom.options[this.document.client.elements.udom.selectedIndex].value; +|; + } + $ output .= qq| this.document.pserver.submit(); } - </script> -$errormessage - -<p> -<!-- We separate the forms into 'server' and 'client' in order to - ensure that unencrypted passwords will not be sent out by a - crappy browser --> +|; +} -<form name="pserver" action="/adm/preferences" method="post"> -<input type="hidden" name="logtoken" value="$logtoken" /> -<input type="hidden" name="action" value="verify_and_change_pass" /> -<input type="hidden" name="currentpass" value="" /> -<input type="hidden" name="newpass_1" value="" /> -<input type="hidden" name="newpass_2" value="" /> -</form> +sub client_form { + my ($caller,$hexkey,$currentpass,$defdom) = @_; + my %lt=&Apache::lonlocal::texthash( + 'email' => 'EMail Address', + 'username' => 'Username', + 'domain' => 'Domain', + 'currentpass' => 'Current Password', + 'newpass' => 'New Password', + 'confirmpass' => 'Confirm Password', + 'changepass' => 'Change Password'); + my $output = qq| <form name="client" > <table> -<tr><td align="right"> Current password: </td> +|; + if ($caller eq 'reset_by_email') { + $output .= qq| +<tr><td class="LC_preferences_labeltext"><label for="email">$lt{'email'}</label>:</td> + <td><input type="text" name="email" size="30" /> </td></tr> +<tr><td class="LC_preferences_labeltext"><label for="uname">$lt{'username'}</label>:</td> + <td> + <input type="text" name="uname" size="15" /> + <input type="hidden" name="currentpass" value="$currentpass" /> + </td></tr> +<tr><td class="LC_preferences_labeltext"><label for="udom">$lt{'udom'}</label>:</td> + <td> +|; + $output .= &Apache::loncommon::select_dom_form($defdom,'udom').' + </td> +</tr> +'; + } else { + $output .= qq| +<tr><td class="LC_preferences_labeltext"><label for="currentpass">$lt{'currentpass'}</label></td> <td><input type="password" name="currentpass" size="10"/> </td></tr> -<tr><td align="right"> New password: </td> +|; + } + $output .= <<"ENDFORM"; +<tr><td class="LC_preferences_labeltext"><label for="newpass_1">$lt{'newpass'}</label></td> <td><input type="password" name="newpass_1" size="10" /> </td></tr> -<tr><td align="right"> Confirm password: </td> +<tr><td class="LC_preferences_labeltext"><label for="newpass_2">$lt{'confirmpass'}</label></td> <td><input type="password" name="newpass_2" size="10" /> </td></tr> <tr><td colspan="2" align="center"> - <input type="button" value="Change Password" onClick="send();"> + <input type="button" value="$lt{'changepass'}" onClick="send();"> </table> -<input type="hidden" name="ukey_cpass" value="$ukey_cpass" /> -<input type="hidden" name="lkey_cpass" value="$lkey_cpass" /> -<input type="hidden" name="ukey_npass1" value="$ukey_npass1" /> -<input type="hidden" name="lkey_npass1" value="$lkey_npass1" /> -<input type="hidden" name="ukey_npass2" value="$ukey_npass2" /> -<input type="hidden" name="lkey_npass2" value="$lkey_npass2" /> +<input type="hidden" name="ukey_cpass" value="$hexkey->{'ukey_cpass'}" /> +<input type="hidden" name="lkey_cpass" value="$hexkey->{'lkey_cpass'}" /> +<input type="hidden" name="ukey_npass1" value="$hexkey->{'ukey_npass1'}" /> +<input type="hidden" name="lkey_npass1" value="$hexkey->{'lkey_npass1'}" /> +<input type="hidden" name="ukey_npass2" value="$hexkey->{'ukey_npass2'}" /> +<input type="hidden" name="lkey_npass2" value="$hexkey->{'lkey_npass2'}" /> </form> </p> ENDFORM - # - return; + return $output; +} + +sub server_form { + my ($logtoken,$caller,$mailtoken) = @_; + my $action = '/adm/preferences'; + if ($caller eq 'reset_by_email') { + $action = '/adm/resetpw'; + } + my $output = qq| +<form name="pserver" action="$action" method="post"> +<input type="hidden" name="logtoken" value="$logtoken" /> +<input type="hidden" name="currentpass" value="" /> +<input type="hidden" name="newpass_1" value="" /> +<input type="hidden" name="newpass_2" value="" /> + |; + if ($caller eq 'reset_by_email') { + $output .= qq| +<input type="hidden" name="token" value="$mailtoken" /> +<input type="hidden" name="uname" value="" /> +<input type="hidden" name="udom" value="" /> + +|; + } + $output .= qq| +<input type="hidden" name="action" value="verify_and_change_pass" /> +</form> +|; + return $output; } sub verify_and_change_password { - my $r = shift; - my $user = $env{'user.name'}; - my $domain = $env{'user.domain'}; - my $homeserver = $env{'user.home'}; + my ($r,$caller,$mailtoken) = @_; + my ($user,$domain,$homeserver); + if ($caller eq 'reset_by_email') { + $user = $env{'form.uname'}; + $domain = $env{'form.udom'}; + if ($user ne '' && $domain ne '') { + $homeserver = &Apache::lonnet::homeserver($user,$domain); + if ($homeserver eq 'no_host') { + &passwordchanger($r,"<p>\n<span class='LC_error'>". + &mt("Invalid username and/or domain")."</span>\n</p>", + $caller,$mailtoken); + return 1; + } + } else { + &passwordchanger($r,"<p>\n<span class='LC_error'>". + &mt("Username and domain were blank")."</span>\n</p>", + $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. - return if ($currentauth !~ /^(unix|internal):/); + if ($currentauth !~ /^(unix|internal):/) { + if ($caller eq 'reset_by_email') { + &passwordchanger($r,"<p>\n<span class='LC_error'>". + &mt("Authentication type for this user can not be changed by this mechanism"). + "</span>\n</p>", + $caller,$mailtoken); + return 1; + } else { + return; + } + } # my $currentpass = $env{'form.currentpass'}; my $newpass1 = $env{'form.newpass_1'}; @@ -837,8 +1021,9 @@ sub verify_and_change_password { unless (defined($currentpass) && defined($newpass1) && defined($newpass2) ){ - &passwordchanger($r,"<p>\n<font color='#ff0000'>ERROR</font>". - "Password data was blank.\n</p>"); + &passwordchanger($r,"<p>\n<span class='LC_error'>". + &mt("One or more password fields were blank"). + "</span>\n</p>",$caller,$mailtoken); return; } # Get the keys @@ -846,10 +1031,14 @@ sub verify_and_change_password { 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.'); + } + my $unable=&mt("Unable to retrieve stored token for password decryption"); $r->print(<<ENDERROR); <p> -<font color="#ff0000">ERROR:</font> Unable to retrieve stored token for -password decryption. Please log out and try again. +<span class="LC_error">$unable. $tryagain_text</span> </p> ENDERROR # Probably should log an error here @@ -860,19 +1049,29 @@ ENDERROR $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, + '<span class="LC_error">'. + &mt('Could not verify current authentication').'. '. + &mt('Please try again').'.</span>',$caller,$mailtoken); + return 1; + } + } if ($newpass1 ne $newpass2) { &passwordchanger($r, - '<font color="#ff0000">ERROR:</font>'. - 'The new passwords you entered do not match. '. - 'Please try again.'); + '<span class="LC_error">'. + &mt('The new passwords you entered do not match').'. '. + &mt('Please try again').'.</span>',$caller,$mailtoken); return 1; } if (length($newpass1) < 7) { &passwordchanger($r, - '<font color="#ff0000">ERROR:</font>'. - 'Passwords must be a minimum of 7 characters long. '. - 'Please try again.'); + '<span class="LC_error">'. + &mt('Passwords must be a minimum of 7 characters long').'. '. + &mt('Please try again').'</span>.',$caller,$mailtoken); return 1; } # @@ -883,31 +1082,29 @@ ENDERROR } if ($badpassword) { # I can't figure out how to enter bad characters on my browser. - &passwordchanger($r,<<ENDERROR); -<font color="#ff0000">ERROR:</font> -The password you entered contained illegal characters.<br /> -Valid characters are: space and <br /> + my $errormessage ='<span class="LC_error">'. + &mt('The password you entered contained illegal characters').'.<br />'. + &mt('Valid characters are').(<<"ENDERROR"); +: space and <br /> <pre> !"\#$%&\'()*+,-./0123456789:;<=>?\@ ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_\`abcdefghijklmnopqrstuvwxyz{|}~ -</pre> +</pre></span> ENDERROR + &passwordchanger($r,$errormessage,$caller,$mailtoken); + return 1; } # # Change the password (finally) my $result = &Apache::lonnet::changepass - ($user,$domain,$currentpass,$newpass1,$homeserver); + ($user,$domain,$currentpass,$newpass1,$homeserver,$caller); # Inform the user the password has (not?) been changed if ($result =~ /^ok$/) { - $r->print(<<"ENDTEXT"); -<h2>The password for $user was successfully changed</h2> -ENDTEXT + $r->print("<h3>".&mt('The password for [_1] was successfully changed',$user)."</h3>"); } else { # error error: run in circles, scream and shout - $r->print(<<ENDERROR); -<h2><font color="#ff0000">The password for $user was not changed</font></h2> -Please make sure your old password was entered correctly. -ENDERROR + $r->print("<h3><span class='LC_error'>".&mt("The password for [_1] was not changed",$user)."</span></h3>". + &mt('Please make sure your old password was entered correctly').'.'); return 1; } return; @@ -1196,7 +1393,7 @@ sub handler { })); push (@Options,({ action => 'changemsgforward', - linktext => 'Change Message Forwarding and Notification Addresses', + linktext => 'Change Message Forwarding and Notification Email Addresses', href => '/adm/preferences', help => 'Prefs_Forwarding', breadcrumb => @@ -1280,20 +1477,21 @@ sub handler { printmenu => 'yes', subroutine => \&verify_and_change_discussion, } )); - + + my $role = ($env{'user.adv'} ? 'Roles' : 'Course'); push (@Options,({ action => 'changerolespref', - linktext => 'Change Roles Page Preferences', + linktext => 'Change '.$role.' Page Preferences', href => '/adm/preferences', subroutine => \&rolesprefchanger, breadcrumb => { href => '/adm/preferences?action=changerolespref', - text => 'Change Roles Pref'}, + text => 'Change '.$role.' Page Pref'}, }, { action => 'verify_and_change_rolespref', subroutine => \&verify_and_change_rolespref, breadcrumb => { href => '/adm/preferences?action=changerolespref', - text => 'Change Roles Preferences'}, + text => 'Change '.$role.' Page Preferences'}, printmenu => 'yes', })); @@ -1325,6 +1523,22 @@ sub handler { })); } + push (@Options,({ action => 'changeicons', + linktext => 'Change How Menus are Displayed', + href => '/adm/preferences', + subroutine => \&iconchanger, + breadcrumb => + { href => '/adm/preferences?action=changeicons', + text => 'Change Main Menu'}, + }, + { action => 'verify_and_change_icons', + subroutine => \&verify_and_change_icons, + breadcrumb => + { href => '/adm/preferences?action=changeicons', + text => 'Change Main Menu'}, + printmenu => 'yes', + })); + if (&Apache::lonnet::allowed('whn',$env{'request.course.id'}) || &Apache::lonnet::allowed('whn',$env{'request.course.id'}.'/' .$env{'request.course.sec'})) {