Diff for /loncom/interface/domainprefs.pm between versions 1.160.6.118.2.16 and 1.259

version 1.160.6.118.2.16, 2024/01/02 02:25:19 version 1.259, 2015/03/16 13:16:27
Line 19 Line 19
 #  #
 # You should have received a copy of the GNU General Public License  # You should have received a copy of the GNU General Public License
 # along with LON-CAPA; if not, write to the Free Software  # along with LON-CAPA; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA#
 #  
 # /home/httpd/html/adm/gpl.txt  # /home/httpd/html/adm/gpl.txt
 #  #
 # http://www.lon-capa.org/  # http://www.lon-capa.org/
 #  #
 #  #
 ###############################################################  ###############################################################
 ###############################################################  ##############################################################
   
 =pod  =pod
   
Line 104  $datatable  - HTML containing form eleme Line 103  $datatable  - HTML containing form eleme
   
 In the case of course requests, radio buttons are displayed for each institutional  In the case of course requests, radio buttons are displayed for each institutional
 affiliate type (and also default, and _LC_adv) for each of the course types   affiliate type (and also default, and _LC_adv) for each of the course types 
 (official, unofficial, community, textbook, and lti).  (official, unofficial, community, and textbook).  In each case the radio buttons 
 In each case the radio buttons allow the selection of one of four values:  allow the selection of one of four values:
   
 0, approval, validate, autolimit=N (where N is blank, or a positive integer).  0, approval, validate, autolimit=N (where N is blank, or a positive integer).
 which have the following effects:  which have the following effects:
Line 167  use Apache::lonmsg(); Line 166  use Apache::lonmsg();
 use Apache::lonconfigsettings;  use Apache::lonconfigsettings;
 use Apache::lonuserutils();  use Apache::lonuserutils();
 use Apache::loncoursequeueadmin();  use Apache::loncoursequeueadmin();
 use Apache::courseprefs();  
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
 use LONCAPA::Enrollment;  use LONCAPA::Enrollment;
 use LONCAPA::lonauthcgi();  use LONCAPA::lonauthcgi();
Line 175  use File::Copy; Line 173  use File::Copy;
 use Locale::Language;  use Locale::Language;
 use DateTime::TimeZone;  use DateTime::TimeZone;
 use DateTime::Locale;  use DateTime::Locale;
 use Time::HiRes qw( sleep );  
 use Net::CIDR;  
 use Crypt::CBC;  
   
 my $registered_cleanup;  my $registered_cleanup;
 my $modified_urls;  my $modified_urls;
Line 220  sub handler { Line 215  sub handler {
                 'contacts','defaults','scantron','coursecategories',                  'contacts','defaults','scantron','coursecategories',
                 'serverstatuses','requestcourses','helpsettings',                  'serverstatuses','requestcourses','helpsettings',
                 'coursedefaults','usersessions','loadbalancing',                  'coursedefaults','usersessions','loadbalancing',
                 'requestauthor','selfenrollment','inststatus',                  'requestauthor','selfenrollment','inststatus'],$dom);
                 'passwords','ltitools','toolsec','lti','ltisec',      my @prefs_order = ('rolecolors','login','defaults','quotas','autoenroll',
                 'wafproxy','ipaccess'],$dom);                         'autoupdate','autocreate','directorysrch','contacts',
     my %encconfig =                         'usercreation','selfcreation','usermodification','scantron',
         &Apache::lonnet::get_dom('encconfig',['ltitools','lti','linkprot'],$dom,undef,1);                         'requestcourses','requestauthor','coursecategories',
     my ($checked_is_home,$is_home);                         'serverstatuses','helpsettings',
     if (ref($domconfig{'ltitools'}) eq 'HASH') {                         'coursedefaults','selfenrollment','usersessions');
         if (ref($encconfig{'ltitools'}) eq 'HASH') {  
             my $home = &Apache::lonnet::domain($dom,'primary');  
             unless (($home eq 'no_host') || ($home eq '')) {  
                 my @ids=&Apache::lonnet::current_machine_ids();  
                 if (grep(/^\Q$home\E$/,@ids)) {  
                     $is_home = 1;  
                 }  
             }  
             $checked_is_home = 1;  
             foreach my $id (keys(%{$domconfig{'ltitools'}})) {  
                 if ((ref($domconfig{'ltitools'}{$id}) eq 'HASH') &&  
                     (ref($encconfig{'ltitools'}{$id}) eq 'HASH')) {  
                     $domconfig{'ltitools'}{$id}{'key'} = $encconfig{'ltitools'}{$id}{'key'};  
                     if (($is_home) && ($phase eq 'process')) {  
                         $domconfig{'ltitools'}{$id}{'secret'} = $encconfig{'ltitools'}{$id}{'secret'};  
                     }  
                 }  
             }  
         }  
     }  
     if (ref($domconfig{'lti'}) eq 'HASH') {  
         if (ref($encconfig{'lti'}) eq 'HASH') {  
             unless ($checked_is_home) {  
                 my $home = &Apache::lonnet::domain($dom,'primary');  
                 unless (($home eq 'no_host') || ($home eq '')) {  
                     my @ids=&Apache::lonnet::current_machine_ids();  
                     if (grep(/^\Q$home\E$/,@ids)) {  
                         $is_home = 1;  
                     }  
                 }  
                 $checked_is_home = 1;  
             }  
             foreach my $id (keys(%{$domconfig{'lti'}})) {  
                 if ((ref($domconfig{'lti'}{$id}) eq 'HASH') &&  
                     (ref($encconfig{'lti'}{$id}) eq 'HASH')) {  
                     $domconfig{'lti'}{$id}{'key'} = $encconfig{'lti'}{$id}{'key'};  
                     if (($is_home) && ($phase eq 'process')) {  
                         $domconfig{'lti'}{$id}{'secret'} = $encconfig{'lti'}{$id}{'secret'};  
                     }  
                 }  
             }  
         }  
     }  
     if (ref($domconfig{'ltisec'}) eq 'HASH') {  
         if (ref($domconfig{'ltisec'}{'linkprot'}) eq 'HASH') {  
             if (ref($encconfig{'linkprot'}) eq 'HASH') {  
                 foreach my $id (keys(%{$domconfig{'ltisec'}{'linkprot'}})) {  
                     unless ($id =~ /^\d+$/) {  
                         delete($domconfig{'ltisec'}{'linkprot'}{$id});  
                     }  
                     if ((ref($domconfig{'ltisec'}{'linkprot'}{$id}) eq 'HASH') &&  
                         (ref($encconfig{'linkprot'}{$id}) eq 'HASH')) {  
                         foreach my $item ('key','secret') {  
                             $domconfig{'ltisec'}{'linkprot'}{$id}{$item} = $encconfig{'linkprot'}{$id}{$item};  
                         }  
                     }  
                 }  
             }  
         }  
     }  
     my @prefs_order = ('rolecolors','login','ipaccess','defaults','wafproxy','passwords',  
                        'quotas','autoenroll','autoupdate','autocreate','directorysrch',  
                        'contacts','usercreation','selfcreation','usermodification',  
                        'scantron','requestcourses','requestauthor','coursecategories',  
                        'serverstatuses','helpsettings','coursedefaults',  
                        'ltitools','selfenrollment','usersessions','lti');  
     my %existing;      my %existing;
     if (ref($domconfig{'loadbalancing'}) eq 'HASH') {      if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
         %existing = %{$domconfig{'loadbalancing'}};          %existing = %{$domconfig{'loadbalancing'}};
Line 323  sub handler { Line 252  sub handler {
                                  {col1 => 'Log-in Help',                                   {col1 => 'Log-in Help',
                                   col2 => 'Value'},                                    col2 => 'Value'},
                                  {col1 => 'Custom HTML in document head',                                   {col1 => 'Custom HTML in document head',
                                   col2 => 'Value'},                                    col2 => 'Value'}],
                                  {col1 => 'SSO',  
                                   col2 => 'Dual login: SSO and non-SSO options'},  
                                 ],  
                       print => \&print_login,                        print => \&print_login,
                       modify => \&modify_login,                        modify => \&modify_login,
                     },                      },
Line 336  sub handler { Line 262  sub handler {
                       header => [{col1 => 'Setting',                        header => [{col1 => 'Setting',
                                   col2 => 'Value'},                                    col2 => 'Value'},
                                  {col1 => 'Institutional user types',                                   {col1 => 'Institutional user types',
                                   col2 => 'Name displayed'},                                    col2 => 'Assignable to e-mail usernames'}],
                                  {col1 => 'Mapping for missing usernames via standard log-in',  
                                   col2 => 'Rules in use'}],  
                       print => \&print_defaults,                        print => \&print_defaults,
                       modify => \&modify_defaults,                        modify => \&modify_defaults,
                     },                      },
         'wafproxy' =>  
                     { text => 'Web Application Firewall/Reverse Proxy',  
                       help => 'Domain_Configuration_WAF_Proxy',  
                       header => [{col1 => 'Domain(s)',  
                                   col2 => 'Servers and WAF/Reverse Proxy alias(es)',  
                                  },  
                                  {col1 => 'Domain(s)',  
                                   col2 => 'WAF Configuration',}],  
                       print => \&print_wafproxy,  
                       modify => \&modify_wafproxy,  
                     },  
         'passwords' =>  
                     { text => 'Passwords (Internal authentication)',  
                       help => 'Domain_Configuration_Passwords',  
                       header => [{col1 => 'Resetting Forgotten Password',  
                                   col2 => 'Settings'},  
                                  {col1 => 'Encryption of Stored Passwords (Internal Auth)',  
                                   col2 => 'Settings'},  
                                  {col1 => 'Rules for LON-CAPA Passwords',  
                                   col2 => 'Settings'},  
                                  {col1 => 'Course Owner Changing Student Passwords',  
                                   col2 => 'Settings'}],  
                       print => \&print_passwords,  
                       modify => \&modify_passwords,  
                     },  
         'quotas' =>           'quotas' => 
                     { text => 'Blogs, personal pages/timezones, webDAV/quotas, portfolio',                      { text => 'Blogs, personal web pages, webDAV/quotas, portfolios',
                       help => 'Domain_Configuration_Quotas',                        help => 'Domain_Configuration_Quotas',
                       header => [{col1 => 'User affiliation',                        header => [{col1 => 'User affiliation',
                                   col2 => 'Available tools',                                    col2 => 'Available tools',
Line 405  sub handler { Line 304  sub handler {
                      modify => \&modify_autocreate,                       modify => \&modify_autocreate,
                   },                    },
         'directorysrch' =>           'directorysrch' => 
                   { text => 'Directory searches',                    { text => 'Institutional directory searches',
                     help => 'Domain_Configuration_InstDirectory_Search',                      help => 'Domain_Configuration_InstDirectory_Search',
                     header => [{col1 => 'Institutional Directory Setting',                      header => [{col1 => 'Setting',
                                 col2 => 'Value',},  
                                {col1 => 'LON-CAPA Directory Setting',  
                                 col2 => 'Value',}],                                  col2 => 'Value',}],
                     print => \&print_directorysrch,                      print => \&print_directorysrch,
                     modify => \&modify_directorysrch,                      modify => \&modify_directorysrch,
                   },                    },
         'contacts' =>          'contacts' =>
                   { text => 'E-mail addresses and helpform',                    { text => 'Contact Information',
                     help => 'Domain_Configuration_Contact_Info',                      help => 'Domain_Configuration_Contact_Info',
                     header => [{col1 => 'Default e-mail addresses',                      header => [{col1 => 'Setting',
                                 col2 => 'Value',},                                  col2 => 'Value',}],
                                {col1 => 'Recipient(s) for notifications',  
                                 col2 => 'Value',},  
                                {col1 => 'Nightly status check e-mail',  
                                 col2 => 'Settings',},  
                                {col1 => 'Ask helpdesk form settings',  
                                 col2 => 'Value',},],  
                     print => \&print_contacts,                      print => \&print_contacts,
                     modify => \&modify_contacts,                      modify => \&modify_contacts,
                   },                    },
Line 447  sub handler { Line 338  sub handler {
                                 col2 => 'Enabled?'},                                  col2 => 'Enabled?'},
                                {col1 => 'Institutional user type (login/SSO self-creation)',                                 {col1 => 'Institutional user type (login/SSO self-creation)',
                                 col2 => 'Information user can enter'},                                  col2 => 'Information user can enter'},
                                {col1 => 'Self-creation with e-mail verification',                                 {col1 => 'Self-creation with e-mail as username',
                                 col2 => 'Settings'}],                                  col2 => 'Settings'}],
                     print => \&print_selfcreation,                      print => \&print_selfcreation,
                     modify => \&modify_selfcreation,                      modify => \&modify_selfcreation,
Line 463  sub handler { Line 354  sub handler {
                     modify => \&modify_usermodification,                      modify => \&modify_usermodification,
                   },                    },
         'scantron' =>          'scantron' =>
                   { text => 'Bubblesheet format',                    { text => 'Bubblesheet format file',
                     help => 'Domain_Configuration_Scantron_Format',                      help => 'Domain_Configuration_Scantron_Format',
                     header => [ {col1 => 'Bubblesheet format file',                      header => [ {col1 => 'Item',
                                  col2 => ''},                                   col2 => '',
                                 {col1 => 'Bubblesheet data upload formats',                                }],
                                  col2 => 'Settings'}],  
                     print => \&print_scantron,                      print => \&print_scantron,
                     modify => \&modify_scantron,                      modify => \&modify_scantron,
                   },                    },
Line 522  sub handler { Line 412  sub handler {
                   modify => \&modify_serverstatuses,                    modify => \&modify_serverstatuses,
                  },                   },
         'helpsettings' =>          'helpsettings' =>
                  {text   => 'Support settings',                   {text   => 'Help page settings',
                   help   => 'Domain_Configuration_Help_Settings',                    help   => 'Domain_Configuration_Help_Settings',
                   header => [{col1 => 'Help Page Settings (logged-in users)',                    header => [{col1 => 'Help Settings (logged-in users)',
                               col2 => 'Value'},                                col2 => 'Value'}],
                              {col1 => 'Helpdesk Roles',  
                               col2 => 'Settings'},],  
                   print  => \&print_helpsettings,                    print  => \&print_helpsettings,
                   modify => \&modify_helpsettings,                    modify => \&modify_helpsettings,
                  },                   },
Line 553  sub handler { Line 441  sub handler {
                   print => \&print_selfenrollment,                    print => \&print_selfenrollment,
                   modify => \&modify_selfenrollment,                    modify => \&modify_selfenrollment,
                  },                   },
           'privacy' => 
                    {text   => 'User Privacy',
                     help   => 'Domain_Configuration_User_Privacy',
                     header => [{col1 => 'Setting',
                                 col2 => 'Value',}],
                     print => \&print_privacy,
                     modify => \&modify_privacy,
                    },
         'usersessions' =>          'usersessions' =>
                  {text  => 'User session hosting/offloading',                   {text  => 'User session hosting/offloading',
                   help  => 'Domain_Configuration_User_Sessions',                    help  => 'Domain_Configuration_User_Sessions',
Line 565  sub handler { Line 461  sub handler {
                   print => \&print_usersessions,                    print => \&print_usersessions,
                   modify => \&modify_usersessions,                    modify => \&modify_usersessions,
                  },                   },
         'loadbalancing' =>           'loadbalancing' =>
                  {text  => 'Dedicated Load Balancer(s)',                   {text  => 'Dedicated Load Balancer(s)',
                   help  => 'Domain_Configuration_Load_Balancing',                    help  => 'Domain_Configuration_Load_Balancing',
                   header => [{col1 => 'Balancers',                    header => [{col1 => 'Balancers',
Line 576  sub handler { Line 472  sub handler {
                   print => \&print_loadbalancing,                    print => \&print_loadbalancing,
                   modify => \&modify_loadbalancing,                    modify => \&modify_loadbalancing,
                  },                   },
         'ltitools' =>  
                  {text => 'External Tools (LTI)',  
                   help => 'Domain_Configuration_LTI_Tools',  
                   header => [{col1 => 'Encryption of shared secrets',  
                               col2 => 'Settings'},  
                              {col1 => 'Rules for shared secrets',  
                               col2 => 'Settings'},  
                              {col1 => 'Providers',  
                               col2 => 'Settings',}],  
                   print => \&print_ltitools,  
                   modify => \&modify_ltitools,  
                  },  
         'lti' =>  
                  {text => 'LTI Link Protection and LTI Consumers',  
                   help => 'Domain_Configuration_LTI_Provider',  
                   header => [{col1 => 'Encryption of shared secrets',  
                               col2 => 'Settings'},  
                              {col1 => 'Rules for shared secrets',  
                               col2 => 'Settings'},  
                              {col1 => 'Link Protectors',  
                               col2 => 'Settings'},  
                              {col1 => 'Consumers',  
                               col2 => 'Settings'},],  
                   print => \&print_lti,  
                   modify => \&modify_lti,  
                  },  
         'ipaccess' =>  
                        {text => 'IP-based access control',  
                         help => 'Domain_Configuration_IP_Access',  
                         header => [{col1 => 'Setting',  
                                     col2 => 'Value'},],  
                         print  => \&print_ipaccess,  
                         modify => \&modify_ipaccess,  
                        },  
     );      );
     if (keys(%servers) > 1) {      if (keys(%servers) > 1) {
         $prefs{'login'}  = { text   => 'Log-in page options',          $prefs{'login'}  = { text   => 'Log-in page options',
Line 617  sub handler { Line 479  sub handler {
                             header => [{col1 => 'Log-in Service',                              header => [{col1 => 'Log-in Service',
                                         col2 => 'Server Setting',},                                          col2 => 'Server Setting',},
                                        {col1 => 'Log-in Page Items',                                         {col1 => 'Log-in Page Items',
                                         col2 => 'Settings'},                                          col2 => ''},
                                        {col1 => 'Log-in Help',                                         {col1 => 'Log-in Help',
                                         col2 => 'Value'},                                          col2 => 'Value'},
                                        {col1 => 'Custom HTML in document head',                                         {col1 => 'Custom HTML in document head',
                                         col2 => 'Value'},                                          col2 => 'Value'}],
                                        {col1 => 'SSO',  
                                         col2 => 'Dual login: SSO and non-SSO options'},  
                                       ],  
                             print => \&print_login,                              print => \&print_login,
                             modify => \&modify_login,                              modify => \&modify_login,
                            };                             };
Line 665  $javascript_validations Line 524  $javascript_validations
 </script>  </script>
 $coursebrowserjs  $coursebrowserjs
 END  END
         } elsif (grep(/^ipaccess$/,@actions)) {  
             $js .= &Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'});  
         }  
         if (grep(/^selfcreation$/,@actions)) {  
             $js .= &selfcreate_javascript();  
         }  
         if (grep(/^contacts$/,@actions)) {  
             $js .= &contacts_javascript();  
         }  
         if (grep(/^scantron$/,@actions)) {  
             $js .= &scantron_javascript();  
         }          }
         &Apache::lonconfigsettings::display_settings($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname,$js);          &Apache::lonconfigsettings::display_settings($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname,$js);
     } else {      } else {
Line 766  sub process_changes { Line 614  sub process_changes {
     } elsif ($action eq 'autocreate') {      } elsif ($action eq 'autocreate') {
         $output = &modify_autocreate($dom,%domconfig);          $output = &modify_autocreate($dom,%domconfig);
     } elsif ($action eq 'directorysrch') {      } elsif ($action eq 'directorysrch') {
         $output = &modify_directorysrch($dom,$lastactref,%domconfig);          $output = &modify_directorysrch($dom,%domconfig);
     } elsif ($action eq 'usercreation') {      } elsif ($action eq 'usercreation') {
         $output = &modify_usercreation($dom,%domconfig);          $output = &modify_usercreation($dom,%domconfig);
     } elsif ($action eq 'selfcreation') {      } elsif ($action eq 'selfcreation') {
         $output = &modify_selfcreation($dom,$lastactref,%domconfig);          $output = &modify_selfcreation($dom,%domconfig);
     } elsif ($action eq 'usermodification') {      } elsif ($action eq 'usermodification') {
         $output = &modify_usermodification($dom,%domconfig);          $output = &modify_usermodification($dom,%domconfig);
     } elsif ($action eq 'contacts') {      } elsif ($action eq 'contacts') {
Line 788  sub process_changes { Line 636  sub process_changes {
     } elsif ($action eq 'requestauthor') {      } elsif ($action eq 'requestauthor') {
         $output = &modify_quotas($r,$dom,$action,$lastactref,%domconfig);          $output = &modify_quotas($r,$dom,$action,$lastactref,%domconfig);
     } elsif ($action eq 'helpsettings') {      } elsif ($action eq 'helpsettings') {
         $output = &modify_helpsettings($r,$dom,$confname,$lastactref,%domconfig);          $output = &modify_helpsettings($r,$dom,$confname,%domconfig);
     } elsif ($action eq 'coursedefaults') {      } elsif ($action eq 'coursedefaults') {
         $output = &modify_coursedefaults($dom,$lastactref,%domconfig);          $output = &modify_coursedefaults($dom,$lastactref,%domconfig);
     } elsif ($action eq 'selfenrollment') {      } elsif ($action eq 'selfenrollment') {
Line 797  sub process_changes { Line 645  sub process_changes {
         $output = &modify_usersessions($dom,$lastactref,%domconfig);          $output = &modify_usersessions($dom,$lastactref,%domconfig);
     } elsif ($action eq 'loadbalancing') {      } elsif ($action eq 'loadbalancing') {
         $output = &modify_loadbalancing($dom,%domconfig);          $output = &modify_loadbalancing($dom,%domconfig);
     } elsif ($action eq 'ltitools') {  
         $output = &modify_ltitools($r,$dom,$action,$lastactref,%domconfig);  
     } elsif ($action eq 'lti') {  
         $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);  
     } elsif ($action eq 'passwords') {  
         $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);  
     } elsif ($action eq 'wafproxy') {  
         $output = &modify_wafproxy($dom,$action,$lastactref,%domconfig);  
     } elsif ($action eq 'ipaccess') {  
         $output = &modify_ipaccess($dom,$lastactref,%domconfig);  
     }      }
     return $output;      return $output;
 }  }
Line 819  sub print_config_box { Line 657  sub print_config_box {
         $output = &coursecategories_javascript($settings);          $output = &coursecategories_javascript($settings);
     } elsif ($action eq 'defaults') {      } elsif ($action eq 'defaults') {
         $output = &defaults_javascript($settings);           $output = &defaults_javascript($settings); 
     } elsif ($action eq 'passwords') {  
         $output = &passwords_javascript($action);  
     } elsif ($action eq 'helpsettings') {  
         my (%privs,%levelscurrent);  
         my %full=();  
         my %levels=(  
                      course => {},  
                      domain => {},  
                      system => {},  
                    );  
         my $context = 'domain';  
         my $crstype = 'Course';  
         my $formname = 'display';  
         &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);  
         my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);  
         $output =  
             &Apache::lonuserutils::custom_roledefs_js($context,$crstype,$formname,\%full,  
                                                       \@templateroles);  
     } elsif ($action eq 'ltitools') {  
         $output .= &Apache::lonconfigsettings::ltitools_javascript($settings);  
     } elsif ($action eq 'lti') {  
         $output .= &passwords_javascript('ltisecrets')."\n".  
                    &lti_javascript($dom,$settings);  
     } elsif ($action eq 'wafproxy') {  
         $output .= &wafproxy_javascript($dom);  
     } elsif ($action eq 'autoupdate') {  
         $output .= &autoupdate_javascript();  
     } elsif ($action eq 'autoenroll') {  
         $output .= &autoenroll_javascript();  
     } elsif ($action eq 'login') {  
         $output .= &saml_javascript();  
     } elsif ($action eq 'ipaccess') {  
         $output .= &ipaccess_javascript($settings);  
     }      }
     $output .=      $output .=
          '<table class="LC_nested_outer">           '<table class="LC_nested_outer">
           <tr>            <tr>
            <th class="LC_left_item LC_middle"><span class="LC_nobreak">'.             <th align="left" valign="middle"><span class="LC_nobreak">'.
            &mt($item->{text}).'&nbsp;'.             &mt($item->{text}).'&nbsp;'.
            &Apache::loncommon::help_open_topic($item->{'help'}).'</span></th>'."\n".             &Apache::loncommon::help_open_topic($item->{'help'}).'</span></th>'."\n".
           '</tr>';            '</tr>';
Line 868  sub print_config_box { Line 673  sub print_config_box {
     if ($numheaders > 1) {      if ($numheaders > 1) {
         my $colspan = '';          my $colspan = '';
         my $rightcolspan = '';          my $rightcolspan = '';
         my $leftnobr = '';  
         if (($action eq 'rolecolors') || ($action eq 'defaults') ||          if (($action eq 'rolecolors') || ($action eq 'defaults') ||
             ($action eq 'directorysrch') ||              (($action eq 'login') && ($numheaders < 4))) {
             (($action eq 'login') && ($numheaders < 5))) {  
             $colspan = ' colspan="2"';              $colspan = ' colspan="2"';
         }          }
         if ($action eq 'usersessions') {          if ($action eq 'usersessions') {
             $rightcolspan = ' colspan="3"';               $rightcolspan = ' colspan="3"'; 
         }          }
         if ($action eq 'passwords') {  
             $leftnobr = ' LC_nobreak';  
         }  
         $output .= '          $output .= '
           <tr>            <tr>
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[0]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[0]->{'col1'}).'</td>
               <td class="LC_right_item"'.$rightcolspan.'>'.&mt($item->{'header'}->[0]->{'col2'}).'</td>                <td class="LC_right_item"'.$rightcolspan.'>'.&mt($item->{'header'}->[0]->{'col2'}).'</td>
              </tr>';               </tr>';
         $rowtotal ++;          $rowtotal ++;
         if (($action eq 'autoupdate') || ($action eq 'usercreation') || ($action eq 'selfcreation') ||          if (($action eq 'autoupdate') || ($action eq 'usercreation') || ($action eq 'selfcreation') ||
             ($action eq 'usermodification') || ($action eq 'defaults') || ($action eq 'coursedefaults') ||              ($action eq 'usermodification') || ($action eq 'defaults') || ($action eq 'coursedefaults') ||
             ($action eq 'selfenrollment') || ($action eq 'usersessions') || ($action eq 'directorysrch') ||              ($action eq 'selfenrollment') || ($action eq 'usersessions')) {
             ($action eq 'helpsettings') || ($action eq 'contacts') || ($action eq 'wafproxy') ||  
             ($action eq 'lti') || ($action eq 'ltitools')) {  
             $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);              $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'passwords') {  
             $output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);  
         } elsif ($action eq 'coursecategories') {          } elsif ($action eq 'coursecategories') {
             $output .= $item->{'print'}->('top',$dom,$item,$settings,\$rowtotal);              $output .= $item->{'print'}->('top',$dom,$item,$settings,\$rowtotal);
         } elsif ($action eq 'scantron') {  
             $output .= $item->{'print'}->($r,'top',$dom,$confname,$settings,\$rowtotal);  
         } elsif ($action eq 'login') {          } elsif ($action eq 'login') {
             if ($numheaders == 5) {              if ($numheaders == 4) {
                 $colspan = ' colspan="2"';                  $colspan = ' colspan="2"';
                 $output .= &print_login('service',$dom,$confname,$phase,$settings,\$rowtotal);                  $output .= &print_login('service',$dom,$confname,$phase,$settings,\$rowtotal);
             } else {              } else {
Line 927  sub print_config_box { Line 721  sub print_config_box {
             $rowtotal ++;              $rowtotal ++;
         if (($action eq 'autoupdate') || ($action eq 'usercreation') ||          if (($action eq 'autoupdate') || ($action eq 'usercreation') ||
             ($action eq 'selfcreation') || ($action eq 'selfenrollment') ||              ($action eq 'selfcreation') || ($action eq 'selfenrollment') ||
             ($action eq 'usersessions') || ($action eq 'coursecategories') ||              ($action eq 'usersessions') || ($action eq 'coursecategories')) {
             ($action eq 'contacts') || ($action eq 'passwords') ||   
             ($action eq 'defaults') || ($action eq 'lti') ||  
             ($action eq 'ltitools')) {  
             if ($action eq 'coursecategories') {              if ($action eq 'coursecategories') {
                 $output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);                  $output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);
                 $colspan = ' colspan="2"';                  $colspan = ' colspan="2"';
             } elsif ($action eq 'passwords') {  
                 $output .= $item->{'print'}->('middle',$dom,$confname,$settings,\$rowtotal);  
             } else {              } else {
                 $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);                  $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);
             }              }
Line 952  sub print_config_box { Line 741  sub print_config_box {
              </tr>'."\n";               </tr>'."\n";
             if ($action eq 'coursecategories') {              if ($action eq 'coursecategories') {
                 $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);                  $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);
             } elsif (($action eq 'contacts') || ($action eq 'passwords')) {  
                 if ($action eq 'passwords') {  
                     $output .= $item->{'print'}->('lower',$dom,$confname,$settings,\$rowtotal);  
                 } else {  
                     $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal);  
                 }  
                 $output .= '  
              </tr>  
             </table>  
            </td>  
           </tr>  
           <tr>  
            <td>  
             <table class="LC_nested">  
              <tr class="LC_info_row">  
               <td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>  
               <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'."\n";  
                 if ($action eq 'passwords') {  
                     $output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal);  
                 } else {  
                     $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);  
                 }  
                 $output .= '  
             </table>  
           </td>  
          </tr>  
          <tr>';  
             } else {              } else {
                 $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);                  $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
             }              }
             $rowtotal ++;              $rowtotal ++;
         } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||          } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||
                  ($action eq 'directorysrch') || ($action eq 'helpsettings') ||                    ($action eq 'defaults')) {
                  ($action eq 'wafproxy')) {  
             $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);              $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'scantron') {  
             $output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal);  
         } elsif ($action eq 'login') {          } elsif ($action eq 'login') {
             if ($numheaders == 5) {              if ($numheaders == 4) {
                 $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).'                  $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).'
            </table>             </table>
           </td>            </td>
Line 1014  sub print_config_box { Line 773  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">';               <tr class="LC_info_row">';
             if ($numheaders == 5) {              if ($numheaders == 4) {
                 $output .= '                  $output .= '
               <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
               <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td>                <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td>
Line 1026  sub print_config_box { Line 785  sub print_config_box {
              </tr>';               </tr>';
             }              }
             $rowtotal ++;              $rowtotal ++;
             $output .= &print_login('headtag',$dom,$confname,$phase,$settings,\$rowtotal).'              $output .= &print_login('headtag',$dom,$confname,$phase,$settings,\$rowtotal);
            </table>  
           </td>  
          </tr>  
          <tr>  
            <td>  
             <table class="LC_nested">  
              <tr class="LC_info_row">';  
             if ($numheaders == 5) {  
                 $output .= '  
               <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[4]->{'col1'}).'</td>  
               <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[4]->{'col2'}).'</td>  
              </tr>';  
             } else {  
                 $output .= '  
               <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>  
               <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td>  
              </tr>';  
             }  
             $rowtotal ++;  
             $output .= &print_login('saml',$dom,$confname,$phase,$settings,\$rowtotal);  
         } elsif ($action eq 'requestcourses') {          } elsif ($action eq 'requestcourses') {
             $output .= &print_requestmail($dom,$action,$settings,\$rowtotal);              $output .= &print_requestmail($dom,$action,$settings,\$rowtotal);
             $rowtotal ++;              $rowtotal ++;
Line 1120  sub print_config_box { Line 859  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">';               <tr class="LC_info_row">';
         if ($action eq 'login') {          if (($action eq 'login') || ($action eq 'directorysrch')) {
             $output .= '                $output .= '  
               <td class="LC_left_item" colspan="2">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';                <td class="LC_left_item" colspan="2">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';
         } elsif ($action eq 'serverstatuses') {          } elsif ($action eq 'serverstatuses') {
Line 1164  sub print_config_box { Line 903  sub print_config_box {
         $rowtotal ++;          $rowtotal ++;
         if ($action eq 'quotas') {          if ($action eq 'quotas') {
             $output .= &print_quotas($dom,$settings,\$rowtotal,$action);              $output .= &print_quotas($dom,$settings,\$rowtotal,$action);
         } elsif (($action eq 'autoenroll') || ($action eq 'autocreate') ||           } elsif (($action eq 'autoenroll') || ($action eq 'autocreate') || ($action eq 'directorysrch') ||
                  ($action eq 'serverstatuses') || ($action eq 'loadbalancing') ||                   ($action eq 'contacts') || ($action eq 'serverstatuses') || ($action eq 'loadbalancing')) {
                  ($action eq 'ipaccess')) {  
             $output .= $item->{'print'}->($dom,$settings,\$rowtotal);              $output .= $item->{'print'}->($dom,$settings,\$rowtotal);
           } elsif ($action eq 'scantron') {
               $output .= &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal);
           } elsif ($action eq 'helpsettings') {
               $output .= &print_helpsettings($dom,$confname,$settings,\$rowtotal);
         }          }
     }      }
     $output .= '      $output .= '
Line 1180  sub print_config_box { Line 922  sub print_config_box {
   
 sub print_login {  sub print_login {
     my ($caller,$dom,$confname,$phase,$settings,$rowtotal) = @_;      my ($caller,$dom,$confname,$phase,$settings,$rowtotal) = @_;
     my ($css_class,$datatable,$switchserver,%lt);      my ($css_class,$datatable);
     my %choices = &login_choices();      my %choices = &login_choices();
     if (($caller eq 'help') || ($caller eq 'headtag') || ($caller eq 'saml')) {  
         %lt = &login_file_options();  
         $switchserver = &check_switchserver($dom,$confname);  
     }  
     if ($caller eq 'service') {      if ($caller eq 'service') {
         my %servers = &Apache::lonnet::internet_dom_servers($dom);          my %servers = &Apache::lonnet::internet_dom_servers($dom);
         my $choice = $choices{'disallowlogin'};          my $choice = $choices{'disallowlogin'};
Line 1272  sub print_login { Line 1011  sub print_login {
             }              }
         }          }
         my @images = ('img','logo','domlogo','login');          my @images = ('img','logo','domlogo','login');
         my @alttext = ('img','logo','domlogo');  
         my @logintext = ('textcol','bgcol');          my @logintext = ('textcol','bgcol');
         my @bgs = ('pgbg','mainbg','sidebg');          my @bgs = ('pgbg','mainbg','sidebg');
         my @links = ('link','alink','vlink');          my @links = ('link','alink','vlink');
Line 1314  sub print_login { Line 1052  sub print_login {
                     $designs{'showlogo'}{$item} = $settings->{'showlogo'}{$item};                      $designs{'showlogo'}{$item} = $settings->{'showlogo'}{$item};
                 }                  }
             }              }
             foreach my $item (@alttext) {  
                 if (ref($settings->{'alttext'}) eq 'HASH') {  
                     if ($settings->{'alttext'}->{$item} ne '') {  
                         $designs{'alttext'}{$item} = $settings->{'alttext'}{$item};  
                     }  
                 }  
             }  
             foreach my $item (@logintext) {              foreach my $item (@logintext) {
                 if ($settings->{$item} ne '') {                  if ($settings->{$item} ne '') {
                     $designs{'logintext'}{$item} = $settings->{$item};                      $designs{'logintext'}{$item} = $settings->{$item};
Line 1387  sub print_login { Line 1118  sub print_login {
         $datatable .= &display_color_options($dom,$confname,$phase,'login',$itemcount,\%choices,\%is_custom,\%defaults,\%designs,\@images,\@bgs,\@links,\%alt_text,$rowtotal,\@logintext);          $datatable .= &display_color_options($dom,$confname,$phase,'login',$itemcount,\%choices,\%is_custom,\%defaults,\%designs,\@images,\@bgs,\@links,\%alt_text,$rowtotal,\@logintext);
         $datatable .= '</tr></table></td></tr>';          $datatable .= '</tr></table></td></tr>';
     } elsif ($caller eq 'help') {      } elsif ($caller eq 'help') {
         my ($defaulturl,$defaulttype,%url,%type,%langchoices);          my ($defaulturl,$defaulttype,%url,%type,%lt,%langchoices);
           my $switchserver = &check_switchserver($dom,$confname);
         my $itemcount = 1;          my $itemcount = 1;
         $defaulturl = '/adm/loginproblems.html';          $defaulturl = '/adm/loginproblems.html';
         $defaulttype = 'default';          $defaulttype = 'default';
           %lt = &Apache::lonlocal::texthash (
                        del     => 'Delete?',
                        rep     => 'Replace:',
                        upl     => 'Upload:',
                        default => 'Default',
                        custom  => 'Custom',
                                                );
         %langchoices = &Apache::lonlocal::texthash(&get_languages_hash());          %langchoices = &Apache::lonlocal::texthash(&get_languages_hash());
         my @currlangs;          my @currlangs;
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
Line 1487  sub print_login { Line 1226  sub print_login {
                 }                  }
             }              }
         }          }
           my %lt = &Apache::lonlocal::texthash(
                                                  del  => 'Delete?',
                                                  rep  => 'Replace:',
                                                  upl  => 'Upload:',
                                                  curr => 'View contents',
                                                  none => 'None',
           );
           my $switchserver = &check_switchserver($dom,$confname);
         foreach my $lonhost (sort(keys(%domservers))) {          foreach my $lonhost (sort(keys(%domservers))) {
             my $exempt = &check_exempt_addresses($currexempt{$lonhost});              my $exempt = &check_exempt_addresses($currexempt{$lonhost});
             $datatable .= '<tr><td>'.$domservers{$lonhost}.'</td>';              $datatable .= '<tr><td>'.$domservers{$lonhost}.'</td>';
Line 1507  sub print_login { Line 1254  sub print_login {
             } else {              } else {
                 $datatable .= '<input type="file" name="loginheadtag_'.$lonhost.'" />';                  $datatable .= '<input type="file" name="loginheadtag_'.$lonhost.'" />';
             }              }
             $datatable .= '</td><td><input type="text" name="loginheadtagexempt_'.$lonhost.'" value="'.$exempt.'" /></td></tr>';              $datatable .= '</td><td><input type="textbox" name="loginheadtagexempt_'.$lonhost.'" value="'.$exempt.'" /></td></tr>';
         }  
         $datatable .= '</table></td></tr>';  
     } elsif ($caller eq 'saml') {  
         my %domservers = &Apache::lonnet::get_servers($dom);  
         $datatable .= '<tr><td colspan="3" style="text-align: left">'.  
                       '<table><tr><th>'.$choices{'hostid'}.'</th>'.  
                       '<th>'.$choices{'samllanding'}.'</th>'.  
                       '<th>'.$choices{'samloptions'}.'</th></tr>'."\n";  
         my (%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlwindow,%samlnotsso,%styleon,%styleoff);  
         foreach my $lonhost (keys(%domservers)) {  
             $samlurl{$lonhost} = '/adm/sso';  
             $styleon{$lonhost} = 'display:none';  
             $styleoff{$lonhost} = '';  
         }  
         if ((ref($settings) eq 'HASH') && (ref($settings->{'saml'}) eq 'HASH')) {  
             foreach my $lonhost (keys(%{$settings->{'saml'}})) {  
                 if (ref($settings->{'saml'}{$lonhost}) eq 'HASH') {  
                     $saml{$lonhost} = 1;  
                     $samltext{$lonhost} = $settings->{'saml'}{$lonhost}{'text'};  
                     $samlimg{$lonhost} = $settings->{'saml'}{$lonhost}{'img'};  
                     $samlalt{$lonhost} = $settings->{'saml'}{$lonhost}{'alt'};  
                     $samlurl{$lonhost} = $settings->{'saml'}{$lonhost}{'url'};  
                     $samltitle{$lonhost} = $settings->{'saml'}{$lonhost}{'title'};  
                     $samlwindow{$lonhost} = $settings->{'saml'}{$lonhost}{'window'};  
                     $samlnotsso{$lonhost} = $settings->{'saml'}{$lonhost}{'notsso'};  
                     $styleon{$lonhost} = '';  
                     $styleoff{$lonhost} = 'display:none';  
                 } else {  
                     $styleon{$lonhost} = 'display:none';  
                     $styleoff{$lonhost} = '';  
                 }  
             }  
         }  
         my $itemcount = 1;  
         foreach my $lonhost (sort(keys(%domservers))) {  
             my $samlon = ' ';  
             my $samloff = ' checked="checked" ';  
             if ($saml{$lonhost}) {  
                 $samlon = $samloff;  
                 $samloff = ' ';  
             }  
             my $samlwinon = '';  
             my $samlwinoff = ' checked="checked"';  
             if ($samlwindow{$lonhost}) {  
                 $samlwinon = $samlwinoff;  
                 $samlwinoff = '';  
             }  
             my $css_class = $itemcount%2?' class="LC_odd_row"':'';  
             $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.$domservers{$lonhost}.'</span></td>'.  
                           '<td><span class="LC_nobreak"><label><input type="radio" name="saml_'.$lonhost.'"'.$samloff.  
                           'onclick="toggleSamlOptions(this.form,'."'$lonhost'".');" value="0" />'.  
                           &mt('No').'</label>'.('&nbsp;'x2).  
                           '<label><input type="radio" name="saml_'.$lonhost.'"'.$samlon.  
                           'onclick="toggleSamlOptions(this.form,'."'$lonhost'".');" value="1" />'.  
                           &mt('Yes').'</label></span></td>'.  
                           '<td id="samloptionson_'.$lonhost.'" style="'.$styleon{$lonhost}.'" width="100%">'.  
                           '<table width="100%"><tr><th colspan="3" align="center">'.&mt('SSO').'</th></tr>'.  
                           '<tr><th>'.&mt('Text').'</th><th>'.&mt('Image').'</th>'.  
                           '<th>'.&mt('Alt Text').'</th></tr>'.  
                           '<tr'.$css_class.'><td><input type="text" name="saml_text_'.$lonhost.'" size="20" value="'.  
                           $samltext{$lonhost}.'" /></td><td>';  
             if ($samlimg{$lonhost}) {  
                 $datatable .= '<img src="'.$samlimg{$lonhost}.'" /><br />'.  
                               '<span class="LC_nobreak"><label>'.  
                               '<input type="checkbox" name="saml_img_del" value="'.$lonhost.'" />'.  
                               $lt{'del'}.'</label>&nbsp;'.$lt{'rep'}.'</span>';  
             } else {  
                 $datatable .= $lt{'upl'};  
             }  
             $datatable .='<br />';  
             if ($switchserver) {  
                 $datatable .= &mt('Upload to library server: [_1]',$switchserver);  
             } else {  
                 $datatable .= '<input type="file" name="saml_img_'.$lonhost.'" />';  
             }  
             $datatable .= '</td>'.  
                           '<td><input type="text" name="saml_alt_'.$lonhost.'" size="25" '.  
                           'value="'.$samlalt{$lonhost}.'" /></td></tr></table><br />'.  
                           '<table width="100%"><tr><th colspan="3" align="center">'.&mt('SSO').'</th><th align="center">'.  
                           '<span class="LC_nobreak">'.&mt('Non-SSO').'</span></th></tr>'.  
                           '<tr><th>'.&mt('URL').'</th><th>'.&mt('Tool Tip').'</th>'.  
                           '<th>'.&mt('Pop-up if iframe').'</th><th>'.&mt('Text').'</th></tr>'.  
                           '<tr'.$css_class.'>'.  
                           '<td><input type="text" name="saml_url_'.$lonhost.'" size="30" '.  
                           'value="'.$samlurl{$lonhost}.'" /></td>'.  
                           '<td><textarea name="saml_title_'.$lonhost.'" rows="3" cols="20">'.  
                           $samltitle{$lonhost}.'</textarea></td>'.  
                           '<td><label><input type="radio" name="saml_window_'.$lonhost.'" value=""'.$samlwinoff.'>'.  
                           &mt('No').'</label>'.('&nbsp;'x2).'<label><input type="radio" '.  
                           'name="saml_window_'.$lonhost.'" value="1"'.$samlwinon.'>'.&mt('Yes').'</label></td>'.  
                           '<td><input type="text" name="saml_notsso_'.$lonhost.'" size="12" '.  
                           'value="'.$samlnotsso{$lonhost}.'" /></td></tr>'.  
                           '</table></td>'.  
                           '<td id="samloptionsoff_'.$lonhost.'" style="'.$styleoff{$lonhost}.'" width="100%">&nbsp;</td></tr>';  
            $itemcount ++;  
         }          }
         $datatable .= '</table></td></tr>';          $datatable .= '</table></td></tr>';
     }      }
Line 1641  sub login_choices { Line 1293  sub login_choices {
             headtag       => "Custom markup",              headtag       => "Custom markup",
             action        => "Action",              action        => "Action",
             current       => "Current",              current       => "Current",
             samllanding   => "Dual login?",  
             samloptions   => "Options",  
             alttext       => "Alt text",  
         );          );
     return %choices;      return %choices;
 }  }
   
 sub login_file_options {  
       return &Apache::lonlocal::texthash(  
                                            del     => 'Delete?',  
                                            rep     => 'Replace:',  
                                            upl     => 'Upload:',  
                                            curr    => 'View contents',  
                                            default => 'Default',  
                                            custom  => 'Custom',  
                                            none    => 'None',  
       );  
 }  
   
 sub print_ipaccess {  
     my ($dom,$settings,$rowtotal) = @_;  
     my $css_class;  
     my $itemcount = 0;  
     my $datatable;  
     my %ordered;  
     if (ref($settings) eq 'HASH') {  
         foreach my $item (keys(%{$settings})) {  
             if (ref($settings->{$item}) eq 'HASH') {  
                 my $num = $settings->{$item}{'order'};  
                 if ($num eq '') {  
                     $num = scalar(keys(%{$settings}));  
                 }  
                 $ordered{$num} = $item;  
             }  
         }  
     }  
     my $maxnum = scalar(keys(%ordered));  
     if (keys(%ordered)) {  
         my @items = sort { $a <=> $b } keys(%ordered);  
         for (my $i=0; $i<@items; $i++) {  
             $css_class = $itemcount%2?' class="LC_odd_row"':'';  
             my $item = $ordered{$items[$i]};  
             my ($name,$ipranges,%commblocks,%courses);  
             if (ref($settings->{$item}) eq 'HASH') {  
                 $name = $settings->{$item}->{'name'};  
                 $ipranges = $settings->{$item}->{'ip'};  
                 if (ref($settings->{$item}->{'commblocks'}) eq 'HASH') {  
                     %commblocks = %{$settings->{$item}->{'commblocks'}};  
                 }  
                 if (ref($settings->{$item}->{'courses'}) eq 'HASH') {  
                     %courses = %{$settings->{$item}->{'courses'}};  
                 }  
             }  
             my $chgstr = ' onchange="javascript:reorderIPaccess(this.form,'."'ipaccess_pos_".$item."'".');"';  
             $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'  
                          .'<select name="ipaccess_pos_'.$item.'"'.$chgstr.'>';  
             for (my $k=0; $k<=$maxnum; $k++) {  
                 my $vpos = $k+1;  
                 my $selstr;  
                 if ($k == $i) {  
                     $selstr = ' selected="selected" ';  
                 }  
                 $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';  
             }  
             $datatable .= '</select>'.('&nbsp;'x2).  
                 '<label><input type="checkbox" name="ipaccess_del" value="'.$item.'" />'.  
                 &mt('Delete?').'</label></span></td>'.  
                 '<td colspan="2"><input type="hidden" name="ipaccess_id_'.$i.'" value="'.$item.'" />'.  
                 &ipaccess_options($i,$itemcount,$dom,$name,$ipranges,\%commblocks,\%courses).  
                 '</td></tr>';  
             $itemcount ++;  
         }  
     }  
     $css_class = $itemcount%2?' class="LC_odd_row"':'';  
     my $chgstr = ' onchange="javascript:reorderIPaccess(this.form,'."'ipaccess_pos_add'".');"';  
     $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".  
                   '<input type="hidden" name="ipaccess_maxnum" value="'.$maxnum.'" />'."\n".  
                   '<select name="ipaccess_pos_add"'.$chgstr.'>';  
     for (my $k=0; $k<$maxnum+1; $k++) {  
         my $vpos = $k+1;  
         my $selstr;  
         if ($k == $maxnum) {  
             $selstr = ' selected="selected" ';  
         }  
         $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';  
     }  
     $datatable .= '</select>&nbsp;'."\n".  
                   '<input type="checkbox" name="ipaccess_add" value="1" />'.&mt('Add').'</span></td>'."\n".  
                   '<td colspan="2">'.  
                   &ipaccess_options('add',$itemcount,$dom).  
                   '</td>'."\n".  
                   '</tr>'."\n";  
     $$rowtotal ++;  
     return $datatable;  
 }  
   
 sub ipaccess_options {  
     my ($num,$itemcount,$dom,$name,$ipranges,$blocksref,$coursesref) = @_;  
     my (%currblocks,%currcourses,$output);  
     if (ref($blocksref) eq 'HASH') {  
         %currblocks = %{$blocksref};  
     }  
     if (ref($coursesref) eq 'HASH') {  
         %currcourses = %{$coursesref};  
     }  
     $output = '<fieldset><legend>'.&mt('Location(s)').'</legend>'.  
               '<span class="LC_nobreak">'.&mt('Name').':&nbsp;'.  
               '<input type="text" name="ipaccess_name_'.$num.'" value="'.$name.'" />'.  
               '</span></fieldset>'.  
               '<fieldset><legend>'.&mt('IP Range(s)').'</legend>'.  
               &mt('Format for each IP range').': '.&mt('A.B.C.D/N or A.B.C.D-E.F.G.H').'<br />'.  
               &mt('Range(s) will be stored as IP netblock(s) in CIDR notation (comma separated)').'<br />'.  
               '<textarea name="ipaccess_range_'.$num.'" rows="3" cols="80">'.  
               $ipranges.'</textarea></fieldset>'.  
               '<fieldset><legend>'.&mt('Functionality Blocked?').'</legend>'.  
               &blocker_checkboxes($num,$blocksref).'</fieldset>'.  
               '<fieldset><legend>'.&mt('Courses/Communities allowed').'</legend>'.  
               '<table>';  
     foreach my $cid (sort(keys(%currcourses))) {  
         my %courseinfo = &Apache::lonnet::coursedescription($cid,{'one_time' => 1});  
         $output .= '<tr><td><span class="LC_nobreak">'.  
                    '<label><input type="checkbox" name="ipaccess_course_delete_'.$num.'" value="'.$cid.'" />'.  
                    &mt('Delete?').'&nbsp;<span class="LC_cusr_emph">'.$courseinfo{'description'}.'</span></label></span>'.  
                    ' <span class="LC_fontsize_medium">('.$cid.')</span></td></tr>';  
     }  
     $output .= '<tr><td><span class="LC_nobreak">'.&mt('Add').':&nbsp;'.  
                '<input type="text" name="ipaccess_cdesc_'.$num.'" value="" onfocus="this.blur();opencrsbrowser('."'display','ipaccess_cnum_$num','ipaccess_cdom_$num','ipaccess_cdesc_$num'".');" />'.  
                 &Apache::loncommon::selectcourse_link('display','ipaccess_cnum_'.$num,'ipaccess_cdom_'.$num,'ipaccess_cdesc_'.$num,$dom,undef,'Course/Community').  
                '<input type="hidden" name="ipaccess_cnum_'.$num.'" value="" />'.  
                '<input type="hidden" name="ipaccess_cdom_'.$num.'" value="" />'.  
                '</span></td></tr></table>'."\n".  
                '</fieldset>';  
     return $output;  
 }  
   
 sub blocker_checkboxes {  
     my ($num,$blocks) = @_;  
     my ($typeorder,$types) = &commblocktype_text();  
     my $numinrow = 6;  
     my $output = '<table>';  
     for (my $i=0; $i<@{$typeorder}; $i++) {  
         my $block = $typeorder->[$i];  
         my $blockstatus;  
         if (ref($blocks) eq 'HASH') {  
             if ($blocks->{$block} eq 'on') {  
                 $blockstatus = 'checked="checked"';  
             }  
         }  
         my $rem = $i%($numinrow);  
         if ($rem == 0) {  
             if ($i > 0) {  
                 $output .= '</tr>';  
             }  
             $output .= '<tr>';  
         }  
         if ($i == scalar(@{$typeorder})-1) {  
             my $colsleft = $numinrow-$rem;  
             if ($colsleft > 1) {  
                 $output .= '<td colspan="'.$colsleft.'">';  
             } else {  
                 $output .= '<td>';  
             }  
         } else {  
             $output .= '<td>';  
         }  
         my $item = 'ipaccess_block_'.$num;  
         if ($blockstatus) {  
             $blockstatus = ' '.$blockstatus;  
         }  
         $output .= '<span class="LC_nobreak"><label>'."\n".  
                    '<input type="checkbox" name="'.$item.'"'.  
                    $blockstatus.' value="'.$block.'"'.' />'.  
                    $types->{$block}.'</label></span>'."\n".  
                    '<br /></td>';  
     }  
     $output .= '</tr></table>';  
     return $output;  
 }  
   
 sub commblocktype_text {  
     my %types = &Apache::lonlocal::texthash(  
         'com' => 'Messaging',  
         'chat' => 'Chat Room',  
         'boards' => 'Discussion',  
         'port' => 'Portfolio',  
         'groups' => 'Groups',  
         'blogs' => 'Blogs',  
         'about' => 'User Information',  
         'printout' => 'Printouts',  
         'passwd' => 'Change Password',  
         'grades' => 'Gradebook',  
         'search' => 'Course search',  
         'wishlist' => 'Stored links',  
         'annotate' => 'Annotations',  
     );  
     my $typeorder = ['com','chat','boards','port','groups','blogs','about','wishlist','printout','grades','search','annotate','passwd'];  
     return ($typeorder,\%types);  
 }  
   
 sub print_rolecolors {  sub print_rolecolors {
     my ($phase,$role,$dom,$confname,$settings,$rowtotal) = @_;      my ($phase,$role,$dom,$confname,$settings,$rowtotal) = @_;
     my %choices = &color_font_choices();      my %choices = &color_font_choices();
Line 1957  sub display_color_options { Line 1414  sub display_color_options {
     my $datatable = '<tr'.$css_class.'>'.      my $datatable = '<tr'.$css_class.'>'.
         '<td>'.$choices->{'font'}.'</td>';          '<td>'.$choices->{'font'}.'</td>';
     if (!$is_custom->{'font'}) {      if (!$is_custom->{'font'}) {
         $datatable .=  '<td>'.&mt('Default in use:').'&nbsp;<span class="css_default_'.$role.'_font" style="color: '.$defaults->{'font'}.';">'.$defaults->{'font'}.'</span></td>';          $datatable .=  '<td>'.&mt('Default in use:').'&nbsp;<span id="css_default_'.$role.'_font" style="color: '.$defaults->{'font'}.';">'.$defaults->{'font'}.'</span></td>';
     } else {      } else {
         $datatable .= '<td>&nbsp;</td>';          $datatable .= '<td>&nbsp;</td>';
     }      }
Line 1966  sub display_color_options { Line 1423  sub display_color_options {
     $datatable .= '<td><span class="LC_nobreak">'.      $datatable .= '<td><span class="LC_nobreak">'.
                   '<input type="text" class="colorchooser" size="10" name="'.$role.'_font"'.                    '<input type="text" class="colorchooser" size="10" name="'.$role.'_font"'.
                   ' value="'.$current_color.'" />&nbsp;'.                    ' value="'.$current_color.'" />&nbsp;'.
                   '&nbsp;</span></td></tr>';                    '&nbsp;</td></tr>';
     unless ($role eq 'login') {       unless ($role eq 'login') { 
         $datatable .= '<tr'.$css_class.'>'.          $datatable .= '<tr'.$css_class.'>'.
                       '<td>'.$choices->{'fontmenu'}.'</td>';                        '<td>'.$choices->{'fontmenu'}.'</td>';
         if (!$is_custom->{'fontmenu'}) {          if (!$is_custom->{'fontmenu'}) {
             $datatable .=  '<td>'.&mt('Default in use:').'&nbsp;<span class="css_default_'.$role.'_font" style="color: '.$defaults->{'fontmenu'}.';">'.$defaults->{'fontmenu'}.'</span></td>';              $datatable .=  '<td>'.&mt('Default in use:').'&nbsp;<span id="css_default_'.$role.'_font" style="color: '.$defaults->{'fontmenu'}.';">'.$defaults->{'fontmenu'}.'</span></td>';
         } else {          } else {
             $datatable .= '<td>&nbsp;</td>';              $datatable .= '<td>&nbsp;</td>';
         }          }
Line 1981  sub display_color_options { Line 1438  sub display_color_options {
                       '<input class="colorchooser" type="text" size="10" name="'                        '<input class="colorchooser" type="text" size="10" name="'
       .$role.'_fontmenu"'.        .$role.'_fontmenu"'.
                       ' value="'.$current_color.'" />&nbsp;'.                        ' value="'.$current_color.'" />&nbsp;'.
                       '&nbsp;</span></td></tr>';                        '&nbsp;</td></tr>';
     }      }
     my $switchserver = &check_switchserver($dom,$confname);      my $switchserver = &check_switchserver($dom,$confname);
     foreach my $img (@{$images}) {      foreach my $img (@{$images}) {
Line 1989  sub display_color_options { Line 1446  sub display_color_options {
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $datatable .= '<tr'.$css_class.'>'.          $datatable .= '<tr'.$css_class.'>'.
                       '<td>'.$choices->{$img};                        '<td>'.$choices->{$img};
         my ($imgfile,$img_import,$login_hdr_pick,$logincolors,$alttext);          my ($imgfile,$img_import,$login_hdr_pick,$logincolors);
         if ($role eq 'login') {          if ($role eq 'login') {
             if ($img eq 'login') {              if ($img eq 'login') {
                 $login_hdr_pick =                  $login_hdr_pick =
Line 1997  sub display_color_options { Line 1454  sub display_color_options {
                 $logincolors =                  $logincolors =
                     &login_text_colors($img,$role,$logintext,$phase,$choices,                      &login_text_colors($img,$role,$logintext,$phase,$choices,
                                        $designs,$defaults);                                         $designs,$defaults);
             } else {              } elsif ($img ne 'domlogo') {
                 if ($img ne 'domlogo') {                  $datatable.= &logo_display_options($img,$defaults,$designs);
                     $datatable.= &logo_display_options($img,$defaults,$designs);  
                 }  
                 if (ref($designs->{'alttext'}) eq 'HASH') {  
                     $alttext = $designs->{'alttext'}{$img};  
                 }  
             }              }
         }          }
         $datatable .= '</td>';          $datatable .= '</td>';
Line 2045  sub display_color_options { Line 1497  sub display_color_options {
                         if ($fullwidth ne '' && $fullheight ne '') {                          if ($fullwidth ne '' && $fullheight ne '') {
                             if ($fullwidth > $width && $fullheight > $height) {                               if ($fullwidth > $width && $fullheight > $height) { 
                                 my $size = $width.'x'.$height;                                  my $size = $width.'x'.$height;
                                 my @args = ('convert','-sample',$size,$input,$output);                                  system("convert -sample $size $input $output");
                                 system({$args[0]} @args);  
                                 $showfile = "/$imgdir/tn-".$filename;                                  $showfile = "/$imgdir/tn-".$filename;
                             }                              }
                         }                          }
Line 2095  sub display_color_options { Line 1546  sub display_color_options {
                 $datatable .='&nbsp;<input type="file" name="'.$role.'_'.$img.'" />';                  $datatable .='&nbsp;<input type="file" name="'.$role.'_'.$img.'" />';
             }              }
         }          }
         if (($role eq 'login') && ($img ne 'login')) {  
             $datatable .= ('&nbsp;' x2).' <span class="LC_nobreak"><label>'.$choices->{'alttext'}.':'.  
                           '<input type="text" name="'.$role.'_alt_'.$img.'" size="10" value="'.$alttext.'" />'.  
                           '</label></span>';  
         }  
         $datatable .= '</td></tr>';          $datatable .= '</td></tr>';
     }      }
     $itemcount ++;      $itemcount ++;
Line 2109  sub display_color_options { Line 1555  sub display_color_options {
     my $bgs_def;      my $bgs_def;
     foreach my $item (@{$bgs}) {      foreach my $item (@{$bgs}) {
         if (!$is_custom->{$item}) {          if (!$is_custom->{$item}) {
             $bgs_def .= '<td><span class="LC_nobreak">'.$choices->{$item}.'</span>&nbsp;<span class="css_default_'.$role.'_'.$item.'" style="background-color: '.$defaults->{'bgs'}{$item}.';">&nbsp;&nbsp;&nbsp;</span><br />'.$defaults->{'bgs'}{$item}.'</td>';              $bgs_def .= '<td><span class="LC_nobreak">'.$choices->{$item}.'</span>&nbsp;<span id="css_default_'.$role.'_'.$item.'" style="background-color: '.$defaults->{'bgs'}{$item}.';">&nbsp;&nbsp;&nbsp;</span><br />'.$defaults->{'bgs'}{$item}.'</td>';
         }          }
     }      }
     if ($bgs_def) {      if ($bgs_def) {
Line 2137  sub display_color_options { Line 1583  sub display_color_options {
     my $links_def;      my $links_def;
     foreach my $item (@{$links}) {      foreach my $item (@{$links}) {
         if (!$is_custom->{$item}) {          if (!$is_custom->{$item}) {
             $links_def .= '<td>'.$choices->{$item}.'<br /><span class="css_default_'.$role.'_'.$item.'" style="color: '.$defaults->{'links'}{$item}.';">'.$defaults->{'links'}{$item}.'</span></td>';              $links_def .= '<td>'.$choices->{$item}.'<br /><span id="css_default_'.$role.'_'.$item.'" style="color: '.$defaults->{'links'}{$item}.';">'.$defaults->{'links'}{$item}.'</span></td>';
         }          }
     }      }
     if ($links_def) {      if ($links_def) {
Line 2223  sub image_changes { Line 1669  sub image_changes {
     my ($is_custom,$alt_text,$img_import,$showfile,$fullsize,$role,$img,$imgfile,$logincolors) = @_;      my ($is_custom,$alt_text,$img_import,$showfile,$fullsize,$role,$img,$imgfile,$logincolors) = @_;
     my $output;      my $output;
     if ($img eq 'login') {      if ($img eq 'login') {
         $output = '</td><td>'.$logincolors; # suppress image for Log-in header              # suppress image for Log-in header
     } elsif (!$is_custom) {      } elsif (!$is_custom) {
         if ($img ne 'domlogo') {          if ($img ne 'domlogo') {
             $output = &mt('Default image:').'<br />';              $output .= &mt('Default image:').'<br />';
         } else {          } else {
             $output = &mt('Default in use:').'<br />';              $output .= &mt('Default in use:').'<br />';
         }          }
     }      }
     if ($img ne 'login') {      if ($img eq 'login') { # suppress image for Log-in header
           $output .= '<td>'.$logincolors;
       } else {
         if ($img_import) {          if ($img_import) {
             $output .= '<input type="hidden" name="'.$role.'_import_'.$img.'" value="'.$imgfile.'" />';              $output .= '<input type="hidden" name="'.$role.'_import_'.$img.'" value="'.$imgfile.'" />';
         }          }
Line 2262  sub print_quotas { Line 1710  sub print_quotas {
     my $typecount = 0;      my $typecount = 0;
     my ($css_class,%titles);      my ($css_class,%titles);
     if ($context eq 'requestcourses') {      if ($context eq 'requestcourses') {
         @usertools = ('official','unofficial','community','textbook','lti');          @usertools = ('official','unofficial','community','textbook');
         @options =('norequest','approval','validate','autolimit');          @options =('norequest','approval','validate','autolimit');
         %validations = &Apache::lonnet::auto_courserequest_checks($dom);          %validations = &Apache::lonnet::auto_courserequest_checks($dom);
         %titles = &courserequest_titles();          %titles = &courserequest_titles();
Line 2271  sub print_quotas { Line 1719  sub print_quotas {
         @options = ('norequest','approval','automatic');          @options = ('norequest','approval','automatic');
         %titles = &authorrequest_titles();          %titles = &authorrequest_titles();
     } else {      } else {
         @usertools = ('aboutme','blog','webdav','portfolio','timezone');          @usertools = ('aboutme','blog','webdav','portfolio');
         %titles = &tool_titles();          %titles = &tool_titles();
     }      }
     if (ref($types) eq 'ARRAY') {      if (ref($types) eq 'ARRAY') {
Line 2375  sub print_quotas { Line 1823  sub print_quotas {
                         }                          }
                     } else {                      } else {
                         my $checked = 'checked="checked" ';                          my $checked = 'checked="checked" ';
                         if ($item eq 'timezone') {  
                             $checked = '';  
                         }  
                         if (ref($settings) eq 'HASH') {                          if (ref($settings) eq 'HASH') {
                             if (ref($settings->{$item}) eq 'HASH') {                              if (ref($settings->{$item}) eq 'HASH') {
                                 if (!$settings->{$item}->{$type}) {                                  if ($settings->{$item}->{$type} == 0) {
                                     $checked = '';                                      $checked = '';
                                 } elsif ($settings->{$item}->{$type} == 1) {                                  } elsif ($settings->{$item}->{$type} == 1) {
                                     $checked =  'checked="checked" ';                                      $checked =  'checked="checked" ';
Line 2678  sub print_quotas { Line 2123  sub print_quotas {
 }  }
   
 sub print_requestmail {  sub print_requestmail {
     my ($dom,$action,$settings,$rowtotal,$customcss,$rowstyle) = @_;      my ($dom,$action,$settings,$rowtotal) = @_;
     my ($now,$datatable,%currapp);      my ($now,$datatable,%currapp);
     $now = time;      $now = time;
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
Line 2690  sub print_requestmail { Line 2135  sub print_requestmail {
     }      }
     my $numinrow = 2;      my $numinrow = 2;
     my $css_class;      my $css_class;
     if ($$rowtotal%2) {      $css_class = ($$rowtotal%2? ' class="LC_odd_row"':'');
         $css_class = 'LC_odd_row';  
     }  
     if ($customcss) {  
         $css_class .= " $customcss";  
     }  
     $css_class =~ s/^\s+//;  
     if ($css_class) {  
         $css_class = ' class="'.$css_class.'"';  
     }  
     if ($rowstyle) {  
         $css_class .= ' style="'.$rowstyle.'"';  
     }  
     my $text;      my $text;
     if ($action eq 'requestcourses') {      if ($action eq 'requestcourses') {
         $text = &mt('Receive notification of course requests requiring approval');          $text = &mt('Receive notification of course requests requiring approval');
Line 2729  sub print_studentcode { Line 2162  sub print_studentcode {
     my ($settings,$rowtotal) = @_;      my ($settings,$rowtotal) = @_;
     my $rownum = 0;       my $rownum = 0; 
     my ($output,%current);      my ($output,%current);
     my @crstypes = ('official','unofficial','community','textbook','lti');      my @crstypes = ('official','unofficial','community','textbook');
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if (ref($settings->{'uniquecode'}) eq 'HASH') {          if (ref($settings->{'uniquecode'}) eq 'HASH') {
             foreach my $type (@crstypes) {              foreach my $type (@crstypes) {
Line 2825  sub print_textbookcourses { Line 2258  sub print_textbookcourses {
                               ('&nbsp;'x2).                                ('&nbsp;'x2).
                               '<span class="LC_nobreak">'.&mt('Thumbnail:');                                '<span class="LC_nobreak">'.&mt('Thumbnail:');
                 if ($image) {                  if ($image) {
                     $datatable .= $imgsrc.                      $datatable .= '<span class="LC_nobreak">'.
                                     $imgsrc.
                                   '<label><input type="checkbox" name="'.$type.'_image_del"'.                                    '<label><input type="checkbox" name="'.$type.'_image_del"'.
                                   ' value="'.$key.'" />'.&mt('Delete?').'</label></span> '.                                    ' value="'.$key.'" />'.&mt('Delete?').'</label></span> '.
                                   '<span class="LC_nobreak">&nbsp;'.&mt('Replace:').'&nbsp;';                                    '<span class="LC_nobreak">&nbsp;'.&mt('Replace:').'&nbsp;';
Line 2856  sub print_textbookcourses { Line 2290  sub print_textbookcourses {
         $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';          $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
     }      }
     $datatable .= '</select>&nbsp;'."\n".      $datatable .= '</select>&nbsp;'."\n".
                   '<input type="checkbox" name="'.$type.'_addbook" value="1" />'.&mt('Add').'</span></td>'."\n".                    '<input type="checkbox" name="'.$type.'_addbook" value="1" />'.&mt('Add').'</td>'."\n".
                   '<td colspan="2">'.                    '<td colspan="2">'.
                   '<span class="LC_nobreak">'.&mt('Subject:').'<input type="text" size="15" name="'.$type.'_addbook_subject" value="" /></span> '."\n".                    '<span class="LC_nobreak">'.&mt('Subject:').'<input type="text" size="15" name="'.$type.'_addbook_subject" value="" /></span> '."\n".
                   ('&nbsp;'x2).                    ('&nbsp;'x2).
Line 2873  sub print_textbookcourses { Line 2307  sub print_textbookcourses {
         } else {          } else {
             $datatable .= '<input type="file" name="'.$type.'_addbook_image" value="" />';              $datatable .= '<input type="file" name="'.$type.'_addbook_image" value="" />';
         }          }
         $datatable .= '</span>'."\n";  
     }      }
     $datatable .= '<span class="LC_nobreak">'.&mt('LON-CAPA course:').'&nbsp;'.      $datatable .= '</span>'."\n".
                     '<span class="LC_nobreak">'.&mt('LON-CAPA course:').'&nbsp;'.
                   &Apache::loncommon::select_dom_form($env{'request.role.domain'},$type.'_addbook_cdom').                    &Apache::loncommon::select_dom_form($env{'request.role.domain'},$type.'_addbook_cdom').
                   '<input type="text" size="25" name="'.$type.'_addbook_cnum" value="" />'.                    '<input type="text" size="25" name="'.$type.'_addbook_cnum" value="" />'.
                   &Apache::loncommon::selectcourse_link                    &Apache::loncommon::selectcourse_link
                       ('display',$type.'_addbook_cnum',$type.'_addbook_cdom',undef,undef,undef,'Course').                        ('display',$type.'_addbook_cnum',$type.'_addbook_cdom',undef,undef,undef,'Course');
                   '</span></td>'."\n".                    '</span></td>'."\n".
                   '</tr>'."\n";                    '</tr>'."\n";
     $itemcount ++;      $itemcount ++;
Line 2979  $jstext{'templates'}; Line 2413  $jstext{'templates'};
 ENDSCRIPT  ENDSCRIPT
 }  }
   
 sub ltitools_javascript {  
     my ($settings) = @_;  
     my $togglejs = &ltitools_toggle_js();  
     unless (ref($settings) eq 'HASH') {  
         return $togglejs;  
     }  
     my (%ordered,$total,%jstext);  
     $total = 0;  
     foreach my $item (keys(%{$settings})) {  
         if (ref($settings->{$item}) eq 'HASH') {  
             my $num = $settings->{$item}{'order'};  
             $ordered{$num} = $item;  
         }  
     }  
     $total = scalar(keys(%{$settings}));  
     my @jsarray = ();  
     foreach my $item (sort {$a <=> $b } (keys(%ordered))) {  
         push(@jsarray,$ordered{$item});  
     }  
     my $jstext = '    var ltitools = Array('."'".join("','",@jsarray)."'".');'."\n";  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
 function reorderLTITools(form,item) {  
     var changedVal;  
 $jstext  
     var newpos = 'ltitools_add_pos';  
     var maxh = 1 + $total;  
     var current = new Array;  
     var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;  
     if (item == newpos) {  
         changedVal = newitemVal;  
     } else {  
         changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;  
         current[newitemVal] = newpos;  
     }  
     for (var i=0; i<ltitools.length; i++) {  
         var elementName = 'ltitools_'+ltitools[i];  
         if (elementName != item) {  
             if (form.elements[elementName]) {  
                 var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;  
                 current[currVal] = elementName;  
             }  
         }  
     }  
     var oldVal;  
     for (var j=0; j<maxh; j++) {  
         if (current[j] == undefined) {  
             oldVal = j;  
         }  
     }  
     if (oldVal < changedVal) {  
         for (var k=oldVal+1; k<=changedVal ; k++) {  
            var elementName = current[k];  
            form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;  
         }  
     } else {  
         for (var k=changedVal; k<oldVal; k++) {  
             var elementName = current[k];  
             form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;  
         }  
     }  
     return;  
 }  
   
 // ]]>  
 </script>  
   
 $togglejs  
   
 ENDSCRIPT  
 }  
   
 sub ltitools_toggle_js {  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
   
 function toggleLTITools(form,setting,item) {  
     var radioname = '';  
     var divid = '';  
     if ((setting == 'passback') || (setting == 'roster')) {  
         radioname = 'ltitools_'+setting+'_'+item;  
         divid = 'ltitools_'+setting+'time_'+item;  
         var num = form.elements[radioname].length;  
         if (num) {  
             var setvis = '';  
             for (var i=0; i<num; i++) {  
                 if (form.elements[radioname][i].checked) {  
                     if (form.elements[radioname][i].value == '1') {  
                         if (document.getElementById(divid)) {  
                             document.getElementById(divid).style.display = 'inline-block';  
                         }  
                         setvis = 1;  
                     }  
                     break;  
                 }  
             }  
         }  
         if (!setvis) {  
             if (document.getElementById(divid)) {  
                 document.getElementById(divid).style.display = 'none';  
             }  
         }  
     }  
     if (setting == 'user') {  
         divid = 'ltitools_'+setting+'_div_'+item;  
         var checkid = 'ltitools_'+setting+'_field_'+item;  
         if (document.getElementById(divid)) {  
             if (document.getElementById(checkid)) {  
                 if (document.getElementById(checkid).checked) {  
                     document.getElementById(divid).style.display = 'inline-block';  
                 } else {  
                     document.getElementById(divid).style.display = 'none';  
                 }  
             }  
         }  
     }  
     return;  
 }  
 // ]]>  
 </script>  
   
 ENDSCRIPT  
 }  
   
 sub wafproxy_javascript {  
     my ($dom) = @_;  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
 function updateWAF() {  
     if (document.getElementById('wafproxy_remoteip')) {  
         var wafremote = 0;  
         if (document.display.wafproxy_remoteip.options[document.display.wafproxy_remoteip.selectedIndex].value == 'h') {  
             wafremote = 1;  
         }  
         var fields = new Array('header','trust');  
         for (var i=0; i<fields.length; i++) {  
             if (document.getElementById('wafproxy_'+fields[i])) {  
                 if (wafremote == 1) {  
                     document.getElementById('wafproxy_'+fields[i]).style.display = 'table-row';  
                 }  
                 else {  
                     document.getElementById('wafproxy_'+fields[i]).style.display = 'none';  
                 }  
             }  
         }  
         if (document.getElementById('wafproxyranges_$dom')) {  
             if (wafremote == 1) {  
                 document.getElementById('wafproxyranges_$dom').style.display = 'inline-block';  
             } else {  
                 for (var i=0; i<document.display.wafproxy_vpnaccess.length; i++) {  
                     if (document.display.wafproxy_vpnaccess[i].checked) {  
                         if (document.display.wafproxy_vpnaccess[i].value == 0) {  
                             document.getElementById('wafproxyranges_$dom').style.display = 'none';  
                         }  
                     }  
                 }  
             }  
         }  
     }  
     return;  
 }  
   
 function checkWAF() {  
     if (document.getElementById('wafproxy_remoteip')) {  
         var wafvpn = 0;  
         for (var i=0; i<document.display.wafproxy_vpnaccess.length; i++) {  
             if (document.display.wafproxy_vpnaccess[i].checked) {  
                 if (document.display.wafproxy_vpnaccess[i].value == 1) {  
                     wafvpn = 1;  
                 }  
                 break;  
             }  
         }  
         var vpn = new Array('vpnint','vpnext');  
         for (var i=0; i<vpn.length; i++) {  
             if (document.getElementById('wafproxy_show_'+vpn[i])) {  
                 if (wafvpn == 1) {  
                     document.getElementById('wafproxy_show_'+vpn[i]).style.display = 'table-row';  
                 }  
                 else {  
                     document.getElementById('wafproxy_show_'+vpn[i]).style.display = 'none';  
                 }  
             }  
         }  
         if (document.getElementById('wafproxyranges_$dom')) {  
             if (wafvpn == 1) {  
                 document.getElementById('wafproxyranges_$dom').style.display = 'inline-block';  
             }  
             else if (document.display.wafproxy_remoteip.options[document.display.wafproxy_remoteip.selectedIndex].value != 'h') {  
                 document.getElementById('wafproxyranges_$dom').style.display = 'none';  
             }  
         }  
     }  
     return;  
 }  
   
 function toggleWAF() {  
     if (document.getElementById('wafproxy_table')) {  
         var wafproxy = 0;  
         for (var i=0; i<document.display.wafproxy_${dom}.length; i++) {  
              if (document.display.wafproxy_${dom}[i].checked) {  
                  if (document.display.wafproxy_${dom}[i].value == 1) {  
                      wafproxy = 1;  
                      break;  
                 }  
             }  
         }  
         if (wafproxy == 1) {  
             document.getElementById('wafproxy_table').style.display='inline';  
         }  
         else {  
            document.getElementById('wafproxy_table').style.display='none';  
         }  
         if (document.getElementById('wafproxyrow_${dom}')) {  
             if (wafproxy == 1) {  
                 document.getElementById('wafproxyrow_${dom}').style.display = 'table-row';  
             }  
             else {  
                 document.getElementById('wafproxyrow_${dom}').style.display = 'none';  
             }  
         }  
         if (document.getElementById('nowafproxyrow_$dom')) {  
             if (wafproxy == 1) {  
                 document.getElementById('nowafproxyrow_${dom}').style.display = 'none';  
             }  
             else {  
                 document.getElementById('nowafproxyrow_${dom}').style.display = 'table-row';  
             }  
         }  
     }  
     return;  
 }  
 // ]]>  
 </script>  
   
 ENDSCRIPT  
 }  
   
 sub lti_javascript {  
     my ($dom,$settings) = @_;  
     my $togglejs = &lti_toggle_js($dom);  
     my $linkprot_js = &Apache::courseprefs::linkprot_javascript();  
     unless (ref($settings) eq 'HASH') {  
         return $togglejs.'  
 <script type="text/javascript">  
 // <![CDATA[  
   
 '.$linkprot_js.'  
   
 // ]]>  
 </script>  
 ';  
     }  
     my (%ordered,$total,%jstext);  
     $total = scalar(keys(%{$settings}));  
     foreach my $item (keys(%{$settings})) {  
         if (ref($settings->{$item}) eq 'HASH') {  
             my $num = $settings->{$item}{'order'};  
             if ($num eq '') {  
                 $num = $total - 1;  
             }  
             $ordered{$num} = $item;  
         }  
     }  
     my @jsarray = ();  
     foreach my $item (sort {$a <=> $b } (keys(%ordered))) {  
         push(@jsarray,$ordered{$item});  
     }  
     my $jstext = '    var lti = Array('."'".join("','",@jsarray)."'".');'."\n";  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
 function reorderLTI(form,item) {  
     var changedVal;  
 $jstext  
     var newpos = 'lti_pos_add';  
     var maxh = 1 + $total;  
     var current = new Array;  
     var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;  
     if (item == newpos) {  
         changedVal = newitemVal;  
     } else {  
         changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;  
         current[newitemVal] = newpos;  
     }  
     for (var i=0; i<lti.length; i++) {  
         var elementName = 'lti_pos_'+lti[i];  
         if (elementName != item) {  
             if (form.elements[elementName]) {  
                 var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;  
                 current[currVal] = elementName;  
             }  
         }  
     }  
     var oldVal;  
     for (var j=0; j<maxh; j++) {  
         if (current[j] == undefined) {  
             oldVal = j;  
         }  
     }  
     if (oldVal < changedVal) {  
         for (var k=oldVal+1; k<=changedVal ; k++) {  
            var elementName = current[k];  
            form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;  
         }  
     } else {  
         for (var k=changedVal; k<oldVal; k++) {  
             var elementName = current[k];  
             form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;  
         }  
     }  
     return;  
 }  
   
 $linkprot_js  
   
 // ]]>  
 </script>  
   
 $togglejs  
   
 ENDSCRIPT  
 }  
   
 sub lti_toggle_js {  
     my ($dom) = @_;  
     my %lcauthparmtext = &Apache::lonlocal::texthash (  
                             localauth => 'Local auth argument',  
                             krb       => 'Kerberos domain',  
                          );  
     my $crsincalert = &mt('"User\'s identity sent" needs to be set to "Yes" first,[_1] before setting "Course\'s identity sent" to "Yes"',"\n");  
     &js_escape(\$crsincalert);  
     my %servers = &Apache::lonnet::get_servers($dom,'library');  
     my $primary = &Apache::lonnet::domain($dom,'primary');  
     my $course_servers = "'".join("','",keys(%servers))."'";  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
   
 function toggleLTI(form,setting,item) {  
     if ((setting == 'requser') || (setting == 'crsinc')) {  
         var usrfieldsets = document.getElementsByClassName('ltioption_usr_'+item);  
         var setvis = '';  
         var radioname = 'lti_requser_'+item;  
         var num = form.elements[radioname].length;  
         if (num) {  
             for (var i=0; i<num; i++) {  
                 if (form.elements[radioname][i].checked) {  
                     if (form.elements[radioname][i].value == '1') {  
                         setvis = 1;  
                         break;  
                     }  
                 }  
             }  
         }  
         if (usrfieldsets.length) {  
             for (var j=0; j<usrfieldsets.length; j++) {  
                 if (setvis) {  
                     usrfieldsets[j].style.display = 'block';  
                 } else {  
                     usrfieldsets[j].style.display = 'none';  
                 }  
             }  
         }  
         var crsfieldsets = document.getElementsByClassName('ltioption_crs_'+item);  
         if (crsfieldsets.length) {  
             radioname = 'lti_crsinc_'+item;  
             var num = form.elements[radioname].length;  
             if (num) {  
                 var crsvis = '';  
                 for (var i=0; i<num; i++) {  
                     if (form.elements[radioname][i].checked) {  
                         if (form.elements[radioname][i].value == '1') {  
                             if (setvis == '') {  
                                 if (setting == 'crsinc'){  
                                     alert("$crsincalert");  
                                     form.elements[radioname][0].checked = true;  
                                 }  
                             } else {  
                                 crsvis = 1;  
                             }  
                             break;  
                         }  
                     }  
                 }  
                 setvis = crsvis;  
             }  
             for (var j=0; j<crsfieldsets.length; j++) {  
                 if (setvis) {  
                     crsfieldsets[j].style.display = 'block';  
                 } else {  
                     crsfieldsets[j].style.display = 'none';  
                 }  
             }  
         }  
     } else if ((setting == 'user') || (setting == 'crs') || (setting == 'passback') || (setting == 'callback')) {  
         var radioname = '';  
         var divid = '';  
         if (setting == 'user') {  
             radioname = 'lti_mapuser_'+item;  
             divid = 'lti_userfield_'+item;  
         } else if (setting == 'crs') {  
             radioname = 'lti_mapcrs_'+item;  
             divid = 'lti_crsfield_'+item;  
         } else if (setting == 'callback') {  
             radioname = 'lti_callback_'+item;  
             divid = 'lti_callbackfield_'+item;  
         } else {  
             radioname = 'lti_passback_'+item;  
             divid =  'lti_passback_'+item;  
         }  
         var num = form.elements[radioname].length;  
         if (num) {  
             var setvis = '';  
             for (var i=0; i<num; i++) {  
                if (form.elements[radioname][i].checked) {  
                    if ((setting == 'passback') || (setting == 'callback')) {  
                        if (form.elements[radioname][i].value == '1') {  
                            if (document.getElementById(divid)) {  
                                document.getElementById(divid).style.display = 'inline-block';  
                            }  
                            setvis = 1;  
                            break;  
                        }  
                    } else {  
                        if (form.elements[radioname][i].value == 'other') {  
                            if (document.getElementById(divid)) {  
                                document.getElementById(divid).style.display = 'inline-block';  
                            }  
                            setvis = 1;  
                            break;  
                        }  
                    }  
                }  
             }  
             if (!setvis) {  
                 if (document.getElementById(divid)) {  
                     document.getElementById(divid).style.display = 'none';  
                 }  
             }  
         }  
     } else if ((setting == 'sec') || (setting == 'secsrc')) {  
         var numsec = form.elements['lti_crssec_'+item].length;  
         if (numsec) {  
             var setvis = '';  
             for (var i=0; i<numsec; i++) {  
                 if (form.elements['lti_crssec_'+item][i].checked) {  
                     if (form.elements['lti_crssec_'+item][i].value == '1') {  
                         if (document.getElementById('lti_crssecfield_'+item)) {  
                             document.getElementById('lti_crssecfield_'+item).style.display = 'inline-block';  
                             setvis = 1;  
                             var numsrcsec = form.elements['lti_crssecsrc_'+item].length;  
                             if (numsrcsec) {  
                                 var setsrcvis = '';  
                                 for (var j=0; j<numsrcsec; j++) {  
                                     if (form.elements['lti_crssecsrc_'+item][j].checked) {  
                                         if (form.elements['lti_crssecsrc_'+item][j].value == 'other') {  
                                             if (document.getElementById('lti_secsrcfield_'+item)) {  
                                                 document.getElementById('lti_secsrcfield_'+item).style.display = 'inline-block';  
                                                 setsrcvis = 1;  
                                             }  
                                         }  
                                     }  
                                 }  
                                 if (!setsrcvis) {  
                                     if (document.getElementById('lti_secsrcfield_'+item)) {  
                                         document.getElementById('lti_secsrcfield_'+item).style.display = 'none';  
                                     }  
                                 }  
                             }  
                         }  
                     }  
                 }  
             }  
             if (!setvis) {  
                 if (document.getElementById('lti_crssecfield_'+item)) {  
                     document.getElementById('lti_crssecfield_'+item).style.display = 'none';  
                 }  
                 if (document.getElementById('lti_secsrcfield_'+item)) {  
                     document.getElementById('lti_secsrcfield_'+item).style.display = 'none';  
                 }  
             }  
         }  
     } else if (setting == 'lcauth') {  
         var numauth = form.elements['lti_lcauth_'+item].length;  
         if (numauth) {  
             for (var i=0; i<numauth; i++) {  
                 if (form.elements['lti_lcauth_'+item][i].checked) {  
                     if (document.getElementById('lti_'+setting+'_parmrow_'+item)) {  
                         if ((form.elements['lti_'+setting+'_'+item][i].value == 'internal') || (form.elements['lti_'+setting+'_'+item][i].value == 'lti')) {  
                             document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'none';  
                         } else {  
                             document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'table-row';  
                             if (document.getElementById('lti_'+setting+'_parmtext_'+item)) {  
                                 if (form.elements['lti_'+setting+'_'+item][i].value == 'localauth') {  
                                     document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'localauth'}";  
                                 } else {  
                                     document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'krb'}";  
                                 }  
                             }  
                         }  
                     }  
                 }  
             }  
         }  
     } else if (setting == 'lcmenu') {  
         var menus = new Array('lti_topmenu_'+item,'lti_inlinemenu_'+item);  
         var divid = 'lti_menufield_'+item;  
         var setvis = '';  
         for (var i=0; i<menus.length; i++) {  
             var radioname = menus[i];  
             var num = form.elements[radioname].length;  
             if (num) {  
                 for (var j=0; j<num; j++) {  
                     if (form.elements[radioname][j].checked) {  
                         if (form.elements[radioname][j].value == '1') {  
                             if (document.getElementById(divid)) {  
                                 document.getElementById(divid).style.display = 'inline-block';  
                             }  
                             setvis = 1;  
                             break;  
                         }  
                     }  
                 }  
             }  
             if (setvis == 1) {  
                 break;  
             }  
         }  
         if (!setvis) {  
             if (document.getElementById(divid)) {  
                 document.getElementById(divid).style.display = 'none';  
             }  
         }  
     }  
     return;  
 }  
   
 // ]]>  
 </script>  
   
 ENDSCRIPT  
 }  
   
 sub autoupdate_javascript {  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
 function toggleLastActiveDays(form) {  
     var radioname = 'lastactive';  
     var divid = 'lastactive_div';  
     var num = form.elements[radioname].length;  
     if (num) {  
         var setvis = '';  
         for (var i=0; i<num; i++) {  
             if (form.elements[radioname][i].checked) {  
                 if (form.elements[radioname][i].value == '1') {  
                     if (document.getElementById(divid)) {  
                         document.getElementById(divid).style.display = 'inline-block';  
                     }  
                     setvis = 1;  
                 }  
                 break;  
             }  
         }  
         if (!setvis) {  
             if (document.getElementById(divid)) {  
                 document.getElementById(divid).style.display = 'none';  
             }  
         }  
     }  
     return;  
 }  
 // ]]>  
 </script>  
   
 ENDSCRIPT  
 }  
   
 sub autoenroll_javascript {  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
 function toggleFailsafe(form) {  
     var radioname = 'autoenroll_failsafe';  
     var divid = 'autoenroll_failsafe_div';  
     var num = form.elements[radioname].length;  
     if (num) {  
         var setvis = '';  
         for (var i=0; i<num; i++) {  
             if (form.elements[radioname][i].checked) {  
                 if ((form.elements[radioname][i].value == 'zero') || (form.elements[radioname][i].value == 'any')) {  
                     if (document.getElementById(divid)) {  
                         document.getElementById(divid).style.display = 'inline-block';  
                     }  
                     setvis = 1;  
                 }  
                 break;  
             }  
         }  
         if (!setvis) {  
             if (document.getElementById(divid)) {  
                 document.getElementById(divid).style.display = 'none';  
             }  
         }  
     }  
     return;  
 }  
 // ]]>  
 </script>  
   
 ENDSCRIPT  
 }  
   
 sub saml_javascript {  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
 function toggleSamlOptions(form,hostid) {  
     var radioname = 'saml_'+hostid;  
     var tablecellon = 'samloptionson_'+hostid;  
     var tablecelloff = 'samloptionsoff_'+hostid;  
     var num = form.elements[radioname].length;  
     if (num) {  
         var setvis = '';  
         for (var i=0; i<num; i++) {  
             if (form.elements[radioname][i].checked) {  
                 if (form.elements[radioname][i].value == '1') {  
                     if (document.getElementById(tablecellon)) {  
                         document.getElementById(tablecellon).style.display='';  
                     }  
                     if (document.getElementById(tablecelloff)) {  
                         document.getElementById(tablecelloff).style.display='none';  
                     }  
                     setvis = 1;  
                 }  
                 break;  
             }  
         }  
         if (!setvis) {  
             if (document.getElementById(tablecellon)) {  
                 document.getElementById(tablecellon).style.display='none';  
             }  
             if (document.getElementById(tablecelloff)) {  
                 document.getElementById(tablecelloff).style.display='';  
             }  
         }  
     }  
     return;  
 }  
 // ]]>  
 </script>  
   
 ENDSCRIPT  
 }  
   
 sub ipaccess_javascript {  
     my ($settings) = @_;  
     my (%ordered,$total,%jstext);  
     $total = 0;  
     if (ref($settings) eq 'HASH') {  
         foreach my $item (keys(%{$settings})) {  
             if (ref($settings->{$item}) eq 'HASH') {  
                 my $num = $settings->{$item}{'order'};  
                 $ordered{$num} = $item;  
             }  
         }  
         $total = scalar(keys(%{$settings}));  
     }  
     my @jsarray = ();  
     foreach my $item (sort {$a <=> $b } (keys(%ordered))) {  
         push(@jsarray,$ordered{$item});  
     }  
     my $jstext = '    var ipaccess = Array('."'".join("','",@jsarray)."'".');'."\n";  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
 function reorderIPaccess(form,item) {  
     var changedVal;  
 $jstext  
     var newpos = 'ipaccess_pos_add';  
     var maxh = 1 + $total;  
     var current = new Array;  
     var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;  
     if (item == newpos) {  
         changedVal = newitemVal;  
     } else {  
         changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;  
         current[newitemVal] = newpos;  
     }  
     for (var i=0; i<ipaccess.length; i++) {  
         var elementName = 'ipaccess_pos_'+ipaccess[i];  
         if (elementName != item) {  
             if (form.elements[elementName]) {  
                 var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;  
                 current[currVal] = elementName;  
             }  
         }  
     }  
     var oldVal;  
     for (var j=0; j<maxh; j++) {  
         if (current[j] == undefined) {  
             oldVal = j;  
         }  
     }  
     if (oldVal < changedVal) {  
         for (var k=oldVal+1; k<=changedVal ; k++) {  
            var elementName = current[k];  
            form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;  
         }  
     } else {  
         for (var k=changedVal; k<oldVal; k++) {  
             var elementName = current[k];  
             form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;  
         }  
     }  
     return;  
 }  
 // ]]>  
 </script>  
   
 ENDSCRIPT  
 }  
   
 sub print_autoenroll {  sub print_autoenroll {
     my ($dom,$settings,$rowtotal) = @_;      my ($dom,$settings,$rowtotal) = @_;
     my $autorun = &Apache::lonnet::auto_run(undef,$dom),      my $autorun = &Apache::lonnet::auto_run(undef,$dom),
     my ($defdom,$runon,$runoff,$coownerson,$coownersoff,      my ($defdom,$runon,$runoff,$coownerson,$coownersoff);
         $failsafe,$autofailsafe,$failsafesty,%failsafechecked);  
     $failsafesty = 'none';  
     %failsafechecked = (  
         off => ' checked="checked"',  
     );  
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if (exists($settings->{'run'})) {          if (exists($settings->{'run'})) {
             if ($settings->{'run'} eq '0') {              if ($settings->{'run'} eq '0') {
Line 3748  sub print_autoenroll { Line 2450  sub print_autoenroll {
         if (exists($settings->{'sender_domain'})) {          if (exists($settings->{'sender_domain'})) {
             $defdom = $settings->{'sender_domain'};              $defdom = $settings->{'sender_domain'};
         }          }
         if (exists($settings->{'failsafe'})) {  
             $failsafe = $settings->{'failsafe'};  
             if ($failsafe eq 'zero') {  
                 $failsafechecked{'zero'} = ' checked="checked"';  
                 $failsafechecked{'off'} = '';  
                 $failsafesty = 'inline-block';  
             } elsif ($failsafe eq 'any') {  
                 $failsafechecked{'any'} = ' checked="checked"';  
                 $failsafechecked{'off'} = '';  
             }  
             $autofailsafe = $settings->{'autofailsafe'};  
         } elsif (exists($settings->{'autofailsafe'})) {  
             $autofailsafe = $settings->{'autofailsafe'};  
             if ($autofailsafe ne '') {  
                 $failsafechecked{'zero'} = ' checked="checked"';  
                 $failsafe = 'zero';  
                 $failsafechecked{'off'} = '';  
             }  
         }  
     } else {      } else {
         if ($autorun) {          if ($autorun) {
             $runon = ' checked="checked" ';              $runon = ' checked="checked" ';
Line 3802  sub print_autoenroll { Line 2485  sub print_autoenroll {
                   $coownerson.' value="1" />'.&mt('Yes').'</label>&nbsp;'.                    $coownerson.' value="1" />'.&mt('Yes').'</label>&nbsp;'.
                   '<label><input type="radio" name="autoassign_coowners"'.                    '<label><input type="radio" name="autoassign_coowners"'.
                   $coownersoff.' value="0" />'.&mt('No').'</label></span></td>'.                    $coownersoff.' value="0" />'.&mt('No').'</label></span></td>'.
                   '</tr><tr>'.                    '</tr>';
                   '<td>'.&mt('Failsafe for no drops when institutional data missing').'</td>'.      $$rowtotal += 3;
                   '<td class="LC_left_item"><span class="LC_nobreak">'.  
                   '<span class="LC_nobreak"><label><input type="radio" name="autoenroll_failsafe" value="off" onclick="toggleFailsafe(this.form)"'.$failsafechecked{'off'}.' />'.&mt('Not in use').'</label></span>&nbsp;&nbsp;&nbsp; '.  
                   '<span class="LC_nobreak"><label><input type="radio" name="autoenroll_failsafe" value="zero" onclick="toggleFailsafe(this.form)"'.$failsafechecked{'zero'}.' />'.&mt('Retrieved section enrollment is zero').'</label></span><br />'.  
                   '<span class="LC_nobreak"><label><input type="radio" name="autoenroll_failsafe" value="any" onclick="toggleFailsafe(this.form)"'.$failsafechecked{'any'}.' />'.&mt('Retrieved section enrollment is zero or greater').'</label></span>'.  
                   '<div class="LC_floatleft" style="display:'.$failsafesty.';" id="autoenroll_failsafe_div">'.  
                   '<span class="LC_nobreak">'.  
                   &mt('Threshold for number of students in section to drop: [_1]',  
                       '<input type="text" name="autoenroll_autofailsafe" value="'.$autofailsafe.'" size="4" />').  
                   '</span></div></td></tr>';  
     $$rowtotal += 4;  
     return $datatable;      return $datatable;
 }  }
   
 sub print_autoupdate {  sub print_autoupdate {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($enable,$datatable);      my $datatable;
     if ($position eq 'top') {      if ($position eq 'top') {
         my %choices = &Apache::lonlocal::texthash (  
                           run        => 'Auto-update active?',  
                           classlists => 'Update information in classlists?',  
                           unexpired  => 'Skip updates for users without active or future roles?',  
                           lastactive => 'Skip updates for inactive users?',  
         );  
         my $itemcount = 0;  
         my $updateon = ' ';          my $updateon = ' ';
         my $updateoff = ' checked="checked" ';          my $updateoff = ' checked="checked" ';
           my $classlistson = ' ';
           my $classlistsoff = ' checked="checked" ';
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ($settings->{'run'} eq '1') {              if ($settings->{'run'} eq '1') {
                 $updateon = $updateoff;                  $updateon = $updateoff;
                 $updateoff = ' ';                  $updateoff = ' ';
             }              }
               if ($settings->{'classlists'} eq '1') {
                   $classlistson = $classlistsoff;
                   $classlistsoff = ' ';
               }
         }          }
         $enable = '<tr class="LC_odd_row">'.          my %title = (
                   '<td>'.$choices{'run'}.'</td>'.                     run => 'Auto-update active?',
                   '<td class="LC_left_item"><span class="LC_nobreak"><label>'.                     classlists => 'Update information in classlists?',
                       );
           $datatable = '<tr class="LC_odd_row">'. 
                     '<td>'.&mt($title{'run'}).'</td>'.
                     '<td class="LC_right_item"><span class="LC_nobreak"><label>'.
                   '<input type="radio" name="autoupdate_run"'.                    '<input type="radio" name="autoupdate_run"'.
                   $updateoff.'value="0" />'.&mt('No').'</label>&nbsp;'.                    $updateon.' value="1" />'.&mt('Yes').'</label>&nbsp;'.
                   '<label><input type="radio" name="autoupdate_run"'.                    '<label><input type="radio" name="autoupdate_run"'.
                   $updateon.'value="1" />'.&mt('Yes').'</label></span></td>'.                    $updateoff.'value="0" />'.&mt('No').'</label></span></td>'.
                     '</tr><tr>'.
                     '<td>'.&mt($title{'classlists'}).'</td>'.
                     '<td class="LC_right_item"><span class="LC_nobreak">'.
                     '<label><input type="radio" name="classlists"'.
                     $classlistson.' value="1" />'.&mt('Yes').'</label>&nbsp;'.
                     '<label><input type="radio" name="classlists"'.
                     $classlistsoff.'value="0" />'.&mt('No').'</label></span></td>'.
                   '</tr>';                    '</tr>';
         my @toggles = ('classlists','unexpired');          $$rowtotal += 2;
         my %defaultchecked = ('classlists' => 'off',  
                               'unexpired'  => 'off'  
                               );  
         $$rowtotal ++;  
         ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,  
                                                      \%choices,$itemcount,'','','left','no');  
         $datatable = $enable.$datatable;  
         $$rowtotal += $itemcount;  
         my $lastactiveon = ' ';  
         my $lastactiveoff = ' checked="checked" ';  
         my $lastactivestyle = 'none';  
         my $lastactivedays;  
         my $onclick = ' onclick="javascript:toggleLastActiveDays(this.form);"';  
         if (ref($settings) eq 'HASH') {  
             if ($settings->{'lastactive'} =~ /^\d+$/) {  
                 $lastactiveon = $lastactiveoff;  
                 $lastactiveoff = ' ';  
                 $lastactivestyle = 'inline-block';  
                 $lastactivedays = $settings->{'lastactive'};  
             }  
         }  
         my $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'>'.  
                       '<td>'.$choices{'lastactive'}.'</td>'.  
                       '<td class="LC_left_item"><span class="LC_nobreak"><label>'.  
                       '<input type="radio" name="lastactive"'.  
                       $lastactiveoff.'value="0"'.$onclick.' />'.&mt('No').'</label>'.  
                       '&nbsp;<label>'.  
                       '<input type="radio" name="lastactive"'.  
                       $lastactiveon.' value="1"'.$onclick.' />'.&mt('Yes').'</label>'.  
                       '<div id="lastactive_div" style="display:'.$lastactivestyle.';">'.  
                       ':&nbsp;'.&mt('inactive = no activity in last [_1] days',  
                           '<input type="text" size="5" name="lastactivedays" value="'.  
                           $lastactivedays.'" />').  
                       '</span></td>'.  
                       '</tr>';  
         $$rowtotal ++;  
     } elsif ($position eq 'middle') {      } elsif ($position eq 'middle') {
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);          my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
         my $numinrow = 3;          my $numinrow = 3;
         my $locknamesettings;          my $locknamesettings;
         $datatable .= &insttypes_row($settings,$types,$usertypes,          $datatable .= &insttypes_row($settings,$types,$usertypes,
                                      $dom,$numinrow,$othertitle,                                       $dom,$numinrow,$othertitle,
                                     'lockablenames',$rowtotal);                                      'lockablenames');
         $$rowtotal ++;          $$rowtotal ++;
     } else {      } else {
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);          my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
Line 3969  sub print_autocreate { Line 2615  sub print_autocreate {
 }  }
   
 sub print_directorysrch {  sub print_directorysrch {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($dom,$settings,$rowtotal) = @_;
     my $datatable;      my $srchon = ' ';
     if ($position eq 'top') {      my $srchoff = ' checked="checked" ';
         my $instsrchon = ' ';      my ($exacton,$containson,$beginson);
         my $instsrchoff = ' checked="checked" ';      my $localon = ' ';
         my ($exacton,$containson,$beginson);      my $localoff = ' checked="checked" ';
         my $instlocalon = ' ';      if (ref($settings) eq 'HASH') {
         my $instlocaloff = ' checked="checked" ';          if ($settings->{'available'} eq '1') {
         if (ref($settings) eq 'HASH') {              $srchon = $srchoff;
             if ($settings->{'available'} eq '1') {              $srchoff = ' ';
                 $instsrchon = $instsrchoff;          }
                 $instsrchoff = ' ';          if ($settings->{'localonly'} eq '1') {
             }              $localon = $localoff;
             if ($settings->{'localonly'} eq '1') {              $localoff = ' ';
                 $instlocalon = $instlocaloff;          }
                 $instlocaloff = ' ';          if (ref($settings->{'searchtypes'}) eq 'ARRAY') {
             }              foreach my $type (@{$settings->{'searchtypes'}}) {
             if (ref($settings->{'searchtypes'}) eq 'ARRAY') {                  if ($type eq 'exact') {
                 foreach my $type (@{$settings->{'searchtypes'}}) {  
                     if ($type eq 'exact') {  
                         $exacton = ' checked="checked" ';  
                     } elsif ($type eq 'contains') {  
                         $containson = ' checked="checked" ';  
                     } elsif ($type eq 'begins') {  
                         $beginson = ' checked="checked" ';  
                     }  
                 }  
             } else {  
                 if ($settings->{'searchtypes'} eq 'exact') {  
                     $exacton = ' checked="checked" ';  
                 } elsif ($settings->{'searchtypes'} eq 'contains') {  
                     $containson = ' checked="checked" ';  
                 } elsif ($settings->{'searchtypes'} eq 'specify') {  
                     $exacton = ' checked="checked" ';                      $exacton = ' checked="checked" ';
                   } elsif ($type eq 'contains') {
                     $containson = ' checked="checked" ';                      $containson = ' checked="checked" ';
                   } elsif ($type eq 'begins') {
                       $beginson = ' checked="checked" ';
                 }                  }
             }              }
         }          } else {
         my ($searchtitles,$titleorder) = &sorted_searchtitles();              if ($settings->{'searchtypes'} eq 'exact') {
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);                  $exacton = ' checked="checked" ';
               } elsif ($settings->{'searchtypes'} eq 'contains') {
         my $numinrow = 4;                  $containson = ' checked="checked" ';
         my $cansrchrow = 0;              } elsif ($settings->{'searchtypes'} eq 'specify') {
         $datatable='<tr class="LC_odd_row">'.                  $exacton = ' checked="checked" ';
                    '<td colspan="2"><span class ="LC_nobreak">'.&mt('Institutional directory search available?').'</span></td>'.                  $containson = ' checked="checked" ';
                    '<td class="LC_right_item"><span class="LC_nobreak"><label>'.  
                    '<input type="radio" name="dirsrch_available"'.  
                    $instsrchon.' value="1" />'.&mt('Yes').'</label>&nbsp;'.  
                    '<label><input type="radio" name="dirsrch_available"'.  
                    $instsrchoff.' value="0" />'.&mt('No').'</label></span></td>'.  
                    '</tr><tr>'.  
                    '<td colspan="2"><span class ="LC_nobreak">'.&mt('Other domains can search institution?').'</span></td>'.  
                    '<td class="LC_right_item"><span class="LC_nobreak"><label>'.  
                    '<input type="radio" name="dirsrch_instlocalonly"'.  
                    $instlocaloff.' value="0" />'.&mt('Yes').'</label>&nbsp;'.  
                    '<label><input type="radio" name="dirsrch_instlocalonly"'.  
                    $instlocalon.' value="1" />'.&mt('No').'</label></span></td>'.  
                    '</tr>';  
         $$rowtotal += 2;  
         if (ref($usertypes) eq 'HASH') {  
             if (keys(%{$usertypes}) > 0) {  
                 $datatable .= &insttypes_row($settings,$types,$usertypes,$dom,  
                                              $numinrow,$othertitle,'cansearch',  
                                              $rowtotal);  
                 $cansrchrow = 1;  
             }              }
         }          }
         if ($cansrchrow) {      }
             $$rowtotal ++;      my ($searchtitles,$titleorder) = &sorted_searchtitles();
             $datatable .= '<tr>';      my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
         } else {  
             $datatable .= '<tr class="LC_odd_row">';      my $numinrow = 4;
       my $cansrchrow = 0;
       my $datatable='<tr class="LC_odd_row">'.
                     '<td colspan="2"><span class ="LC_nobreak">'.&mt('Directory search available?').'</span></td>'.
                     '<td class="LC_right_item"><span class="LC_nobreak"><label>'.
                     '<input type="radio" name="dirsrch_available"'.
                     $srchon.' value="1" />'.&mt('Yes').'</label>&nbsp;'.
                     '<label><input type="radio" name="dirsrch_available"'.
                     $srchoff.' value="0" />'.&mt('No').'</label></span></td>'.
                     '</tr><tr>'.
                     '<td colspan="2"><span class ="LC_nobreak">'.&mt('Other domains can search?').'</span></td>'.
                     '<td class="LC_right_item"><span class="LC_nobreak"><label>'.
                     '<input type="radio" name="dirsrch_localonly"'.
                     $localoff.' value="0" />'.&mt('Yes').'</label>&nbsp;'.
                     '<label><input type="radio" name="dirsrch_localonly"'.
                     $localon.' value="1" />'.&mt('No').'</label></span></td>'.
                     '</tr>';
       $$rowtotal += 2;
       if (ref($usertypes) eq 'HASH') {
           if (keys(%{$usertypes}) > 0) {
               $datatable .= &insttypes_row($settings,$types,$usertypes,$dom,
                                            $numinrow,$othertitle,'cansearch');
               $cansrchrow = 1;
         }          }
         $datatable .= '<td><span class ="LC_nobreak">'.&mt('Supported search methods').      }
                       '</span></td><td class="LC_left_item" colspan="2"><table><tr>';      if ($cansrchrow) {
         foreach my $title (@{$titleorder}) {          $$rowtotal ++;
             if (defined($searchtitles->{$title})) {          $datatable .= '<tr>';
                 my $check = ' ';      } else {
                 if (ref($settings) eq 'HASH') {          $datatable .= '<tr class="LC_odd_row">';
                     if (ref($settings->{'searchby'}) eq 'ARRAY') {      }
                         if (grep(/^\Q$title\E$/,@{$settings->{'searchby'}})) {      $datatable .= '<td><span class ="LC_nobreak">'.&mt('Supported search methods').
                             $check = ' checked="checked" ';                    '</span></td><td class="LC_left_item" colspan="2"><table><tr>';
                         }      foreach my $title (@{$titleorder}) {
           if (defined($searchtitles->{$title})) {
               my $check = ' ';
               if (ref($settings) eq 'HASH') {
                   if (ref($settings->{'searchby'}) eq 'ARRAY') {
                       if (grep(/^\Q$title\E$/,@{$settings->{'searchby'}})) {
                           $check = ' checked="checked" ';
                     }                      }
                 }                  }
                 $datatable .= '<td class="LC_left_item">'.  
                               '<span class="LC_nobreak"><label>'.  
                               '<input type="checkbox" name="searchby" '.  
                               'value="'.$title.'"'.$check.'/>'.  
                               $searchtitles->{$title}.'</label></span></td>';  
             }              }
               $datatable .= '<td class="LC_left_item">'.
                             '<span class="LC_nobreak"><label>'.
                             '<input type="checkbox" name="searchby" '.
                             'value="'.$title.'"'.$check.'/>'.
                             $searchtitles->{$title}.'</label></span></td>';
         }          }
         $datatable .= '</tr></table></td></tr>';      }
         $$rowtotal ++;      $datatable .= '</tr></table></td></tr>';
         if ($cansrchrow) {      $$rowtotal ++;
             $datatable .= '<tr class="LC_odd_row">';      if ($cansrchrow) {
         } else {          $datatable .= '<tr class="LC_odd_row">';
             $datatable .= '<tr>';  
         }  
         $datatable .= '<td><span class ="LC_nobreak">'.&mt('Search latitude').'</span></td>'.     
                       '<td class="LC_left_item" colspan="2">'.  
                       '<span class="LC_nobreak"><label>'.  
                       '<input type="checkbox" name="searchtypes" '.  
                       $exacton.' value="exact" />'.&mt('Exact match').  
                       '</label>&nbsp;'.  
                       '<label><input type="checkbox" name="searchtypes" '.  
                       $beginson.' value="begins" />'.&mt('Begins with').  
                       '</label>&nbsp;'.  
                       '<label><input type="checkbox" name="searchtypes" '.  
                       $containson.' value="contains" />'.&mt('Contains').  
                       '</label></span></td></tr>';  
         $$rowtotal ++;  
     } else {      } else {
         my $domsrchon = ' checked="checked" ';          $datatable .= '<tr>';
         my $domsrchoff = ' ';  
         my $domlocalon = ' ';  
         my $domlocaloff = ' checked="checked" ';  
         if (ref($settings) eq 'HASH') {  
             if ($settings->{'lclocalonly'} eq '1') {  
                 $domlocalon = $domlocaloff;  
                 $domlocaloff = ' ';  
             }  
             if ($settings->{'lcavailable'} eq '0') {  
                 $domsrchoff = $domsrchon;  
                 $domsrchon = ' ';  
             }  
         }  
         $datatable='<tr class="LC_odd_row">'.  
                       '<td colspan="2"><span class ="LC_nobreak">'.&mt('LON-CAPA directory search available?').'</span></td>'.  
                       '<td class="LC_right_item"><span class="LC_nobreak"><label>'.  
                       '<input type="radio" name="dirsrch_domavailable"'.  
                       $domsrchon.' value="1" />'.&mt('Yes').'</label>&nbsp;'.  
                       '<label><input type="radio" name="dirsrch_domavailable"'.  
                       $domsrchoff.' value="0" />'.&mt('No').'</label></span></td>'.  
                       '</tr><tr>'.  
                       '<td colspan="2"><span class ="LC_nobreak">'.&mt('Other domains can search LON-CAPA domain?').'</span></td>'.  
                       '<td class="LC_right_item"><span class="LC_nobreak"><label>'.  
                       '<input type="radio" name="dirsrch_domlocalonly"'.  
                       $domlocaloff.' value="0" />'.&mt('Yes').'</label>&nbsp;'.  
                       '<label><input type="radio" name="dirsrch_domlocalonly"'.  
                       $domlocalon.' value="1" />'.&mt('No').'</label></span></td>'.  
                       '</tr>';  
         $$rowtotal += 2;  
     }      }
       $datatable .= '<td><span class ="LC_nobreak">'.&mt('Search latitude').'</span></td>'.   
                     '<td class="LC_left_item" colspan="2">'.
                     '<span class="LC_nobreak"><label>'.
                     '<input type="checkbox" name="searchtypes" '.
                     $exacton.' value="exact" />'.&mt('Exact match').
                     '</label>&nbsp;'.
                     '<label><input type="checkbox" name="searchtypes" '.
                     $beginson.' value="begins" />'.&mt('Begins with').
                     '</label>&nbsp;'.
                     '<label><input type="checkbox" name="searchtypes" '.
                     $containson.' value="contains" />'.&mt('Contains').
                     '</label></span></td></tr>';
       $$rowtotal ++;
     return $datatable;      return $datatable;
 }  }
   
 sub print_contacts {  sub print_contacts {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($dom,$settings,$rowtotal) = @_;
     my $datatable;      my $datatable;
     my @contacts = ('adminemail','supportemail');      my @contacts = ('adminemail','supportemail');
     my (%checked,%to,%otheremails,%bccemails,%includestr,%includeloc,%currfield,      my (%checked,%to,%otheremails,%bccemails);
         $maxsize,$fields,$fieldtitles,$fieldoptions,$possoptions,@mailings,%lonstatus);      my @mailings = ('errormail','packagesmail','lonstatusmail','helpdeskmail',
     if ($position eq 'top') {                      'requestsmail','updatesmail','idconflictsmail');
         if (ref($settings) eq 'HASH') {      foreach my $type (@mailings) {
             foreach my $item (@contacts) {          $otheremails{$type} = '';
                 if (exists($settings->{$item})) {  
                     $to{$item} = $settings->{$item};  
                 }  
             }  
         }  
     } elsif ($position eq 'middle') {  
         @mailings = ('errormail','packagesmail','lonstatusmail','requestsmail',  
                      'updatesmail','idconflictsmail','hostipmail');  
         foreach my $type (@mailings) {  
             $otheremails{$type} = '';  
         }  
     } elsif ($position eq 'lower') {  
         if (ref($settings) eq 'HASH') {  
             if (ref($settings->{'lonstatus'}) eq 'HASH') {  
                 %lonstatus = %{$settings->{'lonstatus'}};  
             }  
         }  
     } else {  
         @mailings = ('helpdeskmail','otherdomsmail');  
         foreach my $type (@mailings) {  
             $otheremails{$type} = '';  
         }  
         $bccemails{'helpdeskmail'} = '';  
         $bccemails{'otherdomsmail'} = '';  
         $includestr{'helpdeskmail'} = '';  
         $includestr{'otherdomsmail'} = '';  
         ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields();  
     }      }
       $bccemails{'helpdeskmail'} = '';
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         unless (($position eq 'top') || ($position eq 'lower')) {          foreach my $item (@contacts) {
             foreach my $type (@mailings) {              if (exists($settings->{$item})) {
                 if (exists($settings->{$type})) {                  $to{$item} = $settings->{$item};
                     if (ref($settings->{$type}) eq 'HASH') {  
                         foreach my $item (@contacts) {  
                             if ($settings->{$type}{$item}) {  
                                 $checked{$type}{$item} = ' checked="checked" ';  
                             }  
                         }  
                         $otheremails{$type} = $settings->{$type}{'others'};  
                         if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {  
                             $bccemails{$type} = $settings->{$type}{'bcc'};  
                             if ($settings->{$type}{'include'} ne '') {  
                                 ($includeloc{$type},$includestr{$type}) = split(/:/,$settings->{$type}{'include'},2);  
                                 $includestr{$type} = &unescape($includestr{$type});  
                             }  
                         }  
                     }  
                 } elsif ($type eq 'lonstatusmail') {  
                     $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" ';  
                 }  
             }              }
         }          }
         if ($position eq 'bottom') {          foreach my $type (@mailings) {
             foreach my $type (@mailings) {              if (exists($settings->{$type})) {
                 $bccemails{$type} = $settings->{$type}{'bcc'};                  if (ref($settings->{$type}) eq 'HASH') {
                 if ($settings->{$type}{'include'} ne '') {                      foreach my $item (@contacts) {
                     ($includeloc{$type},$includestr{$type}) = split(/:/,$settings->{$type}{'include'},2);                          if ($settings->{$type}{$item}) {
                     $includestr{$type} = &unescape($includestr{$type});                              $checked{$type}{$item} = ' checked="checked" ';
                 }                          }
             }  
             if (ref($settings->{'helpform'}) eq 'HASH') {  
                 if (ref($fields) eq 'ARRAY') {  
                     foreach my $field (@{$fields}) {  
                         $currfield{$field} = $settings->{'helpform'}{$field};  
                     }                      }
                 }                      $otheremails{$type} = $settings->{$type}{'others'};
                 if (exists($settings->{'helpform'}{'maxsize'})) {                      if ($type eq 'helpdeskmail') {
                     $maxsize = $settings->{'helpform'}{'maxsize'};                          $bccemails{$type} = $settings->{$type}{'bcc'};
                 } else {  
                     $maxsize = '1.0';  
                 }  
             } else {  
                 if (ref($fields) eq 'ARRAY') {  
                     foreach my $field (@{$fields}) {  
                         $currfield{$field} = 'yes';  
                     }                      }
                 }                  }
                 $maxsize = '1.0';              } elsif ($type eq 'lonstatusmail') {
                   $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" ';
             }              }
         }          }
     } else {      } else {
         if ($position eq 'top') {          $to{'supportemail'} = $Apache::lonnet::perlvar{'lonSupportEMail'};
             $to{'supportemail'} = $Apache::lonnet::perlvar{'lonSupportEMail'};          $to{'adminemail'} = $Apache::lonnet::perlvar{'lonAdmEMail'};
             $to{'adminemail'} = $Apache::lonnet::perlvar{'lonAdmEMail'};          $checked{'errormail'}{'adminemail'} = ' checked="checked" ';
             $checked{'errormail'}{'adminemail'} = ' checked="checked" ';          $checked{'packagesmail'}{'adminemail'} = ' checked="checked" ';
             $checked{'packagesmail'}{'adminemail'} = ' checked="checked" ';          $checked{'helpdeskmail'}{'supportemail'} = ' checked="checked" ';
             $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" ';          $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" '; 
             $checked{'requestsmail'}{'adminemail'} = ' checked="checked" ';          $checked{'requestsmail'}{'adminemail'} = ' checked="checked" ';
             $checked{'updatesmail'}{'adminemail'} = ' checked="checked" ';          $checked{'updatesmail'}{'adminemail'} = ' checked="checked" ';
             $checked{'idconflictsmail'}{'adminemail'} = ' checked="checked" ';          $checked{'idconflictsmail'}{'adminemail'} = ' checked="checked" ';
             $checked{'hostipmail'}{'adminemail'} = ' checked="checked" ';  
         } elsif ($position eq 'bottom') {  
             $checked{'helpdeskmail'}{'supportemail'} = ' checked="checked" ';  
             $checked{'otherdomsmail'}{'supportemail'} = ' checked="checked" ';  
             if (ref($fields) eq 'ARRAY') {  
                 foreach my $field (@{$fields}) {  
                     $currfield{$field} = 'yes';  
                 }  
             }  
             $maxsize = '1.0';  
         }  
     }      }
     my ($titles,$short_titles) = &contact_titles();      my ($titles,$short_titles) = &contact_titles();
     my $rownum = 0;      my $rownum = 0;
     my $css_class;      my $css_class;
     if ($position eq 'top') {      foreach my $item (@contacts) {
         foreach my $item (@contacts) {  
             $css_class = $rownum%2?' class="LC_odd_row"':'';  
             $datatable .= '<tr'.$css_class.'>'.   
                           '<td><span class="LC_nobreak">'.$titles->{$item}.  
                           '</span></td><td class="LC_right_item">'.  
                           '<input type="text" name="'.$item.'" value="'.  
                           $to{$item}.'" /></td></tr>';  
             $rownum ++;  
         }  
     } elsif ($position eq 'bottom') {  
         $css_class = $rownum%2?' class="LC_odd_row"':'';          $css_class = $rownum%2?' class="LC_odd_row"':'';
         $datatable .= '<tr'.$css_class.'>'.          $datatable .= '<tr'.$css_class.'>'. 
                       '<td>'.&mt('Extra helpdesk form fields:').'<br />'.                    '<td><span class="LC_nobreak">'.$titles->{$item}.
                       &mt('(e-mail, subject, and description always shown)').                    '</span></td><td class="LC_right_item">'.
                       '</td><td class="LC_left_item">';                    '<input type="text" name="'.$item.'" value="'.
         if ((ref($fields) eq 'ARRAY') && (ref($fieldtitles) eq 'HASH') &&                    $to{$item}.'" /></td></tr>';
             (ref($fieldoptions) eq 'HASH') && (ref($possoptions) eq 'HASH')) {  
             $datatable .= '<table><tr><th>'.&mt('Field').'</th><th>'.&mt('Status').'</th></tr>';  
             foreach my $field (@{$fields}) {  
                 $datatable .= '<tr><td>'.$fieldtitles->{$field};  
                 if (($field eq 'screenshot') || ($field eq 'cc')) {  
                     $datatable .= ' '.&mt('(logged-in users)');  
                 }  
                 $datatable .='</td><td>';  
                 my $clickaction;  
                 if ($field eq 'screenshot') {  
                     $clickaction = ' onclick="screenshotSize(this);"';  
                 }  
                 if (ref($possoptions->{$field}) eq 'ARRAY') {  
                     foreach my $option (@{$possoptions->{$field}}) {  
                         my $checked;  
                         if ($currfield{$field} eq $option) {  
                             $checked = ' checked="checked"';  
                         }  
                         $datatable .= '<span class="LC_nobreak"><label>'.  
                                       '<input type="radio" name="helpform_'.$field.'" '.  
                                       'value="'.$option.'"'.$checked.$clickaction.' />'.$fieldoptions->{$option}.  
                                       '</label></span>'.('&nbsp;'x2);  
                     }  
                 }  
                 if ($field eq 'screenshot') {  
                     my $display;  
                     if ($currfield{$field} eq 'no') {  
                         $display = ' style="display:none"';  
                     }  
                     $datatable .= '</td></tr><tr id="help_screenshotsize"'.$display.'>'.  
                                   '<td>'.&mt('Maximum size for upload (MB)').'</td><td>'.  
                                   '<input type="text" size="5" name="helpform_maxsize" value="'.$maxsize.'" />';  
                 }  
                 $datatable .= '</td></tr>';  
             }  
             $datatable .= '</table>';  
         }  
         $datatable .= '</td></tr>'."\n";  
         $rownum ++;          $rownum ++;
     }      }
     unless (($position eq 'top') || ($position eq 'lower')) {      foreach my $type (@mailings) {
         foreach my $type (@mailings) {  
             $css_class = $rownum%2?' class="LC_odd_row"':'';  
             $datatable .= '<tr'.$css_class.'>'.  
                           '<td><span class="LC_nobreak">'.  
                           $titles->{$type}.': </span></td>'.  
                           '<td class="LC_left_item">';  
             if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {  
                 $datatable .= '<fieldset><legend>'.&mt('E-mail recipient(s)').'</legend>';  
             }  
             $datatable .= '<span class="LC_nobreak">';  
             foreach my $item (@contacts) {  
                 $datatable .= '<label>'.  
                               '<input type="checkbox" name="'.$type.'"'.  
                               $checked{$type}{$item}.  
                               ' value="'.$item.'" />'.$short_titles->{$item}.  
                               '</label>&nbsp;';  
             }  
             $datatable .= '</span><br />'.&mt('Others').':&nbsp;&nbsp;'.  
                           '<input type="text" name="'.$type.'_others" '.  
                           'value="'.$otheremails{$type}.'"  />';  
             my %locchecked;  
             if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {  
                 foreach my $loc ('s','b') {  
                     if ($includeloc{$type} eq $loc) {  
                         $locchecked{$loc} = ' checked="checked"';  
                         last;  
                     }  
                 }  
                 $datatable .= '<br />'.&mt('Bcc:').('&nbsp;'x6).  
                               '<input type="text" name="'.$type.'_bcc" '.  
                               'value="'.$bccemails{$type}.'"  /></fieldset>'.  
                               '<fieldset><legend>'.&mt('Optional added text').'</legend>'.  
                               &mt('Text automatically added to e-mail:').' '.  
                               '<input type="text" name="'.$type.'_includestr" value="'.$includestr{$type}.'" /><br />'.  
                               '<span class="LC_nobreak">'.&mt('Location:').'&nbsp;'.  
                               '<label><input type="radio" name="'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'.  
                               ('&nbsp;'x2).  
                               '<label><input type="radio" name="'.$type.'_includeloc" value="b"'.$locchecked{'b'}.' />'.&mt('in body').'</label>'.  
                               '</span></fieldset>';  
             }  
             $datatable .= '</td></tr>'."\n";  
             $rownum ++;  
         }  
     }  
     if ($position eq 'middle') {  
         my %choices;  
         my $corelink = &core_link_msu();  
         $choices{'reporterrors'} = &mt('E-mail error reports to [_1]',$corelink);  
         $choices{'reportupdates'} = &mt('E-mail record of completed LON-CAPA updates to [_1]',  
                                         $corelink);  
         $choices{'reportstatus'} = &mt('E-mail status if errors above threshold to [_1]',$corelink);  
         my @toggles = ('reporterrors','reportupdates','reportstatus');  
         my %defaultchecked = ('reporterrors'  => 'on',  
                               'reportupdates' => 'on',  
                               'reportstatus'  => 'on');  
         (my $reports,$rownum) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,  
                                                    \%choices,$rownum);  
         $datatable .= $reports;  
     } elsif ($position eq 'lower') {  
         my (%current,%excluded,%weights);  
         my ($defaults,$names) = &Apache::loncommon::lon_status_items();  
         if ($lonstatus{'threshold'} =~ /^\d+$/) {  
             $current{'errorthreshold'} = $lonstatus{'threshold'};  
         } else {  
             $current{'errorthreshold'} = $defaults->{'threshold'};  
         }  
         if ($lonstatus{'sysmail'} =~ /^\d+$/) {  
             $current{'errorsysmail'} = $lonstatus{'sysmail'};  
         } else {  
             $current{'errorsysmail'} = $defaults->{'sysmail'};  
         }  
         if (ref($lonstatus{'weights'}) eq 'HASH') {  
             foreach my $type ('E','W','N','U') {  
                 if ($lonstatus{'weights'}{$type} =~ /^\d+$/) {  
                     $weights{$type} = $lonstatus{'weights'}{$type};  
                 } else {  
                     $weights{$type} = $defaults->{$type};  
                 }  
             }  
         } else {  
             foreach my $type ('E','W','N','U') {  
                 $weights{$type} = $defaults->{$type};  
             }  
         }  
         if (ref($lonstatus{'excluded'}) eq 'ARRAY') {  
             if (@{$lonstatus{'excluded'}} > 0) {  
                 map {$excluded{$_} = 1; } @{$lonstatus{'excluded'}};  
             }  
         }  
         foreach my $item ('errorthreshold','errorsysmail') {  
             $css_class = $rownum%2?' class="LC_odd_row"':'';  
             $datatable .= '<tr'.$css_class.'>'.  
                           '<td class="LC_left_item"><span class="LC_nobreak">'.  
                           $titles->{$item}.  
                           '</span></td><td class="LC_left_item">'.  
                           '<input type="text" name="'.$item.'" value="'.  
                           $current{$item}.'" size="5" /></td></tr>';  
             $rownum ++;  
         }  
         $css_class = $rownum%2?' class="LC_odd_row"':'';          $css_class = $rownum%2?' class="LC_odd_row"':'';
         $datatable .= '<tr'.$css_class.'>'.          $datatable .= '<tr'.$css_class.'>'.
                         '<td><span class="LC_nobreak">'.
                         $titles->{$type}.': </span></td>'.
                       '<td class="LC_left_item">'.                        '<td class="LC_left_item">'.
                       '<span class="LC_nobreak">'.$titles->{'errorweights'}.                        '<span class="LC_nobreak">';
                       '</span></td><td class="LC_left_item"><table><tr>';          foreach my $item (@contacts) {
         foreach my $type ('E','W','N','U') {              $datatable .= '<label>'.
             $datatable .= '<td>'.$names->{$type}.'<br />'.                            '<input type="checkbox" name="'.$type.'"'.
                           '<input type="text" name="errorweights_'.$type.'" value="'.                            $checked{$type}{$item}.
                           $weights{$type}.'" size="5" /></td>';                            ' value="'.$item.'" />'.$short_titles->{$item}.
         }                            '</label>&nbsp;';
         $datatable .= '</tr></table></tr>';          }
         $rownum ++;          $datatable .= '</span><br />'.&mt('Others').':&nbsp;&nbsp;'.
         $css_class = $rownum%2?' class="LC_odd_row"':'';                        '<input type="text" name="'.$type.'_others" '.
         $datatable .= '<tr'.$css_class.'><td class="LC_left_item">'.                        'value="'.$otheremails{$type}.'"  />';
                       $titles->{'errorexcluded'}.'</td>'.          if ($type eq 'helpdeskmail') {
                       '<td class="LC_left_item"><table>';              $datatable .= '<br />'.&mt('Bcc:').('&nbsp;'x6).
         my $numinrow = 4;                            '<input type="text" name="'.$type.'_bcc" '.
         my @ids = sort(values(%Apache::lonnet::serverhomeIDs));                            'value="'.$bccemails{$type}.'"  />';
         for (my $i=0; $i<@ids; $i++) {  
             my $rem = $i%($numinrow);  
             if ($rem == 0) {  
                 if ($i > 0) {  
                     $datatable .= '</tr>';  
                 }  
                 $datatable .= '<tr>';  
             }  
             my $check;  
             if ($excluded{$ids[$i]}) {  
                 $check = ' checked="checked" ';  
             }  
             $datatable .= '<td class="LC_left_item">'.  
                           '<span class="LC_nobreak"><label>'.  
                           '<input type="checkbox" name="errorexcluded" '.  
                           'value="'.$ids[$i].'"'.$check.' />'.  
                           $ids[$i].'</label></span></td>';  
         }  
         my $colsleft = $numinrow - @ids%($numinrow);  
         if ($colsleft > 1 ) {  
             $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.  
                           '&nbsp;</td>';  
         } elsif ($colsleft == 1) {  
             $datatable .= '<td class="LC_left_item">&nbsp;</td>';  
         }          }
         $datatable .= '</tr></table></td></tr>';          $datatable .= '</td></tr>'."\n";
         $rownum ++;          $rownum ++;
     } elsif ($position eq 'bottom') {  
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
         my (@posstypes,%usertypeshash);  
         if (ref($types) eq 'ARRAY') {  
             @posstypes = @{$types};  
         }  
         if (@posstypes) {  
             if (ref($usertypes) eq 'HASH') {  
                 %usertypeshash = %{$usertypes};  
             }  
             my @overridden;  
             my $numinrow = 4;  
             if (ref($settings) eq 'HASH') {  
                 if (ref($settings->{'overrides'}) eq 'HASH') {  
                     foreach my $key (sort(keys(%{$settings->{'overrides'}}))) {  
                         if (ref($settings->{'overrides'}{$key}) eq 'HASH') {  
                             push(@overridden,$key);  
                             foreach my $item (@contacts) {  
                                 if ($settings->{'overrides'}{$key}{$item}) {  
                                     $checked{'override_'.$key}{$item} = ' checked="checked" ';  
                                 }  
                             }  
                             $otheremails{'override_'.$key} = $settings->{'overrides'}{$key}{'others'};  
                             $bccemails{'override_'.$key} = $settings->{'overrides'}{$key}{'bcc'};  
                             $includeloc{'override_'.$key} = '';  
                             $includestr{'override_'.$key} = '';  
                             if ($settings->{'overrides'}{$key}{'include'} ne '') {  
                                 ($includeloc{'override_'.$key},$includestr{'override_'.$key}) =  
                                     split(/:/,$settings->{'overrides'}{$key}{'include'},2);  
                                 $includestr{'override_'.$key} = &unescape($includestr{'override_'.$key});  
                             }  
                         }  
                     }  
                 }  
             }  
             my $customclass = 'LC_helpdesk_override';  
             my $optionsprefix = 'LC_options_helpdesk_';  
   
             my $onclicktypes = "toggleHelpdeskRow(this.form,'overrides','$customclass','$optionsprefix');";  
             $datatable .= &insttypes_row($settings,$types,$usertypes,$dom,  
                                          $numinrow,$othertitle,'overrides',  
                                          \$rownum,$onclicktypes,$customclass);  
             $rownum ++;  
             $usertypeshash{'default'} = $othertitle;  
             foreach my $status (@posstypes) {  
                 my $css_class;  
                 if ($rownum%2) {  
                     $css_class = 'LC_odd_row ';  
                 }  
                 $css_class .= $customclass;  
                 my $rowid = $optionsprefix.$status;  
                 my $hidden = 1;  
                 my $currstyle = 'display:none';  
                 if (grep(/^\Q$status\E$/,@overridden)) {  
                     $currstyle = 'display:table-row';  
                     $hidden = 0;  
                 }  
                 my $key = 'override_'.$status;  
                 $datatable .= &overridden_helpdesk($checked{$key},$otheremails{$key},$bccemails{$key},  
                                                   $includeloc{$key},$includestr{$key},$status,$rowid,  
                                                   $usertypeshash{$status},$css_class,$currstyle,  
                                                   \@contacts,$short_titles);  
                 unless ($hidden) {  
                     $rownum ++;  
                 }  
             }  
         }  
     }      }
       my %choices;
       $choices{'reporterrors'} = &mt('E-mail error reports to [_1]',
                                      &Apache::loncommon::modal_link('http://loncapa.org/core.html',
                                      &mt('LON-CAPA core group - MSU'),600,500));
       $choices{'reportupdates'} = &mt('E-mail record of completed LON-CAPA updates to [_1]',
                                       &Apache::loncommon::modal_link('http://loncapa.org/core.html',
                                       &mt('LON-CAPA core group - MSU'),600,500));
       my @toggles = ('reporterrors','reportupdates');
       my %defaultchecked = ('reporterrors'  => 'on',
                             'reportupdates' => 'on');
       (my $reports,$rownum) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
                                                  \%choices,$rownum);
       $datatable .= $reports;
     $$rowtotal += $rownum;      $$rowtotal += $rownum;
     return $datatable;      return $datatable;
 }  }
   
 sub core_link_msu {  
     return &Apache::loncommon::modal_link('http://loncapa.org/core.html',  
                                           &mt('LON-CAPA core group - MSU'),600,500);  
 }  
   
 sub overridden_helpdesk {  
     my ($checked,$otheremails,$bccemails,$includeloc,$includestr,$type,$rowid,  
         $typetitle,$css_class,$rowstyle,$contacts,$short_titles) = @_;  
     my $class = 'LC_left_item';  
     if ($css_class) {  
         $css_class = ' class="'.$css_class.'"';  
     }  
     if ($rowid) {  
         $rowid = ' id="'.$rowid.'"';  
     }  
     if ($rowstyle) {  
         $rowstyle = ' style="'.$rowstyle.'"';  
     }  
     my ($output,$description);  
     $description = &mt('Helpdesk requests from: [_1] in this domain (overrides default)',"<b>$typetitle</b>");  
     $output = '<tr'.$css_class.$rowid.$rowstyle.'>'.  
               "<td>$description</td>\n".  
               '<td class="'.$class.'" colspan="2">'.  
               '<fieldset><legend>'.&mt('E-mail recipient(s)').'</legend>'.  
               '<span class="LC_nobreak">';  
     if (ref($contacts) eq 'ARRAY') {  
         foreach my $item (@{$contacts}) {  
             my $check;  
             if (ref($checked) eq 'HASH') {  
                $check = $checked->{$item};  
             }  
             my $title;  
             if (ref($short_titles) eq 'HASH') {  
                 $title = $short_titles->{$item};  
             }  
             $output .= '<label>'.  
                        '<input type="checkbox" name="override_'.$type.'"'.$check.  
                        ' value="'.$item.'" />'.$title.'</label>&nbsp;';  
         }  
     }  
     $output .= '</span><br />'.&mt('Others').':&nbsp;&nbsp;'.  
                '<input type="text" name="override_'.$type.'_others" '.  
                'value="'.$otheremails.'"  />';  
     my %locchecked;  
     foreach my $loc ('s','b') {  
         if ($includeloc eq $loc) {  
             $locchecked{$loc} = ' checked="checked"';  
             last;  
         }  
     }  
     $output .= '<br />'.&mt('Bcc:').('&nbsp;'x6).  
                '<input type="text" name="override_'.$type.'_bcc" '.  
                'value="'.$bccemails.'"  /></fieldset>'.  
                '<fieldset><legend>'.&mt('Optional added text').'</legend>'.  
                &mt('Text automatically added to e-mail:').' '.  
                '<input type="text" name="override_'.$type.'_includestr" value="'.$includestr.'" /><br />'.  
                '<span class="LC_nobreak">'.&mt('Location:').'&nbsp;'.  
                '<label><input type="radio" name="override_'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'.  
                ('&nbsp;'x2).  
                '<label><input type="radio" name="override_'.$type.'_includeloc" value="b"'.$locchecked{'b'}.' />'.&mt('in body').'</label>'.  
                '</span></fieldset>'.  
                '</td></tr>'."\n";  
     return $output;  
 }  
   
 sub contacts_javascript {  
     return <<"ENDSCRIPT";  
   
 <script type="text/javascript">  
 // <![CDATA[  
   
 function screenshotSize(field) {  
     if (document.getElementById('help_screenshotsize')) {  
         if (field.value == 'no') {  
             document.getElementById('help_screenshotsize').style.display="none";  
         } else {  
             document.getElementById('help_screenshotsize').style.display="";  
         }  
     }  
     return;  
 }  
   
 function toggleHelpdeskRow(form,checkbox,target,prefix,docount) {  
     if (form.elements[checkbox].length != undefined) {  
         var count = 0;  
         if (docount) {  
             for (var i=0; i<form.elements[checkbox].length; i++) {  
                 if (form.elements[checkbox][i].checked) {  
                     count ++;  
                 }  
             }  
         }  
         for (var i=0; i<form.elements[checkbox].length; i++) {  
             var type = form.elements[checkbox][i].value;  
             if (document.getElementById(prefix+type)) {  
                 if (form.elements[checkbox][i].checked) {  
                     document.getElementById(prefix+type).style.display = 'table-row';  
                     if (count % 2 == 1) {  
                         document.getElementById(prefix+type).className = target+' LC_odd_row';  
                     } else {  
                         document.getElementById(prefix+type).className = target;  
                     }  
                     count ++;  
                 } else {  
                     document.getElementById(prefix+type).style.display = 'none';  
                 }  
             }  
         }  
     }  
     return;  
 }  
   
 // ]]>  
 </script>  
   
 ENDSCRIPT  
 }  
   
 sub print_helpsettings {  sub print_helpsettings {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($dom,$confname,$settings,$rowtotal) = @_;
     my $confname = $dom.'-domainconfig';  
     my $formname = 'display';  
     my ($datatable,$itemcount);      my ($datatable,$itemcount);
     if ($position eq 'top') {      $itemcount = 1;
         $itemcount = 1;      my (%choices,%defaultchecked,@toggles);
         my (%choices,%defaultchecked,@toggles);      $choices{'submitbugs'} = &mt('Display link to: [_1]?',
         $choices{'submitbugs'} = &mt('Display link to: [_1]?',                                   &Apache::loncommon::modal_link('http://bugs.loncapa.org',
                                      &Apache::loncommon::modal_link('http://bugs.loncapa.org',                                   &mt('LON-CAPA bug tracker'),600,500));
                                      &mt('LON-CAPA bug tracker'),600,500));      %defaultchecked = ('submitbugs' => 'on');
         %defaultchecked = ('submitbugs' => 'on');      @toggles = ('submitbugs',);
         @toggles = ('submitbugs');  
         ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,  
                                                      \%choices,$itemcount);  
         $$rowtotal ++;  
     } else {  
         my $css_class;  
         my %existing=&Apache::lonnet::dump('roles',$dom,$confname,'rolesdef_');  
         my (%customroles,%ordered,%current);  
         if (ref($settings) eq 'HASH') {  
             if (ref($settings->{'adhoc'}) eq 'HASH') {  
                 %current = %{$settings->{'adhoc'}};  
             }  
         }  
         my $count = 0;  
         foreach my $key (sort(keys(%existing))) {  
             if ($key=~/^rolesdef\_(\w+)$/) {  
                 my $rolename = $1;  
                 my (%privs,$order);  
                 ($privs{'system'},$privs{'domain'},$privs{'course'}) = split(/\_/,$existing{$key});  
                 $customroles{$rolename} = \%privs;  
                 if (ref($current{$rolename}) eq 'HASH') {  
                     $order = $current{$rolename}{'order'};  
                 }  
                 if ($order eq '') {  
                     $order = $count;  
                 }  
                 $ordered{$order} = $rolename;  
                 $count++;  
             }  
         }  
         my $maxnum = scalar(keys(%ordered));  
         my @roles_by_num = ();  
         foreach my $item (sort {$a <=> $b } (keys(%ordered))) {  
             push(@roles_by_num,$item);  
         }  
         my $context = 'domprefs';  
         my $crstype = 'Course';  
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
         my @accesstypes = ('all','dh','da','none');  
         my ($numstatustypes,@jsarray);  
         if (ref($types) eq 'ARRAY') {  
             if (@{$types} > 0) {  
                 $numstatustypes = scalar(@{$types});  
                 push(@accesstypes,'status');  
                 @jsarray = ('bystatus');  
             }  
         }  
         my %domhelpdesk = &Apache::lonnet::get_active_domroles($dom,['dh','da']);  
         if (keys(%domhelpdesk)) {  
             push(@accesstypes,('inc','exc'));  
             push(@jsarray,('notinc','notexc'));  
         }  
         my $hiddenstr = join("','",@jsarray);  
         my $context = 'domprefs';  
         my $crstype = 'Course';  
         my $prefix = 'helproles_';  
         my $add_class = 'LC_hidden';  
         foreach my $num (@roles_by_num) {  
             my $role = $ordered{$num};  
             my ($desc,$access,@statuses);  
             if (ref($current{$role}) eq 'HASH') {  
                 $desc = $current{$role}{'desc'};  
                 $access = $current{$role}{'access'};  
                 if (ref($current{$role}{'insttypes'}) eq 'ARRAY') {  
                     @statuses = @{$current{$role}{'insttypes'}};  
                 }  
             }  
             if ($desc eq '') {  
                 $desc = $role;  
             }  
             my $identifier = 'custhelp'.$num;  
             my %full=();  
             my %levels= (  
                          course => {},  
                          domain => {},  
                          system => {},  
                         );  
             my %levelscurrent=(  
                                course => {},  
                                domain => {},  
                                system => {},  
                               );  
             &Apache::lonuserutils::custom_role_privs($customroles{$role},\%full,\%levels,\%levelscurrent);  
             my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);  
             $css_class = $itemcount%2?' class="LC_odd_row"':'';  
             my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$num."_pos'".');"';  
             $datatable .= '<tr '.$css_class.'><td valign="top"><b>'.$role.'</b><br />'.  
                           '<select name="helproles_'.$num.'_pos"'.$chgstr.'>';  
             for (my $k=0; $k<=$maxnum; $k++) {  
                 my $vpos = $k+1;  
                 my $selstr;  
                 if ($k == $num) {  
                     $selstr = ' selected="selected" ';  
                 }  
                 $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';  
             }  
             $datatable .= '</select>'.('&nbsp;'x2).  
                           '<input type="hidden" name="helproles_'.$num.'" value="'.$role.'" />'.  
                           '</td>'.  
                           '<td><fieldset><legend>'.&mt('Role name').'</legend>'.  
                           &mt('Name shown to users:').  
                           '<input type="text" name="helproles_'.$num.'_desc" value="'.$desc.'" />'.  
                           '</fieldset>'.  
                           &helpdeskroles_access($dom,$prefix,$num,$add_class,$current{$role},\@accesstypes,  
                                                 $othertitle,$usertypes,$types,\%domhelpdesk).  
                           '<fieldset>'.  
                           '<legend>'.&mt('Role privileges').&adhocbutton($prefix,$num,'privs','show').'</legend>'.  
                           &Apache::lonuserutils::custom_role_table($crstype,\%full,\%levels,  
                                                                    \%levelscurrent,$identifier,  
                                                                    'LC_hidden',$prefix.$num.'_privs').  
                           '</fieldset></td>';  
             $itemcount ++;  
         }  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         my $newcust = 'custhelp'.$count;  
         my (%privs,%levelscurrent);  
         my %full=();  
         my %levels= (  
                      course => {},  
                      domain => {},  
                      system => {},  
                     );  
         &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);  
         my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);  
         my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$count."_pos'".');"';  
         $datatable .= '<tr '.$css_class.'><td valign="top"><span class="LC_nobreak"><label>'.  
                       '<input type="hidden" name="helproles_maxnum" value="'.$maxnum.'" />'."\n".  
                       '<select name="helproles_'.$count.'_pos"'.$chgstr.'>';  
         for (my $k=0; $k<$maxnum+1; $k++) {  
             my $vpos = $k+1;  
             my $selstr;  
             if ($k == $maxnum) {  
                 $selstr = ' selected="selected" ';  
             }  
             $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';  
         }  
         $datatable .= '</select>&nbsp;'."\n".  
                       '<input type="checkbox" name="newcusthelp" value="'.$count.'" />'. &mt('Add').  
                       '</label></span></td>'.  
                       '<td><fieldset><legend>'.&mt('Role name').'</legend>'.  
                       '<span class="LC_nobreak">'.  
                       &mt('Internal name:').  
                       '<input type="text" size="10" name="custhelpname'.$count.'" value="" />'.  
                       '</span>'.('&nbsp;'x4).  
                       '<span class="LC_nobreak">'.  
                       &mt('Name shown to users:').  
                       '<input type="text" size="20" name="helproles_'.$count.'_desc" value="" />'.  
                       '</span></fieldset>'.  
                        &helpdeskroles_access($dom,$prefix,$count,'',undef,\@accesstypes,$othertitle,  
                                              $usertypes,$types,\%domhelpdesk).  
                       '<fieldset><legend>'.&mt('Role privileges').'</legend>'.  
                       &Apache::lonuserutils::custom_role_header($context,$crstype,  
                                                                 \@templateroles,$newcust).  
                       &Apache::lonuserutils::custom_role_table('Course',\%full,\%levels,  
                                                                \%levelscurrent,$newcust).  
                       '</fieldset>'.  
                       &helpsettings_javascript(\@roles_by_num,$maxnum,$hiddenstr,$formname).  
                       '</td></tr>';  
         $count ++;  
         $$rowtotal += $count;  
     }  
     return $datatable;  
 }  
   
 sub adhocbutton {  
     my ($prefix,$num,$field,$visibility) = @_;  
     my %lt = &Apache::lonlocal::texthash(  
                                           show => 'Show details',  
                                           hide => 'Hide details',  
                                         );  
     return '<span style="text-decoration:line-through; font-weight: normal;">'.('&nbsp;'x10).  
            '</span>'.('&nbsp;'x2).'<input type="button" id="'.$prefix.$num.'_'.$field.'_vis"'.  
            ' value="'.$lt{$visibility}.'" style="height:20px;" '.  
            'onclick="toggleHelpdeskItem('."'$num','$field'".');" />'.('&nbsp;'x2);  
 }  
   
 sub helpsettings_javascript {  
     my ($roles_by_num,$total,$hiddenstr,$formname) = @_;  
     return unless(ref($roles_by_num) eq 'ARRAY');  
     my %html_js_lt = &Apache::lonlocal::texthash(  
                                           show => 'Show details',  
                                           hide => 'Hide details',  
                                         );  
     &html_escape(\%html_js_lt);  
     my $jstext = '    var helproles = Array('."'".join("','",@{$roles_by_num})."'".');'."\n";  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
   
 function reorderHelpRoles(form,item) {      ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
     var changedVal;                                                   \%choices,$itemcount);
 $jstext      return $datatable;
     var newpos = 'helproles_${total}_pos';  
     var maxh = 1 + $total;  
     var current = new Array();  
     var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;  
     if (item == newpos) {  
         changedVal = newitemVal;  
     } else {  
         changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;  
         current[newitemVal] = newpos;  
     }  
     for (var i=0; i<helproles.length; i++) {  
         var elementName = 'helproles_'+helproles[i]+'_pos';  
         if (elementName != item) {  
             if (form.elements[elementName]) {  
                 var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;  
                 current[currVal] = elementName;  
             }  
         }  
     }  
     var oldVal;  
     for (var j=0; j<maxh; j++) {  
         if (current[j] == undefined) {  
             oldVal = j;  
         }  
     }  
     if (oldVal < changedVal) {  
         for (var k=oldVal+1; k<=changedVal ; k++) {  
            var elementName = current[k];  
            form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;  
         }  
     } else {  
         for (var k=changedVal; k<oldVal; k++) {  
             var elementName = current[k];  
             form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;  
         }  
     }  
     return;  
 }  
   
 function helpdeskAccess(num) {  
     var curraccess = null;  
     if (document.$formname.elements['helproles_'+num+'_access'].length) {  
         for (var i=0; i<document.$formname.elements['helproles_'+num+'_access'].length; i++) {  
             if (document.$formname.elements['helproles_'+num+'_access'][i].checked) {  
                 curraccess = document.$formname.elements['helproles_'+num+'_access'][i].value;  
             }  
         }  
     }  
     var shown = Array();  
     var hidden = Array();  
     if (curraccess == 'none') {  
         hidden = Array('$hiddenstr');  
     } else {  
         if (curraccess == 'status') {  
             shown = Array('bystatus');  
             hidden = Array('notinc','notexc');  
         } else {  
             if (curraccess == 'exc') {  
                 shown = Array('notexc');  
                 hidden = Array('notinc','bystatus');  
             }  
             if (curraccess == 'inc') {  
                 shown = Array('notinc');  
                 hidden = Array('notexc','bystatus');  
             }  
             if ((curraccess == 'all') || (curraccess == 'dh') || (curraccess == 'da')) {  
                 hidden = Array('notinc','notexc','bystatus');  
             }  
         }  
     }  
     if (hidden.length > 0) {  
         for (var i=0; i<hidden.length; i++) {  
             if (document.getElementById('helproles_'+num+'_'+hidden[i])) {  
                 document.getElementById('helproles_'+num+'_'+hidden[i]).style.display = 'none';  
             }  
         }  
     }  
     if (shown.length > 0) {  
         for (var i=0; i<shown.length; i++) {  
             if (document.getElementById('helproles_'+num+'_'+shown[i])) {  
                 if (shown[i] == 'privs') {  
                     document.getElementById('helproles_'+num+'_'+shown[i]).style.display = 'block';  
                 } else {  
                     document.getElementById('helproles_'+num+'_'+shown[i]).style.display = 'inline-block';  
                 }  
             }  
         }  
     }  
     return;  
 }  
   
 function toggleHelpdeskItem(num,field) {  
     if (document.getElementById('helproles_'+num+'_'+field)) {  
         if (document.getElementById('helproles_'+num+'_'+field).className.match(/(?:^|\\s)LC_hidden(?!\\S)/)) {  
             document.getElementById('helproles_'+num+'_'+field).className =  
                 document.getElementById('helproles_'+num+'_'+field).className.replace(/(?:^|\\s)LC_hidden(?!\\S)/g ,'');  
             if (document.getElementById('helproles_'+num+'_'+field+'_vis')) {  
                 document.getElementById('helproles_'+num+'_'+field+'_vis').value = '$html_js_lt{hide}';  
             }  
         } else {  
             document.getElementById('helproles_'+num+'_'+field).className += ' LC_hidden';  
             if (document.getElementById('helproles_'+num+'_'+field+'_vis')) {  
                 document.getElementById('helproles_'+num+'_'+field+'_vis').value = '$html_js_lt{show}';  
             }  
         }  
     }  
     return;  
 }  
   
 // ]]>  
 </script>  
   
 ENDSCRIPT  
 }  
   
 sub helpdeskroles_access {  
     my ($dom,$prefix,$num,$add_class,$current,$accesstypes,$othertitle,  
         $usertypes,$types,$domhelpdesk) = @_;  
     return unless ((ref($accesstypes) eq 'ARRAY') && (ref($domhelpdesk) eq 'HASH'));  
     my %lt = &Apache::lonlocal::texthash(  
                     'rou'    => 'Role usage',  
                     'whi'    => 'Which helpdesk personnel may use this role?',  
                     'all'    => 'All with domain helpdesk or helpdesk assistant role',  
                     'dh'     => 'All with domain helpdesk role',  
                     'da'     => 'All with domain helpdesk assistant role',  
                     'none'   => 'None',  
                     'status' => 'Determined based on institutional status',  
                     'inc'    => 'Include all, but exclude specific personnel',  
                     'exc'    => 'Exclude all, but include specific personnel',  
                   );  
     my %usecheck = (  
                      all => ' checked="checked"',  
                    );  
     my %displaydiv = (  
                       status => 'none',  
                       inc    => 'none',  
                       exc    => 'none',  
                       priv   => 'block',  
                      );  
     my $output;  
     if (ref($current) eq 'HASH') {  
         if (($current->{'access'} ne '') && ($current->{'access'} ne 'all')) {  
             if (grep(/^\Q$current->{access}\E$/,@{$accesstypes})) {  
                 $usecheck{$current->{access}} = $usecheck{'all'};  
                 delete($usecheck{'all'});  
                 if ($current->{access} =~ /^(status|inc|exc)$/) {  
                     my $access = $1;  
                     $displaydiv{$access} = 'inline';  
                 } elsif ($current->{access} eq 'none') {  
                     $displaydiv{'priv'} = 'none';  
                 }  
             }  
         }  
     }  
     $output = '<fieldset id="'.$prefix.$num.'_usage"><legend>'.$lt{'rou'}.'</legend>'.  
               '<p>'.$lt{'whi'}.'</p>';  
     foreach my $access (@{$accesstypes}) {  
         $output .= '<p><label><input type="radio" name="'.$prefix.$num.'_access" value="'.$access.'" '.$usecheck{$access}.  
                    ' onclick="helpdeskAccess('."'$num'".');" />'.  
                    $lt{$access}.'</label>';  
         if ($access eq 'status') {  
             $output .= '<div id="'.$prefix.$num.'_bystatus" style="display:'.$displaydiv{$access}.'">'.  
                        &Apache::lonuserutils::adhoc_status_types($dom,$prefix,$num,$current->{$access},  
                                                                  $othertitle,$usertypes,$types).  
                        '</div>';  
         } elsif (($access eq 'inc') && (keys(%{$domhelpdesk}) > 0)) {  
             $output .= '<div id="'.$prefix.$num.'_notinc" style="display:'.$displaydiv{$access}.'">'.  
                        &Apache::lonuserutils::adhoc_staff($access,$prefix,$num,$current->{$access},$domhelpdesk).  
                        '</div>';  
         } elsif (($access eq 'exc') && (keys(%{$domhelpdesk}) > 0)) {  
             $output .= '<div id="'.$prefix.$num.'_notexc" style="display:'.$displaydiv{$access}.'">'.  
                        &Apache::lonuserutils::adhoc_staff($access,$prefix,$num,$current->{$access},$domhelpdesk).  
                        '</div>';  
         }  
         $output .= '</p>';  
     }  
     $output .= '</fieldset>';  
     return $output;  
 }  }
   
 sub radiobutton_prefs {  sub radiobutton_prefs {
     my ($settings,$toggles,$defaultchecked,$choices,$itemcount,$onclick,      my ($settings,$toggles,$defaultchecked,$choices,$itemcount,$onclick,
         $additional,$align,$firstval) = @_;          $additional,$align) = @_;
     return unless ((ref($toggles) eq 'ARRAY') && (ref($defaultchecked) eq 'HASH') &&      return unless ((ref($toggles) eq 'ARRAY') && (ref($defaultchecked) eq 'HASH') &&
                    (ref($choices) eq 'HASH'));                     (ref($choices) eq 'HASH'));
   
Line 5048  sub radiobutton_prefs { Line 2884  sub radiobutton_prefs {
         } else {          } else {
             $datatable .= '<td class="LC_right_item">';              $datatable .= '<td class="LC_right_item">';
         }          }
         $datatable .= '<span class="LC_nobreak">';          $datatable .= 
         if ($firstval eq 'no') {              '<span class="LC_nobreak">'.
             $datatable .=              '<label><input type="radio" name="'.
                 '<label><input type="radio" name="'.              $item.'" '.$checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').
                 $item.'" '.$checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').              '</label>&nbsp;<label><input type="radio" name="'.$item.'" '.
                 '</label>&nbsp;<label><input type="radio" name="'.$item.'" '.              $checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').'</label>'.
                 $checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').'</label>';              '</span>'.$additional.
         } else {              '</td>'.
             $datatable .=              '</tr>';
                 '<label><input type="radio" name="'.  
                 $item.'" '.$checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').  
                 '</label>&nbsp;<label><input type="radio" name="'.$item.'" '.  
                 $checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').'</label>';  
         }  
         $datatable .= '</span>'.$additional.'</td></tr>';  
         $itemcount ++;          $itemcount ++;
     }      }
     return ($datatable,$itemcount);      return ($datatable,$itemcount);
 }  }
   
 sub print_ltitools {  
     my ($position,$dom,$settings,$rowtotal) = @_;  
     my (%rules,%encrypt,%privkeys,%linkprot);  
     if (ref($settings) eq 'HASH') {  
         if ($position eq 'top') {  
             if (exists($settings->{'encrypt'})) {  
                 if (ref($settings->{'encrypt'}) eq 'HASH') {  
                     foreach my $key (keys(%{$settings->{'encrypt'}})) {  
                         $encrypt{'toolsec_'.$key} = $settings->{'encrypt'}{$key};  
                     }  
                 }  
             }  
             if (exists($settings->{'private'})) {  
                 if (ref($settings->{'private'}) eq 'HASH') {  
                     if (ref($settings->{'private'}) eq 'HASH') {  
                         if (ref($settings->{'private'}{'keys'}) eq 'ARRAY') {  
                             map { $privkeys{$_} = 1; } (@{$settings->{'private'}{'keys'}});  
                         }  
                     }  
                 }  
             }  
         } elsif ($position eq 'middle') {  
             if (exists($settings->{'rules'})) {  
                 if (ref($settings->{'rules'}) eq 'HASH') {  
                     %rules = %{$settings->{'rules'}};  
                 }  
             }  
         } else {  
             foreach my $key ('encrypt','private','rules') {  
                 if (exists($settings->{$key})) {  
                     delete($settings->{$key});  
                 }  
             }  
         }  
     }  
     my $datatable;  
     my $itemcount = 1;  
     if ($position eq 'top') {  
         $datatable = &secrets_form($dom,'toolsec',\%encrypt,\%privkeys,$rowtotal);  
     } elsif ($position eq 'middle') {  
         $datatable = &password_rules('toolsecrets',\$itemcount,\%rules);  
         $$rowtotal += $itemcount;  
     } else {  
         $datatable = &Apache::courseprefs::print_ltitools($dom,'',$settings,\$rowtotal,'','','domain');  
     }  
     return $datatable;  
 }  
   
 sub ltitools_names {  
     my %lt = &Apache::lonlocal::texthash(  
                                           'title'          => 'Title',  
                                           'version'        => 'Version',  
                                           'msgtype'        => 'Message Type',  
                                           'sigmethod'      => 'Signature Method',  
                                           'url'            => 'URL',  
                                           'key'            => 'Key',  
                                           'lifetime'       => 'Nonce lifetime (s)',  
                                           'secret'         => 'Secret',  
                                           'icon'           => 'Icon',  
                                           'user'           => 'User',  
                                           'fullname'       => 'Full Name',  
                                           'firstname'      => 'First Name',  
                                           'lastname'       => 'Last Name',  
                                           'email'          => 'E-mail',  
                                           'roles'          => 'Role',  
                                           'window'         => 'Window',  
                                           'tab'            => 'Tab',  
                                           'iframe'         => 'iFrame',  
                                           'height'         => 'Height',  
                                           'width'          => 'Width',  
                                           'linktext'       => 'Default Link Text',  
                                           'explanation'    => 'Default Explanation',  
                                           'passback'       => 'Tool can return grades:',  
                                           'roster'         => 'Tool can retrieve roster:',  
                                           'crstarget'      => 'Display target',  
                                           'crslabel'       => 'Course label',  
                                           'crstitle'       => 'Course title',  
                                           'crslinktext'    => 'Link Text',  
                                           'crsexplanation' => 'Explanation',  
                                           'crsappend'      => 'Provider URL',  
                                         );  
     return %lt;  
 }  
   
 sub secrets_form {  
     my ($dom,$context,$encrypt,$privkeys,$rowtotal) = @_;  
     my @ids=&Apache::lonnet::current_machine_ids();  
     my %servers = &Apache::lonnet::get_servers($dom,'library');  
     my $primary = &Apache::lonnet::domain($dom,'primary');  
     my ($css_class,$extra,$numshown,$itemcount,$output);  
     $itemcount = 0;  
     foreach my $hostid (sort(keys(%servers))) {  
         my ($showextra,$divsty,$switch);  
         if ($hostid eq $primary) {  
             if ($context eq 'ltisec') {  
                 if (($encrypt->{'ltisec_consumers'}) || ($encrypt->{'ltisec_domlinkprot'})) {  
                     $showextra = 1;  
                 }  
                 if ($encrypt->{'ltisec_crslinkprot'}) {  
                     $showextra = 1;  
                 }  
             } else {  
                 if (($encrypt->{'toolsec_crs'}) || ($encrypt->{'toolsec_dom'})) {  
                     $showextra = 1;  
                 }  
             }  
             unless (grep(/^\Q$hostid\E$/,@ids)) {  
                 $switch = 1;  
             }  
             if ($showextra) {  
                 $numshown ++;  
                 $divsty = 'display:inline-block';  
             } else {  
                 $divsty = 'display:none';  
             }  
             $extra .= '<fieldset id="'.$context.'_info_'.$hostid.'" style="'.$divsty.'">'.  
                       '<legend>'.$hostid.'</legend>';  
             if ($switch) {  
                 my $switchserver = '<a href="/adm/switchserver?otherserver='.$hostid.'&amp;role='.  
                                    &HTML::Entities::encode($env{'request.role'},'\'<>"&').  
                                    '&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';  
                 if (exists($privkeys->{$hostid})) {  
                     $extra .= '<div id="'.$context.'_divcurrprivkey_'.$hostid.'" style="display:inline-block" />'.  
                               '<span class="LC_nobreak">'.  
                               &mt('Encryption Key').': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.  
                               '<span class="LC_nobreak">'.&mt('Change?').  
                               '<label><input type="radio" value="0" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" checked="checked" />'.&mt('No').'</label>'.  
                               ('&nbsp;'x2).  
                               '<label><input type="radio" value="1" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" />'.&mt('Yes').  
                               '</label>&nbsp;&nbsp;</span><div id="'.$context.'_divchgprivkey_'.$hostid.'" style="display:none" />'.  
                               '<span class="LC_nobreak"> - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver).  
                               '</span></div>';  
                 } else {  
                     $extra .= '<span class="LC_nobreak">'.  
                               &mt('Key required').' - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver).  
                               '</span>'."\n";  
                 }  
             } elsif (exists($privkeys->{$hostid})) {  
                 $extra .= '<div id="'.$context.'_divcurrprivkey_'.$hostid.'" style="display:inline-block" /><span class="LC_nobreak">'.  
                           &mt('Encryption Key').': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.  
                           '<span class="LC_nobreak">'.&mt('Change?').  
                           '<label><input type="radio" value="0" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" checked="checked" />'.&mt('No').'</label>'.  
                           ('&nbsp;'x2).  
                           '<label><input type="radio" value="1" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" />'.&mt('Yes').  
                           '</label>&nbsp;&nbsp;</span><div id="'.$context.'_divchgprivkey_'.$hostid.'" style="display:none" />'.  
                           '<span class="LC_nobreak">'.&mt('New Key').':'.  
                           '<input type="password" size="20" name="'.$context.'_privkey_'.$hostid.'" value="" autocomplete="new-password" />'.  
                           '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.'.$context.'_privkey_'.$hostid.'.type='."'text'".' } else { this.form.'.$context.'_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.  
                           '</span></div>';  
             } else {  
                 $extra .= '<span class="LC_nobreak">'.&mt('Encryption Key').':'.  
                           '<input type="password" size="20" name="'.$context.'_privkey_'.$hostid.'" value="" autocomplete="new-password" />'.  
                           '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.'.$context.'_privkey_'.$hostid.'.type='."'text'".' } else { this.form.'.$context.'_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>';  
             }  
             $extra .= '</fieldset>';  
         }  
     }  
     my (%choices,@toggles,%defaultchecked);  
     if ($context eq 'ltisec') {  
         %choices = &Apache::lonlocal::texthash (  
                                                   ltisec_crslinkprot => 'Encrypt stored link protection secrets defined in courses',  
                                                   ltisec_domlinkprot => 'Encrypt stored link protection secrets defined in domain',  
                                                   ltisec_consumers   => 'Encrypt stored consumer secrets defined in domain',  
                                                );  
         @toggles = qw(ltisec_crslinkprot ltisec_domlinkprot ltisec_consumers);  
         %defaultchecked = (  
                            'ltisec_crslinkprot' => 'off',  
                            'ltisec_domlinkprot' => 'off',  
                            'ltisec_consumers'   => 'off',  
                           );  
     } else {  
         %choices = &Apache::lonlocal::texthash (  
                                                   toolsec_crs => 'Encrypt stored external tool secrets defined in courses',  
                                                   toolsec_dom => 'Encrypt stored external tool secrets defined in domain',  
                                                );  
         @toggles = qw(toolsec_crs toolsec_dom);  
         %defaultchecked = (  
                            'toolsec_crs' => 'off',  
                            'toolsec_dom' => 'off',  
                           );  
     }  
     my ($onclick,$itemcount);  
     $onclick = 'javascript:toggleLTIEncKey(this.form,'."'$context'".');';  
     ($output,$itemcount) = &radiobutton_prefs($encrypt,\@toggles,\%defaultchecked,  
                                               \%choices,$itemcount,$onclick,'','left','no');  
   
     $css_class = $itemcount%2?' class="LC_odd_row"':'';  
     my $noprivkeysty = 'display:inline-block';  
     if ($numshown) {  
         $noprivkeysty = 'display:none';  
     }  
     $output .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.&mt('Encryption Key(s)').'</td>'.  
                '<td><div id="'.$context.'_noprivkey" style="'.$noprivkeysty.'" >'.  
                '<span class="LC_nobreak">'.&mt('Not in use').'</span></div>'.  
                $extra.  
                '</td></tr>';  
     $itemcount ++;  
     $$rowtotal += $itemcount;  
     return $output;  
 }  
   
 sub print_lti {  
     my ($position,$dom,$settings,$rowtotal) = @_;  
     my $itemcount = 1;  
     my ($datatable,$css_class);  
     my (%rules,%encrypt,%privkeys,%linkprot);  
     if (ref($settings) eq 'HASH') {  
         if ($position eq 'top') {  
             if (exists($settings->{'encrypt'})) {  
                 if (ref($settings->{'encrypt'}) eq 'HASH') {  
                     foreach my $key (keys(%{$settings->{'encrypt'}})) {  
                         if ($key eq 'consumers') {  
                             $encrypt{'ltisec_'.$key} = $settings->{'encrypt'}{$key};  
                         } else {  
                             $encrypt{'ltisec_'.$key.'linkprot'} = $settings->{'encrypt'}{$key};  
                         }  
                     }  
                 }  
             }  
             if (exists($settings->{'private'})) {  
                 if (ref($settings->{'private'}) eq 'HASH') {  
                     if (ref($settings->{'private'}) eq 'HASH') {  
                         if (ref($settings->{'private'}{'keys'}) eq 'ARRAY') {  
                             map { $privkeys{$_} = 1; } (@{$settings->{'private'}{'keys'}});  
                         }  
                     }  
                 }  
             }  
         } elsif ($position eq 'middle') {  
             if (exists($settings->{'rules'})) {  
                 if (ref($settings->{'rules'}) eq 'HASH') {  
                     %rules = %{$settings->{'rules'}};  
                 }  
             }  
         } elsif ($position eq 'lower') {  
             if (exists($settings->{'linkprot'})) {  
                 if (ref($settings->{'linkprot'}) eq 'HASH') {  
                     %linkprot = %{$settings->{'linkprot'}};  
                     if ($linkprot{'lock'}) {  
                         delete($linkprot{'lock'});  
                     }  
                 }  
             }  
         } else {  
             foreach my $key ('encrypt','private','rules','linkprot') {  
                 if (exists($settings->{$key})) {  
                     delete($settings->{$key});  
                 }  
             }  
         }  
     }  
     if ($position eq 'top') {  
         $datatable = &secrets_form($dom,'ltisec',\%encrypt,\%privkeys,$rowtotal);  
     } elsif ($position eq 'middle') {  
         $datatable = &password_rules('ltisecrets',\$itemcount,\%rules);  
         $$rowtotal += $itemcount;  
     } elsif ($position eq 'lower') {  
          $datatable .= &Apache::courseprefs::print_linkprotection($dom,'',$settings,$rowtotal,'','','domain');  
     } else {  
         my ($switchserver,$switchmessage);  
         $switchserver = &check_switchserver($dom);  
         $switchmessage = &mt("submit from domain's primary library server: [_1].",$switchserver);  
         my $maxnum = 0;  
         my %ordered;  
         if (ref($settings) eq 'HASH') {  
             foreach my $item (keys(%{$settings})) {  
                 if (ref($settings->{$item}) eq 'HASH') {  
                     my $num = $settings->{$item}{'order'};  
                     if ($num eq '') {  
                         $num = scalar(keys(%{$settings}));  
                     }  
                     $ordered{$num} = $item;  
                 }  
             }  
         }  
         $maxnum = scalar(keys(%ordered));  
         my %lt = &lti_names();  
         if (keys(%ordered)) {  
             my @items = sort { $a <=> $b } keys(%ordered);  
             for (my $i=0; $i<@items; $i++) {  
                 $css_class = $itemcount%2?' class="LC_odd_row"':'';  
                 my $item = $ordered{$items[$i]};  
                 my ($key,$secret,$usable,$lifetime,$consumer,$requser,$crsinc,$current);  
                 if (ref($settings->{$item}) eq 'HASH') {  
                     $key = $settings->{$item}->{'key'};  
                     $usable = $settings->{$item}->{'usable'};  
                     $lifetime = $settings->{$item}->{'lifetime'};  
                     $consumer = $settings->{$item}->{'consumer'};  
                     $requser = $settings->{$item}->{'requser'};  
                     $crsinc = $settings->{$item}->{'crsinc'};  
                     $current = $settings->{$item};  
                 }  
                 my $onclickrequser = ' onclick="toggleLTI(this.form,'."'requser','$i'".');"';  
                 my %checkedrequser = (  
                                        yes => ' checked="checked"',  
                                        no  => '',  
                                      );  
                 if (!$requser) {  
                     $checkedrequser{'no'} = $checkedrequser{'yes'};  
                     $checkedrequser{'yes'} = '';  
                 }  
                 my $onclickcrsinc = ' onclick="toggleLTI(this.form,'."'crsinc','$i'".');"';  
                 my %checkedcrsinc = (  
                                       yes => ' checked="checked"',  
                                       no  => '',  
                                     );  
                 if (!$crsinc) {  
                     $checkedcrsinc{'no'} = $checkedcrsinc{'yes'};  
                     $checkedcrsinc{'yes'} = '';  
                 }  
                 my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_".$item."'".');"';  
                 $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'  
                              .'<select name="lti_pos_'.$item.'"'.$chgstr.'>';  
                 for (my $k=0; $k<=$maxnum; $k++) {  
                     my $vpos = $k+1;  
                     my $selstr;  
                     if ($k == $i) {  
                         $selstr = ' selected="selected" ';  
                     }  
                     $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';  
                 }  
                 $datatable .= '</select>'.('&nbsp;'x2).  
                     '<label><input type="checkbox" name="lti_del" value="'.$item.'" />'.  
                     &mt('Delete?').'</label></span></td>'.  
                     '<td colspan="2">'.  
                     '<fieldset><legend>'.&mt('Required settings').'</legend>'.  
                     '<span class="LC_nobreak">'.$lt{'consumer'}.  
                     ':<input type="text" size="15" name="lti_consumer_'.$i.'" value="'.$consumer.'" /></span> '.  
                     ('&nbsp;'x2).  
                     '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_'.$i.'">'.  
                     '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '.  
                     ('&nbsp;'x2).  
                     '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" name="lti_lifetime_'.$i.'"'.  
                     'value="'.$lifetime.'" size="3" /></span><br /><br />';  
                 if ($key ne '') {  
                     $datatable .= '<span class="LC_nobreak">'.$lt{'key'};  
                     if ($switchserver) {  
                         $datatable .= ': ['.&mt('[_1] to view/edit',$switchserver).']';  
                     } else {  
                         $datatable .= ':<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" autocomplete="off" />';  
                     }  
                     $datatable .= '</span> '.('&nbsp;'x2);  
                 } elsif (!$switchserver) {  
                     $datatable .= '<span class="LC_nobreak">'.$lt{'key'}.':'.  
                                   '<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" autocomplete="off" />'.  
                                   '</span> '.('&nbsp;'x2);  
                 }  
                 if ($switchserver) {  
                     if ($usable ne '') {  
                         $datatable .= '<div id="lti_divcurrsecret_'.$i.'" style="display:inline-block" /><span class="LC_nobreak">'.  
                                       $lt{'secret'}.': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.  
                                       '<span class="LC_nobreak">'.&mt('Change secret?').  
                                       '<label><input type="radio" value="0" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" checked="checked" />'.&mt('No').'</label>'.  
                                       ('&nbsp;'x2).  
                                      '<label><input type="radio" value="1" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" />'.&mt('Yes').'</label>'.('&nbsp;'x2).  
                                       '</span><div id="lti_divchgsecret_'.$i.'" style="display:none" />'.  
                                       '<span class="LC_nobreak"> - '.$switchmessage.'</span>'.  
                                       '</div>';  
                     } elsif ($key eq '') {  
                         $datatable .= '<span class="LC_nobreak">'.&mt('Key and Secret are required').' - '.$switchmessage.'</span>'."\n";  
                     } else {  
                         $datatable .= '<span class="LC_nobreak">'.&mt('Secret required').' - '.$switchmessage.'</span>'."\n";  
                     }  
                 } else {  
                     if ($usable ne '') {  
                         $datatable .= '<div id="lti_divcurrsecret_'.$i.'" style="display:inline-block" /><span class="LC_nobreak">'.  
                                       $lt{'secret'}.': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.  
                                       '<span class="LC_nobreak">'.&mt('Change?').  
                                       '<label><input type="radio" value="0" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" checked="checked" />'.&mt('No').'</label>'.  
                                       ('&nbsp;'x2).  
                                       '<label><input type="radio" value="1" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" />'.&mt('Yes').  
                                       '</label>&nbsp;&nbsp;</span><div id="lti_divchgsecret_'.$i.'" style="display:none" />'.  
                                       '<span class="LC_nobreak">'.&mt('New Secret').':'.  
                                       '<input type="password" size="20" name="lti_secret_'.$i.'" value="" autocomplete="new-password" />'.  
                                       '<label><input type="checkbox" name="lti_visible_'.$i.'" id="lti_visible_'.$i.'" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label></span></div>';  
                     } else {  
                         $datatable .=  
                             '<span class="LC_nobreak">'.$lt{'secret'}.':'.  
                             '<input type="password" size="20" name="lti_secret_'.$i.'" value="" autocomplete="new-password" />'.  
                             '<label><input type="checkbox" name="lti_visible_'.$i.'" id="lti_visible_'.$i.'" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>';  
                     }  
                 }  
                 $datatable .= '<br /><br />'.  
                     '<span class="LC_nobreak">'.$lt{'requser'}.':'.  
                     '<label><input type="radio" name="lti_requser_'.$i.'" value="1"'.$onclickrequser.$checkedrequser{yes}.' />'.&mt('Yes').'</label>&nbsp;'."\n".  
                     '<label><input type="radio" name="lti_requser_'.$i.'" value="0"'.$onclickrequser.$checkedrequser{no}.' />'.&mt('No').'</label></span>'."\n".  
                     '<br /><br />'.  
                     '<span class="LC_nobreak">'.$lt{'crsinc'}.':'.  
                     '<label><input type="radio" name="lti_crsinc_'.$i.'" value="1"'.$onclickcrsinc.$checkedcrsinc{yes}.' />'.&mt('Yes').'</label>&nbsp;'."\n".  
                     '<label><input type="radio" name="lti_crsinc_'.$i.'" value="0"'.$onclickcrsinc.$checkedcrsinc{no}.' />'.&mt('No').'</label></span>'."\n".  
                     ('&nbsp;'x4).  
                     '<input type="hidden" name="lti_id_'.$i.'" value="'.$item.'" /></span>'.  
                     '</fieldset>'.&lti_options($i,$current,$itemcount,%lt).'</td></tr>';  
                 $itemcount ++;  
             }  
         }  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_add'".');"';  
         $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".  
                       '<input type="hidden" name="lti_maxnum" value="'.$maxnum.'" />'."\n".  
                       '<select name="lti_pos_add"'.$chgstr.'>';  
         for (my $k=0; $k<$maxnum+1; $k++) {  
             my $vpos = $k+1;  
             my $selstr;  
             if ($k == $maxnum) {  
                 $selstr = ' selected="selected" ';  
             }  
             $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';  
         }  
         $datatable .= '</select>&nbsp;'."\n".  
                       '<input type="checkbox" name="lti_add" value="1" />'.&mt('Add').'</span></td>'."\n".  
                       '<td colspan="2">'.  
                       '<fieldset><legend>'.&mt('Required settings').'</legend>'.  
                       '<span class="LC_nobreak">'.$lt{'consumer'}.  
                       ':<input type="text" size="15" name="lti_consumer_add" value="" /></span> '."\n".  
                       ('&nbsp;'x2).  
                       '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_add">'.  
                       '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".  
                       ('&nbsp;'x2).  
                       '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="3" name="lti_lifetime_add" value="300" /></span><br /><br />'."\n";  
         if ($switchserver) {  
             $datatable .= '<span class="LC_nobreak">'.&mt('Key and Secret are required').' - '.$switchmessage.'</span>'."\n";  
         } else {  
             $datatable .= '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="lti_key_add" value="" autocomplete="off" /></span> '."\n".  
                           ('&nbsp;'x2).  
                           '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="lti_secret_add" value="" autocomplete="new-password" />'.  
                           '<label><input type="checkbox" name="lti_add_visible" id="lti_add_visible" onclick="if (this.checked) { this.form.lti_secret_add.type='."'text'".' } else { this.form.lti_secret_add.type='."'password'".' }" />'.&mt('Visible input').'</label></span> '."\n";  
         }  
         $datatable .= '<br /><br />'.  
                       '<span class="LC_nobreak">'.$lt{'requser'}.':'.  
                       '<label><input type="radio" name="lti_requser_add" value="1" onclick="toggleLTI(this.form,'."'requser','add'".');" checked="checked" />'.&mt('Yes').'</label>&nbsp;'."\n".  
                       '<label><input type="radio" name="lti_requser_add" value="0" onclick="toggleLTI(this.form,'."'requser','add'".');" />'.&mt('No').'</label></span>'."\n".  
                       '<br /><br />'.  
                       '<span class="LC_nobreak">'.$lt{'crsinc'}.':'.  
                       '<label><input type="radio" name="lti_crsinc_add" value="1" onclick="toggleLTI(this.form,'."'crsinc','add'".');" checked="checked" />'.&mt('Yes').'</label>&nbsp;'."\n".  
                       '<label><input type="radio" name="lti_crsinc_add" value="0" onclick="toggleLTI(this.form,'."'crsinc','add'".');" />'.&mt('No').'</label></span>'."\n".  
                       '</fieldset>'.&lti_options('add',undef,$itemcount,%lt).  
                       '</td>'."\n".  
                       '</tr>'."\n";  
         $itemcount ++;  
     }  
     $$rowtotal += $itemcount;  
     return $datatable;  
 }  
   
 sub lti_names {  
     my %lt = &Apache::lonlocal::texthash(  
                                           'version'   => 'LTI Version',  
                                           'url'       => 'URL',  
                                           'key'       => 'Key',  
                                           'lifetime'  => 'Nonce lifetime (s)',  
                                           'consumer'  => 'Consumer',  
                                           'secret'    => 'Secret',  
                                           'requser'   => "User's identity sent",  
                                           'crsinc'    => "Course's identity sent",  
                                           'email'     => 'Email address',  
                                           'sourcedid' => 'User ID',  
                                           'other'     => 'Other',  
                                           'passback'  => 'Can return grades to Consumer:',  
                                           'roster'    => 'Can retrieve roster from Consumer:',  
                                           'topmenu'   => 'Display LON-CAPA page header',  
                                           'inlinemenu'=> 'Display LON-CAPA inline menu',  
                                         );  
     return %lt;  
 }  
   
 sub lti_options {  
     my ($num,$current,$itemcount,%lt) = @_;  
     my (%checked,%rolemaps,$crssecsrc,$userfield,$cidfield,$callback);  
     $checked{'mapuser'}{'sourcedid'} = ' checked="checked"';  
     $checked{'mapcrs'}{'course_offering_sourcedid'} = ' checked="checked"';  
     $checked{'storecrs'}{'Y'} = ' checked="checked"';  
     $checked{'makecrs'}{'N'} = ' checked="checked"';  
     $checked{'mapcrstype'} = {};  
     $checked{'makeuser'} = {};  
     $checked{'selfenroll'} = {};  
     $checked{'crssec'} = {};  
     $checked{'crssecsrc'} = {};  
     $checked{'lcauth'} = {};  
     $checked{'menuitem'} = {};  
     if ($num eq 'add') {  
         $checked{'lcauth'}{'lti'} = ' checked="checked"';  
     }  
     my $userfieldsty = 'none';  
     my $crsfieldsty = 'none';  
     my $crssecfieldsty = 'none';  
     my $secsrcfieldsty = 'none';  
     my $callbacksty = 'none';  
     my $passbacksty = 'none';  
     my $optionsty = 'block';  
     my $crssty = 'block';  
     my $lcauthparm;  
     my $lcauthparmstyle = 'display:none';  
     my $lcauthparmtext;  
     my $menusty;  
     my $numinrow = 4;  
     my %menutitles = &ltimenu_titles();  
   
     if (ref($current) eq 'HASH') {  
         if (!$current->{'requser'}) {  
             $optionsty = 'none';  
             $crssty = 'none';  
         } elsif (!$current->{'crsinc'}) {  
             $crssty = 'none';  
         }  
         if (($current->{'mapuser'} ne '') && ($current->{'mapuser'} ne 'lis_person_sourcedid')) {  
             $checked{'mapuser'}{'sourcedid'} = '';  
             if ($current->{'mapuser'} eq 'lis_person_contact_email_primary') {  
                 $checked{'mapuser'}{'email'} = ' checked="checked"';  
             } else {  
                 $checked{'mapuser'}{'other'} = ' checked="checked"';  
                 $userfield = $current->{'mapuser'};  
                 $userfieldsty = 'inline-block';  
             }  
         }  
         if (($current->{'mapcrs'} ne '') && ($current->{'mapcrs'} ne 'course_offering_sourcedid')) {  
             $checked{'mapcrs'}{'course_offering_sourcedid'} = '';  
             if ($current->{'mapcrs'} eq 'context_id') {  
                 $checked{'mapcrs'}{'context_id'} = ' checked="checked"';  
             } else {  
                 $checked{'mapcrs'}{'other'} = ' checked="checked"';  
                 $cidfield = $current->{'mapcrs'};  
                 $crsfieldsty = 'inline-block';  
             }  
         }  
         if (ref($current->{'mapcrstype'}) eq 'ARRAY') {  
             foreach my $type (@{$current->{'mapcrstype'}}) {  
                 $checked{'mapcrstype'}{$type} = ' checked="checked"';  
             }  
         }  
         if (!$current->{'storecrs'}) {  
             $checked{'storecrs'}{'N'} = $checked{'storecrs'}{'Y'};  
             $checked{'storecrs'}{'Y'} = '';  
         }  
         if ($current->{'makecrs'}) {  
             $checked{'makecrs'}{'Y'} = '  checked="checked"';  
         }  
         if (ref($current->{'makeuser'}) eq 'ARRAY') {  
             foreach my $role (@{$current->{'makeuser'}}) {  
                 $checked{'makeuser'}{$role} = ' checked="checked"';  
             }  
         }  
         if ($current->{'lcauth'} =~ /^(internal|localauth|krb4|krb5|lti)$/) {  
             $checked{'lcauth'}{$1} = ' checked="checked"';  
             unless (($current->{'lcauth'} eq 'lti') || ($current->{'lcauth'} eq 'internal')) {  
                 $lcauthparm = $current->{'lcauthparm'};  
                 $lcauthparmstyle = 'display:table-row';  
                 if ($current->{'lcauth'} eq 'localauth') {  
                     $lcauthparmtext = &mt('Local auth argument');  
                 } else {  
                     $lcauthparmtext = &mt('Kerberos domain');  
                 }  
             }  
         }  
         if (ref($current->{'selfenroll'}) eq 'ARRAY') {  
             foreach my $role (@{$current->{'selfenroll'}}) {  
                 $checked{'selfenroll'}{$role} = ' checked="checked"';  
             }  
         }  
         if (ref($current->{'maproles'}) eq 'HASH') {  
             %rolemaps = %{$current->{'maproles'}};  
         }  
         if ($current->{'section'} ne '') {  
             $checked{'crssec'}{'Y'} = '  checked="checked"';  
             $crssecfieldsty = 'inline-block';  
             if ($current->{'section'} eq 'course_section_sourcedid') {  
                 $checked{'crssecsrc'}{'sourcedid'} = ' checked="checked"';  
             } else {  
                 $checked{'crssecsrc'}{'other'} = ' checked="checked"';  
                 $crssecsrc = $current->{'section'};  
                 $secsrcfieldsty = 'inline-block';  
             }  
         } else {  
             $checked{'crssec'}{'N'} = ' checked="checked"';  
         }  
         if ($current->{'callback'} ne '') {  
             $callback = $current->{'callback'};  
             $checked{'callback'}{'Y'} = ' checked="checked"';  
             $callbacksty = 'inline-block';  
         } else {  
             $checked{'callback'}{'N'} = ' checked="checked"';  
         }  
         if ($current->{'topmenu'}) {  
             $checked{'topmenu'}{'Y'} = ' checked="checked"';  
         } else {  
             $checked{'topmenu'}{'N'} = ' checked="checked"';  
         }  
         if ($current->{'inlinemenu'}) {  
             $checked{'inlinemenu'}{'Y'} = ' checked="checked"';  
         } else {  
             $checked{'inlinemenu'}{'N'} = ' checked="checked"';  
         }  
         if (($current->{'topmenu'}) || ($current->{'inlinemenu'})) {  
             $menusty = 'inline-block';  
             if (ref($current->{'lcmenu'}) eq 'ARRAY') {  
                 foreach my $item (@{$current->{'lcmenu'}}) {  
                     if (exists($menutitles{$item})) {  
                         $checked{'menuitem'}{$item} = ' checked="checked"';  
                     }  
                 }  
             }  
         } else {  
             $menusty = 'none';  
         }  
     } else {  
         $checked{'makecrs'}{'N'} = ' checked="checked"';  
         $checked{'crssec'}{'N'} = ' checked="checked"';  
         $checked{'callback'}{'N'} = ' checked="checked"';  
         $checked{'topmenu'}{'N'} = ' checked="checked"';  
         $checked{'inlinemenu'}{'Y'} = ' checked="checked"';  
         $checked{'menuitem'}{'grades'} = ' checked="checked"';  
         $menusty = 'inline-block';  
     }  
     my @coursetypes = ('official','unofficial','community','textbook','lti');  
     my %coursetypetitles = &Apache::lonlocal::texthash (  
                                official   => 'Official',  
                                unofficial => 'Unofficial',  
                                community  => 'Community',  
                                textbook   => 'Textbook',  
                                lti        => 'LTI Provider',  
     );  
     my @authtypes = ('internal','krb4','krb5','localauth');  
     my %shortauth = (  
                      internal => 'int',  
                      krb4 => 'krb4',  
                      krb5 => 'krb5',  
                      localauth  => 'loc'  
                     );  
     my %authnames = &authtype_names();  
     my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator);  
     my @lticourseroles = qw(Learner Instructor TeachingAssistant Mentor);  
     my @courseroles = ('cc','in','ta','ep','st');  
     my $onclickuser = ' onclick="toggleLTI(this.form,'."'user','$num'".');"';  
     my $onclickcrs = ' onclick="toggleLTI(this.form,'."'crs','$num'".');"';  
     my $onclicksec = ' onclick="toggleLTI(this.form,'."'sec','$num'".');"';  
     my $onclickcallback = ' onclick="toggleLTI(this.form,'."'callback','$num'".');"';  
     my $onclicksecsrc = ' onclick="toggleLTI(this.form,'."'secsrc','$num'".')"';  
     my $onclicklcauth = ' onclick="toggleLTI(this.form,'."'lcauth','$num'".')"';  
     my $onclickmenu = ' onclick="toggleLTI(this.form,'."'lcmenu','$num'".');"';  
     my $output = '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Logout options').'</legend>'.  
                  '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Callback to logout LON-CAPA on log out from Consumer').':&nbsp;'.  
                  '<label><input type="radio" name="lti_callback_'.$num.'" value="0"'.  
                  $checked{'callback'}{'N'}.$onclickcallback.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                  '<label><input type="radio" name="lti_callback_'.$num.'" value="1"'.  
                  $checked{'callback'}{'Y'}.$onclickcallback.' />'.&mt('Yes').'</label></span></div>'.  
                  '<div class="LC_floatleft" style="display:'.$callbacksty.';" id="lti_callbackfield_'.$num.'">'.  
                  '<span class="LC_nobreak">'.&mt('Parameter').': '.  
                  '<input type="text" name="lti_callbackparam_'.$num.'" value="'.$callback.'" /></span>'.  
                  '</div><div style="padding:0;clear:both;margin:0;border:0"></div></fieldset>'.  
                  '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Mapping users').'</legend>'.  
                  '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('LON-CAPA username').':&nbsp;';  
     foreach my $option ('sourcedid','email','other') {  
         $output .= '<label><input type="radio" name="lti_mapuser_'.$num.'" value="'.$option.'"'.  
                    $checked{'mapuser'}{$option}.$onclickuser.' />'.$lt{$option}.'</label>'.  
                    ($option eq 'other' ? '' : ('&nbsp;'x2) );  
     }  
     $output .= '</span></div>'.  
                '<div class="LC_floatleft" style="display:'.$userfieldsty.';" id="lti_userfield_'.$num.'">'.  
                '<input type="text" name="lti_customuser_'.$num.'" '.  
                'value="'.$userfield.'" /></div></fieldset>'.  
                '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Roles which may create user accounts').'</legend>';  
     foreach my $ltirole (@ltiroles) {  
         $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_makeuser_'.$num.'" value="'.$ltirole.'"'.  
                    $checked{'makeuser'}{$ltirole}.' />'.$ltirole.'</label>&nbsp;</span> ';  
     }  
     $output .= '</fieldset>'.  
                '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('New user accounts created for LTI users').'</legend>'.  
                '<table>'.  
                &modifiable_userdata_row('lti','instdata_'.$num,$current,$numinrow,$itemcount).  
                '</table>'.  
                '<table class="LC_nested"><tr><td class="LC_left_item">LON-CAPA Authentication</td>'.  
                '<td class="LC_left_item">';  
     foreach my $auth ('lti',@authtypes) {  
         my $authtext;  
         if ($auth eq 'lti') {  
             $authtext = &mt('None');  
         } else {  
             $authtext = $authnames{$shortauth{$auth}};  
         }  
         $output .= '<span class="LC_nobreak"><label><input type="radio" name="lti_lcauth_'.$num.  
                    '" value="'.$auth.'"'.$checked{'lcauth'}{$auth}.$onclicklcauth.' />'.  
                    $authtext.'</label></span> &nbsp;';  
     }  
     $output .= '</td></tr>'.  
                '<tr id="lti_lcauth_parmrow_'.$num.'" style="'.$lcauthparmstyle.'">'.  
                '<td class="LC_right_item" colspan="2"><span class="LC_nobreak">'.  
                '<span id="lti_lcauth_parmtext_'.$num.'">'.$lcauthparmtext.'</span>'.  
                '<input type="text" name="lti_lcauthparm_'.$num.'" value="" /></span></td></tr>'.  
                '</table></fieldset>'.  
                '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.  
                &mt('LON-CAPA menu items (Course Coordinator can override)').'</legend>'.  
                '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'topmenu'}.':&nbsp;'.  
                '<label><input type="radio" name="lti_topmenu_'.$num.'" value="0"'.  
                $checked{'topmenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_topmenu_'.$num.'" value="1"'.  
                $checked{'topmenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>'.  
                '<div style="padding:0;clear:both;margin:0;border:0"></div>'.  
                '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'inlinemenu'}.':&nbsp;'.  
                '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="0"'.  
                $checked{'inlinemenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="1"'.  
                $checked{'inlinemenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>';  
      $output .='<div style="padding:0;clear:both;margin:0;border:0"></div>'.  
                '<div class="LC_floatleft" style="display:'.$menusty.';" id="lti_menufield_'.$num.'">'.  
                '<span class="LC_nobreak">'.&mt('Menu items').':&nbsp;';  
     foreach my $type ('fullname','coursetitle','role','logout','grades') {  
         $output .= '<label><input type="checkbox" name="lti_menuitem_'.$num.'" value="'.$type.'"'.  
                    $checked{'menuitem'}{$type}.' />'.$menutitles{$type}.'</label>'.  
                    ('&nbsp;'x2);  
     }  
     $output .= '</span></div></fieldset>'.  
                '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Mapping courses').'</legend>'.  
                '<div class="LC_floatleft"><span class="LC_nobreak">'.  
                &mt('Unique course identifier').':&nbsp;';  
     foreach my $option ('course_offering_sourcedid','context_id','other') {  
         $output .= '<label><input type="radio" name="lti_mapcrs_'.$num.'" value="'.$option.'"'.  
                    $checked{'mapcrs'}{$option}.$onclickcrs.' />'.$option.'</label>'.  
                    ($option eq 'other' ? '' : ('&nbsp;'x2) );  
     }  
     $output .= '</span></div><div class="LC_floatleft" style="display:'.$crsfieldsty.';" id="lti_crsfield_'.$num.'">'.  
                '<input type="text" name="lti_mapcrsfield_'.$num.'" value="'.$cidfield.'" />'.  
                '</div><div style="padding:0;clear:both;margin:0;border:0"></div>'.  
                '<span class="LC_nobreak">'.&mt('LON-CAPA course type(s)').':&nbsp;';  
     foreach my $type (@coursetypes) {  
         $output .= '<label><input type="checkbox" name="lti_mapcrstype_'.$num.'" value="'.$type.'"'.  
                    $checked{'mapcrstype'}{$type}.' />'.$coursetypetitles{$type}.'</label>'.  
                    ('&nbsp;'x2);  
     }  
     $output .= '</span><br /><br />'.  
                '<span class="LC_nobreak">'.&mt('Store mapping of course identifier to LON-CAPA CourseID').':&nbsp;'.  
                '<label><input type="radio" name="lti_storecrs_'.$num.'" value="0"'.  
                $checked{'storecrs'}{'N'}.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_storecrs_'.$num.'" value="1"'.  
                $checked{'storecrs'}{'Y'}.' />'.&mt('Yes').'</label></span>'.  
                '</fieldset>'.  
                '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Mapping course roles').'</legend><table><tr>';  
     foreach my $ltirole (@lticourseroles) {  
         my ($selected,$selectnone);  
         if ($rolemaps{$ltirole} eq '') {  
             $selectnone = ' selected="selected"';  
         }  
         $output .= '<td style="text-align: center">'.$ltirole.'<br />'.  
                    '<select name="lti_maprole_'.$ltirole.'_'.$num.'">'.  
                    '<option value=""'.$selectnone.'>'.&mt('Select').'</option>';  
         foreach my $role (@courseroles) {  
             unless ($selectnone) {  
                 if ($rolemaps{$ltirole} eq $role) {  
                     $selected = ' selected="selected"';  
                 } else {  
                     $selected = '';  
                 }  
             }  
             $output .= '<option value="'.$role.'"'.$selected.'>'.  
                        &Apache::lonnet::plaintext($role,'Course').  
                        '</option>';  
         }  
         $output .= '</select></td>';  
     }  
     $output .= '</tr></table></fieldset>'.  
                '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Creating courses').'</legend>'.  
                '<span class="LC_nobreak">'.&mt('Course created (if absent) on Instructor access').':&nbsp;'.  
                '<label><input type="radio" name="lti_makecrs_'.$num.'" value="0"'.  
                $checked{'makecrs'}{'N'}.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_makecrs_'.$num.'" value="1"'.  
                $checked{'makecrs'}{'Y'}.' />'.&mt('Yes').'</label></span>'.  
                '</fieldset>'.  
                '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Roles which may self-enroll').'</legend>';  
     foreach my $lticrsrole (@lticourseroles) {  
         $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_selfenroll_'.$num.'" value="'.$lticrsrole.'"'.  
                    $checked{'selfenroll'}{$lticrsrole}.' />'.$lticrsrole.'</label>&nbsp;</span> ';  
     }  
     $output .= '</fieldset>'.  
                '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Course options').'</legend>'.  
                '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Assign users to sections').':&nbsp;'.  
                '<label><input type="radio" name="lti_crssec_'.$num.'" value="0"'.  
                $checked{'crssec'}{'N'}.$onclicksec.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_crssec_'.$num.'" value="1"'.  
                $checked{'crssec'}{'Y'}.$onclicksec.' />'.&mt('Yes').'</label></span></div>'.  
                '<div class="LC_floatleft" style="display:'.$crssecfieldsty.';" id="lti_crssecfield_'.$num.'">'.  
                '<span class="LC_nobreak">'.&mt('From').':<label>'.  
                '<input type="radio" name="lti_crssecsrc_'.$num.'" value="course_section_sourcedid"'.  
                $checked{'crssecsrc'}{'sourcedid'}.$onclicksecsrc.' />'.  
                &mt('Standard field').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_crssecsrc_'.$num.'" value="other"'.  
                $checked{'crssecsrc'}{'other'}.$onclicksecsrc.' />'.&mt('Other').  
                '</label></span></div><div class="LC_floatleft" style="display:'.$secsrcfieldsty.';" id="lti_secsrcfield_'.$num.'">'.  
                '<input type="text" name="lti_customsection_'.$num.'" value="'.$crssecsrc.'" />'.  
                '</div><div style="padding:0;clear:both;margin:0;border:0"></div>';  
     my ($pb1p1chk,$pb1p0chk,$onclickpb);  
     foreach my $extra ('roster','passback') {  
         my $checkedon = '';  
         my $checkedoff = ' checked="checked"';  
         if ($extra eq 'passback') {  
             $pb1p1chk = ' checked="checked"';  
             $pb1p0chk = '';  
             $onclickpb = ' onclick="toggleLTI(this.form,'."'passback','$num'".');"';  
         } else {  
             $onclickpb = '';  
         }  
         if (ref($current) eq 'HASH') {  
             if (($current->{$extra})) {  
                 $checkedon = $checkedoff;  
                 $checkedoff = '';  
                 if ($extra eq 'passback') {  
                     $passbacksty = 'inline-block';  
                 }  
                 if ($current->{'passbackformat'} eq '1.0') {  
                     $pb1p0chk =  ' checked="checked"';  
                     $pb1p1chk = '';  
                 }  
             }  
         }  
         $output .= $lt{$extra}.'&nbsp;'.  
                    '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="0"'.$checkedoff.$onclickpb.' />'.  
                    &mt('No').'</label>'.('&nbsp;'x2).  
                    '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="1"'.$checkedon.$onclickpb.' />'.  
                    &mt('Yes').'</label><br />';  
     }  
     $output .= '<div class="LC_floatleft" style="display:'.$passbacksty.';" id="lti_passback_'.$num.'">'.  
                '<span class="LC_nobreak">'.&mt('Grade format').  
                '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.1"'.$pb1p1chk.' />'.  
                &mt('Outcomes Service (1.1)').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.0"'.$pb1p0chk.'/>'.  
                &mt('Outcomes Extension (1.0)').'</label></span></div>'.  
                '<div style="padding:0;clear:both;margin:0;border:0"></div></fieldset>';  
     $output .= '</span></div></fieldset>';  
 #        '<fieldset><legend>'.&mt('Assigning author roles').'</legend>';  
 #  
 #    $output .= '</fieldset>'.  
 #        '<fieldset><legend>'.&mt('Assigning domain roles').'</legend>';  
     return $output;  
 }  
   
 sub ltimenu_titles {  
     return &Apache::lonlocal::texthash(  
                                         fullname    => 'Full name',  
                                         coursetitle => 'Course title',  
                                         role        => 'Role',  
                                         logout      => 'Logout',  
                                         grades      => 'Grades',  
     );  
 }  
   
   
   
 sub print_coursedefaults {  sub print_coursedefaults {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles);      my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles);
     my $itemcount = 1;      my $itemcount = 1;
     my %choices =  &Apache::lonlocal::texthash (      my %choices =  &Apache::lonlocal::texthash (
           canuse_pdfforms      => 'Course/Community users can create/upload PDF forms',
         uploadquota          => 'Default quota for files uploaded directly to course/community using Course Editor (MB)',          uploadquota          => 'Default quota for files uploaded directly to course/community using Course Editor (MB)',
         coursequota          => 'Default cumulative quota for all group portfolio spaces in course',  
         anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys',          anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys',
         coursecredits        => 'Credits can be specified for courses',          coursecredits        => 'Credits can be specified for courses',
         uselcmath            => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)',          uselcmath            => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)',
         usejsme              => 'Molecule editor uses JSME (HTML5) in place of JME (Java)',          usejsme              => 'Molecule editor uses JSME (HTML5) in place of JME (Java)',
         inline_chem          => 'Use inline previewer for chemical reaction response in place of pop-up',  
         texengine            => 'Default method to display mathematics',  
         postsubmit           => 'Disable submit button/keypress following student submission',          postsubmit           => 'Disable submit button/keypress following student submission',
         canclone             => "People who may clone a course (besides course's owner and coordinators)",  
         mysqltables          => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver',  
         ltiauth              => 'Student username in LTI launch of deep-linked URL can be accepted without re-authentication',  
         domexttool           => 'External Tools defined in the domain may be used in courses/communities (by type)',  
         exttool              => 'External Tools can be defined and configured in courses/communities (by type)',  
     );      );
     my %staticdefaults = (      my %staticdefaults = (
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
                            coursequota          => 20,  
                            postsubmit           => 60,                             postsubmit           => 60,
                            mysqltables          => 172800,  
                            domexttool           => 1,  
                            exttool              => 0,  
                          );                           );
     if ($position eq 'top') {      if ($position eq 'top') {
         %defaultchecked = (          %defaultchecked = (
                               'canuse_pdfforms' => 'off',
                             'uselcmath'       => 'on',                              'uselcmath'       => 'on',
                             'usejsme'         => 'on',                              'usejsme'         => 'on',
                             'inline_chem'     => 'on',  
                             'canclone'        => 'none',  
                           );                            );
         @toggles = ('uselcmath','usejsme','inline_chem');          @toggles = ('canuse_pdfforms','uselcmath','usejsme');
         my $deftex = $Apache::lonnet::deftex;  
         if (ref($settings) eq 'HASH') {  
             if ($settings->{'texengine'}) {  
                 if ($settings->{'texengine'} =~ /^(MathJax|mimetex|tth)$/) {  
                     $deftex = $settings->{'texengine'};  
                 }  
             }  
         }  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         my $mathdisp = '<tr'.$css_class.'><td style="vertical-align: top">'.  
                        '<span class="LC_nobreak">'.$choices{'texengine'}.  
                        '</span></td><td class="LC_right_item">'.  
                        '<select name="texengine">'."\n";  
         my %texoptions = (  
                             MathJax  => 'MathJax',  
                             mimetex  => &mt('Convert to Images'),  
                             tth      => &mt('TeX to HTML'),  
                          );  
         foreach my $renderer ('MathJax','mimetex','tth') {  
             my $selected = '';  
             if ($renderer eq $deftex) {  
                 $selected = ' selected="selected"';  
             }  
             $mathdisp .= '<option value="'.$renderer.'"'.$selected.'>'.$texoptions{$renderer}.'</option>'."\n";  
         }  
         $mathdisp .= '</select></td></tr>'."\n";  
         $itemcount ++;  
         ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,          ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
                                                      \%choices,$itemcount);                                                       \%choices,$itemcount);
         $datatable = $mathdisp.$datatable;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .=  
             '<tr'.$css_class.'><td valign="top">'.  
             '<span class="LC_nobreak">'.$choices{'canclone'}.  
             '</span></td><td class="LC_left_item">';  
         my $currcanclone = 'none';  
         my $onclick;  
         my @cloneoptions = ('none','domain');  
         my %clonetitles = &Apache::lonlocal::texthash (  
                              none     => 'No additional course requesters',  
                              domain   => "Any course requester in course's domain",  
                              instcode => 'Course requests for official courses ...',  
                           );  
         my (%codedefaults,@code_order,@posscodes);  
         if (&Apache::lonnet::auto_instcode_defaults($dom,\%codedefaults,  
                                                     \@code_order) eq 'ok') {  
             if (@code_order > 0) {  
                 push(@cloneoptions,'instcode');  
                 $onclick = ' onclick="toggleDisplay(this.form,'."'cloneinstcode'".');"';  
             }  
         }  
         if (ref($settings) eq 'HASH') {  
             if ($settings->{'canclone'}) {  
                 if (ref($settings->{'canclone'}) eq 'HASH') {  
                     if (ref($settings->{'canclone'}{'instcode'}) eq 'ARRAY') {  
                         if (@code_order > 0) {  
                             $currcanclone = 'instcode';  
                             @posscodes = @{$settings->{'canclone'}{'instcode'}};  
                         }  
                     }  
                 } elsif ($settings->{'canclone'} eq 'domain') {  
                     $currcanclone = $settings->{'canclone'};  
                 }  
             }  
         }  
         foreach my $option (@cloneoptions) {  
             my ($checked,$additional);  
             if ($currcanclone eq $option) {  
                 $checked = ' checked="checked"';  
             }  
             if ($option eq 'instcode') {  
                 if (@code_order) {  
                     my $show = 'none';  
                     if ($checked) {  
                         $show = 'block';  
                     }  
                     $additional = '<div id="cloneinstcode" style="display:'.$show.';" />'.  
                                   &mt('Institutional codes for new and cloned course have identical:').  
                                   '<br />';  
                     foreach my $item (@code_order) {  
                         my $codechk;  
                         if ($checked) {  
                             if (grep(/^\Q$item\E$/,@posscodes)) {  
                                 $codechk = ' checked="checked"';  
                             }  
                         }  
                         $additional .= '<label>'.  
                                        '<input type="checkbox" name="clonecode" value="'.$item.'"'.$codechk.' />'.  
                                        $item.'</label>';  
                     }  
                     $additional .= ('&nbsp;'x2).'('.&mt('check as many as needed').')</div>';  
                 }  
             }  
             $datatable .=  
                 '<span class="LC_nobreak"><label><input type="radio" name="canclone"'.$checked.  
                 ' value="'.$option.'"'.$onclick.' />'.$clonetitles{$option}.  
                 '</label>&nbsp;'.$additional.'</span><br />';  
         }  
         $datatable .= '</td>'.  
                       '</tr>';  
         $itemcount ++;  
     } else {      } else {
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';          $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
         my ($currdefresponder,%defcredits,%curruploadquota,%currcoursequota,          my ($currdefresponder,%defcredits,%curruploadquota,%deftimeout);
             %deftimeout,%currmysql);  
         my $currusecredits = 0;          my $currusecredits = 0;
         my $postsubmitclient = 1;          my $postsubmitclient = 1;
         my $ltiauth = 0;  
         my %domexttool;  
         my %exttool;  
         my @types = ('official','unofficial','community','textbook');          my @types = ('official','unofficial','community','textbook');
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ($settings->{'ltiauth'}) {  
                 $ltiauth = 1;  
             }  
             if (ref($settings->{'domexttool'}) eq 'HASH') {  
                 foreach my $type (@types) {  
                     if ($settings->{'domexttool'}->{$type}) {  
                         $domexttool{$type} = ' checked="checked"';  
                     }  
                 }  
             } else {  
                 foreach my $type (@types) {  
                     if ($staticdefaults{'domexttool'}) {  
                         $domexttool{$type} = ' checked="checked"';  
                     }  
                 }  
             }  
             if (ref($settings->{'exttool'}) eq 'HASH') {  
                 foreach my $type (@types) {  
                     if ($settings->{'exttool'}->{$type}) {  
                         $exttool{$type} = ' checked="checked"';  
                     }  
                 }  
             }  
             $currdefresponder = $settings->{'anonsurvey_threshold'};              $currdefresponder = $settings->{'anonsurvey_threshold'};
             if (ref($settings->{'uploadquota'}) eq 'HASH') {              if (ref($settings->{'uploadquota'}) eq 'HASH') {
                 foreach my $type (keys(%{$settings->{'uploadquota'}})) {                  foreach my $type (keys(%{$settings->{'uploadquota'}})) {
                     $curruploadquota{$type} = $settings->{'uploadquota'}{$type};                      $curruploadquota{$type} = $settings->{'uploadquota'}{$type};
                 }                  }
             }              }
             if (ref($settings->{'coursequota'}) eq 'HASH') {  
                 foreach my $type (keys(%{$settings->{'coursequota'}})) {  
                     $currcoursequota{$type} = $settings->{'coursequota'}{$type};  
                 }  
             }  
             if (ref($settings->{'coursecredits'}) eq 'HASH') {              if (ref($settings->{'coursecredits'}) eq 'HASH') {
                 foreach my $type (@types) {                  foreach my $type (@types) {
                     next if ($type eq 'community');                      next if ($type eq 'community');
Line 6115  sub print_coursedefaults { Line 2957  sub print_coursedefaults {
                     foreach my $type (@types) {                      foreach my $type (@types) {
                         if (ref($settings->{'postsubmit'}->{'timeout'}) eq 'HASH') {                          if (ref($settings->{'postsubmit'}->{'timeout'}) eq 'HASH') {
                             if ($settings->{'postsubmit'}->{'timeout'}->{$type} =~ /^\d+$/) {                              if ($settings->{'postsubmit'}->{'timeout'}->{$type} =~ /^\d+$/) {
                                 $deftimeout{$type} = $settings->{'postsubmit'}->{'timeout'}->{$type};                                  $deftimeout{$type} = $settings->{'postsubmit'}->{'timeout'}->{$type}; 
                             } else {                              } else {
                                 $deftimeout{$type} = $staticdefaults{'postsubmit'};                                  $deftimeout{$type} = $staticdefaults{'postsubmit'};
                             }                              }
Line 6129  sub print_coursedefaults { Line 2971  sub print_coursedefaults {
                     $deftimeout{$type} = $staticdefaults{'postsubmit'};                      $deftimeout{$type} = $staticdefaults{'postsubmit'};
                 }                  }
             }              }
             if (ref($settings->{'mysqltables'}) eq 'HASH') {  
                 foreach my $type (keys(%{$settings->{'mysqltables'}})) {  
                     $currmysql{$type} = $settings->{'mysqltables'}{$type};  
                 }  
             } else {  
                 foreach my $type (@types) {  
                     $currmysql{$type} = $staticdefaults{'mysqltables'};  
                 }  
             }  
         } else {          } else {
             foreach my $type (@types) {              foreach my $type (@types) {
                 $deftimeout{$type} = $staticdefaults{'postsubmit'};                  $deftimeout{$type} = $staticdefaults{'postsubmit'};
                 if ($staticdefaults{'domexttool'}) {  
                     $domexttool{$type} = ' checked="checked"';  
                 }  
             }              }
         }          }
         if (!$currdefresponder) {          if (!$currdefresponder) {
Line 6155  sub print_coursedefaults { Line 2985  sub print_coursedefaults {
             if ($curruploadquota{$type} eq '') {              if ($curruploadquota{$type} eq '') {
                 $curruploadquota{$type} = $staticdefaults{'uploadquota'};                  $curruploadquota{$type} = $staticdefaults{'uploadquota'};
             }              }
             if ($currcoursequota{$type} eq '') {  
                 $currcoursequota{$type} = $staticdefaults{'coursequota'};  
             }  
         }          }
         $datatable .=          $datatable .=
                 '<tr'.$css_class.'><td><span class="LC_nobreak">'.                  '<tr'.$css_class.'><td><span class="LC_nobreak">'.
Line 6181  sub print_coursedefaults { Line 3008  sub print_coursedefaults {
         }          }
         $datatable .= '</tr></table></td></tr>'."\n";          $datatable .= '</tr></table></td></tr>'."\n";
         $itemcount ++;          $itemcount ++;
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.  
                       $choices{'coursequota'}.  
                       '</span></td>'.  
                       '<td style="text-align: right" class="LC_right_item">'.  
                       '<table><tr>';  
         foreach my $type (@types) {  
             $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.  
                            '<input type="text" name="coursequota_'.$type.'"'.  
                            ' value="'.$currcoursequota{$type}.'" size="5" /></td>';  
         }  
         $datatable .= '</tr></table></td></tr>'."\n";  
         $itemcount ++;  
         my $onclick = "toggleDisplay(this.form,'credits');";          my $onclick = "toggleDisplay(this.form,'credits');";
         my $display = 'none';          my $display = 'none';
         if ($currusecredits) {          if ($currusecredits) {
Line 6234  sub print_coursedefaults { Line 3048  sub print_coursedefaults {
         $additional .= '</tr></table></div>'."\n";          $additional .= '</tr></table></div>'."\n";
         %defaultchecked = ('postsubmit' => 'on');          %defaultchecked = ('postsubmit' => 'on');
         @toggles = ('postsubmit');          @toggles = ('postsubmit');
         $current = {          my $current = {
                        'postsubmit' => $postsubmitclient,                          'postsubmit' => $postsubmitclient,
                    };                        };
         ($table,$itemcount) =          ($table,$itemcount) =
             &radiobutton_prefs($current,\@toggles,\%defaultchecked,              &radiobutton_prefs($current,\@toggles,\%defaultchecked,
                                \%choices,$itemcount,$onclick,$additional,'left');                                 \%choices,$itemcount,$onclick,$additional,'left');
         $datatable .= $table;          $datatable .= $table;
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.  
                       $choices{'mysqltables'}.  
                       '</span></td>'.  
                       '<td align="right" class="LC_right_item">'.  
                       '<table><tr>';  
         foreach my $type (@types) {  
             $datatable .= '<td align="center">'.&mt($type).'<br />'.  
                            '<input type="text" name="mysqltables_'.$type.'"'.  
                            ' value="'.$currmysql{$type}.'" size="8" /></td>';  
         }  
         $datatable .= '</tr></table></td></tr>'."\n";  
         $itemcount ++;  
         %defaultchecked = ('ltiauth' => 'off');  
         @toggles = ('ltiauth');  
         $current = {  
                        'ltiauth' => $ltiauth,  
                    };  
         ($table,$itemcount) =  
             &radiobutton_prefs($current,\@toggles,\%defaultchecked,  
                                \%choices,$itemcount,undef,undef,'left');  
         $datatable .= $table;  
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.  
                       $choices{'domexttool'}.  
                       '</span></td>'.  
                       '<td style="text-align: right" class="LC_right_item">'.  
                       '<table><tr>';  
         foreach my $type (@types) {  
             $datatable .= '<td style="text-align: left">'.  
                           '<span class="LC_nobreak">'.  
                           '<input type="checkbox" name="domexttool"'.  
                           ' value="'.$type.'"'.$domexttool{$type}.' />'.  
                           &mt($type).'</span></td>'."\n";  
         }  
         $datatable .= '</tr></table></td></tr>'."\n";  
         $itemcount ++;  
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.  
                       $choices{'exttool'}.  
                       '</span></td>'.  
                       '<td style="text-align: right" class="LC_right_item">'.  
                       '<table><tr>';  
         foreach my $type (@types) {  
             $datatable .= '<td style="text-align: left">'.  
                           '<span class="LC_nobreak">'.  
                           '<input type="checkbox" name="exttool"'.  
                           ' value="'.$type.'"'.$exttool{$type}.' />'.  
                           &mt($type).'</span></td>'."\n";  
         }  
         $datatable .= '</tr></table></td></tr>'."\n";  
     }      }
     $$rowtotal += $itemcount;      $$rowtotal += $itemcount;
     return $datatable;      return $datatable;
Line 6485  sub print_validation_rows { Line 3248  sub print_validation_rows {
                               '</label></span> ';                                '</label></span> ';
             }              }
         } elsif ($item eq 'markup') {          } elsif ($item eq 'markup') {
             $datatable .= '<textarea name="'.$caller.'_validation_markup" cols="50" rows="5">'.              $datatable .= '<textarea name="'.$caller.'_validation_markup" cols="50" rows="5" wrap="soft">'.
                            $currvalidation{$item}.                             $currvalidation{$item}.
                               '</textarea>';                                '</textarea>';
         }          }
Line 6507  sub print_validation_rows { Line 3270  sub print_validation_rows {
         my ($numdc,$dctable,$rows) = &active_dc_picker($dom,$numinrow,'radio',          my ($numdc,$dctable,$rows) = &active_dc_picker($dom,$numinrow,'radio',
                                                        'validationdc',%currhash);                                                         'validationdc',%currhash);
         my $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';          my $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
         $datatable .= '<tr'.$css_class.'><td>';          $datatable .= '</td></tr><tr'.$css_class.'><td>';
         if ($numdc > 1) {          if ($numdc > 1) {
             $datatable .= &mt('Course creation processed as: (choose Dom. Coord.)');              $datatable .= &mt('Course creation processed as: (choose Dom. Coord.)');
         } else {          } else {
Line 6522  sub print_validation_rows { Line 3285  sub print_validation_rows {
     return $datatable;      return $datatable;
 }  }
   
 sub print_passwords {  
     my ($position,$dom,$confname,$settings,$rowtotal) = @_;  
     my ($datatable,$css_class);  
     my $itemcount = 0;  
     my %titles = &Apache::lonlocal::texthash (  
         captcha        => '"Forgot Password" CAPTCHA validation',  
         link           => 'Reset link expiration (hours)',  
         case           => 'Case-sensitive usernames/e-mail',  
         prelink        => 'Information required (form 1)',  
         postlink       => 'Information required (form 2)',  
         emailsrc       => 'LON-CAPA e-mail address type(s)',  
         customtext     => 'Domain specific text (HTML)',  
         intauth_cost   => 'Encryption cost for bcrypt (positive integer)',  
         intauth_check  => 'Check bcrypt cost if authenticated',  
         intauth_switch => 'Existing crypt-based switched to bcrypt on authentication',  
         permanent      => 'Permanent e-mail address',  
         critical       => 'Critical notification address',  
         notify         => 'Notification address',  
         min            => 'Minimum password length',  
         max            => 'Maximum password length',  
         chars          => 'Required characters',  
         numsaved       => 'Number of previous passwords to save and disallow reuse',  
     );  
     if ($position eq 'top') {  
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
         my $shownlinklife = 2;  
         my $prelink = 'both';  
         my (%casesens,%postlink,%emailsrc,$nostdtext,$customurl);  
         if (ref($settings) eq 'HASH') {  
             if ($settings->{resetlink} =~ /^\d+(|\.\d*)$/) {  
                 $shownlinklife = $settings->{resetlink};  
             }  
             if (ref($settings->{resetcase}) eq 'ARRAY') {  
                 map { $casesens{$_} = 1; } (@{$settings->{resetcase}});  
             }  
             if ($settings->{resetprelink} =~ /^(both|either)$/) {  
                 $prelink = $settings->{resetprelink};  
             }  
             if (ref($settings->{resetpostlink}) eq 'HASH') {  
                 %postlink = %{$settings->{resetpostlink}};  
             }  
             if (ref($settings->{resetemail}) eq 'ARRAY') {  
                 map { $emailsrc{$_} = 1; } (@{$settings->{resetemail}});  
             }  
             if ($settings->{resetremove}) {  
                 $nostdtext = 1;  
             }  
             if ($settings->{resetcustom}) {  
                 $customurl = $settings->{resetcustom};  
             }  
         } else {  
             if (ref($types) eq 'ARRAY') {  
                 foreach my $item (@{$types}) {  
                     $casesens{$item} = 1;  
                     $postlink{$item} = ['username','email'];  
                 }  
             }  
             $casesens{'default'} = 1;  
             $postlink{'default'} = ['username','email'];  
             $prelink = 'both';  
             %emailsrc = (  
                           permanent => 1,  
                           critical  => 1,  
                           notify    => 1,  
             );  
         }  
         $datatable = &captcha_choice('passwords',$settings,$$rowtotal);  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'link'}.'</td>'.  
                       '<td class="LC_left_item">'.  
                       '<input type="textbox" value="'.$shownlinklife.'" '.  
                       'name="passwords_link" size="3" /></td></tr>';  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'case'}.'</td>'.  
                       '<td class="LC_left_item">';  
         if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {  
             foreach my $item (@{$types}) {  
                 my $checkedcase;  
                 if ($casesens{$item}) {  
                     $checkedcase = ' checked="checked"';  
                 }  
                 $datatable .= '<span class="LC_nobreak"><label>'.  
                               '<input type="checkbox" name="passwords_case_sensitive" value="'.  
                               $item.'"'.$checkedcase.' />'.$usertypes->{$item}.'</label>'.  
                               '</span>&nbsp;&nbsp; ';  
             }  
         }  
         my $checkedcase;  
         if ($casesens{'default'}) {  
             $checkedcase = ' checked="checked"';  
         }  
         $datatable .= '<span class="LC_nobreak"><label><input type="checkbox" '.  
                       'name="passwords_case_sensitive" value="default"'.$checkedcase.' />'.  
                       $othertitle.'</label></span></td>';  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         my %checkedpre = (  
                              both => ' checked="checked"',  
                              either => '',  
                          );  
         if ($prelink eq 'either') {  
             $checkedpre{either} = ' checked="checked"';  
             $checkedpre{both} = '';  
         }  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'prelink'}.'</td>'.  
                       '<td class="LC_left_item"><span class="LC_nobreak">'.  
                       '<label><input type="radio" name="passwords_prelink" value="both"'.$checkedpre{'both'}.' />'.  
                       &mt('Both username and e-mail address').'</label></span>&nbsp;&nbsp; '.  
                       '<span class="LC_nobreak"><label>'.  
                       '<input type="radio" name="passwords_prelink" value="either"'.$checkedpre{'either'}.' />'.  
                       &mt('Either username or e-mail address').'</label></span></td></tr>';  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'postlink'}.'</td>'.  
                       '<td class="LC_left_item">';  
         my %postlinked;  
         if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {  
             foreach my $item (@{$types}) {  
                 undef(%postlinked);  
                 $datatable .= '<fieldset style="display: inline-block;">'.  
                               '<legend>'.$usertypes->{$item}.'</legend>';  
                 if (ref($postlink{$item}) eq 'ARRAY') {  
                     map { $postlinked{$_} = 1; } (@{$postlink{$item}});  
                 }  
                 foreach my $field ('email','username') {  
                     my $checked;  
                     if ($postlinked{$field}) {  
                         $checked = ' checked="checked"';  
                     }  
                     $datatable .= '<span class="LC_nobreak"><label>'.  
                                   '<input type="checkbox" name="passwords_postlink_'.$item.'" value="'.  
                                   $field.'"'.$checked.' />'.$field.'</label>'.  
                                   '<span>&nbsp;&nbsp; ';  
                 }  
                 $datatable .= '</fieldset>';  
             }  
         }  
         if (ref($postlink{'default'}) eq 'ARRAY') {  
             map { $postlinked{$_} = 1; } (@{$postlink{'default'}});  
         }  
         $datatable .= '<fieldset style="display: inline-block;">'.  
                       '<legend>'.$othertitle.'</legend>';  
         foreach my $field ('email','username') {  
             my $checked;  
             if ($postlinked{$field}) {  
                 $checked = ' checked="checked"';  
             }  
             $datatable .= '<span class="LC_nobreak"><label>'.  
                           '<input type="checkbox" name="passwords_postlink_default" value="'.  
                           $field.'"'.$checked.' />'.$field.'</label>'.  
                           '<span>&nbsp;&nbsp; ';  
         }  
         $datatable .= '</fieldset></td></tr>';  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'emailsrc'}.'</td>'.  
                       '<td class="LC_left_item">';  
         foreach my $type ('permanent','critical','notify') {  
             my $checkedemail;  
             if ($emailsrc{$type}) {  
                 $checkedemail = ' checked="checked"';  
             }  
             $datatable .= '<span class="LC_nobreak"><label>'.  
                           '<input type="checkbox" name="passwords_emailsrc" value="'.  
                           $type.'"'.$checkedemail.' />'.$titles{$type}.'</label>'.  
                           '<span>&nbsp;&nbsp; ';  
         }  
         $datatable .= '</td></tr>';  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         my $switchserver = &check_switchserver($dom,$confname);  
         my ($showstd,$noshowstd);  
         if ($nostdtext) {  
             $noshowstd = ' checked="checked"';  
         } else {  
             $showstd = ' checked="checked"';  
         }  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'customtext'}.'</td>'.  
                       '<td class="LC_left_item"><span class="LC_nobreak">'.  
                       &mt('Retain standard text:').  
                       '<label><input type="radio" name="passwords_stdtext" value="1"'.$showstd.' />'.  
                       &mt('Yes').'</label>'.'&nbsp;'.  
                       '<label><input type="radio" name="passwords_stdtext" value="0"'.$noshowstd.' />'.  
                       &mt('No').'</label></span><br />'.  
                       '<span class="LC_fontsize_small">'.  
                       &mt('(If you use the same account ...  reset a password from this page.)').'</span><br /><br />'.  
                       &mt('Include custom text:');  
         if ($customurl) {  
             my $link =  &Apache::loncommon::modal_link($customurl,&mt('custom text'),600,500,  
                                                        undef,undef,undef,undef,'background-color:#ffffff');  
             $datatable .= '<span class="LC_nobreak">&nbsp;'.$link.  
                           '<label><input type="checkbox" name="passwords_custom_del"'.  
                           ' value="1" />'.&mt('Delete?').'</label></span>'.  
                           ' <span class="LC_nobreak">&nbsp;'.&mt('Replace:').'</span>';  
         }  
         if ($switchserver) {  
             $datatable .= '<span class="LC_nobreak">&nbsp;'.&mt('Upload to library server: [_1]',$switchserver).'</span>';  
         } else {  
             $datatable .='<span class="LC_nobreak">&nbsp;'.  
                          '<input type="file" name="passwords_customfile" /></span>';  
         }  
         $datatable .= '</td></tr>';  
     } elsif ($position eq 'middle') {  
         my %domconf = &Apache::lonnet::get_dom('configuration',['defaults'],$dom);  
         my @items = ('intauth_cost','intauth_check','intauth_switch');  
         my %defaults;  
         if (ref($domconf{'defaults'}) eq 'HASH') {  
             %defaults = %{$domconf{'defaults'}};  
             if ($defaults{'intauth_cost'} !~ /^\d+$/) {  
                 $defaults{'intauth_cost'} = 10;  
             }  
             if ($defaults{'intauth_check'} !~ /^(0|1|2)$/) {  
                 $defaults{'intauth_check'} = 0;  
             }  
             if ($defaults{'intauth_switch'} !~ /^(0|1|2)$/) {  
                 $defaults{'intauth_switch'} = 0;  
             }  
         } else {  
             %defaults = (  
                           'intauth_cost'   => 10,  
                           'intauth_check'  => 0,  
                           'intauth_switch' => 0,  
                         );  
         }  
         foreach my $item (@items) {  
             if ($itemcount%2) {  
                 $css_class = '';  
             } else {  
                 $css_class = ' class="LC_odd_row" ';  
             }  
             $datatable .= '<tr'.$css_class.'>'.  
                           '<td><span class="LC_nobreak">'.$titles{$item}.  
                           '</span></td><td class="LC_left_item" colspan="3">';  
             if ($item eq 'intauth_switch') {  
                 my @options = (0,1,2);  
                 my %optiondesc = &Apache::lonlocal::texthash (  
                                    0 => 'No',  
                                    1 => 'Yes',  
                                    2 => 'Yes, and copy existing passwd file to passwd.bak file',  
                                  );  
                 $datatable .= '<table width="100%">';  
                 foreach my $option (@options) {  
                     my $checked = ' ';  
                     if ($defaults{$item} eq $option) {  
                         $checked = ' checked="checked"';  
                     }  
                     $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.  
                                   '<label><input type="radio" name="'.$item.  
                                   '" value="'.$option.'"'.$checked.' />'.  
                                   $optiondesc{$option}.'</label></span></td></tr>';  
                 }  
                 $datatable .= '</table>';  
             } elsif ($item eq 'intauth_check') {  
                 my @options = (0,1,2);  
                 my %optiondesc = &Apache::lonlocal::texthash (  
                                    0 => 'No',  
                                    1 => 'Yes, allow login then update passwd file using default cost (if higher)',  
                                    2 => 'Yes, disallow login if stored cost is less than domain default',  
                                  );  
                 $datatable .= '<table width="100%">';  
                 foreach my $option (@options) {  
                     my $checked = ' ';  
                     my $onclick;  
                     if ($defaults{$item} eq $option) {  
                         $checked = ' checked="checked"';  
                     }  
                     if ($option == 2) {  
                         $onclick = ' onclick="javascript:warnIntAuth(this);"';  
                     }  
                     $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.  
                                   '<label><input type="radio" name="'.$item.  
                                   '" value="'.$option.'"'.$checked.$onclick.' />'.  
                                   $optiondesc{$option}.'</label></span></td></tr>';  
                 }  
                 $datatable .= '</table>';  
             } else {  
                 $datatable .= '<input type="text" name="'.$item.'" value="'.  
                               $defaults{$item}.'" size="3" onblur="javascript:warnIntAuth(this);" />';  
             }  
             $datatable .= '</td></tr>';  
             $itemcount ++;  
         }  
     } elsif ($position eq 'lower') {  
         $datatable .= &password_rules('passwords',\$itemcount,$settings);  
     } else {  
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
         my %ownerchg = (  
                           by  => {},  
                           for => {},  
                        );  
         my %ownertitles = &Apache::lonlocal::texthash (  
                             by  => 'Course owner status(es) allowed',  
                             for => 'Student status(es) allowed',  
                           );  
         if (ref($settings) eq 'HASH') {  
             if (ref($settings->{crsownerchg}) eq 'HASH') {  
                 if (ref($settings->{crsownerchg}{'by'}) eq 'ARRAY') {  
                     map { $ownerchg{by}{$_} = 1; } (@{$settings->{crsownerchg}{'by'}});  
                 }  
                 if (ref($settings->{crsownerchg}{'for'}) eq 'ARRAY') {  
                     map { $ownerchg{for}{$_} = 1; } (@{$settings->{crsownerchg}{'for'}});  
                 }  
             }  
         }  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr '.$css_class.'>'.  
                       '<td>'.  
                       &mt('Requirements').'<ul>'.  
                       '<li>'.&mt("Course 'type' is not a Community").'</li>'.  
                       '<li>'.&mt('User is Course Coordinator and also course owner').'</li>'.  
                       '<li>'.&mt("Student's only active roles are student role(s) in course(s) owned by this user").'</li>'.  
                       '<li>'.&mt('User, course, and student share same domain').'</li>'.  
                       '</ul>'.  
                       '</td>'.  
                       '<td class="LC_left_item">';  
         foreach my $item ('by','for') {  
             $datatable .= '<fieldset style="display: inline-block;">'.  
                           '<legend>'.$ownertitles{$item}.'</legend>';  
             if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {  
                 foreach my $type (@{$types}) {  
                     my $checked;  
                     if ($ownerchg{$item}{$type}) {  
                         $checked = ' checked="checked"';  
                     }  
                     $datatable .= '<span class="LC_nobreak"><label>'.  
                                   '<input type="checkbox" name="passwords_crsowner_'.$item.'" value="'.  
                                   $type.'"'.$checked.' />'.$usertypes->{$type}.'</label>'.  
                                   '</span>&nbsp;&nbsp; ';  
                 }  
             }  
             my $checked;  
             if ($ownerchg{$item}{'default'}) {  
                 $checked = ' checked="checked"';  
             }  
             $datatable .= '<span class="LC_nobreak"><label><input type="checkbox" '.  
                           'name="passwords_crsowner_'.$item.'" value="default"'.$checked.' />'.  
                           $othertitle.'</label></span></fieldset>';  
         }  
         $datatable .= '</td></tr>';  
     }  
     return $datatable;  
 }  
   
 sub password_rules {  
     my ($prefix,$itemcountref,$settings) = @_;  
     my ($min,$max,%chars,$numsaved,$numinrow);  
     my %titles;  
     if ($prefix eq 'passwords') {  
         %titles = &Apache::lonlocal::texthash (  
             min            => 'Minimum password length',  
             max            => 'Maximum password length',  
             chars          => 'Required characters',  
         );  
     } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {  
         %titles = &Apache::lonlocal::texthash (  
             min            => 'Minimum secret length',  
             max            => 'Maximum secret length',  
             chars          => 'Required characters',  
         );  
     }  
     $min = $Apache::lonnet::passwdmin;  
     my $datatable;  
     my $itemcount;  
     if (ref($itemcountref)) {  
         $itemcount = $$itemcountref;  
     }  
     if (ref($settings) eq 'HASH') {  
         if ($settings->{min}) {  
             $min = $settings->{min};  
         }  
         if ($settings->{max}) {  
             $max = $settings->{max};  
         }  
         if (ref($settings->{chars}) eq 'ARRAY') {  
             map { $chars{$_} = 1; } (@{$settings->{chars}});  
         }  
         if ($prefix eq 'passwords') {  
             if ($settings->{numsaved}) {  
                 $numsaved = $settings->{numsaved};  
             }  
         }  
     }  
     my %rulenames = &Apache::lonlocal::texthash(  
                                                  uc => 'At least one upper case letter',  
                                                  lc => 'At least one lower case letter',  
                                                  num => 'At least one number',  
                                                  spec => 'At least one non-alphanumeric',  
                                                );  
     my $css_class = $itemcount%2?' class="LC_odd_row"':'';  
     $datatable .= '<tr'.$css_class.'><td>'.$titles{'min'}.'</td>'.  
                   '<td class="LC_left_item"><span class="LC_nobreak">'.  
                   '<input type="text" name="'.$prefix.'_min" value="'.$min.'" size="3" '.  
                   'onblur="javascript:warnInt'.$prefix.'(this);" />'.  
                   '<span class="LC_fontsize_small"> '.&mt('(Enter an integer: 7 or larger)').'</span>'.  
                   '</span></td></tr>';  
     $itemcount ++;  
     $css_class = $itemcount%2?' class="LC_odd_row"':'';  
     $datatable .= '<tr'.$css_class.'><td>'.$titles{'max'}.'</td>'.  
                   '<td class="LC_left_item"><span class="LC_nobreak">'.  
                   '<input type="text" name="'.$prefix.'_max" value="'.$max.'" size="3" '.  
                   'onblur="javascript:warnInt'.$prefix.'(this);" />'.  
                   '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no maximum)').'</span>'.  
                   '</span></td></tr>';  
     $itemcount ++;  
     $css_class = $itemcount%2?' class="LC_odd_row"':'';  
     $datatable .= '<tr'.$css_class.'><td>'.$titles{'chars'}.'<br />'.  
                   '<span class="LC_nobreak LC_fontsize_small">'.&mt('(Leave unchecked if not required)').  
                   '</span></td>';  
     my $numinrow = 2;  
     my @possrules = ('uc','lc','num','spec');  
     $datatable .= '<td class="LC_left_item"><table>';  
     for (my $i=0; $i<@possrules; $i++) {  
         my ($rem,$checked);  
         if ($chars{$possrules[$i]}) {  
             $checked = ' checked="checked"';  
         }  
         $rem = $i%($numinrow);  
         if ($rem == 0) {  
             if ($i > 0) {  
                 $datatable .= '</tr>';  
             }  
             $datatable .= '<tr>';  
         }  
         $datatable .= '<td><span class="LC_nobreak"><label>'.  
                       '<input type="checkbox" name="'.$prefix.'_chars" value="'.$possrules[$i].'"'.$checked.' />'.  
                       $rulenames{$possrules[$i]}.'</label></span></td>';  
     }  
     my $rem = @possrules%($numinrow);  
     my $colsleft = $numinrow - $rem;  
     if ($colsleft > 1 ) {  
         $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.  
                       '&nbsp;</td>';  
     } elsif ($colsleft == 1) {  
         $datatable .= '<td class="LC_left_item">&nbsp;</td>';  
     }  
     $datatable .='</table></td></tr>';  
     $itemcount ++;  
     if ($prefix eq 'passwords') {  
         $titles{'numsaved'} = &mt('Number of previous passwords to save and disallow reuse');  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'numsaved'}.'</td>'.  
                       '<td class="LC_left_item"><span class="LC_nobreak">'.  
                       '<input type="text" name="'.$prefix.'_numsaved" value="'.$numsaved.'" size="3" '.  
                       'onblur="javascript:warnInt'.$prefix.'(this);" />'.  
                       '<span class="LC_fontsize_small"> '.&mt('(Leave blank to not save previous passwords)').'</span>'.  
                       '</span></td></tr>';  
         $itemcount ++;  
     }  
     if (ref($itemcountref)) {  
         $$itemcountref += $itemcount;  
     }  
     return $datatable;  
 }  
   
 sub print_wafproxy {  
     my ($position,$dom,$settings,$rowtotal) = @_;  
     my $css_class;  
     my $itemcount = 0;  
     my $datatable;  
     my %servers = &Apache::lonnet::internet_dom_servers($dom);  
     my (%othercontrol,%otherdoms,%aliases,%saml,%values,$setdom,$showdom);  
     my %lt = &wafproxy_titles();  
     foreach my $server (sort(keys(%servers))) {  
         my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});  
         next if ($serverhome eq '');  
         my $serverdom;  
         if ($serverhome ne $server) {  
             $serverdom = &Apache::lonnet::host_domain($serverhome);  
             if (($serverdom ne '') && (&Apache::lonnet::domain($serverdom) ne '')) {  
                 $othercontrol{$server} = $serverdom;  
             }  
         } else {  
             $serverdom = &Apache::lonnet::host_domain($server);  
             next if (($serverdom eq '') || (&Apache::lonnet::domain($serverdom) eq ''));  
             if ($serverdom ne $dom) {  
                 $othercontrol{$server} = $serverdom;  
             } else {  
                 $setdom = 1;  
                 if (ref($settings) eq 'HASH') {  
                     if (ref($settings->{'alias'}) eq 'HASH') {  
                         $aliases{$dom} = $settings->{'alias'};  
                         if ($aliases{$dom} ne '') {  
                             $showdom = 1;  
                         }  
                     }  
                     if (ref($settings->{'saml'}) eq 'HASH') {  
                         $saml{$dom} = $settings->{'saml'};  
                     }  
                 }  
             }  
         }  
     }  
     if ($setdom) {  
         %{$values{$dom}} = ();  
         if (ref($settings) eq 'HASH') {  
             foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') {  
                 $values{$dom}{$item} = $settings->{$item};  
             }  
         }  
     }  
     if (keys(%othercontrol)) {  
         %otherdoms = reverse(%othercontrol);  
         foreach my $domain (keys(%otherdoms)) {  
             %{$values{$domain}} = ();  
             my %config = &Apache::lonnet::get_dom('configuration',['wafproxy'],$domain);  
             if (ref($config{'wafproxy'}) eq 'HASH') {  
                 $aliases{$domain} = $config{'wafproxy'}{'alias'};  
                 if (exists($config{'wafproxy'}{'saml'})) {  
                     $saml{$domain} = $config{'wafproxy'}{'saml'};  
                 }  
                 foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') {  
                     $values{$domain}{$item} = $config{'wafproxy'}{$item};  
                 }  
             }  
         }  
     }  
     if ($position eq 'top') {  
         my %servers = &Apache::lonnet::internet_dom_servers($dom);  
         my %aliasinfo;  
         foreach my $server (sort(keys(%servers))) {  
             $itemcount ++;  
             my $dom_in_effect;  
             my $aliasrows = '<tr>'.  
                             '<td class="LC_left_item" style="vertical-align: baseline;">'.  
                             &mt('Hostname').':&nbsp;'.  
                             '<span class="LC_nobreak LC_cusr_emph">'.  
                             &Apache::lonnet::hostname($server).'</span></td><td>&nbsp;</td>';  
             if ($othercontrol{$server}) {  
                 $dom_in_effect = $othercontrol{$server};  
                 my ($current,$forsaml);  
                 if (ref($aliases{$dom_in_effect}) eq 'HASH') {  
                     $current = $aliases{$dom_in_effect}{$server};  
                 }  
                 if (ref($saml{$dom_in_effect}) eq 'HASH') {  
                     if ($saml{$dom_in_effect}{$server}) {  
                         $forsaml = 1;  
                     }  
                 }  
                 $aliasrows .= '<td class="LC_left_item" style="vertical-align: baseline;">'.  
                               &mt('Alias').':&nbsp';  
                 if ($current) {  
                     $aliasrows .= $current;  
                     if ($forsaml) {  
                          $aliasrows .= '&nbsp;('.&mt('also for SSO Auth').')';  
                     }  
                 } else {  
                     $aliasrows .= &mt('None');  
                 }  
                 $aliasrows .= '&nbsp;<span class="LC_small">('.  
                               &mt('controlled by domain: [_1]',  
                                   '<b>'.$dom_in_effect.'</b>').')</span></td>';  
             } else {  
                 $dom_in_effect = $dom;  
                 my ($current,$samlon,$samloff);  
                 $samloff = ' checked="checked"';  
                 if (ref($aliases{$dom}) eq 'HASH') {  
                     if ($aliases{$dom}{$server}) {  
                         $current = $aliases{$dom}{$server};  
                     }  
                 }  
                 if (ref($saml{$dom}) eq 'HASH') {  
                     if ($saml{$dom}{$server}) {  
                         $samlon = $samloff;  
                         undef($samloff);  
                     }  
                 }  
                 $aliasrows .= '<td class="LC_left_item" style="vertical-align: baseline;">'.  
                               &mt('Alias').':&nbsp;'.  
                               '<input type="text" name="wafproxy_alias_'.$server.'" '.  
                               'value="'.$current.'" size="30" />'.  
                               ('&nbsp;'x2).'<span class="LC_nobreak">'.  
                               &mt('Alias used for SSO Auth').':&nbsp;<label>'.  
                               '<input type="radio" value="0"'.$samloff.' name="wafproxy_alias_saml_'.$server.'" />'.  
                               &mt('No').'</label>&nbsp;<label>'.  
                               '<input type="radio" value="1"'.$samlon.' name="wafproxy_alias_saml_'.$server.'" />'.  
                               &mt('Yes').'</label></span>'.  
                               '</td>';  
             }  
             $aliasrows .= '</tr>';  
             $aliasinfo{$dom_in_effect} .= $aliasrows;  
         }  
         if ($aliasinfo{$dom}) {  
             my ($onclick,$wafon,$wafoff,$showtable);  
             $onclick = ' onclick="javascript:toggleWAF();"';  
             $wafoff = ' checked="checked"';  
             $showtable = ' style="display:none";';  
             if ($showdom) {  
                 $wafon = $wafoff;  
                 $wafoff = '';  
                 $showtable = ' style="display:inline;"';  
             }  
             $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
             $datatable = '<tr'.$css_class.'>'.  
                          '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'<br />'.  
                          '<span class="LC_nobreak">'.&mt('WAF in use?').'&nbsp;<label>'.  
                          '<input type="radio" name="wafproxy_'.$dom.'" value="1"'.$wafon.$onclick.' />'.  
                          &mt('Yes').'</label>'.('&nbsp;'x2).'<label>'.  
                          '<input type="radio" name="wafproxy_'.$dom.'" value="0"'.$wafoff.$onclick.' />'.  
                          &mt('No').'</label></span></td>'.  
                          '<td class="LC_left_item">'.  
                          '<table id="wafproxy_table"'.$showtable.'>'.$aliasinfo{$dom}.  
                          '</table></td></tr>';  
             $itemcount++;  
         }  
         if (keys(%otherdoms)) {  
             foreach my $key (sort(keys(%otherdoms))) {  
                 $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
                 $datatable .= '<tr'.$css_class.'>'.  
                               '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$key.'</b>').'</td>'.  
                               '<td class="LC_left_item"><table>'.$aliasinfo{$key}.  
                               '</table></td></tr>';  
                 $itemcount++;  
             }  
         }  
     } else {  
         my %ip_methods = &remoteip_methods();  
         if ($setdom) {  
             $itemcount ++;  
             $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
             my ($nowafstyle,$wafstyle,$curr_remotip,$currwafdisplay,$vpndircheck,$vpnaliascheck,  
                 $currwafvpn,$wafrangestyle,$alltossl,$ssltossl);  
             $wafstyle = ' style="display:none;"';  
             $nowafstyle = ' style="display:table-row;"';  
             $currwafdisplay = ' style="display: none"';  
             $wafrangestyle = ' style="display: none"';  
             $curr_remotip = 'n';  
             $ssltossl = ' checked="checked"';  
             if ($showdom) {  
                 $wafstyle = ' style="display:table-row;"';  
                 $nowafstyle =  ' style="display:none;"';  
                 if (keys(%{$values{$dom}})) {  
                     if ($values{$dom}{remoteip} =~ /^[nmh]$/) {  
                         $curr_remotip = $values{$dom}{remoteip};  
                     }  
                     if ($curr_remotip eq 'h') {  
                         $currwafdisplay = ' style="display:table-row"';  
                         $wafrangestyle = ' style="display:inline-block;"';  
                     }  
                     if ($values{$dom}{'sslopt'}) {  
                         $alltossl = ' checked="checked"';  
                         $ssltossl = '';  
                     }  
                 }  
                 if (($values{$dom}{'vpnint'} ne '') || ($values{$dom}{'vpnext'} ne '')) {  
                     $vpndircheck = ' checked="checked"';  
                     $currwafvpn = ' style="display:table-row;"';  
                     $wafrangestyle = ' style="display:inline-block;"';  
                 } else {  
                     $vpnaliascheck = ' checked="checked"';  
                     $currwafvpn = ' style="display:none;"';  
                 }  
             }  
             $datatable .= '<tr'.$css_class.' id="nowafproxyrow_'.$dom.'"'.$wafstyle.'>'.  
                           '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'</td>'.  
                           '<td class="LC_right_item">'.&mt('WAF not in use, nothing to set').'</td>'.  
                           '</tr>'.  
                           '<tr'.$css_class.' id="wafproxyrow_'.$dom.'"'.$wafstyle.'>'.  
                           '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'<br /><br />'.  
                           '<div id="wafproxyranges_'.$dom.'">'.&mt('Format for comma separated IP ranges').':<br />'.  
                           &mt('A.B.C.D/N or A.B.C.D-E.F.G.H').'<br />'.  
                           &mt('Range(s) stored in CIDR notation').'</div></td>'.  
                           '<td class="LC_left_item"><table>'.  
                           '<tr>'.  
                           '<td valign="top">'.$lt{'remoteip'}.':&nbsp;'.  
                           '<select name="wafproxy_remoteip" id="wafproxy_remoteip" onchange="javascript:updateWAF();">';  
             foreach my $option ('m','h','n') {  
                 my $sel;  
                 if ($option eq $curr_remotip) {  
                    $sel = ' selected="selected"';  
                 }  
                 $datatable .= '<option value="'.$option.'"'.$sel.'>'.  
                               $ip_methods{$option}.'</option>';  
             }  
             $datatable .= '</select></td></tr>'."\n".  
                           '<tr id="wafproxy_header"'.$currwafdisplay.'><td>'.  
                           $lt{'ipheader'}.':&nbsp;'.  
                           '<input type="text" value="'.$values{$dom}{'ipheader'}.'" '.  
                           'name="wafproxy_ipheader" />'.  
                           '</td></tr>'."\n".  
                           '<tr id="wafproxy_trust"'.$currwafdisplay.'><td>'.  
                           $lt{'trusted'}.':<br />'.  
                           '<textarea name="wafproxy_trusted" rows="3" cols="80">'.  
                           $values{$dom}{'trusted'}.'</textarea>'.  
                           '</td></tr>'."\n".  
                           '<tr><td><hr /></td></tr>'."\n".  
                           '<tr>'.  
                           '<td valign="top">'.$lt{'vpnaccess'}.':<br /><span class="LC_nobreak">'.  
                           '<label><input type="radio" name="wafproxy_vpnaccess"'.$vpndircheck.' value="1" onclick="javascript:checkWAF();" />'.  
                           $lt{'vpndirect'}.'</label>'.('&nbsp;'x2).  
                           '<label><input type="radio" name="wafproxy_vpnaccess"'.$vpnaliascheck.' value="0" onclick="javascript:checkWAF();" />'.  
                           $lt{'vpnaliased'}.'</label></span></td></tr>';  
             foreach my $item ('vpnint','vpnext') {  
                 $datatable .= '<tr id="wafproxy_show_'.$item.'"'.$currwafvpn.'>'.  
                               '<td valign="top">'.$lt{$item}.':<br />'.  
                               '<textarea name="wafproxy_'.$item.'" rows="3" cols="80">'.  
                               $values{$dom}{$item}.'</textarea>'.  
                               '</td></tr>'."\n";  
             }  
             $datatable .= '<tr><td><hr /></td></tr>'."\n".  
                           '<tr>'.  
                           '<td valign="top">'.$lt{'sslopt'}.':<br /><span class="LC_nobreak">'.  
                           '<label><input type="radio" name="wafproxy_sslopt"'.$alltossl.' value="1" />'.  
                           $lt{'alltossl'}.'</label>'.('&nbsp;'x2).  
                           '<label><input type="radio" name="wafproxy_sslopt"'.$ssltossl.' value="0" />'.  
                           $lt{'ssltossl'}.'</label></span></td></tr>'."\n".  
                           '</table></td></tr>';  
         }  
         if (keys(%otherdoms)) {  
             foreach my $domain (sort(keys(%otherdoms))) {  
                 $itemcount ++;  
                 $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
                 $datatable .= '<tr'.$css_class.'>'.  
                               '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$domain.'</b>').'</td>'.  
                               '<td class="LC_left_item"><table>';  
                 foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext','sslopt') {  
                     my $showval = &mt('None');  
                     if ($item eq 'ssl') {  
                         $showval = $lt{'ssltossl'};  
                     }  
                     if ($values{$domain}{$item}) {  
                         $showval = $values{$domain}{$item};  
                         if ($item eq 'ssl') {  
                             $showval = $lt{'alltossl'};  
                         } elsif ($item eq 'remoteip') {  
                             $showval = $ip_methods{$values{$domain}{$item}};  
                         }  
                     }  
                     $datatable .= '<tr>'.  
                                   '<td>'.$lt{$item}.':&nbsp;'.$showval.'</td></tr>';  
                 }  
                 $datatable .= '</table></td></tr>';  
             }  
         }  
     }  
     $$rowtotal += $itemcount;  
     return $datatable;  
 }  
   
 sub wafproxy_titles {  
     return &Apache::lonlocal::texthash(  
                remoteip   => "Method for determining user's IP",  
                ipheader   => 'Request header containing remote IP',  
                trusted    => 'Trusted IP range(s)',  
                vpnaccess  => 'Access from institutional VPN',  
                vpndirect  => 'via regular hostname (no WAF)',  
                vpnaliased => 'via aliased hostname (WAF)',  
                vpnint     => 'Internal IP Range(s) for VPN sessions',  
                vpnext     => 'IP Range(s) for backend WAF connections',  
                sslopt     => 'Forwarding http/https',  
                alltossl   => 'WAF forwards both http and https requests to https',  
                ssltossl   => 'WAF forwards http requests to http and https to https',  
            );  
 }  
   
 sub remoteip_methods {  
     return &Apache::lonlocal::texthash(  
               m => 'Use Apache mod_remoteip',  
               h => 'Use headers parsed by LON-CAPA',  
               n => 'Not in use',  
            );  
 }  
   
 sub print_usersessions {  sub print_usersessions {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable,%checked,%choices);      my ($css_class,$datatable,%checked,%choices);
Line 7300  sub print_usersessions { Line 3299  sub print_usersessions {
     if ($position eq 'top') {      if ($position eq 'top') {
         if (keys(%serverhomes) > 1) {          if (keys(%serverhomes) > 1) {
             my %spareid = &current_offloads_to($dom,$settings,\%servers);              my %spareid = &current_offloads_to($dom,$settings,\%servers);
             my ($curroffloadnow,$curroffloadoth);              $datatable .= &spares_row($dom,\%servers,\%spareid,\%serverhomes,\%altids,$rowtotal);
             if (ref($settings) eq 'HASH') {  
                 if (ref($settings->{'offloadnow'}) eq 'HASH') {  
                     $curroffloadnow = $settings->{'offloadnow'};  
                 }  
                 if (ref($settings->{'offloadoth'}) eq 'HASH') {  
                     $curroffloadoth = $settings->{'offloadoth'};  
                 }  
             }  
             my $other_insts = scalar(keys(%by_location));  
             $datatable .= &spares_row($dom,\%servers,\%spareid,\%serverhomes,\%altids,  
                                       $other_insts,$curroffloadnow,$curroffloadoth,$rowtotal);  
         } else {          } else {
             $datatable .= '<tr'.$css_class.'><td colspan="2">'.              $datatable .= '<tr'.$css_class.'><td colspan="2">'.
                           &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.').                            &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.');
                           '</td></tr>';  
         }          }
     } else {      } else {
         if (keys(%by_location) == 0) {          if (keys(%by_location) == 0) {
             $datatable .= '<tr'.$css_class.'><td colspan="2">'.              $datatable .= '<tr'.$css_class.'><td colspan="2">'.
                           &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.').                            &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.');
                           '</td></tr>';  
         } else {          } else {
             my %lt = &usersession_titles();              my %lt = &usersession_titles();
             my $numinrow = 5;              my $numinrow = 5;
Line 7563  sub current_offloads_to { Line 3549  sub current_offloads_to {
 }  }
   
 sub spares_row {  sub spares_row {
     my ($dom,$servers,$spareid,$serverhomes,$altids,$other_insts,      my ($dom,$servers,$spareid,$serverhomes,$altids,$rowtotal) = @_;
         $curroffloadnow,$curroffloadoth,$rowtotal) = @_;  
     my $css_class;      my $css_class;
     my $numinrow = 4;      my $numinrow = 4;
     my $itemcount = 1;      my $itemcount = 1;
Line 7584  sub spares_row { Line 3569  sub spares_row {
                 }                  }
             }              }
             next unless (ref($spareid->{$server}) eq 'HASH');              next unless (ref($spareid->{$server}) eq 'HASH');
             my ($checkednow,$checkedoth);  
             if (ref($curroffloadnow) eq 'HASH') {  
                 if ($curroffloadnow->{$server}) {  
                     $checkednow = ' checked="checked"';  
                 }  
             }  
             if (ref($curroffloadoth) eq 'HASH') {  
                 if ($curroffloadoth->{$server}) {  
                     $checkedoth = ' checked="checked"';  
                 }  
             }  
             $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';              $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
             $datatable .= '<tr'.$css_class.'>              $datatable .= '<tr'.$css_class.'>
                            <td rowspan="2">                             <td rowspan="2">
                             <span class="LC_nobreak">'.                              <span class="LC_nobreak">'.
                           &mt('[_1] when busy, offloads to:'                            &mt('[_1] when busy, offloads to:'
                               ,'<b>'.$server.'</b>').'</span><br />'.                                ,'<b>'.$server.'</b>').
                           '<span class="LC_nobreak">'."\n".  
                           '<label><input type="checkbox" name="offloadnow" value="'.$server.'"'.$checkednow.' />'.  
                           '&nbsp;'.&mt('Switch any active user on next access').'</label></span>'.  
                           "\n";  
             if ($other_insts) {  
                 $datatable .= '<br />'.  
                               '<span class="LC_nobreak">'."\n".  
                           '<label><input type="checkbox" name="offloadoth" value="'.$server.'"'.$checkedoth.' />'.  
                           '&nbsp;'.&mt('Switch other institutions on next access').'</label></span>'.  
                           "\n";                            "\n";
             }  
             my (%current,%canselect);              my (%current,%canselect);
             my @choices =               my @choices = 
                 &possible_newspares($server,$spareid->{$server},$serverhomes,$altids);                  &possible_newspares($server,$spareid->{$server},$serverhomes,$altids);
Line 7735  sub print_loadbalancing { Line 3699  sub print_loadbalancing {
     my $numinrow = 1;      my $numinrow = 1;
     my $datatable;      my $datatable;
     my %servers = &Apache::lonnet::internet_dom_servers($dom);      my %servers = &Apache::lonnet::internet_dom_servers($dom);
     my (%currbalancer,%currtargets,%currrules,%existing,%currcookies);      my (%currbalancer,%currtargets,%currrules,%existing);
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         %existing = %{$settings};          %existing = %{$settings};
     }      }
     if ((keys(%servers) > 1) || (keys(%existing) > 0)) {      if ((keys(%servers) > 1) || (keys(%existing) > 0)) {
         &get_loadbalancers_config(\%servers,\%existing,\%currbalancer,          &get_loadbalancers_config(\%servers,\%existing,\%currbalancer,
                                   \%currtargets,\%currrules,\%currcookies);                                    \%currtargets,\%currrules);
     } else {      } else {
         return;          return;
     }      }
Line 7815  sub print_loadbalancing { Line 3779  sub print_loadbalancing {
         my ($numspares,@spares) = &count_servers($lonhost,%servers);          my ($numspares,@spares) = &count_servers($lonhost,%servers);
         my @sparestypes = ('primary','default');          my @sparestypes = ('primary','default');
         my %typetitles = &sparestype_titles();          my %typetitles = &sparestype_titles();
         my %hostherechecked = (  
                                   no => ' checked="checked"',  
                               );  
         my %balcookiechecked = (  
                                   no => ' checked="checked"',  
                                );  
         foreach my $sparetype (@sparestypes) {          foreach my $sparetype (@sparestypes) {
             my $targettable;              my $targettable;
             for (my $i=0; $i<$numspares; $i++) {              for (my $i=0; $i<$numspares; $i++) {
Line 7866  sub print_loadbalancing { Line 3824  sub print_loadbalancing {
                 $datatable .=  '<i>'.$typetitles{$sparetype}.'</i><br />'.                  $datatable .=  '<i>'.$typetitles{$sparetype}.'</i><br />'.
                                '<table><tr>'.$targettable.'</tr></table><br />';                                 '<table><tr>'.$targettable.'</tr></table><br />';
             }              }
             $hostherechecked{$sparetype} = '';  
             if (ref($currtargets{$lonhost}) eq 'HASH') {  
                 if (ref($currtargets{$lonhost}{$sparetype}) eq 'ARRAY') {  
                     if (grep(/^\Q$lonhost\E$/,@{$currtargets{$lonhost}{$sparetype}})) {  
                         $hostherechecked{$sparetype} = ' checked="checked"';  
                         $hostherechecked{'no'} = '';  
                     }  
                 }  
             }  
         }  
         if ($currcookies{$lonhost}) {  
             %balcookiechecked = (  
                                     yes => ' checked="checked"',  
                                 );  
         }          }
         $datatable .= &mt('Hosting on balancer itself').'<br />'.          $datatable .= '</div></td></tr>'.
                       '<label><input type="radio" name="loadbalancing_target_'.$balnum.'_hosthere" value="no"'.  
                       $hostherechecked{'no'}.' />'.&mt('No').'</label><br />';  
         foreach my $sparetype (@sparestypes) {  
             $datatable .= '<label><input type="radio" name="loadbalancing_target_'.$balnum.'_hosthere" '.  
                           'value="'.$sparetype.'"'.$hostherechecked{$sparetype}.' /><i>'.$typetitles{$sparetype}.  
                           '</i></label><br />';  
         }  
         $datatable .= &mt('Use balancer cookie').'<br />'.  
                       '<label><input type="radio" name="loadbalancing_cookie_'.$balnum.'" value="1"'.  
                       $balcookiechecked{'yes'}.' />'.&mt('Yes').'</label><br />'.  
                       '<label><input type="radio" name="loadbalancing_cookie_'.$balnum.'" value="0"'.  
                       $balcookiechecked{'no'}.' />'.&mt('No').'</label><br />'.  
                       '</div></td></tr>'.  
                       &loadbalancing_rules($dom,$intdom,$currrules{$lonhost},                        &loadbalancing_rules($dom,$intdom,$currrules{$lonhost},
                                            $othertitle,$usertypes,$types,\%servers,                                             $othertitle,$usertypes,$types,\%servers,
                                            \%currbalancer,$lonhost,                                             \%currbalancer,$lonhost,
Line 7908  sub print_loadbalancing { Line 3839  sub print_loadbalancing {
 }  }
   
 sub get_loadbalancers_config {  sub get_loadbalancers_config {
     my ($servers,$existing,$currbalancer,$currtargets,$currrules,$currcookies) = @_;      my ($servers,$existing,$currbalancer,$currtargets,$currrules) = @_;
     return unless ((ref($servers) eq 'HASH') &&      return unless ((ref($servers) eq 'HASH') &&
                    (ref($existing) eq 'HASH') && (ref($currbalancer) eq 'HASH') &&                     (ref($existing) eq 'HASH') && (ref($currbalancer) eq 'HASH') &&
                    (ref($currtargets) eq 'HASH') && (ref($currrules) eq 'HASH') &&                     (ref($currtargets) eq 'HASH') && (ref($currrules) eq 'HASH'));
                    (ref($currcookies) eq 'HASH'));  
     if (keys(%{$existing}) > 0) {      if (keys(%{$existing}) > 0) {
         my $oldlonhost;          my $oldlonhost;
         foreach my $key (sort(keys(%{$existing}))) {          foreach my $key (sort(keys(%{$existing}))) {
Line 7931  sub get_loadbalancers_config { Line 3861  sub get_loadbalancers_config {
                 $currbalancer->{$key} = 1;                  $currbalancer->{$key} = 1;
                 $currtargets->{$key} = $existing->{$key}{'targets'};                  $currtargets->{$key} = $existing->{$key}{'targets'};
                 $currrules->{$key} = $existing->{$key}{'rules'};                  $currrules->{$key} = $existing->{$key}{'rules'};
                 if ($existing->{$key}{'cookie'}) {  
                     $currcookies->{$key} = 1;  
                 }  
             }              }
         }          }
     } else {      } else {
Line 7989  sub loadbalancing_titles { Line 3916  sub loadbalancing_titles {
            '_LC_ipchange'    => &mt('Non-SSO users with IP mismatch'),             '_LC_ipchange'    => &mt('Non-SSO users with IP mismatch'),
                      );                       );
     my @alltypes = ('_LC_adv','_LC_author','_LC_internetdom','_LC_external','_LC_ipchangesso','_LC_ipchange');      my @alltypes = ('_LC_adv','_LC_author','_LC_internetdom','_LC_external','_LC_ipchangesso','_LC_ipchange');
     my @available;  
     if (ref($types) eq 'ARRAY') {      if (ref($types) eq 'ARRAY') {
         @available = @{$types};          unshift(@alltypes,@{$types},'default');
     }  
     unless (grep(/^default$/,@available)) {  
         push(@available,'default');  
     }      }
     unshift(@alltypes,@available);  
     my %titles;      my %titles;
     foreach my $type (@alltypes) {      foreach my $type (@alltypes) {
         if ($type =~ /^_LC_/) {          if ($type =~ /^_LC_/) {
Line 8037  sub loadbalance_rule_row { Line 3959  sub loadbalance_rule_row {
     }      }
     my $space;      my $space;
     if ($islast && $num == 1) {      if ($islast && $num == 1) {
         $space = '<div style="display:inline-block;">&nbsp;</div>';          $space = '<div display="inline-block">&nbsp;</div>';
     }      }
     my $output =      my $output =
         '<tr class="'.$css_class.'" id="balanceruletr_'.$balnum.'_'.$num.'"><td valign="top">'.$space.          '<tr class="'.$css_class.'" id="balanceruletr_'.$balnum.'_'.$num.'"><td valign="top">'.$space.
Line 8119  sub sparestype_titles { Line 4041  sub sparestype_titles {
   
 sub contact_titles {  sub contact_titles {
     my %titles = &Apache::lonlocal::texthash (      my %titles = &Apache::lonlocal::texthash (
                    'supportemail'    => 'Support E-mail address',                     'supportemail' => 'Support E-mail address',
                    'adminemail'      => 'Default Server Admin E-mail address',                     'adminemail'   => 'Default Server Admin E-mail address',
                    'errormail'       => 'Error reports to be e-mailed to',                     'errormail'    => 'Error reports to be e-mailed to',
                    'packagesmail'    => 'Package update alerts to be e-mailed to',                     'packagesmail' => 'Package update alerts to be e-mailed to',
                    'helpdeskmail'    => "Helpdesk requests from all users in this domain",                     'helpdeskmail' => 'Helpdesk requests to be e-mailed to',
                    'otherdomsmail'   => 'Helpdesk requests from users in other (unconfigured) domains',                     'lonstatusmail' => 'E-mail from nightly status check (warnings/errors)',
                    'lonstatusmail'   => 'E-mail from nightly status check (warnings/errors)',                     'requestsmail' => 'E-mail from course requests requiring approval',
                    'requestsmail'    => 'E-mail from course requests requiring approval',                     'updatesmail'  => 'E-mail from nightly check of LON-CAPA module integrity/updates',
                    'updatesmail'     => 'E-mail from nightly check of LON-CAPA module integrity/updates',  
                    'idconflictsmail' => 'E-mail from bi-nightly check for multiple users sharing same student/employee ID',                     'idconflictsmail' => 'E-mail from bi-nightly check for multiple users sharing same student/employee ID',
                    'hostipmail'      => 'E-mail from nightly check of hostname/IP network changes',  
                    'errorthreshold'  => 'Error count threshold for status e-mail to admin(s)',  
                    'errorsysmail'    => 'Error count threshold for e-mail to developer group',  
                    'errorweights'    => 'Weights used to compute error count',  
                    'errorexcluded'   => 'Servers with unsent updates excluded from count',  
                  );                   );
     my %short_titles = &Apache::lonlocal::texthash (      my %short_titles = &Apache::lonlocal::texthash (
                            adminemail   => 'Admin E-mail address',                             adminemail   => 'Admin E-mail address',
Line 8142  sub contact_titles { Line 4058  sub contact_titles {
     return (\%titles,\%short_titles);      return (\%titles,\%short_titles);
 }  }
   
 sub helpform_fields {  
     my %titles =  &Apache::lonlocal::texthash (  
                        'username'   => 'Name',  
                        'user'       => 'Username/domain',  
                        'phone'      => 'Phone',  
                        'cc'         => 'Cc e-mail',  
                        'course'     => 'Course Details',  
                        'section'    => 'Sections',  
                        'screenshot' => 'File upload',  
     );  
     my @fields = ('username','phone','user','course','section','cc','screenshot');  
     my %possoptions = (  
                         username     => ['yes','no','req'],  
                         phone        => ['yes','no','req'],  
                         user         => ['yes','no'],  
                         cc           => ['yes','no'],  
                         course       => ['yes','no'],  
                         section      => ['yes','no'],  
                         screenshot   => ['yes','no'],  
                       );  
     my %fieldoptions = &Apache::lonlocal::texthash (  
                          'yes'  => 'Optional',  
                          'req'  => 'Required',  
                          'no'   => "Not shown",  
     );  
     return (\@fields,\%titles,\%fieldoptions,\%possoptions);  
 }  
   
 sub tool_titles {  sub tool_titles {
     my %titles = &Apache::lonlocal::texthash (      my %titles = &Apache::lonlocal::texthash (
                      aboutme    => 'Personal web page',                       aboutme    => 'Personal web page',
                      blog       => 'Blog',                       blog       => 'Blog',
                      webdav     => 'WebDAV',                       webdav     => 'WebDAV',
                      portfolio  => 'Portfolio',                       portfolio  => 'Portfolio',
                      timezone   => 'Can set time zone',  
                      official   => 'Official courses (with institutional codes)',                       official   => 'Official courses (with institutional codes)',
                      unofficial => 'Unofficial courses',                       unofficial => 'Unofficial courses',
                      community  => 'Communities',                       community  => 'Communities',
Line 8191  sub courserequest_titles { Line 4078  sub courserequest_titles {
                                    unofficial => 'Unofficial',                                     unofficial => 'Unofficial',
                                    community  => 'Communities',                                     community  => 'Communities',
                                    textbook   => 'Textbook',                                     textbook   => 'Textbook',
                                    lti        => 'LTI Provider',  
                                    norequest  => 'Not allowed',                                     norequest  => 'Not allowed',
                                    approval   => 'Approval by Dom. Coord.',                                     approval   => 'Approval by Dom. Coord.',
                                    validate   => 'With validation',                                     validate   => 'With validation',
Line 8305  sub print_usercreation { Line 4191  sub print_usercreation {
         }          }
     } else {      } else {
         my @contexts = ('author','course','domain');          my @contexts = ('author','course','domain');
         my @authtypes = ('int','krb4','krb5','loc','lti');          my @authtypes = ('int','krb4','krb5','loc');
         my %checked;          my %checked;
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if (ref($settings->{'authtypes'}) eq 'HASH') {              if (ref($settings->{'authtypes'}) eq 'HASH') {
Line 8356  sub print_usercreation { Line 4242  sub print_usercreation {
   
 sub print_selfcreation {  sub print_selfcreation {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my (@selfcreate,$createsettings,$processing,$emailoptions,$emailverified,      my (@selfcreate,$createsettings,$processing,$datatable);
         $emaildomain,$datatable);  
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if (ref($settings->{'cancreate'}) eq 'HASH') {          if (ref($settings->{'cancreate'}) eq 'HASH') {
             $createsettings = $settings->{'cancreate'};              $createsettings = $settings->{'cancreate'};
Line 8374  sub print_selfcreation { Line 4259  sub print_selfcreation {
                 if (ref($createsettings->{'selfcreateprocessing'}) eq 'HASH') {                  if (ref($createsettings->{'selfcreateprocessing'}) eq 'HASH') {
                     $processing = $createsettings->{'selfcreateprocessing'};                      $processing = $createsettings->{'selfcreateprocessing'};
                 }                  }
                 if (ref($createsettings->{'emailoptions'}) eq 'HASH') {  
                     $emailoptions = $createsettings->{'emailoptions'};  
                 }  
                 if (ref($createsettings->{'emailverified'}) eq 'HASH') {  
                     $emailverified = $createsettings->{'emailverified'};  
                 }  
                 if (ref($createsettings->{'emaildomain'}) eq 'HASH') {  
                     $emaildomain = $createsettings->{'emaildomain'};  
                 }  
             }              }
         }          }
     }      }
     my %radiohash;      my %radiohash;
     my $numinrow = 4;      my $numinrow = 4;
     map { $radiohash{'cancreate_'.$_} = 1; } @selfcreate;      map { $radiohash{'cancreate_'.$_} = 1; } @selfcreate;
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
     if ($position eq 'top') {      if ($position eq 'top') {
         my %choices = &Apache::lonlocal::texthash (          my %choices = &Apache::lonlocal::texthash (
                                                       cancreate_login      => 'Institutional Login',                                                        cancreate_login      => 'Institutional Login',
Line 8404  sub print_selfcreation { Line 4279  sub print_selfcreation {
         ($datatable,$itemcount) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked,          ($datatable,$itemcount) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked,
                                                      \%choices,$itemcount,$onclick);                                                       \%choices,$itemcount,$onclick);
         $$rowtotal += $itemcount;          $$rowtotal += $itemcount;
           
           my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
   
         if (ref($usertypes) eq 'HASH') {          if (ref($usertypes) eq 'HASH') {
             if (keys(%{$usertypes}) > 0) {              if (keys(%{$usertypes}) > 0) {
                 $datatable .= &insttypes_row($createsettings,$types,$usertypes,                  $datatable .= &insttypes_row($createsettings,$types,$usertypes,
                                              $dom,$numinrow,$othertitle,                                               $dom,$numinrow,$othertitle,
                                              'statustocreate',$rowtotal);                                               'statustocreate',$$rowtotal);
                 $$rowtotal ++;                  $$rowtotal ++;
             }              }
         }          }
Line 8422  sub print_selfcreation { Line 4299  sub print_selfcreation {
         $datatable .= '<tr'.$css_class.'>'.          $datatable .= '<tr'.$css_class.'>'.
                      '<td class="LC_left_item">'.&mt('Mapping of Shibboleth environment variable names to user data fields (SSO auth)').'</td>'.                       '<td class="LC_left_item">'.&mt('Mapping of Shibboleth environment variable names to user data fields (SSO auth)').'</td>'.
                      '<td class="LC_left_item">'."\n".                       '<td class="LC_left_item">'."\n".
                      '<table>'."\n";                       '<table><tr><td>'."\n";
         for (my $i=0; $i<@fields; $i++) {          for (my $i=0; $i<@fields; $i++) {
             $rem = $i%($numperrow);              $rem = $i%($numperrow);
             if ($rem == 0) {              if ($rem == 0) {
Line 8454  sub print_selfcreation { Line 4331  sub print_selfcreation {
         $$rowtotal ++;          $$rowtotal ++;
     } elsif ($position eq 'middle') {      } elsif ($position eq 'middle') {
         my %domconf = &Apache::lonnet::get_dom('configuration',['usermodification'],$dom);          my %domconf = &Apache::lonnet::get_dom('configuration',['usermodification'],$dom);
         my @posstypes;          my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
           $usertypes->{'default'} = $othertitle;
         if (ref($types) eq 'ARRAY') {          if (ref($types) eq 'ARRAY') {
             @posstypes = @{$types};              push(@{$types},'default');
         }              $usertypes->{'default'} = $othertitle;
         unless (grep(/^default$/,@posstypes)) {              foreach my $status (@{$types}) {
             push(@posstypes,'default');                  $datatable .= &modifiable_userdata_row('selfcreate',$status,$domconf{'usermodification'},
         }                                                         $numinrow,$$rowtotal,$usertypes);
         my %usertypeshash;                  $$rowtotal ++;
         if (ref($usertypes) eq 'HASH') {              }
             %usertypeshash = %{$usertypes};  
         }  
         $usertypeshash{'default'} = $othertitle;  
         foreach my $status (@posstypes) {  
             $datatable .= &modifiable_userdata_row('selfcreate',$status,$domconf{'usermodification'},  
                                                    $numinrow,$$rowtotal,\%usertypeshash);  
             $$rowtotal ++;  
         }          }
     } else {      } else {
         my %choices = &Apache::lonlocal::texthash (          my %choices = &Apache::lonlocal::texthash (
                           'cancreate_email' => 'Non-institutional username (via e-mail verification)',                                                        cancreate_email => 'E-mail address as username',
                                                   );                                                    );
         my @toggles = sort(keys(%choices));          my @toggles = sort(keys(%choices));
         my %defaultchecked = (          my %defaultchecked = (
                                'cancreate_email' => 'off',                                 'cancreate_email' => 'off',
                              );                               );
         my $customclass = 'LC_selfcreate_email';          my $itemcount = 0;
         my $classprefix = 'LC_canmodify_emailusername_';  
         my $optionsprefix = 'LC_options_emailusername_';  
         my $display = 'none';          my $display = 'none';
         my $rowstyle = 'display:none';  
         if (grep(/^\Qemail\E$/,@selfcreate)) {          if (grep(/^\Qemail\E$/,@selfcreate)) {
             $display = 'block';              $display = 'block';
             $rowstyle = 'display:table-row';  
         }          }
         my $onclick = "toggleRows(this.form,'cancreate_email','selfassign','$customclass','$classprefix','$optionsprefix');";          my $onclick = "toggleDisplay(this.form,'emailoptions');";
         ($datatable,$$rowtotal) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked,          my $additional = '<div id="emailoptions" style="display: '.$display.'">';
                                                      \%choices,$$rowtotal,$onclick);  
         $datatable .= &print_requestmail($dom,'selfcreation',$createsettings,$rowtotal,$customclass,  
                                          $rowstyle);  
         $$rowtotal ++;  
         $datatable .= &captcha_choice('cancreate',$createsettings,$$rowtotal,$customclass,  
                                       $rowstyle);  
         $$rowtotal ++;  
         my (@ordered,@posstypes,%usertypeshash);  
         my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);          my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
         my ($emailrules,$emailruleorder) =          my $usertypes = {};
             &Apache::lonnet::inst_userrules($dom,'email');          my $order = [];
         my $primary_id = &Apache::lonnet::domain($dom,'primary');          if ((ref($domdefaults{'inststatustypes'}) eq 'HASH') && (ref($domdefaults{'inststatusguest'}) eq 'ARRAY')) {
         my $intdom = &Apache::lonnet::internet_dom($primary_id);              $usertypes = $domdefaults{'inststatustypes'};
         if (ref($types) eq 'ARRAY') {              $order = $domdefaults{'inststatusguest'};
             @posstypes = @{$types};          }
         }          if (ref($order) eq 'ARRAY') {
         if (@posstypes) {              push(@{$order},'default');
             unless (grep(/^default$/,@posstypes)) {              if (@{$order} > 1) {
                 push(@posstypes,'default');                  $usertypes->{'default'} = &mt('Other users');
             }                  $additional .= '<table><tr>';
             if (ref($usertypes) eq 'HASH') {                  foreach my $status (@{$order}) {
                 %usertypeshash = %{$usertypes};                      $additional .= '<th>'.$usertypes->{$status}.'</th>';
             }                  }
             my $currassign;                  $additional .= '</tr><tr>';
             if (ref($domdefaults{'inststatusguest'}) eq 'ARRAY') {                  foreach my $status (@{$order}) {
                 $currassign = {                      $additional .= '<td>'.&email_as_username($rowtotal,$processing,$status).'</td>';
                                   selfassign => $domdefaults{'inststatusguest'},  
                               };  
                 @ordered = @{$domdefaults{'inststatusguest'}};  
             } else {  
                 $currassign = { selfassign => [] };  
             }  
             my $onclicktypes = "toggleDataRow(this.form,'selfassign','$customclass','$optionsprefix',);".  
                                "toggleDataRow(this.form,'selfassign','$customclass','$classprefix',1);";  
             $datatable .= &insttypes_row($currassign,$types,$usertypes,$dom,  
                                          $numinrow,$othertitle,'selfassign',  
                                          $rowtotal,$onclicktypes,$customclass,  
                                          $rowstyle);  
             $$rowtotal ++;  
             $usertypeshash{'default'} = $othertitle;  
             foreach my $status (@posstypes) {  
                 my $css_class;  
                 if ($$rowtotal%2) {  
                     $css_class = 'LC_odd_row ';  
                 }  
                 $css_class .= $customclass;  
                 my $rowid = $optionsprefix.$status;  
                 my $hidden = 1;  
                 my $currstyle = 'display:none';  
                 if (grep(/^\Q$status\E$/,@ordered)) {  
                     $currstyle = $rowstyle;  
                     $hidden = 0;  
                 }  
                 $datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain,  
                                              $emailrules,$emailruleorder,$settings,$status,$rowid,  
                                              $usertypeshash{$status},$css_class,$currstyle,$intdom);  
                 unless ($hidden) {  
                     $$rowtotal ++;  
                 }                  }
                   $additional .= '</tr></table>';
               } else {
                   $usertypes->{'default'} = &mt('All users');
                   $additional .= &email_as_username($rowtotal,$processing);
             }              }
         } else {  
             my $css_class;  
             if ($$rowtotal%2) {  
                 $css_class = 'LC_odd_row ';  
             }  
             $css_class .= $customclass;  
             $usertypeshash{'default'} = $othertitle;  
             $datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain,  
                                          $emailrules,$emailruleorder,$settings,'default','',  
                                          $othertitle,$css_class,$rowstyle,$intdom);  
             $$rowtotal ++;  
         }          }
           $additional .= '</div>'."\n";
   
           ($datatable,$itemcount) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked,
                                                        \%choices,$$rowtotal,$onclick,$additional);
           $$rowtotal ++;
           $datatable .= &print_requestmail($dom,'selfcreation',$createsettings,$rowtotal);
           $$rowtotal ++;
         my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info();          my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info();
         $numinrow = 1;          $numinrow = 1;
         if (@posstypes) {          if (ref($order) eq 'ARRAY') {
             foreach my $status (@posstypes) {              foreach my $status (@{$order}) {
                 my $rowid = $classprefix.$status;  
                 my $datarowstyle = 'display:none';  
                 if (grep(/^\Q$status\E$/,@ordered)) {  
                     $datarowstyle = $rowstyle;  
                 }  
                 $datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings,                  $datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings,
                                                        $numinrow,$$rowtotal,\%usertypeshash,$infofields,                                                         $numinrow,$$rowtotal,$usertypes,$infofields,$infotitles);
                                                        $infotitles,$rowid,$customclass,$datarowstyle);                  $$rowtotal ++;
                 unless ($datarowstyle eq 'display:none') {  
                     $$rowtotal ++;  
                 }  
             }              }
         } else {  
             $datatable .= &modifiable_userdata_row('cancreate','emailusername_default',$settings,  
                                                    $numinrow,$$rowtotal,\%usertypeshash,$infofields,  
                                                    $infotitles,'',$customclass,$rowstyle);  
         }          }
     }          my ($emailrules,$emailruleorder) =
     return $datatable;              &Apache::lonnet::inst_userrules($dom,'email');
 }          if (ref($emailrules) eq 'HASH') {
               if (keys(%{$emailrules}) > 0) {
 sub selfcreate_javascript {                  $datatable .= &user_formats_row('email',$settings,$emailrules,
     return <<"ENDSCRIPT";                                                  $emailruleorder,$numinrow,$$rowtotal);
                   $$rowtotal ++;
 <script type="text/javascript">  
 // <![CDATA[  
   
 function toggleRows(form,radio,checkbox,target,prefix,altprefix) {  
     var x = document.getElementsByClassName(target);  
     var insttypes = 0;  
     var insttypeRegExp = new RegExp(prefix);  
     if ((x.length != undefined) && (x.length > 0)) {  
         if (form.elements[radio].length != undefined) {  
             for (var i=0; i<form.elements[radio].length; i++) {  
                 if (form.elements[radio][i].checked) {  
                     if (form.elements[radio][i].value == 1) {  
                         for (var j=0; j<x.length; j++) {  
                             if (x[j].id == 'undefined') {  
                                 x[j].style.display = 'table-row';  
                             } else if (insttypeRegExp.test(x[j].id)) {  
                                 insttypes ++;  
                             } else {  
                                 x[j].style.display = 'table-row';  
                             }  
                         }  
                     } else {  
                         for (var j=0; j<x.length; j++) {  
                             x[j].style.display = 'none';  
                         }  
                     }  
                     break;  
                 }  
             }  
             if (insttypes > 0) {  
                 toggleDataRow(form,checkbox,target,altprefix);  
                 toggleDataRow(form,checkbox,target,prefix,1);  
             }              }
         }          }
           $datatable .= &captcha_choice('cancreate',$createsettings,$$rowtotal);
     }      }
     return;      return $datatable;
 }  }
   
 function toggleDataRow(form,checkbox,target,prefix,docount) {  sub email_as_username {
     if (form.elements[checkbox].length != undefined) {      my ($rowtotal,$processing,$type) = @_;
         var count = 0;      my %choices =
         if (docount) {          &Apache::lonlocal::texthash (
             for (var i=0; i<form.elements[checkbox].length; i++) {                                        automatic => 'Automatic approval',
                 if (form.elements[checkbox][i].checked) {                                        approval  => 'Queued for approval',
                     count ++;                                      );
                 }      my $output;
             }      foreach my $option ('automatic','approval') {
         }          my $checked;
         for (var i=0; i<form.elements[checkbox].length; i++) {          if (ref($processing) eq 'HASH') {
             var type = form.elements[checkbox][i].value;              if ($type eq '') {   
             if (document.getElementById(prefix+type)) {                  if (!exists($processing->{'default'})) {
                 if (form.elements[checkbox][i].checked) {                      if ($option eq 'automatic') {
                     document.getElementById(prefix+type).style.display = 'table-row';                          $checked = ' checked="checked"';
                     if (count % 2 == 1) {  
                         document.getElementById(prefix+type).className = target+' LC_odd_row';  
                     } else {  
                         document.getElementById(prefix+type).className = target;  
                     }                      }
                     count ++;  
                 } else {                  } else {
                     document.getElementById(prefix+type).style.display = 'none';                      if ($processing->{'default'} eq $option) {
                 }                          $checked = ' checked="checked"';
             }  
         }  
     }  
     return;  
 }  
   
 function toggleEmailOptions(form,radio,prefix,altprefix,status) {  
     var caller = radio+'_'+status;  
     if (form.elements[caller].length != undefined) {  
         for (var i=0; i<form.elements[caller].length; i++) {  
             if (form.elements[caller][i].checked) {  
                 if (document.getElementById(altprefix+'_inst_'+status)) {  
                     var curr = form.elements[caller][i].value;  
                     if (prefix) {  
                         document.getElementById(prefix+'_'+status).style.display = 'none';  
                     }  
                     document.getElementById(altprefix+'_inst_'+status).style.display = 'none';  
                     document.getElementById(altprefix+'_noninst_'+status).style.display = 'none';  
                     if (curr == 'custom') {  
                         if (prefix) {  
                             document.getElementById(prefix+'_'+status).style.display = 'inline';  
                         }  
                     } else if (curr == 'inst') {  
                         document.getElementById(altprefix+'_inst_'+status).style.display = 'inline';  
                     } else if (curr == 'noninst') {  
                         document.getElementById(altprefix+'_noninst_'+status).style.display = 'inline';  
                     }  
                     break;  
                 }  
             }  
         }  
     }  
 }  
   
 // ]]>  
 </script>  
   
 ENDSCRIPT  
 }  
   
 sub noninst_users {  
     my ($processing,$emailverified,$emailoptions,$emaildomain,$emailrules,  
         $emailruleorder,$settings,$type,$rowid,$typetitle,$css_class,$rowstyle,$intdom) = @_;  
     my $class = 'LC_left_item';  
     if ($css_class) {  
         $css_class = ' class="'.$css_class.'"';  
     }  
     if ($rowid) {  
         $rowid = ' id="'.$rowid.'"';  
     }  
     if ($rowstyle) {  
         $rowstyle = ' style="'.$rowstyle.'"';  
     }  
     my ($output,$description);  
     if ($type eq 'default') {  
         $description = &mt('Requests for: [_1]',$typetitle);  
     } else {  
         $description = &mt('Requests for: [_1] (status self-reported)',$typetitle);  
     }  
     $output = '<tr'.$css_class.$rowid.$rowstyle.'>'.  
               "<td>$description</td>\n".  
               '<td class="'.$class.'" colspan="2">'.  
               '<table><tr>';  
     my %headers = &Apache::lonlocal::texthash(  
               approve  => 'Processing',  
               email    => 'E-mail',  
               username => 'Username',  
     );  
     foreach my $item ('approve','email','username') {  
         $output .= '<th>'.$headers{$item}.'</th>';  
     }  
     $output .= '</tr><tr>';  
     foreach my $item ('approve','email','username') {  
         $output .= '<td valign="top">';  
         my (%choices,@options,$hashref,$defoption,$name,$onclick,$hascustom);  
         if ($item eq 'approve') {  
             %choices = &Apache::lonlocal::texthash (  
                                                      automatic => 'Automatically approved',  
                                                      approval  => 'Queued for approval',  
                                                    );  
             @options = ('automatic','approval');  
             $hashref = $processing;  
             $defoption = 'automatic';  
             $name = 'cancreate_emailprocess_'.$type;  
         } elsif ($item eq 'email') {  
             %choices = &Apache::lonlocal::texthash (  
                                                      any     => 'Any e-mail',  
                                                      inst    => 'Institutional only',  
                                                      noninst => 'Non-institutional only',  
                                                      custom  => 'Custom restrictions',  
                                                    );  
             @options = ('any','inst','noninst');  
             my $showcustom;  
             if (ref($emailrules) eq 'HASH') {  
                 if (keys(%{$emailrules}) > 0) {  
                     push(@options,'custom');  
                     $showcustom = 'cancreate_emailrule';  
                     if (ref($settings) eq 'HASH') {  
                         if (ref($settings->{'email_rule'}) eq 'ARRAY') {  
                             foreach my $rule (@{$settings->{'email_rule'}}) {  
                                 if (exists($emailrules->{$rule})) {  
                                     $hascustom ++;  
                                 }  
                             }  
                         } elsif (ref($settings->{'email_rule'}) eq 'HASH') {  
                             if (ref($settings->{'email_rule'}{$type}) eq 'ARRAY') {  
                                 foreach my $rule (@{$settings->{'email_rule'}{$type}}) {  
                                     if (exists($emailrules->{$rule})) {  
                                         $hascustom ++;  
                                     }  
                                 }  
                             }  
                         }  
                     }                      }
                 }                  }
             }              } else {
             $onclick = ' onclick="toggleEmailOptions(this.form,'."'cancreate_emailoptions','$showcustom',".                  if (!exists($processing->{$type})) {
                                                      "'cancreate_emaildomain','$type'".');"';                      if ($option eq 'automatic') {
             $hashref = $emailoptions;                          $checked = ' checked="checked"';
             $defoption = 'any';  
             $name = 'cancreate_emailoptions_'.$type;  
         } elsif ($item eq 'username') {  
             %choices = &Apache::lonlocal::texthash (  
                                                      all    => 'Same as e-mail',  
                                                      first  => 'Omit @domain',  
                                                      free   => 'Free to choose',  
                                                    );  
             @options = ('all','first','free');  
             $hashref = $emailverified;  
             $defoption = 'all';  
             $name = 'cancreate_usernameoptions_'.$type;  
         }  
         foreach my $option (@options) {  
             my $checked;  
             if (ref($hashref) eq 'HASH') {  
                 if ($type eq '') {  
                     if (!exists($hashref->{'default'})) {  
                         if ($option eq $defoption) {  
                             $checked = ' checked="checked"';  
                         }  
                     } else {  
                         if ($hashref->{'default'} eq $option) {  
                             $checked = ' checked="checked"';  
                         }  
                     }                      }
                 } else {                  } else {
                     if (!exists($hashref->{$type})) {                      if ($processing->{$type} eq $option) {
                         if ($option eq $defoption) {                          $checked = ' checked="checked"';
                             $checked = ' checked="checked"';  
                         }  
                     } else {  
                         if ($hashref->{$type} eq $option) {  
                             $checked = ' checked="checked"';  
                         }  
                     }  
                 }  
             } elsif (($item eq 'email') && ($hascustom)) {  
                 if ($option eq 'custom') {  
                     $checked = ' checked="checked"';  
                 }  
             } elsif ($option eq $defoption) {  
                 $checked = ' checked="checked"';  
             }  
             $output .= '<span class="LC_nobreak"><label>'.  
                        '<input type="radio" name="'.$name.'"'.  
                        $checked.' value="'.$option.'"'.$onclick.' />'.  
                        $choices{$option}.'</label></span><br />';  
             if ($item eq 'email') {  
                 if ($option eq 'custom') {  
                     my $id = 'cancreate_emailrule_'.$type;  
                     my $display = 'none';  
                     if ($checked) {  
                         $display = 'inline';  
                     }  
                     my $numinrow = 2;  
                     $output .= '<fieldset id="'.$id.'" style="display:'.$display.';">'.  
                                '<legend>'.&mt('Disallow').'</legend><table>'.  
                                &user_formats_row('email',$settings,$emailrules,  
                                                  $emailruleorder,$numinrow,'',$type);  
                               '</table></fieldset>';  
                 } elsif (($option eq 'inst') || ($option eq 'noninst')) {  
                     my %text = &Apache::lonlocal::texthash (  
                                                              inst    => 'must end:',  
                                                              noninst => 'cannot end:',  
                                                            );  
                     my $value;  
                     if (ref($emaildomain) eq 'HASH') {  
                         if (ref($emaildomain->{$type}) eq 'HASH') {  
                             $value = $emaildomain->{$type}->{$option};  
                         }  
                     }  
                     if ($value eq '') {  
                         $value = '@'.$intdom;  
                     }  
                     my $condition = 'cancreate_emaildomain_'.$option.'_'.$type;  
                     my $display = 'none';  
                     if ($checked) {  
                         $display = 'inline';  
                     }                      }
                     $output .= '<div id="'.$condition.'" style="display:'.$display.';">'.  
                                '<span class="LC_domprefs_email">'.$text{$option}.'</span> '.  
                                '<input type="text" name="'.$condition.'" value="'.$value.'" size="10" />'.  
                                '</div>';  
                 }                  }
             }              }
           } elsif ($option eq 'automatic') {
               $checked = ' checked="checked"'; 
           }
           my $name = 'cancreate_emailprocess';
           if (($type ne '') && ($type ne 'default')) {
               $name .= '_'.$type;
           }
           $output .= '<span class="LC_nobreak"><label>'.
                      '<input type="radio" name="'.$name.'"'.
                      $checked.' value="'.$option.'" />'.
                      $choices{$option}.'</label></span>';
           if ($type eq '') {
               $output .= '&nbsp;';
           } else {
               $output .= '<br />';
         }          }
         $output .= '</td>'."\n";  
     }      }
     $output .= "</tr></table></td></tr>\n";      $$rowtotal ++;
     return $output;      return $output;
 }  }
   
 sub captcha_choice {  sub captcha_choice {
     my ($context,$settings,$itemcount,$customcss,$rowstyle) = @_;      my ($context,$settings,$itemcount) = @_;
     my ($keyentry,$currpub,$currpriv,%checked,$rowname,$pubtext,$privtext,      my ($keyentry,$currpub,$currpriv,%checked,$rowname,$pubtext,$privtext);
         $vertext,$currver);  
     my %lt = &captcha_phrases();      my %lt = &captcha_phrases();
     $keyentry = 'hidden';      $keyentry = 'hidden';
     my $colspan=2;  
     if ($context eq 'cancreate') {      if ($context eq 'cancreate') {
         $rowname = &mt('CAPTCHA validation');          $rowname = &mt('CAPTCHA validation');
     } elsif ($context eq 'login') {      } elsif ($context eq 'login') {
         $rowname =  &mt('"Contact helpdesk" CAPTCHA validation');          $rowname =  &mt('"Contact helpdesk" CAPTCHA validation');
     } elsif ($context eq 'passwords') {  
         $rowname = &mt('"Forgot Password" CAPTCHA validation');  
         $colspan=1;  
     }      }
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if ($settings->{'captcha'}) {          if ($settings->{'captcha'}) {
Line 8889  sub captcha_choice { Line 4485  sub captcha_choice {
             $pubtext = $lt{'pub'};              $pubtext = $lt{'pub'};
             $privtext = $lt{'priv'};              $privtext = $lt{'priv'};
             $keyentry = 'text';              $keyentry = 'text';
             $vertext = $lt{'ver'};  
             $currver = $settings->{'recaptchaversion'};  
             if ($currver ne '2') {  
                 $currver = 1;  
             }  
         }          }
         if (ref($settings->{'recaptchakeys'}) eq 'HASH') {          if (ref($settings->{'recaptchakeys'}) eq 'HASH') {
             $currpub = $settings->{'recaptchakeys'}{'public'};              $currpub = $settings->{'recaptchakeys'}{'public'};
Line 8902  sub captcha_choice { Line 4493  sub captcha_choice {
     } else {      } else {
         $checked{'original'} = ' checked="checked"';          $checked{'original'} = ' checked="checked"';
     }      }
     my $css_class;      my $css_class = $itemcount%2?' class="LC_odd_row"':'';
     if ($itemcount%2) {  
         $css_class = 'LC_odd_row';  
     }  
     if ($customcss) {  
         $css_class .= " $customcss";  
     }  
     $css_class =~ s/^\s+//;  
     if ($css_class) {  
         $css_class = ' class="'.$css_class.'"';  
     }  
     if ($rowstyle) {  
         $css_class .= ' style="'.$rowstyle.'"';  
     }  
     my $output = '<tr'.$css_class.'>'.      my $output = '<tr'.$css_class.'>'.
                  '<td class="LC_left_item">'.$rowname.'</td><td class="LC_left_item" colspan="'.$colspan.'">'."\n".                   '<td class="LC_left_item">'.$rowname.'</td><td class="LC_left_item" colspan="2">'."\n".
                  '<table><tr><td>'."\n";                   '<table><tr><td>'."\n";
     foreach my $option ('original','recaptcha','notused') {      foreach my $option ('original','recaptcha','notused') {
         $output .= '<span class="LC_nobreak"><label><input type="radio" name="'.$context.'_captcha" value="'.          $output .= '<span class="LC_nobreak"><label><input type="radio" name="'.$context.'_captcha" value="'.
Line 8934  sub captcha_choice { Line 4512  sub captcha_choice {
 # specified for use with the key should be broad enough to accommodate all servers in the LON-CAPA domain.  # specified for use with the key should be broad enough to accommodate all servers in the LON-CAPA domain.
 #  #
     $output .= '</td></tr>'."\n".      $output .= '</td></tr>'."\n".
                '<tr><td class="LC_zero_height">'."\n".                 '<tr><td>'."\n".
                '<span class="LC_nobreak"><span id="'.$context.'_recaptchapubtxt">'.$pubtext.'</span>&nbsp;'."\n".                 '<span class="LC_nobreak"><span id="'.$context.'_recaptchapubtxt">'.$pubtext.'</span>&nbsp;'."\n".
                '<input type="'.$keyentry.'" id="'.$context.'_recaptchapub" name="'.$context.'_recaptchapub" value="'.                 '<input type="'.$keyentry.'" id="'.$context.'_recaptchapub" name="'.$context.'_recaptchapub" value="'.
                $currpub.'" size="40" /></span><br />'."\n".                 $currpub.'" size="40" /></span><br />'."\n".
                '<span class="LC_nobreak"><span id="'.$context.'_recaptchaprivtxt">'.$privtext.'</span>&nbsp;'."\n".                 '<span class="LC_nobreak"><span id="'.$context.'_recaptchaprivtxt">'.$privtext.'</span>&nbsp;'."\n".
                '<input type="'.$keyentry.'" id="'.$context.'_recaptchapriv" name="'.$context.'_recaptchapriv" value="'.                 '<input type="'.$keyentry.'" id="'.$context.'_recaptchapriv" name="'.$context.'_recaptchapriv" value="'.
                $currpriv.'" size="40" /></span><br />'.                 $currpriv.'" size="40" /></span></td></tr></table>'."\n".
                '<span class="LC_nobreak"><span id="'.$context.'_recaptchavertxt">'.$vertext.'</span>&nbsp;'."\n".  
                '<input type="'.$keyentry.'" id="'.$context.'_recaptchaversion" name="'.$context.'_recaptchaversion" value="'.  
                $currver.'" size="3" /></span><br />'.  
                '</td></tr></table>'."\n".  
                '</td></tr>';                 '</td></tr>';
     return $output;      return $output;
 }  }
   
 sub user_formats_row {  sub user_formats_row {
     my ($type,$settings,$rules,$ruleorder,$numinrow,$rowcount,$status) = @_;      my ($type,$settings,$rules,$ruleorder,$numinrow,$rowcount) = @_;
     my $output;      my $output;
     my %text = (      my %text = (
                    'username' => 'new usernames',                     'username' => 'new usernames',
                    'id'       => 'IDs',                     'id'       => 'IDs',
                      'email'    => 'self-created accounts (e-mail)',
                );                 );
     unless (($type eq 'email') || ($type eq 'unamemap')) {      my $css_class = $rowcount%2?' class="LC_odd_row"':'';
         my $css_class = $rowcount%2?' class="LC_odd_row"':'';      $output = '<tr '.$css_class.'>'.
         $output = '<tr '.$css_class.'>'.                '<td><span class="LC_nobreak">';
                   '<td><span class="LC_nobreak">'.      if ($type eq 'email') {
                   &mt("Format rules to check for $text{$type}: ").          $output .= &mt("Formats disallowed for $text{$type}: ");
                   '</td><td class="LC_left_item" colspan="2"><table>';      } else {
           $output .= &mt("Format rules to check for $text{$type}: ");
     }      }
       $output .= '</span></td>'.
                  '<td class="LC_left_item" colspan="2"><table>';
     my $rem;      my $rem;
     if (ref($ruleorder) eq 'ARRAY') {      if (ref($ruleorder) eq 'ARRAY') {
         for (my $i=0; $i<@{$ruleorder}; $i++) {          for (my $i=0; $i<@{$ruleorder}; $i++) {
Line 8980  sub user_formats_row { Line 4558  sub user_formats_row {
                         if (grep(/^\Q$ruleorder->[$i]\E$/,@{$settings->{$type.'_rule'}})) {                          if (grep(/^\Q$ruleorder->[$i]\E$/,@{$settings->{$type.'_rule'}})) {
                             $check = ' checked="checked" ';                              $check = ' checked="checked" ';
                         }                          }
                     } elsif ((ref($settings->{$type.'_rule'}) eq 'HASH') && ($status ne '')) {  
                         if (ref($settings->{$type.'_rule'}->{$status}) eq 'ARRAY') {  
                             if (grep(/^\Q$ruleorder->[$i]\E$/,@{$settings->{$type.'_rule'}->{$status}})) {  
                                 $check = ' checked="checked" ';  
                             }  
                         }  
                     }                      }
                 }                  }
                 my $name = $type.'_rule';  
                 if ($type eq 'email') {  
                     $name .= '_'.$status;  
                 }  
                 $output .= '<td class="LC_left_item">'.                  $output .= '<td class="LC_left_item">'.
                            '<span class="LC_nobreak"><label>'.                             '<span class="LC_nobreak"><label>'.
                            '<input type="checkbox" name="'.$name.'" '.                             '<input type="checkbox" name="'.$type.'_rule" '.
                            'value="'.$ruleorder->[$i].'"'.$check.'/>'.                             'value="'.$ruleorder->[$i].'"'.$check.'/>'.
                            $rules->{$ruleorder->[$i]}{'name'}.'</label></span></td>';                             $rules->{$ruleorder->[$i]}{'name'}.'</label></span></td>';
             }              }
         }          }
         $rem = @{$ruleorder}%($numinrow);          $rem = @{$ruleorder}%($numinrow);
     }      }
     my $colsleft;      my $colsleft = $numinrow - $rem;
     if ($rem) {  
         $colsleft = $numinrow - $rem;  
     }  
     if ($colsleft > 1 ) {      if ($colsleft > 1 ) {
         $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.          $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
                    '&nbsp;</td>';                     '&nbsp;</td>';
     } elsif ($colsleft == 1) {      } elsif ($colsleft == 1) {
         $output .= '<td class="LC_left_item">&nbsp;</td>';          $output .= '<td class="LC_left_item">&nbsp;</td>';
     }      }
     $output .= '</tr>';      $output .= '</tr></table></td></tr>';
     unless (($type eq 'email') || ($type eq 'unamemap')) {  
         $output .= '</table></td></tr>';  
     }  
     return $output;      return $output;
 }  }
   
Line 9049  sub authtype_names { Line 4611  sub authtype_names {
                       krb4   => 'Kerberos 4',                        krb4   => 'Kerberos 4',
                       krb5   => 'Kerberos 5',                        krb5   => 'Kerberos 5',
                       loc    => 'Local',                        loc    => 'Local',
                       lti    => 'LTI',  
                   );                    );
     return %lt;      return %lt;
 }  }
Line 9092  sub print_usermodification { Line 4653  sub print_usermodification {
 sub print_defaults {  sub print_defaults {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my $rownum = 0;      my $rownum = 0;
     my ($datatable,$css_class,$titles);      my ($datatable,$css_class);
     unless ($position eq 'bottom') {  
         $titles = &defaults_titles($dom);  
     }  
     if ($position eq 'top') {      if ($position eq 'top') {
         my @items = ('auth_def','auth_arg_def','lang_def','timezone_def',          my @items = ('auth_def','auth_arg_def','lang_def','timezone_def',
                      'datelocale_def','portal_def');                       'datelocale_def','portal_def');
Line 9108  sub print_defaults { Line 4666  sub print_defaults {
                 $defaults{$item} = $domdefaults{$item};                  $defaults{$item} = $domdefaults{$item};
             }              }
         }          }
           my $titles = &defaults_titles($dom);
         foreach my $item (@items) {          foreach my $item (@items) {
             if ($rownum%2) {              if ($rownum%2) {
                 $css_class = '';                  $css_class = '';
Line 9118  sub print_defaults { Line 4677  sub print_defaults {
                           '<td><span class="LC_nobreak">'.$titles->{$item}.                            '<td><span class="LC_nobreak">'.$titles->{$item}.
                           '</span></td><td class="LC_right_item" colspan="3">';                            '</span></td><td class="LC_right_item" colspan="3">';
             if ($item eq 'auth_def') {              if ($item eq 'auth_def') {
                 my @authtypes = ('internal','krb4','krb5','localauth','lti');                  my @authtypes = ('internal','krb4','krb5','localauth');
                 my %shortauth = (                  my %shortauth = (
                                  internal => 'int',                                   internal => 'int',
                                  krb4 => 'krb4',                                   krb4 => 'krb4',
                                  krb5 => 'krb5',                                   krb5 => 'krb5',
                                  localauth  => 'loc',                                   localauth  => 'loc'
                                  lti => 'lti',  
                                 );                                  );
                 my %authnames = &authtype_names();                  my %authnames = &authtype_names();
                 foreach my $auth (@authtypes) {                  foreach my $auth (@authtypes) {
Line 9143  sub print_defaults { Line 4701  sub print_defaults {
                 my $includeempty = 1;                  my $includeempty = 1;
                 $datatable .= &Apache::loncommon::select_datelocale($item,$defaults{$item},undef,$includeempty);                  $datatable .= &Apache::loncommon::select_datelocale($item,$defaults{$item},undef,$includeempty);
             } elsif ($item eq 'lang_def') {              } elsif ($item eq 'lang_def') {
                 my $includeempty = 1;                  my %langchoices = &get_languages_hash();
                 $datatable .= &Apache::loncommon::select_language($item,$defaults{$item},$includeempty);                  $langchoices{''} = 'No language preference';
             } elsif ($item eq 'portal_def') {                  %langchoices = &Apache::lonlocal::texthash(%langchoices);
                 $datatable .= '<input type="text" name="'.$item.'" value="'.                  $datatable .= &Apache::loncommon::select_form($defaults{$item},$item,
                               $defaults{$item}.'" size="25" onkeyup="portalExtras(this);" />';                                                                \%langchoices);
                 my $portalsty = 'none';              } else {
                 if ($defaults{$item}) {                  my $size;
                     $portalsty = 'block';                  if ($item eq 'portal_def') {
                 }                      $size = ' size="25"';
                 foreach my $field ('email','web') {  
                     my $checkedoff = ' checked="checked"';  
                     my $checkedon;  
                     if ($defaults{$item.'_'.$field}) {  
                         $checkedon = $checkedoff;  
                         $checkedoff = '';  
                     }  
                     $datatable .= '<div id="'.$item.'_'.$field.'_div" style="display:'.$portalsty.'">'.  
                               '<span class="LC_nobreak">'.$titles->{$field}.'&nbsp;'.  
                               '<label><input type="radio" name="'.$item.'_'.$field.'" value="1"'.$checkedon.'/>'.&mt('Yes').'</label>'.  
                               ('&nbsp;'x2).  
                               '<label><input type="radio" name="'.$item.'_'.$field.'" value="0"'.$checkedoff.'/>'.&mt('No').'</label>'.  
                               '</div>';  
                 }                  }
             } else {                  $datatable .= '<input type="text" name="'.$item.'" value="'.
                 $datatable .= '<input type="text" name="'.$item.'" value="'.$defaults{$item}.'" />';                                $defaults{$item}.'"'.$size.' />';
             }              }
             $datatable .= '</td></tr>';              $datatable .= '</td></tr>';
             $rownum ++;              $rownum ++;
         }          }
     } elsif ($position eq 'middle') {      } else {
         my %defaults;          my (%defaults);
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {              if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH') &&
                   (ref($settings->{'inststatusguest'}) eq 'ARRAY')) {
                 my $maxnum = @{$settings->{'inststatusorder'}};                  my $maxnum = @{$settings->{'inststatusorder'}};
                 for (my $i=0; $i<$maxnum; $i++) {                  for (my $i=0; $i<$maxnum; $i++) {
                     $css_class = $rownum%2?' class="LC_odd_row"':'';                      $css_class = $rownum%2?' class="LC_odd_row"':'';
                     my $item = $settings->{'inststatusorder'}->[$i];                      my $item = $settings->{'inststatusorder'}->[$i];
                     my $title = $settings->{'inststatustypes'}->{$item};                      my $title = $settings->{'inststatustypes'}->{$item};
                       my $guestok;
                       if (grep(/^\Q$item\E$/,@{$settings->{'inststatusguest'}})) {
                           $guestok = 1;
                       }
                     my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'$item'".');"';                      my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'$item'".');"';
                     $datatable .= '<tr'.$css_class.'>'.                      $datatable .= '<tr'.$css_class.'>'.
                                   '<td><span class="LC_nobreak">'.                                    '<td><span class="LC_nobreak">'.
Line 9193  sub print_defaults { Line 4743  sub print_defaults {
                         }                          }
                         $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';                          $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
                     }                      }
                       my ($checkedon,$checkedoff);
                       $checkedoff = ' checked="checked"';
                       if ($guestok) {
                           $checkedon = $checkedoff;
                           $checkedoff = ''; 
                       }
                     $datatable .= '</select>&nbsp;'.&mt('Internal ID:').'&nbsp;<b>'.$item.'</b>&nbsp;'.                      $datatable .= '</select>&nbsp;'.&mt('Internal ID:').'&nbsp;<b>'.$item.'</b>&nbsp;'.
                                   '<input type="checkbox" name="inststatus_delete" value="'.$item.'" />'.                                    '<input type="checkbox" name="inststatus_delete" value="'.$item.'" />'.
                                   &mt('delete').'</span></td>'.                                    &mt('delete').'</span></td>'.
                                   '<td class="LC_left_item"><span class="LC_nobreak">'.&mt('Name displayed').':'.                                    '<td class="LC_left_item"><span class="LC_nobreak">'.&mt('Name displayed:').
                                   '<input type="text" size="20" name="inststatus_title_'.$item.'" value="'.$title.'" />'.                                    '<input type="text" size="20" name="inststatus_title_'.$item.'" value="'.$title.'" />'.
                                   '</span></td></tr>';                                    '</span></td>'.
                                     '<td class="LC_right_item"><span class="LC_nobreak">'.
                                     '<label><input type="radio" value="1" name="inststatus_guest_'.$item.'"'.$checkedon.' />'.
                                     &mt('Yes').'</label>'.('&nbsp;'x2).
                                     '<label><input type="radio" value="0" name="inststatus_guest_'.$item.'"'.$checkedoff.' />'.
                                     &mt('No').'</label></span></td></tr>';
                 }                  }
                 $css_class = $rownum%2?' class="LC_odd_row"':'';                  $css_class = $rownum%2?' class="LC_odd_row"':'';
                 my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'addinststatus_pos'".');"';                  my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'addinststatus_pos'".');"';
Line 9213  sub print_defaults { Line 4774  sub print_defaults {
                     $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';                      $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
                 }                  }
                 $datatable .= '</select>&nbsp;'.&mt('Internal ID:').                  $datatable .= '</select>&nbsp;'.&mt('Internal ID:').
                               '<input type="text" size="10" name="addinststatus" value="" />'.                                '<input type="text" size="10" name="addinststatus" value="" /></span>'.
                               '&nbsp;'.&mt('(new)').                                '&nbsp;'.&mt('(new)').
                               '</span></td><td class="LC_left_item"><span class="LC_nobreak">'.                                '</span></td><td class="LC_left_item"><span class="LC_nobreak">'.
                               &mt('Name displayed').':'.                                &mt('Name displayed:').
                               '<input type="text" size="20" name="addinststatus_title" value="" /></span></td>'.                                '<input type="text" size="20" name="addinststatus_title" value="" /></span></td>'.
                                 '<td class="LC_right_item"><span class="LC_nobreak">'.
                                 '<label><input type="radio" value="1" name="addinststatus_guest" />'.
                                 &mt('Yes').'</label>'.('&nbsp;'x2).
                                 '<label><input type="radio" value="0" name="addinststatus_guest" />'.
                                 &mt('No').'</label></span></td></tr>';
                               '</tr>'."\n";                                '</tr>'."\n";
                 $rownum ++;                  $rownum ++;
             }              }
         }          }
     } else {  
         my ($unamemaprules,$ruleorder) =  
             &Apache::lonnet::inst_userrules($dom,'unamemap');  
         $css_class = $rownum%2?' class="LC_odd_row"':'';  
         if ((ref($unamemaprules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {  
             my $numinrow = 2;  
             $datatable .= '<tr'.$css_class.'><td>'.&mt('Available conversions').'</td><td><table>'.  
                           &user_formats_row('unamemap',$settings,$unamemaprules,  
                                             $ruleorder,$numinrow).  
                           '</table></td></tr>';  
         }  
         if ($datatable eq '') {  
             $datatable .= '<tr'.$css_class.'><td colspan="2">'.  
                           &mt('No rules set for domain in customized localenroll.pm').  
                           '</td></tr>';  
         }  
     }      }
     $$rowtotal += $rownum;      $$rowtotal += $rownum;
     return $datatable;      return $datatable;
Line 9263  sub defaults_titles { Line 4813  sub defaults_titles {
                    'timezone_def'  => 'Default timezone',                     'timezone_def'  => 'Default timezone',
                    'datelocale_def' => 'Default locale for dates',                     'datelocale_def' => 'Default locale for dates',
                    'portal_def'     => 'Portal/Default URL',                     'portal_def'     => 'Portal/Default URL',
                    'email'          => 'Email links use portal URL',  
                    'web'            => 'Public web links use portal URL',  
                    'intauth_cost'   => 'Encryption cost for bcrypt (positive integer)',  
                    'intauth_check'  => 'Check bcrypt cost if authenticated',  
                    'intauth_switch' => 'Existing crypt-based switched to bcrypt on authentication',  
                  );                   );
     if ($dom) {      if ($dom) {
         my $uprimary_id = &Apache::lonnet::domain($dom,'primary');          my $uprimary_id = &Apache::lonnet::domain($dom,'primary');
Line 9282  sub defaults_titles { Line 4827  sub defaults_titles {
     return (\%titles);      return (\%titles);
 }  }
   
 sub print_scantron {  
     my ($r,$position,$dom,$confname,$settings,$rowtotal) = @_;  
     if ($position eq 'top') {  
         return &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal);  
     } else {  
         return &print_scantronconfig($dom,$settings,\$rowtotal);  
     }  
 }  
   
 sub scantron_javascript {  
     return <<"ENDSCRIPT";  
   
 <script type="text/javascript">  
 // <![CDATA[  
   
 function toggleScantron(form) {  
     var csvfieldset = new Array();  
     if (document.getElementById('scantroncsv_cols')) {  
         csvfieldset.push(document.getElementById('scantroncsv_cols'));  
     }  
     if (document.getElementById('scantroncsv_options')) {  
         csvfieldset.push(document.getElementById('scantroncsv_options'));  
     }  
     if (csvfieldset.length) {  
         if (document.getElementById('scantronconfcsv')) {  
             var scantroncsv = document.getElementById('scantronconfcsv');  
             if (scantroncsv.checked) {  
                 for (var i=0; i<csvfieldset.length; i++) {  
                     csvfieldset[i].style.display = 'block';  
                 }  
             } else {  
                 for (var i=0; i<csvfieldset.length; i++) {  
                     csvfieldset[i].style.display = 'none';  
                 }  
                 var csvselects = document.getElementsByClassName('scantronconfig_csv');  
                 if (csvselects.length) {  
                     for (var j=0; j<csvselects.length; j++) {  
                         csvselects[j].selectedIndex = 0;  
                     }  
                 }  
             }  
         }  
     }  
     return;  
 }  
 // ]]>  
 </script>  
   
 ENDSCRIPT  
   
 }  
   
 sub print_scantronformat {  sub print_scantronformat {
     my ($r,$dom,$confname,$settings,$rowtotal) = @_;      my ($r,$dom,$confname,$settings,$rowtotal) = @_;
     my $itemcount = 1;      my $itemcount = 1;
Line 9360  sub print_scantronformat { Line 4853  sub print_scantronformat {
             if ($configuserok eq 'ok') {              if ($configuserok eq 'ok') {
                 if ($author_ok eq 'ok') {                  if ($author_ok eq 'ok') {
                     my %legacyfile = (                      my %legacyfile = (
  default => $Apache::lonnet::perlvar{'lonTabDir'}.'/default_scantronformat.tab',   default => $Apache::lonnet::perlvar{'lonTabDir'}.'/default_scantronformat.tab', 
  custom  => $Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab',   custom  => $Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab', 
                     );                      );
                     my %md5chk;                      my %md5chk;
                     foreach my $type (keys(%legacyfile)) {                      foreach my $type (keys(%legacyfile)) {
Line 9370  sub print_scantronformat { Line 4863  sub print_scantronformat {
                     }                      }
                     if ($md5chk{'default'} ne $md5chk{'custom'}) {                      if ($md5chk{'default'} ne $md5chk{'custom'}) {
                         foreach my $type (keys(%legacyfile)) {                          foreach my $type (keys(%legacyfile)) {
                             ($scantronurls{$type},my $error) =                              ($scantronurls{$type},my $error) = 
                                 &legacy_scantronformat($r,$dom,$confname,                                  &legacy_scantronformat($r,$dom,$confname,
                                                  $type,$legacyfile{$type},                                                   $type,$legacyfile{$type},
                                                  $scantronurls{$type},                                                   $scantronurls{$type},
Line 9381  sub print_scantronformat { Line 4874  sub print_scantronformat {
                         }                          }
                         if (keys(%error) == 0) {                          if (keys(%error) == 0) {
                             $is_custom = 1;                              $is_custom = 1;
                             $confhash{'scantron'}{'scantronformat'} =                              $confhash{'scantron'}{'scantronformat'} = 
                                 $scantronurls{'custom'};                                  $scantronurls{'custom'};
                             my $putresult =                              my $putresult = 
                                 &Apache::lonnet::put_dom('configuration',                                  &Apache::lonnet::put_dom('configuration',
                                                          \%confhash,$dom);                                                           \%confhash,$dom);
                             if ($putresult ne 'ok') {                              if ($putresult ne 'ok') {
                                 $error{'custom'} =                                  $error{'custom'} = 
                                     '<span class="LC_error">'.                                      '<span class="LC_error">'.
                                     &mt('An error occurred updating the domain configuration: [_1]',$putresult).'</span>';                                      &mt('An error occurred updating the domain configuration: [_1]',$putresult).'</span>';
                             }                              }
Line 9497  sub legacy_scantronformat { Line 4990  sub legacy_scantronformat {
     my ($url,$error);      my ($url,$error);
     my @statinfo = &Apache::lonnet::stat_file($newurl);      my @statinfo = &Apache::lonnet::stat_file($newurl);
     if ((!@statinfo) || ($statinfo[0] eq 'no_such_dir')) {      if ((!@statinfo) || ($statinfo[0] eq 'no_such_dir')) {
         my $modified = [];  
         (my $result,$url) =          (my $result,$url) =
             &Apache::lonconfigsettings::publishlogo($r,'copy',$legacyfile,$dom,$confname,              &publishlogo($r,'copy',$legacyfile,$dom,$confname,'scantron',
                                                     'scantron','','',$newfile,$modified);                           '','',$newfile);
         if ($result eq 'ok') {          if ($result ne 'ok') {
             &update_modify_urls($r,$modified);  
         } else {  
             $error = &mt("An error occurred publishing the [_1] bubblesheet format file in RES space. Error was: [_2].",$newfile,$result);              $error = &mt("An error occurred publishing the [_1] bubblesheet format file in RES space. Error was: [_2].",$newfile,$result);
         }          }
     }      }
     return ($url,$error);      return ($url,$error);
 }  }
   
 sub print_scantronconfig {  
     my ($dom,$settings,$rowtotal) = @_;  
     my $itemcount = 2;  
     my $is_checked = ' checked="checked"';  
     my %optionson = (  
                      hdr => ' checked="checked"',  
                      pad => ' checked="checked"',  
                      rem => ' checked="checked"',  
                     );  
     my %optionsoff = (  
                       hdr => '',  
                       pad => '',  
                       rem => '',  
                      );  
     my $currcsvsty = 'none';  
     my ($datatable,%csvfields,%checked,%onclick,%csvoptions);  
     my @fields = &scantroncsv_fields();  
     my %titles = &scantronconfig_titles();  
     if (ref($settings) eq 'HASH') {  
         if (ref($settings->{config}) eq 'HASH') {  
             if ($settings->{config}->{dat}) {  
                 $checked{'dat'} = $is_checked;  
             }  
             if (ref($settings->{config}->{csv}) eq 'HASH') {  
                 if (ref($settings->{config}->{csv}->{fields}) eq 'HASH') {  
                     %csvfields = %{$settings->{config}->{csv}->{fields}};  
                     if (keys(%csvfields) > 0) {  
                         $checked{'csv'} = $is_checked;  
                         $currcsvsty = 'block';  
                     }  
                 }  
                 if (ref($settings->{config}->{csv}->{options}) eq 'HASH') {  
                     %csvoptions = %{$settings->{config}->{csv}->{options}};  
                     foreach my $option (keys(%optionson)) {  
                         unless ($csvoptions{$option}) {  
                             $optionsoff{$option} = $optionson{$option};  
                             $optionson{$option} = '';  
                         }  
                     }  
                 }  
             }  
         } else {  
             $checked{'dat'} = $is_checked;  
         }  
     } else {  
         $checked{'dat'} = $is_checked;  
     }  
     $onclick{'csv'} = ' onclick="toggleScantron(this.form);"';  
     my $css_class = $itemcount%2? ' class="LC_odd_row"':'';  
     $datatable = '<tr '.$css_class.'><td>'.&mt('Supported formats').'</td>'.  
                  '<td class="LC_left_item" valign="top"><span class="LC_nobreak">';  
     foreach my $item ('dat','csv') {  
         my $id;  
         if ($item eq 'csv') {  
             $id = 'id="scantronconfcsv" ';  
         }  
         $datatable .= '<label><input type="checkbox" name="scantronconfig" '.$id.'value="'.$item.'"'.$checked{$item}.$onclick{$item}.' />'.  
                       $titles{$item}.'</label>'.('&nbsp;'x3);  
         if ($item eq 'csv') {  
             $datatable .= '<fieldset style="display:'.$currcsvsty.'" id="scantroncsv_cols">'.  
                           '<legend>'.&mt('CSV Column Mapping').'</legend>'.  
                           '<table><tr><th>'.&mt('Field').'</th><th>'.&mt('Location').'</th></tr>'."\n";  
             foreach my $col (@fields) {  
                 my $selnone;  
                 if ($csvfields{$col} eq '') {  
                     $selnone = ' selected="selected"';  
                 }  
                 $datatable .= '<tr><td>'.$titles{$col}.'</td>'.  
                               '<td><select name="scantronconfig_csv_'.$col.'" class="scantronconfig_csv">'.  
                               '<option value=""'.$selnone.'></option>';  
                 for (my $i=0; $i<20; $i++) {  
                     my $shown = $i+1;  
                     my $sel;  
                     unless ($selnone) {  
                         if (exists($csvfields{$col})) {  
                             if ($csvfields{$col} == $i) {  
                                 $sel = ' selected="selected"';  
                             }  
                         }  
                     }  
                     $datatable .= '<option value="'.$i.'"'.$sel.'>'.$shown.'</option>';  
                 }  
                 $datatable .= '</select></td></tr>';  
            }  
            $datatable .= '</table></fieldset>'.  
                          '<fieldset style="display:'.$currcsvsty.'" id="scantroncsv_options">'.  
                          '<legend>'.&mt('CSV Options').'</legend>';  
            foreach my $option ('hdr','pad','rem') {  
                $datatable .= '<span class="LC_nobreak">'.$titles{$option}.':'.  
                          '<label><input type="radio" name="scantroncsv_'.$option.'" value="1"'.$optionson{$option}.' />'.  
                          &mt('Yes').'</label>'.('&nbsp;'x2)."\n".  
                          '<label><input type="radio" name="scantroncsv_'.$option.'" value="0"'.$optionsoff{$option}.' />'.&mt('No').'</label></span><br />';  
            }  
            $datatable .= '</fieldset>';  
            $itemcount ++;  
         }  
     }  
     $datatable .= '</td></tr>';  
     $$rowtotal ++;  
     return $datatable;  
 }  
   
 sub scantronconfig_titles {  
     return &Apache::lonlocal::texthash(  
                                           dat => 'Standard format (.dat)',  
                                           csv => 'Comma separated values (.csv)',  
                                           hdr => 'Remove first line in file (contains column titles)',  
                                           pad => 'Prepend 0s to PaperID',  
                                           rem => 'Remove leading spaces (except Question Response columns)',  
                                           CODE => 'CODE',  
                                           ID   => 'Student ID',  
                                           PaperID => 'Paper ID',  
                                           FirstName => 'First Name',  
                                           LastName => 'Last Name',  
                                           FirstQuestion => 'First Question Response',  
                                           Section => 'Section',  
     );  
 }  
   
 sub scantroncsv_fields {  
     return ('PaperID','LastName','FirstName','ID','Section','CODE','FirstQuestion');  
 }  
   
 sub print_coursecategories {  sub print_coursecategories {
     my ($position,$dom,$hdritem,$settings,$rowtotal) = @_;      my ($position,$dom,$hdritem,$settings,$rowtotal) = @_;
     my $datatable;      my $datatable;
Line 9675  sub print_coursecategories { Line 5042  sub print_coursecategories {
                              '<input type="radio" name="coursecat_'.$item.'" value="'.$type.'"'.$ischecked.                               '<input type="radio" name="coursecat_'.$item.'" value="'.$type.'"'.$ischecked.
                              ' />'.$lt{$type}.'</label>&nbsp;';                               ' />'.$lt{$type}.'</label>&nbsp;';
            }             }
            $datatable .= '</span></td></tr>';             $datatable .= '</td></tr>';
            $itemcount ++;             $itemcount ++;
         }          }
         $$rowtotal += $itemcount;          $$rowtotal += $itemcount;
Line 9886  sub print_coursecategories { Line 5253  sub print_coursecategories {
                 $datatable .= &initialize_categories($itemcount);                  $datatable .= &initialize_categories($itemcount);
             }              }
         } else {          } else {
             $datatable .= '<tr><td class="LC_right_item">'.$hdritem->{'header'}->[1]->{'col2'}.'</td></tr>'              $datatable .= '<td class="LC_right_item">'.$hdritem->{'header'}->[1]->{'col2'}.'</td>'
                           .&initialize_categories($itemcount);                            .&initialize_categories($itemcount);
         }          }
         $$rowtotal += $itemcount;          $$rowtotal += $itemcount;
Line 9934  sub print_serverstatuses { Line 5301  sub print_serverstatuses {
                       '<span class="LC_nobreak">'.                        '<span class="LC_nobreak">'.
                       '<input type="text" name="'.$type.'_machines" '.                        '<input type="text" name="'.$type.'_machines" '.
                       'value="'.$machineaccess{$type}.'" size="10" />'.                        'value="'.$machineaccess{$type}.'" size="10" />'.
                       '</span></td></tr>'."\n";                        '</td></tr>'."\n";
     }      }
     $$rowtotal += $rownum;      $$rowtotal += $rownum;
     return $datatable;      return $datatable;
Line 9944  sub serverstatus_pages { Line 5311  sub serverstatus_pages {
     return ('userstatus','lonstatus','loncron','server-status','codeversions',      return ('userstatus','lonstatus','loncron','server-status','codeversions',
             'checksums','clusterstatus','metadata_keywords','metadata_harvest',              'checksums','clusterstatus','metadata_keywords','metadata_harvest',
             'takeoffline','takeonline','showenv','toggledebug','ping','domconf',              'takeoffline','takeonline','showenv','toggledebug','ping','domconf',
             'uniquecodes','diskusage','coursecatalog');              'uniquecodes','diskusage');
 }  }
   
 sub defaults_javascript {  sub defaults_javascript {
     my ($settings) = @_;      my ($settings) = @_;
     return unless (ref($settings) eq 'HASH');      return unless (ref($settings) eq 'HASH'); 
     my $portal_js = <<"ENDPORTAL";  
   
 function portalExtras(caller) {  
     var x = caller.value;  
     var y = new Array('email','web');  
     for (var i=0; i<y.length; i++) {  
         if (document.getElementById('portal_def_'+y[i]+'_div')) {  
             var z = document.getElementById('portal_def_'+y[i]+'_div');  
             if (x.length > 0) {  
                 z.style.display = 'block';  
             } else {  
                 z.style.display = 'none';  
             }  
         }  
     }  
 }  
 ENDPORTAL  
     if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {      if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {
         my $maxnum = scalar(@{$settings->{'inststatusorder'}});          my $maxnum = scalar(@{$settings->{'inststatusorder'}});
         if ($maxnum eq '') {          if ($maxnum eq '') {
Line 10020  $jstext Line 5370  $jstext
     return;      return;
 }  }
   
 $portal_js  
   
 // ]]>  // ]]>
 </script>  </script>
   
 ENDSCRIPT  ENDSCRIPT
     } else {  
 return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
 $portal_js  
 // ]]>  
 </script>  
   
 ENDSCRIPT  
     }  
     return;  
 }  
   
 sub passwords_javascript {  
     my ($prefix) = @_;  
     my %intalert;  
     if ($prefix eq 'passwords') {  
         %intalert = &Apache::lonlocal::texthash (  
             authcheck => 'Warning: disallowing login for an authenticated user if the stored cost is less than the default will require a password reset by/for the user.',  
             authcost => 'Warning: bcrypt encryption cost for internal authentication must be an integer.',  
             passmin => 'Warning: minimum password length must be a positive integer greater than 6.',  
             passmax => 'Warning: maximum password length must be a positive integer (or blank).',  
             passnum => 'Warning: number of previous passwords to save must be a positive integer (or blank).',  
         );  
     } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {  
         %intalert = &Apache::lonlocal::texthash (  
             passmin => 'Warning: minimum secret length must be a positive integer greater than 6.',  
             passmax => 'Warning: maximum secret length must be a positive integer (or blank).',  
         );  
     }      }
     &js_escape(\%intalert);  
     my $defmin = $Apache::lonnet::passwdmin;  
     my $intauthjs;  
     if ($prefix eq 'passwords') { $intauthjs = <<"ENDSCRIPT";  
   
 function warnIntAuth(field) {  
     if (field.name == 'intauth_check') {  
         if (field.value == '2') {  
             alert('$intalert{authcheck}');  
         }  
     }  
     if (field.name == 'intauth_cost') {  
         field.value.replace(/\s/g,'');  
         if (field.value != '') {  
             var regexdigit=/^\\d+\$/;  
             if (!regexdigit.test(field.value)) {  
                 alert('$intalert{authcost}');  
             }  
         }  
     }  
     return;  
 }  
   
 ENDSCRIPT  
   
      }  
   
      $intauthjs .= <<"ENDSCRIPT";  
   
 function warnInt$prefix(field) {  
     field.value.replace(/^\s+/,'');  
     field.value.replace(/\s+\$/,'');  
     var regexdigit=/^\\d+\$/;  
     if (field.name == '${prefix}_min') {  
         if (field.value == '') {  
             alert('$intalert{passmin}');  
             field.value = '$defmin';  
         } else {  
             if (!regexdigit.test(field.value)) {  
                 alert('$intalert{passmin}');  
                 field.value = '$defmin';  
             }  
             var minval = parseInt(field.value,10);  
             if (minval < $defmin) {  
                 alert('$intalert{passmin}');  
                 field.value = '$defmin';  
             }  
         }  
     } else {  
         if (field.value == '0') {  
             field.value = '';  
         }  
         if (field.value != '') {  
             if (!regexdigit.test(field.value)) {  
                 if (field.name == '${prefix}_max') {  
                     alert('$intalert{passmax}');  
                 } else {  
                     if (field.name == '${prefix}_numsaved') {  
                         alert('$intalert{passnum}');  
                     }  
                 }  
                 field.value = '';  
             }  
         }  
     }  
     return;  
 }  
   
 ENDSCRIPT  
     return &Apache::lonhtmlcommon::scripttag($intauthjs);  
 }  }
   
 sub coursecategories_javascript {  sub coursecategories_javascript {
Line 10152  sub coursecategories_javascript { Line 5401  sub coursecategories_javascript {
     }      }
     my $instcode_reserved = &mt('The name: [_1] is a reserved category.','"instcode"');      my $instcode_reserved = &mt('The name: [_1] is a reserved category.','"instcode"');
     my $communities_reserved = &mt('The name: [_1] is a reserved category.','"communities"');      my $communities_reserved = &mt('The name: [_1] is a reserved category.','"communities"');
     my $choose_again = "\n".&mt('Please use a different name for the new top level category.');       my $choose_again = '\\n'.&mt('Please use a different name for the new top level category.'); 
     &js_escape(\$instcode_reserved);  
     &js_escape(\$communities_reserved);  
     &js_escape(\$choose_again);  
     $output = <<"ENDSCRIPT";      $output = <<"ENDSCRIPT";
 <script type="text/javascript">  <script type="text/javascript">
 // <![CDATA[  // <![CDATA[
Line 10237  ENDSCRIPT Line 5483  ENDSCRIPT
 sub initialize_categories {  sub initialize_categories {
     my ($itemcount) = @_;      my ($itemcount) = @_;
     my ($datatable,$css_class,$chgstr);      my ($datatable,$css_class,$chgstr);
     my %default_names = &Apache::lonlocal::texthash (      my %default_names = (
                       instcode    => 'Official courses (with institutional codes)',                        instcode    => 'Official courses (with institutional codes)',
                       communities => 'Communities',                        communities => 'Communities',
                         );                          );
Line 10245  sub initialize_categories { Line 5491  sub initialize_categories {
     my $select1 = '';      my $select1 = '';
     foreach my $default ('instcode','communities') {      foreach my $default ('instcode','communities') {
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','0'".');"';          $chgstr = ' onchange="javascript:reorderCats(this.form,'."'',$default"."_pos','0'".');"';
         if ($default eq 'communities') {          if ($default eq 'communities') {
             $select1 = $select0;              $select1 = $select0;
             $select0 = '';              $select0 = '';
Line 10270  sub initialize_categories { Line 5516  sub initialize_categories {
                   .'<option value="0">1</option>'                    .'<option value="0">1</option>'
                   .'<option value="1">2</option>'                    .'<option value="1">2</option>'
                   .'<option value="2" selected="selected">3</option></select>&nbsp;'                    .'<option value="2" selected="selected">3</option></select>&nbsp;'
                   .&mt('Add category').'</span></td><td><span class="LC_nobreak">'.&mt('Name:')                    .&mt('Add category').'</td><td>'.&mt('Name:')
                   .'&nbsp;<input type="text" size="20" name="addcategory_name" value="" /></span>'                    .'&nbsp;<input type="text" size="20" name="addcategory_name" value="" /></td></tr>';
                   .'</td></tr>';  
     return $datatable;      return $datatable;
 }  }
   
Line 10327  sub build_category_rows { Line 5572  sub build_category_rows {
                             pop(@{$path});                              pop(@{$path});
                         }                          }
                     } else {                      } else {
                         $text .= &mt('Add subcategory:').'&nbsp;</span><input type="text" size="20" name="addcategory_name_';                          $text .= &mt('Add subcategory:').'&nbsp;</span><input type="textbox" size="20" name="addcategory_name_';
                         if ($j == $numchildren) {                          if ($j == $numchildren) {
                             $text .= $name;                              $text .= $name;
                         } else {                          } else {
Line 10350  sub build_category_rows { Line 5595  sub build_category_rows {
                 my $colspan;                  my $colspan;
                 if ($parent ne 'instcode') {                  if ($parent ne 'instcode') {
                     $colspan = $maxdepth - $depth - 1;                      $colspan = $maxdepth - $depth - 1;
                     $text .= '<td colspan="'.$colspan.'">'.&mt('Add subcategory:').'<input type="text" size="20" name="subcat_'.$name.'" value="" /></td>';                      $text .= '<td colspan="'.$colspan.'">'.&mt('Add subcategory:').'<input type="textbox" size="20" name="subcat_'.$name.'" value="" /></td>';
                 }                  }
             }              }
         }          }
Line 10359  sub build_category_rows { Line 5604  sub build_category_rows {
 }  }
   
 sub modifiable_userdata_row {  sub modifiable_userdata_row {
     my ($context,$item,$settings,$numinrow,$rowcount,$usertypes,$fieldsref,$titlesref,      my ($context,$item,$settings,$numinrow,$rowcount,$usertypes,$fieldsref,$titlesref) = @_;
         $rowid,$customcss,$rowstyle,$itemdesc) = @_;  
     my ($role,$rolename,$statustype);      my ($role,$rolename,$statustype);
     $role = $item;      $role = $item;
     if ($context eq 'cancreate') {      if ($context eq 'cancreate') {
         if ($item =~ /^(emailusername)_(.+)$/) {          if ($item =~ /^emailusername_(.+)$/) {
             $role = $1;              $statustype = $1;
             $statustype = $2;              $role = 'emailusername';
             if (ref($usertypes) eq 'HASH') {              if (ref($usertypes) eq 'HASH') {
                 if ($usertypes->{$statustype}) {                  if ($usertypes->{$statustype}) {
                     $rolename = &mt('Data provided by [_1]',$usertypes->{$statustype});                      $rolename = &mt('Data provided by [_1]',$usertypes->{$statustype});
Line 10381  sub modifiable_userdata_row { Line 5625  sub modifiable_userdata_row {
         } else {          } else {
             $rolename = $role;              $rolename = $role;
         }          }
     } elsif ($context eq 'lti') {  
         $rolename = &mt('Institutional data used (if available)');  
     } else {      } else {
         if ($role eq 'cr') {          if ($role eq 'cr') {
             $rolename = &mt('Custom role');              $rolename = &mt('Custom role');
Line 10403  sub modifiable_userdata_row { Line 5645  sub modifiable_userdata_row {
         %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();          %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
     }      }
     my $output;      my $output;
     my $css_class;      my $css_class = $rowcount%2?' class="LC_odd_row"':'';
     if ($rowcount%2) {      $output = '<tr '.$css_class.'>'.
         $css_class = 'LC_odd_row';  
     }  
     if ($customcss) {  
         $css_class .= " $customcss";  
     }  
     $css_class =~ s/^\s+//;  
     if ($css_class) {  
         $css_class = ' class="'.$css_class.'"';  
     }  
     if ($rowstyle) {  
         $css_class .= ' style="'.$rowstyle.'"';  
     }  
     if ($rowid) {  
         $rowid = ' id="'.$rowid.'"';  
     }  
     $output = '<tr '.$css_class.$rowid.'>'.  
               '<td><span class="LC_nobreak">'.$rolename.'</span></td>'.                '<td><span class="LC_nobreak">'.$rolename.'</span></td>'.
               '<td class="LC_left_item" colspan="2"><table>';                '<td class="LC_left_item" colspan="2"><table>';
     my $rem;      my $rem;
     my %checks;      my %checks;
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         my $hashref;          if (ref($settings->{$context}) eq 'HASH') {
         if ($context eq 'lti') {  
             if (ref($settings) eq 'HASH') {  
                 $hashref = $settings->{'instdata'};  
             }  
         } elsif (ref($settings->{$context}) eq 'HASH') {  
             if (ref($settings->{$context}->{$role}) eq 'HASH') {              if (ref($settings->{$context}->{$role}) eq 'HASH') {
                 $hashref = $settings->{'lti_instdata'};                  my $hashref = $settings->{$context}->{$role};
             }                  if ($role eq 'emailusername') {
             if ($role eq 'emailusername') {                      if ($statustype) {
                 if ($statustype) {                          if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') {
                     if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') {                              $hashref = $settings->{$context}->{$role}->{$statustype};
                         $hashref = $settings->{$context}->{$role}->{$statustype};                              if (ref($hashref) eq 'HASH') { 
                                   foreach my $field (@fields) {
                                       if ($hashref->{$field}) {
                                           $checks{$field} = $hashref->{$field};
                                       }
                                   }
                               }
                           }
                     }                      }
                 }                  } else {
             }                      if (ref($hashref) eq 'HASH') {
         }                          foreach my $field (@fields) {
         if (ref($hashref) eq 'HASH') {                              if ($hashref->{$field}) {
             foreach my $field (@fields) {                                  $checks{$field} = ' checked="checked" ';
                 if ($hashref->{$field}) {                              }
                     if ($role eq 'emailusername') {                          }
                         $checks{$field} = $hashref->{$field};  
                     } else {  
                         $checks{$field} = ' checked="checked" ';  
                     }                      }
                 }                  }
             }              }
         }          }
     }      }
     my $total = scalar(@fields);       
     for (my $i=0; $i<$total; $i++) {      for (my $i=0; $i<@fields; $i++) {
         $rem = $i%($numinrow);          my $rem = $i%($numinrow);
         if ($rem == 0) {          if ($rem == 0) {
             if ($i > 0) {              if ($i > 0) {
                 $output .= '</tr>';                  $output .= '</tr>';
Line 10467  sub modifiable_userdata_row { Line 5692  sub modifiable_userdata_row {
         my $check = ' ';          my $check = ' ';
         unless ($role eq 'emailusername') {          unless ($role eq 'emailusername') {
             if (exists($checks{$fields[$i]})) {              if (exists($checks{$fields[$i]})) {
                 $check = $checks{$fields[$i]};                  $check = $checks{$fields[$i]}
             } elsif ($context ne 'lti') {              } else {
                 if ($role eq 'st') {                  if ($role eq 'st') {
                     if (ref($settings) ne 'HASH') {                      if (ref($settings) ne 'HASH') {
                         $check = ' checked="checked" ';                           $check = ' checked="checked" '; 
Line 10478  sub modifiable_userdata_row { Line 5703  sub modifiable_userdata_row {
         }          }
         $output .= '<td class="LC_left_item">'.          $output .= '<td class="LC_left_item">'.
                    '<span class="LC_nobreak">';                     '<span class="LC_nobreak">';
         my $prefix = 'canmodify';  
         if ($role eq 'emailusername') {          if ($role eq 'emailusername') {
             unless ($checks{$fields[$i]} =~ /^(required|optional)$/) {              unless ($checks{$fields[$i]} =~ /^(required|optional)$/) {
                 $checks{$fields[$i]} = 'omit';                  $checks{$fields[$i]} = 'omit';
Line 10489  sub modifiable_userdata_row { Line 5713  sub modifiable_userdata_row {
                     $checked='checked="checked" ';                      $checked='checked="checked" ';
                 }                  }
                 $output .= '<label>'.                  $output .= '<label>'.
                            '<input type="radio" name="'.$prefix.'_'.$item.'_'.$fields[$i].'" value="'.$option.'" '.$checked.'/>'.                             '<input type="radio" name="canmodify_'.$item.'_'.$fields[$i].'" value="'.$option.'" '.$checked.'/>'.
                            &mt($option).'</label>'.('&nbsp;' x2);                             &mt($option).'</label>'.('&nbsp;' x2);
             }              }
             $output .= '<i>'.$fieldtitles{$fields[$i]}.'</i>';              $output .= '<i>'.$fieldtitles{$fields[$i]}.'</i>';
         } else {          } else {
             if ($context eq 'lti') {  
                 $prefix = 'lti';  
             }  
             $output .= '<label>'.              $output .= '<label>'.
                        '<input type="checkbox" name="'.$prefix.'_'.$role.'" '.                         '<input type="checkbox" name="canmodify_'.$role.'" '.
                        'value="'.$fields[$i].'"'.$check.'/>'.$fieldtitles{$fields[$i]}.                         'value="'.$fields[$i].'"'.$check.'/>'.$fieldtitles{$fields[$i]}.
                        '</label>';                         '</label>';
         }          }
         $output .= '</span></td>';          $output .= '</span></td>';
           $rem = @fields%($numinrow);
     }      }
     $rem = $total%$numinrow;      my $colsleft = $numinrow - $rem;
     my $colsleft;      if ($colsleft > 1 ) {
     if ($rem) {  
         $colsleft = $numinrow - $rem;  
     }  
     if ($colsleft > 1) {  
         $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.          $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
                    '&nbsp;</td>';                     '&nbsp;</td>';
     } elsif ($colsleft == 1) {      } elsif ($colsleft == 1) {
Line 10520  sub modifiable_userdata_row { Line 5738  sub modifiable_userdata_row {
 }  }
   
 sub insttypes_row {  sub insttypes_row {
     my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rowtotal,$onclick,      my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rownum) = @_;
         $customcss,$rowstyle) = @_;  
     my %lt = &Apache::lonlocal::texthash (      my %lt = &Apache::lonlocal::texthash (
                       cansearch => 'Users allowed to search',                        cansearch => 'Users allowed to search',
                       statustocreate => 'Institutional affiliation(s) able to create own account (login/SSO)',                        statustocreate => 'Institutional affiliation(s) able to create own account (login/SSO)',
                       lockablenames => 'User preference to lock name',                        lockablenames => 'User preference to lock name',
                       selfassign    => 'Self-reportable affiliations',  
                       overrides     => "Override domain's helpdesk settings based on requester's affiliation",  
              );               );
     my $showdom;      my $showdom;
     if ($context eq 'cansearch') {      if ($context eq 'cansearch') {
Line 10537  sub insttypes_row { Line 5752  sub insttypes_row {
     if ($context eq 'statustocreate') {      if ($context eq 'statustocreate') {
         $class = 'LC_right_item';          $class = 'LC_right_item';
     }      }
     my $css_class;      my $css_class = ' class="LC_odd_row"';
     if ($$rowtotal%2) {      if ($rownum ne '') { 
         $css_class = 'LC_odd_row';          $css_class = ($rownum%2? ' class="LC_odd_row"':'');
     }  
     if ($customcss) {  
         $css_class .= ' '.$customcss;  
     }  
     $css_class =~ s/^\s+//;  
     if ($css_class) {  
         $css_class = ' class="'.$css_class.'"';  
     }  
     if ($rowstyle) {  
         $css_class .= ' style="'.$rowstyle.'"';  
     }  
     if ($onclick) {  
         $onclick = 'onclick="'.$onclick.'" ';  
     }      }
     my $output = '<tr'.$css_class.'>'.      my $output = '<tr'.$css_class.'>'.
                  '<td>'.$lt{$context}.$showdom.                   '<td>'.$lt{$context}.$showdom.
Line 10574  sub insttypes_row { Line 5776  sub insttypes_row {
                         if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) {                          if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) {
                             $check = ' checked="checked" ';                              $check = ' checked="checked" ';
                         }                          }
                     } elsif (ref($settings->{$context}) eq 'HASH') {  
                         if (ref($settings->{$context}->{$types->[$i]}) eq 'HASH') {  
                             $check = ' checked="checked" ';  
                         }  
                     } elsif ($context eq 'statustocreate') {                      } elsif ($context eq 'statustocreate') {
                         $check = ' checked="checked" ';                          $check = ' checked="checked" ';
                     }                      }
Line 10585  sub insttypes_row { Line 5783  sub insttypes_row {
                 $output .= '<td class="LC_left_item">'.                  $output .= '<td class="LC_left_item">'.
                            '<span class="LC_nobreak"><label>'.                             '<span class="LC_nobreak"><label>'.
                            '<input type="checkbox" name="'.$context.'" '.                             '<input type="checkbox" name="'.$context.'" '.
                            'value="'.$types->[$i].'"'.$check.$onclick.' />'.                             'value="'.$types->[$i].'"'.$check.'/>'.
                            $usertypes->{$types->[$i]}.'</label></span></td>';                             $usertypes->{$types->[$i]}.'</label></span></td>';
             }              }
         }          }
         $rem = @{$types}%($numinrow);          $rem = @{$types}%($numinrow);
     }      }
     my $colsleft = $numinrow - $rem;      my $colsleft = $numinrow - $rem;
     if ($context eq 'overrides') {      if (($rem == 0) && (@{$types} > 0)) {
         if ($colsleft > 1) {          $output .= '<tr>';
             $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">';      }
         } else {      if ($colsleft > 1) {
             $output .= '<td class="LC_left_item">';          $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">';
         }  
         $output .= '&nbsp;';  
     } else {      } else {
         if ($rem == 0) {          $output .= '<td class="LC_left_item">';
             $output .= '<tr>';      }
         }      my $defcheck = ' ';
         if ($colsleft > 1) {      if (ref($settings) eq 'HASH') {  
             $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">';          if (ref($settings->{$context}) eq 'ARRAY') {
         } else {              if (grep(/^default$/,@{$settings->{$context}})) {
             $output .= '<td class="LC_left_item">';  
         }  
         my $defcheck = ' ';  
         if (ref($settings) eq 'HASH') {    
             if (ref($settings->{$context}) eq 'ARRAY') {  
                 if (grep(/^default$/,@{$settings->{$context}})) {  
                     $defcheck = ' checked="checked" ';  
                 }  
             } elsif ($context eq 'statustocreate') {  
                 $defcheck = ' checked="checked" ';                  $defcheck = ' checked="checked" ';
             }              }
           } elsif ($context eq 'statustocreate') {
               $defcheck = ' checked="checked" ';
         }          }
         $output .= '<span class="LC_nobreak"><label>'.  
                    '<input type="checkbox" name="'.$context.'" '.  
                    'value="default"'.$defcheck.$onclick.' />'.  
                    $othertitle.'</label></span>';  
     }      }
     $output .= '</td></tr></table></td></tr>';      $output .= '<span class="LC_nobreak"><label>'.
                  '<input type="checkbox" name="'.$context.'" '.
                  'value="default"'.$defcheck.'/>'.
                  $othertitle.'</label></span></td>'.
                  '</tr></table></td></tr>';
     return $output;      return $output;
 }  }
   
Line 10700  sub usertype_update_row { Line 5889  sub usertype_update_row {
 sub modify_login {  sub modify_login {
     my ($r,$dom,$confname,$lastactref,%domconfig) = @_;      my ($r,$dom,$confname,$lastactref,%domconfig) = @_;
     my ($resulttext,$errors,$colchgtext,%changes,%colchanges,%newfile,%newurl,      my ($resulttext,$errors,$colchgtext,%changes,%colchanges,%newfile,%newurl,
         %curr_loginvia,%loginhash,@currlangs,@newlangs,$addedfile,%title,@offon,          %curr_loginvia,%loginhash,@currlangs,@newlangs,$addedfile,%title,@offon);
         %currsaml,%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlwindow,%samlnotsso);  
     %title = ( coursecatalog => 'Display course catalog',      %title = ( coursecatalog => 'Display course catalog',
                adminmail => 'Display administrator E-mail address',                 adminmail => 'Display administrator E-mail address',
                helpdesk  => 'Display "Contact Helpdesk" link',                 helpdesk  => 'Display "Contact Helpdesk" link',
                newuser => 'Link for visitors to create a user account',                 newuser => 'Link for visitors to create a user account',
                loginheader => 'Log-in box header',                 loginheader => 'Log-in box header');
                saml => 'Dual SSO and non-SSO login');  
     @offon = ('off','on');      @offon = ('off','on');
     if (ref($domconfig{login}) eq 'HASH') {      if (ref($domconfig{login}) eq 'HASH') {
         if (ref($domconfig{login}{loginvia}) eq 'HASH') {          if (ref($domconfig{login}{loginvia}) eq 'HASH') {
Line 10715  sub modify_login { Line 5902  sub modify_login {
                 $curr_loginvia{$lonhost} = $domconfig{login}{loginvia}{$lonhost};                  $curr_loginvia{$lonhost} = $domconfig{login}{loginvia}{$lonhost};
             }              }
         }          }
         if (ref($domconfig{login}{'saml'}) eq 'HASH') {  
             foreach my $lonhost (keys(%{$domconfig{login}{'saml'}})) {  
                 if (ref($domconfig{login}{'saml'}{$lonhost}) eq 'HASH') {  
                     $currsaml{$lonhost} = $domconfig{login}{'saml'}{$lonhost};  
                     $saml{$lonhost} = 1;  
                     $samltext{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'text'};  
                     $samlurl{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'url'};  
                     $samlalt{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'alt'};  
                     $samlimg{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'img'};  
                     $samltitle{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'title'};  
                     $samlwindow{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'window'};  
                     $samlnotsso{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'notsso'};  
                 }  
             }  
         }  
     }      }
     ($errors,%colchanges) = &modify_colors($r,$dom,$confname,['login'],      ($errors,%colchanges) = &modify_colors($r,$dom,$confname,['login'],
                                            \%domconfig,\%loginhash);                                             \%domconfig,\%loginhash);
Line 10868  sub modify_login { Line 6040  sub modify_login {
                 if ($addedfile ne '') {                  if ($addedfile ne '') {
                     push(@allnew,$addedfile);                      push(@allnew,$addedfile);
                 }                  }
                 my $modified = [];  
                 foreach my $lang (@allnew) {                  foreach my $lang (@allnew) {
                     my $formelem = 'loginhelpurl_'.$lang;                      my $formelem = 'loginhelpurl_'.$lang;
                     if ($lang eq $env{'form.loginhelpurl_add_lang'}) {                      if ($lang eq $env{'form.loginhelpurl_add_lang'}) {
                         $formelem = 'loginhelpurl_add_file';                          $formelem = 'loginhelpurl_add_file';
                     }                      }
                     (my $result,$newurl{$lang}) =                      (my $result,$newurl{$lang}) = &publishlogo($r,'upload',$formelem,$dom,$confname,
                         &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,                                                                 "help/$lang",'','',$newfile{$lang});
                                                                 "help/$lang",'','',$newfile{$lang},  
                                                                 $modified);  
                     if ($result eq 'ok') {                      if ($result eq 'ok') {
                         $loginhash{'login'}{'helpurl'}{$lang} = $newurl{$lang};                          $loginhash{'login'}{'helpurl'}{$lang} = $newurl{$lang};
                         $changes{'helpurl'}{$lang} = 1;                          $changes{'helpurl'}{$lang} = 1;
Line 10890  sub modify_login { Line 6059  sub modify_login {
                         }                          }
                     }                      }
                 }                  }
                 &update_modify_urls($r,$modified);  
             } else {              } else {
                 $error = &mt("Upload of custom log-in help file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);                  $error = &mt("Upload of custom log-in help file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);
             }              }
Line 10910  sub modify_login { Line 6078  sub modify_login {
                 if ($domservers{$lonhost}) {                  if ($domservers{$lonhost}) {
                     if (ref($domconfig{'login'}{'headtag'}{$lonhost}) eq 'HASH') {                      if (ref($domconfig{'login'}{'headtag'}{$lonhost}) eq 'HASH') {
                         $currheadtagurls{$lonhost} = $domconfig{'login'}{'headtag'}{$lonhost}{'url'};                          $currheadtagurls{$lonhost} = $domconfig{'login'}{'headtag'}{$lonhost}{'url'};
                         $currexempt{$lonhost} = $domconfig{'login'}{'headtag'}{$lonhost}{'exempt'};                          $currexempt{$lonhost} = $domconfig{'login'}{'headtagexempt'}{$lonhost}{'exempt'}
                     }                      }
                 }                  }
             }              }
Line 10929  sub modify_login { Line 6097  sub modify_login {
             } elsif ($currheadtagurls{$lonhost}) {              } elsif ($currheadtagurls{$lonhost}) {
                 $loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $currheadtagurls{$lonhost};                  $loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $currheadtagurls{$lonhost};
                 if ($currexempt{$lonhost}) {                  if ($currexempt{$lonhost}) {
                     if ((!exists($possexempt{$lonhost})) || ($possexempt{$lonhost} ne $currexempt{$lonhost})) {                      if ((!exists($possexempt{$lonhost})) || ($possexempt{$lonhost} ne $currexempt{$lonhost})) { 
                         $changes{'headtag'}{$lonhost} = 1;                          $changes{'headtag'}{$lonhost} = 1;
                     }                      }
                 } elsif ($possexempt{$lonhost}) {                  } elsif ($possexempt{$lonhost}) {
Line 10948  sub modify_login { Line 6116  sub modify_login {
             if ($switchserver) {              if ($switchserver) {
                 $error = &mt("Upload of custom markup is not permitted to this server: [_1]",$switchserver);                  $error = &mt("Upload of custom markup is not permitted to this server: [_1]",$switchserver);
             } elsif ($author_ok eq 'ok') {              } elsif ($author_ok eq 'ok') {
                 my $modified = [];  
                 foreach my $lonhost (@newhosts) {                  foreach my $lonhost (@newhosts) {
                     my $formelem = 'loginheadtag_'.$lonhost;                      my $formelem = 'loginheadtag_'.$lonhost;
                     (my $result,$newheadtagurls{$lonhost}) =                      (my $result,$newheadtagurls{$lonhost}) = &publishlogo($r,'upload',$formelem,$dom,$confname,
                         &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,                                                                            "login/headtag/$lonhost",'','',
                                                                 "login/headtag/$lonhost",'','',                                                                            $env{'form.loginheadtag_'.$lonhost.'.filename'});
                                                                 $env{'form.loginheadtag_'.$lonhost.'.filename'},  
                                                                 $modified);  
                     if ($result eq 'ok') {                      if ($result eq 'ok') {
                         $loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $newheadtagurls{$lonhost};                          $loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $newheadtagurls{$lonhost};
                         $changes{'headtag'}{$lonhost} = 1;                          $changes{'headtag'}{$lonhost} = 1;
Line 10972  sub modify_login { Line 6137  sub modify_login {
                         }                          }
                     }                      }
                 }                  }
                 &update_modify_urls($r,$modified);  
             } else {              } else {
                 $error = &mt("Upload of custom markup file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);                  $error = &mt("Upload of custom markup file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);
             }              }
Line 10984  sub modify_login { Line 6148  sub modify_login {
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';              $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
         }          }
     }      }
     my @delsamlimg = &Apache::loncommon::get_env_multiple('form.saml_img_del');  
     my @newsamlimgs;  
     foreach my $lonhost (keys(%domservers)) {  
         if ($env{'form.saml_'.$lonhost}) {  
             if ($env{'form.saml_img_'.$lonhost.'.filename'}) {  
                 push(@newsamlimgs,$lonhost);  
             }  
             foreach my $item ('text','alt','url','title','window','notsso') {  
                 $env{'form.saml_'.$item.'_'.$lonhost} =~ s/^\s+|\s+$//g;  
             }  
             if ($saml{$lonhost}) {  
                 if ($env{'form.saml_window_'.$lonhost} ne '1') {  
                     $env{'form.saml_window_'.$lonhost} = '';  
                 }  
                 if (grep(/^\Q$lonhost\E$/,@delsamlimg)) {  
 #FIXME Need to obsolete published image  
                     delete($currsaml{$lonhost}{'img'});  
                     $changes{'saml'}{$lonhost} = 1;  
                 }  
                 if ($env{'form.saml_alt_'.$lonhost} ne $samlalt{$lonhost}) {  
                     $changes{'saml'}{$lonhost} = 1;  
                 }  
                 if ($env{'form.saml_text_'.$lonhost} ne $samltext{$lonhost}) {  
                     $changes{'saml'}{$lonhost} = 1;  
                 }  
                 if ($env{'form.saml_url_'.$lonhost} ne $samlurl{$lonhost}) {  
                     $changes{'saml'}{$lonhost} = 1;  
                 }  
                 if ($env{'form.saml_title_'.$lonhost} ne $samltitle{$lonhost}) {  
                     $changes{'saml'}{$lonhost} = 1;  
                 }  
                 if ($env{'form.saml_window_'.$lonhost} ne $samlwindow{$lonhost}) {  
                     $changes{'saml'}{$lonhost} = 1;  
                 }  
                 if ($env{'form.saml_notsso_'.$lonhost} ne $samlnotsso{$lonhost}) {  
                     $changes{'saml'}{$lonhost} = 1;  
                 }  
             } else {  
                 $changes{'saml'}{$lonhost} = 1;  
             }  
             foreach my $item ('text','alt','url','title','window','notsso') {  
                 $currsaml{$lonhost}{$item} = $env{'form.saml_'.$item.'_'.$lonhost};  
             }  
         } else {  
             if ($saml{$lonhost}) {  
                 $changes{'saml'}{$lonhost} = 1;  
                 delete($currsaml{$lonhost});  
             }  
         }  
     }  
     foreach my $posshost (keys(%currsaml)) {  
         unless (exists($domservers{$posshost})) {  
             delete($currsaml{$posshost});  
         }  
     }  
     %{$loginhash{'login'}{'saml'}} = %currsaml;  
     if (@newsamlimgs) {  
         my $error;  
         my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);  
         if ($configuserok eq 'ok') {  
             if ($switchserver) {  
                 $error = &mt("Upload of SSO Button Image is not permitted to this server: [_1].",$switchserver);  
             } elsif ($author_ok eq 'ok') {  
                 my $modified = [];  
                 foreach my $lonhost (@newsamlimgs) {  
                     my $formelem = 'saml_img_'.$lonhost;  
                     my ($result,$imgurl) =  
                         &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,  
                                                                 "login/saml/$lonhost",'','',  
                                                                 $env{'form.saml_img_'.$lonhost.'.filename'},  
                                                                 $modified);  
                     if ($result eq 'ok') {  
                         $currsaml{$lonhost}{'img'} = $imgurl;  
                         $loginhash{'login'}{'saml'}{$lonhost}{'img'} = $imgurl;  
                         $changes{'saml'}{$lonhost} = 1;  
                     } else {  
                         my $puberror = &mt("Upload of SSO button image failed for [_1] because an error occurred publishing the file in RES space. Error was: [_2].",  
                                            $lonhost,$result);  
                         $errors .= '<li><span class="LC_error">'.$puberror.'</span></li>';  
                     }  
                 }  
                 &update_modify_urls($r,$modified);  
             } else {  
                 $error = &mt("Upload of SSO button image file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);  
             }  
         } else {  
             $error = &mt("Upload of SSO button image file(s) failed because a Domain Configuration user ([_1]) could not be created in domain: [_2].  Error was: [_3].",$confname,$dom,$configuserok);  
         }  
         if ($error) {  
             &Apache::lonnet::logthis($error);  
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';  
         }  
     }  
     &process_captcha('login',\%changes,$loginhash{'login'},$domconfig{'login'});      &process_captcha('login',\%changes,$loginhash{'login'},$domconfig{'login'});
   
     my $defaulthelpfile = '/adm/loginproblems.html';      my $defaulthelpfile = '/adm/loginproblems.html';
Line 11117  sub modify_login { Line 6188  sub modify_login {
         }          }
         if (keys(%changes) > 0 || $colchgtext) {          if (keys(%changes) > 0 || $colchgtext) {
             &Apache::loncommon::devalidate_domconfig_cache($dom);              &Apache::loncommon::devalidate_domconfig_cache($dom);
             if (exists($changes{'saml'})) {  
                 my $hostid_in_use;  
                 my @hosts = &Apache::lonnet::current_machine_ids();  
                 if (@hosts > 1) {  
                     foreach my $hostid (@hosts) {  
                         if (&Apache::lonnet::host_domain($hostid) eq $dom) {  
                             $hostid_in_use = $hostid;  
                             last;  
                         }  
                     }  
                 } else {  
                     $hostid_in_use = $r->dir_config('lonHostID');  
                 }  
                 if (($hostid_in_use) &&  
                     (&Apache::lonnet::host_domain($hostid_in_use) eq $dom)) {  
                     &Apache::lonnet::devalidate_cache_new('samllanding',$hostid_in_use);  
                 }  
                 if (ref($lastactref) eq 'HASH') {  
                     if (ref($changes{'saml'}) eq 'HASH') {  
                         my %updates;  
                         map { $updates{$_} = 1; } keys(%{$changes{'saml'}});  
                         $lastactref->{'samllanding'} = \%updates;  
                     }  
                 }  
             }  
             if (ref($lastactref) eq 'HASH') {              if (ref($lastactref) eq 'HASH') {
                 $lastactref->{'domainconfig'} = 1;                  $lastactref->{'domainconfig'} = 1;
             }              }
Line 11221  sub modify_login { Line 6267  sub modify_login {
                             }                              }
                         }                          }
                     }                      }
                 } elsif ($item eq 'saml') {  
                     if (ref($changes{$item}) eq 'HASH') {  
                         my %notlt = (  
                                        text   => 'Text for log-in by SSO',  
                                        img    => 'SSO button image',  
                                        alt    => 'Alt text for button image',  
                                        url    => 'SSO URL',  
                                        title  => 'Tooltip for SSO link',  
                                        window => 'Pop-up window if iframe',  
                                        notsso => 'Text for non-SSO log-in',  
                                     );  
                         foreach my $lonhost (sort(keys(%{$changes{$item}}))) {  
                             if (ref($currsaml{$lonhost}) eq 'HASH') {  
                                 $resulttext .= '<li>'.&mt("$title{$item} in use for [_1]","<b>$lonhost</b>").  
                                                '<ul>';  
                                 foreach my $key ('text','img','alt','url','title','window','notsso') {  
                                     if ($currsaml{$lonhost}{$key} eq '') {  
                                         $resulttext .= '<li>'.&mt("$notlt{$key} not in use").'</li>';  
                                     } else {  
                                         my $value = "'$currsaml{$lonhost}{$key}'";  
                                         if ($key eq 'img') {  
                                             $value = '<img src="'.$currsaml{$lonhost}{$key}.'" />';  
                                         } elsif ($key eq 'window') {  
                                             $value = 'On';  
                                         }  
                                         $resulttext .= '<li>'.&mt("$notlt{$key} set to: [_1]",  
                                                                   $value).'</li>';  
                                     }  
                                 }  
                                 $resulttext .= '</ul></li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt("$title{$item} not in use for [_1]",$lonhost).'</li>';  
                             }  
                         }  
                     }  
                 } elsif ($item eq 'captcha') {                  } elsif ($item eq 'captcha') {
                     if (ref($loginhash{'login'}) eq 'HASH') {                      if (ref($loginhash{'login'}) eq 'HASH') {
                         my $chgtxt;                          my $chgtxt;
Line 11292  sub modify_login { Line 6303  sub modify_login {
                         $chgtxt .= '</ul>';                          $chgtxt .= '</ul>';
                         $resulttext .= '<li>'.$chgtxt.'</li>';                          $resulttext .= '<li>'.$chgtxt.'</li>';
                     }                      }
                 } elsif ($item eq 'recaptchaversion') {  
                     if (ref($loginhash{'login'}) eq 'HASH') {  
                         if ($loginhash{'login'}{'captcha'} eq 'recaptcha') {  
                             $resulttext .= '<li>'.&mt('ReCAPTCHA for helpdesk form set to version [_1]',$loginhash{'login'}{'recaptchaversion'}).  
                                            '</li>';  
                         }  
                     }  
                 } else {                  } else {
                     $resulttext .= '<li>'.&mt("$title{$item} set to $offon[$env{'form.'.$item}]").'</li>';                      $resulttext .= '<li>'.&mt("$title{$item} set to $offon[$env{'form.'.$item}]").'</li>';
                 }                  }
Line 11318  sub modify_login { Line 6322  sub modify_login {
     return $resulttext;      return $resulttext;
 }  }
   
   
 sub check_exempt_addresses {  sub check_exempt_addresses {
     my ($iplist) = @_;      my ($iplist) = @_;
     $iplist =~ s/^\s+//;      $iplist =~ s/^\s+//;
Line 11358  sub color_font_choices { Line 6363  sub color_font_choices {
     return %choices;      return %choices;
 }  }
   
 sub modify_ipaccess {  
     my ($dom,$lastactref,%domconfig) = @_;  
     my (@allpos,%changes,%confhash,$errors,$resulttext);  
     my (@items,%deletions,%itemids,@warnings);  
     my ($typeorder,$types) = &commblocktype_text();  
     if ($env{'form.ipaccess_add'}) {  
         my $name = $env{'form.ipaccess_name_add'};  
         my ($newid,$error) = &get_ipaccess_id($dom,$name);  
         if ($newid) {  
             $itemids{'add'} = $newid;  
             push(@items,'add');  
             $changes{$newid} = 1;  
         } else {  
             $error = &mt('Failed to acquire unique ID for new IP access control item');  
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';  
         }  
     }  
     if (ref($domconfig{'ipaccess'}) eq 'HASH') {  
         my @todelete = &Apache::loncommon::get_env_multiple('form.ipaccess_del');  
         if (@todelete) {  
             map { $deletions{$_} = 1; } @todelete;  
         }  
         my $maxnum = $env{'form.ipaccess_maxnum'};  
         for (my $i=0; $i<$maxnum; $i++) {  
             my $itemid = $env{'form.ipaccess_id_'.$i};  
             $itemid =~ s/\D+//g;  
             if (ref($domconfig{'ipaccess'}{$itemid}) eq 'HASH') {  
                 if ($deletions{$itemid}) {  
                     $changes{$itemid} = $domconfig{'ipaccess'}{$itemid}{'name'};  
                 } else {  
                     push(@items,$i);  
                     $itemids{$i} = $itemid;  
                 }  
             }  
         }  
     }  
     foreach my $idx (@items) {  
         my $itemid = $itemids{$idx};  
         next unless ($itemid);  
         my %current;  
         unless ($idx eq 'add') {  
             if (ref($domconfig{'ipaccess'}{$itemid}) eq 'HASH') {  
                 %current = %{$domconfig{'ipaccess'}{$itemid}};  
             }  
         }  
         my $position = $env{'form.ipaccess_pos_'.$itemid};  
         $position =~ s/\D+//g;  
         if ($position ne '') {  
             $allpos[$position] = $itemid;  
         }  
         my $name = $env{'form.ipaccess_name_'.$idx};  
         $name =~ s/^\s+|\s+$//g;  
         $confhash{$itemid}{'name'} = $name;  
         my $possrange = $env{'form.ipaccess_range_'.$idx};  
         $possrange =~ s/^\s+|\s+$//g;  
         unless ($possrange eq '') {  
             $possrange =~ s/[\r\n]+/\s/g;  
             $possrange =~ s/\s*-\s*/-/g;  
             $possrange =~ s/\s+/,/g;  
             $possrange =~ s/,+/,/g;  
             if ($possrange ne '') {  
                 my (@ok,$count);  
                 $count = 0;  
                 foreach my $poss (split(/\,/,$possrange)) {  
                     $count ++;  
                     $poss = &validate_ip_pattern($poss);  
                     if ($poss ne '') {  
                         push(@ok,$poss);  
                     }  
                 }  
                 my $diff = $count - scalar(@ok);  
                 if ($diff) {  
                     $errors .= '<li><span class="LC_error">'.  
                                &mt('[quant,_1,IP] invalid and excluded from saved value for IP range(s) for [_2]',  
                                    $diff,$name).  
                                '</span></li>';  
                 }  
                 if (@ok) {  
                     my @cidr_list;  
                     foreach my $item (@ok) {  
                         @cidr_list = &Net::CIDR::cidradd($item,@cidr_list);  
                     }  
                     $confhash{$itemid}{'ip'} = join(',',@cidr_list);  
                 }  
             }  
         }  
         foreach my $field ('name','ip') {  
             unless (($idx eq 'add') || ($changes{$itemid})) {  
                 if ($current{$field} ne $confhash{$itemid}{$field}) {  
                     $changes{$itemid} = 1;  
                     last;  
                 }  
             }  
         }  
         $confhash{$itemid}{'commblocks'} = {};  
   
         my %commblocks;  
         map { $commblocks{$_} = 1; } &Apache::loncommon::get_env_multiple('form.ipaccess_block_'.$idx);  
         foreach my $type (@{$typeorder}) {  
             if ($commblocks{$type}) {  
                 $confhash{$itemid}{'commblocks'}{$type} = 'on';  
             }  
             unless (($idx eq 'add') || ($changes{$itemid})) {  
                 if (ref($current{'commblocks'}) eq 'HASH') {  
                     if ($confhash{$itemid}{'commblocks'}{$type} ne $current{'commblocks'}{$type}) {  
                         $changes{$itemid} = 1;  
                     }  
                 } elsif ($confhash{$itemid}{'commblocks'}{$type}) {  
                     $changes{$itemid} = 1;  
                 }  
             }  
         }  
         $confhash{$itemid}{'courses'} = {};  
         my %crsdeletions;  
         my @delcrs = &Apache::loncommon::get_env_multiple('form.ipaccess_course_delete_'.$idx);  
         if (@delcrs) {  
             map { $crsdeletions{$_} = 1; } @delcrs;  
         }  
         if (ref($current{'courses'}) eq 'HASH') {  
             foreach my $cid (sort(keys(%{$current{'courses'}}))) {  
                 if ($crsdeletions{$cid}) {  
                     $changes{$itemid} = 1;  
                 } else {  
                     $confhash{$itemid}{'courses'}{$cid} = 1;  
                 }  
             }  
         }  
         $env{'form.ipaccess_cnum_'.$idx} =~ s/^\s+|\s+$//g;  
         $env{'form.ipaccess_cdom_'.$idx} =~ s/^\s+|\s+$//g;  
         if (($env{'form.ipaccess_cnum_'.$idx} =~ /^$match_courseid$/) &&  
             ($env{'form.ipaccess_cdom_'.$idx} =~ /^$match_domain$/)) {  
             if (&Apache::lonnet::homeserver($env{'form.ipaccess_cnum_'.$idx},  
                                             $env{'form.ipaccess_cdom_'.$idx}) eq 'no_host') {  
                 $errors .= '<li><span class="LC_error">'.  
                            &mt('Invalid courseID [_1] omitted from list of allowed courses',  
                                $env{'form.ipaccess_cdom_'.$idx}.'_'.$env{'form.ipaccess_cnum_'.$idx}).  
                            '</span></li>';  
             } else {  
                 $confhash{$itemid}{'courses'}{$env{'form.ipaccess_cdom_'.$idx}.'_'.$env{'form.ipaccess_cnum_'.$idx}} = 1;  
                 $changes{$itemid} = 1;  
             }  
         }  
     }  
     if (@allpos > 0) {  
         my $idx = 0;  
         foreach my $itemid (@allpos) {  
             if ($itemid ne '') {  
                 $confhash{$itemid}{'order'} = $idx;  
                 unless ($changes{$itemid}) {  
                     if (ref($domconfig{'ipaccess'}) eq 'HASH') {  
                         if (ref($domconfig{'ipaccess'}{$itemid}) eq 'HASH') {  
                             if ($domconfig{'ipaccess'}{$itemid}{'order'} ne $idx) {  
                                 $changes{$itemid} = 1;  
                             }  
                         }  
                     }  
                 }  
                 $idx ++;  
             }  
         }  
     }  
     if (keys(%changes)) {  
         my %defaultshash = (  
                               ipaccess => \%confhash,  
                            );  
         my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,  
                                                  $dom);  
         if ($putresult eq 'ok') {  
             my $cachetime = 1800;  
             &Apache::lonnet::do_cache_new('ipaccess',$dom,\%confhash,$cachetime);  
             if (ref($lastactref) eq 'HASH') {  
                 $lastactref->{'ipaccess'} = 1;  
             }  
             $resulttext = &mt('Changes made:').'<ul>';  
             my %bynum;  
             foreach my $itemid (sort(keys(%changes))) {  
                 if (ref($confhash{$itemid}) eq 'HASH') {  
                     my $position = $confhash{$itemid}{'order'};  
                     if ($position =~ /^\d+$/) {  
                         $bynum{$position} = $itemid;  
                     }  
                 }  
             }  
             if (keys(%deletions)) {  
                 foreach my $itemid (sort { $a <=> $b } keys(%deletions)) {  
                     $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';  
                 }  
             }  
             foreach my $pos (sort { $a <=> $b } keys(%bynum)) {  
                 my $itemid = $bynum{$pos};  
                 if (ref($confhash{$itemid}) eq 'HASH') {  
                     $resulttext .= '<li><b>'.$confhash{$itemid}{'name'}.'</b><ul>';  
                     my $position = $pos + 1;  
                     $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';  
                     if ($confhash{$itemid}{'ip'} eq '') {  
                         $resulttext .= '<li>'.&mt('No IP Range(s) set').'</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('IP Range(s): [_1]',$confhash{$itemid}{'ip'}).'</li>';  
                     }  
                     if (keys(%{$confhash{$itemid}{'commblocks'}})) {  
                         $resulttext .= '<li>'.&mt('Functionality Blocked: [_1]',  
                                                   join(', ', map { $types->{$_}; } sort(keys(%{$confhash{$itemid}{'commblocks'}})))).  
                                        '</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('No functionality blocked').'</li>';  
                     }  
                     if (keys(%{$confhash{$itemid}{'courses'}})) {  
                         my @courses;  
                         foreach my $cid (sort(keys(%{$confhash{$itemid}{'courses'}}))) {  
                             my %courseinfo = &Apache::lonnet::coursedescription($cid,{'one_time' => 1});  
                             push(@courses,$courseinfo{'description'}.' ('.$cid.')');  
                         }  
                         $resulttext .= '<li>'.&mt('Courses/Communities allowed').':<ul><li>'.  
                                              join('</li><li>',@courses).'</li></ul>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('No courses allowed').'</li>';  
                     }  
                     $resulttext .= '</ul></li>';  
                 }  
             }  
             $resulttext .= '</ul>';  
         } else {  
             $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';  
         }  
     } else {  
         $resulttext = &mt('No changes made');  
     }  
     if ($errors) {  
         $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.  
                        $errors.'</ul></p>';  
     }  
     return $resulttext;  
 }  
   
 sub get_ipaccess_id {  
     my ($domain,$location) = @_;  
     # get lock on ipaccess db  
     my $lockhash = {  
                       lock => $env{'user.name'}.  
                               ':'.$env{'user.domain'},  
                    };  
     my $tries = 0;  
     my $gotlock = &Apache::lonnet::newput_dom('ipaccess',$lockhash,$domain);  
     my ($id,$error);  
   
     while (($gotlock ne 'ok') && ($tries<10)) {  
         $tries ++;  
         sleep (0.1);  
         $gotlock = &Apache::lonnet::newput_dom('ipaccess',$lockhash,$domain);  
     }  
     if ($gotlock eq 'ok') {  
         my %currids = &Apache::lonnet::dump_dom('ipaccess',$domain);  
         if ($currids{'lock'}) {  
             delete($currids{'lock'});  
             if (keys(%currids)) {  
                 my @curr = sort { $a <=> $b } keys(%currids);  
                 if ($curr[-1] =~ /^\d+$/) {  
                     $id = 1 + $curr[-1];  
                 }  
             } else {  
                 $id = 1;  
             }  
             if ($id) {  
                 unless (&Apache::lonnet::newput_dom('ipaccess',{ $id => $location },$domain) eq 'ok') {  
                     $error = 'nostore';  
                 }  
             } else {  
                 $error = 'nonumber';  
             }  
         }  
         my $dellockoutcome = &Apache::lonnet::del_dom('ipaccess',['lock'],$domain);  
     } else {  
         $error = 'nolock';  
     }  
     return ($id,$error);  
 }  
   
 sub modify_rolecolors {  sub modify_rolecolors {
     my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_;      my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_;
     my ($resulttext,%rolehash);      my ($resulttext,%rolehash);
Line 11742  sub modify_colors { Line 6470  sub modify_colors {
             $domconfig->{$role} = {};              $domconfig->{$role} = {};
         }          }
         foreach my $img (@images) {          foreach my $img (@images) {
             if ($role eq 'login') {              if (($role eq 'login') && (($img eq 'img') || ($img eq 'logo'))) {  
                 if (($img eq 'img') || ($img eq 'logo')) {                    if (defined($env{'form.login_showlogo_'.$img})) {
                     if (defined($env{'form.login_showlogo_'.$img})) {                      $confhash->{$role}{'showlogo'}{$img} = 1;
                         $confhash->{$role}{'showlogo'}{$img} = 1;                  } else { 
                     } else {                       $confhash->{$role}{'showlogo'}{$img} = 0;
                         $confhash->{$role}{'showlogo'}{$img} = 0;  
                     }  
                 }  
                 if ($env{'form.login_alt_'.$img} ne '') {  
                     $confhash->{$role}{'alttext'}{$img} = $env{'form.login_alt_'.$img};  
                 }                  }
             }              } 
     if ( ! $env{'form.'.$role.'_'.$img.'.filename'}       if ( ! $env{'form.'.$role.'_'.$img.'.filename'} 
  && !defined($domconfig->{$role}{$img})   && !defined($domconfig->{$role}{$img})
  && !$env{'form.'.$role.'_del_'.$img}   && !$env{'form.'.$role.'_del_'.$img}
Line 11770  sub modify_colors { Line 6493  sub modify_colors {
                         $error = &mt("Upload of [_1] image for $role page(s) is not permitted to this server: [_2]",$choices{$img},$switchserver);                          $error = &mt("Upload of [_1] image for $role page(s) is not permitted to this server: [_2]",$choices{$img},$switchserver);
                     } else {                      } else {
                         if ($author_ok eq 'ok') {                          if ($author_ok eq 'ok') {
                             my $modified = [];  
                             my ($result,$logourl) =                               my ($result,$logourl) = 
                                 &Apache::lonconfigsettings::publishlogo($r,'upload',$role.'_'.$img,                                  &publishlogo($r,'upload',$role.'_'.$img,
                                                                         $dom,$confname,$img,$width,$height,                                             $dom,$confname,$img,$width,$height);
                                                                         '',$modified);  
                             if ($result eq 'ok') {                              if ($result eq 'ok') {
                                 $confhash->{$role}{$img} = $logourl;                                  $confhash->{$role}{$img} = $logourl;
                                 $changes{$role}{'images'}{$img} = 1;                                  $changes{$role}{'images'}{$img} = 1;
                                 &update_modify_urls($r,$modified);  
                             } else {                              } else {
                                 $error = &mt("Upload of [_1] image for $role page(s) failed because an error occurred publishing the file in RES space. Error was: [_2].",$choices{img},$result);                                  $error = &mt("Upload of [_1] image for $role page(s) failed because an error occurred publishing the file in RES space. Error was: [_2].",$choices{img},$result);
                             }                              }
Line 11800  sub modify_colors { Line 6520  sub modify_colors {
 # is confname an author?  # is confname an author?
                         if ($switchserver eq '') {                          if ($switchserver eq '') {
                             if ($author_ok eq 'ok') {                              if ($author_ok eq 'ok') {
                                 my $modified = [];  
                                 my ($result,$logourl) =                                   my ($result,$logourl) = 
                                     &Apache::lonconfigsettings::publishlogo($r,'copy',$domconfig->{$role}{$img},                                 &publishlogo($r,'copy',$domconfig->{$role}{$img},
                                                                             $dom,$confname,$img,$width,$height,                                              $dom,$confname,$img,$width,$height);
                                                                             '',$modified);  
                                 if ($result eq 'ok') {                                  if ($result eq 'ok') {
                                     $confhash->{$role}{$img} = $logourl;                                      $confhash->{$role}{$img} = $logourl;
     $changes{$role}{'images'}{$img} = 1;      $changes{$role}{'images'}{$img} = 1;
                                     &update_modify_urls($r,$modified);  
                                 }                                  }
                             }                              }
                         }                          }
Line 11834  sub modify_colors { Line 6551  sub modify_colors {
                             $changes{$role}{'images'}{$img} = 1;                              $changes{$role}{'images'}{$img} = 1;
                         }                           } 
                     }                      }
                     if ($role eq 'login') {                      if (($role eq 'login') && (($img eq 'logo') || ($img eq 'img'))) {
                         if (($img eq 'logo') || ($img eq 'img')) {                          if (ref($domconfig->{'login'}{'showlogo'}) eq 'HASH') {
                             if (ref($domconfig->{'login'}{'showlogo'}) eq 'HASH') {                              if ($confhash->{$role}{'showlogo'}{$img} ne 
                                 if ($confhash->{$role}{'showlogo'}{$img} ne                                   $domconfig->{$role}{'showlogo'}{$img}) {
                                     $domconfig->{$role}{'showlogo'}{$img}) {                                  $changes{$role}{'showlogo'}{$img} = 1; 
                                     $changes{$role}{'showlogo'}{$img} = 1;   
                                 }  
                             } else {  
                                 if ($confhash->{$role}{'showlogo'}{$img} == 0) {  
                                     $changes{$role}{'showlogo'}{$img} = 1;  
                                 }  
                             }                              }
                         }                          } else {
                         if ($img ne 'login') {                              if ($confhash->{$role}{'showlogo'}{$img} == 0) {
                             if (ref($domconfig->{$role}{'alttext'}) eq 'HASH') {                                  $changes{$role}{'showlogo'}{$img} = 1;
                                 if ($confhash->{$role}{'alttext'}{$img} ne  
                                     $domconfig->{$role}{'alttext'}{$img}) {  
                                     $changes{$role}{'alttext'}{$img} = 1;  
                                 }  
                             } else {  
                                 if ($confhash->{$role}{'alttext'}{$img} ne '') {  
                                     $changes{$role}{'alttext'}{$img} = 1;  
                                 }  
                             }                              }
                         }                          }
                     }                      }
Line 11967  sub default_change_checker { Line 6670  sub default_change_checker {
             if ($confhash->{$role}{'showlogo'}{$img} == 0) {              if ($confhash->{$role}{'showlogo'}{$img} == 0) {
                 $changes->{$role}{'showlogo'}{$img} = 1;                  $changes->{$role}{'showlogo'}{$img} = 1;
             }              }
             if (ref($confhash->{$role}{'alttext'}) eq 'HASH') {  
                 if ($confhash->{$role}{'alttext'}{$img} ne '') {  
                     $changes->{$role}{'alttext'}{$img} = 1;  
                 }  
             }  
         }          }
     }      }
     if ($confhash->{$role}{'font'}) {      if ($confhash->{$role}{'font'}) {
Line 12010  sub display_colorchgs { Line 6708  sub display_colorchgs {
                             } else {                              } else {
                                 $resulttext .= '<li>'.&mt("$choices{$item} set to not be displayed").'</li>';                                  $resulttext .= '<li>'.&mt("$choices{$item} set to not be displayed").'</li>';
                             }                              }
                         } elsif (($role eq 'login') && ($key eq 'alttext')) {  
                             if ($confhash->{$role}{$key}{$item} ne '') {  
                                 $resulttext .= '<li>'.&mt("$choices{$key} for $choices{$item} set to [_1].",  
                                                $confhash->{$role}{$key}{$item}).'</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt("$choices{$key} for $choices{$item} deleted.").'</li>';  
                             }  
                         } elsif ($confhash->{$role}{$item} eq '') {                          } elsif ($confhash->{$role}{$item} eq '') {
                             $resulttext .= '<li>'.&mt("$choices{$item} set to default").'</li>';                              $resulttext .= '<li>'.&mt("$choices{$item} set to default").'</li>';
                         } else {                          } else {
Line 12075  sub check_configuser { Line 6766  sub check_configuser {
     my ($configuserok,%currroles);      my ($configuserok,%currroles);
     if ($uhome eq 'no_host') {      if ($uhome eq 'no_host') {
         srand( time() ^ ($$ + ($$ << 15))  ); # Seed rand.          srand( time() ^ ($$ + ($$ << 15))  ); # Seed rand.
         my $configpass = &LONCAPA::Enrollment::create_password($dom);          my $configpass = &LONCAPA::Enrollment::create_password();
         $configuserok =           $configuserok = 
             &Apache::lonnet::modifyuser($dom,$confname,'','internal',              &Apache::lonnet::modifyuser($dom,$confname,'','internal',
                              $configpass,'','','','','',undef,$servadm);                               $configpass,'','','','','',undef,$servadm);
Line 12102  sub check_authorstatus { Line 6793  sub check_authorstatus {
     return $author_ok;      return $author_ok;
 }  }
   
 sub update_modify_urls {  sub publishlogo {
     my ($r,$modified) = @_;      my ($r,$action,$formname,$dom,$confname,$subdir,$thumbwidth,$thumbheight,$savefileas) = @_;
     if ((ref($modified) eq 'ARRAY') && (@{$modified})) {      my ($output,$fname,$logourl);
         push(@{$modified_urls},$modified);      if ($action eq 'upload') {
         unless ($registered_cleanup) {          $fname=$env{'form.'.$formname.'.filename'};
             my $handlers = $r->get_handlers('PerlCleanupHandler');          chop($env{'form.'.$formname});
             $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);      } else {
             $registered_cleanup=1;          ($fname) = ($formname =~ /([^\/]+)$/);
       }
       if ($savefileas ne '') {
           $fname = $savefileas;
       }
       $fname=&Apache::lonnet::clean_filename($fname);
   # See if there is anything left
       unless ($fname) { return ('error: no uploaded file'); }
       $fname="$subdir/$fname";
       my $docroot=$r->dir_config('lonDocRoot');
       my $filepath="$docroot/priv";
       my $relpath = "$dom/$confname";
       my ($fnamepath,$file,$fetchthumb);
       $file=$fname;
       if ($fname=~m|/|) {
           ($fnamepath,$file) = ($fname =~ m|^(.*)/([^/]+)$|);
       }
       my @parts=split(/\//,"$filepath/$relpath/$fnamepath");
       my $count;
       for ($count=5;$count<=$#parts;$count++) {
           $filepath.="/$parts[$count]";
           if ((-e $filepath)!=1) {
               mkdir($filepath,02770);
           }
       }
       # Check for bad extension and disallow upload
       if ($file=~/\.(\w+)$/ &&
           (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {
           $output = 
               &mt('Invalid file extension ([_1]) - reserved for internal use.',$1); 
       } elsif ($file=~/\.(\w+)$/ &&
           !defined(&Apache::loncommon::fileembstyle($1))) {
           $output = &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1);
       } elsif ($file=~/\.(\d+)\.(\w+)$/) {
           $output = &mt('Filename not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2);
       } elsif (-d "$filepath/$file") {
           $output = &mt('Filename is a directory name - rename the file and re-upload');
       } else {
           my $source = $filepath.'/'.$file;
           my $logfile;
           if (!open($logfile,">>$source".'.log')) {
               return (&mt('No write permission to Authoring Space'));
           }
           print $logfile
   "\n================= Publish ".localtime()." ================\n".
   $env{'user.name'}.':'.$env{'user.domain'}."\n";
   # Save the file
           if (!open(FH,'>'.$source)) {
               &Apache::lonnet::logthis('Failed to create '.$source);
               return (&mt('Failed to create file'));
           }
           if ($action eq 'upload') {
               if (!print FH ($env{'form.'.$formname})) {
                   &Apache::lonnet::logthis('Failed to write to '.$source);
                   return (&mt('Failed to write file'));
               }
           } else {
               my $original = &Apache::lonnet::filelocation('',$formname);
               if(!copy($original,$source)) {
                   &Apache::lonnet::logthis('Failed to copy '.$original.' to '.$source);
                   return (&mt('Failed to write file'));
               }
           }
           close(FH);
           chmod(0660, $source); # Permissions to rw-rw---.
   
           my $targetdir=$docroot.'/res/'.$dom.'/'.$confname .'/'.$fnamepath;
           my $copyfile=$targetdir.'/'.$file;
   
           my @parts=split(/\//,$targetdir);
           my $path="/$parts[1]/$parts[2]/$parts[3]/$parts[4]";
           for (my $count=5;$count<=$#parts;$count++) {
               $path.="/$parts[$count]";
               if (!-e $path) {
                   print $logfile "\nCreating directory ".$path;
                   mkdir($path,02770);
               }
           }
           my $versionresult;
           if (-e $copyfile) {
               $versionresult = &logo_versioning($targetdir,$file,$logfile);
           } else {
               $versionresult = 'ok';
           }
           if ($versionresult eq 'ok') {
               if (copy($source,$copyfile)) {
                   print $logfile "\nCopied original source to ".$copyfile."\n";
                   $output = 'ok';
                   $logourl = '/res/'.$dom.'/'.$confname.'/'.$fname;
                   push(@{$modified_urls},[$copyfile,$source]);
                   my $metaoutput = 
                       &write_metadata($dom,$confname,$formname,$targetdir,$file,$logfile);
                   unless ($registered_cleanup) {
                       my $handlers = $r->get_handlers('PerlCleanupHandler');
                       $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);
                       $registered_cleanup=1;
                   }
               } else {
                   print $logfile "\nUnable to write ".$copyfile.':'.$!."\n";
                   $output = &mt('Failed to copy file to RES space').", $!";
               }
               if (($thumbwidth =~ /^\d+$/) && ($thumbheight =~ /^\d+$/)) {
                   my $inputfile = $filepath.'/'.$file;
                   my $outfile = $filepath.'/'.'tn-'.$file;
                   my ($fullwidth,$fullheight) = &check_dimensions($inputfile);
                   if ($fullwidth ne '' && $fullheight ne '') { 
                       if ($fullwidth > $thumbwidth && $fullheight > $thumbheight) {
                           my $thumbsize = $thumbwidth.'x'.$thumbheight;
                           system("convert -sample $thumbsize $inputfile $outfile");
                           chmod(0660, $filepath.'/tn-'.$file);
                           if (-e $outfile) {
                               my $copyfile=$targetdir.'/tn-'.$file;
                               if (copy($outfile,$copyfile)) {
                                   print $logfile "\nCopied source to ".$copyfile."\n";
                                   my $thumb_metaoutput = 
                                       &write_metadata($dom,$confname,$formname,
                                                       $targetdir,'tn-'.$file,$logfile);
                                   push(@{$modified_urls},[$copyfile,$outfile]);
                                   unless ($registered_cleanup) {
                                       my $handlers = $r->get_handlers('PerlCleanupHandler');
                                       $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);
                                       $registered_cleanup=1;
                                   }
                               } else {
                                   print $logfile "\nUnable to write ".$copyfile.
                                                  ':'.$!."\n";
                               }
                           }
                       }
                   }
               }
           } else {
               $output = $versionresult;
           }
       }
       return ($output,$logourl);
   }
   
   sub logo_versioning {
       my ($targetdir,$file,$logfile) = @_;
       my $target = $targetdir.'/'.$file;
       my ($maxversion,$fn,$extn,$output);
       $maxversion = 0;
       if ($file =~ /^(.+)\.(\w+)$/) {
           $fn=$1;
           $extn=$2;
       }
       opendir(DIR,$targetdir);
       while (my $filename=readdir(DIR)) {
           if ($filename=~/\Q$fn\E\.(\d+)\.\Q$extn\E$/) {
               $maxversion=($1>$maxversion)?$1:$maxversion;
           }
       }
       $maxversion++;
       print $logfile "\nCreating old version ".$maxversion."\n";
       my $copyfile=$targetdir.'/'.$fn.'.'.$maxversion.'.'.$extn;
       if (copy($target,$copyfile)) {
           print $logfile "Copied old target to ".$copyfile."\n";
           $copyfile=$copyfile.'.meta';
           if (copy($target.'.meta',$copyfile)) {
               print $logfile "Copied old target metadata to ".$copyfile."\n";
               $output = 'ok';
           } else {
               print $logfile "Unable to write metadata ".$copyfile.':'.$!."\n";
               $output = &mt('Failed to copy old meta').", $!, ";
           }
       } else {
           print $logfile "Unable to write ".$copyfile.':'.$!."\n";
           $output = &mt('Failed to copy old target').", $!, ";
       }
       return $output;
   }
   
   sub write_metadata {
       my ($dom,$confname,$formname,$targetdir,$file,$logfile) = @_;
       my (%metadatafields,%metadatakeys,$output);
       $metadatafields{'title'}=$formname;
       $metadatafields{'creationdate'}=time;
       $metadatafields{'lastrevisiondate'}=time;
       $metadatafields{'copyright'}='public';
       $metadatafields{'modifyinguser'}=$env{'user.name'}.':'.
                                            $env{'user.domain'};
       $metadatafields{'authorspace'}=$confname.':'.$dom;
       $metadatafields{'domain'}=$dom;
       {
           print $logfile "\nWrite metadata file for ".$targetdir.'/'.$file;
           my $mfh;
           if (open($mfh,'>'.$targetdir.'/'.$file.'.meta')) {
               foreach (sort(keys(%metadatafields))) {
                   unless ($_=~/\./) {
                       my $unikey=$_;
                       $unikey=~/^([A-Za-z]+)/;
                       my $tag=$1;
                       $tag=~tr/A-Z/a-z/;
                       print $mfh "\n\<$tag";
                       foreach (split(/\,/,$metadatakeys{$unikey})) {
                           my $value=$metadatafields{$unikey.'.'.$_};
                           $value=~s/\"/\'\'/g;
                           print $mfh ' '.$_.'="'.$value.'"';
                       }
                       print $mfh '>'.
                           &HTML::Entities::encode($metadatafields{$unikey},'<>&"')
                               .'</'.$tag.'>';
                   }
               }
               $output = 'ok';
               print $logfile "\nWrote metadata";
               close($mfh);
           } else {
               print $logfile "\nFailed to open metadata file";
               $output = &mt('Could not write metadata');
         }          }
     }      }
       return $output;
 }  }
   
 sub notifysubscribed {  sub notifysubscribed {
Line 12119  sub notifysubscribed { Line 7021  sub notifysubscribed {
         next unless (ref($targetsource) eq 'ARRAY');          next unless (ref($targetsource) eq 'ARRAY');
         my ($target,$source)=@{$targetsource};          my ($target,$source)=@{$targetsource};
         if ($source ne '') {          if ($source ne '') {
             if (open(my $logfh,">>",$source.'.log')) {              if (open(my $logfh,'>>'.$source.'.log')) {
                 print $logfh "\nCleanup phase: Notifications\n";                  print $logfh "\nCleanup phase: Notifications\n";
                 my @subscribed=&subscribed_hosts($target);                  my @subscribed=&subscribed_hosts($target);
                 foreach my $subhost (@subscribed) {                  foreach my $subhost (@subscribed) {
Line 12145  sub notifysubscribed { Line 7047  sub notifysubscribed {
 sub subscribed_hosts {  sub subscribed_hosts {
     my ($target) = @_;      my ($target) = @_;
     my @subscribed;      my @subscribed;
     if (open(my $fh,"<","$target.subscription")) {      if (open(my $fh,"<$target.subscription")) {
         while (my $subline=<$fh>) {          while (my $subline=<$fh>) {
             if ($subline =~ /^($match_lonid):/) {              if ($subline =~ /^($match_lonid):/) {
                 my $host = $1;                  my $host = $1;
Line 12162  sub subscribed_hosts { Line 7064  sub subscribed_hosts {
   
 sub check_switchserver {  sub check_switchserver {
     my ($dom,$confname) = @_;      my ($dom,$confname) = @_;
     my ($allowed,$switchserver,$home);      my ($allowed,$switchserver);
     if ($confname eq '') {      my $home = &Apache::lonnet::homeserver($confname,$dom);
       if ($home eq 'no_host') {
         $home = &Apache::lonnet::domain($dom,'primary');          $home = &Apache::lonnet::domain($dom,'primary');
     } else {  
         $home = &Apache::lonnet::homeserver($confname,$dom);  
         if ($home eq 'no_host') {  
             $home = &Apache::lonnet::domain($dom,'primary');  
         }  
     }      }
     my @ids=&Apache::lonnet::current_machine_ids();      my @ids=&Apache::lonnet::current_machine_ids();
     foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }      foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
     if (!$allowed) {      if (!$allowed) {
  $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&amp;role='.   $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&amp;role=dc./'.$dom.'/&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';
                       &HTML::Entities::encode($env{'request.role'},'\'<>"&').  
                       '&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';  
     }      }
     return $switchserver;      return $switchserver;
 }  }
Line 12193  sub modify_quotas { Line 7089  sub modify_quotas {
         $context = $action;          $context = $action;
     }      }
     if ($context eq 'requestcourses') {      if ($context eq 'requestcourses') {
         @usertools = ('official','unofficial','community','textbook','lti');          @usertools = ('official','unofficial','community','textbook');
         @options =('norequest','approval','validate','autolimit');          @options =('norequest','approval','validate','autolimit');
         %validations = &Apache::lonnet::auto_courserequest_checks($dom);          %validations = &Apache::lonnet::auto_courserequest_checks($dom);
         %titles = &courserequest_titles();          %titles = &courserequest_titles();
Line 12208  sub modify_quotas { Line 7104  sub modify_quotas {
         @usertools = ('author');          @usertools = ('author');
         %titles = &authorrequest_titles();          %titles = &authorrequest_titles();
     } else {      } else {
         @usertools = ('aboutme','blog','webdav','portfolio','timezone');          @usertools = ('aboutme','blog','webdav','portfolio');
         %titles = &tool_titles();          %titles = &tool_titles();
     }      }
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);      my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
Line 12242  sub modify_quotas { Line 7138  sub modify_quotas {
         my @approvalnotify = &Apache::loncommon::get_env_multiple('form.'.$context.'notifyapproval');          my @approvalnotify = &Apache::loncommon::get_env_multiple('form.'.$context.'notifyapproval');
         @approvalnotify = sort(@approvalnotify);          @approvalnotify = sort(@approvalnotify);
         $confhash{'notify'}{'approval'} = join(',',@approvalnotify);          $confhash{'notify'}{'approval'} = join(',',@approvalnotify);
         my @crstypes = ('official','unofficial','community','textbook','lti');          my @crstypes = ('official','unofficial','community','textbook');
         my @hasuniquecode = &Apache::loncommon::get_env_multiple('form.uniquecode');          my @hasuniquecode = &Apache::loncommon::get_env_multiple('form.uniquecode');
         foreach my $type (@hasuniquecode) {          foreach my $type (@hasuniquecode) {
             if (grep(/^\Q$type\E$/,@crstypes)) {              if (grep(/^\Q$type\E$/,@crstypes)) {
Line 12336  sub modify_quotas { Line 7232  sub modify_quotas {
                                     my $newpos = $env{'form.'.$itemid};                                      my $newpos = $env{'form.'.$itemid};
                                     $newpos =~ s/\D+//g;                                      $newpos =~ s/\D+//g;
                                     foreach my $item ('subject','title','publisher','author') {                                      foreach my $item ('subject','title','publisher','author') {
                                         next if ((($item eq 'author') || ($item eq 'publisher')) &&                                          next if ((($item eq 'author') || ($item eq 'publisher')) && 
                                                  ($type eq 'templates'));                                                   ($type eq 'templates'));
                                         $confhash{$type}{$key}{$item} = $env{'form.'.$type.'_'.$item.'_'.$i};                                          $confhash{$type}{$key}{$item} = $env{'form.'.$type.'_'.$item.'_'.$i};
                                         if ($domconfig{$action}{$type}{$key}{$item} ne $confhash{$type}{$key}{$item}) {                                          if ($domconfig{$action}{$type}{$key}{$item} ne $confhash{$type}{$key}{$item}) {
Line 12350  sub modify_quotas { Line 7246  sub modify_quotas {
                                     #FIXME need to obsolete item in RES space                                      #FIXME need to obsolete item in RES space
                                 } elsif ($env{'form.'.$type.'_image_'.$i.'.filename'}) {                                  } elsif ($env{'form.'.$type.'_image_'.$i.'.filename'}) {
                                     my ($cdom,$cnum) = split(/_/,$key);                                      my ($cdom,$cnum) = split(/_/,$key);
                                     if (&Apache::lonnet::homeserver($cnum,$cdom) eq 'no_host') {                                      my ($imgurl,$error) = &process_textbook_image($r,$dom,$confname,$type.'_image_'.$i,
                                         $errors .= '<li><span class="LC_error">'.&mt('Image not saved: could not find textbook course').'</li>';                                                                                    $cdom,$cnum,$type,$configuserok,
                                     } else {                                                                                    $switchserver,$author_ok);
                                         my ($imgurl,$error) = &process_textbook_image($r,$dom,$confname,$type.'_image_'.$i,                                      if ($imgurl) {
                                                                                       $cdom,$cnum,$type,$configuserok,                                          $confhash{$type}{$key}{'image'} = $imgurl;
                                                                                       $switchserver,$author_ok);                                          $changes{$type}{$key} = 1; 
                                         if ($imgurl) {                                      }
                                             $confhash{$type}{$key}{'image'} = $imgurl;                                      if ($error) {
                                             $changes{$type}{$key} = 1;                                           &Apache::lonnet::logthis($error);
                                         }                                          $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
                                         if ($error) {                                      } 
                                             &Apache::lonnet::logthis($error);  
                                             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';  
                                         }  
                                     }  
                                 } elsif ($domconfig{$action}{$type}{$key}{'image'}) {                                  } elsif ($domconfig{$action}{$type}{$key}{'image'}) {
                                     $confhash{$type}{$key}{'image'} =                                       $confhash{$type}{$key}{'image'} = 
                                         $domconfig{$action}{$type}{$key}{'image'};                                          $domconfig{$action}{$type}{$key}{'image'};
Line 12397  sub modify_quotas { Line 7289  sub modify_quotas {
                     if ($type eq 'textbooks') {                      if ($type eq 'textbooks') {
                         if ($env{'form.'.$type.'_addbook_image.filename'} ne '') {                          if ($env{'form.'.$type.'_addbook_image.filename'} ne '') {
                             my ($cdom,$cnum) = split(/_/,$newbook{$type});                              my ($cdom,$cnum) = split(/_/,$newbook{$type});
                             if (&Apache::lonnet::homeserver($cnum,$cdom) eq 'no_host') {                              my ($imageurl,$error) =
                                 $errors .= '<li><span class="LC_error">'.&mt('Image not saved: could not find textbook course').'</li>';                                  &process_textbook_image($r,$dom,$confname,$type.'_addbook_image',$cdom,$cnum,$type,
                             } else {                                                          $configuserok,$switchserver,$author_ok);
                                 my ($imageurl,$error) =                              if ($imageurl) {
                                     &process_textbook_image($r,$dom,$confname,$type.'_addbook_image',$cdom,$cnum,$type,                                  $confhash{$type}{$newbook{$type}}{'image'} = $imageurl;
                                                             $configuserok,$switchserver,$author_ok);                              }
                                 if ($imageurl) {                              if ($error) {
                                     $confhash{$type}{$newbook{$type}}{'image'} = $imageurl;                                  &Apache::lonnet::logthis($error);
                                 }                                  $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
                                 if ($error) {  
                                     &Apache::lonnet::logthis($error);  
                                     $errors .= '<li><span class="LC_error">'.$error.'</span></li>';  
                                 }  
                             }                              }
                         }                          }
                     }                      }
Line 12441  sub modify_quotas { Line 7329  sub modify_quotas {
                         if (@{$confhash{'validation'}{$item}} > 0) {                          if (@{$confhash{'validation'}{$item}} > 0) {
                             @{$confhash{'validation'}{$item}} = sort(@{$confhash{'validation'}{$item}});                              @{$confhash{'validation'}{$item}} = sort(@{$confhash{'validation'}{$item}});
                         }                          }
                         if (ref($domconfig{'requestcourses'}) eq 'HASH') {                          if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {
                             if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {                              if (ref($domconfig{'requestcourses'}{'validation'}{$item}) eq 'ARRAY') {
                                 if (ref($domconfig{'requestcourses'}{'validation'}{$item}) eq 'ARRAY') {                                  @changed = &Apache::loncommon::compare_arrays($confhash{'validation'}{$item},
                                     @changed = &Apache::loncommon::compare_arrays($confhash{'validation'}{$item},                                                                                $domconfig{'requestcourses'}{'validation'}{$item});
                                                                                   $domconfig{'requestcourses'}{'validation'}{$item});  
                                 } else {  
                                     @changed = @{$confhash{'validation'}{$item}};  
                                 }  
                             } else {                              } else {
                                 @changed = @{$confhash{'validation'}{$item}};                                  @changed = @{$confhash{'validation'}{$item}};
                             }                              }
Line 12469  sub modify_quotas { Line 7353  sub modify_quotas {
                                 $env{'form.requestcourses_validation_'.$item} =~ s/[\n\r\f]+/\s/gs;                                  $env{'form.requestcourses_validation_'.$item} =~ s/[\n\r\f]+/\s/gs;
                             }                              }
                         }                          }
                         if (ref($domconfig{'requestcourses'}) eq 'HASH') {                          if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {
                             if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {                              if ($domconfig{'requestcourses'}{'validation'}{$item} ne $confhash{'validation'}{$item}) {
                                 if ($domconfig{'requestcourses'}{'validation'}{$item} ne $confhash{'validation'}{$item}) {                                  $changes{'validation'}{$item} = $confhash{'validation'}{$item};
                                     $changes{'validation'}{$item} = $confhash{'validation'}{$item};  
                                 }  
                             } else {  
                                 if ($confhash{'validation'}{$item} ne '') {  
                                     $changes{'validation'}{$item} = $confhash{'validation'}{$item};  
                                 }  
                             }                              }
                         } else {                          } else {
                             if ($confhash{'validation'}{$item} ne '') {                              if ($confhash{'validation'}{$item} ne '') {
Line 12489  sub modify_quotas { Line 7367  sub modify_quotas {
             }              }
             if ($env{'form.validationdc'}) {              if ($env{'form.validationdc'}) {
                 my $newval = $env{'form.validationdc'};                  my $newval = $env{'form.validationdc'};
                 my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']);                  my %domcoords = &get_active_dcs($dom);
                 if (exists($domcoords{$newval})) {                  if (exists($domcoords{$newval})) {
                     $confhash{'validation'}{'dc'} = $newval;                      $confhash{'validation'}{'dc'} = $newval;
                 }                  }
             }              }
             if (ref($confhash{'validation'}) eq 'HASH') {              if (ref($confhash{'validation'}) eq 'HASH') {
                 if (ref($domconfig{'requestcourses'}) eq 'HASH') {                  if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {
                     if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {                      if ($domconfig{'requestcourses'}{'validation'}{'dc'}) {
                         if ($domconfig{'requestcourses'}{'validation'}{'dc'}) {                          unless ($confhash{'validation'}{'dc'} eq $domconfig{'requestcourses'}{'validation'}{'dc'}) {
                             unless ($confhash{'validation'}{'dc'} eq $domconfig{'requestcourses'}{'validation'}{'dc'}) {                              if ($confhash{'validation'}{'dc'} eq '') {
                                 if ($confhash{'validation'}{'dc'} eq '') {                                  $changes{'validation'}{'dc'} = &mt('None');
                                     $changes{'validation'}{'dc'} = &mt('None');                              } else {
                                 } else {                                  $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};
                                     $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};  
                                 }  
                             }                              }
                         } elsif ($confhash{'validation'}{'dc'} ne '') {  
                             $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};  
                         }                          }
                     } elsif ($confhash{'validation'}{'dc'} ne '') {                      } elsif ($confhash{'validation'}{'dc'} ne '') {
                         $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};                          $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};
Line 12514  sub modify_quotas { Line 7388  sub modify_quotas {
                 } elsif ($confhash{'validation'}{'dc'} ne '') {                  } elsif ($confhash{'validation'}{'dc'} ne '') {
                     $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};                      $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};
                 }                  }
             } else {              } elsif (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {
                 if (ref($domconfig{'requestcourses'}) eq 'HASH') {                  if ($domconfig{'requestcourses'}{'validation'}{'dc'}) {
                     if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {                      $changes{'validation'}{'dc'} = &mt('None');
                         if ($domconfig{'requestcourses'}{'validation'}{'dc'}) {  
                             $changes{'validation'}{'dc'} = &mt('None');  
                         }  
                     }  
                 }                  }
             }              }
         }          }
Line 12899  sub process_textbook_image { Line 7769  sub process_textbook_image {
             $error = &mt('Upload of textbook image is not permitted to this server: [_1]',              $error = &mt('Upload of textbook image is not permitted to this server: [_1]',
                          $switchserver);                           $switchserver);
         } elsif ($author_ok eq 'ok') {          } elsif ($author_ok eq 'ok') {
             my $modified = [];  
             my ($result,$imageurl) =              my ($result,$imageurl) =
                 &Apache::lonconfigsettings::publishlogo($r,'upload',$caller,$dom,$confname,                  &publishlogo($r,'upload',$caller,$dom,$confname,
                                                         "$type/$cdom/$cnum/cover",$width,$height,                               "$type/$dom/$cnum/cover",$width,$height);
                                                         '',$modified);  
             if ($result eq 'ok') {              if ($result eq 'ok') {
                 $url = $imageurl;                  $url = $imageurl;
                 &update_modify_urls($r,$modified);  
             } else {              } else {
                 $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);                  $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);
             }              }
Line 12919  sub process_textbook_image { Line 7786  sub process_textbook_image {
     return ($url,$error);      return ($url,$error);
 }  }
   
 sub modify_ltitools {  
     my ($r,$dom,$action,$lastactref,%domconfig) = @_;  
     my (%currtoolsec,%secchanges,%newtoolsec,%newkeyset);  
     &fetch_secrets($dom,'toolsec',\%domconfig,\%currtoolsec,\%secchanges,\%newtoolsec,\%newkeyset);  
   
     my $confname = $dom.'-domainconfig';  
     my $servadm = $r->dir_config('lonAdmEMail');  
     my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);  
   
     my ($resulttext,$ltitoolsoutput,$is_home,$errors,%ltitoolschg,%newtoolsenc,%newltitools);  
     my $toolserror =  
         &Apache::courseprefs::process_ltitools($r,$dom,$confname,$domconfig{'ltitools'},\%ltitoolschg,'domain',  
                                                $lastactref,$configuserok,$switchserver,$author_ok);  
   
     my $home = &Apache::lonnet::domain($dom,'primary');  
     unless (($home eq 'no_host') || ($home eq '')) {  
         my @ids=&Apache::lonnet::current_machine_ids();  
         foreach my $id (@ids) { if ($id eq $home) { $is_home=1; last; } }  
     }  
   
     if (keys(%ltitoolschg)) {  
         foreach my $id (keys(%ltitoolschg)) {  
             if (ref($ltitoolschg{$id}) eq 'HASH') {  
                 foreach my $inner (keys(%{$ltitoolschg{$id}})) {  
                     if (($inner eq 'secret') || ($inner eq 'key')) {  
                         if ($is_home) {  
                             $newtoolsenc{$id}{$inner} = $ltitoolschg{$id}{$inner};  
                         }  
                     }  
                 }  
             }  
         }  
         $ltitoolsoutput = &Apache::courseprefs::store_ltitools($dom,'','domain',\%ltitoolschg,$domconfig{'ltitools'});  
         if (keys(%ltitoolschg)) {  
             %newltitools = %ltitoolschg;  
         }  
     }  
     if (ref($domconfig{'ltitools'}) eq 'HASH') {  
         foreach my $id (%{$domconfig{'ltitools'}}) {  
             next if ($id !~ /^\d+$/);  
             unless (exists($ltitoolschg{$id})) {  
                 if (ref($domconfig{'ltitools'}{$id}) eq 'HASH') {  
                     foreach my $inner (keys(%{$domconfig{'ltitools'}{$id}})) {  
                         if (($inner eq 'secret') || ($inner eq 'key')) {  
                             if ($is_home) {  
                                 $newtoolsenc{$id}{$inner} = $domconfig{'ltitools'}{$id}{$inner};  
                             }  
                         } else {  
                             $newltitools{$id}{$inner} = $domconfig{'ltitools'}{$id}{$inner};  
                         }  
                     }  
                 } else {  
                     $newltitools{$id} = $domconfig{'ltitools'}{$id};  
                 }  
             }  
         }  
     }  
     if ($toolserror) {  
         $errors = '<li>'.$toolserror.'</li>';  
     }  
     if ((keys(%ltitoolschg) == 0) && (keys(%secchanges) == 0)) {  
         $resulttext = &mt('No changes made.');  
         if ($errors) {  
             $resulttext .= '<br />'.&mt('The following errors occurred: ').'<ul>'.  
                                  $errors.'</ul>';  
         }  
         return $resulttext;  
     }  
     my %ltitoolshash = (  
                           $action => { %newltitools }  
                        );  
     if (keys(%secchanges)) {  
         $ltitoolshash{'toolsec'} = \%newtoolsec;  
     }  
     my $putresult = &Apache::lonnet::put_dom('configuration',\%ltitoolshash,$dom);  
     if ($putresult eq 'ok') {  
         my %keystore;  
         if ($is_home) {  
             my %toolsenchash = (  
                                    $action => { %newtoolsenc }  
                                );  
             &Apache::lonnet::put_dom('encconfig',\%toolsenchash,$dom,undef,1);  
             my $cachetime = 24*60*60;  
             &Apache::lonnet::do_cache_new('ltitoolsenc',$dom,\%newtoolsenc,$cachetime);  
             &store_security($dom,'ltitools',\%secchanges,\%newkeyset,\%keystore,$lastactref);  
         }  
         $resulttext = &mt('Changes made:').'<ul>';  
         if (keys(%secchanges) > 0) {  
             $resulttext .= &lti_security_results($dom,'ltitools',\%secchanges,\%newtoolsec,\%newkeyset,\%keystore);  
         }  
         if (keys(%ltitoolschg) > 0) {  
             $resulttext .= $ltitoolsoutput;  
         }  
         my $cachetime = 24*60*60;  
         &Apache::lonnet::do_cache_new('ltitools',$dom,\%newltitools,$cachetime);  
         if (ref($lastactref) eq 'HASH') {  
             $lastactref->{'ltitools'} = 1;  
         }  
     } else {  
         $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';  
     }  
     if ($errors) {  
         $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.  
                        $errors.'</ul></p>';  
     }  
     return $resulttext;  
 }  
   
 sub fetch_secrets {  
     my ($dom,$context,$domconfig,$currsec,$secchanges,$newsec,$newkeyset) = @_;  
     my %keyset;  
     %{$currsec} = ();  
     $newsec->{'private'}{'keys'} = [];  
     $newsec->{'encrypt'} = {};  
     $newsec->{'rules'} = {};  
     if ($context eq 'ltisec') {  
         $newsec->{'linkprot'} = {};  
     }  
     if (ref($domconfig->{$context}) eq 'HASH') {  
         %{$currsec} = %{$domconfig->{$context}};  
         if ($context eq 'ltisec') {  
             if (ref($currsec->{'linkprot'}) eq 'HASH') {  
                 foreach my $id (keys(%{$currsec->{'linkprot'}})) {  
                     unless ($id =~ /^\d+$/) {  
                         delete($currsec->{'linkprot'}{$id});  
                     }  
                 }  
             }  
         }  
         if (ref($currsec->{'private'}) eq 'HASH') {  
             if (ref($currsec->{'private'}{'keys'}) eq 'ARRAY') {  
                 $newsec->{'private'}{'keys'} = $currsec->{'private'}{'keys'};  
                 map { $keyset{$_} = 1; } @{$currsec->{'private'}{'keys'}};  
             }  
         }  
     }  
     my @items= ('crs','dom');  
     if ($context eq 'ltisec') {  
         push(@items,'consumers');  
     }  
     foreach my $item (@items) {  
         my $formelement;  
         if (($context eq 'toolsec') || ($item eq 'consumers')) {  
             $formelement = 'form.'.$context.'_'.$item;  
         } else {  
             $formelement = 'form.'.$context.'_'.$item.'linkprot';  
         }  
         if ($env{$formelement}) {  
             $newsec->{'encrypt'}{$item} = 1;  
             if (ref($currsec->{'encrypt'}) eq 'HASH') {  
                 unless ($currsec->{'encrypt'}{$item}) {  
                     $secchanges->{'encrypt'} = 1;  
                 }  
             } else {  
                 $secchanges->{'encrypt'} = 1;  
             }  
         } elsif (ref($currsec->{'encrypt'}) eq 'HASH') {  
             if ($currsec->{'encrypt'}{$item}) {  
                 $secchanges->{'encrypt'} = 1;  
             }  
         }  
     }  
     my $secrets;  
     if ($context eq 'ltisec') {  
         $secrets = 'ltisecrets';  
     } else {  
         $secrets = 'toolsecrets';  
     }  
     unless (exists($currsec->{'rules'})) {  
         $currsec->{'rules'} = {};  
     }  
     &password_rule_changes($secrets,$newsec->{'rules'},$currsec->{'rules'},$secchanges);  
   
     my @ids=&Apache::lonnet::current_machine_ids();  
     my %servers = &Apache::lonnet::get_servers($dom,'library');  
   
     foreach my $hostid (keys(%servers)) {  
         if (($hostid ne '') && (grep(/^\Q$hostid\E$/,@ids))) {  
             my $keyitem = 'form.'.$context.'_privkey_'.$hostid;  
             if (exists($env{$keyitem})) {  
                 $env{$keyitem} =~ s/(`)/'/g;  
                 if ($keyset{$hostid}) {  
                     if ($env{'form.'.$context.'_changeprivkey_'.$hostid}) {  
                         if ($env{$keyitem} ne '') {  
                             $secchanges->{'private'} = 1;  
                             $newkeyset->{$hostid} = $env{$keyitem};  
                         }  
                     }  
                 } elsif ($env{$keyitem} ne '') {  
                     unless (grep(/^\Q$hostid\E$/,@{$newsec->{'private'}{'keys'}})) {  
                         push(@{$newsec->{'private'}{'keys'}},$hostid);  
                     }  
                     $secchanges->{'private'} = 1;  
                     $newkeyset->{$hostid} = $env{$keyitem};  
                 }  
             }  
         }  
     }  
 }  
   
 sub store_security {  
     my ($dom,$context,$secchanges,$newkeyset,$keystore) = @_;  
     return unless ((ref($secchanges) eq 'HASH') && (ref($newkeyset) eq 'HASH') &&  
                    (ref($keystore) eq 'HASH'));  
     if (keys(%{$secchanges})) {  
         if ($secchanges->{'private'}) {  
             my $who = &escape($env{'user.name'}.':'.$env{'user.domain'});  
             foreach my $hostid (keys(%{$newkeyset})) {  
                 my $storehash = {  
                                    key => $newkeyset->{$hostid},  
                                    who => $env{'user.name'}.':'.$env{'user.domain'},  
                                 };  
                 $keystore->{$hostid} = &Apache::lonnet::store_dom($storehash,$context,'private',  
                                                                   $dom,$hostid);  
             }  
         }  
     }  
 }  
   
 sub lti_security_results {  
     my ($dom,$context,$secchanges,$newsec,$newkeyset,$keystore) = @_;  
     my $output;  
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);  
     my $needs_update;  
     foreach my $item (keys(%{$secchanges})) {  
         if ($item eq 'encrypt') {  
             $needs_update = 1;  
             my %encrypted;  
             if ($context eq 'lti') {  
                 %encrypted = (  
                               crs  => {  
                                         on => &mt('Encryption of stored link protection secrets defined in courses enabled'),  
                                         off => &mt('Encryption of stored link protection secrets defined in courses disabled'),  
                                       },  
                               dom => {  
                                        on => &mt('Encryption of stored link protection secrets defined in domain enabled'),  
                                        off => &mt('Encryption of stored link protection secrets defined in domain disabled'),  
                                      },  
                               consumers => {  
                                              on => &mt('Encryption of stored consumer secrets defined in domain enabled'),  
                                              off => &mt('Encryption of stored consumer secrets defined in domain disabled'),  
                                            },  
                              );  
             } else {  
                 %encrypted = (  
                               crs  => {  
                                         on => &mt('Encryption of stored external tool secrets defined in courses enabled'),  
                                         off => &mt('Encryption of stored external tool secrets defined in courses disabled'),  
                                       },  
                               dom => {  
                                        on => &mt('Encryption of stored external tool secrets defined in domain enabled'),  
                                        off => &mt('Encryption of stored external tool secrets defined in domain disabled'),  
                                      },  
                              );  
   
             }  
             my @types= ('crs','dom');  
             if ($context eq 'lti') {  
                 foreach my $type (@types) {  
                     undef($domdefaults{'linkprotenc_'.$type});  
                 }  
                 push(@types,'consumers');  
                 undef($domdefaults{'ltienc_consumers'});  
             } elsif ($context eq 'ltitools') {  
                 foreach my $type (@types) {  
                     undef($domdefaults{'toolenc_'.$type});  
                 }  
             }  
             foreach my $type (@types) {  
                 my $shown = $encrypted{$type}{'off'};  
                 if (ref($newsec->{$item}) eq 'HASH') {  
                     if ($newsec->{$item}{$type}) {  
                         if ($context eq 'lti') {  
                             if ($type eq 'consumers') {  
                                 $domdefaults{'ltienc_consumers'} = 1;  
                             } else {  
                                 $domdefaults{'linkprotenc_'.$type} = 1;  
                             }  
                         } elsif ($context eq 'ltitools') {  
                             $domdefaults{'toolenc_'.$type} = 1;  
                         }  
                         $shown = $encrypted{$type}{'on'};  
                     }  
                 }  
                 $output .= '<li>'.$shown.'</li>';  
             }  
         } elsif ($item eq 'rules') {  
             my %titles = &Apache::lonlocal::texthash(  
                                       min   => 'Minimum password length',  
                                       max   => 'Maximum password length',  
                                       chars => 'Required characters',  
                          );  
             foreach my $rule ('min','max') {  
                 if ($newsec->{rules}{$rule} eq '') {  
                     if ($rule eq 'min') {  
                         $output .= '<li>'.&mt('[_1] not set.',$titles{$rule});  
                                    ' '.&mt('Default of [_1] will be used',  
                                            $Apache::lonnet::passwdmin).'</li>';  
                     } else {  
                         $output .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>';  
                     }  
                 } else {  
                     $output .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$newsec->{rules}{$rule}).'</li>';  
                 }  
             }  
             if (ref($newsec->{'rules'}{'chars'}) eq 'ARRAY') {  
                 if (@{$newsec->{'rules'}{'chars'}} > 0) {  
                     my %rulenames = &Apache::lonlocal::texthash(  
                                              uc => 'At least one upper case letter',  
                                              lc => 'At least one lower case letter',  
                                              num => 'At least one number',  
                                              spec => 'At least one non-alphanumeric',  
                                     );  
                     my $needed = '<ul><li>'.  
                                  join('</li><li>',map {$rulenames{$_} } @{$newsec->{'rules'}{'chars'}}).  
                                  '</li></ul>';  
                     $output .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>';  
                 } else {  
                     $output .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';  
                 }  
             } else {  
                 $output .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';  
             }  
         } elsif ($item eq 'private') {  
             $needs_update = 1;  
             if ($context eq 'lti') {  
                 undef($domdefaults{'ltiprivhosts'});  
             } elsif ($context eq 'ltitools') {  
                 undef($domdefaults{'toolprivhosts'});  
             }  
             if (keys(%{$newkeyset})) {  
                 my @privhosts;  
                 foreach my $hostid (sort(keys(%{$newkeyset}))) {  
                     if ($keystore->{$hostid} eq 'ok') {  
                         $output .= '<li>'.&mt('Encryption key for storage of shared secrets saved for [_1]',$hostid).'</li>';  
                         unless (grep(/^\Q$hostid\E$/,@privhosts)) {  
                             push(@privhosts,$hostid);  
                         }  
                     }  
                 }  
                 if (@privhosts) {  
                     if ($context eq 'lti') {  
                         $domdefaults{'ltiprivhosts'} = \@privhosts;  
                     } elsif ($context eq 'ltitools') {  
                         $domdefaults{'toolprivhosts'} = \@privhosts;  
                     }  
                 }  
             }  
         } elsif ($item eq 'linkprot') {  
             next;  
         }  
     }  
     if ($needs_update) {  
         my $cachetime = 24*60*60;  
         &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);  
     }  
     return $output;  
 }  
   
 sub modify_lti {  
     my ($r,$dom,$action,$lastactref,%domconfig) = @_;  
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);  
     my ($newid,@allpos,%changes,%confhash,%ltienc,$errors,$resulttext);  
     my (%posslti,%posslticrs,%posscrstype);  
     my @courseroles = ('cc','in','ta','ep','st');  
     my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator);  
     my @lticourseroles = qw(Instructor TeachingAssistant Mentor Learner);  
     my @coursetypes = ('official','unofficial','community','textbook','placement','lti');  
     my %coursetypetitles = &Apache::lonlocal::texthash (  
                                official   => 'Official',  
                                unofficial => 'Unofficial',  
                                community  => 'Community',  
                                textbook   => 'Textbook',  
                                placement  => 'Placement Test',  
                                lti        => 'LTI Provider',  
     );  
     my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();  
     my %lt = &lti_names();  
     map { $posslti{$_} = 1; } @ltiroles;  
     map { $posslticrs{$_} = 1; } @lticourseroles;  
     map { $posscrstype{$_} = 1; } @coursetypes;  
   
     my %menutitles = &ltimenu_titles();  
     my (%currltisec,%secchanges,%newltisec,%newltienc,%newkeyset);  
   
     &fetch_secrets($dom,'ltisec',\%domconfig,\%currltisec,\%secchanges,\%newltisec,\%newkeyset);  
   
     my (%linkprotchg,$linkprotoutput,$is_home);  
     my $proterror = &Apache::courseprefs::process_linkprot($dom,'',$currltisec{'linkprot'},  
                                                            \%linkprotchg,'domain');  
     my $home = &Apache::lonnet::domain($dom,'primary');  
     unless (($home eq 'no_host') || ($home eq '')) {  
         my @ids=&Apache::lonnet::current_machine_ids();  
         foreach my $id (@ids) { if ($id eq $home) { $is_home=1; } }  
     }  
   
     if (keys(%linkprotchg)) {  
         $secchanges{'linkprot'} = 1;  
         my %oldlinkprot;  
         if (ref($currltisec{'linkprot'}) eq 'HASH') {  
             %oldlinkprot = %{$currltisec{'linkprot'}};  
         }  
         foreach my $id (keys(%linkprotchg)) {  
             if (ref($linkprotchg{$id}) eq 'HASH') {  
                 foreach my $inner (keys(%{$linkprotchg{$id}})) {  
                     if (($inner eq 'secret') || ($inner eq 'key')) {  
                         if ($is_home) {  
                             $newltienc{$id}{$inner} = $linkprotchg{$id}{$inner};  
                         }  
                     }  
                 }  
             } else {  
                 $newltisec{'linkprot'}{$id} = $linkprotchg{$id};  
             }  
         }  
         $linkprotoutput = &Apache::courseprefs::store_linkprot($dom,'','domain',\%linkprotchg,\%oldlinkprot);  
         if (keys(%linkprotchg)) {  
             %{$newltisec{'linkprot'}} = %linkprotchg;  
         }  
     }  
     if (ref($currltisec{'linkprot'}) eq 'HASH') {  
         foreach my $id (%{$currltisec{'linkprot'}}) {  
             next if ($id !~ /^\d+$/);  
             unless (exists($linkprotchg{$id})) {  
                 if (ref($currltisec{'linkprot'}{$id}) eq 'HASH') {  
                     foreach my $inner (keys(%{$currltisec{'linkprot'}{$id}})) {  
                         if (($inner eq 'secret') || ($inner eq 'key')) {  
                             if ($is_home) {  
                                 $newltienc{$id}{$inner} = $currltisec{'linkprot'}{$id}{$inner};  
                             }  
                         } else {  
                             $newltisec{'linkprot'}{$id}{$inner} = $currltisec{'linkprot'}{$id}{$inner};  
                         }  
                     }  
                 } else {  
                     $newltisec{'linkprot'}{$id} = $currltisec{'linkprot'}{$id};  
                 }  
             }  
         }  
     }  
     if ($proterror) {  
         $errors .= '<li>'.$proterror.'</li>';  
     }  
     my (@items,%deletions,%itemids);  
     if ($env{'form.lti_add'}) {  
         my $consumer = $env{'form.lti_consumer_add'};  
         $consumer =~ s/(`)/'/g;  
         ($newid,my $error) = &get_lti_id($dom,$consumer);  
         if ($newid) {  
             $itemids{'add'} = $newid;  
             push(@items,'add');  
             $changes{$newid} = 1;  
         } else {  
             my $error = &mt('Failed to acquire unique ID for new LTI configuration');  
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';  
         }  
     }  
     if (ref($domconfig{$action}) eq 'HASH') {  
         my @todelete = &Apache::loncommon::get_env_multiple('form.lti_del');  
         if (@todelete) {  
             map { $deletions{$_} = 1; } @todelete;  
         }  
         my $maxnum = $env{'form.lti_maxnum'};  
         for (my $i=0; $i<$maxnum; $i++) {  
             my $itemid = $env{'form.lti_id_'.$i};  
             $itemid =~ s/\D+//g;  
             if (ref($domconfig{$action}{$itemid}) eq 'HASH') {  
                 if ($deletions{$itemid}) {  
                     $changes{$itemid} = $domconfig{$action}{$itemid}{'consumer'};  
                 } else {  
                     push(@items,$i);  
                     $itemids{$i} = $itemid;  
                 }  
             }  
         }  
     }  
     my (%keystore,$secstored);  
     if ($is_home) {  
         &store_security($dom,'lti',\%secchanges,\%newkeyset,\%keystore);  
     }  
   
     my ($cipher,$privnum);  
     if ((@items > 0) && ($is_home)) {  
         ($cipher,$privnum) = &get_priv_creds($dom,$home,$secchanges{'encrypt'},  
                                              $newltisec{'encrypt'},$keystore{$home});  
     }  
     foreach my $idx (@items) {  
         my $itemid = $itemids{$idx};  
         next unless ($itemid);  
         my %currlti;  
         unless ($idx eq 'add') {  
             if (ref($domconfig{$action}) eq 'HASH') {  
                 if (ref($domconfig{$action}{$itemid}) eq 'HASH') {  
                     %currlti = %{$domconfig{$action}{$itemid}};  
                 }  
             }  
         }  
         my $position = $env{'form.lti_pos_'.$itemid};  
         $position =~ s/\D+//g;  
         if ($position ne '') {  
             $allpos[$position] = $itemid;  
         }  
         foreach my $item ('consumer','lifetime','requser','crsinc') {  
             my $formitem = 'form.lti_'.$item.'_'.$idx;  
             $env{$formitem} =~ s/(`)/'/g;  
             if ($item eq 'lifetime') {  
                 $env{$formitem} =~ s/[^\d.]//g;  
             }  
             if ($env{$formitem} ne '') {  
                 $confhash{$itemid}{$item} = $env{$formitem};  
                 unless (($idx eq 'add') || ($changes{$itemid})) {  
                     if ($currlti{$item} ne $confhash{$itemid}{$item}) {  
                         $changes{$itemid} = 1;  
                     }  
                 }  
             }  
         }  
         if ($env{'form.lti_version_'.$idx} eq 'LTI-1p0') {  
             $confhash{$itemid}{'version'} = $env{'form.lti_version_'.$idx};  
         }  
         if ($confhash{$itemid}{'requser'}) {  
             if ($env{'form.lti_mapuser_'.$idx} eq 'sourcedid') {  
                 $confhash{$itemid}{'mapuser'} = 'lis_person_sourcedid';  
             } elsif ($env{'form.lti_mapuser_'.$idx} eq 'email') {  
                 $confhash{$itemid}{'mapuser'} = 'lis_person_contact_email_primary';  
             } elsif ($env{'form.lti_mapuser_'.$idx} eq 'other') {  
                 my $mapuser = $env{'form.lti_customuser_'.$idx};  
                 $mapuser =~ s/(`)/'/g;  
                 $mapuser =~ s/^\s+|\s+$//g;  
                 $confhash{$itemid}{'mapuser'} = $mapuser;  
             }  
             my @possmakeuser = &Apache::loncommon::get_env_multiple('form.lti_makeuser_'.$idx);  
             my @makeuser;  
             foreach my $ltirole (sort(@possmakeuser)) {  
                 if ($posslti{$ltirole}) {  
                     push(@makeuser,$ltirole);  
                 }  
             }  
             $confhash{$itemid}{'makeuser'} = \@makeuser;  
             if (@makeuser) {  
                 my $lcauth = $env{'form.lti_lcauth_'.$idx};  
                 if ($lcauth =~ /^(internal|krb4|krb5|localauth)$/) {  
                     $confhash{$itemid}{'lcauth'} = $lcauth;  
                     if ($lcauth ne 'internal') {  
                         my $lcauthparm = $env{'form.lti_lcauthparm_'.$idx};  
                         $lcauthparm =~ s/^(\s+|\s+)$//g;  
                         $lcauthparm =~ s/`//g;  
                         if ($lcauthparm ne '') {  
                             $confhash{$itemid}{'lcauthparm'} = $lcauthparm;  
                         }  
                     }  
                 } else {  
                     $confhash{$itemid}{'lcauth'} = 'lti';  
                 }  
             }  
             my @possinstdata =  &Apache::loncommon::get_env_multiple('form.lti_instdata_'.$idx);  
             if (@possinstdata) {  
                 foreach my $field (@possinstdata) {  
                     if (exists($fieldtitles{$field})) {  
                         push(@{$confhash{$itemid}{'instdata'}});  
                     }  
                 }  
             }  
             if ($env{'form.lti_callback_'.$idx}) {  
                 if ($env{'form.lti_callbackparam_'.$idx}) {  
                     my $callback = $env{'form.lti_callbackparam_'.$idx};  
                     $callback =~ s/^\s+|\s+$//g;  
                     $confhash{$itemid}{'callback'} = $callback;  
                 }  
             }  
             foreach my $field ('topmenu','inlinemenu') {  
                 if ($env{'form.lti_'.$field.'_'.$idx}) {  
                     $confhash{$itemid}{$field} = 1;  
                 }  
             }  
             if ($env{'form.lti_topmenu_'.$idx} || $env{'form.lti_inlinemenu_'.$idx}) {  
                 $confhash{$itemid}{lcmenu} = [];  
                 my @possmenu = &Apache::loncommon::get_env_multiple('form.lti_menuitem_'.$idx);  
                 foreach my $field (@possmenu) {  
                     if (exists($menutitles{$field})) {  
                         if ($field eq 'grades') {  
                             next unless ($env{'form.lti_inlinemenu_'.$idx});  
                         }  
                         push(@{$confhash{$itemid}{lcmenu}},$field);  
                     }  
                 }  
             }  
             if ($confhash{$itemid}{'crsinc'}) {  
                 if (($env{'form.lti_mapcrs_'.$idx} eq 'course_offering_sourcedid') ||  
                     ($env{'form.lti_mapcrs_'.$idx} eq 'context_id'))  {  
                     $confhash{$itemid}{'mapcrs'} = $env{'form.lti_mapcrs_'.$idx};  
                 } elsif ($env{'form.lti_mapcrs_'.$idx} eq 'other') {  
                     my $mapcrs = $env{'form.lti_mapcrsfield_'.$idx};  
                     $mapcrs =~ s/(`)/'/g;  
                     $mapcrs =~ s/^\s+|\s+$//g;  
                     $confhash{$itemid}{'mapcrs'} = $mapcrs;  
                 }  
                 my @posstypes = &Apache::loncommon::get_env_multiple('form.lti_mapcrstype_'.$idx);  
                 my @crstypes;  
                 foreach my $type (sort(@posstypes)) {  
                     if ($posscrstype{$type}) {  
                         push(@crstypes,$type);  
                     }  
                 }  
                 $confhash{$itemid}{'mapcrstype'} = \@crstypes;  
                 if ($env{'form.lti_storecrs_'.$idx}) {  
                     $confhash{$itemid}{'storecrs'} = 1;  
                 }  
                 if ($env{'form.lti_makecrs_'.$idx}) {  
                     $confhash{$itemid}{'makecrs'} = 1;  
                 }  
                 foreach my $ltirole (@lticourseroles) {  
                     my $possrole = $env{'form.lti_maprole_'.$ltirole.'_'.$idx};  
                     if (grep(/^\Q$possrole\E$/,@courseroles)) {  
                         $confhash{$itemid}{'maproles'}{$ltirole} = $possrole;  
                     }  
                 }  
                 my @possenroll = &Apache::loncommon::get_env_multiple('form.lti_selfenroll_'.$idx);  
                 my @selfenroll;  
                 foreach my $type (sort(@possenroll)) {  
                     if ($posslticrs{$type}) {  
                         push(@selfenroll,$type);  
                     }  
                 }  
                 $confhash{$itemid}{'selfenroll'} = \@selfenroll;  
                 if ($env{'form.lti_crssec_'.$idx}) {  
                     if ($env{'form.lti_crssecsrc_'.$idx} eq 'course_section_sourcedid') {  
                         $confhash{$itemid}{'section'} = $env{'form.lti_crssecsrc_'.$idx};  
                     } elsif ($env{'form.lti_crssecsrc_'.$idx} eq 'other') {  
                         my $section = $env{'form.lti_customsection_'.$idx};  
                         $section =~ s/(`)/'/g;  
                         $section =~ s/^\s+|\s+$//g;  
                         if ($section ne '') {  
                             $confhash{$itemid}{'section'} = $section;  
                         }  
                     }  
                 }  
                 foreach my $field ('passback','roster') {  
                     if ($env{'form.lti_'.$field.'_'.$idx}) {  
                         $confhash{$itemid}{$field} = 1;  
                     }  
                 }  
                 if ($env{'form.lti_passback_'.$idx}) {  
                     if ($env{'form.lti_passbackformat_'.$idx} eq '1.0') {  
                         $confhash{$itemid}{'passbackformat'} = '1.0';  
                     } else {  
                         $confhash{$itemid}{'passbackformat'} = '1.1';  
                     }  
                 }  
             }  
             unless (($idx eq 'add') || ($changes{$itemid})) {  
                 if ($confhash{$itemid}{'crsinc'}) {  
                     foreach my $field ('mapcrs','storecrs','makecrs','section','passback','roster') {  
                         if ($currlti{$field} ne $confhash{$itemid}{$field}) {  
                             $changes{$itemid} = 1;  
                         }  
                     }  
                     unless ($changes{$itemid}) {  
                         if ($currlti{'passback'} eq $confhash{$itemid}{'passback'}) {  
                             if ($currlti{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) {  
                                 $changes{$itemid} = 1;  
                             }  
                         }  
                     }  
                     foreach my $field ('mapcrstype','selfenroll') {  
                         unless ($changes{$itemid}) {  
                             if (ref($currlti{$field}) eq 'ARRAY') {  
                                 if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {  
                                     my @diffs = &Apache::loncommon::compare_arrays($currlti{$field},  
                                                                                    $confhash{$itemid}{$field});  
                                     if (@diffs) {  
                                         $changes{$itemid} = 1;  
                                     }  
                                 } elsif (@{$currlti{$field}} > 0) {  
                                     $changes{$itemid} = 1;  
                                 }  
                             } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {  
                                 if (@{$confhash{$itemid}{$field}} > 0) {  
                                     $changes{$itemid} = 1;  
                                 }  
                             }  
                         }  
                     }  
                     unless ($changes{$itemid}) {  
                         if (ref($currlti{'maproles'}) eq 'HASH') {  
                             if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {  
                                 foreach my $ltirole (keys(%{$currlti{'maproles'}})) {  
                                     if ($currlti{'maproles'}{$ltirole} ne  
                                         $confhash{$itemid}{'maproles'}{$ltirole}) {  
                                         $changes{$itemid} = 1;  
                                         last;  
                                     }  
                                 }  
                                 unless ($changes{$itemid}) {  
                                     foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) {  
                                         if ($confhash{$itemid}{'maproles'}{$ltirole} ne  
                                             $currlti{'maproles'}{$ltirole}) {  
                                             $changes{$itemid} = 1;  
                                             last;  
                                         }  
                                     }  
                                 }  
                             } elsif (keys(%{$currlti{'maproles'}}) > 0) {  
                                 $changes{$itemid} = 1;  
                             }  
                         } elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {  
                             unless ($changes{$itemid}) {  
                                 if (keys(%{$confhash{$itemid}{'maproles'}}) > 0) {  
                                     $changes{$itemid} = 1;  
                                 }  
                             }  
                         }  
                     }  
                 }  
                 unless ($changes{$itemid}) {  
                     foreach my $field ('mapuser','lcauth','lcauthparm','topmenu','inlinemenu','callback') {  
                         if ($currlti{$field} ne $confhash{$itemid}{$field}) {  
                             $changes{$itemid} = 1;  
                         }  
                     }  
                     unless ($changes{$itemid}) {  
                         foreach my $field ('makeuser','lcmenu') {  
                             if (ref($currlti{$field}) eq 'ARRAY') {  
                                 if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {  
                                     my @diffs = &Apache::loncommon::compare_arrays($currlti{$field},  
                                                                                    $confhash{$itemid}{$field});  
                                     if (@diffs) {  
                                         $changes{$itemid} = 1;  
                                     }  
                                 } elsif (@{$currlti{$field}} > 0) {  
                                     $changes{$itemid} = 1;  
                                 }  
                             } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {  
                                 if (@{$confhash{$itemid}{$field}} > 0) {  
                                     $changes{$itemid} = 1;  
                                 }  
                             }  
                         }  
                     }  
                 }  
             }  
         }  
         if ($is_home) {  
             my $keyitem = 'form.lti_key_'.$idx;  
             $env{$keyitem} =~ s/(`)/'/g;  
             if ($env{$keyitem} ne '') {  
                 $ltienc{$itemid}{'key'} = $env{$keyitem};  
                 unless ($changes{$itemid}) {  
                     if ($currlti{'key'} ne $env{$keyitem}) {  
                         $changes{$itemid} = 1;  
                     }  
                 }  
             }  
             my $secretitem = 'form.lti_secret_'.$idx;  
             $env{$secretitem} =~ s/(`)/'/g;  
             if ($currlti{'usable'}) {  
                 if ($env{'form.lti_changesecret_'.$idx}) {  
                     if ($env{$secretitem} ne '') {  
                         if ($privnum && $cipher) {  
                             $ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});  
                             $confhash{$itemid}{'cipher'} = $privnum;  
                         } else {  
                             $ltienc{$itemid}{'secret'} = $env{$secretitem};  
                         }  
                         $changes{$itemid} = 1;  
                     }  
                 } else {  
                     $ltienc{$itemid}{'secret'} = $currlti{'secret'};  
                     $confhash{$itemid}{'cipher'} = $currlti{'cipher'};  
                 }  
                 if (ref($ltienc{$itemid}) eq 'HASH') {  
                     if (($ltienc{$itemid}{'key'} ne '') && ($ltienc{$itemid}{'secret'} ne '')) {  
                         $confhash{$itemid}{'usable'} = 1;  
                     }  
                 }  
             } elsif ($env{$secretitem} ne '') {  
                 if ($privnum && $cipher) {  
                     $ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});  
                     $confhash{$itemid}{'cipher'} = $privnum;  
                 } else {  
                     $ltienc{$itemid}{'secret'} = $env{$secretitem};  
                 }  
                 if (ref($ltienc{$itemid}) eq 'HASH') {  
                     if (($ltienc{$itemid}{'key'} ne '') && ($ltienc{$itemid}{'key'} ne '')) {  
                         $confhash{$itemid}{'usable'} = 1;  
                     }  
                 }  
                 $changes{$itemid} = 1;  
             }  
         }  
         unless ($changes{$itemid}) {  
             foreach my $key (keys(%currlti)) {  
                 if (ref($currlti{$key}) eq 'HASH') {  
                     if (ref($confhash{$itemid}{$key}) eq 'HASH') {  
                         foreach my $innerkey (keys(%{$currlti{$key}})) {  
                             unless (exists($confhash{$itemid}{$key}{$innerkey})) {  
                                 $changes{$itemid} = 1;  
                                 last;  
                             }  
                         }  
                     } elsif (keys(%{$currlti{$key}}) > 0) {  
                         $changes{$itemid} = 1;  
                     }  
                 }  
                 last if ($changes{$itemid});  
             }  
         }  
     }  
     if (@allpos > 0) {  
         my $idx = 0;  
         foreach my $itemid (@allpos) {  
             if ($itemid ne '') {  
                 $confhash{$itemid}{'order'} = $idx;  
                 if (ref($domconfig{$action}) eq 'HASH') {  
                     if (ref($domconfig{$action}{$itemid}) eq 'HASH') {  
                         if ($domconfig{$action}{$itemid}{'order'} ne $idx) {  
                             $changes{$itemid} = 1;  
                         }  
                     }  
                 }  
                 $idx ++;  
             }  
         }  
     }  
   
     if ((keys(%changes) == 0) && (keys(%secchanges) == 0)) {  
         return &mt('No changes made.');  
     }  
   
     my %ltihash = (  
                       $action => { %confhash }  
                   );  
     my %ltienchash;  
   
     if ($is_home) {  
         %ltienchash = (  
                          $action => { %ltienc }  
                       );  
     }  
     if (keys(%secchanges)) {  
         $ltihash{'ltisec'} = \%newltisec;  
         if ($secchanges{'linkprot'}) {  
             if ($is_home) {  
                 $ltienchash{'linkprot'} = \%newltienc;  
             }  
         }  
     }  
     my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,$dom);  
     if ($putresult eq 'ok') {  
         if (keys(%ltienchash)) {  
             &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1);  
         }  
         $resulttext = &mt('Changes made:').'<ul>';  
         if (keys(%secchanges) > 0) {  
             $resulttext .= &lti_security_results($dom,'lti',\%secchanges,\%newltisec,\%newkeyset,\%keystore);  
             if (exists($secchanges{'linkprot'})) {  
                 $resulttext .= $linkprotoutput;  
             }  
         }  
         if (keys(%changes) > 0) {  
             my $cachetime = 24*60*60;  
             &Apache::lonnet::do_cache_new('lti',$dom,\%confhash,$cachetime);  
             if (ref($lastactref) eq 'HASH') {  
                 $lastactref->{'lti'} = 1;  
             }  
             my %bynum;  
             foreach my $itemid (sort(keys(%changes))) {  
                 if (ref($confhash{$itemid}) eq 'HASH') {  
                     my $position = $confhash{$itemid}{'order'};  
                     $bynum{$position} = $itemid;  
                 }  
             }  
             foreach my $pos (sort { $a <=> $b } keys(%bynum)) {  
                 my $itemid = $bynum{$pos};  
                 if (ref($confhash{$itemid}) eq 'HASH') {  
                     $resulttext .= '<li><b>'.$confhash{$itemid}{'consumer'}.'</b><ul>';  
                     my $position = $pos + 1;  
                     $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';  
                     foreach my $item ('version','lifetime') {  
                         if ($confhash{$itemid}{$item} ne '') {  
                             $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{$item}.'</li>';  
                         }  
                     }  
                     if ($ltienc{$itemid}{'key'} ne '') {  
                         $resulttext .= '<li>'.$lt{'key'}.':&nbsp;'.$ltienc{$itemid}{'key'}.'</li>';  
                     }  
                     if ($ltienc{$itemid}{'secret'} ne '') {  
                         $resulttext .= '<li>'.$lt{'secret'}.':&nbsp;['.&mt('not shown').']</li>';  
                     }  
                     if ($confhash{$itemid}{'requser'}) {  
                         if ($confhash{$itemid}{'callback'}) {  
                             $resulttext .= '<li>'.&mt('Callback setting').': '.$confhash{$itemid}{'callback'}.'</li>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('Callback to logout LON-CAPA on log out from Consumer').'</li>';  
                         }  
                         if ($confhash{$itemid}{'mapuser'}) {  
                             my $shownmapuser;  
                             if ($confhash{$itemid}{'mapuser'} eq 'lis_person_sourcedid') {  
                                 $shownmapuser = $lt{'sourcedid'}.' (lis_person_sourcedid)';  
                             } elsif ($confhash{$itemid}{'mapuser'} eq 'lis_person_contact_email_primary') {  
                                 $shownmapuser = $lt{'email'}.' (lis_person_contact_email_primary)';  
                             } else {  
                                 $shownmapuser = &mt('Other').' ('.$confhash{$itemid}{'mapuser'}.')';  
                             }  
                             $resulttext .= '<li>'.&mt('LON-CAPA username').': '.$shownmapuser.'</li>';  
                         }  
                         if (ref($confhash{$itemid}{'makeuser'}) eq 'ARRAY') {  
                             if (@{$confhash{$itemid}{'makeuser'}} > 0) {  
                                 $resulttext .= '<li>'.&mt('Following roles may create user accounts: [_1]',  
                                                           join(', ',@{$confhash{$itemid}{'makeuser'}})).'<br />';  
                                 if ($confhash{$itemid}{'lcauth'} eq 'lti') {  
                                     $resulttext .= &mt('New users will only be able to authenticate via LTI').'</li>';  
                                 } else {  
                                     $resulttext .= &mt('New users will be assigned LON-CAPA authentication: [_1]',  
                                                        $confhash{$itemid}{'lcauth'});  
                                     if ($confhash{$itemid}{'lcauth'} eq 'internal') {  
                                         $resulttext .= '; '.&mt('a randomly generated password will be created');  
                                     } elsif ($confhash{$itemid}{'lcauth'} eq 'localauth') {  
                                         if ($confhash{$itemid}{'lcauthparm'} ne '') {  
                                             $resulttext .= ' '.&mt('with argument: [_1]',$confhash{$itemid}{'lcauthparm'});  
                                         }  
                                     } else {  
                                         $resulttext .= '; '.&mt('Kerberos domain: [_1]',$confhash{$itemid}{'lcauthparm'});  
                                     }  
                                 }  
                                 $resulttext .= '</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('User account creation not permitted.').'</li>';  
                             }  
                         }  
                         if (ref($confhash{$itemid}{'instdata'}) eq 'ARRAY') {  
                             if (@{$confhash{$itemid}{'instdata'}} > 0) {  
                                 $resulttext .= '<li>'.&mt('Institutional data will be used when creating a new user for: [_1]',  
                                                           join(', ',map { $fieldtitles{$_}; } @{$confhash{$itemid}{'instdata'}})).'</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('No institutional data used when creating a new user.').'</li>';  
                             }  
                         }  
                         foreach my $item ('topmenu','inlinemenu') {  
                             $resulttext .= '<li>'.$lt{$item}.':&nbsp;';  
                             if ($confhash{$itemid}{$item}) {  
                                 $resulttext .= &mt('Yes');  
                             } else {  
                                 $resulttext .= &mt('No');  
                             }  
                             $resulttext .= '</li>';  
                         }  
                         if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') {  
                             if (@{$confhash{$itemid}{'lcmenu'}} > 0) {  
                                 $resulttext .= '<li>'.&mt('Menu items:').' '.  
                                                join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>';  
                             }  
                         }  
                         if ($confhash{$itemid}{'crsinc'}) {  
                             if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {  
                                 my $rolemaps;  
                                 foreach my $role (@ltiroles) {  
                                     if ($confhash{$itemid}{'maproles'}{$role}) {  
                                         $rolemaps .= ('&nbsp;'x2).$role.'='.  
                                                      &Apache::lonnet::plaintext($confhash{$itemid}{'maproles'}{$role},  
                                                                                 'Course').',';  
                                     }  
                                 }  
                                 if ($rolemaps) {  
                                     $rolemaps =~ s/,$//;  
                                     $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>';  
                                 }  
                             }  
                             if ($confhash{$itemid}{'mapcrs'}) {  
                                 $resulttext .= '<li>'.&mt('Unique course identifier').': '.$confhash{$itemid}{'mapcrs'}.'</li>';  
                             }  
                             if (ref($confhash{$itemid}{'mapcrstype'}) eq 'ARRAY') {  
                                 if (@{$confhash{$itemid}{'mapcrstype'}} > 0) {  
                                     $resulttext .= '<li>'.&mt('Mapping for the following LON-CAPA course types: [_1]',  
                                                    join(', ',map { $coursetypetitles{$_}; } @coursetypes)).  
                                                    '</li>';  
                                 } else {  
                                     $resulttext .= '<li>'.&mt('No mapping to LON-CAPA courses').'</li>';  
                                 }  
                             }  
                             if ($confhash{$itemid}{'storecrs'}) {  
                                 $resulttext .= '<li>'.&mt('Store mapping of course identifier to LON-CAPA CourseID').': '.$confhash{$itemid}{'storecrs'}.'</li>';  
                             }  
                             if ($confhash{$itemid}{'makecrs'}) {  
                                 $resulttext .= '<li>'.&mt('Instructor may create course (if absent).').'</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('Instructor may not create course (if absent).').'</li>';  
                             }  
                             if (ref($confhash{$itemid}{'selfenroll'}) eq 'ARRAY') {  
                                 if (@{$confhash{$itemid}{'selfenroll'}} > 0) {  
                                     $resulttext .= '<li>'.&mt('Self-enrollment for following roles: [_1]',  
                                                               join(', ',@{$confhash{$itemid}{'selfenroll'}})).  
                                                    '</li>';  
                                 } else {  
                                     $resulttext .= '<li>'.&mt('Self-enrollment not permitted').'</li>';  
                                 }  
                             }  
                             if ($confhash{$itemid}{'section'}) {  
                                 if ($confhash{$itemid}{'section'} eq 'course_section_sourcedid') {  
                                     $resulttext .= '<li>'.&mt('User section from standard field:').  
                                                          ' (course_section_sourcedid)'.'</li>';  
                                 } else {  
                                     $resulttext .= '<li>'.&mt('User section from:').' '.  
                                                           $confhash{$itemid}{'section'}.'</li>';  
                                 }  
                             } else {  
                                 $resulttext .= '<li>'.&mt('No section assignment').'</li>';  
                             }  
                             foreach my $item ('passback','roster','topmenu','inlinemenu') {  
                                 $resulttext .= '<li>'.$lt{$item}.':&nbsp;';  
                                 if ($confhash{$itemid}{$item}) {  
                                     $resulttext .= &mt('Yes');  
                                     if ($item eq 'passback') {  
                                         if ($confhash{$itemid}{'passbackformat'} eq '1.0') {  
                                             $resulttext .= '&nbsp;('.&mt('Outcomes Extension (1.0)').')';  
                                         } elsif ($confhash{$itemid}{'passbackformat'} eq '1.1') {  
                                             $resulttext .= '&nbsp;('.&mt('Outcomes Service (1.1)').')';  
                                         }  
                                     }  
                                 } else {  
                                     $resulttext .= &mt('No');  
                                 }  
                                 $resulttext .= '</li>';  
                             }  
                             if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') {  
                                 if (@{$confhash{$itemid}{'lcmenu'}} > 0) {  
                                     $resulttext .= '<li>'.&mt('Menu items:').' '.  
                                                    join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>';  
                                 } else {  
                                     $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>';  
                                 }  
                             }  
                         }  
                     }  
                     $resulttext .= '</ul></li>';  
                 }  
             }  
             if (keys(%deletions)) {  
                 foreach my $itemid (sort { $a <=> $b } keys(%deletions)) {  
                     $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';  
                 }  
             }  
         }  
         $resulttext .= '</ul>';  
         if (ref($lastactref) eq 'HASH') {  
             if (($secchanges{'encrypt'}) || ($secchanges{'private'})) {  
                 $lastactref->{'domdefaults'} = 1;  
             }  
         }  
     } else {  
         $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';  
     }  
     if ($errors) {  
         $resulttext .= &mt('The following errors occurred: ').'<ul>'.  
                        $errors.'</ul>';  
     }  
     return $resulttext;  
 }  
   
 sub get_priv_creds {  
     my ($dom,$home,$encchg,$encrypt,$storedsec) = @_;  
     my ($needenc,$cipher,$privnum);  
     my %domdefs = &Apache::lonnet::get_domain_defaults($dom);  
     if (($encchg) && (ref($encrypt) eq 'HASH')) {  
         $needenc = $encrypt->{'consumers'}  
     } else {  
         $needenc = $domdefs{'ltienc_consumers'};  
     }  
     if ($needenc) {  
         if (($storedsec eq 'ok') || ((ref($domdefs{'ltiprivhosts'}) eq 'ARRAY') &&  
                                      (grep(/^\Q$home\E$/,@{$domdefs{'ltiprivhosts'}})))) {  
                         my %privhash  = &Apache::lonnet::restore_dom('lti','private',$dom,$home,1);  
             my $privkey = $privhash{'key'};  
             $privnum = $privhash{'version'};  
             if (($privnum) && ($privkey ne '')) {  
                 $cipher = Crypt::CBC->new({'key'     => $privkey,  
                                           'cipher'  => 'DES'});  
             }  
         }  
     }  
     return ($cipher,$privnum);  
 }  
   
 sub get_lti_id {  
     my ($domain,$consumer) = @_;  
     # get lock on lti db  
     my $lockhash = {  
                       lock => $env{'user.name'}.  
                               ':'.$env{'user.domain'},  
                    };  
     my $tries = 0;  
     my $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);  
     my ($id,$error);  
   
     while (($gotlock ne 'ok') && ($tries<10)) {  
         $tries ++;  
         sleep (0.1);  
         $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);  
     }  
     if ($gotlock eq 'ok') {  
         my %currids = &Apache::lonnet::dump_dom('lti',$domain);  
         if ($currids{'lock'}) {  
             delete($currids{'lock'});  
             if (keys(%currids)) {  
                 my @curr = sort { $a <=> $b } keys(%currids);  
                 if ($curr[-1] =~ /^\d+$/) {  
                     $id = 1 + $curr[-1];  
                 }  
             } else {  
                 $id = 1;  
             }  
             if ($id) {  
                 unless (&Apache::lonnet::newput_dom('lti',{ $id => $consumer },$domain) eq 'ok') {  
                     $error = 'nostore';  
                 }  
             } else {  
                 $error = 'nonumber';  
             }  
         }  
         my $dellockoutcome = &Apache::lonnet::del_dom('lti',['lock'],$domain);  
     } else {  
         $error = 'nolock';  
     }  
     return ($id,$error);  
 }  
   
 sub modify_autoenroll {  sub modify_autoenroll {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,%changes);      my ($resulttext,%changes);
Line 14059  sub modify_autoenroll { Line 7798  sub modify_autoenroll {
     my $autorun = &Apache::lonnet::auto_run(undef,$dom),      my $autorun = &Apache::lonnet::auto_run(undef,$dom),
     my %title = ( run => 'Auto-enrollment active',      my %title = ( run => 'Auto-enrollment active',
                   sender => 'Sender for notification messages',                    sender => 'Sender for notification messages',
                   coowners => 'Automatic assignment of co-ownership to instructors of record (institutional data)',                    coowners => 'Automatic assignment of co-ownership to instructors of record (institutional data)');
                   autofailsafe => 'Failsafe for no drops if institutional data missing for a section');  
     my @offon = ('off','on');      my @offon = ('off','on');
     my $sender_uname = $env{'form.sender_uname'};      my $sender_uname = $env{'form.sender_uname'};
     my $sender_domain = $env{'form.sender_domain'};      my $sender_domain = $env{'form.sender_domain'};
Line 14070  sub modify_autoenroll { Line 7808  sub modify_autoenroll {
         $sender_domain = '';          $sender_domain = '';
     }      }
     my $coowners = $env{'form.autoassign_coowners'};      my $coowners = $env{'form.autoassign_coowners'};
     my $autofailsafe = $env{'form.autoenroll_autofailsafe'};  
     $autofailsafe =~ s{^\s+|\s+$}{}g;  
     if ($autofailsafe =~ /\D/) {  
         undef($autofailsafe);  
     }  
     my $failsafe = $env{'form.autoenroll_failsafe'};  
     unless (($failsafe eq 'zero') || ($failsafe eq 'any')) {  
         $failsafe = 'off';  
         undef($autofailsafe);  
     }  
     my %autoenrollhash =  (      my %autoenrollhash =  (
                        autoenroll => { 'run' => $env{'form.autoenroll_run'},                         autoenroll => { 'run' => $env{'form.autoenroll_run'},
                                        'sender_uname' => $sender_uname,                                         'sender_uname' => $sender_uname,
                                        'sender_domain' => $sender_domain,                                         'sender_domain' => $sender_domain,
                                        'co-owners' => $coowners,                                         'co-owners' => $coowners,
                                        'autofailsafe' => $autofailsafe,  
                                        'failsafe' => $failsafe,  
                                 }                                  }
                      );                       );
     my $putresult = &Apache::lonnet::put_dom('configuration',\%autoenrollhash,      my $putresult = &Apache::lonnet::put_dom('configuration',\%autoenrollhash,
Line 14113  sub modify_autoenroll { Line 7839  sub modify_autoenroll {
             }              }
         } elsif ($coowners) {          } elsif ($coowners) {
             $changes{'coowners'} = 1;              $changes{'coowners'} = 1;
         }          }      
         if ($currautoenroll{'autofailsafe'} ne $autofailsafe) {  
             $changes{'autofailsafe'} = 1;  
         }  
         if ($currautoenroll{'failsafe'} ne $failsafe) {  
             $changes{'failsafe'} = 1;  
         }  
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
             $resulttext = &mt('Changes made:').'<ul>';              $resulttext = &mt('Changes made:').'<ul>';
             if ($changes{'run'}) {              if ($changes{'run'}) {
Line 14139  sub modify_autoenroll { Line 7859  sub modify_autoenroll {
                     $lastactref->{'domainconfig'} = 1;                      $lastactref->{'domainconfig'} = 1;
                 }                  }
             }              }
             if ($changes{'autofailsafe'}) {  
                 if ($autofailsafe ne '') {  
                     $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section set to: [_1]',$autofailsafe).'</li>';  
                 } else {  
                     $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section not in use').'</li>';  
                 }  
             }  
             if ($changes{'failsafe'}) {  
                 if ($failsafe eq 'off') {  
                     unless ($changes{'autofailsafe'}) {  
                         $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section not in use').'</li>';  
                     }  
                 } elsif ($failsafe eq 'zero') {  
                     $resulttext .= '<li>'.&mt('Failsafe applies if retrieved section enrollment is zero').'</li>';  
                 } else {  
                     $resulttext .= '<li>'.&mt('Failsafe applies if retrieved section enrollment is zero or greater').'</li>';  
                 }  
             }  
             if (($changes{'autofailsafe'}) || ($changes{'failsafe'})) {  
                 &Apache::lonnet::get_domain_defaults($dom,1);  
                 if (ref($lastactref) eq 'HASH') {  
                     $lastactref->{'domdefaults'} = 1;  
                 }  
             }  
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
         } else {          } else {
             $resulttext = &mt('No changes made to auto-enrollment settings');              $resulttext = &mt('No changes made to auto-enrollment settings');
Line 14184  sub modify_autoupdate { Line 7880  sub modify_autoupdate {
     }      }
     my @offon = ('off','on');      my @offon = ('off','on');
     my %title = &Apache::lonlocal::texthash (      my %title = &Apache::lonlocal::texthash (
                     run        => 'Auto-update:',                     run => 'Auto-update:',
                     classlists => 'Updates to user information in classlists?',                     classlists => 'Updates to user information in classlists?'
                     unexpired  => 'Skip updates for users without active or future roles?',  
                     lastactive => 'Skip updates for inactive users?',  
                 );                  );
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);      my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
     my %fieldtitles = &Apache::lonlocal::texthash (      my %fieldtitles = &Apache::lonlocal::texthash (
Line 14231  sub modify_autoupdate { Line 7925  sub modify_autoupdate {
     my %updatehash = (      my %updatehash = (
                       autoupdate => { run => $env{'form.autoupdate_run'},                        autoupdate => { run => $env{'form.autoupdate_run'},
                                       classlists => $env{'form.classlists'},                                        classlists => $env{'form.classlists'},
                                       unexpired  => $env{'form.unexpired'},  
                                       fields => {%fields},                                        fields => {%fields},
                                       lockablenames => \@lockablenames,                                        lockablenames => \@lockablenames,
                                     }                                      }
                      );                       );
     my $lastactivedays;  
     if ($env{'form.lastactive'}) {  
         $lastactivedays = $env{'form.lastactivedays'};  
         $lastactivedays =~ s/^\s+|\s+$//g;  
         unless ($lastactivedays =~ /^\d+$/) {  
             undef($lastactivedays);  
             $env{'form.lastactive'} = 0;  
         }  
     }  
     $updatehash{'autoupdate'}{'lastactive'} = $lastactivedays;  
     foreach my $key (keys(%currautoupdate)) {      foreach my $key (keys(%currautoupdate)) {
         if (($key eq 'run') || ($key eq 'classlists') || ($key eq 'unexpired') || ($key eq 'lastactive')) {          if (($key eq 'run') || ($key eq 'classlists')) {
             if (exists($updatehash{autoupdate}{$key})) {              if (exists($updatehash{autoupdate}{$key})) {
                 if ($currautoupdate{$key} ne $updatehash{autoupdate}{$key}) {                  if ($currautoupdate{$key} ne $updatehash{autoupdate}{$key}) {
                     $changes{$key} = 1;                      $changes{$key} = 1;
Line 14293  sub modify_autoupdate { Line 7976  sub modify_autoupdate {
             $changes{'lockablenames'} = 1;              $changes{'lockablenames'} = 1;
         }          }
     }      }
     unless (grep(/^unexpired$/,keys(%currautoupdate))) {  
         if ($updatehash{'autoupdate'}{'unexpired'}) {  
             $changes{'unexpired'} = 1;  
         }  
     }  
     unless (grep(/^lastactive$/,keys(%currautoupdate))) {  
         if ($updatehash{'autoupdate'}{'lastactive'} ne '') {  
             $changes{'lastactive'} = 1;  
         }  
     }  
     foreach my $item (@{$types},'default') {      foreach my $item (@{$types},'default') {
         if (defined($fields{$item})) {          if (defined($fields{$item})) {
             if (ref($currautoupdate{'fields'}) eq 'HASH') {              if (ref($currautoupdate{'fields'}) eq 'HASH') {
Line 14365  sub modify_autoupdate { Line 8038  sub modify_autoupdate {
                     my $newvalue;                      my $newvalue;
                     if ($key eq 'run') {                      if ($key eq 'run') {
                         $newvalue = $offon[$env{'form.autoupdate_run'}];                          $newvalue = $offon[$env{'form.autoupdate_run'}];
                     } elsif ($key eq 'lastactive') {  
                         $newvalue = $offon[$env{'form.lastactive'}];  
                         unless ($lastactivedays eq '') {  
                             $newvalue .= '; '.&mt('inactive = no activity in last [quant,_1,day]',$lastactivedays);  
                         }  
                     } else {                      } else {
                         $newvalue = $offon[$env{'form.'.$key}];                          $newvalue = $offon[$env{'form.'.$key}];
                     }                      }
Line 14406  sub modify_autocreate { Line 8074  sub modify_autocreate {
         $newvals{$item} = 0 if ($newvals{$item} eq '');          $newvals{$item} = 0 if ($newvals{$item} eq '');
     }      }
     $newvals{'xmldc'} = $env{'form.autocreate_xmldc'};      $newvals{'xmldc'} = $env{'form.autocreate_xmldc'};
     my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']);      my %domcoords = &get_active_dcs($dom);
     unless (exists($domcoords{$newvals{'xmldc'}})) {      unless (exists($domcoords{$newvals{'xmldc'}})) {
         $newvals{'xmldc'} = '';          $newvals{'xmldc'} = '';
     }       } 
Line 14463  sub modify_autocreate { Line 8131  sub modify_autocreate {
 }  }
   
 sub modify_directorysrch {  sub modify_directorysrch {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,%domconfig) = @_;
     my ($resulttext,%changes);      my ($resulttext,%changes);
     my %currdirsrch;      my %currdirsrch;
     if (ref($domconfig{'directorysrch'}) eq 'HASH') {      if (ref($domconfig{'directorysrch'}) eq 'HASH') {
Line 14471  sub modify_directorysrch { Line 8139  sub modify_directorysrch {
             $currdirsrch{$key} = $domconfig{'directorysrch'}{$key};              $currdirsrch{$key} = $domconfig{'directorysrch'}{$key};
         }          }
     }      }
     my %title = ( available => 'Institutional directory search available',      my %title = ( available => 'Directory search available',
                   localonly => 'Other domains can search institution',                    localonly => 'Other domains can search',
                   lcavailable => 'LON-CAPA directory search available',  
                   lclocalonly => 'Other domains can search LON-CAPA domain',  
                   searchby => 'Search types',                    searchby => 'Search types',
                   searchtypes => 'Search latitude');                    searchtypes => 'Search latitude');
     my @offon = ('off','on');      my @offon = ('off','on');
Line 14548  sub modify_directorysrch { Line 8214  sub modify_directorysrch {
     my %dirsrch_hash =  (      my %dirsrch_hash =  (
             directorysrch => { available => $env{'form.dirsrch_available'},              directorysrch => { available => $env{'form.dirsrch_available'},
                                cansearch => \@cansearch,                                 cansearch => \@cansearch,
                                localonly => $env{'form.dirsrch_instlocalonly'},                                 localonly => $env{'form.dirsrch_localonly'},
                                lclocalonly => $env{'form.dirsrch_domlocalonly'},  
                                lcavailable => $env{'form.dirsrch_domavailable'},  
                                searchby => \@searchby,                                 searchby => \@searchby,
                                searchtypes => \@searchtypes,                                 searchtypes => \@searchtypes,
                              }                               }
Line 14567  sub modify_directorysrch { Line 8231  sub modify_directorysrch {
                 $changes{'available'} = 1;                  $changes{'available'} = 1;
             }              }
         }          }
         if (exists($currdirsrch{'lcavailable'})) {  
             if ($currdirsrch{'lcavailable'} ne $env{'form.dirsrch_domavailable'}) {  
                 $changes{'lcavailable'} = 1;  
             }  
         } else {  
             if ($env{'form.dirsrch_lcavailable'} eq '1') {  
                 $changes{'lcavailable'} = 1;  
             }  
         }  
         if (exists($currdirsrch{'localonly'})) {          if (exists($currdirsrch{'localonly'})) {
             if ($currdirsrch{'localonly'} ne $env{'form.dirsrch_instlocalonly'}) {               if ($currdirsrch{'localonly'} ne $env{'form.dirsrch_localonly'}) {
                 $changes{'localonly'} = 1;                   $changes{'localonly'} = 1;
             }               }
         } else {          } else {
             if ($env{'form.dirsrch_instlocalonly'} eq '1') {              if ($env{'form.dirsrch_localonly'} eq '1') {
                 $changes{'localonly'} = 1;                  $changes{'localonly'} = 1;
             }              }
         }          }
         if (exists($currdirsrch{'lclocalonly'})) {  
             if ($currdirsrch{'lclocalonly'} ne $env{'form.dirsrch_domlocalonly'}) {  
                 $changes{'lclocalonly'} = 1;  
             }  
         } else {  
             if ($env{'form.dirsrch_domlocalonly'} eq '1') {  
                 $changes{'lclocalonly'} = 1;  
             }  
         }  
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
             $resulttext = &mt('Changes made:').'<ul>';              $resulttext = &mt('Changes made:').'<ul>';
             if ($changes{'available'}) {              if ($changes{'available'}) {
                 $resulttext .= '<li>'.&mt("$title{'available'} set to: $offon[$env{'form.dirsrch_available'}]").'</li>';                  $resulttext .= '<li>'.&mt("$title{'available'} set to: $offon[$env{'form.dirsrch_available'}]").'</li>';
             }              }
             if ($changes{'lcavailable'}) {  
                 $resulttext .= '<li>'.&mt("$title{'lcavailable'} set to: $offon[$env{'form.dirsrch_domavailable'}]").'</li>';  
             }  
             if ($changes{'localonly'}) {              if ($changes{'localonly'}) {
                 $resulttext .= '<li>'.&mt("$title{'localonly'} set to: $otherdoms[$env{'form.dirsrch_instlocalonly'}]").'</li>';                  $resulttext .= '<li>'.&mt("$title{'localonly'} set to: $otherdoms[$env{'form.dirsrch_localonly'}]").'</li>';
             }  
             if ($changes{'lclocalonly'}) {  
                 $resulttext .= '<li>'.&mt("$title{'lclocalonly'} set to: $otherdoms[$env{'form.dirsrch_domlocalonly'}]").'</li>';  
             }              }
   
             if (ref($changes{'cansearch'}) eq 'ARRAY') {              if (ref($changes{'cansearch'}) eq 'ARRAY') {
                 my $chgtext;                  my $chgtext;
                 if (ref($usertypes) eq 'HASH') {                  if (ref($usertypes) eq 'HASH') {
Line 14657  sub modify_directorysrch { Line 8298  sub modify_directorysrch {
                 $resulttext .= '<li>'.&mt($title{'searchtypes'}.' set to: "[_1]"',$chgtext).'</li>';                  $resulttext .= '<li>'.&mt($title{'searchtypes'}.' set to: "[_1]"',$chgtext).'</li>';
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
             &Apache::lonnet::do_cache_new('directorysrch',$dom,$dirsrch_hash{'directorysrch'},3600);  
             if (ref($lastactref) eq 'HASH') {  
                 $lastactref->{'directorysrch'} = 1;  
             }  
         } else {          } else {
             $resulttext = &mt('No changes made to directory search settings');              $resulttext = &mt('No changes made to institution directory search settings');
         }          }
     } else {      } else {
         $resulttext = '<span class="LC_error">'.          $resulttext = '<span class="LC_error">'.
Line 14679  sub modify_contacts { Line 8316  sub modify_contacts {
             $currsetting{$key} = $domconfig{'contacts'}{$key};              $currsetting{$key} = $domconfig{'contacts'}{$key};
         }          }
     }      }
     my (%others,%to,%bcc,%includestr,%includeloc);      my (%others,%to,%bcc);
     my @contacts = ('supportemail','adminemail');      my @contacts = ('supportemail','adminemail');
     my @mailings = ('errormail','packagesmail','helpdeskmail','otherdomsmail',      my @mailings = ('errormail','packagesmail','helpdeskmail','lonstatusmail',
                     'lonstatusmail','requestsmail','updatesmail','idconflictsmail','hostipmail');                      'requestsmail','updatesmail','idconflictsmail');
     my @toggles = ('reporterrors','reportupdates','reportstatus');      my @toggles = ('reporterrors','reportupdates');
     my @lonstatus = ('threshold','sysmail','weights','excluded');  
     my ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields();  
     foreach my $type (@mailings) {      foreach my $type (@mailings) {
         @{$newsetting{$type}} =           @{$newsetting{$type}} = 
             &Apache::loncommon::get_env_multiple('form.'.$type);              &Apache::loncommon::get_env_multiple('form.'.$type);
Line 14695  sub modify_contacts { Line 8330  sub modify_contacts {
             } else {              } else {
                 $contacts_hash{contacts}{$type}{$item} = 0;                  $contacts_hash{contacts}{$type}{$item} = 0;
             }              }
         }          }  
         $others{$type} = $env{'form.'.$type.'_others'};          $others{$type} = $env{'form.'.$type.'_others'};
         $contacts_hash{contacts}{$type}{'others'} = $others{$type};          $contacts_hash{contacts}{$type}{'others'} = $others{$type};
         if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {          if ($type eq 'helpdeskmail') {
             $bcc{$type} = $env{'form.'.$type.'_bcc'};              $bcc{$type} = $env{'form.'.$type.'_bcc'};
             $contacts_hash{contacts}{$type}{'bcc'} = $bcc{$type};              $contacts_hash{contacts}{$type}{'bcc'} = $bcc{$type};
             if (($env{'form.'.$type.'_includestr'} ne '') && ($env{'form.'.$type.'_includeloc'} =~ /^s|b$/)) {  
                 $includestr{$type} = $env{'form.'.$type.'_includestr'};  
                 $includeloc{$type} = $env{'form.'.$type.'_includeloc'};  
                 $contacts_hash{contacts}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type});  
             }  
         }          }
     }      }
     foreach my $item (@contacts) {      foreach my $item (@contacts) {
Line 14717  sub modify_contacts { Line 8347  sub modify_contacts {
             $contacts_hash{'contacts'}{$item} = $env{'form.'.$item};              $contacts_hash{'contacts'}{$item} = $env{'form.'.$item};
         }          }
     }      }
     my ($lonstatus_defs,$lonstatus_names) = &Apache::loncommon::lon_status_items();  
     foreach my $item (@lonstatus) {  
         if ($item eq 'excluded') {  
             my (%serverhomes,@excluded);  
             map { $serverhomes{$_} = 1; } values(%Apache::lonnet::serverhomeIDs);  
             my @possexcluded = &Apache::loncommon::get_env_multiple('form.errorexcluded');  
             if (@possexcluded) {  
                 foreach my $id (sort(@possexcluded)) {  
                     if ($serverhomes{$id}) {  
                         push(@excluded,$id);  
                     }  
                 }  
             }  
             if (@excluded) {  
                 $contacts_hash{'contacts'}{'lonstatus'}{$item} = \@excluded;  
             }  
         } elsif ($item eq 'weights') {  
             foreach my $type ('E','W','N','U') {  
                 $env{'form.error'.$item.'_'.$type} =~ s/^\s+|\s+$//g;  
                 if ($env{'form.error'.$item.'_'.$type} =~ /^\d+$/) {  
                     unless ($env{'form.error'.$item.'_'.$type} == $lonstatus_defs->{$type}) {  
                         $contacts_hash{'contacts'}{'lonstatus'}{$item}{$type} =  
                             $env{'form.error'.$item.'_'.$type};  
                     }  
                 }  
             }  
         } elsif (($item eq 'threshold') || ($item eq 'sysmail')) {  
             $env{'form.error'.$item} =~ s/^\s+|\s+$//g;  
             if ($env{'form.error'.$item} =~ /^\d+$/) {  
                 unless ($env{'form.error'.$item} == $lonstatus_defs->{$item}) {  
                     $contacts_hash{'contacts'}{'lonstatus'}{$item} = $env{'form.error'.$item};  
                 }  
             }  
         }  
     }  
     if ((ref($fields) eq 'ARRAY') && (ref($possoptions) eq 'HASH')) {  
         foreach my $field (@{$fields}) {  
             if (ref($possoptions->{$field}) eq 'ARRAY') {  
                 my $value = $env{'form.helpform_'.$field};  
                 $value =~ s/^\s+|\s+$//g;  
                 if (grep(/^\Q$value\E$/,@{$possoptions->{$field}})) {  
                     $contacts_hash{'contacts'}{'helpform'}{$field} = $value;  
                     if ($field eq 'screenshot') {  
                         $env{'form.helpform_maxsize'} =~ s/^\s+|\s+$//g;  
                         if ($env{'form.helpform_maxsize'} =~ /^\d+\.?\d*$/) {  
                             $contacts_hash{'contacts'}{'helpform'}{'maxsize'} = $env{'form.helpform_maxsize'};  
                         }  
                     }  
                 }  
             }  
         }  
     }  
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
     my (@statuses,%usertypeshash,@overrides);  
     if ((ref($types) eq 'ARRAY') && (@{$types} > 0)) {  
         @statuses = @{$types};  
         if (ref($usertypes) eq 'HASH') {  
             %usertypeshash = %{$usertypes};  
         }  
     }  
     if (@statuses) {  
         my @possoverrides = &Apache::loncommon::get_env_multiple('form.overrides');  
         foreach my $type (@possoverrides) {  
             if (($type ne '') && (grep(/^\Q$type\E$/,@statuses))) {  
                 push(@overrides,$type);  
             }  
         }  
         if (@overrides) {  
             foreach my $type (@overrides) {  
                 my @standard = &Apache::loncommon::get_env_multiple('form.override_'.$type);  
                 foreach my $item (@contacts) {  
                     if (grep(/^\Q$item\E$/,@standard)) {  
                         $contacts_hash{'contacts'}{'overrides'}{$type}{$item} = 1;  
                         $newsetting{'override_'.$type}{$item} = 1;  
                     } else {  
                         $contacts_hash{'contacts'}{'overrides'}{$type}{$item} = 0;  
                         $newsetting{'override_'.$type}{$item} = 0;  
                     }  
                 }  
                 $contacts_hash{'contacts'}{'overrides'}{$type}{'others'} = $env{'form.override_'.$type.'_others'};  
                 $contacts_hash{'contacts'}{'overrides'}{$type}{'bcc'} = $env{'form.override_'.$type.'_bcc'};  
                 $newsetting{'override_'.$type}{'others'} = $env{'form.override_'.$type.'_others'};  
                 $newsetting{'override_'.$type}{'bcc'} = $env{'form.override_'.$type.'_bcc'};  
                 if (($env{'form.override_'.$type.'_includestr'} ne '') && ($env{'form.override_'.$type.'_includeloc'} =~ /^s|b$/)) {  
                     $includestr{$type} = $env{'form.override_'.$type.'_includestr'};  
                     $includeloc{$type} = $env{'form.override_'.$type.'_includeloc'};  
                     $contacts_hash{'contacts'}{'overrides'}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type});  
                     $newsetting{'override_'.$type}{'include'} = $contacts_hash{'contacts'}{'overrides'}{$type}{'include'};  
                 }  
             }  
         }  
     }  
     if (keys(%currsetting) > 0) {      if (keys(%currsetting) > 0) {
         foreach my $item (@contacts) {          foreach my $item (@contacts) {
             if ($to{$item} ne $currsetting{$item}) {              if ($to{$item} ne $currsetting{$item}) {
Line 14828  sub modify_contacts { Line 8366  sub modify_contacts {
             if ($others{$type} ne $currsetting{$type}{'others'}) {              if ($others{$type} ne $currsetting{$type}{'others'}) {
                 push(@{$changes{$type}},'others');                  push(@{$changes{$type}},'others');
             }              }
             if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {              if ($type eq 'helpdeskmail') {   
                 if ($bcc{$type} ne $currsetting{$type}{'bcc'}) {                  if ($bcc{$type} ne $currsetting{$type}{'bcc'}) {
                     push(@{$changes{$type}},'bcc');                       push(@{$changes{$type}},'bcc'); 
                 }                  }
                 my ($currloc,$currstr) = split(/:/,$currsetting{$type}{'include'},2);  
                 if (($includeloc{$type} ne $currloc) || (&escape($includestr{$type}) ne $currstr)) {  
                     push(@{$changes{$type}},'include');  
                 }  
             }  
         }  
         if (ref($fields) eq 'ARRAY') {  
             if (ref($currsetting{'helpform'}) eq 'HASH') {  
                 foreach my $field (@{$fields}) {  
                     if ($currsetting{'helpform'}{$field} ne $contacts_hash{'contacts'}{'helpform'}{$field}) {  
                         push(@{$changes{'helpform'}},$field);  
                     }  
                     if (($field eq 'screenshot') && ($contacts_hash{'contacts'}{'helpform'}{'screenshot'} ne 'no')) {  
                         if ($currsetting{'helpform'}{'maxsize'} ne $contacts_hash{'contacts'}{'helpform'}{'maxsize'}) {  
                             push(@{$changes{'helpform'}},'maxsize');  
                         }  
                     }  
                 }  
             } else {  
                 foreach my $field (@{$fields}) {  
                     if ($contacts_hash{'contacts'}{'helpform'}{$field} ne 'yes') {  
                         push(@{$changes{'helpform'}},$field);  
                     }  
                     if (($field eq 'screenshot') && ($contacts_hash{'contacts'}{'helpform'}{'screenshot'} ne 'no')) {  
                         if ($contacts_hash{'contacts'}{'helpform'}{'maxsize'} != 1) {  
                             push(@{$changes{'helpform'}},'maxsize');  
                         }  
                     }  
                 }  
             }  
         }  
         if (@statuses) {  
             if (ref($currsetting{'overrides'}) eq 'HASH') {  
                 foreach my $key (keys(%{$currsetting{'overrides'}})) {  
                     if (ref($currsetting{'overrides'}{$key}) eq 'HASH') {  
                         if (ref($newsetting{'override_'.$key}) eq 'HASH') {  
                             foreach my $item (@contacts,'bcc','others','include') {  
                                 if ($currsetting{'overrides'}{$key}{$item} ne $newsetting{'override_'.$key}{$item}) {  
                                     push(@{$changes{'overrides'}},$key);  
                                     last;  
                                 }  
                             }  
                         } else {  
                             push(@{$changes{'overrides'}},$key);  
                         }  
                     }  
                 }  
                 foreach my $key (@overrides) {  
                     unless (exists($currsetting{'overrides'}{$key})) {  
                         push(@{$changes{'overrides'}},$key);  
                     }  
                 }  
             } else {  
                 foreach my $key (@overrides) {  
                     push(@{$changes{'overrides'}},$key);  
                 }  
             }  
         }  
         if (ref($currsetting{'lonstatus'}) eq 'HASH') {  
             foreach my $key ('excluded','weights','threshold','sysmail') {  
                 if ($key eq 'excluded') {  
                     if ((ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') &&  
                         (ref($contacts_hash{contacts}{lonstatus}{excluded}) eq 'ARRAY')) {  
                         if ((ref($currsetting{'lonstatus'}{$key}) eq 'ARRAY') &&  
                             (@{$currsetting{'lonstatus'}{$key}})) {  
                             my @diffs =  
                                 &Apache::loncommon::compare_arrays($contacts_hash{contacts}{lonstatus}{excluded},  
                                                                    $currsetting{'lonstatus'}{$key});  
                             if (@diffs) {  
                                 push(@{$changes{'lonstatus'}},$key);  
                             }  
                         } elsif (@{$contacts_hash{contacts}{lonstatus}{excluded}}) {  
                             push(@{$changes{'lonstatus'}},$key);  
                         }  
                     } elsif ((ref($currsetting{'lonstatus'}{$key}) eq 'ARRAY') &&  
                              (@{$currsetting{'lonstatus'}{$key}})) {  
                         push(@{$changes{'lonstatus'}},$key);  
                     }  
                 } elsif ($key eq 'weights') {  
                     if ((ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') &&  
                         (ref($contacts_hash{contacts}{lonstatus}{$key}) eq 'HASH')) {  
                         if (ref($currsetting{'lonstatus'}{$key}) eq 'HASH') {  
                             foreach my $type ('E','W','N','U') {  
                                 unless ($contacts_hash{contacts}{lonstatus}{$key}{$type} eq  
                                         $currsetting{'lonstatus'}{$key}{$type}) {  
                                     push(@{$changes{'lonstatus'}},$key);  
                                     last;  
                                 }  
                             }  
                         } else {  
                             foreach my $type ('E','W','N','U') {  
                                 if ($contacts_hash{contacts}{lonstatus}{$key}{$type} ne '') {  
                                     push(@{$changes{'lonstatus'}},$key);  
                                     last;  
                                 }  
                             }  
                         }  
                     } elsif (ref($currsetting{'lonstatus'}{$key}) eq 'HASH') {  
                         foreach my $type ('E','W','N','U') {  
                             if ($currsetting{'lonstatus'}{$key}{$type} ne '') {  
                                 push(@{$changes{'lonstatus'}},$key);  
                                 last;  
                             }  
                         }  
                     }  
                 } elsif (($key eq 'threshold') || ($key eq 'sysmail')) {  
                     if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') {  
                         if ($currsetting{'lonstatus'}{$key} =~ /^\d+$/) {  
                             if ($currsetting{'lonstatus'}{$key} != $contacts_hash{contacts}{lonstatus}{$key}) {  
                                 push(@{$changes{'lonstatus'}},$key);  
                             }  
                         } elsif ($contacts_hash{contacts}{lonstatus}{$key} =~ /^\d+$/) {  
                             push(@{$changes{'lonstatus'}},$key);  
                         }  
                     } elsif ($currsetting{'lonstatus'}{$key} =~ /^\d+$/) {  
                         push(@{$changes{'lonstatus'}},$key);  
                     }  
                 }  
             }  
         } else {  
             if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') {  
                 foreach my $key ('excluded','weights','threshold','sysmail') {  
                     if (exists($contacts_hash{contacts}{lonstatus}{$key})) {  
                         push(@{$changes{'lonstatus'}},$key);  
                     }  
                 }  
             }              }
         }          }
     } else {      } else {
Line 14967  sub modify_contacts { Line 8379  sub modify_contacts {
         $default{'errormail'} = 'adminemail';          $default{'errormail'} = 'adminemail';
         $default{'packagesmail'} = 'adminemail';          $default{'packagesmail'} = 'adminemail';
         $default{'helpdeskmail'} = 'supportemail';          $default{'helpdeskmail'} = 'supportemail';
         $default{'otherdomsmail'} = 'supportemail';  
         $default{'lonstatusmail'} = 'adminemail';          $default{'lonstatusmail'} = 'adminemail';
         $default{'requestsmail'} = 'adminemail';          $default{'requestsmail'} = 'adminemail';
         $default{'updatesmail'} = 'adminemail';          $default{'updatesmail'} = 'adminemail';
         $default{'hostipmail'} = 'adminemail';  
         foreach my $item (@contacts) {          foreach my $item (@contacts) {
            if ($to{$item} ne $default{$item}) {             if ($to{$item} ne $default{$item}) {
                $changes{$item} = 1;                $changes{$item} = 1;
            }             }
         }          }
         foreach my $type (@mailings) {          foreach my $type (@mailings) {
             if ((@{$newsetting{$type}} != 1) || ($newsetting{$type}[0] ne $default{$type})) {              if ((@{$newsetting{$type}} != 1) || ($newsetting{$type}[0] ne $default{$type})) {
                  
                 push(@{$changes{$type}},@{$newsetting{$type}});                  push(@{$changes{$type}},@{$newsetting{$type}});
             }              }
             if ($others{$type} ne '') {              if ($others{$type} ne '') {
                 push(@{$changes{$type}},'others');                  push(@{$changes{$type}},'others');
             }              }
             if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {              if ($type eq 'helpdeskmail') {
                 if ($bcc{$type} ne '') {                  if ($bcc{$type} ne '') {
                     push(@{$changes{$type}},'bcc');                      push(@{$changes{$type}},'bcc');
                 }                  }
                 if (($includeloc{$type} =~ /^b|s$/) && ($includestr{$type} ne '')) {  
                     push(@{$changes{$type}},'include');  
                 }  
             }  
         }  
         if (ref($fields) eq 'ARRAY') {  
             foreach my $field (@{$fields}) {  
                 if ($contacts_hash{'contacts'}{'helpform'}{$field} ne 'yes') {  
                     push(@{$changes{'helpform'}},$field);  
                 }  
                 if (($field eq 'screenshot') && ($contacts_hash{'contacts'}{'helpform'}{'screenshot'} ne 'no')) {  
                     if ($contacts_hash{'contacts'}{'helpform'}{'maxsize'} != 1) {  
                         push(@{$changes{'helpform'}},'maxsize');  
                     }  
                 }  
             }  
         }  
         if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') {  
             foreach my $key ('excluded','weights','threshold','sysmail') {  
                 if (exists($contacts_hash{contacts}{lonstatus}{$key})) {  
                     push(@{$changes{'lonstatus'}},$key);  
                 }  
             }              }
         }          }
     }      }
Line 15041  sub modify_contacts { Line 8430  sub modify_contacts {
             }              }
             foreach my $type (@mailings) {              foreach my $type (@mailings) {
                 if (ref($changes{$type}) eq 'ARRAY') {                  if (ref($changes{$type}) eq 'ARRAY') {
                     if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {                      $resulttext .= '<li>'.$titles->{$type}.': ';
                         $resulttext .= '<li>'.$titles->{$type}.' -- '.&mt('sent to').': ';  
                     } else {  
                         $resulttext .= '<li>'.$titles->{$type}.': ';  
                     }  
                     my @text;                      my @text;
                     foreach my $item (@{$newsetting{$type}}) {                      foreach my $item (@{$newsetting{$type}}) {
                         push(@text,$short_titles->{$item});                          push(@text,$short_titles->{$item});
Line 15053  sub modify_contacts { Line 8438  sub modify_contacts {
                     if ($others{$type} ne '') {                      if ($others{$type} ne '') {
                         push(@text,$others{$type});                          push(@text,$others{$type});
                     }                      }
                     if (@text) {                      $resulttext .= '<span class="LC_cusr_emph">'.
                         $resulttext .= '<span class="LC_cusr_emph">'.                                     join(', ',@text).'</span>';
                                        join(', ',@text).'</span>';                      if ($type eq 'helpdeskmail') {
                     }  
                     if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {  
                         if ($bcc{$type} ne '') {                          if ($bcc{$type} ne '') {
                             my $bcctext;                              $resulttext .= '&nbsp;'.&mt('with Bcc to').': <span class="LC_cusr_emph">'.$bcc{$type}.'</span>';
                             if (@text) {  
                                 $bcctext = '&nbsp;'.&mt('with Bcc to');  
                             } else {  
                                 $bcctext = '(Bcc)';  
                             }  
                             $resulttext .= $bcctext.': <span class="LC_cusr_emph">'.$bcc{$type}.'</span>';  
                         } elsif (!@text) {  
                             $resulttext .= &mt('No one');  
                         }                          }
                         if ($includestr{$type} ne '') {  
                             if ($includeloc{$type} eq 'b') {  
                                 $resulttext .= '<br />'.&mt('Text automatically added to e-mail body:').' '.$includestr{$type};  
                             } elsif ($includeloc{$type} eq 's') {  
                                 $resulttext .= '<br />'.&mt('Text automatically added to e-mail subject:').' '.$includestr{$type};  
                             }  
                         }  
                     } elsif (!@text) {  
                         $resulttext .= &mt('No recipients');  
                     }                      }
                     $resulttext .= '</li>';                      $resulttext .= '</li>';
                 }                  }
             }              }
             if (ref($changes{'overrides'}) eq 'ARRAY') {  
                 my @deletions;  
                 foreach my $type (@{$changes{'overrides'}}) {  
                     if ($usertypeshash{$type}) {  
                         if (grep(/^\Q$type\E/,@overrides)) {  
                             $resulttext .= '<li>'.&mt("Overrides based on requester's affiliation set for [_1]",  
                                                       $usertypeshash{$type}).'<ul><li>';  
                             if (ref($newsetting{'override_'.$type}) eq 'HASH') {  
                                 my @text;  
                                 foreach my $item (@contacts) {  
                                     if ($newsetting{'override_'.$type}{$item}) {  
                                         push(@text,$short_titles->{$item});  
                                     }  
                                 }  
                                 if ($newsetting{'override_'.$type}{'others'} ne '') {  
                                     push(@text,$newsetting{'override_'.$type}{'others'});  
                                 }  
   
                                 if (@text) {  
                                     $resulttext .= &mt('Helpdesk e-mail sent to: [_1]',  
                                                        '<span class="LC_cusr_emph">'.join(', ',@text).'</span>');  
                                 }  
                                 if ($newsetting{'override_'.$type}{'bcc'} ne '') {  
                                     my $bcctext;  
                                     if (@text) {  
                                         $bcctext = '&nbsp;'.&mt('with Bcc to');  
                                     } else {  
                                         $bcctext = '(Bcc)';  
                                     }  
                                     $resulttext .= $bcctext.': <span class="LC_cusr_emph">'.$newsetting{'override_'.$type}{'bcc'}.'</span>';  
                                 } elsif (!@text) {  
                                      $resulttext .= &mt('Helpdesk e-mail sent to no one');  
                                 }  
                                 $resulttext .= '</li>';  
                                 if ($newsetting{'override_'.$type}{'include'} ne '') {  
                                     my ($loc,$str) = split(/:/,$newsetting{'override_'.$type}{'include'});  
                                     if ($loc eq 'b') {  
                                         $resulttext .= '<li>'.&mt('Text automatically added to e-mail body:').' '.&unescape($str).'</li>';  
                                     } elsif ($loc eq 's') {  
                                         $resulttext .= '<li>'.&mt('Text automatically added to e-mail subject:').' '.&unescape($str).'</li>';  
                                     }  
                                 }  
                             }  
                             $resulttext .= '</li></ul></li>';  
                         } else {  
                             push(@deletions,$usertypeshash{$type});  
                         }  
                     }  
                 }  
                 if (@deletions) {  
                     $resulttext .= '<li>'.&mt("Overrides based on requester's affiliation discontinued for: [_1]",  
                                               join(', ',@deletions)).'</li>';  
                 }  
             }  
             my @offon = ('off','on');              my @offon = ('off','on');
             my $corelink = &core_link_msu();  
             if ($changes{'reporterrors'}) {              if ($changes{'reporterrors'}) {
                 $resulttext .= '<li>'.                  $resulttext .= '<li>'.
                                &mt('E-mail error reports to [_1] set to "'.                                 &mt('E-mail error reports to [_1] set to "'.
                                    $offon[$env{'form.reporterrors'}].'".',                                     $offon[$env{'form.reporterrors'}].'".',
                                    $corelink).                                     &Apache::loncommon::modal_link('http://loncapa.org/core.html',
                                          &mt('LON-CAPA core group - MSU'),600,500)).
                                '</li>';                                 '</li>';
             }              }
             if ($changes{'reportupdates'}) {              if ($changes{'reportupdates'}) {
                 $resulttext .= '<li>'.                  $resulttext .= '<li>'.
                                 &mt('E-mail record of completed LON-CAPA updates to [_1] set to "'.                                  &mt('E-mail record of completed LON-CAPA updates to [_1] set to "'.
                                     $offon[$env{'form.reportupdates'}].'".',                                      $offon[$env{'form.reportupdates'}].'".',
                                     $corelink).                                      &Apache::loncommon::modal_link('http://loncapa.org/core.html',
                                 '</li>';                                          &mt('LON-CAPA core group - MSU'),600,500)).
             }  
             if ($changes{'reportstatus'}) {  
                 $resulttext .= '<li>'.  
                                 &mt('E-mail status if errors above threshold to [_1] set to "'.  
                                     $offon[$env{'form.reportstatus'}].'".',  
                                     $corelink).  
                                 '</li>';                                  '</li>';
             }              }
             if (ref($changes{'lonstatus'}) eq 'ARRAY') {  
                 $resulttext .= '<li>'.  
                                &mt('Nightly status check e-mail settings').':<ul>';  
                 my (%defval,%use_def,%shown);  
                 $defval{'threshold'} = $lonstatus_defs->{'threshold'};  
                 $defval{'sysmail'} = $lonstatus_defs->{'sysmail'};  
                 $defval{'weights'} =  
                     join(', ',map { $lonstatus_names->{$_}.'='.$lonstatus_defs->{$_}; } ('E','W','N','U'));  
                 $defval{'excluded'} = &mt('None');  
                 if (ref($contacts_hash{'contacts'}{'lonstatus'}) eq 'HASH') {  
                     foreach my $item ('threshold','sysmail','weights','excluded') {  
                         if (exists($contacts_hash{'contacts'}{'lonstatus'}{$item})) {  
                             if (($item eq 'threshold') || ($item eq 'sysmail')) {  
                                 $shown{$item} = $contacts_hash{'contacts'}{'lonstatus'}{$item};  
                             } elsif ($item eq 'weights') {  
                                 if (ref($contacts_hash{'contacts'}{'lonstatus'}{$item}) eq 'HASH') {  
                                     foreach my $type ('E','W','N','U') {  
                                         $shown{$item} .= $lonstatus_names->{$type}.'=';  
                                         if (exists($contacts_hash{'contacts'}{'lonstatus'}{$item}{$type})) {  
                                             $shown{$item} .= $contacts_hash{'contacts'}{'lonstatus'}{$item}{$type};  
                                         } else {  
                                             $shown{$item} .= $lonstatus_defs->{$type};  
                                         }  
                                         $shown{$item} .= ', ';  
                                     }  
                                     $shown{$item} =~ s/, $//;  
                                 } else {  
                                     $shown{$item} = $defval{$item};  
                                 }  
                             } elsif ($item eq 'excluded') {  
                                 if (ref($contacts_hash{'contacts'}{'lonstatus'}{$item}) eq 'ARRAY') {  
                                     $shown{$item} = join(', ',@{$contacts_hash{'contacts'}{'lonstatus'}{$item}});  
                                 } else {  
                                     $shown{$item} = $defval{$item};  
                                 }  
                             }  
                         } else {  
                             $shown{$item} = $defval{$item};  
                         }  
                     }  
                 } else {  
                     foreach my $item ('threshold','weights','excluded','sysmail') {  
                         $shown{$item} = $defval{$item};  
                     }  
                 }  
                 foreach my $item ('threshold','weights','excluded','sysmail') {  
                     $resulttext .= '<li>'.&mt($titles->{'error'.$item}.' -- [_1]',  
                                           $shown{$item}).'</li>';  
                 }  
                 $resulttext .= '</ul></li>';  
             }  
             if ((ref($changes{'helpform'}) eq 'ARRAY') && (ref($fields) eq 'ARRAY')) {  
                 my (@optional,@required,@unused,$maxsizechg);  
                 foreach my $field (@{$changes{'helpform'}}) {  
                     if ($field eq 'maxsize') {  
                         $maxsizechg = 1;  
                         next;  
                     }  
                     if ($contacts_hash{'contacts'}{'helpform'}{$field} eq 'yes') {  
                         push(@optional,$field);  
                     } elsif ($contacts_hash{'contacts'}{'helpform'}{$field} eq 'no') {  
                         push(@unused,$field);  
                     } elsif ($contacts_hash{'contacts'}{'helpform'}{$field} eq 'req') {  
                         push(@required,$field);  
                     }  
                 }  
                 if (@optional) {  
                     $resulttext .= '<li>'.  
                                    &mt('Help form fields changed to "Optional": [_1].',  
                                        '<span class="LC_cusr_emph">'.join(', ',map { $fieldtitles->{$_}; } @optional)).'</span>'.  
                                    '</li>';  
                 }  
                 if (@required) {  
                     $resulttext .= '<li>'.  
                                    &mt('Help form fields changed to "Required": [_1].',  
                                        '<span class="LC_cusr_emph">'.join(', ',map { $fieldtitles->{$_}; } @required)).'</span>'.  
                                    '</li>';  
                 }  
                 if (@unused) {  
                     $resulttext .= '<li>'.  
                                    &mt('Help form fields changed to "Not shown": [_1].',  
                                        '<span class="LC_cusr_emph">'.join(', ',map { $fieldtitles->{$_}; } @unused)).'</span>'.  
                                    '</li>';  
                 }  
                 if ($maxsizechg) {  
                     $resulttext .= '<li>'.  
                                    &mt('Max size for file uploaded to help form by logged-in user set to [_1] MB.',  
                                        $contacts_hash{'contacts'}{'helpform'}{'maxsize'}).  
                                    '</li>';  
                 }  
             }  
             $resulttext .= '</ul>';  
         } else {  
             $resulttext = &mt('No changes made to contacts and form settings');  
         }  
     } else {  
         $resulttext = '<span class="LC_error">'.  
             &mt('An error occurred: [_1]',$putresult).'</span>';  
     }  
     return $resulttext;  
 }  
   
 sub modify_passwords {  
     my ($r,$dom,$confname,$lastactref,%domconfig) = @_;  
     my ($resulttext,%current,%changes,%newvalues,@oktypes,$errors,  
         $updatedefaults,$updateconf);  
     my $customfn = 'resetpw.html';  
     if (ref($domconfig{'passwords'}) eq 'HASH') {  
         %current = %{$domconfig{'passwords'}};  
     }  
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);  
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
     if (ref($types) eq 'ARRAY') {  
         @oktypes = @{$types};  
     }  
     push(@oktypes,'default');  
   
     my %titles = &Apache::lonlocal::texthash (  
         intauth_cost   => 'Encryption cost for bcrypt (positive integer)',  
         intauth_check  => 'Check bcrypt cost if authenticated',  
         intauth_switch => 'Existing crypt-based switched to bcrypt on authentication',  
         permanent      => 'Permanent e-mail address',  
         critical       => 'Critical notification address',  
         notify         => 'Notification address',  
         min            => 'Minimum password length',  
         max            => 'Maximum password length',  
         chars          => 'Required characters',  
         numsaved       => 'Number of previous passwords to save',  
         reset          => 'Resetting Forgotten Password',  
         intauth        => 'Encryption of Stored Passwords (Internal Auth)',  
         rules          => 'Rules for LON-CAPA Passwords',  
         crsownerchg    => 'Course Owner Changing Student Passwords',  
         username       => 'Username',  
         email          => 'E-mail address',  
     );  
   
 #  
 # Retrieve current domain configuration for internal authentication from $domconfig{'defaults'}.  
 #  
     my (%curr_defaults,%save_defaults);  
     if (ref($domconfig{'defaults'}) eq 'HASH') {  
         foreach my $key (keys(%{$domconfig{'defaults'}})) {  
             if ($key =~ /^intauth_(cost|check|switch)$/) {  
                 $curr_defaults{$key} = $domconfig{'defaults'}{$key};  
             } else {  
                 $save_defaults{$key} = $domconfig{'defaults'}{$key};  
             }  
         }  
     }  
     my %staticdefaults = (  
         'resetlink'      => 2,  
         'resetcase'      => \@oktypes,  
         'resetprelink'   => 'both',  
         'resetemail'     => ['critical','notify','permanent'],  
         'intauth_cost'   => 10,  
         'intauth_check'  => 0,  
         'intauth_switch' => 0,  
     );  
     $staticdefaults{'min'} = $Apache::lonnet::passwdmin;  
     foreach my $type (@oktypes) {  
         $staticdefaults{'resetpostlink'}{$type} = ['email','username'];  
     }  
     my $linklife = $env{'form.passwords_link'};  
     $linklife =~ s/^\s+|\s+$//g;  
     if (($linklife =~ /^\d+(|\.\d*)$/) && ($linklife > 0)) {  
         $newvalues{'resetlink'} = $linklife;  
         if ($current{'resetlink'}) {  
             if ($current{'resetlink'} ne $linklife) {  
                 $changes{'reset'} = 1;  
             }  
         } elsif (!ref($domconfig{passwords}) eq 'HASH') {  
             if ($staticdefaults{'resetlink'} ne $linklife) {  
                 $changes{'reset'} = 1;  
             }  
         }  
     } elsif ($current{'resetlink'}) {  
         $changes{'reset'} = 1;  
     }  
     my @casesens;  
     my @posscase = &Apache::loncommon::get_env_multiple('form.passwords_case_sensitive');  
     foreach my $case (sort(@posscase)) {  
         if (grep(/^\Q$case\E$/,@oktypes)) {  
             push(@casesens,$case);  
         }  
     }  
     $newvalues{'resetcase'} = \@casesens;  
     if (ref($current{'resetcase'}) eq 'ARRAY') {  
         my @diffs = &Apache::loncommon::compare_arrays($current{'resetcase'},\@casesens);  
         if (@diffs > 0) {  
             $changes{'reset'} = 1;  
         }  
     } elsif (!ref($domconfig{passwords}) eq 'HASH') {  
         my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetcase'},\@casesens);  
         if (@diffs > 0) {  
             $changes{'reset'} = 1;  
         }  
     }  
     if ($env{'form.passwords_prelink'} =~ /^(both|either)$/) {  
         $newvalues{'resetprelink'} = $env{'form.passwords_prelink'};  
         if (exists($current{'resetprelink'})) {  
             if ($current{'resetprelink'} ne $newvalues{'resetprelink'}) {  
                 $changes{'reset'} = 1;  
             }  
         } elsif (!ref($domconfig{passwords}) eq 'HASH') {  
             if ($staticdefaults{'resetprelink'} ne $newvalues{'resetprelink'}) {  
                 $changes{'reset'} = 1;  
             }  
         }  
     } elsif ($current{'resetprelink'}) {  
         $changes{'reset'} = 1;  
     }  
     foreach my $type (@oktypes) {  
         my @possplink = &Apache::loncommon::get_env_multiple('form.passwords_postlink_'.$type);  
         my @postlink;  
         foreach my $item (sort(@possplink)) {  
             if ($item =~ /^(email|username)$/) {  
                 push(@postlink,$item);  
             }  
         }  
         $newvalues{'resetpostlink'}{$type} = \@postlink;  
         unless ($changes{'reset'}) {  
             if (ref($current{'resetpostlink'}) eq 'HASH') {  
                 if (ref($current{'resetpostlink'}{$type}) eq 'ARRAY') {  
                     my @diffs = &Apache::loncommon::compare_arrays($current{'resetpostlink'}{$type},\@postlink);  
                     if (@diffs > 0) {  
                         $changes{'reset'} = 1;  
                     }  
                 } else {  
                     $changes{'reset'} = 1;  
                 }  
             } elsif (!ref($domconfig{passwords}) eq 'HASH') {  
                 my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetpostlink'}{$type},\@postlink);  
                 if (@diffs > 0) {  
                     $changes{'reset'} = 1;  
                 }  
             }  
         }  
     }  
     my @possemailsrc = &Apache::loncommon::get_env_multiple('form.passwords_emailsrc');  
     my @resetemail;  
     foreach my $item (sort(@possemailsrc)) {  
         if ($item =~ /^(permanent|critical|notify)$/) {  
             push(@resetemail,$item);  
         }  
     }  
     $newvalues{'resetemail'} = \@resetemail;  
     unless ($changes{'reset'}) {  
         if (ref($current{'resetemail'}) eq 'ARRAY') {  
             my @diffs = &Apache::loncommon::compare_arrays($current{'resetemail'},\@resetemail);  
             if (@diffs > 0) {  
                 $changes{'reset'} = 1;  
             }  
         } elsif (!ref($domconfig{passwords}) eq 'HASH') {  
             my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetemail'},\@resetemail);  
             if (@diffs > 0) {  
                 $changes{'reset'} = 1;  
             }  
         }  
     }  
     if ($env{'form.passwords_stdtext'} == 0) {  
         $newvalues{'resetremove'} = 1;  
         unless ($current{'resetremove'}) {  
             $changes{'reset'} = 1;  
         }  
     } elsif ($current{'resetremove'}) {  
         $changes{'reset'} = 1;  
     }  
     if ($env{'form.passwords_customfile.filename'} ne '') {  
         my $servadm = $r->dir_config('lonAdmEMail');  
         my ($configuserok,$author_ok,$switchserver) =  
             &config_check($dom,$confname,$servadm);  
         my $error;  
         if ($configuserok eq 'ok') {  
             if ($switchserver) {  
                 $error = &mt("Upload of file containing domain-specific text is not permitted to this server: [_1]",$switchserver);  
             } else {  
                 if ($author_ok eq 'ok') {  
                     my $modified = [];  
                     my ($result,$customurl) =  
                         &Apache::lonconfigsettings::publishlogo($r,'upload','passwords_customfile',$dom,  
                                                                 $confname,'customtext/resetpw','','',$customfn,  
                                                                 $modified);  
                     if ($result eq 'ok') {  
                         $newvalues{'resetcustom'} = $customurl;  
                         $changes{'reset'} = 1;  
                         &update_modify_urls($r,$modified);  
                     } else {  
                         $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$customfn,$result);  
                     }  
                 } else {  
                     $error = &mt("Upload of [_1] failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3].  Error was: [_4].",$customfn,$confname,$dom,$author_ok);  
                 }  
             }  
         } else {  
             $error = &mt("Upload of [_1] failed because a Domain Configuration user ([_2]) could not be created in domain: [_3].  Error was: [_4].",$customfn,$confname,$dom,$configuserok);  
         }  
         if ($error) {  
             &Apache::lonnet::logthis($error);  
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';  
         }  
     } elsif ($current{'resetcustom'}) {  
         if ($env{'form.passwords_custom_del'}) {  
             $changes{'reset'} = 1;  
         } else {  
             $newvalues{'resetcustom'} = $current{'resetcustom'};  
         }  
     }  
     $env{'form.intauth_cost'} =~ s/^\s+|\s+$//g;  
     if (($env{'form.intauth_cost'} ne '') && ($env{'form.intauth_cost'} =~ /^\d+$/)) {  
         $save_defaults{'intauth_cost'} = $env{'form.intauth_cost'};  
         if ($save_defaults{'intauth_cost'} ne $curr_defaults{'intauth_cost'}) {  
             $changes{'intauth'} = 1;  
         }  
     } else {  
         $save_defaults{'intauth_cost'} = $curr_defaults{'intauth_cost'};  
     }  
     if ($env{'form.intauth_check'} =~ /^(0|1|2)$/) {  
         $save_defaults{'intauth_check'} = $env{'form.intauth_check'};  
         if ($save_defaults{'intauth_check'} ne $curr_defaults{'intauth_check'}) {  
             $changes{'intauth'} = 1;  
         }  
     } else {  
         $save_defaults{'intauth_check'} = $curr_defaults{'intauth_check'};  
     }  
     if ($env{'form.intauth_switch'} =~ /^(0|1|2)$/) {  
         $save_defaults{'intauth_switch'} = $env{'form.intauth_switch'};  
         if ($save_defaults{'intauth_switch'} ne $curr_defaults{'intauth_switch'}) {  
             $changes{'intauth'} = 1;  
         }  
     } else {  
         $save_defaults{'intauth_check'} = $curr_defaults{'intauth_check'};  
     }  
     foreach my $item ('cost','check','switch') {  
         if ($save_defaults{'intauth_'.$item} ne $domdefaults{'intauth_'.$item}) {  
             $domdefaults{'intauth_'.$item} = $save_defaults{'intauth_'.$item};  
             $updatedefaults = 1;  
         }  
     }  
     &password_rule_changes('passwords',\%newvalues,\%current,\%changes);  
     my %crsownerchg = (  
                         by => [],  
                         for => [],  
                       );  
     foreach my $item ('by','for') {  
         my @posstypes = &Apache::loncommon::get_env_multiple('form.passwords_crsowner_'.$item);  
         foreach my $type (sort(@posstypes)) {  
             if (grep(/^\Q$type\E$/,@oktypes)) {  
                 push(@{$crsownerchg{$item}},$type);  
             }  
         }  
     }  
     $newvalues{'crsownerchg'} = \%crsownerchg;  
     if (ref($current{'crsownerchg'}) eq 'HASH') {  
         foreach my $item ('by','for') {  
             if (ref($current{'crsownerchg'}{$item}) eq 'ARRAY') {  
                 my @diffs = &Apache::loncommon::compare_arrays($current{'crsownerchg'}{$item},$crsownerchg{$item});  
                 if (@diffs > 0) {  
                     $changes{'crsownerchg'} = 1;  
                     last;  
                 }  
             }  
         }  
     } elsif (!(ref($domconfig{passwords}) eq 'HASH')) {  
         foreach my $item ('by','for') {  
             if (@{$crsownerchg{$item}} > 0) {  
                 $changes{'crsownerchg'} = 1;  
                 last;  
             }  
         }  
     }  
   
     my %confighash = (  
                         defaults  => \%save_defaults,  
                         passwords => \%newvalues,  
                      );  
     &process_captcha('passwords',\%changes,$confighash{'passwords'},$domconfig{'passwords'});  
   
     my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,$dom);  
     if ($putresult eq 'ok') {  
         if (keys(%changes) > 0) {  
             $resulttext = &mt('Changes made: ').'<ul>';  
             foreach my $key ('reset','intauth','rules','crsownerchg') {  
                 if ($changes{$key}) {  
                     unless ($key eq 'intauth') {  
                         $updateconf = 1;  
                     }  
                     $resulttext .= '<li>'.$titles{$key}.':<ul>';  
                     if ($key eq 'reset') {  
                         if ($confighash{'passwords'}{'captcha'} eq 'original') {  
                             $resulttext .= '<li>'.&mt('CAPTCHA validation set to use: original CAPTCHA').'</li>';  
                         } elsif ($confighash{'passwords'}{'captcha'} eq 'recaptcha') {  
                             $resulttext .= '<li>'.&mt('CAPTCHA validation set to use: reCAPTCHA').' '.  
                                            &mt('version: [_1]',$confighash{'passwords'}{'recaptchaversion'}).'<br />';  
                             if (ref($confighash{'passwords'}{'recaptchakeys'}) eq 'HASH') {  
                                 $resulttext .= &mt('Public key: [_1]',$confighash{'passwords'}{'recaptchakeys'}{'public'}).'</br>'.  
                                                &mt('Private key: [_1]',$confighash{'passwords'}{'recaptchakeys'}{'private'}).'</li>';  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('No CAPTCHA validation').'</li>';  
                         }  
                         if ($confighash{'passwords'}{'resetlink'}) {  
                             $resulttext .= '<li>'.&mt('Reset link expiration set to [quant,_1,hour]',$confighash{'passwords'}{'resetlink'}).'</li>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('No reset link expiration set.').' '.  
                                                   &mt('Will default to 2 hours').'</li>';  
                         }  
                         if (ref($confighash{'passwords'}{'resetcase'}) eq 'ARRAY') {  
                             if (@{$confighash{'passwords'}{'resetcase'}} == 0) {  
                                 $resulttext .= '<li>'.&mt('User input for username and/or e-mail address not case sensitive for "Forgot Password" web form').'</li>';  
                             } else {  
                                 my $casesens;  
                                 foreach my $type (@{$confighash{'passwords'}{'resetcase'}}) {  
                                     if ($type eq 'default') {  
                                         $casesens .= $othertitle.', ';  
                                     } elsif ($usertypes->{$type} ne '') {  
                                         $casesens .= $usertypes->{$type}.', ';  
                                     }  
                                 }  
                                 $casesens =~ s/\Q, \E$//;  
                                 $resulttext .= '<li>'.&mt('"Forgot Password" web form input for username and/or e-mail address is case-sensitive for: [_1]',$casesens).'</li>';  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('Case-sensitivity not set for "Forgot Password" web form').' '.&mt('Will default to case-sensitive for username and/or e-mail address for all').'</li>';  
                         }  
                         if ($confighash{'passwords'}{'resetprelink'} eq 'either') {  
                             $resulttext .= '<li>'.&mt('Users can enter either a username or an e-mail address in "Forgot Password" web form').'</li>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('Users can enter both a username and an e-mail address in "Forgot Password" web form').'</li>';  
                         }  
                         if (ref($confighash{'passwords'}{'resetpostlink'}) eq 'HASH') {  
                             my $output;  
                             if (ref($types) eq 'ARRAY') {  
                                 foreach my $type (@{$types}) {  
                                     if (ref($confighash{'passwords'}{'resetpostlink'}{$type}) eq 'ARRAY') {  
                                         if (@{$confighash{'passwords'}{'resetpostlink'}{$type}} == 0) {  
                                             $output .= $usertypes->{$type}.' -- '.&mt('none');  
                                         } else {  
                                             $output .= $usertypes->{$type}.' -- '.  
                                                        join(', ',map { $titles{$_}; } (@{$confighash{'passwords'}{'resetpostlink'}{$type}})).'; ';  
                                         }  
                                     }  
                                 }  
                             }  
                             if (ref($confighash{'passwords'}{'resetpostlink'}{'default'}) eq 'ARRAY') {  
                                 if (@{$confighash{'passwords'}{'resetpostlink'}{'default'}} == 0) {  
                                     $output .= $othertitle.' -- '.&mt('none');  
                                 } else {  
                                     $output .= $othertitle.' -- '.  
                                                join(', ',map { $titles{$_}; } (@{$confighash{'passwords'}{'resetpostlink'}{'default'}}));  
                                 }  
                             }  
                             if ($output) {  
                                 $resulttext .= '<li>'.&mt('Information required for new password form (by user type) set to: [_1]',$output).'</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('Information required for new password form not set.').' '.&mt('Will default to requiring both the username and an e-mail address').'</li>';  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('Information required for new password form not set.').' '.&mt('Will default to requiring both the username and an e-mail address').'</li>';  
                         }  
                         if (ref($confighash{'passwords'}{'resetemail'}) eq 'ARRAY') {  
                             if (@{$confighash{'passwords'}{'resetemail'}} > 0) {  
                                 $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$confighash{'passwords'}{'resetemail'}})).'</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>';  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>';  
                         }  
                         if ($confighash{'passwords'}{'resetremove'}) {  
                             $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form not shown').'</li>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form is shown').'</li>';  
                         }  
                         if ($confighash{'passwords'}{'resetcustom'}) {  
                             my $customlink = &Apache::loncommon::modal_link($confighash{'passwords'}{'resetcustom'},  
                                                                             &mt('custom text'),600,500,undef,undef,  
                                                                             undef,undef,'background-color:#ffffff');  
                             $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" form includes: [_1]',$customlink).'</li>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('No custom text included in preamble to "Forgot Password" form').'</li>';  
                         }  
                     } elsif ($key eq 'intauth') {  
                         foreach my $item ('cost','switch','check') {  
                             my $value = $save_defaults{$key.'_'.$item};  
                             if ($item eq 'switch') {  
                                 my %optiondesc = &Apache::lonlocal::texthash (  
                                                      0 => 'No',  
                                                      1 => 'Yes',  
                                                      2 => 'Yes, and copy existing passwd file to passwd.bak file',  
                                                  );  
                                 if ($value =~ /^(0|1|2)$/) {  
                                     $value = $optiondesc{$value};  
                                 } else {  
                                     $value = &mt('none -- defaults to No');  
                                 }  
                             } elsif ($item eq 'check') {  
                                 my %optiondesc = &Apache::lonlocal::texthash (  
                                                      0 => 'No',  
                                                      1 => 'Yes, allow login then update passwd file using default cost (if higher)',  
                                                      2 => 'Yes, disallow login if stored cost is less than domain default',  
                                                  );  
                                 if ($value =~ /^(0|1|2)$/) {  
                                     $value = $optiondesc{$value};  
                                 } else {  
                                     $value = &mt('none -- defaults to No');  
                                 }  
                             }  
                             $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$titles{$key.'_'.$item},$value).'</li>';  
                         }  
                     } elsif ($key eq 'rules') {  
                         foreach my $rule ('min','max','numsaved') {  
                             if ($confighash{'passwords'}{$rule} eq '') {  
                                 if ($rule eq 'min') {  
                                     $resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule});  
                                                    ' '.&mt('Default of [_1] will be used',  
                                                            $Apache::lonnet::passwdmin).'</li>';  
                                 } else {  
                                     $resulttext .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>';  
                                 }  
                             } else {  
                                 $resulttext .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$confighash{'passwords'}{$rule}).'</li>';  
                             }  
                         }  
                         if (ref($confighash{'passwords'}{'chars'}) eq 'ARRAY') {  
                             if (@{$confighash{'passwords'}{'chars'}} > 0) {  
                                 my %rulenames = &Apache::lonlocal::texthash(  
                                                      uc => 'At least one upper case letter',  
                                                      lc => 'At least one lower case letter',  
                                                      num => 'At least one number',  
                                                      spec => 'At least one non-alphanumeric',  
                                                    );  
                                 my $needed = '<ul><li>'.  
                                              join('</li><li>',map {$rulenames{$_} } @{$confighash{'passwords'}{'chars'}}).  
                                              '</li></ul>';  
                                 $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';  
                         }  
                     } elsif ($key eq 'crsownerchg') {  
                         if (ref($confighash{'passwords'}{'crsownerchg'}) eq 'HASH') {  
                             if ((@{$confighash{'passwords'}{'crsownerchg'}{'by'}} == 0) ||  
                                 (@{$confighash{'passwords'}{'crsownerchg'}{'for'}} == 0)) {  
                                 $resulttext .= '<li>'.&mt('Course owner may not change student passwords.').'</li>';  
                             } else {  
                                 my %crsownerstr;  
                                 foreach my $item ('by','for') {  
                                     if (ref($confighash{'passwords'}{'crsownerchg'}{$item}) eq 'ARRAY') {  
                                         foreach my $type (@{$confighash{'passwords'}{'crsownerchg'}{$item}}) {  
                                             if ($type eq 'default') {  
                                                 $crsownerstr{$item} .= $othertitle.', ';  
                                             } elsif ($usertypes->{$type} ne '') {  
                                                 $crsownerstr{$item} .= $usertypes->{$type}.', ';  
                                             }  
                                         }  
                                         $crsownerstr{$item} =~ s/\Q, \E$//;  
                                     }  
                                 }  
                                 $resulttext .= '<li>'.&mt('Course owner (with status: [_1]) may change passwords for students (with status: [_2]).',  
                                            $crsownerstr{'by'},$crsownerstr{'for'}).'</li>';  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('Course owner may not change student passwords.').'</li>';  
                         }  
                     }  
                     $resulttext .= '</ul></li>';  
                 }  
             }  
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
         } else {          } else {
             $resulttext = &mt('No changes made to password settings');              $resulttext = &mt('No changes made to contact information');
         }  
         my $cachetime = 24*60*60;  
         if ($updatedefaults) {  
             &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);  
             if (ref($lastactref) eq 'HASH') {  
                 $lastactref->{'domdefaults'} = 1;  
             }  
         }  
         if ($updateconf) {  
             &Apache::lonnet::do_cache_new('passwdconf',$dom,$confighash{'passwords'},$cachetime);  
             if (ref($lastactref) eq 'HASH') {  
                 $lastactref->{'passwdconf'} = 1;  
             }  
         }          }
     } else {      } else {
         $resulttext = '<span class="LC_error">'.          $resulttext = '<span class="LC_error">'.
             &mt('An error occurred: [_1]',$putresult).'</span>';              &mt('An error occurred: [_1].',$putresult).'</span>';
     }  
     if ($errors) {  
         $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.  
                        $errors.'</ul></p>';  
     }      }
     return $resulttext;      return $resulttext;
 }  }
   
 sub password_rule_changes {  
     my ($prefix,$newvalues,$current,$changes) = @_;  
     return unless ((ref($newvalues) eq 'HASH') &&  
                    (ref($current) eq 'HASH') &&  
                    (ref($changes) eq 'HASH'));  
     my (@rules,%staticdefaults);  
     if ($prefix eq 'passwords') {  
         @rules = ('min','max','numsaved');  
     } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {  
         @rules = ('min','max');  
     }  
     $staticdefaults{'min'} = $Apache::lonnet::passwdmin;  
     foreach my $rule (@rules) {  
         $env{'form.'.$prefix.'_'.$rule} =~ s/^\s+|\s+$//g;  
         my $ruleok;  
         if ($rule eq 'min') {  
             if ($env{'form.'.$prefix.'_'.$rule} =~ /^\d+$/) {  
                 if ($env{'form.'.$prefix.'_'.$rule} >= $staticdefaults{$rule}) {  
                     $ruleok = 1;  
                 }  
             }  
         } elsif (($env{'form.'.$prefix.'_'.$rule} =~ /^\d+$/) &&  
                  ($env{'form.'.$prefix.'_'.$rule} ne '0')) {  
             $ruleok = 1;  
         }  
         if ($ruleok) {  
             $newvalues->{$rule} = $env{'form.'.$prefix.'_'.$rule};  
             if (exists($current->{$rule})) {  
                 if ($newvalues->{$rule} ne $current->{$rule}) {  
                     $changes->{'rules'} = 1;  
                 }  
             } elsif ($rule eq 'min') {  
                 if ($staticdefaults{$rule} ne $newvalues->{$rule}) {  
                     $changes->{'rules'} = 1;  
                 }  
             } else {  
                 $changes->{'rules'} = 1;  
             }  
         } elsif (exists($current->{$rule})) {  
             $changes->{'rules'} = 1;  
         }  
     }  
     my @posschars = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_chars');  
     my @chars;  
     foreach my $item (sort(@posschars)) {  
         if ($item =~ /^(uc|lc|num|spec)$/) {  
             push(@chars,$item);  
         }  
     }  
     $newvalues->{'chars'} = \@chars;  
     unless ($changes->{'rules'}) {  
         if (ref($current->{'chars'}) eq 'ARRAY') {  
             my @diffs = &Apache::loncommon::compare_arrays($current->{'chars'},\@chars);  
             if (@diffs > 0) {  
                 $changes->{'rules'} = 1;  
             }  
         } else {  
             if (@chars > 0) {  
                 $changes->{'rules'} = 1;  
             }  
         }  
     }  
     return;  
 }  
   
 sub modify_usercreation {  sub modify_usercreation {
     my ($dom,%domconfig) = @_;      my ($dom,%domconfig) = @_;
     my ($resulttext,%curr_usercreation,%changes,%authallowed,%cancreate,%save_usercreate);      my ($resulttext,%curr_usercreation,%changes,%authallowed,%cancreate,%save_usercreate);
Line 15831  sub modify_usercreation { Line 8485  sub modify_usercreation {
             if ($key eq 'cancreate') {              if ($key eq 'cancreate') {
                 if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') {                  if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') {
                     foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) {                      foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) {
                         if (($item eq 'requestcrs') || ($item eq 'course') || ($item eq 'author')) {                          if (($item eq 'selfcreate') || ($item eq 'statustocreate') ||
                             $curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};                              ($item eq 'captcha') || ($item eq 'recaptchakeys')) {
                         } else {  
                             $save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};                              $save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};
                           } else {
                               $curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};
                         }                          }
                     }                      }
                 }                  }
Line 15906  sub modify_usercreation { Line 8561  sub modify_usercreation {
     }      }
   
     my @authen_contexts = ('author','course','domain');      my @authen_contexts = ('author','course','domain');
     my @authtypes = ('int','krb4','krb5','loc','lti');      my @authtypes = ('int','krb4','krb5','loc');
     my %authhash;      my %authhash;
     foreach my $item (@authen_contexts) {      foreach my $item (@authen_contexts) {
         my @authallowed =  &Apache::loncommon::get_env_multiple('form.'.$item.'_auth');          my @authallowed =  &Apache::loncommon::get_env_multiple('form.'.$item.'_auth');
Line 16037  sub modify_usercreation { Line 8692  sub modify_usercreation {
 }  }
   
 sub modify_selfcreation {  sub modify_selfcreation {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,%domconfig) = @_;
     my ($resulttext,$warningmsg,%curr_usercreation,%curr_usermodify,%curr_inststatus,%changes,%cancreate);      my ($resulttext,$warningmsg,%curr_usercreation,%curr_usermodify,%changes,%cancreate);
     my (%save_usercreate,%save_usermodify,%save_inststatus,@types,%usertypes);      my (%save_usercreate,%save_usermodify);
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);      my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
     my ($othertitle,$usertypesref,$typesref) = &Apache::loncommon::sorted_inst_types($dom);      if (ref($types) eq 'ARRAY') {
     if (ref($typesref) eq 'ARRAY') {          $usertypes->{'default'} = $othertitle;
         @types = @{$typesref};          push(@{$types},'default');
     }  
     if (ref($usertypesref) eq 'HASH') {  
         %usertypes = %{$usertypesref};  
     }      }
     $usertypes{'default'} = $othertitle;  
 #  #
 # Retrieve current domain configuration for self-creation of usernames from $domconfig{'usercreation'}.  # Retrieve current domain configuration for self-creation of usernames from $domconfig{'usercreation'}.
 #  #
Line 16058  sub modify_selfcreation { Line 8709  sub modify_selfcreation {
                 if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') {                  if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') {
                     foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) {                      foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) {
                         if (($item eq 'selfcreate') || ($item eq 'statustocreate') ||                          if (($item eq 'selfcreate') || ($item eq 'statustocreate') ||
                             ($item eq 'captcha') || ($item eq 'recaptchakeys') ||                              ($item eq 'captcha') || ($item eq 'recaptchakeys') || 
                             ($item eq 'recaptchaversion') || ($item eq 'notify') ||                              ($item eq 'emailusername') || ($item eq 'notify') ||
                             ($item eq 'emailusername') || ($item eq 'shibenv') ||                              ($item eq 'selfcreateprocessing') || ($item eq 'shibenv')) {
                             ($item eq 'selfcreateprocessing') || ($item eq 'emailverified') ||  
                             ($item eq 'emailoptions') || ($item eq 'emaildomain')) {  
                             $curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};                              $curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};
                         } else {                          } else {
                             $save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};                              $save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};
Line 16088  sub modify_selfcreation { Line 8737  sub modify_selfcreation {
             }              }
         }          }
     }      }
 #  
 # Retrieve current domain configuration for institutional status types from $domconfig{'inststatus'}.  
 #  
     if (ref($domconfig{'inststatus'}) eq 'HASH') {  
         foreach my $key (keys(%{$domconfig{'inststatus'}})) {  
             if ($key eq 'inststatusguest') {  
                 $curr_inststatus{$key} = $domconfig{'inststatus'}{$key};  
             } else {  
                 $save_inststatus{$key} = $domconfig{'inststatus'}{$key};  
             }  
         }  
     }  
   
     my @contexts = ('selfcreate');      my @contexts = ('selfcreate');
     @{$cancreate{'selfcreate'}} = ();      @{$cancreate{'selfcreate'}} = ();
     %{$cancreate{'emailusername'}} = ();      %{$cancreate{'emailusername'}} = ();
     if (@types) {      @{$cancreate{'statustocreate'}} = ();
         @{$cancreate{'statustocreate'}} = ();  
     }  
     %{$cancreate{'selfcreateprocessing'}} = ();      %{$cancreate{'selfcreateprocessing'}} = ();
     %{$cancreate{'shibenv'}} = ();      %{$cancreate{'shibenv'}} = ();
     %{$cancreate{'emailverified'}} = ();  
     %{$cancreate{'emailoptions'}} = ();  
     %{$cancreate{'emaildomain'}} = ();  
     my %selfcreatetypes = (      my %selfcreatetypes = (
                              sso   => 'users authenticated by institutional single sign on',                               sso   => 'users authenticated by institutional single sign on',
                              login => 'users authenticated by institutional log-in',                               login => 'users authenticated by institutional log-in',
                              email => 'users verified by e-mail',                               email => 'users who provide a valid e-mail address for use as username',
                           );                            );
 #  #
 # Populate $cancreate{'selfcreate'} array reference with types of user, for which self-creation of user accounts  # Populate $cancreate{'selfcreate'} array reference with types of user, for which self-creation of user accounts
 # is permitted.  # is permitted.
 #  #
     my ($emailrules,$emailruleorder) = &Apache::lonnet::inst_userrules($dom,'email');  
   
     my (@statuses,%email_rule);      my @statuses;
       if (ref($domconfig{'inststatus'}) eq 'HASH') {
           if (ref($domconfig{'inststatus'}{'inststatusguest'}) eq 'ARRAY') {
               @statuses = @{$domconfig{'inststatus'}{'inststatusguest'}};
           }
       }
       push(@statuses,'default');
   
     foreach my $item ('login','sso','email') {      foreach my $item ('login','sso','email') {
         if ($item eq 'email') {          if ($item eq 'email') {
             if ($env{'form.cancreate_email'}) {              if ($env{'form.cancreate_email'}) {
                 if (@types) {                  push(@{$cancreate{'selfcreate'}},'email');
                     my @poss_statuses = &Apache::loncommon::get_env_multiple('form.selfassign');                  push(@contexts,'selfcreateprocessing');
                     foreach my $status (@poss_statuses) {                  foreach my $type (@statuses) {
                         if (grep(/^\Q$status\E$/,(@types,'default'))) {                      if ($type eq 'default') {
                             push(@statuses,$status);                          $cancreate{'selfcreateprocessing'}{$type} = $env{'form.cancreate_emailprocess'};
                         }                      } else { 
                     }                          $cancreate{'selfcreateprocessing'}{$type} = $env{'form.cancreate_emailprocess_'.$type};
                     $save_inststatus{'inststatusguest'} = \@statuses;  
                 } else {  
                     push(@statuses,'default');  
                 }  
                 if (@statuses) {  
                     my %curr_rule;  
                     if (ref($curr_usercreation{'email_rule'}) eq 'ARRAY') {  
                         foreach my $type (@statuses) {  
                             $curr_rule{$type} = $curr_usercreation{'email_rule'};  
                         }  
                     } elsif (ref($curr_usercreation{'email_rule'}) eq 'HASH') {  
                         foreach my $type (@statuses) {  
                             $curr_rule{$type} = $curr_usercreation{'email_rule'}{$type};  
                         }  
                     }  
                     push(@{$cancreate{'selfcreate'}},'email');  
                     push(@contexts,('selfcreateprocessing','emailverified','emailoptions'));  
                     my %curremaildom;  
                     if (ref($curr_usercreation{'cancreate'}{'emaildomain'}) eq 'HASH') {  
                         %curremaildom = %{$curr_usercreation{'cancreate'}{'emaildomain'}};  
                     }  
                     foreach my $type (@statuses) {  
                         if ($env{'form.cancreate_emailprocess_'.$type} =~ /^(?:approval|automatic)$/) {  
                             $cancreate{'selfcreateprocessing'}{$type} = $env{'form.cancreate_emailprocess_'.$type};  
                         }  
                         if ($env{'form.cancreate_usernameoptions_'.$type} =~ /^(?:all|first|free)$/) {  
                             $cancreate{'emailverified'}{$type} = $env{'form.cancreate_usernameoptions_'.$type};  
                         }  
                         if ($env{'form.cancreate_emailoptions_'.$type} =~ /^(any|inst|noninst|custom)$/) {  
 #  
 # Retrieve rules (if any) governing types of e-mail address which may be used to verify a username.  
 #  
                             my $chosen = $1;  
                             if (($chosen eq 'inst') || ($chosen eq 'noninst')) {  
                                 my $emaildom;  
                                 if ($env{'form.cancreate_emaildomain_'.$chosen.'_'.$type} =~ /^\@[^\@]+$/) {  
                                     $emaildom = $env{'form.cancreate_emaildomain_'.$chosen.'_'.$type};  
                                     $cancreate{'emaildomain'}{$type}{$chosen} = $emaildom;  
                                     if (ref($curremaildom{$type}) eq 'HASH') {  
                                         if (exists($curremaildom{$type}{$chosen})) {  
                                             if ($curremaildom{$type}{$chosen} ne $emaildom) {  
                                                 push(@{$changes{'cancreate'}},'emaildomain');  
                                             }  
                                         } elsif ($emaildom ne '') {  
                                             push(@{$changes{'cancreate'}},'emaildomain');  
                                         }  
                                     } elsif ($emaildom ne '') {  
                                         push(@{$changes{'cancreate'}},'emaildomain');  
                                     }  
                                 }  
                                 $cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type};  
                             } elsif ($chosen eq 'custom') {  
                                 my @possemail_rules = &Apache::loncommon::get_env_multiple('form.email_rule_'.$type);  
                                 $email_rule{$type} = [];  
                                 if (ref($emailrules) eq 'HASH') {  
                                     foreach my $rule (@possemail_rules) {  
                                         if (exists($emailrules->{$rule})) {  
                                             push(@{$email_rule{$type}},$rule);  
                                         }  
                                     }  
                                 }  
                                 if (@{$email_rule{$type}}) {  
                                     $cancreate{'emailoptions'}{$type} = 'custom';  
                                     if (ref($curr_rule{$type}) eq 'ARRAY') {  
                                         if (@{$curr_rule{$type}} > 0) {  
                                             foreach my $rule (@{$curr_rule{$type}}) {  
                                                 if (!grep(/^\Q$rule\E$/,@{$email_rule{$type}})) {  
                                                     push(@{$changes{'email_rule'}},$type);  
                                                 }  
                                             }  
                                         }  
                                         foreach my $type (@{$email_rule{$type}}) {  
                                             if (!grep(/^\Q$type\E$/,@{$curr_rule{$type}})) {  
                                                 push(@{$changes{'email_rule'}},$type);  
                                             }  
                                         }  
                                     } else {  
                                         push(@{$changes{'email_rule'}},$type);  
                                     }  
                                 }  
                             } else {  
                                 $cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type};  
                             }  
                         }  
                     }  
                     if (@types) {  
                         if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') {  
                             my @changed = &Apache::loncommon::compare_arrays(\@statuses,$curr_inststatus{'inststatusguest'});  
                             if (@changed) {  
                                 push(@{$changes{'inststatus'}},'inststatusguest');  
                             }  
                         } else {  
                             push(@{$changes{'inststatus'}},'inststatusguest');  
                         }  
                     }  
                 } else {  
                     delete($env{'form.cancreate_email'});  
                     if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') {  
                         if (@{$curr_inststatus{'inststatusguest'}} > 0) {  
                             push(@{$changes{'inststatus'}},'inststatusguest');  
                         }  
                     }  
                 }  
             } else {  
                 $save_inststatus{'inststatusguest'} = [];  
                 if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') {  
                     if (@{$curr_inststatus{'inststatusguest'}} > 0) {  
                         push(@{$changes{'inststatus'}},'inststatusguest');  
                     }                      }
                 }                  }
             }              }
Line 16251  sub modify_selfcreation { Line 8781  sub modify_selfcreation {
             }              }
         }          }
     }      }
     my (%userinfo,%savecaptcha);      my (@email_rule,%userinfo,%savecaptcha);
     my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info();      my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info();
 #  #
 # Populate $cancreate{'emailusername'}{$type} hash ref with information fields (if new user will provide data  # Populate $cancreate{'emailusername'}{$type} hash ref with information fields (if new user will provide data
Line 16260  sub modify_selfcreation { Line 8790  sub modify_selfcreation {
   
     if ($env{'form.cancreate_email'}) {      if ($env{'form.cancreate_email'}) {
         push(@contexts,'emailusername');          push(@contexts,'emailusername');
         if (@statuses) {          if (ref($types) eq 'ARRAY') {
             foreach my $type (@statuses) {              foreach my $type (@{$types}) {
                 if (ref($infofields) eq 'ARRAY') {                  if (ref($infofields) eq 'ARRAY') {
                     foreach my $field (@{$infofields}) {                      foreach my $field (@{$infofields}) {
                         if ($env{'form.canmodify_emailusername_'.$type.'_'.$field} =~ /^(required|optional)$/) {                          if ($env{'form.canmodify_emailusername_'.$type.'_'.$field} =~ /^(required|optional)$/) {
Line 16273  sub modify_selfcreation { Line 8803  sub modify_selfcreation {
         }          }
 #  #
 # Populate $cancreate{'notify'} hash ref with names of Domain Coordinators who are to be notified of  # Populate $cancreate{'notify'} hash ref with names of Domain Coordinators who are to be notified of
 # queued requests for self-creation of account verified by e-mail.  # queued requests for self-creation of account using e-mail address as username
 #  #
   
         my @approvalnotify = &Apache::loncommon::get_env_multiple('form.selfcreationnotifyapproval');          my @approvalnotify = &Apache::loncommon::get_env_multiple('form.selfcreationnotifyapproval');
Line 16293  sub modify_selfcreation { Line 8823  sub modify_selfcreation {
             push(@{$changes{'cancreate'}},'notify');              push(@{$changes{'cancreate'}},'notify');
         }          }
   
   #
   # Retrieve rules (if any) governing types of e-mail address which may be used as a username
   #
           @email_rule = &Apache::loncommon::get_env_multiple('form.email_rule');
         &process_captcha('cancreate',\%changes,\%savecaptcha,$curr_usercreation{'cancreate'});          &process_captcha('cancreate',\%changes,\%savecaptcha,$curr_usercreation{'cancreate'});
           if (ref($curr_usercreation{'email_rule'}) eq 'ARRAY') {
               if (@{$curr_usercreation{'email_rule'}} > 0) {
                   foreach my $type (@{$curr_usercreation{'email_rule'}}) {
                       if (!grep(/^\Q$type\E$/,@email_rule)) {
                           push(@{$changes{'email_rule'}},$type);
                       }
                   }
               }
               if (@email_rule > 0) {
                   foreach my $type (@email_rule) {
                       if (!grep(/^\Q$type\E$/,@{$curr_usercreation{'email_rule'}})) {
                           push(@{$changes{'email_rule'}},$type);
                       }
                   }
               }
           } elsif (@email_rule > 0) {
               push(@{$changes{'email_rule'}},@email_rule);
           }
     }      }
 #    #  
 # Check if domain default is set appropriately, if self-creation of accounts is to be available for  # Check if domain default is set appropriately, if self-creation of accounts is to be available for
 # institutional log-in.  # institutional log-in.
 #  #
     if (grep(/^login$/,@{$cancreate{'selfcreate'}})) {      if (grep(/^login$/,@{$cancreate{'selfcreate'}})) {
           my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
         if (!((($domdefaults{'auth_def'} =~/^krb/) && ($domdefaults{'auth_arg_def'} ne '')) ||           if (!((($domdefaults{'auth_def'} =~/^krb/) && ($domdefaults{'auth_arg_def'} ne '')) || 
                ($domdefaults{'auth_def'} eq 'localauth'))) {                 ($domdefaults{'auth_def'} eq 'localauth'))) {
             $warningmsg = &mt('Although account creation has been set to be available for institutional logins, currently default authentication in this domain has not been set to support this.').' '.              $warningmsg = &mt('Although account creation has been set to be available for institutional logins, currently default authentication in this domain has not been set to support this.').' '.
Line 16318  sub modify_selfcreation { Line 8871  sub modify_selfcreation {
 # which the user may supply, if institutional data is unavailable.  # which the user may supply, if institutional data is unavailable.
 #  #
     if (($env{'form.cancreate_login'}) || ($env{'form.cancreate_sso'})) {      if (($env{'form.cancreate_login'}) || ($env{'form.cancreate_sso'})) {
         if (@types) {          if (ref($types) eq 'ARRAY') {
             @{$cancreate{'statustocreate'}} = &Apache::loncommon::get_env_multiple('form.statustocreate');              if (@{$types} > 1) {
             push(@contexts,'statustocreate');                  @{$cancreate{'statustocreate'}} = &Apache::loncommon::get_env_multiple('form.statustocreate');
             foreach my $type (@types) {                  push(@contexts,'statustocreate');
               } else {
                   undef($cancreate{'statustocreate'});
               } 
               foreach my $type (@{$types}) {
                 my @modifiable =  &Apache::loncommon::get_env_multiple('form.canmodify_'.$type);                  my @modifiable =  &Apache::loncommon::get_env_multiple('form.canmodify_'.$type);
                 foreach my $field (@fields) {                  foreach my $field (@fields) {
                     if (grep(/^\Q$field\E$/,@modifiable)) {                      if (grep(/^\Q$field\E$/,@modifiable)) {
Line 16332  sub modify_selfcreation { Line 8889  sub modify_selfcreation {
                 }                  }
             }              }
             if (ref($curr_usermodify{'selfcreate'}) eq 'HASH') {              if (ref($curr_usermodify{'selfcreate'}) eq 'HASH') {
                 foreach my $type (@types) {                  foreach my $type (@{$types}) {
                     if (ref($curr_usermodify{'selfcreate'}{$type}) eq 'HASH') {                      if (ref($curr_usermodify{'selfcreate'}{$type}) eq 'HASH') {
                         foreach my $field (@fields) {                          foreach my $field (@fields) {
                             if ($save_usermodify{'selfcreate'}{$type}{$field} ne                              if ($save_usermodify{'selfcreate'}{$type}{$field} ne
Line 16344  sub modify_selfcreation { Line 8901  sub modify_selfcreation {
                     }                      }
                 }                  }
             } else {              } else {
                 foreach my $type (@types) {                  foreach my $type (@{$types}) {
                     push(@{$changes{'selfcreate'}},$type);                      push(@{$changes{'selfcreate'}},$type);
                 }                  }
             }              }
Line 16393  sub modify_selfcreation { Line 8950  sub modify_selfcreation {
             }              }
         } elsif (ref($curr_usercreation{'cancreate'}{$item}) eq 'HASH') {          } elsif (ref($curr_usercreation{'cancreate'}{$item}) eq 'HASH') {
             if (ref($cancreate{$item}) eq 'HASH') {              if (ref($cancreate{$item}) eq 'HASH') {
                 foreach my $type (keys(%{$curr_usercreation{'cancreate'}{$item}})) {                  foreach my $curr (keys(%{$curr_usercreation{'cancreate'}{$item}})) {
                     if (ref($curr_usercreation{'cancreate'}{$item}{$type}) eq 'HASH') {                      if (ref($curr_usercreation{'cancreate'}{$item}{$curr}) eq 'HASH') {
                         foreach my $field (keys(%{$curr_usercreation{'cancreate'}{$item}{$type}})) {                          foreach my $field (keys(%{$curr_usercreation{'cancreate'}{$item}{$curr}})) {
                             unless ($curr_usercreation{'cancreate'}{$item}{$type}{$field} eq $cancreate{$item}{$type}{$field}) {                              unless ($curr_usercreation{'cancreate'}{$item}{$curr}{$field} eq $cancreate{$item}{$curr}{$field}) {
                                 if (!grep(/^$item$/,@{$changes{'cancreate'}})) {                                  if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
                                     push(@{$changes{'cancreate'}},$item);                                      push(@{$changes{'cancreate'}},$item);
                                 }                                  }
                             }                              }
                         }                          }
                     } elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) {                      } elsif ($item eq 'selfcreateprocessing') {
                         if ($cancreate{$item}{$type} ne $curr_usercreation{'cancreate'}{$item}{$type}) {                          if ($cancreate{$item}{$curr} ne $curr_usercreation{'cancreate'}{$item}{$curr}) {
                               if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
                                   push(@{$changes{'cancreate'}},$item);
                               }
                           }
                       } else {
                           if (!$cancreate{$item}{$curr}) {
                             if (!grep(/^$item$/,@{$changes{'cancreate'}})) {                              if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
                                 push(@{$changes{'cancreate'}},$item);                                  push(@{$changes{'cancreate'}},$item);
                             }                              }
                         }                          }
                     }                      }
                 }                  }
                 foreach my $type (keys(%{$cancreate{$item}})) {                  foreach my $field (keys(%{$cancreate{$item}})) {
                     if (ref($cancreate{$item}{$type}) eq 'HASH') {                      if (ref($cancreate{$item}{$field}) eq 'HASH') {
                         foreach my $field (keys(%{$cancreate{$item}{$type}})) {                          foreach my $inner (keys(%{$cancreate{$item}{$field}})) {
                             if (ref($curr_usercreation{'cancreate'}{$item}{$type}) eq 'HASH') {                              if (ref($curr_usercreation{'cancreate'}{$item}{$field}) eq 'HASH') {
                                 unless ($curr_usercreation{'cancreate'}{$item}{$type}{$field} eq $cancreate{$item}{$type}{$field}) {                                  unless ($curr_usercreation{'cancreate'}{$item}{$field}{$inner} eq $cancreate{$item}{$field}{$inner}) {
                                     if (!grep(/^$item$/,@{$changes{'cancreate'}})) {                                      if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
                                         push(@{$changes{'cancreate'}},$item);                                          push(@{$changes{'cancreate'}},$item);
                                     }                                      }
Line 16425  sub modify_selfcreation { Line 8988  sub modify_selfcreation {
                                 }                                  }
                             }                              }
                         }                          }
                     } elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) {                      } elsif ($item eq 'selfcreateprocessing') {
                         if ($cancreate{$item}{$type} ne $curr_usercreation{'cancreate'}{$item}{$type}) {                          if ($cancreate{$item}{$field} ne $curr_usercreation{'cancreate'}{$item}{$field}) {
                               if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
                                   push(@{$changes{'cancreate'}},$item);
                               }
                           }
                       } else {
                           if (!$curr_usercreation{'cancreate'}{$item}{$field}) {
                             if (!grep(/^$item$/,@{$changes{'cancreate'}})) {                              if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
                                 push(@{$changes{'cancreate'}},$item);                                  push(@{$changes{'cancreate'}},$item);
                             }                              }
Line 16441  sub modify_selfcreation { Line 9010  sub modify_selfcreation {
                         push(@{$changes{'cancreate'}},$item);                          push(@{$changes{'cancreate'}},$item);
                     }                      }
                 }                  }
             }              } elsif (ref($cancreate{$item}) eq 'HASH') {
         } elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) {                  if (!$cancreate{$item}{$curr_usercreation{'cancreate'}{$item}}) {
             if (ref($cancreate{$item}) eq 'HASH') {                      if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
                 if (!grep(/^$item$/,@{$changes{'cancreate'}})) {                          push(@{$changes{'cancreate'}},$item);
                     push(@{$changes{'cancreate'}},$item);                      }
                 }                  }
             }              }
         } elsif ($item eq 'emailusername') {          } elsif ($item eq 'emailusername') {
Line 16470  sub modify_selfcreation { Line 9039  sub modify_selfcreation {
 #  #
     $save_usercreate{'cancreate'}{'captcha'} = $savecaptcha{'captcha'};      $save_usercreate{'cancreate'}{'captcha'} = $savecaptcha{'captcha'};
     $save_usercreate{'cancreate'}{'recaptchakeys'} = $savecaptcha{'recaptchakeys'};      $save_usercreate{'cancreate'}{'recaptchakeys'} = $savecaptcha{'recaptchakeys'};
     $save_usercreate{'cancreate'}{'recaptchaversion'} = $savecaptcha{'recaptchaversion'};  
     $save_usercreate{'cancreate'}{'selfcreate'} = $cancreate{'selfcreate'};      $save_usercreate{'cancreate'}{'selfcreate'} = $cancreate{'selfcreate'};
     if (ref($cancreate{'notify'}) eq 'HASH') {      if (ref($cancreate{'notify'}) eq 'HASH') {
         $save_usercreate{'cancreate'}{'notify'} = $cancreate{'notify'};          $save_usercreate{'cancreate'}{'notify'} = $cancreate{'notify'};
Line 16478  sub modify_selfcreation { Line 9046  sub modify_selfcreation {
     if (ref($cancreate{'selfcreateprocessing'}) eq 'HASH') {      if (ref($cancreate{'selfcreateprocessing'}) eq 'HASH') {
         $save_usercreate{'cancreate'}{'selfcreateprocessing'} = $cancreate{'selfcreateprocessing'};          $save_usercreate{'cancreate'}{'selfcreateprocessing'} = $cancreate{'selfcreateprocessing'};
     }      }
     if (ref($cancreate{'emailverified'}) eq 'HASH') {  
         $save_usercreate{'cancreate'}{'emailverified'} = $cancreate{'emailverified'};  
     }  
     if (ref($cancreate{'emailoptions'}) eq 'HASH') {  
         $save_usercreate{'cancreate'}{'emailoptions'} = $cancreate{'emailoptions'};  
     }  
     if (ref($cancreate{'emaildomain'}) eq 'HASH') {  
         $save_usercreate{'cancreate'}{'emaildomain'} = $cancreate{'emaildomain'};  
     }  
     if (ref($cancreate{'statustocreate'}) eq 'ARRAY') {      if (ref($cancreate{'statustocreate'}) eq 'ARRAY') {
         $save_usercreate{'cancreate'}{'statustocreate'} = $cancreate{'statustocreate'};          $save_usercreate{'cancreate'}{'statustocreate'} = $cancreate{'statustocreate'};
     }      }
Line 16494  sub modify_selfcreation { Line 9053  sub modify_selfcreation {
         $save_usercreate{'cancreate'}{'shibenv'} = $cancreate{'shibenv'};          $save_usercreate{'cancreate'}{'shibenv'} = $cancreate{'shibenv'};
     }      }
     $save_usercreate{'cancreate'}{'emailusername'} = $cancreate{'emailusername'};      $save_usercreate{'cancreate'}{'emailusername'} = $cancreate{'emailusername'};
     $save_usercreate{'email_rule'} = \%email_rule;      $save_usercreate{'emailrule'} = \@email_rule;
   
     my %userconfig_hash = (      my %userconfig_hash = (
             usercreation     => \%save_usercreate,              usercreation     => \%save_usercreate,
             usermodification => \%save_usermodify,              usermodification => \%save_usermodify,
             inststatus       => \%save_inststatus,  
     );      );
   
     my $putresult = &Apache::lonnet::put_dom('configuration',\%userconfig_hash,      my $putresult = &Apache::lonnet::put_dom('configuration',\%userconfig_hash,
                                              $dom);                                               $dom);
 #  #
 # Accumulate details of changes to domain configuration for self-creation of usernames in $resulttext  # Accumulate details of changes to domain cofiguration for self-creation of usernames in $resulttext
 #  #
     if ($putresult eq 'ok') {      if ($putresult eq 'ok') {
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
Line 16513  sub modify_selfcreation { Line 9070  sub modify_selfcreation {
             if (ref($changes{'cancreate'}) eq 'ARRAY') {              if (ref($changes{'cancreate'}) eq 'ARRAY') {
                 my %lt = &selfcreation_types();                  my %lt = &selfcreation_types();
                 foreach my $type (@{$changes{'cancreate'}}) {                  foreach my $type (@{$changes{'cancreate'}}) {
                     my $chgtext = '';                      my $chgtext;
                     if ($type eq 'selfcreate') {                      if ($type eq 'selfcreate') {
                         if (@{$cancreate{$type}} == 0) {                          if (@{$cancreate{$type}} == 0) {
                             $chgtext .= &mt('Self creation of a new user account is not permitted.');                              $chgtext .= &mt('Self creation of a new user account is not permitted.');
Line 16528  sub modify_selfcreation { Line 9085  sub modify_selfcreation {
                                 if (grep(/^(login|sso)$/,@{$cancreate{$type}})) {                                  if (grep(/^(login|sso)$/,@{$cancreate{$type}})) {
                                     if (ref($cancreate{'statustocreate'}) eq 'ARRAY') {                                      if (ref($cancreate{'statustocreate'}) eq 'ARRAY') {
                                         if (@{$cancreate{'statustocreate'}} == 0) {                                          if (@{$cancreate{'statustocreate'}} == 0) {
                                             $chgtext .= '<span class="LC_warning">'.                                              $chgtext .= '<br />'.
                                                         &mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts via log-in or single sign-on.").                                                          '<span class="LC_warning">'.
                                                         '</span><br />';                                                          &mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts.").
                                                           '</span>';
                                         }                                          }
                                     }                                      }
                                 }                                  }
                                 if (grep(/^email$/,@{$cancreate{$type}})) {  
                                     if (!@statuses) {  
                                         $chgtext .= '<span class="LC_warning">'.  
                                                     &mt("However, e-mail verification is currently set to 'unavailable' for all user types (including 'other'), so self-creation of accounts is not possible for non-institutional log-in.").  
                                                     '</span><br />';  
   
                                     }  
                                 }  
                             }                              }
                         }                          }
                     } elsif ($type eq 'shibenv') {                      } elsif ($type eq 'shibenv') {
                         if (keys(%{$cancreate{$type}}) == 0) {                          if (keys(%{$cancreate{$type}}) == 0) {
                             $chgtext .= &mt('Shibboleth-autheticated user does not use environment variables to set user information').'<br />';                               $chgtext .= &mt('Shibboleth-autheticated user does not use environment variables to set user information'); 
                         } else {                          } else {
                             $chgtext .= &mt('Shibboleth-autheticated user information set from environment variables, as follows:').                              $chgtext .= &mt('Shibboleth-autheticated user information set from environment variables, as follows:').
                                         '<ul>';                                          '<ul>';
Line 16559  sub modify_selfcreation { Line 9109  sub modify_selfcreation {
                                 }                                  }
                             }                              }
                             $chgtext .= '</ul>';                              $chgtext .= '</ul>';
                         }                          }  
                     } elsif ($type eq 'statustocreate') {                      } elsif ($type eq 'statustocreate') {
                         if ((ref($cancreate{'selfcreate'}) eq 'ARRAY') &&                          if ((ref($cancreate{'selfcreate'}) eq 'ARRAY') &&
                             (ref($cancreate{'statustocreate'}) eq 'ARRAY')) {                              (ref($cancreate{'statustocreate'}) eq 'ARRAY')) {
Line 16572  sub modify_selfcreation { Line 9122  sub modify_selfcreation {
                                                     &mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts.").                                                      &mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts.").
                                                     '</span>';                                                      '</span>';
                                     }                                      }
                                 } elsif (keys(%usertypes) > 0) {                                  } elsif (ref($usertypes) eq 'HASH') {
                                     if (grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) {                                      if (grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) {
                                         $chgtext .= &mt('Creation of a new account for an institutional user is restricted to the following institutional affiliation(s):');                                          $chgtext .= &mt('Creation of a new account for an institutional user is restricted to the following institutional affiliation(s):');
                                     } else {                                      } else {
Line 16583  sub modify_selfcreation { Line 9133  sub modify_selfcreation {
                                         if ($case eq 'default') {                                          if ($case eq 'default') {
                                             $chgtext .= '<li>'.$othertitle.'</li>';                                              $chgtext .= '<li>'.$othertitle.'</li>';
                                         } else {                                          } else {
                                             $chgtext .= '<li>'.$usertypes{$case}.'</li>';                                              $chgtext .= '<li>'.$usertypes->{$case}.'</li>';
                                         }                                          }
                                     }                                      }
                                     $chgtext .= '</ul>';                                      $chgtext .= '</ul>';
                                     if (!grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) {                                      if (!grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) {
                                         $chgtext .= '<span class="LC_warning">'.                                          $chgtext .= '<br /><span class="LC_warning">'.
                                                     &mt('However, users authenticated by institutional login/single sign on are not currently permitted to create accounts.').                                                      &mt('However, users authenticated by institutional login/single sign on are not currently permitted to create accounts.').
                                                     '</span>';                                                      '</span>';
                                     }                                      }
Line 16600  sub modify_selfcreation { Line 9150  sub modify_selfcreation {
                                     $chgtext .= &mt('Although institutional affiliations permitted to create accounts were changed, self creation of accounts is not currently permitted for any authentication types.');                                      $chgtext .= &mt('Although institutional affiliations permitted to create accounts were changed, self creation of accounts is not currently permitted for any authentication types.');
                                 }                                  }
                             }                              }
                             $chgtext .= '<br />';  
                         }                          }
                     } elsif ($type eq 'selfcreateprocessing') {                      } elsif ($type eq 'selfcreateprocessing') {
                         my %choices = &Apache::lonlocal::texthash (                          my %choices = &Apache::lonlocal::texthash (
                                                                     automatic => 'Automatic approval',                                                                      automatic => 'Automatic approval',
                                                                     approval  => 'Queued for approval',                                                                      approval  => 'Queued for approval',
                                                                   );                                                                    );
                         if (@types) {                          if (@statuses > 1) {
                             if (@statuses) {                              $chgtext .= &mt('Processing of requests to create account with e-mail address as username set as follows:'). 
                                 $chgtext .= &mt('Processing of requests to create account with e-mail verification set as follows:').                                          '<ul>';
                                             '<ul>';                             foreach my $type (@statuses) {
                                 foreach my $status (@statuses) {                                 if ($type eq 'default') {
                                     if ($status eq 'default') {                                     $chgtext .= '<li>'.$othertitle.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$type}}.'</li>';
                                         $chgtext .= '<li>'.$othertitle.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$status}}.'</li>';                                 } else {
                                     } else {                                     $chgtext .= '<li>'.$usertypes->{$type}.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$type}}.'</li>';
                                         $chgtext .= '<li>'.$usertypes{$status}.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$status}}.'</li>';                                 }
                                     }                             }
                                 }                             $chgtext .= '</ul>';
                                 $chgtext .= '</ul>';  
                             }  
                         } else {  
                             $chgtext .= &mt('Processing of requests to create account with e-mail verification set to: "[_1]"',  
                                             $choices{$cancreate{'selfcreateprocessing'}{'default'}});  
                         }  
                     } elsif ($type eq 'emailverified') {  
                         my %options = &Apache::lonlocal::texthash (  
                                                                     all   => 'Same as e-mail',  
                                                                     first => 'Omit @domain',  
                                                                     free  => 'Free to choose',  
                                                                   );  
                         if (@types) {  
                             if (@statuses) {  
                                 $chgtext .= &mt('For self-created accounts verified by e-mail address, username is set as follows:').  
                                             '<ul>';  
                                 foreach my $status (@statuses) {  
                                     if ($status eq 'default') {  
                                         $chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';  
                                     } else {  
                                         $chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';  
                                     }  
                                 }  
                                 $chgtext .= '</ul>';  
                             }  
                         } else {  
                             $chgtext .= &mt("For self-created accounts verified by e-mail address, user's username is: '[_1]'",  
                                             $options{$cancreate{'emailverified'}{'default'}});  
                         }  
                     } elsif ($type eq 'emailoptions') {  
                         my %options = &Apache::lonlocal::texthash (  
                                                                     any     => 'Any e-mail',  
                                                                     inst    => 'Institutional only',  
                                                                     noninst => 'Non-institutional only',  
                                                                     custom  => 'Custom restrictions',  
                                                                   );  
                         if (@types) {  
                             if (@statuses) {  
                                 $chgtext .= &mt('For self-created accounts verified by e-mail address, requirements for e-mail address are as follows:').  
                                             '<ul>';  
                                 foreach my $status (@statuses) {  
                                     if ($type eq 'default') {  
                                         $chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailoptions'}{$status}}.'</li>';  
                                     } else {  
                                         $chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailoptions'}{$status}}.'</li>';  
                                     }  
                                 }  
                                 $chgtext .= '</ul>';  
                             }  
                         } else {                          } else {
                             if ($cancreate{'emailoptions'}{'default'} eq 'any') {                             $chgtext .= &mt('Processing of requests to create account with e-mail address as username set to: "[_1]"',
                                 $chgtext .= &mt('For self-created accounts verified by e-mail address, any e-mail may be used');                                           $choices{$cancreate{'selfcreateprocessing'}{'default'}});
                             } else {  
                                 $chgtext .= &mt('For self-created accounts verified by e-mail address, e-mail restricted to: "[_1]"',  
                                                 $options{$cancreate{'emailoptions'}{'default'}});  
                             }  
                         }  
                     } elsif ($type eq 'emaildomain') {  
                         my $output;  
                         if (@statuses) {  
                             foreach my $type (@statuses) {  
                                 if (ref($cancreate{'emaildomain'}{$type}) eq 'HASH') {  
                                     if ($cancreate{'emailoptions'}{$type} eq 'inst') {  
                                         if ($type eq 'default') {  
                                             if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') ||  
                                                 ($cancreate{'emaildomain'}{$type}{'inst'} eq '')) {  
                                                 $output = '<li>'.$othertitle.' -- '.&mt('No restriction on e-mail domain').'</li>';  
                                             } else {  
                                                 $output = '<li>'.$othertitle.' -- '.&mt("User's e-mail address needs to end: [_1]",  
                                                                                         $cancreate{'emaildomain'}{$type}{'inst'}).'</li>';  
                                             }  
                                         } else {  
                                             if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') ||  
                                                 ($cancreate{'emaildomain'}{$type}{'inst'} eq '')) {  
                                                 $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';  
                                             } else {  
                                                 $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address needs to end: [_1]",  
                                                                                               $cancreate{'emaildomain'}{$type}{'inst'}).'</li>';  
                                             }  
                                         }  
                                     } elsif ($cancreate{'emailoptions'}{$type} eq 'noninst') {  
                                         if ($type eq 'default') {  
                                             if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') ||  
                                                 ($cancreate{'emaildomain'}{$type}{'noninst'} eq '')) {  
                                                 $output = '<li>'.$othertitle.' -- '.&mt('No restriction on e-mail domain').'</li>';  
                                             } else {  
                                                 $output = '<li>'.$othertitle.' -- '.&mt("User's e-mail address must not end: [_1]",  
                                                                                         $cancreate{'emaildomain'}{$type}{'noninst'}).'</li>';  
                                             }  
                                         } else {  
                                             if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') ||  
                                                 ($cancreate{'emaildomain'}{$type}{'noninst'} eq '')) {  
                                                 $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';  
                                             } else {  
                                                 $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address must not end: [_1]",  
                                                                                                 $cancreate{'emaildomain'}{$type}{'noninst'}).'</li>';  
                                             }  
                                         }  
                                     }  
                                 }  
                             }  
                         }  
                         if ($output ne '') {  
                             $chgtext .= &mt('For self-created accounts verified by e-mail address:').  
                                         '<ul>'.$output.'</ul>';  
                         }                          }
                     } elsif ($type eq 'captcha') {                      } elsif ($type eq 'captcha') {
                         if ($savecaptcha{$type} eq 'notused') {                          if ($savecaptcha{$type} eq 'notused') {
Line 16753  sub modify_selfcreation { Line 9200  sub modify_selfcreation {
                             $chgtext .= '<li>'.&mt('Private key set to [_1]',$pubkey).'</li>';                              $chgtext .= '<li>'.&mt('Private key set to [_1]',$pubkey).'</li>';
                         }                          }
                         $chgtext .= '</ul>';                          $chgtext .= '</ul>';
                     } elsif ($type eq 'recaptchaversion') {  
                         if ($savecaptcha{'captcha'} eq 'recaptcha') {  
                             $chgtext .= &mt('ReCAPTCHA set to version [_1]',$savecaptcha{$type});  
                         }  
                     } elsif ($type eq 'emailusername') {                      } elsif ($type eq 'emailusername') {
                         if (ref($cancreate{'emailusername'}) eq 'HASH') {                          if (ref($cancreate{'emailusername'}) eq 'HASH') {
                             if (@statuses) {                              if (ref($types) eq 'ARRAY') {
                                 foreach my $type (@statuses) {                                  foreach my $type (@{$types}) {
                                     if (ref($cancreate{'emailusername'}{$type}) eq 'HASH') {                                      if (ref($cancreate{'emailusername'}{$type}) eq 'HASH') {
                                         if (keys(%{$cancreate{'emailusername'}{$type}}) > 0) {                                          if (keys(%{$cancreate{'emailusername'}{$type}}) > 0) {
                                             $chgtext .= &mt('When self-creating account with e-mail verification, the following information will be provided by [_1]:',"'$usertypes{$type}'").                                              $chgtext .= &mt('When self-creating account with e-mail as username, the following information will be provided by [_1]:',"'$usertypes->{$type}'").
                                                     '<ul>';                                                      '<ul>';
                                             foreach my $field (@{$infofields}) {                                              foreach my $field (@{$infofields}) {
                                                 if ($cancreate{'emailusername'}{$type}{$field}) {                                                  if ($cancreate{'emailusername'}{$type}{$field}) {
Line 16772  sub modify_selfcreation { Line 9215  sub modify_selfcreation {
                                             }                                              }
                                             $chgtext .= '</ul>';                                              $chgtext .= '</ul>';
                                         } else {                                          } else {
                                             $chgtext .= &mt('When self creating account with e-mail verification, no information besides e-mail address will be provided by [_1].',"'$usertypes{$type}'").'<br />';                                              $chgtext .= &mt('When self creating account with e-mail as username, no information besides e-mail address will be provided by [_1].',"'$usertypes->{$type}'").'<br />';
                                         }                                          }
                                     } else {                                      } else {
                                         $chgtext .= &mt('When self creating account with e-mail verification, no information besides e-mail address will be provided by [_1].',"'$usertypes{$type}'").'<br />';                                          $chgtext .= &mt('When self creating account with e-mail as username, no information besides e-mail address will be provided by [_1].',"'$usertypes->{$type}'").'<br />';
                                     }                                      }
                                 }                                  }
                             }                              }
                         }                          }
                     } elsif ($type eq 'notify') {                      } elsif ($type eq 'notify') {
                         my $numapprove = 0;                          $chgtext = &mt('No Domain Coordinators will receive notification of username requests requiring approval.');
                         if (ref($changes{'cancreate'}) eq 'ARRAY') {                          if (ref($changes{'cancreate'}) eq 'ARRAY') {
                             if ((grep(/^notify$/,@{$changes{'cancreate'}})) && (ref($cancreate{'notify'}) eq 'HASH')) {                              if ((grep(/^notify$/,@{$changes{'cancreate'}})) && (ref($cancreate{'notify'}) eq 'HASH')) {
                                 if ($cancreate{'notify'}{'approval'}) {                                  if ($cancreate{'notify'}{'approval'}) {
                                     $chgtext .= &mt('Notification of username requests requiring approval will be sent to: ').$cancreate{'notify'}{'approval'};                                      $chgtext = &mt('Notification of username requests requiring approval will be sent to: ').$cancreate{'notify'}{'approval'};
                                     $numapprove ++;  
                                 }                                  }
                             }                              }
                         }                          }
                         unless ($numapprove) {  
                             $chgtext .= &mt('No Domain Coordinators will receive notification of username requests requiring approval.');  
                         }  
                     }                      }
                     if ($chgtext) {                      if ($chgtext) {
                         $resulttext .= '<li>'.$chgtext.'</li>';                          $resulttext .= '<li>'.$chgtext.'</li>';
                     }                      }
                 }                  }
             }              }
             if ((ref($changes{'email_rule'}) eq 'ARRAY') && (@{$changes{'email_rule'}} > 0)) {              if (ref($changes{'email_rule'}) eq 'ARRAY') {
                 my ($emailrules,$emailruleorder) =                  my ($emailrules,$emailruleorder) =
                     &Apache::lonnet::inst_userrules($dom,'email');                      &Apache::lonnet::inst_userrules($dom,'email');
                 foreach my $type (@{$changes{'email_rule'}}) {                  my $chgtext = '<ul>';
                     if (ref($email_rule{$type}) eq 'ARRAY') {                  foreach my $type (@email_rule) {
                         my $chgtext = '<ul>';                      if (ref($emailrules->{$type}) eq 'HASH') {
                         foreach my $rule (@{$email_rule{$type}}) {                          $chgtext .= '<li>'.$emailrules->{$type}{'name'}.'</li>';
                             if (ref($emailrules->{$rule}) eq 'HASH') {  
                                 $chgtext .= '<li>'.$emailrules->{$rule}{'name'}.'</li>';  
                             }  
                         }  
                         $chgtext .= '</ul>';  
                         my $typename;  
                         if (@types) {  
                             if ($type eq 'default') {  
                                 $typename = $othertitle;  
                             } else {  
                                 $typename = $usertypes{$type};  
                             }  
                             $chgtext .= &mt('(Affiliation: [_1])',$typename);  
                         }  
                         if (@{$email_rule{$type}} > 0) {  
                             $resulttext .= '<li>'.  
                                            &mt('Accounts may not be created by users verified by e-mail, for e-mail addresses of the following types: ',  
                                                $usertypes{$type}).  
                                            $chgtext.  
                                            '</li>';  
                         } else {  
                             $resulttext .= '<li>'.  
                                            &mt('There are now no restrictions on e-mail addresses which may be used for verification when a user requests an account.').  
                                            '</li>'.  
                                            &mt('(Affiliation: [_1])',$typename);  
                         }  
                     }                      }
                 }                  }
             }                  $chgtext .= '</ul>';
             if (ref($changes{'inststatus'}) eq 'ARRAY') {                  if (@email_rule > 0) {
                 if (ref($save_inststatus{'inststatusguest'}) eq 'ARRAY') {                      $resulttext .= '<li>'.
                     if (@{$save_inststatus{'inststatusguest'}} > 0) {                                     &mt('Accounts may not be created by users self-enrolling with e-mail addresses of the following types: ').
                         my $chgtext = '<ul>';                                         $chgtext.
                         foreach my $type (@{$save_inststatus{'inststatusguest'}}) {                                     '</li>';
                             $chgtext .= '<li>'.$usertypes{$type}.'</li>';                  } else {
                         }                      $resulttext .= '<li>'.
                         $chgtext .= '</ul>';                                     &mt('There are now no restrictions on e-mail addresses which may be used as a username when self-enrolling.').
                         $resulttext .= '<li>'.                                     '</li>';
                                        &mt('A user will self-report one of the following affiliations when requesting an account verified by e-mail: ').  
                                           $chgtext.  
                                        '</li>';  
                     } else {  
                         $resulttext .= '<li>'.  
                                        &mt('No affiliations available for self-reporting when requesting an account verified by e-mail.').  
                                        '</li>';  
                     }  
                 }                  }
             }              }
             if (ref($changes{'selfcreate'}) eq 'ARRAY') {              if (ref($changes{'selfcreate'}) eq 'ARRAY') {
Line 16859  sub modify_selfcreation { Line 9264  sub modify_selfcreation {
                 my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();                  my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
                 foreach my $type (@{$changes{'selfcreate'}}) {                  foreach my $type (@{$changes{'selfcreate'}}) {
                     my $typename = $type;                      my $typename = $type;
                     if (keys(%usertypes) > 0) {                      if (ref($usertypes) eq 'HASH') {
                         if ($usertypes{$type} ne '') {                          if ($usertypes->{$type} ne '') {
                             $typename = $usertypes{$type};                              $typename = $usertypes->{$type};
                         }                          }
                     }                      }
                     my @modifiable;                      my @modifiable;
Line 16884  sub modify_selfcreation { Line 9289  sub modify_selfcreation {
                 $resulttext .= '</ul></li>';                  $resulttext .= '</ul></li>';
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
             my $cachetime = 24*60*60;  
             $domdefaults{'inststatusguest'} = $save_inststatus{'inststatusguest'};  
             &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);  
             if (ref($lastactref) eq 'HASH') {  
                 $lastactref->{'domdefaults'} = 1;  
             }  
         } else {          } else {
             $resulttext = &mt('No changes made to self-creation settings');              $resulttext = &mt('No changes made to self-creation settings');
         }          }
Line 16904  sub modify_selfcreation { Line 9303  sub modify_selfcreation {
 }  }
   
 sub process_captcha {  sub process_captcha {
     my ($container,$changes,$newsettings,$currsettings) = @_;      my ($container,$changes,$newsettings,$current) = @_;
     return unless ((ref($changes) eq 'HASH') && (ref($newsettings) eq 'HASH'));      return unless ((ref($changes) eq 'HASH') && (ref($newsettings) eq 'HASH') || (ref($current) eq 'HASH'));
     $newsettings->{'captcha'} = $env{'form.'.$container.'_captcha'};      $newsettings->{'captcha'} = $env{'form.'.$container.'_captcha'};
     unless ($newsettings->{'captcha'} eq 'recaptcha' || $newsettings->{'captcha'} eq 'notused') {      unless ($newsettings->{'captcha'} eq 'recaptcha' || $newsettings->{'captcha'} eq 'notused') {
         $newsettings->{'captcha'} = 'original';          $newsettings->{'captcha'} = 'original';
     }      }
     my %current;      if ($current->{'captcha'} ne $newsettings->{'captcha'}) {
     if (ref($currsettings) eq 'HASH') {  
         %current = %{$currsettings};  
     }  
     if ($current{'captcha'} ne $newsettings->{'captcha'}) {  
         if ($container eq 'cancreate') {          if ($container eq 'cancreate') {
             if (ref($changes->{'cancreate'}) eq 'ARRAY') {              if (ref($changes->{'cancreate'}) eq 'ARRAY') {
                 push(@{$changes->{'cancreate'}},'captcha');                  push(@{$changes->{'cancreate'}},'captcha');
             } elsif (!defined($changes->{'cancreate'})) {              } elsif (!defined($changes->{'cancreate'})) {
                 $changes->{'cancreate'} = ['captcha'];                  $changes->{'cancreate'} = ['captcha'];
             }              }
         } elsif ($container eq 'passwords') {  
             $changes->{'reset'} = 1;  
         } else {          } else {
             $changes->{'captcha'} = 1;              $changes->{'captcha'} = 1;
         }          }
     }      }
     my ($newpub,$newpriv,$currpub,$currpriv,$newversion,$currversion);      my ($newpub,$newpriv,$currpub,$currpriv);
     if ($newsettings->{'captcha'} eq 'recaptcha') {      if ($newsettings->{'captcha'} eq 'recaptcha') {
         $newpub = $env{'form.'.$container.'_recaptchapub'};          $newpub = $env{'form.'.$container.'_recaptchapub'};
         $newpriv = $env{'form.'.$container.'_recaptchapriv'};          $newpriv = $env{'form.'.$container.'_recaptchapriv'};
Line 16937  sub process_captcha { Line 9330  sub process_captcha {
                                              public  => $newpub,                                               public  => $newpub,
                                              private => $newpriv,                                               private => $newpriv,
                                           };                                            };
         $newversion = $env{'form.'.$container.'_recaptchaversion'};      }
         $newversion =~ s/\D//g;      if (ref($current->{'recaptchakeys'}) eq 'HASH') {
         if ($newversion ne '2') {          $currpub = $current->{'recaptchakeys'}{'public'};
             $newversion = 1;          $currpriv = $current->{'recaptchakeys'}{'private'};
         }  
         $newsettings->{'recaptchaversion'} = $newversion;  
     }  
     if (ref($current{'recaptchakeys'}) eq 'HASH') {  
         $currpub = $current{'recaptchakeys'}{'public'};  
         $currpriv = $current{'recaptchakeys'}{'private'};  
         unless ($newsettings->{'captcha'} eq 'recaptcha') {          unless ($newsettings->{'captcha'} eq 'recaptcha') {
             $newsettings->{'recaptchakeys'} = {              $newsettings->{'recaptchakeys'} = {
                                                  public  => '',                                                   public  => '',
Line 16954  sub process_captcha { Line 9341  sub process_captcha {
                                               }                                                }
         }          }
     }      }
     if ($current{'captcha'} eq 'recaptcha') {  
         $currversion = $current{'recaptchaversion'};  
         if ($currversion ne '2') {  
             $currversion = 1;  
         }  
     }  
     if ($currversion ne $newversion) {  
         if ($container eq 'cancreate') {  
             if (ref($changes->{'cancreate'}) eq 'ARRAY') {  
                 push(@{$changes->{'cancreate'}},'recaptchaversion');  
             } elsif (!defined($changes->{'cancreate'})) {  
                 $changes->{'cancreate'} = ['recaptchaversion'];  
             }  
         } elsif ($container eq 'passwords') {  
             $changes->{'reset'} = 1;  
         } else {  
             $changes->{'recaptchaversion'} = 1;  
         }  
     }  
     if (($newpub ne $currpub) || ($newpriv ne $currpriv)) {      if (($newpub ne $currpub) || ($newpriv ne $currpriv)) {
         if ($container eq 'cancreate') {          if ($container eq 'cancreate') {
             if (ref($changes->{'cancreate'}) eq 'ARRAY') {              if (ref($changes->{'cancreate'}) eq 'ARRAY') {
Line 16980  sub process_captcha { Line 9348  sub process_captcha {
             } elsif (!defined($changes->{'cancreate'})) {              } elsif (!defined($changes->{'cancreate'})) {
                 $changes->{'cancreate'} = ['recaptchakeys'];                  $changes->{'cancreate'} = ['recaptchakeys'];
             }              }
         } elsif ($container eq 'passwords') {  
             $changes->{'reset'} = 1;  
         } else {          } else {
             $changes->{'recaptchakeys'} = 1;              $changes->{'recaptchakeys'} = 1;
         }          }
Line 17096  sub modify_defaults { Line 9462  sub modify_defaults {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,$mailmsgtxt,%newvalues,%changes,@errors);      my ($resulttext,$mailmsgtxt,%newvalues,%changes,@errors);
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);      my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
     my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def',      my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def','portal_def');
                  'portal_def');      my @authtypes = ('internal','krb4','krb5','localauth');
     my @authtypes = ('internal','krb4','krb5','localauth','lti');  
     foreach my $item (@items) {      foreach my $item (@items) {
         $newvalues{$item} = $env{'form.'.$item};          $newvalues{$item} = $env{'form.'.$item};
         if ($item eq 'auth_def') {          if ($item eq 'auth_def') {
Line 17135  sub modify_defaults { Line 9500  sub modify_defaults {
             }              }
         } elsif ($item eq 'portal_def') {          } elsif ($item eq 'portal_def') {
             if ($newvalues{$item} ne '') {              if ($newvalues{$item} ne '') {
                 if ($newvalues{$item} =~ /^https?\:\/\/(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])\/?$/) {                  unless ($newvalues{$item} =~ /^https?\:\/\/(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])\/?$/) {
                     foreach my $field ('email','web') {  
                         if ($env{'form.'.$item.'_'.$field}) {  
                             $newvalues{$item.'_'.$field} = $env{'form.'.$item.'_'.$field};  
                         }  
                     }  
                 } else {  
                     push(@errors,$item);                      push(@errors,$item);
                 }                  }
             }              }
         }          }
         if (grep(/^\Q$item\E$/,@errors)) {          if (grep(/^\Q$item\E$/,@errors)) {
             $newvalues{$item} = $domdefaults{$item};              $newvalues{$item} = $domdefaults{$item};
             if ($item eq 'portal_def') {  
                 if ($domdefaults{$item}) {  
                     foreach my $field ('email','web') {  
                         if (exists($domdefaults{$item.'_'.$field})) {  
                             $newvalues{$item.'_'.$field} = $domdefaults{$item.'_'.$field};  
                         }  
                     }  
                 }  
             }  
         } elsif ($domdefaults{$item} ne $newvalues{$item}) {          } elsif ($domdefaults{$item} ne $newvalues{$item}) {
             $changes{$item} = 1;              $changes{$item} = 1;
         }          }
         if ($item eq 'portal_def') {  
             unless (grep(/^\Q$item\E$/,@errors)) {  
                 if ($newvalues{$item} eq '') {  
                     foreach my $field ('email','web') {  
                         if (exists($domdefaults{$item.'_'.$field})) {  
                             delete($domdefaults{$item.'_'.$field});  
                         }  
                     }  
                 } else {  
                     unless ($changes{$item}) {  
                         foreach my $field ('email','web') {  
                             if ($domdefaults{$item.'_'.$field} ne $newvalues{$item.'_'.$field}) {  
                                 $changes{$item} = 1;  
                                 last;  
                             }  
                         }  
                     }  
                     foreach my $field ('email','web') {  
                         if ($newvalues{$item.'_'.$field}) {  
                             $domdefaults{$item.'_'.$field} = $newvalues{$item.'_'.$field};  
                         } elsif (exists($domdefaults{$item.'_'.$field})) {  
                             delete($domdefaults{$item.'_'.$field});  
                         }  
                     }  
                 }  
             }  
         }  
         $domdefaults{$item} = $newvalues{$item};          $domdefaults{$item} = $newvalues{$item};
     }      }
     my %staticdefaults = (  
                            'intauth_cost'   => 10,  
                            'intauth_check'  => 0,  
                            'intauth_switch' => 0,  
                          );  
     foreach my $item ('intauth_cost','intauth_check','intauth_switch') {  
         if (exists($domdefaults{$item})) {  
             $newvalues{$item} = $domdefaults{$item};  
         } else {  
             $newvalues{$item} = $staticdefaults{$item};  
         }  
     }  
     my ($unamemaprules,$ruleorder);  
     my @possunamemaprules = &Apache::loncommon::get_env_multiple('form.unamemap_rule');  
     if (@possunamemaprules) {  
         ($unamemaprules,$ruleorder) =  
             &Apache::lonnet::inst_userrules($dom,'unamemap');  
         if ((ref($unamemaprules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {  
             if (@{$ruleorder} > 0) {  
                 my %possrules;  
                 map { $possrules{$_} = 1; } @possunamemaprules;  
                 foreach my $rule (@{$ruleorder}) {  
                     if ($possrules{$rule}) {  
                         push(@{$newvalues{'unamemap_rule'}},$rule);  
                     }  
                 }  
             }  
         }  
     }  
     if (ref($domdefaults{'unamemap_rule'}) eq 'ARRAY') {  
         if (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') {  
             my @rulediffs = &Apache::loncommon::compare_arrays($domdefaults{'unamemap_rule'},  
                                                                $newvalues{'unamemap_rule'});  
             if (@rulediffs) {  
                 $changes{'unamemap_rule'} = 1;  
                 $domdefaults{'unamemap_rule'} = $newvalues{'unamemap_rule'};  
             }  
         } elsif (@{$domdefaults{'unamemap_rule'}} > 0) {  
             $changes{'unamemap_rule'} = 1;  
             delete($domdefaults{'unamemap_rule'});  
         }  
     } elsif (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') {  
         if (@{$newvalues{'unamemap_rule'}} > 0) {  
             $changes{'unamemap_rule'} = 1;  
             $domdefaults{'unamemap_rule'} = $newvalues{'unamemap_rule'};  
         }  
     }  
     my %defaults_hash = (      my %defaults_hash = (
                          defaults => \%newvalues,                           defaults => \%newvalues,
                         );                          );
Line 17254  sub modify_defaults { Line 9530  sub modify_defaults {
     }      }
     my @todelete = &Apache::loncommon::get_env_multiple('form.inststatus_delete');      my @todelete = &Apache::loncommon::get_env_multiple('form.inststatus_delete');
     my @allpos;      my @allpos;
       my %guests;
     my %alltypes;      my %alltypes;
     my @inststatusguest;      my ($currtitles,$currguests,$currorder);
     if (ref($currinststatus) eq 'HASH') {  
         if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') {  
             foreach my $type (@{$currinststatus->{'inststatusguest'}}) {  
                 unless (grep(/^\Q$type\E$/,@todelete)) {  
                     push(@inststatusguest,$type);  
                 }  
             }  
         }  
     }  
     my ($currtitles,$currorder);  
     if (ref($currinststatus) eq 'HASH') {      if (ref($currinststatus) eq 'HASH') {
         if (ref($currinststatus->{'inststatusorder'}) eq 'ARRAY') {          if (ref($currinststatus->{'inststatusorder'}) eq 'ARRAY') {
             foreach my $type (@{$currinststatus->{'inststatusorder'}}) {              foreach my $type (@{$currinststatus->{'inststatusorder'}}) {
Line 17280  sub modify_defaults { Line 9547  sub modify_defaults {
                     $allpos[$position] = $type;                      $allpos[$position] = $type;
                     $alltypes{$type} = $env{'form.inststatus_title_'.$type};                      $alltypes{$type} = $env{'form.inststatus_title_'.$type};
                     $alltypes{$type} =~ s/`//g;                      $alltypes{$type} =~ s/`//g;
                       if ($env{'form.inststatus_guest_'.$type}) {
                           $guests{$type} = 1;
                       }
                 }                  }
             }              }
               if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') {
                   $currguests = join(',',@{$currinststatus->{'inststatusguest'}});
               }
             $currorder = join(',',@{$currinststatus->{'inststatusorder'}});              $currorder = join(',',@{$currinststatus->{'inststatusorder'}});
             $currtitles =~ s/,$//;              $currtitles =~ s/,$//;
         }          }
Line 17290  sub modify_defaults { Line 9563  sub modify_defaults {
         my $newtype = $env{'form.addinststatus'};          my $newtype = $env{'form.addinststatus'};
         $newtype =~ s/\W//g;          $newtype =~ s/\W//g;
         unless (exists($alltypes{$newtype})) {          unless (exists($alltypes{$newtype})) {
               if ($env{'form.addinststatus_guest'}) {
                   $guests{$newtype} = 1;
               }
             $alltypes{$newtype} = $env{'form.addinststatus_title'};              $alltypes{$newtype} = $env{'form.addinststatus_title'};
             $alltypes{$newtype} =~ s/`//g;               $alltypes{$newtype} =~ s/`//g; 
             my $position = $env{'form.addinststatus_pos'};              my $position = $env{'form.addinststatus_pos'};
Line 17299  sub modify_defaults { Line 9575  sub modify_defaults {
             }              }
         }          }
     }      }
     my @orderedstatus;      my (@orderedstatus,@orderedguests);
     foreach my $type (@allpos) {      foreach my $type (@allpos) {
         unless (($type eq '') || (grep(/^\Q$type\E$/,@orderedstatus))) {          unless (($type eq '') || (grep(/^\Q$type\E$/,@orderedstatus))) {
             push(@orderedstatus,$type);              push(@orderedstatus,$type);
               if ($guests{$type}) {
                   push(@orderedguests,$type);
               }
         }          }
     }      }
     foreach my $type (keys(%alltypes)) {      foreach my $type (keys(%alltypes)) {
Line 17313  sub modify_defaults { Line 9592  sub modify_defaults {
     $defaults_hash{'inststatus'} = {      $defaults_hash{'inststatus'} = {
                                      inststatustypes => \%alltypes,                                       inststatustypes => \%alltypes,
                                      inststatusorder => \@orderedstatus,                                       inststatusorder => \@orderedstatus,
                                      inststatusguest => \@inststatusguest,                                       inststatusguest => \@orderedguests,
                                    };                                     };
     if (ref($defaults_hash{'inststatus'}) eq 'HASH') {      if (ref($defaults_hash{'inststatus'}) eq 'HASH') {
         foreach my $item ('inststatustypes','inststatusorder','inststatusguest') {          foreach my $item ('inststatustypes','inststatusorder','inststatusguest') {
Line 17323  sub modify_defaults { Line 9602  sub modify_defaults {
     if ($currorder ne join(',',@orderedstatus)) {      if ($currorder ne join(',',@orderedstatus)) {
         $changes{'inststatus'}{'inststatusorder'} = 1;          $changes{'inststatus'}{'inststatusorder'} = 1;
     }      }
       if ($currguests ne join(',',@orderedguests)) {
           $changes{'inststatus'}{'inststatusguest'} = 1;
       }
     my $newtitles;      my $newtitles;
     foreach my $item (@orderedstatus) {      foreach my $item (@orderedstatus) {
         $newtitles .= $alltypes{$item}.',';          $newtitles .= $alltypes{$item}.',';
Line 17341  sub modify_defaults { Line 9623  sub modify_defaults {
             foreach my $item (sort(keys(%changes))) {              foreach my $item (sort(keys(%changes))) {
                 if ($item eq 'inststatus') {                  if ($item eq 'inststatus') {
                     if (ref($changes{'inststatus'}) eq 'HASH') {                      if (ref($changes{'inststatus'}) eq 'HASH') {
                         if (@orderedstatus) {                          if (($changes{'inststatus'}{'inststatustypes'}) || $changes{'inststatus'}{'inststatusorder'}) {
                             $resulttext .= '<li>'.&mt('Institutional user status types set to:').' ';                              $resulttext .= '<li>'.&mt('Institutional user status types set to:').' ';
                             foreach my $type (@orderedstatus) {                               foreach my $type (@orderedstatus) { 
                                 $resulttext .= $alltypes{$type}.', ';                                  $resulttext .= $alltypes{$type}.', ';
                             }                              }
                             $resulttext =~ s/, $//;                              $resulttext =~ s/, $//;
                             $resulttext .= '</li>';                              $resulttext .= '</li>';
                         } else {  
                             $resulttext .= '<li>'.&mt('Institutional user status types deleted').'</li>';  
                         }                          }
                     }                          if ($changes{'inststatus'}{'inststatusguest'}) {
                 } elsif ($item eq 'unamemap_rule') {                              $resulttext .= '<li>'; 
                     if (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') {                              if (@orderedguests) {
                         my @rulenames;                                  $resulttext .= &mt('Types assignable to "non-institutional" usernames set to:').' ';
                         if (ref($unamemaprules) eq 'HASH') {                                  foreach my $type (@orderedguests) {
                             foreach my $rule (@{$newvalues{'unamemap_rule'}}) {                                      $resulttext .= $alltypes{$type}.', ';
                                 if (ref($unamemaprules->{$rule}) eq 'HASH') {  
                                     push(@rulenames,$unamemaprules->{$rule}->{'name'});  
                                 }                                  }
                                   $resulttext =~ s/, $//;
                               } else {
                                   $resulttext .= &mt('Types assignable to "non-institutional" usernames set to none.');
                             }                              }
                               $resulttext .= '</li>';
                         }                          }
                         if (@rulenames) {  
                             $resulttext .= '<li>'.&mt('Mapping for missing usernames includes: [_1]',  
                                                      '<ul><li>'.join('</li><li>',@rulenames).'</li></ul>').  
                                            '</li>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('No mapping for missing usernames via standard log-in').'</li>';  
                         }  
                     } else {  
                         $resulttext .= '<li>'.&mt('Mapping for missing usernames via standard log-in deleted').'</li>';  
                     }                      }
                 } else {                  } else {
                     my $value = $env{'form.'.$item};                      my $value = $env{'form.'.$item};
Line 17383  sub modify_defaults { Line 9656  sub modify_defaults {
                                           krb4       => 'krb4',                                            krb4       => 'krb4',
                                           krb5       => 'krb5',                                            krb5       => 'krb5',
                                           localauth  => 'loc',                                            localauth  => 'loc',
                                           lti        => 'lti',  
                         );                          );
                         $value = $authnames{$shortauth{$value}};                          $value = $authnames{$shortauth{$value}};
                     }                      }
                     $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$item},$value).'</li>';                      $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$item},$value).'</li>';
                     $mailmsgtext .= "$title->{$item} set to $value\n";                      $mailmsgtext .= "$title->{$item} set to $value\n";  
                     if ($item eq 'portal_def') {  
                         if ($env{'form.'.$item} ne '') {  
                             foreach my $field ('email','web') {  
                                 $value = $env{'form.'.$item.'_'.$field};  
                                 if ($value) {  
                                     $value = &mt('Yes');  
                                 } else {  
                                     $value = &mt('No');  
                                 }  
                                 $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$field},$value).'</li>';  
                             }  
                         }  
                     }  
                 }                  }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
Line 17447  sub modify_scantron { Line 9706  sub modify_scantron {
     my $custom = 'custom.tab';      my $custom = 'custom.tab';
     my $default = 'default.tab';      my $default = 'default.tab';
     my $servadm = $r->dir_config('lonAdmEMail');      my $servadm = $r->dir_config('lonAdmEMail');
     my ($configuserok,$author_ok,$switchserver) =      my ($configuserok,$author_ok,$switchserver) = 
         &config_check($dom,$confname,$servadm);          &config_check($dom,$confname,$servadm);
     if ($env{'form.scantronformat.filename'} ne '') {      if ($env{'form.scantronformat.filename'} ne '') {
         my $error;          my $error;
Line 17456  sub modify_scantron { Line 9715  sub modify_scantron {
                 $error = &mt("Upload of bubblesheet format file is not permitted to this server: [_1]",$switchserver);                  $error = &mt("Upload of bubblesheet format file is not permitted to this server: [_1]",$switchserver);
             } else {              } else {
                 if ($author_ok eq 'ok') {                  if ($author_ok eq 'ok') {
                     my $modified = [];  
                     my ($result,$scantronurl) =                      my ($result,$scantronurl) =
                         &Apache::lonconfigsettings::publishlogo($r,'upload','scantronformat',$dom,                          &publishlogo($r,'upload','scantronformat',$dom,
                                                                 $confname,'scantron','','',$custom,                                       $confname,'scantron','','',$custom);
                                                                 $modified);  
                     if ($result eq 'ok') {                      if ($result eq 'ok') {
                         $confhash{'scantron'}{'scantronformat'} = $scantronurl;                          $confhash{'scantron'}{'scantronformat'} = $scantronurl;
                         $changes{'scantronformat'} = 1;                          $changes{'scantronformat'} = 1;
                         &update_modify_urls($r,$modified);  
                     } else {                      } else {
                         $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$custom,$result);                          $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$custom,$result);
                     }                      }
Line 17485  sub modify_scantron { Line 9741  sub modify_scantron {
             if ($env{'form.scantronformat_del'}) {              if ($env{'form.scantronformat_del'}) {
                 $confhash{'scantron'}{'scantronformat'} = '';                  $confhash{'scantron'}{'scantronformat'} = '';
                 $changes{'scantronformat'} = 1;                  $changes{'scantronformat'} = 1;
             } else {  
                 $confhash{'scantron'}{'scantronformat'} = $domconfig{'scantron'}{'scantronformat'};  
             }  
         }  
     }  
     my @options = ('hdr','pad','rem');  
     my @fields = &scantroncsv_fields();  
     my %titles = &scantronconfig_titles();  
     my @formats = &Apache::loncommon::get_env_multiple('form.scantronconfig');  
     my ($newdat,$currdat,%newcol,%currcol);  
     if (grep(/^dat$/,@formats)) {  
         $confhash{'scantron'}{config}{dat} = 1;  
         $newdat = 1;  
     } else {  
         $newdat = 0;  
     }  
     if (grep(/^csv$/,@formats)) {  
         my %bynum;  
         foreach my $field (@fields) {  
             if ($env{'form.scantronconfig_csv_'.$field} =~ /^(\d+)$/) {  
                 my $posscol = $1;  
                 if (($posscol < 20) && (!$bynum{$posscol})) {  
                     $confhash{'scantron'}{config}{csv}{fields}{$field} = $posscol;  
                     $bynum{$posscol} = $field;  
                     $newcol{$field} = $posscol;  
                 }  
             }  
         }  
         if (keys(%newcol)) {  
             foreach my $option (@options) {  
                 if ($env{'form.scantroncsv_'.$option}) {  
                     $confhash{'scantron'}{config}{csv}{options}{$option} = 1;  
                 }  
             }  
         }  
     }  
     $currdat = 1;  
     if (ref($domconfig{'scantron'}) eq 'HASH') {  
         if (ref($domconfig{'scantron'}{'config'}) eq 'HASH') {  
             unless (exists($domconfig{'scantron'}{'config'}{'dat'})) {  
                 $currdat = 0;  
             }  
             if (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH') {  
                 if (ref($domconfig{'scantron'}{'config'}{'csv'}{'fields'}) eq 'HASH') {  
                     %currcol = %{$domconfig{'scantron'}{'config'}{'csv'}{'fields'}};  
                 }  
             }  
         }  
     }  
     if ($currdat != $newdat) {  
         $changes{'config'} = 1;  
     } else {  
         foreach my $field (@fields) {  
             if ($currcol{$field} ne '') {  
                 if ($currcol{$field} ne $newcol{$field}) {  
                     $changes{'config'} = 1;  
                     last;  
                 }  
             } elsif ($newcol{$field} ne '') {  
                 $changes{'config'} = 1;  
                 last;  
             }              }
         }          }
     }      }
Line 17556  sub modify_scantron { Line 9751  sub modify_scantron {
             if (keys(%changes) > 0) {              if (keys(%changes) > 0) {
                 if (ref($confhash{'scantron'}) eq 'HASH') {                  if (ref($confhash{'scantron'}) eq 'HASH') {
                     $resulttext = &mt('Changes made:').'<ul>';                      $resulttext = &mt('Changes made:').'<ul>';
                     if ($changes{'scantronformat'}) {                      if ($confhash{'scantron'}{'scantronformat'} eq '') {
                         if ($confhash{'scantron'}{'scantronformat'} eq '') {                          $resulttext .= '<li>'.&mt('[_1] bubblesheet format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'</li>';
                             $resulttext .= '<li>'.&mt('[_1] bubblesheet format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'</li>';                      } else {
                         } else {                          $resulttext .= '<li>'.&mt('Custom bubblesheet format file ([_1]) uploaded for use with courses in this domain.',$custom).'</li>';
                             $resulttext .= '<li>'.&mt('Custom bubblesheet format file ([_1]) uploaded for use with courses in this domain.',$custom).'</li>';  
                         }  
                     }  
                     if ($changes{'config'}) {  
                         if (ref($confhash{'scantron'}{'config'}) eq 'HASH') {  
                             if ($confhash{'scantron'}{'config'}{'dat'}) {  
                                 $resulttext .= '<li>'.&mt('Bubblesheet data upload formats includes .dat format').'</li>';  
                             }  
                             if (ref($confhash{'scantron'}{'config'}{'csv'}) eq 'HASH') {  
                                 if (ref($confhash{'scantron'}{'config'}{'csv'}{'fields'}) eq 'HASH') {  
                                     if (keys(%{$confhash{'scantron'}{'config'}{'csv'}{'fields'}})) {  
                                         $resulttext .= '<li>'.&mt('Bubblesheet data upload formats includes .csv format, with following fields/column numbers supported:').'<ul>';  
                                         foreach my $field (@fields) {  
                                             if ($confhash{'scantron'}{'config'}{'csv'}{'fields'}{$field} ne '') {  
                                                 my $showcol = $confhash{'scantron'}{'config'}{'csv'}{'fields'}{$field} + 1;  
                                                 $resulttext .= '<li>'.$titles{$field}.': '.$showcol.'</li>';  
                                             }  
                                         }  
                                         $resulttext .= '</ul></li>';  
                                         if (ref($confhash{'scantron'}{'config'}{'csv'}{'options'}) eq 'HASH') {  
                                             if (keys(%{$confhash{'scantron'}{'config'}{'csv'}{'options'}})) {  
                                                 $resulttext .= '<li>'.&mt('Bubblesheet data upload formats includes .csv format, with following options:').'<ul>';  
                                                 foreach my $option (@options) {  
                                                     if ($confhash{'scantron'}{'config'}{'csv'}{'options'}{$option} ne '') {  
                                                         $resulttext .= '<li>'.$titles{$option}.'</li>';  
                                                     }  
                                                 }  
                                                 $resulttext .= '</ul></li>';  
                                             }  
                                         }  
                                     }  
                                 }  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('No bubblesheet data upload formats set -- will default to assuming .dat format').'</li>';  
                         }  
                     }                      }
                     $resulttext .= '</ul>';                      $resulttext .= '</ul>';
                 } else {                  } else {
                     $resulttext = &mt('Changes made to bubblesheet format file.');                      $resulttext = &mt('Changes made to bubblesheet format file.');
                 }                  }
                   $resulttext .= '</ul>';
                 &Apache::loncommon::devalidate_domconfig_cache($dom);                  &Apache::loncommon::devalidate_domconfig_cache($dom);
                 if (ref($lastactref) eq 'HASH') {                  if (ref($lastactref) eq 'HASH') {
                     $lastactref->{'domainconfig'} = 1;                      $lastactref->{'domainconfig'} = 1;
                 }                  }
             } else {              } else {
                 $resulttext = &mt('No changes made to bubblesheet format settings');                  $resulttext = &mt('No changes made to bubblesheet format file');
             }              }
         } else {          } else {
             $resulttext = '<span class="LC_error">'.              $resulttext = '<span class="LC_error">'.
                 &mt('An error occurred: [_1]',$putresult).'</span>';                  &mt('An error occurred: [_1]',$putresult).'</span>';
         }          }
     } else {      } else {
         $resulttext = &mt('No changes made to bubblesheet format settings');          $resulttext = &mt('No changes made to bubblesheet format file'); 
     }      }
     if ($errors) {      if ($errors) {
         $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.          $resulttext .= &mt('The following errors occurred: ').'<ul>'.
                        $errors.'</ul></p>';                         $errors.'</ul>';
     }      }
     return $resulttext;      return $resulttext;
 }  }
Line 17862  sub modify_coursecategories { Line 10022  sub modify_coursecategories {
                     }                      }
                     $resulttext .= '</ul></li>';                      $resulttext .= '</ul></li>';
                 }                  }
                 &Apache::lonnet::do_cache_new('cats',$dom,$cathash,3600);  
                 if (ref($lastactref) eq 'HASH') {  
                     $lastactref->{'cats'} = 1;  
                 }  
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
             if ($changes{'unauth'} || $changes{'auth'}) {              if ($changes{'unauth'} || $changes{'auth'}) {
Line 18017  sub modify_serverstatuses { Line 10173  sub modify_serverstatuses {
 }  }
   
 sub modify_helpsettings {  sub modify_helpsettings {
     my ($r,$dom,$confname,$lastactref,%domconfig) = @_;      my ($r,$dom,$confname,%domconfig) = @_;
     my ($resulttext,$errors,%changes,%helphash);      my ($resulttext,$errors,%changes,%helphash);
     my %defaultchecked = ('submitbugs' => 'on');      my %defaultchecked = ('submitbugs' => 'on');
     my @offon = ('off','on');      my @offon = ('off','on');
     my @toggles = ('submitbugs');      my @toggles = ('submitbugs');
     my %current = ('submitbugs' => '',  
                    'adhoc'      => {},  
                   );  
     if (ref($domconfig{'helpsettings'}) eq 'HASH') {      if (ref($domconfig{'helpsettings'}) eq 'HASH') {
         %current = %{$domconfig{'helpsettings'}};          foreach my $item (@toggles) {
     }              if ($defaultchecked{$item} eq 'on') { 
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);                  if ($domconfig{'helpsettings'}{$item} eq '') {
     foreach my $item (@toggles) {                      if ($env{'form.'.$item} eq '0') {
         if ($defaultchecked{$item} eq 'on') {                           $changes{$item} = 1;
             if ($current{$item} eq '') {  
                 if ($env{'form.'.$item} eq '0') {  
                     $changes{$item} = 1;  
                 }  
             } elsif ($current{$item} ne $env{'form.'.$item}) {  
                 $changes{$item} = 1;  
             }  
         } elsif ($defaultchecked{$item} eq 'off') {  
             if ($current{$item} eq '') {  
                 if ($env{'form.'.$item} eq '1') {  
                     $changes{$item} = 1;  
                 }  
             } elsif ($current{$item} ne $env{'form.'.$item}) {  
                 $changes{$item} = 1;  
             }  
         }  
         if (($env{'form.'.$item} eq '0') || ($env{'form.'.$item} eq '1')) {  
             $helphash{'helpsettings'}{$item} = $env{'form.'.$item};  
         }  
     }  
     my $maxnum = $env{'form.helproles_maxnum'};  
     my $confname = $dom.'-domainconfig';  
     my %existing=&Apache::lonnet::dump('roles',$dom,$confname,'rolesdef_');  
     my (@allpos,%newsettings,%changedprivs,$newrole);  
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
     my @accesstypes = ('all','dh','da','none','status','inc','exc');  
     my %domhelpdesk = &Apache::lonnet::get_active_domroles($dom,['dh','da']);  
     my %lt = &Apache::lonlocal::texthash(  
                     s      => 'system',  
                     d      => 'domain',  
                     order  => 'Display order',  
                     access => 'Role usage',  
                     all    => 'All with domain helpdesk or helpdesk assistant role',  
                     dh     => 'All with domain helpdesk role',  
                     da     => 'All with domain helpdesk assistant role',  
                     none   => 'None',  
                     status => 'Determined based on institutional status',  
                     inc    => 'Include all, but exclude specific personnel',  
                     exc    => 'Exclude all, but include specific personnel',  
     );  
     for (my $num=0; $num<=$maxnum; $num++) {  
         my ($prefix,$identifier,$rolename,%curr);  
         if ($num == $maxnum) {  
             next unless ($env{'form.newcusthelp'} == $maxnum);  
             $identifier = 'custhelp'.$num;  
             $prefix = 'helproles_'.$num;  
             $rolename = $env{'form.custhelpname'.$num};  
             $rolename=~s/[^A-Za-z0-9]//gs;  
             next if ($rolename eq '');  
             next if (exists($existing{'rolesdef_'.$rolename}));  
             my %newprivs = &Apache::lonuserutils::custom_role_update($rolename,$identifier);  
             my $result = &Apache::lonnet::definerole($rolename,$newprivs{'s'},$newprivs{'d'},  
                                                      $newprivs{'c'},$confname,$dom);  
             if ($result ne 'ok') {  
                 $errors .= '<li><span class="LC_error">'.  
                            &mt('An error occurred storing the new custom role: [_1]',  
                            $result).'</span></li>';  
                 next;  
             } else {  
                 $changedprivs{$rolename} = \%newprivs;  
                 $newrole = $rolename;  
             }  
         } else {  
             $prefix = 'helproles_'.$num;  
             $rolename = $env{'form.'.$prefix};  
             next if ($rolename eq '');  
             next unless (exists($existing{'rolesdef_'.$rolename}));  
             $identifier = 'custhelp'.$num;  
             my %newprivs = &Apache::lonuserutils::custom_role_update($rolename,$identifier);  
             my %currprivs;  
             ($currprivs{'s'},$currprivs{'d'},$currprivs{'c'}) =  
                 split(/\_/,$existing{'rolesdef_'.$rolename});  
             foreach my $level ('c','d','s') {  
                 if ($newprivs{$level} ne $currprivs{$level}) {  
                     my $result = &Apache::lonnet::definerole($rolename,$newprivs{'s'},$newprivs{'d'},  
                                                              $newprivs{'c'},$confname,$dom);  
                     if ($result ne 'ok') {  
                         $errors .= '<li><span class="LC_error">'.  
                                    &mt('An error occurred storing privileges for existing role [_1]: [_2]',  
                                        $rolename,$result).'</span></li>';  
                     } else {  
                         $changedprivs{$rolename} = \%newprivs;  
                     }  
                     last;  
                 }  
             }  
             if (ref($current{'adhoc'}) eq 'HASH') {  
                 if (ref($current{'adhoc'}{$rolename}) eq 'HASH') {  
                     %curr = %{$current{'adhoc'}{$rolename}};  
                 }  
             }  
         }  
         my $newpos = $env{'form.'.$prefix.'_pos'};  
         $newpos =~ s/\D+//g;  
         $allpos[$newpos] = $rolename;  
         my $newdesc = $env{'form.'.$prefix.'_desc'};  
         $helphash{'helpsettings'}{'adhoc'}{$rolename}{'desc'} = $newdesc;  
         if ($curr{'desc'}) {  
             if ($curr{'desc'} ne $newdesc) {  
                 $changes{'customrole'}{$rolename}{'desc'} = 1;  
                 $newsettings{$rolename}{'desc'} = $newdesc;  
             }  
         } elsif ($newdesc ne '') {  
             $changes{'customrole'}{$rolename}{'desc'} = 1;  
             $newsettings{$rolename}{'desc'} = $newdesc;  
         }  
         my $access = $env{'form.'.$prefix.'_access'};  
         if (grep(/^\Q$access\E$/,@accesstypes)) {  
             $helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'} = $access;  
             if ($access eq 'status') {  
                 my @statuses = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_status');  
                 if (scalar(@statuses) == 0) {  
                     $helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'} = 'none';  
                 } else {  
                     my (@shownstatus,$numtypes);  
                     $helphash{'helpsettings'}{'adhoc'}{$rolename}{$access} = [];  
                     if (ref($types) eq 'ARRAY') {  
                         $numtypes = scalar(@{$types});  
                         foreach my $type (sort(@statuses)) {  
                             if ($type eq 'default') {  
                                 push(@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}},$type);  
                             } elsif (grep(/^\Q$type\E$/,@{$types})) {  
                                 push(@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}},$type);  
                                 push(@shownstatus,$usertypes->{$type});  
                             }  
                         }  
                     }  
                     if (grep(/^default$/,@statuses)) {  
                         push(@shownstatus,$othertitle);  
                     }  
                     if (scalar(@shownstatus) == 1+$numtypes) {  
                         $helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'} = 'all';  
                         delete($helphash{'helpsettings'}{'adhoc'}{$rolename}{'status'});  
                     } else {  
                         $newsettings{$rolename}{'status'} = join(' '.&mt('or').' ',@shownstatus);  
                         if (ref($curr{'status'}) eq 'ARRAY') {  
                             my @diffs = &Apache::loncommon::compare_arrays($helphash{'helpsettings'}{'adhoc'}{$rolename}{$access},$curr{$access});  
                             if (@diffs) {  
                                 $changes{'customrole'}{$rolename}{$access} = 1;  
                             }  
                         } elsif (@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}}) {  
                             $changes{'customrole'}{$rolename}{$access} = 1;  
                         }  
                     }  
                 }  
             } elsif (($access eq 'inc') || ($access eq 'exc')) {  
                 my @personnel = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_staff_'.$access);  
                 my @newspecstaff;  
                 $helphash{'helpsettings'}{'adhoc'}{$rolename}{$access} = [];  
                 foreach my $person (sort(@personnel)) {  
                     if ($domhelpdesk{$person}) {  
                         push(@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}},$person);  
                     }                      }
                   } elsif ($domconfig{'helpsettings'}{$item} ne $env{'form.'.$item}) {
                       $changes{$item} = 1;
                 }                  }
                 if (ref($curr{$access}) eq 'ARRAY') {              } elsif ($defaultchecked{$item} eq 'off') {
                     my @diffs = &Apache::loncommon::compare_arrays($helphash{'helpsettings'}{'adhoc'}{$rolename}{$access},$curr{$access});                  if ($domconfig{'helpsettings'}{$item} eq '') {
                     if (@diffs) {                      if ($env{'form.'.$item} eq '1') {
                         $changes{'customrole'}{$rolename}{$access} = 1;                          $changes{$item} = 1;
                     }                      }
                 } elsif (@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}}) {                  } elsif ($domconfig{'helpsettings'}{$item} ne $env{'form.'.$item}) {
                     $changes{'customrole'}{$rolename}{$access} = 1;                      $changes{$item} = 1;
                 }  
                 foreach my $person (@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}}) {  
                     my ($uname,$udom) = split(/:/,$person);  
                         push(@newspecstaff,&Apache::loncommon::aboutmewrapper(&Apache::loncommon::plainname($uname,$udom,'lastname'),$uname,$udom));  
                 }                  }
                 $newsettings{$rolename}{$access} = join(', ',sort(@newspecstaff));  
             }              }
         } else {              if (($env{'form.'.$item} eq '0') || ($env{'form.'.$item} eq '1')) {
             $helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'}= 'all';                  $helphash{'helpsettings'}{$item} = $env{'form.'.$item};
         }  
         unless ($curr{'access'} eq $access) {  
             $changes{'customrole'}{$rolename}{'access'} = 1;  
             $newsettings{$rolename}{'access'} = $lt{$helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'}};  
         }  
     }  
     if (@allpos > 0) {  
         my $idx = 0;  
         foreach my $rolename (@allpos) {  
             if ($rolename ne '') {  
                 $helphash{'helpsettings'}{'adhoc'}{$rolename}{'order'} = $idx;  
                 if (ref($current{'adhoc'}) eq 'HASH') {  
                     if (ref($current{'adhoc'}{$rolename}) eq 'HASH') {  
                         if ($current{'adhoc'}{$rolename}{'order'} ne $idx) {  
                             $changes{'customrole'}{$rolename}{'order'} = 1;  
                             $newsettings{$rolename}{'order'} = $idx+1;  
                         }  
                     }  
                 }  
                 $idx ++;  
             }              }
         }          }
     }      }
Line 18228  sub modify_helpsettings { Line 10206  sub modify_helpsettings {
     if (keys(%changes) > 0) {      if (keys(%changes) > 0) {
         $putresult = &Apache::lonnet::put_dom('configuration',\%helphash,$dom);          $putresult = &Apache::lonnet::put_dom('configuration',\%helphash,$dom);
         if ($putresult eq 'ok') {          if ($putresult eq 'ok') {
             if (ref($helphash{'helpsettings'}) eq 'HASH') {              $resulttext = &mt('Changes made:').'<ul>';
                 $domdefaults{'submitbugs'} = $helphash{'helpsettings'}{'submitbugs'};  
                 if (ref($helphash{'helpsettings'}{'adhoc'}) eq 'HASH') {  
                     $domdefaults{'adhocroles'} = $helphash{'helpsettings'}{'adhoc'};  
                 }  
             }  
             my $cachetime = 24*60*60;  
             &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);  
             if (ref($lastactref) eq 'HASH') {  
                 $lastactref->{'domdefaults'} = 1;  
             }  
         } else {  
             $errors .= '<li><span class="LC_error">'.  
                        &mt('An error occurred storing the settings: [_1]',  
                            $putresult).'</span></li>';  
         }  
     }  
     if ((keys(%changes) && ($putresult eq 'ok')) || (keys(%changedprivs))) {  
         $resulttext = &mt('Changes made:').'<ul>';  
         my (%shownprivs,@levelorder);  
         @levelorder = ('c','d','s');  
         if ((keys(%changes)) && ($putresult eq 'ok')) {  
             foreach my $item (sort(keys(%changes))) {              foreach my $item (sort(keys(%changes))) {
                 if ($item eq 'submitbugs') {                  if ($item eq 'submitbugs') {
                     $resulttext .= '<li>'.&mt('Display link to: [_1] set to "'.$offon[$env{'form.'.$item}].'".',                      $resulttext .= '<li>'.&mt('Display link to: [_1] set to "'.$offon[$env{'form.'.$item}].'".',
                                               &Apache::loncommon::modal_link('http://bugs.loncapa.org',                                                &Apache::loncommon::modal_link('http://bugs.loncapa.org',
                                               &mt('LON-CAPA bug tracker'),600,500)).'</li>';                                                &mt('LON-CAPA bug tracker'),600,500)).'</li>';
                 } elsif ($item eq 'customrole') {  
                     if (ref($changes{'customrole'}) eq 'HASH') {  
                         my @keyorder = ('order','desc','access','status','exc','inc');  
                         my %keytext = &Apache::lonlocal::texthash(  
                                                                    order  => 'Order',  
                                                                    desc   => 'Role description',  
                                                                    access => 'Role usage',  
                                                                    status => 'Allowed institutional types',  
                                                                    exc    => 'Allowed personnel',  
                                                                    inc    => 'Disallowed personnel',  
                         );  
                         foreach my $role (sort(keys(%{$changes{'customrole'}}))) {  
                             if (ref($changes{'customrole'}{$role}) eq 'HASH') {  
                                 if ($role eq $newrole) {  
                                     $resulttext .= '<li>'.&mt('New custom role added: [_1]',  
                                                               $role).'<ul>';  
                                 } else {  
                                     $resulttext .= '<li>'.&mt('Existing custom role modified: [_1]',  
                                                               $role).'<ul>';  
                                 }  
                                 foreach my $key (@keyorder) {  
                                     if ($changes{'customrole'}{$role}{$key}) {  
                                         $resulttext .= '<li>'.&mt("[_1] set to: [_2]",  
                                                                   $keytext{$key},$newsettings{$role}{$key}).  
                                                        '</li>';  
                                     }  
                                 }  
                                 if (ref($changedprivs{$role}) eq 'HASH') {  
                                     $shownprivs{$role} = 1;  
                                     $resulttext .= '<li>'.&mt('Privileges set to :').'<ul>';  
                                     foreach my $level (@levelorder) {  
                                         foreach my $item (split(/\:/,$changedprivs{$role}{$level})) {  
                                             next if ($item eq '');  
                                             my ($priv) = split(/\&/,$item,2);  
                                             if (&Apache::lonnet::plaintext($priv)) {  
                                                 $resulttext .= '<li>'.&Apache::lonnet::plaintext($priv);  
                                                 unless ($level eq 'c') {  
                                                     $resulttext .= ' ('.$lt{$level}.')';  
                                                 }  
                                                 $resulttext .= '</li>';  
                                             }  
                                         }  
                                     }  
                                     $resulttext .= '</ul>';  
                                 }  
                                 $resulttext .= '</ul></li>';  
                             }  
                         }  
                     }  
                 }  
             }  
         }  
         if (keys(%changedprivs)) {  
             foreach my $role (sort(keys(%changedprivs))) {  
                 unless ($shownprivs{$role}) {  
                     $resulttext .= '<li>'.&mt('Existing custom role modified: [_1]',  
                                               $role).'<ul>'.  
                                    '<li>'.&mt('Privileges set to :').'<ul>';  
                     foreach my $level (@levelorder) {  
                         foreach my $item (split(/\:/,$changedprivs{$role}{$level})) {  
                             next if ($item eq '');  
                             my ($priv) = split(/\&/,$item,2);  
                             if (&Apache::lonnet::plaintext($priv)) {  
                                 $resulttext .= '<li>'.&Apache::lonnet::plaintext($priv);  
                                 unless ($level eq 'c') {  
                                     $resulttext .= ' ('.$lt{$level}.')';  
                                 }  
                                 $resulttext .= '</li>';  
                             }  
                         }  
                     }  
                     $resulttext .= '</ul></li></ul></li>';  
                 }                  }
             }              }
               $resulttext .= '</ul>';
           } else {
               $resulttext = &mt('No changes made to help settings');
               $errors .= '<li><span class="LC_error">'.
                          &mt('An error occurred storing the settings: [_1]',
                              $putresult).'</span></li>';
         }          }
         $resulttext .= '</ul>';  
     } else {  
         $resulttext = &mt('No changes made to help settings');  
     }      }
     if ($errors) {      if ($errors) {
         $resulttext .= '<br />'.&mt('The following errors occurred: ').'<ul>'.          $resulttext .= '<br />'.&mt('The following errors occurred: ').'<ul>'.
                                     $errors.'</ul>';                         $errors.'</ul>';
     }      }
     return $resulttext;      return $resulttext;
 }  }
Line 18345  sub modify_coursedefaults { Line 10233  sub modify_coursedefaults {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,$errors,%changes,%defaultshash);      my ($resulttext,$errors,%changes,%defaultshash);
     my %defaultchecked = (      my %defaultchecked = (
                              'canuse_pdfforms' => 'off',
                            'uselcmath'       => 'on',                             'uselcmath'       => 'on',
                            'usejsme'         => 'on',                             'usejsme'         => 'on'
                            'inline_chem'     => 'on',  
                            'ltiauth'         => 'off',  
                          );                           );
     my @toggles = ('uselcmath','usejsme','inline_chem','ltiauth');      my @toggles = ('canuse_pdfforms','uselcmath','usejsme');
     my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial',      my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial',
                    'uploadquota_community','uploadquota_textbook','coursequota_official',                     'uploadquota_community','uploadquota_textbook');
                    'coursequota_unofficial','coursequota_community','coursequota_textbook',  
                    'mysqltables_official','mysqltables_unofficial','mysqltables_community',  
                    'mysqltables_textbook');  
     my @types = ('official','unofficial','community','textbook');      my @types = ('official','unofficial','community','textbook');
     my %staticdefaults = (      my %staticdefaults = (
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
                            coursequota          => 20,  
                            postsubmit           => 60,                             postsubmit           => 60,
                            mysqltables          => 172800,  
                            domexttool           => 1,  
                          );                           );
     my %texoptions = (  
                         MathJax  => 'MathJax',  
                         mimetex  => &mt('Convert to Images'),  
                         tth      => &mt('TeX to HTML'),  
                      );  
     $defaultshash{'coursedefaults'} = {};      $defaultshash{'coursedefaults'} = {};
   
     if (ref($domconfig{'coursedefaults'}) ne 'HASH') {      if (ref($domconfig{'coursedefaults'}) ne 'HASH') {
Line 18408  sub modify_coursedefaults { Line 10285  sub modify_coursedefaults {
                 }                  }
                 $defaultshash{'coursedefaults'}{$item} = $newdef;                  $defaultshash{'coursedefaults'}{$item} = $newdef;
             } else {              } else {
                 my ($setting,$type) = ($item =~ /^(uploadquota|coursequota|mysqltables)_(\w+)$/);                  my ($type) = ($item =~ /^\Quploadquota_\E(\w+)$/);
                 if (ref($domconfig{'coursedefaults'}{$setting}) eq 'HASH') {                  if (ref($domconfig{'coursedefaults'}{'uploadquota'}) eq 'HASH') {
                     $currdef = $domconfig{'coursedefaults'}{$setting}{$type};                      $currdef = $domconfig{'coursedefaults'}{'uploadquota'}{$type};
                 }                  }
                 $newdef =~ s/[^\w.\-]//g;                  $newdef =~ s/[^\w.\-]//g;
                 $defaultshash{'coursedefaults'}{$setting}{$type} = $newdef;                  $defaultshash{'coursedefaults'}{'uploadquota'}{$type} = $newdef;
             }              }
             if ($currdef ne $newdef) {              if ($currdef ne $newdef) {
                   my $staticdef;
                 if ($item eq 'anonsurvey_threshold') {                  if ($item eq 'anonsurvey_threshold') {
                     unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) {                      unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) {
                         $changes{$item} = 1;                          $changes{$item} = 1;
                     }                      }
                 } elsif ($item =~ /^(uploadquota|coursequota|mysqltables)_/) {                  } else {
                     my $setting = $1;                      unless (($currdef eq '') && ($newdef == $staticdefaults{'uploadquota'})) {
                     unless (($currdef eq '') && ($newdef == $staticdefaults{$setting})) {                          $changes{'uploadquota'} = 1;
                         $changes{$setting} = 1;  
                     }                      }
                 }                  }
             }              }
         }          }
         my $texengine;  
         if ($env{'form.texengine'} =~ /^(MathJax|mimetex|tth)$/) {  
             $texengine = $env{'form.texengine'};  
             my $currdef = $domconfig{'coursedefaults'}{'texengine'};  
             if ($currdef eq '') {  
                 unless ($texengine eq $Apache::lonnet::deftex) {  
                     $changes{'texengine'} = 1;  
                 }  
             } elsif ($currdef ne $texengine) {  
                 $changes{'texengine'} = 1;  
             }  
         }  
         if ($texengine ne '') {  
             $defaultshash{'coursedefaults'}{'texengine'} = $texengine;  
         }  
         my $currclone = $domconfig{'coursedefaults'}{'canclone'};  
         my @currclonecode;  
         if (ref($currclone) eq 'HASH') {  
             if (ref($currclone->{'instcode'}) eq 'ARRAY') {  
                 @currclonecode = @{$currclone->{'instcode'}};  
             }  
         }  
         my $newclone;  
         if ($env{'form.canclone'} =~ /^(none|domain|instcode)$/) {  
             $newclone = $env{'form.canclone'};  
         }  
         if ($newclone eq 'instcode') {  
             my @newcodes = &Apache::loncommon::get_env_multiple('form.clonecode');  
             my (%codedefaults,@code_order,@clonecode);  
             &Apache::lonnet::auto_instcode_defaults($dom,\%codedefaults,  
                                                     \@code_order);  
             foreach my $item (@code_order) {  
                 if (grep(/^\Q$item\E$/,@newcodes)) {  
                     push(@clonecode,$item);  
                 }  
             }  
             if (@clonecode) {  
                 $defaultshash{'coursedefaults'}{'canclone'} = { $newclone => \@clonecode };  
                 my @diffs = &Apache::loncommon::compare_arrays(\@currclonecode,\@clonecode);  
                 if (@diffs) {  
                     $changes{'canclone'} = 1;  
                 }  
             } else {  
                 $newclone eq '';  
             }  
         } elsif ($newclone ne '') {  
             $defaultshash{'coursedefaults'}{'canclone'} = $newclone;  
         }  
         if ($newclone ne $currclone) {  
             $changes{'canclone'} = 1;  
         }  
         my %credits;          my %credits;
         foreach my $type (@types) {          foreach my $type (@types) {
             unless ($type eq 'community') {              unless ($type eq 'community') {
Line 18493  sub modify_coursedefaults { Line 10320  sub modify_coursedefaults {
                 $defaultshash{'coursedefaults'}{'coursecredits'}{$type} = $credits{$type};                  $defaultshash{'coursedefaults'}{'coursecredits'}{$type} = $credits{$type};
             }              }
         } else {          } else {
             if ($env{'form.coursecredits'} eq '1') {              if ($env{'form.coursecredits'} eq '1') { 
                 foreach my $type (@types) {                  foreach my $type (@types) {
                     unless ($type eq 'community') {                      unless ($type eq 'community') {
                         if ($domconfig{'coursedefaults'}{'coursecredits'}{$type} ne $credits{$type}) {                          if ($domconfig{'coursedefaults'}{'coursecredits'}{$type} ne $credits{$type}) {        
                             $changes{'coursecredits'} = 1;                              $changes{'coursecredits'} = 1;
                         }                          }
                         $defaultshash{'coursedefaults'}{'coursecredits'}{$type} = $credits{$type};                          $defaultshash{'coursedefaults'}{'coursecredits'}{$type} = $credits{$type};
Line 18539  sub modify_coursedefaults { Line 10366  sub modify_coursedefaults {
                 }                  }
                 if (exists($currtimeout{$type})) {                  if (exists($currtimeout{$type})) {
                     if ($timeout ne $currtimeout{$type}) {                      if ($timeout ne $currtimeout{$type}) {
                         $changes{'postsubmit'} = 1;                          $changes{'postsubmit'} = 1; 
                     }                      }
                 } elsif ($timeout ne '') {                  } elsif ($timeout ne '') {
                     $changes{'postsubmit'} = 1;                      $changes{'postsubmit'} = 1;
Line 18555  sub modify_coursedefaults { Line 10382  sub modify_coursedefaults {
                 $changes{'postsubmit'} = 1;                  $changes{'postsubmit'} = 1;
             }              }
         }          }
         my (%newdomexttool,%newexttool,%olddomexttool,%oldexttool);  
         map { $newdomexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.domexttool');  
         map { $newexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.exttool');  
         if (ref($domconfig{'coursedefaults'}{'domexttool'}) eq 'HASH') {  
             %olddomexttool = %{$domconfig{'coursedefaults'}{'domexttool'}};  
         } else {  
            foreach my $type (@types) {  
                if ($staticdefaults{'domexttool'}) {  
                    $olddomexttool{$type} = 1;  
                } else {  
                    $olddomexttool{$type} = 0;  
                }  
             }  
         }  
         if (ref($domconfig{'coursedefaults'}{'exttool'}) eq 'HASH') {  
             %oldexttool = %{$domconfig{'coursedefaults'}{'exttool'}};  
         } else {  
             foreach my $type (@types) {  
                if ($staticdefaults{'exttool'}) {  
                    $oldexttool{$type} = 1;  
                } else {  
                    $oldexttool{$type} = 0;  
                }  
             }  
         }  
         foreach my $type (@types) {  
             unless ($newdomexttool{$type}) {  
                 $newdomexttool{$type} = 0;  
             }  
             unless ($newexttool{$type}) {  
                 $newexttool{$type} = 0;  
             }  
             if ($newdomexttool{$type} != $olddomexttool{$type}) {  
                 $changes{'domexttool'} = 1;  
             }  
             if ($newexttool{$type} != $oldexttool{$type}) {  
                 $changes{'exttool'} = 1;  
             }  
         }  
         $defaultshash{'coursedefaults'}{'domexttool'} = \%newdomexttool;  
         $defaultshash{'coursedefaults'}{'exttool'} = \%newexttool;  
     }      }
     my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,      my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                              $dom);                                               $dom);
     if ($putresult eq 'ok') {      if ($putresult eq 'ok') {
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
             my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);              my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
             if (($changes{'uploadquota'}) || ($changes{'postsubmit'}) ||              if (($changes{'canuse_pdfforms'}) || ($changes{'uploadquota'}) || ($changes{'postsubmit'}) ||
                 ($changes{'coursecredits'}) || ($changes{'uselcmath'}) || ($changes{'usejsme'}) ||                  ($changes{'coursecredits'}) || ($changes{'uselcmath'}) || ($changes{'usejsme'})) { 
                 ($changes{'canclone'}) || ($changes{'mysqltables'}) || ($changes{'texengine'}) ||                  foreach my $item ('canuse_pdfforms','uselcmath','usejsme') { 
                 ($changes{'inline_chem'}) || ($changes{'ltiauth'}) || ($changes{'domexttool'}) ||  
                 ($changes{'exttool'}) || ($changes{'coursequota'})) {  
                 foreach my $item ('uselcmath','usejsme','inline_chem','texengine','ltiauth') {  
                     if ($changes{$item}) {                      if ($changes{$item}) {
                         $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};                          $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};
                     }                      }
                 }                  } 
                 if ($changes{'coursecredits'}) {                  if ($changes{'coursecredits'}) {
                     if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') {                      if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') {
                         foreach my $type (keys(%{$defaultshash{'coursedefaults'}{'coursecredits'}})) {                          foreach my $type (keys(%{$defaultshash{'coursedefaults'}{'coursecredits'}})) {
Line 18638  sub modify_coursedefaults { Line 10421  sub modify_coursedefaults {
                         }                          }
                     }                      }
                 }                  }
                 if ($changes{'coursequota'}) {  
                     if (ref($defaultshash{'coursedefaults'}{'coursequota'}) eq 'HASH') {  
                         foreach my $type (@types) {  
                             $domdefaults{$type.'coursequota'}=$defaultshash{'coursedefaults'}{'coursequota'}{$type};  
                         }  
                     }  
                 }  
                 if ($changes{'canclone'}) {  
                     if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') {  
                         if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {  
                             my @clonecodes = @{$defaultshash{'coursedefaults'}{'canclone'}{'instcode'}};  
                             if (@clonecodes) {  
                                 $domdefaults{'canclone'} = join('+',@clonecodes);  
                             }  
                         }  
                     } else {  
                         $domdefaults{'canclone'}=$defaultshash{'coursedefaults'}{'canclone'};  
                     }  
                 }  
                 if ($changes{'domexttool'}) {  
                     if (ref($defaultshash{'coursedefaults'}{'domexttool'}) eq 'HASH') {  
                         foreach my $type (@types) {  
                             $domdefaults{$type.'domexttool'}=$defaultshash{'coursedefaults'}{'domexttool'}{$type};  
                         }  
                     }  
                 }  
                 if ($changes{'exttool'}) {  
                     if (ref($defaultshash{'coursedefaults'}{'exttool'}) eq 'HASH') {  
                         foreach my $type (@types) {  
                             $domdefaults{$type.'exttool'}=$defaultshash{'coursedefaults'}{'exttool'}{$type};  
                         }  
                     }  
                 }  
                 my $cachetime = 24*60*60;                  my $cachetime = 24*60*60;
                 &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);                  &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
                 if (ref($lastactref) eq 'HASH') {                  if (ref($lastactref) eq 'HASH') {
Line 18679  sub modify_coursedefaults { Line 10429  sub modify_coursedefaults {
             }              }
             $resulttext = &mt('Changes made:').'<ul>';              $resulttext = &mt('Changes made:').'<ul>';
             foreach my $item (sort(keys(%changes))) {              foreach my $item (sort(keys(%changes))) {
                 if ($item eq 'uselcmath') {                  if ($item eq 'canuse_pdfforms') {
                       if ($env{'form.'.$item} eq '1') {
                           $resulttext .= '<li>'.&mt("Course/Community users can create/upload PDF forms set to 'on'").'</li>';
                       } else {
                           $resulttext .= '<li>'.&mt('Course/Community users can create/upload PDF forms set to "off"').'</li>';
                       }
                   } elsif ($item eq 'uselcmath') {
                     if ($env{'form.'.$item} eq '1') {                      if ($env{'form.'.$item} eq '1') {
                         $resulttext .= '<li>'.&mt('Math preview uses LON-CAPA previewer (javascript), if supported by browser.').'</li>';                          $resulttext .= '<li>'.&mt('Math preview uses LON-CAPA previewer (javascript), if supported by browser.').'</li>';
                     } else {                      } else {
Line 18689  sub modify_coursedefaults { Line 10445  sub modify_coursedefaults {
                     if ($env{'form.'.$item} eq '1') {                      if ($env{'form.'.$item} eq '1') {
                         $resulttext .= '<li>'.&mt('Molecule editor uses JSME (HTML5), if supported by browser.').'</li>';                          $resulttext .= '<li>'.&mt('Molecule editor uses JSME (HTML5), if supported by browser.').'</li>';
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('Molecule editor uses JME (Java), if supported by client OS.').'</li>';                          $resulttext .= '<li>'.&mt('Molecule editor uses JME (Java), if supported by client OS.').'</li>'; 
                     }  
                 } elsif ($item eq 'inline_chem') {  
                     if ($env{'form.'.$item} eq '1') {  
                         $resulttext .= '<li>'.&mt('Chemical Reaction Response uses inline previewer').'</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('Chemical Reaction Response uses pop-up previewer').'</li>';  
                     }  
                 } elsif ($item eq 'texengine') {  
                     if ($defaultshash{'coursedefaults'}{'texengine'} ne '') {  
                         $resulttext .= '<li>'.&mt('Default method to display mathematics set to: "[_1]"',  
                                                   $texoptions{$defaultshash{'coursedefaults'}{'texengine'}}).'</li>';  
                     }                      }
                 } elsif ($item eq 'anonsurvey_threshold') {                  } elsif ($item eq 'anonsurvey_threshold') {
                     $resulttext .= '<li>'.&mt('Responder count required for display of anonymous survey submissions set to [_1].',$defaultshash{'coursedefaults'}{'anonsurvey_threshold'}).'</li>';                      $resulttext .= '<li>'.&mt('Responder count required for display of anonymous survey submissions set to [_1].',$defaultshash{'coursedefaults'}{'anonsurvey_threshold'}).'</li>';
Line 18710  sub modify_coursedefaults { Line 10455  sub modify_coursedefaults {
                                        '<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'official'}.'</b>').'</li>'.                                         '<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'official'}.'</b>').'</li>'.
                                        '<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'unofficial'}.'</b>').'</li>'.                                         '<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'unofficial'}.'</b>').'</li>'.
                                        '<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'textbook'}.'</b>').'</li>'.                                         '<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'textbook'}.'</b>').'</li>'.
   
                                        '<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'community'}.'</b>').'</li>'.                                         '<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'community'}.'</b>').'</li>'.
                                        '</ul>'.                                         '</ul>'.
                                        '</li>';                                         '</li>';
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('Default quota for content uploaded via Course Editor remains default: [_1] MB',$staticdefaults{'uploadquota'}).'</li>';                          $resulttext .= '<li>'.&mt('Default quota for content uploaded via Course Editor remains default: [_1] MB',$staticdefaults{'uploadquota'}).'</li>';
                     }                      }
                 } elsif ($item eq 'coursequota') {  
                     if (ref($defaultshash{'coursedefaults'}{'coursequota'}) eq 'HASH') {  
                         $resulttext .= '<li>'.&mt('Default cumulative quota for all group portfolio spaces in course set as follows:').'<ul>'.  
                                        '<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'official'}.'</b>').'</li>'.  
                                        '<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'unofficial'}.'</b>').'</li>'.  
                                        '<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'textbook'}.'</b>').'</li>'.  
                                        '<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'community'}.'</b>').'</li>'.  
                                        '</ul>'.  
                                        '</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('Default cumulative quota for all group portfolio spaces in course remains default: [_1] MB',$staticdefaults{'coursequota'}).'</li>';  
                     }  
                 } elsif ($item eq 'mysqltables') {  
                     if (ref($defaultshash{'coursedefaults'}{'mysqltables'}) eq 'HASH') {  
                         $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver').'<ul>'.  
                                        '<li>'.&mt('Official courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'official'}.'</b>').'</li>'.  
                                        '<li>'.&mt('Unofficial courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'unofficial'}.'</b>').'</li>'.  
                                        '<li>'.&mt('Textbook courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'textbook'}.'</b>').'</li>'.  
                                        '<li>'.&mt('Communities: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'community'}.'</b>').'</li>'.  
                                        '</ul>'.  
                                        '</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver remains default: [_1] s',$staticdefaults{'uploadquota'}).'</li>';  
                     }  
                 } elsif ($item eq 'postsubmit') {                  } elsif ($item eq 'postsubmit') {
                     if ($domdefaults{'postsubmit'} eq 'off') {                      if ($domdefaults{'postsubmit'} eq 'off') {
                         $resulttext .= '<li>'.&mt('Submit button(s) remain enabled on page after student makes submission.');                          $resulttext .= '<li>'.&mt('Submit button(s) remain enabled on page after student makes submission.');
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('Submit button(s) disabled on page after student makes submission').'; ';                          $resulttext .= '<li>'.&mt('Submit button(s) disabled on page after student makes submission').'; ';
                         if (ref($defaultshash{'coursedefaults'}{'postsubmit'}) eq 'HASH') {                          if (ref($defaultshash{'coursedefaults'}{'postsubmit'}) eq 'HASH') { 
                             $resulttext .= &mt('durations:').'<ul>';                              $resulttext .= &mt('durations:').'<ul>';
                             foreach my $type (@types) {                              foreach my $type (@types) {
                                 $resulttext .= '<li>';                                  $resulttext .= '<li>';
Line 18774  sub modify_coursedefaults { Line 10496  sub modify_coursedefaults {
                             }                              }
                             $resulttext .= '</ul>';                              $resulttext .= '</ul>';
                         }                          }
                         $resulttext .= '</li>';                          $resulttext .= '</li>';    
                     }                      }
                 } elsif ($item eq 'coursecredits') {                  } elsif ($item eq 'coursecredits') {
                     if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') {                      if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') {
Line 18793  sub modify_coursedefaults { Line 10515  sub modify_coursedefaults {
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('Student credits not in use for courses in this domain').'</li>';                          $resulttext .= '<li>'.&mt('Student credits not in use for courses in this domain').'</li>';
                     }                      }
                 } elsif ($item eq 'canclone') {  
                     if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') {  
                         if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {  
                             my $clonecodes = join(' '.&mt('and').' ',@{$defaultshash{'coursedefaults'}{'canclone'}{'instcode'}});  
                             $resulttext .= '<li>'.&mt('By default, official courses can be cloned from existing courses with the same: [_1]','<b>'.$clonecodes.'</b>').'</li>';  
                         }  
                     } elsif ($defaultshash{'coursedefaults'}{'canclone'} eq 'domain') {  
                         $resulttext .= '<li>'.&mt('By default, a course requester can clone any course from his/her domain.').'</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('By default, only course owner and coordinators may clone a course.').'</li>';  
                     }  
                 } elsif ($item eq 'ltiauth') {  
                     if ($env{'form.'.$item} eq '1') {  
                         $resulttext .= '<li>'.&mt('LTI launch of deep-linked URL need not require re-authentication').'</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('LTI launch of deep-linked URL will require re-authentication').'</li>';  
                     }  
                 } elsif ($item eq 'domexttool') {  
                     my @noyes = (&mt('no'),&mt('yes'));  
                     if (ref($defaultshash{'coursedefaults'}{'domexttool'}) eq 'HASH') {  
                         $resulttext .= '<li>'.&mt('External Tools defined in the domain may be used as follows:').'<ul>'.  
                                        '<li>'.&mt('Official courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'official'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Unofficial courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'unofficial'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Textbook courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'textbook'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Placement tests: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'placement'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Communities: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'community'}].'</b>').'</li>'.  
                                        '</ul>'.  
                                        '</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('External Tools defined in the domain may be used in all course types, by default').'</li>';  
                     }  
                 } elsif ($item eq 'exttool') {  
                     my @noyes = (&mt('no'),&mt('yes'));  
                     if (ref($defaultshash{'coursedefaults'}{'exttool'}) eq 'HASH') {  
                         $resulttext .= '<li>'.&mt('External Tools can be defined and configured in course containers as follows:').'<ul>'.  
                                        '<li>'.&mt('Official courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'official'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Unofficial courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'unofficial'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Textbook courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'textbook'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Placement tests: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'placement'}].'</b>').'</li>'.  
                                        '<li>'.&mt('Communities: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'community'}].'</b>').'</li>'.  
                                        '</ul>'.  
                                        '</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('External Tools can not be defined in any course types, by default').'</li>';  
                     }  
                 }                  }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
Line 19071  sub modify_selfenrollment { Line 10748  sub modify_selfenrollment {
                         $resulttext .= '</ul></li>';                           $resulttext .= '</ul></li>'; 
                     }                      }
                 }                  }
             }                  if ((exists($changes{'admin'})) || (exists($changes{'default'}))) {
             if ((exists($changes{'admin'})) || (exists($changes{'default'}))) {                      my $cachetime = 24*60*60;
                 my $cachetime = 24*60*60;                      &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
                 &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);                      if (ref($lastactref) eq 'HASH') {
                 if (ref($lastactref) eq 'HASH') {                          $lastactref->{'domdefaults'} = 1;
                     $lastactref->{'domdefaults'} = 1;                      }
                 }                  }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
Line 19090  sub modify_selfenrollment { Line 10767  sub modify_selfenrollment {
     return $resulttext;      return $resulttext;
 }  }
   
 sub modify_wafproxy {  
     my ($dom,$action,$lastactref,%domconfig) = @_;  
     my %servers = &Apache::lonnet::internet_dom_servers($dom);  
     my (%othercontrol,%canset,%values,%curralias,%currsaml,%currvalue,@warnings,  
         %wafproxy,%changes,%expirecache,%expiresaml);  
     foreach my $server (sort(keys(%servers))) {  
         my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});  
         if ($serverhome eq $server) {  
             my $serverdom = &Apache::lonnet::host_domain($server);  
             if ($serverdom eq $dom) {  
                 $canset{$server} = 1;  
             }  
         }  
     }  
     if (ref($domconfig{'wafproxy'}) eq 'HASH') {  
         %{$values{$dom}} = ();  
         if (ref($domconfig{'wafproxy'}{'alias'}) eq 'HASH') {  
             %curralias = %{$domconfig{'wafproxy'}{'alias'}};  
         }  
         if (ref($domconfig{'wafproxy'}{'saml'}) eq 'HASH') {  
             %currsaml = %{$domconfig{'wafproxy'}{'saml'}};  
         }  
         foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext','sslopt') {  
             $currvalue{$item} = $domconfig{'wafproxy'}{$item};  
         }  
     }  
     my $output;  
     if (keys(%canset)) {  
         %{$wafproxy{'alias'}} = ();  
         %{$wafproxy{'saml'}} = ();  
         foreach my $key (sort(keys(%canset))) {  
             if ($env{'form.wafproxy_'.$dom}) {  
                 $wafproxy{'alias'}{$key} = $env{'form.wafproxy_alias_'.$key};  
                 $wafproxy{'alias'}{$key} =~ s/^\s+|\s+$//g;  
                 if ($wafproxy{'alias'}{$key} ne $curralias{$key}) {  
                     $changes{'alias'} = 1;  
                 }  
                 if ($env{'form.wafproxy_alias_saml_'.$key}) {  
                     $wafproxy{'saml'}{$key} = 1;  
                 }  
                 if ($wafproxy{'saml'}{$key} ne $currsaml{$key}) {  
                     $changes{'saml'} = 1;  
                 }  
             } else {  
                 $wafproxy{'alias'}{$key} = '';  
                 $wafproxy{'saml'}{$key} = '';  
                 if ($curralias{$key}) {  
                     $changes{'alias'} = 1;  
                 }  
                 if ($currsaml{$key}) {  
                     $changes{'saml'} = 1;  
                 }  
             }  
             if ($wafproxy{'alias'}{$key} eq '') {  
                 if ($curralias{$key}) {  
                     $expirecache{$key} = 1;  
                 }  
                 delete($wafproxy{'alias'}{$key});  
             }  
             if ($wafproxy{'saml'}{$key} eq '') {  
                 if ($currsaml{$key}) {  
                     $expiresaml{$key} = 1;  
                 }  
                 delete($wafproxy{'saml'}{$key});  
             }  
         }  
         unless (keys(%{$wafproxy{'alias'}})) {  
             delete($wafproxy{'alias'});  
         }  
         unless (keys(%{$wafproxy{'saml'}})) {  
             delete($wafproxy{'saml'});  
         }  
         # Localization for values in %warn occurs in &mt() calls separately.  
         my %warn = (  
                      trusted => 'trusted IP range(s)',  
                      vpnint => 'internal IP range(s) for VPN sessions(s)',  
                      vpnext => 'IP range(s) for backend WAF connections',  
                    );  
         foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext','sslopt') {  
             my $possible = $env{'form.wafproxy_'.$item};  
             $possible =~ s/^\s+|\s+$//g;  
             if ($possible ne '') {  
                 if ($item eq 'remoteip') {  
                     if ($possible =~ /^[mhn]$/) {  
                         $wafproxy{$item} = $possible;  
                     }  
                 } elsif ($item eq 'ipheader') {  
                     if ($wafproxy{'remoteip'} eq 'h') {  
                         $wafproxy{$item} = $possible;  
                     }  
                 } elsif ($item eq 'sslopt') {  
                     if ($possible =~ /^0|1$/) {  
                         $wafproxy{$item} = $possible;  
                     }  
                 } else {  
                     my (@ok,$count);  
                     if (($item eq 'vpnint') || ($item eq 'vpnext')) {  
                         unless ($env{'form.wafproxy_vpnaccess'}) {  
                             $possible = '';  
                         }  
                     } elsif ($item eq 'trusted') {  
                         unless ($wafproxy{'remoteip'} eq 'h') {  
                             $possible = '';  
                         }  
                     }  
                     unless ($possible eq '') {  
                         $possible =~ s/[\r\n]+/\s/g;  
                         $possible =~ s/\s*-\s*/-/g;  
                         $possible =~ s/\s+/,/g;  
                         $possible =~ s/,+/,/g;  
                     }  
                     $count = 0;  
                     if ($possible ne '') {  
                         foreach my $poss (split(/\,/,$possible)) {  
                             $count ++;  
                             $poss = &validate_ip_pattern($poss);  
                             if ($poss ne '') {  
                                 push(@ok,$poss);  
                             }  
                         }  
                         my $diff = $count - scalar(@ok);  
                         if ($diff) {  
                             push(@warnings,'<li>'.  
                                  &mt('[quant,_1,IP] invalid and excluded from saved value for [_2]',  
                                      $diff,$warn{$item}).  
                                  '</li>');  
                         }  
                         if (@ok) {  
                             my @cidr_list;  
                             foreach my $item (@ok) {  
                                 @cidr_list = &Net::CIDR::cidradd($item,@cidr_list);  
                             }  
                             $wafproxy{$item} = join(',',@cidr_list);  
                         }  
                     }  
                 }  
                 if ($wafproxy{$item} ne $currvalue{$item}) {  
                     $changes{$item} = 1;  
                 }  
             } elsif ($currvalue{$item}) {  
                 $changes{$item} = 1;  
             }  
         }  
     } else {  
         if (keys(%curralias)) {  
             $changes{'alias'} = 1;  
         }  
         if (keys(%currsaml)) {  
             $changes{'saml'} = 1;  
         }  
         if (keys(%currvalue)) {  
             foreach my $key (keys(%currvalue)) {  
                 $changes{$key} = 1;  
             }  
         }  
     }  
     if (keys(%changes)) {  
         my %defaultshash = (  
                               wafproxy => \%wafproxy,  
                            );  
         my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,  
                                                  $dom);  
         if ($putresult eq 'ok') {  
             my $cachetime = 24*60*60;  
             my (%domdefaults,$updatedomdefs);  
             foreach my $item ('ipheader','trusted','vpnint','vpnext','sslopt') {  
                 if ($changes{$item}) {  
                     unless ($updatedomdefs) {  
                         %domdefaults = &Apache::lonnet::get_domain_defaults($dom);  
                         $updatedomdefs = 1;  
                     }  
                     if ($wafproxy{$item}) {  
                         $domdefaults{'waf_'.$item} = $wafproxy{$item};  
                     } elsif (exists($domdefaults{'waf_'.$item})) {  
                         delete($domdefaults{'waf_'.$item});  
                     }  
                 }  
             }  
             if ($updatedomdefs) {  
                 &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);  
                 if (ref($lastactref) eq 'HASH') {  
                     $lastactref->{'domdefaults'} = 1;  
                 }  
             }  
             if ((exists($wafproxy{'alias'})) || (keys(%expirecache))) {  
                 my %updates = %expirecache;  
                 foreach my $key (keys(%expirecache)) {  
                     &Apache::lonnet::devalidate_cache_new('proxyalias',$key);  
                 }  
                 if (ref($wafproxy{'alias'}) eq 'HASH') {  
                     my $cachetime = 24*60*60;  
                     foreach my $key (keys(%{$wafproxy{'alias'}})) {  
                         $updates{$key} = 1;  
                         &Apache::lonnet::do_cache_new('proxyalias',$key,$wafproxy{'alias'}{$key},  
                                                       $cachetime);  
                     }  
                 }  
                 if (ref($lastactref) eq 'HASH') {  
                     $lastactref->{'proxyalias'} = \%updates;  
                 }  
             }  
             if ((exists($wafproxy{'saml'})) || (keys(%expiresaml))) {  
                 my %samlupdates = %expiresaml;  
                 foreach my $key (keys(%expiresaml)) {  
                     &Apache::lonnet::devalidate_cache_new('proxysaml',$key);  
                 }  
                 if (ref($wafproxy{'saml'}) eq 'HASH') {  
                     my $cachetime = 24*60*60;  
                     foreach my $key (keys(%{$wafproxy{'saml'}})) {  
                         $samlupdates{$key} = 1;  
                         &Apache::lonnet::do_cache_new('proxysaml',$key,$wafproxy{'saml'}{$key},  
                                                       $cachetime);  
                     }  
                 }  
                 if (ref($lastactref) eq 'HASH') {  
                     $lastactref->{'proxysaml'} = \%samlupdates;  
                 }  
             }  
             $output = &mt('Changes were made to Web Application Firewall/Reverse Proxy').'<ul>';  
             foreach my $item ('alias','saml','remoteip','ipheader','trusted','vpnint','vpnext','sslopt') {  
                 if ($changes{$item}) {  
                     if ($item eq 'alias') {  
                         my $numaliased = 0;  
                         if (ref($wafproxy{'alias'}) eq 'HASH') {  
                             my $shown;  
                             if (keys(%{$wafproxy{'alias'}})) {  
                                 foreach my $server (sort(keys(%{$wafproxy{'alias'}}))) {  
                                     $shown .= '<li>'.&mt('[_1] aliased by [_2]',  
                                                          &Apache::lonnet::hostname($server),  
                                                          $wafproxy{'alias'}{$server}).'</li>';  
                                     $numaliased ++;  
                                 }  
                                 if ($numaliased) {  
                                     $output .= '<li>'.&mt('Aliases for hostnames set to: [_1]',  
                                                           '<ul>'.$shown.'</ul>').'</li>';  
                                 }  
                             }  
                         }  
                         unless ($numaliased) {  
                             $output .= '<li>'.&mt('Aliases deleted for hostnames').'</li>';  
                         }  
                     } elsif ($item eq 'saml') {  
                         my $shown;  
                         if (ref($wafproxy{'saml'}) eq 'HASH') {  
                             if (keys(%{$wafproxy{'saml'}})) {  
                                 $shown = join(', ',sort(keys(%{$wafproxy{'saml'}})));  
                             }  
                         }  
                         if ($shown) {  
                             $output .= '<li>'.&mt('Alias used by SSO Auth for: [_1]',  
                                                   $shown).'</li>';  
                         } else {  
                             $output .= '<li>'.&mt('No alias used for SSO Auth').'</li>';  
                         }  
                     } else {  
                         if ($item eq 'remoteip') {  
                             my %ip_methods = &remoteip_methods();  
                             if ($wafproxy{$item} =~ /^[mh]$/) {  
                                 $output .= '<li>'.&mt("Method for determining user's IP set to: [_1]",  
                                                       $ip_methods{$wafproxy{$item}}).'</li>';  
                             } else {  
                                 if (($env{'form.wafproxy_'.$dom}) && (ref($wafproxy{'alias'}) eq 'HASH')) {  
                                     $output .= '<li>'.&mt("No method in use to get user's real IP (will report IP used by WAF).").  
                                                '</li>';  
                                 } else {  
                                     $output .= '<li>'.&mt('WAF/Reverse Proxy not in use').'</li>';  
                                 }  
                             }  
                         } elsif ($item eq 'ipheader') {  
                             if ($wafproxy{$item}) {  
                                 $output .= '<li>'.&mt('Request header with remote IP set to: [_1]',  
                                                       $wafproxy{$item}).'</li>';  
                             } else {  
                                 $output .= '<li>'.&mt('Request header with remote IP deleted').'</li>';  
                             }  
                         } elsif ($item eq 'trusted') {  
                             if ($wafproxy{$item}) {  
                                 $output .= '<li>'.&mt('Trusted IP range(s) set to: [_1]',  
                                                       $wafproxy{$item}).'</li>';  
                             } else {  
                                 $output .= '<li>'.&mt('Trusted IP range(s) deleted').'</li>';  
                             }  
                         } elsif ($item eq 'vpnint') {  
                             if ($wafproxy{$item}) {  
                                 $output .= '<li>'.&mt('Internal IP Range(s) for VPN sessions set to: [_1]',  
                                                        $wafproxy{$item}).'</li>';  
                             } else {  
                                 $output .= '<li>'.&mt('Internal IP Range(s) for VPN sessions deleted').'</li>';  
                             }  
                         } elsif ($item eq 'vpnext') {  
                             if ($wafproxy{$item}) {  
                                 $output .= '<li>'.&mt('IP Range(s) for backend WAF connections set to: [_1]',  
                                                        $wafproxy{$item}).'</li>';  
                             } else {  
                                 $output .= '<li>'.&mt('IP Range(s) for backend WAF connections deleted').'</li>';  
                             }  
                         } elsif ($item eq 'sslopt') {  
                             if ($wafproxy{$item}) {  
                                 $output .= '<li>'.&mt('WAF/Reverse Proxy expected to forward requests to https on LON-CAPA node, regardless of original protocol in web browser (http or https).').'</li>';  
                             } else {  
                                 $output .= '<li>'.&mt('WAF/Reverse Proxy expected to preserve original protocol in web browser (either http or https) when forwarding to LON-CAPA node.').'</li>';  
                             }  
                         }  
                     }  
                 }  
             }  
             $output .= '</ul>';  
         } else {  
             $output = '<span class="LC_error">'.  
                       &mt('An error occurred: [_1]',$putresult).'</span>';  
         }  
     } elsif (keys(%canset)) {  
         $output = &mt('No changes made to Web Application Firewall/Reverse Proxy settings');  
     }  
     if (@warnings) {  
         $output .= '<br />'.&mt('Warnings:').'<ul>'.  
                        join("\n",@warnings).'</ul>';  
     }  
     return $output;  
 }  
   
 sub validate_ip_pattern {  
     my ($pattern) = @_;  
     if ($pattern =~ /^([^-]+)\-([^-]+)$/) {  
         my ($start,$end) = ($1,$2);  
         if ((&Net::CIDR::cidrvalidate($start)) && (&Net::CIDR::cidrvalidate($end))) {  
             if (($start !~ m{/}) && ($end !~ m{/})) {  
                 return $start.'-'.$end;  
             }  
         }  
     } elsif ($pattern ne '') {  
         $pattern = &Net::CIDR::cidrvalidate($pattern);  
         if ($pattern ne '') {  
             return $pattern;  
         }  
     }  
     return;  
 }  
   
 sub modify_usersessions {  sub modify_usersessions {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my @hostingtypes = ('version','excludedomain','includedomain');      my @hostingtypes = ('version','excludedomain','includedomain');
Line 19595  sub modify_usersessions { Line 10933  sub modify_usersessions {
             $changes{'spares'}{$lonhost} = \%spareschg;              $changes{'spares'}{$lonhost} = \%spareschg;
         }          }
     }      }
     $defaultshash{'usersessions'}{'offloadnow'} = {};  
     $defaultshash{'usersessions'}{'offloadoth'} = {};  
     my @offloadnow = &Apache::loncommon::get_env_multiple('form.offloadnow');  
     my @okoffload;  
     if (@offloadnow) {  
         foreach my $server (@offloadnow) {  
             if (&Apache::lonnet::hostname($server) ne '') {  
                 unless (grep(/^\Q$server\E$/,@okoffload)) {  
                     push(@okoffload,$server);  
                 }  
             }  
         }  
         if (@okoffload) {  
             foreach my $lonhost (@okoffload) {  
                 $defaultshash{'usersessions'}{'offloadnow'}{$lonhost} = 1;  
             }  
         }  
     }  
     my @offloadoth = &Apache::loncommon::get_env_multiple('form.offloadoth');  
     my @okoffloadoth;  
     if (@offloadoth) {  
         foreach my $server (@offloadoth) {  
             if (&Apache::lonnet::hostname($server) ne '') {  
                 unless (grep(/^\Q$server\E$/,@okoffloadoth)) {  
                     push(@okoffloadoth,$server);  
                 }  
             }  
         }  
         if (@okoffloadoth) {  
             foreach my $lonhost (@okoffloadoth) {  
                 $defaultshash{'usersessions'}{'offloadoth'}{$lonhost} = 1;  
             }  
         }  
     }  
     if (ref($domconfig{'usersessions'}) eq 'HASH') {      if (ref($domconfig{'usersessions'}) eq 'HASH') {
         if (ref($domconfig{'usersessions'}{'spares'}) eq 'HASH') {          if (ref($domconfig{'usersessions'}{'spares'}) eq 'HASH') {
             if (ref($changes{'spares'}) eq 'HASH') {              if (ref($changes{'spares'}) eq 'HASH') {
Line 19639  sub modify_usersessions { Line 10944  sub modify_usersessions {
         } else {          } else {
             $savespares = 1;              $savespares = 1;
         }          }
         foreach my $offload ('offloadnow','offloadoth') {  
             if (ref($domconfig{'usersessions'}{$offload}) eq 'HASH') {  
                 foreach my $lonhost (keys(%{$domconfig{'usersessions'}{$offload}})) {  
                     unless ($defaultshash{'usersessions'}{$offload}{$lonhost}) {  
                         $changes{$offload} = 1;  
                         last;  
                     }  
                 }  
                 unless ($changes{$offload}) {  
                     foreach my $lonhost (keys(%{$defaultshash{'usersessions'}{$offload}})) {  
                         unless ($domconfig{'usersessions'}{$offload}{$lonhost}) {  
                             $changes{$offload} = 1;  
                             last;  
                         }  
                     }  
                 }  
             } else {  
                 if (($offload eq 'offloadnow') && (@okoffload)) {  
                      $changes{'offloadnow'} = 1;  
                 }  
                 if (($offload eq 'offloadoth') && (@okoffloadoth)) {  
                     $changes{'offloadoth'} = 1;  
                 }  
             }  
         }  
     } else {  
         if (@okoffload) {  
             $changes{'offloadnow'} = 1;  
         }  
         if (@okoffloadoth) {  
             $changes{'offloadoth'} = 1;  
         }  
     }      }
   
     my $nochgmsg = &mt('No changes made to settings for user session hosting/offloading.');      my $nochgmsg = &mt('No changes made to settings for user session hosting/offloading.');
     if ((keys(%changes) > 0) || ($savespares)) {      if ((keys(%changes) > 0) || ($savespares)) {
         my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,          my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
Line 19684  sub modify_usersessions { Line 10958  sub modify_usersessions {
                 if (ref($defaultshash{'usersessions'}{'hosted'}) eq 'HASH') {                  if (ref($defaultshash{'usersessions'}{'hosted'}) eq 'HASH') {
                     $domdefaults{'hostedsessions'} = $defaultshash{'usersessions'}{'hosted'};                      $domdefaults{'hostedsessions'} = $defaultshash{'usersessions'}{'hosted'};
                 }                  }
                 if (ref($defaultshash{'usersessions'}{'offloadnow'}) eq 'HASH') {  
                     $domdefaults{'offloadnow'} = $defaultshash{'usersessions'}{'offloadnow'};  
                 }  
                 if (ref($defaultshash{'usersessions'}{'offloadoth'}) eq 'HASH') {  
                     $domdefaults{'offloadoth'} = $defaultshash{'usersessions'}{'offloadoth'};  
                 }  
             }              }
             my $cachetime = 24*60*60;              my $cachetime = 24*60*60;
             &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);              &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
             &Apache::lonnet::do_cache_new('usersessions',$dom,$defaultshash{'usersessions'},3600);  
             if (ref($lastactref) eq 'HASH') {              if (ref($lastactref) eq 'HASH') {
                 $lastactref->{'domdefaults'} = 1;                  $lastactref->{'domdefaults'} = 1;
                 $lastactref->{'usersessions'} = 1;  
             }              }
             if (keys(%changes) > 0) {              if (keys(%changes) > 0) {
                 my %lt = &usersession_titles();                  my %lt = &usersession_titles();
Line 19750  sub modify_usersessions { Line 11016  sub modify_usersessions {
                                         }                                          }
                                     } else {                                      } else {
                                         if ($type eq 'version') {                                          if ($type eq 'version') {
                                             $newvalue .= ' '.&mt('(or later)');                                              $newvalue .= ' '.&mt('(or later)'); 
                                         }                                          }
                                         $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>';                                          $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>';
                                     }                                      }
Line 19760  sub modify_usersessions { Line 11026  sub modify_usersessions {
                         $resulttext .= '</ul>';                          $resulttext .= '</ul>';
                     }                      }
                 }                  }
                 if ($changes{'offloadnow'}) {  
                     if (ref($defaultshash{'usersessions'}{'offloadnow'}) eq 'HASH') {  
                         if (keys(%{$defaultshash{'usersessions'}{'offloadnow'}}) > 0) {  
                             $resulttext .= '<li>'.&mt('Switch any active user on next access, for server(s):').'<ul>';  
                             foreach my $lonhost (sort(keys(%{$defaultshash{'usersessions'}{'offloadnow'}}))) {  
                                 $resulttext .= '<li>'.$lonhost.'</li>';  
                             }  
                             $resulttext .= '</ul>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('No servers now set to switch any active user on next access.');  
                         }  
                     } else {  
                         $resulttext .= '<li>'.&mt('No servers now set to switch any active user on next access.').'</li>';  
                     }  
                 }  
                 if ($changes{'offloadoth'}) {  
                     if (ref($defaultshash{'usersessions'}{'offloadoth'}) eq 'HASH') {  
                         if (keys(%{$defaultshash{'usersessions'}{'offloadoth'}}) > 0) {  
                             $resulttext .= '<li>'.&mt('Switch other institutions on next access, for server(s):').'<ul>';  
                             foreach my $lonhost (sort(keys(%{$defaultshash{'usersessions'}{'offloadoth'}}))) {  
                                 $resulttext .= '<li>'.$lonhost.'</li>';  
                             }  
                             $resulttext .= '</ul>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('No servers now set to switch other institutions on next access.');  
                         }  
                     } else {  
                         $resulttext .= '<li>'.&mt('No servers now set to switch other institutions on next access.').'</li>';  
                     }  
                 }  
                 $resulttext .= '</ul>';                  $resulttext .= '</ul>';
             } else {              } else {
                 $resulttext = $nochgmsg;                  $resulttext = $nochgmsg;
Line 19815  sub modify_loadbalancing { Line 11051  sub modify_loadbalancing {
     my @sparestypes = ('primary','default');      my @sparestypes = ('primary','default');
     my %typetitles = &sparestype_titles();      my %typetitles = &sparestype_titles();
     my $resulttext;      my $resulttext;
     my (%currbalancer,%currtargets,%currrules,%existing,%currcookies);      my (%currbalancer,%currtargets,%currrules,%existing);
     if (ref($domconfig{'loadbalancing'}) eq 'HASH') {      if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
         %existing = %{$domconfig{'loadbalancing'}};          %existing = %{$domconfig{'loadbalancing'}};
     }      }
     &get_loadbalancers_config(\%servers,\%existing,\%currbalancer,      &get_loadbalancers_config(\%servers,\%existing,\%currbalancer,
                               \%currtargets,\%currrules,\%currcookies);                                \%currtargets,\%currrules);
     my ($saveloadbalancing,%defaultshash,%changes);      my ($saveloadbalancing,%defaultshash,%changes);
     my ($alltypes,$othertypes,$titles) =      my ($alltypes,$othertypes,$titles) =
         &loadbalancing_titles($dom,$intdom,$usertypes,$types);          &loadbalancing_titles($dom,$intdom,$usertypes,$types);
Line 19864  sub modify_loadbalancing { Line 11100  sub modify_loadbalancing {
                         push(@offloadto,$target);                          push(@offloadto,$target);
                     }                      }
                 }                  }
             }                  $defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype} = \@offloadto;
             if ($env{'form.loadbalancing_target_'.$i.'_hosthere'} eq $sparetype) {  
                 unless(grep(/^\Q$balancer\E$/,@offloadto)) {  
                     push(@offloadto,$balancer);  
                 }  
             }  
             $defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype} = \@offloadto;  
         }  
         if ($env{'form.loadbalancing_cookie_'.$i}) {  
             $defaultshash{'loadbalancing'}{$balancer}{'cookie'} = 1;  
             if (exists($currbalancer{$balancer})) {  
                 unless ($currcookies{$balancer}) {  
                     $changes{'curr'}{$balancer}{'cookie'} = 1;  
                 }  
             }  
         } elsif (exists($currbalancer{$balancer})) {  
             if ($currcookies{$balancer}) {  
                 $changes{'curr'}{$balancer}{'cookie'} = 1;  
             }              }
         }          }
         if (ref($currtargets{$balancer}) eq 'HASH') {          if (ref($currtargets{$balancer}) eq 'HASH') {
Line 19921  sub modify_loadbalancing { Line 11140  sub modify_loadbalancing {
                 }                  }
                 if ($rule eq 'specific') {                  if ($rule eq 'specific') {
                     my $specifiedhost = $env{'form.loadbalancing_singleserver_'.$i.'_'.$type};                      my $specifiedhost = $env{'form.loadbalancing_singleserver_'.$i.'_'.$type};
                     if (exists($servers{$specifiedhost})) {                      if (exists($servers{$specifiedhost})) { 
                         $rule = $specifiedhost;                          $rule = $specifiedhost;
                     }                      }
                 }                  }
Line 19997  sub modify_loadbalancing { Line 11216  sub modify_loadbalancing {
                                         if ($rule eq '') {                                          if ($rule eq '') {
                                             $balancetext =  $ruletitles{'default'};                                              $balancetext =  $ruletitles{'default'};
                                         } elsif (($rule eq 'homeserver') || ($rule eq 'externalbalancer') ||                                          } elsif (($rule eq 'homeserver') || ($rule eq 'externalbalancer') ||
                                                  ($type eq '_LC_ipchange') || ($type eq '_LC_ipchangesso')) {                                                   ($type eq '_LC_ipchange') || ($type eq '_LC_ipchangesso')) { 
                                             if (($type eq '_LC_ipchange') || ($type eq '_LC_ipchangesso')) {                                              if (($type eq '_LC_ipchange') || ($type eq '_LC_ipchangesso')) {
                                                 foreach my $sparetype (@sparestypes) {                                                  foreach my $sparetype (@sparestypes) {
                                                     if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') {                                                      if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') {
Line 20037  sub modify_loadbalancing { Line 11256  sub modify_loadbalancing {
                                 }                                  }
                             }                              }
                         }                          }
                         if ($changes{'curr'}{$balancer}{'cookie'}) {                          if (keys(%toupdate)) {
                             if ($currcookies{$balancer}) {                              my %thismachine;
                                 $resulttext .= '<li>'.&mt('Load Balancer: [_1] -- cookie use disabled',                              my $updatedhere;
                                                           $balancer).'</li>';                              my $cachetime = 60*60*24;
                             } else {                              map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();
                                 $resulttext .= '<li>'.&mt('Load Balancer: [_1] -- cookie use enabled',                              foreach my $lonhost (keys(%toupdate)) {
                                                           $balancer).'</li>';                                  if ($thismachine{$lonhost}) {
                             }                                      unless ($updatedhere) {
                         }                                          &Apache::lonnet::do_cache_new('loadbalancing',$dom,
                     }                                                                        $defaultshash{'loadbalancing'},
                 }                                                                        $cachetime);
                 if (keys(%toupdate)) {                                          $updatedhere = 1;
                     my %thismachine;                                      }
                     my $updatedhere;                                  } else {
                     my $cachetime = 60*60*24;                                      my $cachekey = &escape('loadbalancing').':'.&escape($dom);
                     map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();                                      &Apache::lonnet::remote_devalidate_cache($lonhost,[$cachekey]);
                     foreach my $lonhost (keys(%toupdate)) {                                  }
                         if ($thismachine{$lonhost}) {  
                             unless ($updatedhere) {  
                                 &Apache::lonnet::do_cache_new('loadbalancing',$dom,  
                                                               $defaultshash{'loadbalancing'},  
                                                               $cachetime);  
                                 $updatedhere = 1;  
                             }                              }
                         } else {  
                             my $cachekey = &escape('loadbalancing').':'.&escape($dom);  
                             &Apache::lonnet::remote_devalidate_cache($lonhost,[$cachekey]);  
                         }                          }
                     }                      }
                 }                  }
Line 20125  sub recurse_cat_deletes { Line 11335  sub recurse_cat_deletes {
     return;      return;
 }  }
   
   sub get_active_dcs {
       my ($dom) = @_;
       my $now = time;
       my %dompersonnel = &Apache::lonnet::get_domain_roles($dom,['dc'],$now,$now);
       my %domcoords;
       my $numdcs = 0;
       foreach my $server (keys(%dompersonnel)) {
           foreach my $user (sort(keys(%{$dompersonnel{$server}}))) {
               my ($trole,$uname,$udom,$runame,$rudom,$rsec) = split(/:/,$user);
               $domcoords{$uname.':'.$udom} = $dompersonnel{$server}{$user};
           }
       }
       return %domcoords;
   }
   
 sub active_dc_picker {  sub active_dc_picker {
     my ($dom,$numinrow,$inputtype,$name,%currhash) = @_;      my ($dom,$numinrow,$inputtype,$name,%currhash) = @_;
     my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']);      my %domcoords = &get_active_dcs($dom);
     my @domcoord = keys(%domcoords);      my @domcoord = keys(%domcoords);
     if (keys(%currhash)) {      if (keys(%currhash)) {
         foreach my $dc (keys(%currhash)) {          foreach my $dc (keys(%currhash)) {
Line 20275  sub lonbalance_targets_js { Line 11500  sub lonbalance_targets_js {
     }      }
     push(@alltypes,'default','_LC_adv','_LC_author','_LC_internetdom','_LC_external');      push(@alltypes,'default','_LC_adv','_LC_author','_LC_internetdom','_LC_external');
     $allinsttypes = join("','",@alltypes);      $allinsttypes = join("','",@alltypes);
     my (%currbalancer,%currtargets,%currrules,%existing,%currcookies);      my (%currbalancer,%currtargets,%currrules,%existing);
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         %existing = %{$settings};          %existing = %{$settings};
     }      }
     &get_loadbalancers_config($servers,\%existing,\%currbalancer,      &get_loadbalancers_config($servers,\%existing,\%currbalancer,
                               \%currtargets,\%currrules,\%currcookies);                                \%currtargets,\%currrules);
     my $balancers = join("','",sort(keys(%currbalancer)));      my $balancers = join("','",sort(keys(%currbalancer)));
     return <<"END";      return <<"END";
   
Line 20633  function updateNewSpares(formname,lonhos Line 11858  function updateNewSpares(formname,lonhos
 function checkNewSpares(lonhost,type) {  function checkNewSpares(lonhost,type) {
     var newSpare = document.getElementById('newspare_'+type+'_'+lonhost);      var newSpare = document.getElementById('newspare_'+type+'_'+lonhost);
     var chosen =  newSpare.options[newSpare.selectedIndex].value;      var chosen =  newSpare.options[newSpare.selectedIndex].value;
     if (chosen != '') {      if (chosen != '') { 
         var othertype;          var othertype;
         var othernewSpare;          var othernewSpare;
         if (type == 'primary') {          if (type == 'primary') {
Line 20691  function updateCaptcha(caller,context) { Line 11916  function updateCaptcha(caller,context) {
     var pubitem;      var pubitem;
     var privtext;      var privtext;
     var pubtext;      var pubtext;
     var versionitem;  
     var versiontext;  
     if (document.getElementById(context+'_recaptchapub')) {      if (document.getElementById(context+'_recaptchapub')) {
         pubitem = document.getElementById(context+'_recaptchapub');          pubitem = document.getElementById(context+'_recaptchapub');
     } else {      } else {
Line 20713  function updateCaptcha(caller,context) { Line 11936  function updateCaptcha(caller,context) {
     } else {      } else {
         return;          return;
     }      }
     if (document.getElementById(context+'_recaptchaversion')) {  
         versionitem = document.getElementById(context+'_recaptchaversion');  
     } else {  
         return;  
     }  
     if (document.getElementById(context+'_recaptchavertxt')) {  
         versiontext = document.getElementById(context+'_recaptchavertxt');  
     } else {  
         return;  
     }  
     if (caller.checked) {      if (caller.checked) {
         if (caller.value == 'recaptcha') {          if (caller.value == 'recaptcha') {
             pubitem.type = 'text';              pubitem.type = 'text';
Line 20731  function updateCaptcha(caller,context) { Line 11944  function updateCaptcha(caller,context) {
             privitem.size = '40';              privitem.size = '40';
             pubtext.innerHTML = "$lt{'pub'}";              pubtext.innerHTML = "$lt{'pub'}";
             privtext.innerHTML = "$lt{'priv'}";              privtext.innerHTML = "$lt{'priv'}";
             versionitem.type = 'text';  
             versionitem.size = '3';  
             versiontext.innerHTML = "$lt{'ver'}";  
         } else {          } else {
             pubitem.type = 'hidden';              pubitem.type = 'hidden';
             privitem.type = 'hidden';              privitem.type = 'hidden';
             versionitem.type = 'hidden';  
             pubtext.innerHTML = '';              pubtext.innerHTML = '';
             privtext.innerHTML = '';              privtext.innerHTML = '';
             versiontext.innerHTML = '';  
         }          }
     }      }
     return;      return;
Line 20763  function toggleDisplay(domForm,caller) { Line 11971  function toggleDisplay(domForm,caller) {
     if (document.getElementById(caller)) {      if (document.getElementById(caller)) {
         var divitem = document.getElementById(caller);          var divitem = document.getElementById(caller);
         var optionsElement = domForm.coursecredits;          var optionsElement = domForm.coursecredits;
         var checkval = 1;  
         var dispval = 'block';  
         var selfcreateRegExp = /^cancreate_emailverified/;  
         if (caller == 'emailoptions') {          if (caller == 'emailoptions') {
             optionsElement = domForm.cancreate_email;              optionsElement = domForm.cancreate_email; 
         }          }
         if (caller == 'studentsubmission') {          if (caller == 'studentsubmission') {
             optionsElement = domForm.postsubmit;              optionsElement = domForm.postsubmit;
         }          }
         if (caller == 'cloneinstcode') {  
             optionsElement = domForm.canclone;  
             checkval = 'instcode';  
         }  
         if (selfcreateRegExp.test(caller)) {  
             optionsElement = domForm.elements[caller];  
             checkval = 'other';  
             dispval = 'inline'  
         }  
         if (optionsElement.length) {          if (optionsElement.length) {
             var currval;              var currval;
             for (var i=0; i<optionsElement.length; i++) {              for (var i=0; i<optionsElement.length; i++) {
Line 20788  function toggleDisplay(domForm,caller) { Line 11984  function toggleDisplay(domForm,caller) {
                    currval = optionsElement[i].value;                     currval = optionsElement[i].value;
                 }                  }
             }              }
             if (currval == checkval) {              if (currval == 1) {
                 divitem.style.display = dispval;                  divitem.style.display = 'block';
             } else {              } else {
                 divitem.style.display = 'none';                  divitem.style.display = 'none';
             }              }
Line 20812  sub captcha_phrases { Line 12008  sub captcha_phrases {
                  original  => 'original (CAPTCHA)',                   original  => 'original (CAPTCHA)',
                  recaptcha => 'successor (ReCAPTCHA)',                   recaptcha => 'successor (ReCAPTCHA)',
                  notused   => 'unused',                   notused   => 'unused',
                  ver => 'ReCAPTCHA version (1 or 2)',  
     );      );
 }  }
   
Line 20822  sub devalidate_remote_domconfs { Line 12017  sub devalidate_remote_domconfs {
     my %servers = &Apache::lonnet::internet_dom_servers($dom);      my %servers = &Apache::lonnet::internet_dom_servers($dom);
     my %thismachine;      my %thismachine;
     map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();      map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();
     my @posscached = ('domainconfig','domdefaults','ltitools','usersessions',      my @posscached = ('domainconfig','domdefaults');
                       'directorysrch','passwdconf','cats','proxyalias','proxysaml',      if (keys(%servers) > 1) {
                       'ipaccess');  
     my %cache_by_lonhost;  
     if (exists($cachekeys->{'samllanding'})) {  
         if (ref($cachekeys->{'samllanding'}) eq 'HASH') {  
             my %landing = %{$cachekeys->{'samllanding'}};  
             my %domservers = &Apache::lonnet::get_servers($dom);  
             if (keys(%domservers)) {  
                 foreach my $server (keys(%domservers)) {  
                     my @cached;  
                     next if ($thismachine{$server});  
                     if ($landing{$server}) {  
                         push(@cached,&escape('samllanding').':'.&escape($server));  
                     }  
                     if (@cached) {  
                         $cache_by_lonhost{$server} = \@cached;  
                     }  
                 }  
             }  
         }  
     }  
     if (keys(%servers)) {  
         foreach my $server (keys(%servers)) {          foreach my $server (keys(%servers)) {
             next if ($thismachine{$server});              next if ($thismachine{$server});
             my @cached;              my @cached;
             foreach my $name (@posscached) {              foreach my $name (@posscached) {
                 if ($cachekeys->{$name}) {                  if ($cachekeys->{$name}) {
                     if (($name eq 'proxyalias') || ($name eq 'proxysaml')) {                      push(@cached,&escape($name).':'.&escape($dom));
                         if (ref($cachekeys->{$name}) eq 'HASH') {  
                             foreach my $key (keys(%{$cachekeys->{$name}})) {  
                                 push(@cached,&escape($name).':'.&escape($key));  
                             }  
                         }  
                     } else {  
                         push(@cached,&escape($name).':'.&escape($dom));  
                     }  
                 }                  }
             }              }
             if ((exists($cache_by_lonhost{$server})) &&  
                 (ref($cache_by_lonhost{$server}) eq 'ARRAY')) {  
                 push(@cached,@{$cache_by_lonhost{$server}});  
             }  
             if (@cached) {              if (@cached) {
                 &Apache::lonnet::remote_devalidate_cache($server,\@cached);                  &Apache::lonnet::remote_devalidate_cache($server,\@cached);
             }              }

Removed from v.1.160.6.118.2.16  
changed lines
  Added in v.1.259


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>