Diff for /loncom/interface/domainprefs.pm between versions 1.160.6.118.2.27 and 1.318

version 1.160.6.118.2.27, 2025/03/15 01:32:13 version 1.318, 2017/11/30 01:52:14
Line 95  about default quota sizes for portfolio Line 95  about default quota sizes for portfolio
 institutional affiliation in the domain (e.g., Faculty, Staff, Student etc.),   institutional affiliation in the domain (e.g., Faculty, Staff, Student etc.), 
 but is now also used to manage availability of user tools:   but is now also used to manage availability of user tools: 
 i.e., blogs, aboutme page, and portfolios, and the course request tool,  i.e., blogs, aboutme page, and portfolios, and the course request tool,
 used by course owners to request creation of a course.  used by course owners to request creation of a course, and to display/store
   default quota sizes for Authoring Spaces.
   
 Outputs: 1  Outputs: 1
   
Line 103  $datatable  - HTML containing form eleme Line 104  $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, textbook, and placement).  
 In each case the radio buttons allow the selection of one of four values:  In each case the radio buttons 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 166  use Apache::lonmsg(); Line 167  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();
   use LONCAPA::SSL;
 use File::Copy;  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 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 219  sub handler {
                 'serverstatuses','requestcourses','helpsettings',                  'serverstatuses','requestcourses','helpsettings',
                 'coursedefaults','usersessions','loadbalancing',                  'coursedefaults','usersessions','loadbalancing',
                 'requestauthor','selfenrollment','inststatus',                  'requestauthor','selfenrollment','inststatus',
                 'passwords','ltitools','toolsec','lti','ltisec',                  'ltitools','ssl','trust'],$dom);
                 'wafproxy','ipaccess','authordefaults'],$dom);  
     my %encconfig =  
         &Apache::lonnet::get_dom('encconfig',['ltitools','lti','linkprot'],$dom,undef,1);  
     my ($checked_is_home,$is_home);  
     if (ref($domconfig{'ltitools'}) eq 'HASH') {      if (ref($domconfig{'ltitools'}) eq 'HASH') {
           my %encconfig =
               &Apache::lonnet::get_dom('encconfig',['ltitools'],$dom);
         if (ref($encconfig{'ltitools'}) eq 'HASH') {          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'}})) {              foreach my $id (keys(%{$domconfig{'ltitools'}})) {
                 if ((ref($domconfig{'ltitools'}{$id}) eq 'HASH') &&                  if (ref($domconfig{'ltitools'}{$id}) eq 'HASH') {
                     (ref($encconfig{'ltitools'}{$id}) eq 'HASH')) {                      foreach my $item ('key','secret') {
                     $domconfig{'ltitools'}{$id}{'key'} = $encconfig{'ltitools'}{$id}{'key'};                          $domconfig{'ltitools'}{$id}{$item} = $encconfig{'ltitools'}{$id}{$item};
                     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',      my @prefs_order = ('rolecolors','login','defaults','quotas','autoenroll',
                        'quotas','autoenroll','autoupdate','autocreate','directorysrch',                         'autoupdate','autocreate','directorysrch','contacts',
                        'contacts','usercreation','selfcreation','usermodification',                         'usercreation','selfcreation','usermodification','scantron',
                        'scantron','requestcourses','requestauthor','coursecategories',                         'requestcourses','requestauthor','coursecategories',
                        'serverstatuses','helpsettings','coursedefaults',                         'serverstatuses','helpsettings','coursedefaults',
                        'authordefaults','ltitools','selfenrollment','usersessions','lti');                         'ltitools','selfenrollment','usersessions','ssl','trust');
     my %existing;      my %existing;
     if (ref($domconfig{'loadbalancing'}) eq 'HASH') {      if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
         %existing = %{$domconfig{'loadbalancing'}};          %existing = %{$domconfig{'loadbalancing'}};
Line 322  sub handler { Line 269  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 334  sub handler { Line 278  sub handler {
                       help => 'Domain_Configuration_LangTZAuth',                        help => 'Domain_Configuration_LangTZAuth',
                       header => [{col1 => 'Setting',                        header => [{col1 => 'Setting',
                                   col2 => 'Value'},                                    col2 => 'Value'},
                                    {col1 => 'Internal Authentication',
                                     col2 => 'Value'},
                                  {col1 => 'Institutional user types',                                   {col1 => 'Institutional user types',
                                   col2 => 'Name displayed'},                                    col2 => 'Name displayed'}],
                                  {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, portfolio/quotas',                      { 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',
                                   col3 => 'Portfolio quota (MB)',}],                                    col3 => 'Quotas, MB; (Authoring requires role)',}],
                       print => \&print_quotas,                        print => \&print_quotas,
                       modify => \&modify_quotas,                        modify => \&modify_quotas,
                     },                      },
Line 420  sub handler { Line 339  sub handler {
                                 col2 => 'Value',},                                  col2 => 'Value',},
                                {col1 => 'Recipient(s) for notifications',                                 {col1 => 'Recipient(s) for notifications',
                                 col2 => 'Value',},                                  col2 => 'Value',},
                                {col1 => 'Nightly status check e-mail',  
                                 col2 => 'Settings',},  
                                {col1 => 'Ask helpdesk form settings',                                 {col1 => 'Ask helpdesk form settings',
                                 col2 => 'Value',},],                                  col2 => 'Value',},],
                     print => \&print_contacts,                      print => \&print_contacts,
Line 457  sub handler { Line 374  sub handler {
                     header => [{col1 => 'Target user has role',                      header => [{col1 => 'Target user has role',
                                 col2 => 'User information updatable in author context'},                                  col2 => 'User information updatable in author context'},
                                {col1 => 'Target user has role',                                 {col1 => 'Target user has role',
                                 col2 => 'User information updatable by co-author manager'},  
                                {col1 => 'Target user has role',  
                                 col2 => 'User information updatable in course context'}],                                  col2 => 'User information updatable in course context'}],
                     print => \&print_usermodification,                      print => \&print_usermodification,
                     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 554  sub handler { Line 468  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 577  sub handler { Line 499  sub handler {
                   print => \&print_loadbalancing,                    print => \&print_loadbalancing,
                   modify => \&modify_loadbalancing,                    modify => \&modify_loadbalancing,
                  },                   },
         'ltitools' =>          'ltitools' => 
                  {text => 'External Tools (LTI)',                   {text => 'External Tools (LTI)',
                   help => 'Domain_Configuration_LTI_Tools',                    help => 'Domain_Configuration_LTI_Tools',
                   header => [{col1 => 'Encryption of shared secrets',                    header => [{col1 => 'Setting',
                               col2 => 'Settings'},                                col2 => 'Value',}],
                              {col1 => 'Rules for shared secrets',  
                               col2 => 'Settings'},  
                              {col1 => 'Providers',  
                               col2 => 'Settings',}],  
                   print => \&print_ltitools,                    print => \&print_ltitools,
                   modify => \&modify_ltitools,                    modify => \&modify_ltitools,
                  },                   },
         'lti' =>          'ssl' =>
                  {text => 'LTI Link Protection and LTI Consumers',                   {text  => 'LON-CAPA Network (SSL)',
                   help => 'Domain_Configuration_LTI_Provider',                    help  => 'Domain_Configuration_Network_SSL',
                   header => [{col1 => 'Encryption of shared secrets',                    header => [{col1 => 'Server',
                               col2 => 'Settings'},                                col2 => 'Certificate Status'},
                              {col1 => 'Rules for shared secrets',                               {col1 => 'Connections to other servers',
                               col2 => 'Settings'},                                col2 => 'Rules'},
                              {col1 => 'Link Protectors in Courses',                               {col1 => 'Connections from other servers',
                               col2 => 'Values'},                                col2 => 'Rules'},
                              {col1 => 'Link Protectors',                               {col1 => "Replicating domain's published content",
                               col2 => 'Settings'},                                col2 => 'Rules'}],
                              {col1 => 'Consumers',                    print => \&print_ssl,
                               col2 => 'Settings'},],                    modify => \&modify_ssl,
                   print => \&print_lti,                   },
                   modify => \&modify_lti,          'trust' =>
                    {text   => 'Trust Settings',
                     help   => 'Domain_Configuration_Trust',
                     header => [{col1 => "Access to this domain's content by others",
                                 col2 => 'Rules'},
                                {col1 => "Access to other domain's content by this domain",
                                 col2 => 'Rules'},
                                {col1 => "Enrollment in this domain's courses by others",
                                 col2 => 'Rules',},
                                {col1 => "Co-author roles in this domain for others",
                                 col2 => 'Rules',},
                                {col1 => "Co-author roles for this domain's users elsewhere",
                                 col2 => 'Rules',},
                                {col1 => "Domain roles in this domain assignable to others",
                                 col2 => 'Rules'},
                                {col1 => "Course catalog for this domain displayed elsewhere",
                                 col2 => 'Rules'},
                                {col1 => "Requests for creation of courses in this domain by others",
                                 col2 => 'Rules'},
                                {col1 => "Users in other domains can send messages to this domain",
                                 col2 => 'Rules'},],
                     print => \&print_trust,
                     modify => \&modify_trust,
                  },                   },
         'ipaccess' =>  
                        {text => 'IP-based access control',  
                         help => 'Domain_Configuration_IP_Access',  
                         header => [{col1 => 'Setting',  
                                     col2 => 'Value'},],  
                         print  => \&print_ipaccess,  
                         modify => \&modify_ipaccess,  
                        },  
         'authordefaults' =>  
                             {text => 'Authoring Space defaults',  
                              help => 'Domain_Configuration_Author_Defaults',  
                              header => [{col1 => 'Defaults which can be overridden by Author',  
                                          col2 => 'Settings',},  
                                         {col1 => 'Defaults which can be overridden by a Dom. Coord.',  
                                          col2 => 'Settings',},],  
                              print => \&print_authordefaults,  
                              modify => \&modify_authordefaults,  
                             },  
     );      );
     if (keys(%servers) > 1) {      if (keys(%servers) > 1) {
         $prefs{'login'}  = { text   => 'Log-in page options',          $prefs{'login'}  = { text   => 'Log-in page options',
Line 630  sub handler { Line 552  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 678  $javascript_validations Line 597  $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)) {          if (grep(/^selfcreation$/,@actions)) {
             $js .= &selfcreate_javascript();              $js .= &selfcreate_javascript();
Line 687  END Line 604  END
         if (grep(/^contacts$/,@actions)) {          if (grep(/^contacts$/,@actions)) {
             $js .= &contacts_javascript();              $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 {
 # check if domconfig user exists for the domain.  # check if domconfig user exists for the domain.
Line 812  sub process_changes { Line 726  sub process_changes {
         $output = &modify_loadbalancing($dom,%domconfig);          $output = &modify_loadbalancing($dom,%domconfig);
     } elsif ($action eq 'ltitools') {      } elsif ($action eq 'ltitools') {
         $output = &modify_ltitools($r,$dom,$action,$lastactref,%domconfig);          $output = &modify_ltitools($r,$dom,$action,$lastactref,%domconfig);
     } elsif ($action eq 'lti') {      } elsif ($action eq 'ssl') {
         $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);          $output = &modify_ssl($dom,$lastactref,%domconfig);
     } elsif ($action eq 'passwords') {      } elsif ($action eq 'trust') {
         $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);          $output = &modify_trust($dom,$lastactref,%domconfig);
     } elsif ($action eq 'wafproxy') {  
         $output = &modify_wafproxy($dom,$action,$lastactref,%domconfig);  
     } elsif ($action eq 'ipaccess') {  
         $output = &modify_ipaccess($dom,$lastactref,%domconfig);  
     } elsif ($action eq 'authordefaults') {  
         $output = &modify_authordefaults($dom,$lastactref,%domconfig);  
     }      }
     return $output;      return $output;
 }  }
Line 834  sub print_config_box { Line 742  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') {      } elsif ($action eq 'helpsettings') {
         my (%privs,%levelscurrent);          my (%privs,%levelscurrent);
         my %full=();          my %full=();
Line 850  sub print_config_box { Line 756  sub print_config_box {
         &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);          &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);
         my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);          my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
         $output =          $output =
             &Apache::lonuserutils::custom_roledefs_js($context,$crstype,$formname,\%full,              &Apache::lonuserutils::custom_roledefs_js($context,$crstype,$formname,\%full, 
                                                       \@templateroles);                                                        \@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);  
     } elsif ($action eq 'authordefaults') {  
         $output .= &authordefaults_javascript();  
     }      }
     $output .=      $output .=
          '<table class="LC_nested_outer">           '<table class="LC_nested_outer">
Line 885  sub print_config_box { Line 774  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 'directorysrch') ||
             (($action eq 'login') && ($numheaders < 5))) {              (($action eq 'login') && ($numheaders < 4))) {
             $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 'ssl') ||
             ($action eq 'helpsettings') || ($action eq 'contacts') || ($action eq 'wafproxy') ||              ($action eq 'directorysrch') || ($action eq 'trust') || ($action eq 'helpsettings') ||
             ($action eq 'lti') || ($action eq 'ltitools') || ($action eq 'authordefaults')) {              ($action eq 'contacts')) {
             $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 944  sub print_config_box { Line 825  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 'trust') || ($action eq 'contacts') || ($action eq 'defaults')) {
             ($action eq 'defaults') || ($action eq 'lti') ||  
             ($action eq 'ltitools') || ($action eq 'usermodification')) {  
             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') {              } elsif ($action eq 'trust') {
                 $output .= $item->{'print'}->('middle',$dom,$confname,$settings,\$rowtotal);                  $output .= $item->{'print'}->('shared',$dom,$settings,\$rowtotal);
             } elsif ($action eq 'lti') {  
                 $output .= $item->{'print'}->('upper',$dom,$settings,\$rowtotal).'  
                            </table>  
                           </td>  
                          </tr>  
                          <tr>  
                           <td>  
                           <table class="LC_nested">  
                            <tr class="LC_info_row">  
                             <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>  
                             <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td>  
                            </tr>'."\n".  
                            $item->{'print'}->('middle',$dom,$settings,\$rowtotal);  
             } else {              } else {
                 $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);                  $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);
             }              }
             my $hdridx = 2;              if ($action eq 'trust') {
             if ($action eq 'lti') {                  $output .= '
                 $hdridx = 3;              </table>
             }            </td>
             $output .= '           </tr>';
                   my @trusthdrs = qw(2 3 4 5 6 7);
                   my @prefixes = qw(enroll othcoau coaurem domroles catalog reqcrs);
                   for (my $i=0; $i<@trusthdrs; $i++) {
                       $output .= '
            <tr>
              <td>
               <table class="LC_nested">
                <tr class="LC_info_row">
                 <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[$trusthdrs[$i]]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[$trusthdrs[$i]]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->($prefixes[$i],$dom,$settings,\$rowtotal).'
               </table>
             </td>
            </tr>';
                   }
                   $output .= '
            <tr>
              <td>
               <table class="LC_nested">
                <tr class="LC_info_row">
                 <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
               } else {
                   $output .= '
            </table>             </table>
           </td>            </td>
          </tr>           </tr>
Line 981  sub print_config_box { Line 872  sub print_config_box {
            <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"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
               <td class="LC_right_item">'.&mt($item->{'header'}->[$hdridx]->{'col2'}).'</td>                <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td>
              </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 {                  } else {
                     $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal);                      $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
                 }                  }
                 $hdridx ++;              }
                 $output .= '              $rowtotal ++;
              </tr>          } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||
                    ($action eq 'defaults') || ($action eq 'directorysrch') ||
                    ($action eq 'helpsettings')) {
               $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
           } elsif ($action eq 'ssl') {
               $output .= $item->{'print'}->('connto',$dom,$settings,\$rowtotal).'
             </table>              </table>
            </td>            </td>
           </tr>           </tr>
           <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'}->[$hdridx]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
               <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col2'}).'</td></tr>'."\n";                <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col2'}).'</td></tr>'.
                 if ($action eq 'passwords') {                             $item->{'print'}->('connfrom',$dom,$settings,\$rowtotal).'
                     $output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal);  
                 } else {  
                     $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);  
                 }  
                 $output .= '  
             </table>              </table>
           </td>            </td>
          </tr>           </tr>
          <tr>';           <tr>
             } else {             <td>
                 $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);              <table class="LC_nested">
             }               <tr class="LC_info_row">
             $rowtotal ++;                <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
         } elsif (($action eq 'coursedefaults') || ($action eq 'authordefaults') ||                <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'.
                  ($action eq 'directorysrch') || ($action eq 'helpsettings') ||                             $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
                  ($action eq 'wafproxy')) {  
             $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 1049  sub print_config_box { Line 933  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 1061  sub print_config_box { Line 945  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 1114  sub print_config_box { Line 978  sub print_config_box {
            <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"'.$colspan.' valign="top">'.&mt($item->{'header'}->[4]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.' style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col1'}).'</td>
               <td class="LC_right_item" valign="top">'.&mt($item->{'header'}->[4]->{'col2'}).'</td>                <td class="LC_right_item" style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col2'}).'</td>
              </tr>'.               </tr>'.
             &print_validation_rows('requestcourses',$dom,$settings,\$rowtotal);              &print_validation_rows('requestcourses',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'requestauthor') {          } elsif ($action eq 'requestauthor') {
Line 1130  sub print_config_box { Line 994  sub print_config_box {
            <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"'.$colspan.' valign="top">'.                <td class="LC_left_item"'.$colspan.' style="vertical-align: top">'.
                &mt($item->{'header'}->[2]->{'col1'}).'</td>                 &mt($item->{'header'}->[2]->{'col1'}).'</td>
               <td class="LC_right_item" valign="top">'.                <td class="LC_right_item" style="vertical-align: top">'.
                &mt($item->{'header'}->[2]->{'col2'}).'</td>                 &mt($item->{'header'}->[2]->{'col2'}).'</td>
              </tr>'.               </tr>'.
             &print_rolecolors($phase,'author',$dom,$confname,$settings,\$rowtotal).'              &print_rolecolors($phase,'author',$dom,$confname,$settings,\$rowtotal).'
Line 1160  sub print_config_box { Line 1024  sub print_config_box {
               <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') {
             $output .= '              $output .= '
               <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[0]->{'col1'}).                <td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}).
               '<br />('.&mt('Automatic access for Dom. Coords.').')</td>';                '<br />('.&mt('Automatic access for Dom. Coords.').')</td>';
   
         } else {          } else {
             $output .= '              $output .= '
               <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';                <td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';
         }          }
         if (defined($item->{'header'}->[0]->{'col3'})) {          if (defined($item->{'header'}->[0]->{'col3'})) {
             $output .= '<td class="LC_left_item" valign="top">'.              $output .= '<td class="LC_left_item" style="vertical-align: top">'.
                        &mt($item->{'header'}->[0]->{'col2'});                         &mt($item->{'header'}->[0]->{'col2'});
             if ($action eq 'serverstatuses') {              if ($action eq 'serverstatuses') {
                 $output .= '<br />(<tt>'.&mt('user1:domain1,user2:domain2 etc.').'</tt>)';                  $output .= '<br />(<tt>'.&mt('user1:domain1,user2:domain2 etc.').'</tt>)';
             }               } 
         } else {          } else {
             $output .= '<td class="LC_right_item" valign="top">'.              $output .= '<td class="LC_right_item" style="vertical-align: top">'.
                        &mt($item->{'header'}->[0]->{'col2'});                         &mt($item->{'header'}->[0]->{'col2'});
         }          }
         $output .= '</td>';          $output .= '</td>';
         if ($item->{'header'}->[0]->{'col3'}) {          if ($item->{'header'}->[0]->{'col3'}) {
             if (defined($item->{'header'}->[0]->{'col4'})) {              if (defined($item->{'header'}->[0]->{'col4'})) {
                 $output .= '<td class="LC_left_item" valign="top">'.                  $output .= '<td class="LC_left_item" style="vertical-align: top">'.
                             &mt($item->{'header'}->[0]->{'col3'});                              &mt($item->{'header'}->[0]->{'col3'});
             } else {              } else {
                 $output .= '<td class="LC_right_item" valign="top">'.                  $output .= '<td class="LC_right_item" style="vertical-align: top">'.
                            &mt($item->{'header'}->[0]->{'col3'});                             &mt($item->{'header'}->[0]->{'col3'});
             }              }
             if ($action eq 'serverstatuses') {              if ($action eq 'serverstatuses') {
Line 1192  sub print_config_box { Line 1056  sub print_config_box {
             $output .= '</td>';              $output .= '</td>';
         }          }
         if ($item->{'header'}->[0]->{'col4'}) {          if ($item->{'header'}->[0]->{'col4'}) {
             $output .= '<td class="LC_right_item" valign="top">'.              $output .= '<td class="LC_right_item" style="vertical-align: top">'.
                        &mt($item->{'header'}->[0]->{'col4'});                         &mt($item->{'header'}->[0]->{'col4'});
         }          }
         $output .= '</tr>';          $output .= '</tr>';
Line 1200  sub print_config_box { Line 1064  sub print_config_box {
         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 'serverstatuses') || ($action eq 'loadbalancing') ||                   ($action eq 'serverstatuses') || ($action eq 'loadbalancing') || 
                  ($action eq 'ipaccess')) {                   ($action eq 'ltitools')) {
             $output .= $item->{'print'}->($dom,$settings,\$rowtotal);              $output .= $item->{'print'}->($dom,$settings,\$rowtotal);
           } elsif ($action eq 'scantron') {
               $output .= &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal);
         }          }
     }      }
     $output .= '      $output .= '
Line 1215  sub print_config_box { Line 1081  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'};
         $css_class = ' class="LC_odd_row"';          $css_class = ' class="LC_odd_row"';
         $datatable .= '<tr'.$css_class.'><td>'.$choice.'</td>'.          $datatable .= '<tr'.$css_class.'><td>'.$choice.'</td>'.
                       '<td align="right"><table><tr><th>'.$choices{'hostid'}.'</th>'.                        '<td style="text-align: right"><table><tr><th>'.$choices{'hostid'}.'</th>'.
                       '<th>'.$choices{'server'}.'</th>'.                        '<th>'.$choices{'server'}.'</th>'.
                       '<th>'.$choices{'serverpath'}.'</th>'.                        '<th>'.$choices{'serverpath'}.'</th>'.
                       '<th>'.$choices{'custompath'}.'</th>'.                        '<th>'.$choices{'custompath'}.'</th>'.
Line 1307  sub print_login { Line 1170  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 1349  sub print_login { Line 1211  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 1422  sub print_login { Line 1277  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 1507  sub print_login { Line 1370  sub print_login {
         my $choice = $choices{'headtag'};          my $choice = $choices{'headtag'};
         $css_class = ' class="LC_odd_row"';          $css_class = ' class="LC_odd_row"';
         $datatable .= '<tr'.$css_class.'><td colspan="2">'.$choice.'</td>'.          $datatable .= '<tr'.$css_class.'><td colspan="2">'.$choice.'</td>'.
                       '<td align="left"><table><tr><th>'.$choices{'hostid'}.'</th>'.                        '<td style="text-align: left"><table><tr><th>'.$choices{'hostid'}.'</th>'.
                       '<th>'.$choices{'current'}.'</th>'.                        '<th>'.$choices{'current'}.'</th>'.
                       '<th>'.$choices{'action'}.'</th>'.                        '<th>'.$choices{'action'}.'</th>'.
                       '<th>'.$choices{'exempt'}.'</th></tr>'."\n";                        '<th>'.$choices{'exempt'}.'</th></tr>'."\n";
Line 1522  sub print_login { Line 1385  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 1542  sub print_login { Line 1413  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 1676  sub login_choices { Line 1452  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();
     my @bgs = ('pgbg','tabbg','sidebg');      my @bgs = ('pgbg','tabbg','sidebg');
     my @links = ('link','alink','vlink');      my @links = ('link','alink','vlink');
     my @images = ();      my @images = ('img');
     my %alt_text = &Apache::lonlocal::texthash(img => "Banner for $role role");      my %alt_text = &Apache::lonlocal::texthash(img => "Banner for $role role");
     my %designhash = &Apache::loncommon::get_domainconf($dom);      my %designhash = &Apache::loncommon::get_domainconf($dom);
     my %defaultdesign = %Apache::loncommon::defaultdesign;      my %defaultdesign = %Apache::loncommon::defaultdesign;
Line 1888  sub print_rolecolors { Line 1469  sub print_rolecolors {
     my %defaults = &role_defaults($role,\@bgs,\@links,\@images);      my %defaults = &role_defaults($role,\@bgs,\@links,\@images);
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if (ref($settings->{$role}) eq 'HASH') {          if (ref($settings->{$role}) eq 'HASH') {
               if ($settings->{$role}->{'img'} ne '') {
                   $designs{'img'} = $settings->{$role}->{'img'};
                   $is_custom{'img'} = 1;
               }
             if ($settings->{$role}->{'font'} ne '') {              if ($settings->{$role}->{'font'} ne '') {
                 $designs{'font'} = $settings->{$role}->{'font'};                  $designs{'font'} = $settings->{$role}->{'font'};
                 $is_custom{'font'} = 1;                  $is_custom{'font'} = 1;
Line 1910  sub print_rolecolors { Line 1495  sub print_rolecolors {
             }              }
         }          }
     } else {      } else {
           if ($designhash{$dom.'.'.$role.'.img'} ne '') {
               $designs{img} = $designhash{$dom.'.'.$role.'.img'};
               $is_custom{'img'} = 1;
           }
         if ($designhash{$dom.'.'.$role.'.fontmenu'} ne '') {          if ($designhash{$dom.'.'.$role.'.fontmenu'} ne '') {
             $designs{fontmenu} = $designhash{$dom.'.'.$role.'.fontmenu'};              $designs{fontmenu} = $designhash{$dom.'.'.$role.'.fontmenu'};
             $is_custom{'fontmenu'} = 1;               $is_custom{'fontmenu'} = 1; 
Line 1959  sub role_defaults { Line 1548  sub role_defaults {
         }          }
     } else {      } else {
         %defaults = (          %defaults = (
                          img => $defaultdesign{$role.'.img'},
                        font => $defaultdesign{$role.'.font'},                         font => $defaultdesign{$role.'.font'},
                        fontmenu => $defaultdesign{$role.'.fontmenu'},                         fontmenu => $defaultdesign{$role.'.fontmenu'},
                     );                      );
Line 1983  sub display_color_options { Line 1573  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 1992  sub display_color_options { Line 1582  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 2007  sub display_color_options { Line 1597  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 2015  sub display_color_options { Line 1605  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 2023  sub display_color_options { Line 1613  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 2121  sub display_color_options { Line 1706  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 2135  sub display_color_options { Line 1715  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 2147  sub display_color_options { Line 1727  sub display_color_options {
                   '<table border="0"><tr>';                    '<table border="0"><tr>';
   
     foreach my $item (@{$bgs}) {      foreach my $item (@{$bgs}) {
         $datatable .= '<td align="center">'.$choices->{$item};          $datatable .= '<td style="text-align: center">'.$choices->{$item};
  my $color = $designs->{'bgs'}{$item} ? $designs->{'bgs'}{$item} : $defaults->{'bgs'}{$item};   my $color = $designs->{'bgs'}{$item} ? $designs->{'bgs'}{$item} : $defaults->{'bgs'}{$item};
         if ($designs->{'bgs'}{$item}) {          if ($designs->{'bgs'}{$item}) {
             $datatable .= '&nbsp;';              $datatable .= '&nbsp;';
Line 2163  sub display_color_options { Line 1743  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 2175  sub display_color_options { Line 1755  sub display_color_options {
                   '<table border="0"><tr>';                    '<table border="0"><tr>';
     foreach my $item (@{$links}) {      foreach my $item (@{$links}) {
  my $color = $designs->{'links'}{$item} ? $designs->{'links'}{$item} : $defaults->{'links'}{$item};   my $color = $designs->{'links'}{$item} ? $designs->{'links'}{$item} : $defaults->{'links'}{$item};
         $datatable .= '<td align="center">'.$choices->{$item}."\n";          $datatable .= '<td style="text-align: center">'.$choices->{$item}."\n";
         if ($designs->{'links'}{$item}) {          if ($designs->{'links'}{$item}) {
             $datatable.='&nbsp;';              $datatable.='&nbsp;';
         }          }
Line 2236  sub login_text_colors { Line 1816  sub login_text_colors {
     my ($img,$role,$logintext,$phase,$choices,$designs,$defaults) = @_;      my ($img,$role,$logintext,$phase,$choices,$designs,$defaults) = @_;
     my $color_menu = '<table border="0"><tr>';      my $color_menu = '<table border="0"><tr>';
     foreach my $item (@{$logintext}) {      foreach my $item (@{$logintext}) {
         $color_menu .= '<td align="center">'.$choices->{$item};          $color_menu .= '<td style="text-align: center">'.$choices->{$item};
         my $color = $designs->{'logintext'}{$item} ? $designs->{'logintext'}{$item} : $defaults->{'logintext'}{$item};          my $color = $designs->{'logintext'}{$item} ? $designs->{'logintext'}{$item} : $defaults->{'logintext'}{$item};
         $color_menu .= '<br /><input type="text" class="colorchooser" size="8" name="'.$role.'_'.$item.'" value="'.$color.          $color_menu .= '<br /><input type="text" class="colorchooser" size="8" name="'.$role.'_'.$item.'" value="'.$color.
                       '" onblur = "javascript:colchg_span('."'css_".$role.'_'.$item."'".',this);" /></td>';                        '" onblur = "javascript:colchg_span('."'css_".$role.'_'.$item."'".',this);" /></td>';
Line 2249  sub image_changes { Line 1829  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 2269  sub image_changes { Line 1851  sub image_changes {
                        $role.'_del_'.$img.'" value="1" />'.&mt('Delete?').                         $role.'_del_'.$img.'" value="1" />'.&mt('Delete?').
                        '</label>&nbsp;'.&mt('Replace:').'</span><br />';                         '</label>&nbsp;'.&mt('Replace:').'</span><br />';
         } else {          } else {
             $output .= '<td valign="middle">'.$logincolors.&mt('Upload:').'<br />';              $output .= '<td class="LC_middle">'.$logincolors.&mt('Upload:').'<br />';
         }          }
     }      }
     return $output;      return $output;
Line 2283  sub print_quotas { Line 1865  sub print_quotas {
     } else {      } else {
         $context = $action;          $context = $action;
     }      }
     my ($datatable,$defaultquota,@usertools,@options,%validations);      my ($datatable,$defaultquota,$authorquota,@usertools,@options,%validations);
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);      my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
     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','placement');
         @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 2297  sub print_quotas { Line 1879  sub print_quotas {
         @options = ('norequest','approval','automatic');          @options = ('norequest','approval','automatic');
         %titles = &authorrequest_titles();          %titles = &authorrequest_titles();
     } else {      } else {
         @usertools = ('aboutme','blog','portfolio','portaccess','timezone');          @usertools = ('aboutme','blog','webdav','portfolio');
         %titles = &tool_titles();          %titles = &tool_titles();
     }      }
     if (ref($types) eq 'ARRAY') {      if (ref($types) eq 'ARRAY') {
         foreach my $type (@{$types}) {          foreach my $type (@{$types}) {
             my $currdefquota;              my ($currdefquota,$currauthorquota);
             unless (($context eq 'requestcourses') ||              unless (($context eq 'requestcourses') ||
                     ($context eq 'requestauthor')) {                      ($context eq 'requestauthor')) {
                 if (ref($settings) eq 'HASH') {                  if (ref($settings) eq 'HASH') {
Line 2311  sub print_quotas { Line 1893  sub print_quotas {
                     } else {                      } else {
                         $currdefquota = $settings->{$type};                          $currdefquota = $settings->{$type};
                     }                      }
                       if (ref($settings->{authorquota}) eq 'HASH') {
                           $currauthorquota = $settings->{authorquota}->{$type};
                       }
                 }                  }
             }              }
             if (defined($usertypes->{$type})) {              if (defined($usertypes->{$type})) {
Line 2398  sub print_quotas { Line 1983  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 2428  sub print_quotas { Line 2010  sub print_quotas {
                         ($context eq 'requestauthor')) {                          ($context eq 'requestauthor')) {
                     $datatable .=                       $datatable .= 
                               '<td class="LC_right_item">'.                                '<td class="LC_right_item">'.
                               '<span class="LC_nobreak">'.                                '<span class="LC_nobreak">'.&mt('Portfolio').':&nbsp;'.
                               '<input type="text" name="quota_'.$type.                                '<input type="text" name="quota_'.$type.
                               '" value="'.$currdefquota.                                '" value="'.$currdefquota.
                                 '" size="5" /></span>'.('&nbsp;' x 2).
                                 '<span class="LC_nobreak">'.&mt('Authoring').':&nbsp;'.
                                 '<input type="text" name="authorquota_'.$type.
                                 '" value="'.$currauthorquota.
                               '" size="5" /></span></td>';                                '" size="5" /></span></td>';
                 }                  }
                 $datatable .= '</tr>';                  $datatable .= '</tr>';
Line 2439  sub print_quotas { Line 2025  sub print_quotas {
     }      }
     unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {      unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
         $defaultquota = '20';          $defaultquota = '20';
           $authorquota = '500';
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if (ref($settings->{'defaultquota'}) eq 'HASH') {              if (ref($settings->{'defaultquota'}) eq 'HASH') {
                 $defaultquota = $settings->{'defaultquota'}->{'default'};                  $defaultquota = $settings->{'defaultquota'}->{'default'};
             } elsif (defined($settings->{'default'})) {              } elsif (defined($settings->{'default'})) {
                 $defaultquota = $settings->{'default'};                  $defaultquota = $settings->{'default'};
             }              }
               if (ref($settings->{'authorquota'}) eq 'HASH') {
                   $authorquota = $settings->{'authorquota'}->{'default'};
               }
         }          }
     }      }
     $typecount ++;      $typecount ++;
Line 2556  sub print_quotas { Line 2146  sub print_quotas {
     $datatable .= '</td>';      $datatable .= '</td>';
     unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {      unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
         $datatable .= '<td class="LC_right_item">'.          $datatable .= '<td class="LC_right_item">'.
                       '<span class="LC_nobreak">'.                        '<span class="LC_nobreak">'.&mt('Portfolio').':&nbsp;'.
                       '<input type="text" name="defaultquota" value="'.                        '<input type="text" name="defaultquota" value="'.
                       $defaultquota.'" size="5" /></span></td>';                        $defaultquota.'" size="5" /></span>'.('&nbsp;' x2).
                         '<span class="LC_nobreak">'.&mt('Authoring').':&nbsp;'.
                         '<input type="text" name="authorquota" value="'.
                         $authorquota.'" size="5" /></span></td>';
     }      }
     $datatable .= '</tr>';      $datatable .= '</tr>';
     $typecount ++;      $typecount ++;
Line 2741  sub print_studentcode { Line 2334  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','placement');
     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 2868  sub print_textbookcourses { Line 2461  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 2885  sub print_textbookcourses { Line 2478  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 2993  ENDSCRIPT Line 2586  ENDSCRIPT
   
 sub ltitools_javascript {  sub ltitools_javascript {
     my ($settings) = @_;      my ($settings) = @_;
     my $togglejs = &ltitools_toggle_js();      return unless(ref($settings) eq 'HASH');
     unless (ref($settings) eq 'HASH') {  
         return $togglejs;  
     }  
     my (%ordered,$total,%jstext);      my (%ordered,$total,%jstext);
     $total = 0;      $total = 0;
     foreach my $item (keys(%{$settings})) {      foreach my $item (keys(%{$settings})) {
Line 3014  sub ltitools_javascript { Line 2604  sub ltitools_javascript {
     return <<"ENDSCRIPT";      return <<"ENDSCRIPT";
 <script type="text/javascript">  <script type="text/javascript">
 // <![CDATA[  // <![CDATA[
 function reorderLTITools(form,item) {  function reorderLTI(form,item) {
     var changedVal;      var changedVal;
 $jstext  $jstext
     var newpos = 'ltitools_add_pos';      var newpos = 'ltitools_add_pos';
Line 3059  $jstext Line 2649  $jstext
 // ]]>  // ]]>
 </script>  </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 authordefaults_javascript {  
     my %alert = &Apache::lonlocal::texthash (  
                     reqd => 'Warning: at least one editor needs to be available.',  
                     rest => 'Unchecking this editor disallowed while others unchecked.',  
     );  
     &js_escape(\%alert);  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
   
 function checkEditors(form,checkbox,current) {  
     if (form.elements[checkbox].length != undefined) {  
         var count = 0;  
         for (var i=0; i<form.elements[checkbox].length; i++) {  
             if (form.elements[checkbox][i].checked) {  
                 count ++;  
             }  
         }  
         if (count == 0) {  
             if (current.type =='radio') {  
                 current.checked = true;  
                 alert('$alert{reqd}\\n$alert{rest}');  
             }  
         }  
     }  
     return;  
 }  
 // ]]>  
 </script>  
   
 ENDSCRIPT  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);
         $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 3793  sub print_autoenroll { Line 2689  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'})) {          if (exists($settings->{'autofailsafe'})) {
             $failsafe = $settings->{'failsafe'};              $failsafe = $settings->{'autofailsafe'};
             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) {
Line 3849  sub print_autoenroll { Line 2729  sub print_autoenroll {
                   $coownersoff.' value="0" />'.&mt('No').'</label></span></td>'.                    $coownersoff.' value="0" />'.&mt('No').'</label></span></td>'.
                   '</tr><tr>'.                    '</tr><tr>'.
                   '<td>'.&mt('Failsafe for no drops when institutional data missing').'</td>'.                    '<td>'.&mt('Failsafe for no drops when institutional data missing').'</td>'.
                   '<td class="LC_left_item"><span class="LC_nobreak">'.                    '<td class="LC_right_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; '.                    '<input type="text" name="autoenroll_failsafe"'.
                   '<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 />'.                    ' value="'.$failsafe.'" size="4" /></td></tr>';
                   '<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;      $$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;
Line 4166  sub print_contacts { Line 3013  sub print_contacts {
     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,%includestr,%includeloc,%currfield,
         $maxsize,$fields,$fieldtitles,$fieldoptions,$possoptions,@mailings,%lonstatus);          $maxsize,$fields,$fieldtitles,$fieldoptions,$possoptions,@mailings);
     if ($position eq 'top') {      if ($position eq 'top') {
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             foreach my $item (@contacts) {              foreach my $item (@contacts) {
Line 4177  sub print_contacts { Line 3024  sub print_contacts {
         }          }
     } elsif ($position eq 'middle') {      } elsif ($position eq 'middle') {
         @mailings = ('errormail','packagesmail','lonstatusmail','requestsmail',          @mailings = ('errormail','packagesmail','lonstatusmail','requestsmail',
                      'updatesmail','idconflictsmail','hostipmail');                       'updatesmail','idconflictsmail');
         foreach my $type (@mailings) {          foreach my $type (@mailings) {
             $otheremails{$type} = '';              $otheremails{$type} = '';
         }          }
     } elsif ($position eq 'lower') {  
         if (ref($settings) eq 'HASH') {  
             if (ref($settings->{'lonstatus'}) eq 'HASH') {  
                 %lonstatus = %{$settings->{'lonstatus'}};  
             }  
         }  
     } else {      } else {
         @mailings = ('helpdeskmail','otherdomsmail');          @mailings = ('helpdeskmail','otherdomsmail');
         foreach my $type (@mailings) {          foreach my $type (@mailings) {
Line 4199  sub print_contacts { Line 3040  sub print_contacts {
         ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields();          ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields();
     }      }
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         unless (($position eq 'top') || ($position eq 'lower')) {          unless ($position eq 'top') {
             foreach my $type (@mailings) {              foreach my $type (@mailings) {
                 if (exists($settings->{$type})) {                  if (exists($settings->{$type})) {
                     if (ref($settings->{$type}) eq 'HASH') {                      if (ref($settings->{$type}) eq 'HASH') {
Line 4260  sub print_contacts { Line 3101  sub print_contacts {
             $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') {          } elsif ($position eq 'bottom') {
             $checked{'helpdeskmail'}{'supportemail'} = ' checked="checked" ';              $checked{'helpdeskmail'}{'supportemail'} = ' checked="checked" ';
             $checked{'otherdomsmail'}{'supportemail'} = ' checked="checked" ';              $checked{'otherdomsmail'}{'supportemail'} = ' checked="checked" ';
Line 4321  sub print_contacts { Line 3161  sub print_contacts {
                     if ($currfield{$field} eq 'no') {                      if ($currfield{$field} eq 'no') {
                         $display = ' style="display:none"';                          $display = ' style="display:none"';
                     }                      }
                     $datatable .= '</td></tr><tr id="help_screenshotsize"'.$display.'>'.                      $datatable .= '</td></tr><tr id="help_screenshotsize"'.$display.' />'.
                                   '<td>'.&mt('Maximum size for upload (MB)').'</td><td>'.                                    '<td>'.&mt('Maximum size for upload (MB)').'</td><td>'.
                                   '<input type="text" size="5" name="helpform_maxsize" value="'.$maxsize.'" />';                                    '<input type="text" size="5" name="helpform_maxsize" value="'.$maxsize.'" />';
                 }                  }
Line 4332  sub print_contacts { Line 3172  sub print_contacts {
         $datatable .= '</td></tr>'."\n";          $datatable .= '</td></tr>'."\n";
         $rownum ++;          $rownum ++;
     }      }
     unless (($position eq 'top') || ($position eq 'lower')) {      unless ($position eq 'top') {
         foreach my $type (@mailings) {          foreach my $type (@mailings) {
             $css_class = $rownum%2?' class="LC_odd_row"':'';              $css_class = $rownum%2?' class="LC_odd_row"':'';
             $datatable .= '<tr'.$css_class.'>'.              $datatable .= '<tr'.$css_class.'>'.
Line 4366  sub print_contacts { Line 3206  sub print_contacts {
                               'value="'.$bccemails{$type}.'"  /></fieldset>'.                                'value="'.$bccemails{$type}.'"  /></fieldset>'.
                               '<fieldset><legend>'.&mt('Optional added text').'</legend>'.                                '<fieldset><legend>'.&mt('Optional added text').'</legend>'.
                               &mt('Text automatically added to e-mail:').' '.                                &mt('Text automatically added to e-mail:').' '.
                               '<input type="text" name="'.$type.'_includestr" value="'.$includestr{$type}.'" /><br />'.                                '<input type="text" name="'.$type.'_includestr" value="'.$includestr{$type}.'" /><br >'.
                               '<span class="LC_nobreak">'.&mt('Location:').'&nbsp;'.                                '<span class="LC_nobreak">'.&mt('Location:').'&nbsp;'.
                               '<label><input type="radio" name="'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'.                                '<label><input type="radio" name="'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'.
                               ('&nbsp;'x2).                                ('&nbsp;'x2).
Line 4379  sub print_contacts { Line 3219  sub print_contacts {
     }      }
     if ($position eq 'middle') {      if ($position eq 'middle') {
         my %choices;          my %choices;
         my $corelink = &core_link_msu();          $choices{'reporterrors'} = &mt('E-mail error reports to [_1]',
         $choices{'reporterrors'} = &mt('E-mail error reports to [_1]',$corelink);                                         &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]',          $choices{'reportupdates'} = &mt('E-mail record of completed LON-CAPA updates to [_1]',
                                         $corelink);                                          &Apache::loncommon::modal_link('http://loncapa.org/core.html',
         $choices{'reportstatus'} = &mt('E-mail status if errors above threshold to [_1]',$corelink);                                          &mt('LON-CAPA core group - MSU'),600,500));
         my @toggles = ('reporterrors','reportupdates','reportstatus');          my @toggles = ('reporterrors','reportupdates');
         my %defaultchecked = ('reporterrors'  => 'on',          my %defaultchecked = ('reporterrors'  => 'on',
                               'reportupdates' => 'on',                                'reportupdates' => 'on');
                               'reportstatus'  => 'on');  
         (my $reports,$rownum) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,          (my $reports,$rownum) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
                                                    \%choices,$rownum);                                                     \%choices,$rownum);
         $datatable .= $reports;          $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"':'';  
         $datatable .= '<tr'.$css_class.'>'.  
                       '<td class="LC_left_item">'.  
                       '<span class="LC_nobreak">'.$titles->{'errorweights'}.  
                       '</span></td><td class="LC_left_item"><table><tr>';  
         foreach my $type ('E','W','N','U') {  
             $datatable .= '<td>'.$names->{$type}.'<br />'.  
                           '<input type="text" name="errorweights_'.$type.'" value="'.  
                           $weights{$type}.'" size="5" /></td>';  
         }  
         $datatable .= '</tr></table></tr>';  
         $rownum ++;  
         $css_class = $rownum%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td class="LC_left_item">'.  
                       $titles->{'errorexcluded'}.'</td>'.  
                       '<td class="LC_left_item"><table>';  
         my $numinrow = 4;  
         my @ids = sort(values(%Apache::lonnet::serverhomeIDs));  
         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>';  
         $rownum ++;  
     } elsif ($position eq 'bottom') {      } elsif ($position eq 'bottom') {
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);          my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
         my (@posstypes,%usertypeshash);          my (@posstypes,%usertypeshash);
Line 4504  sub print_contacts { Line 3258  sub print_contacts {
                             $includeloc{'override_'.$key} = '';                              $includeloc{'override_'.$key} = '';
                             $includestr{'override_'.$key} = '';                              $includestr{'override_'.$key} = '';
                             if ($settings->{'overrides'}{$key}{'include'} ne '') {                              if ($settings->{'overrides'}{$key}{'include'} ne '') {
                                 ($includeloc{'override_'.$key},$includestr{'override_'.$key}) =                                  ($includeloc{'override_'.$key},$includestr{'override_'.$key}) = 
                                     split(/:/,$settings->{'overrides'}{$key}{'include'},2);                                      split(/:/,$settings->{'overrides'}{$key}{'include'},2);
                                 $includestr{'override_'.$key} = &unescape($includestr{'override_'.$key});                                  $includestr{'override_'.$key} = &unescape($includestr{'override_'.$key});
                             }                              }
Line 4516  sub print_contacts { Line 3270  sub print_contacts {
             my $optionsprefix = 'LC_options_helpdesk_';              my $optionsprefix = 'LC_options_helpdesk_';
   
             my $onclicktypes = "toggleHelpdeskRow(this.form,'overrides','$customclass','$optionsprefix');";              my $onclicktypes = "toggleHelpdeskRow(this.form,'overrides','$customclass','$optionsprefix');";
    
             $datatable .= &insttypes_row($settings,$types,$usertypes,$dom,              $datatable .= &insttypes_row($settings,$types,$usertypes,$dom,
                                          $numinrow,$othertitle,'overrides',                                           $numinrow,$othertitle,'overrides',
                                          \$rownum,$onclicktypes,$customclass);                                           \$rownum,$onclicktypes,$customclass);
Line 4549  sub print_contacts { Line 3304  sub print_contacts {
     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 {  sub overridden_helpdesk {
     my ($checked,$otheremails,$bccemails,$includeloc,$includestr,$type,$rowid,      my ($checked,$otheremails,$bccemails,$includeloc,$includestr,$type,$rowid,
         $typetitle,$css_class,$rowstyle,$contacts,$short_titles) = @_;          $typetitle,$css_class,$rowstyle,$contacts,$short_titles) = @_;
Line 4582  sub overridden_helpdesk { Line 3332  sub overridden_helpdesk {
             }              }
             my $title;              my $title;
             if (ref($short_titles) eq 'HASH') {              if (ref($short_titles) eq 'HASH') {
                 $title = $short_titles->{$item};                  $title = $short_titles->{$item}; 
             }              }
             $output .= '<label>'.              $output .= '<label>'.
                        '<input type="checkbox" name="override_'.$type.'"'.$check.                         '<input type="checkbox" name="override_'.$type.'"'.$check.
Line 4604  sub overridden_helpdesk { Line 3354  sub overridden_helpdesk {
                'value="'.$bccemails.'"  /></fieldset>'.                 'value="'.$bccemails.'"  /></fieldset>'.
                '<fieldset><legend>'.&mt('Optional added text').'</legend>'.                 '<fieldset><legend>'.&mt('Optional added text').'</legend>'.
                &mt('Text automatically added to e-mail:').' '.                 &mt('Text automatically added to e-mail:').' '.
                '<input type="text" name="override_'.$type.'_includestr" value="'.$includestr.'" /><br />'.                 '<input type="text" name="override_'.$type.'_includestr" value="'.$includestr.'" /><br >'.
                '<span class="LC_nobreak">'.&mt('Location:').'&nbsp;'.                 '<span class="LC_nobreak">'.&mt('Location:').'&nbsp;'.
                '<label><input type="radio" name="override_'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'.                 '<label><input type="radio" name="override_'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'.
                ('&nbsp;'x2).                 ('&nbsp;'x2).
Line 4661  function toggleHelpdeskRow(form,checkbox Line 3411  function toggleHelpdeskRow(form,checkbox
     return;      return;
 }  }
   
   
 // ]]>  // ]]>
 </script>  </script>
   
Line 4732  sub print_helpsettings { Line 3483  sub print_helpsettings {
             push(@jsarray,('notinc','notexc'));              push(@jsarray,('notinc','notexc'));
         }          }
         my $hiddenstr = join("','",@jsarray);          my $hiddenstr = join("','",@jsarray);
           $datatable .= &helpsettings_javascript(\@roles_by_num,$maxnum,$hiddenstr,$formname);
         my $context = 'domprefs';          my $context = 'domprefs';
         my $crstype = 'Course';          my $crstype = 'Course';
         my $prefix = 'helproles_';          my $prefix = 'helproles_';
Line 4765  sub print_helpsettings { Line 3517  sub print_helpsettings {
             my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);              my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
             $css_class = $itemcount%2?' class="LC_odd_row"':'';              $css_class = $itemcount%2?' class="LC_odd_row"':'';
             my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$num."_pos'".');"';              my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$num."_pos'".');"';
             $datatable .= '<tr '.$css_class.'><td valign="top"><b>'.$role.'</b><br />'.              $datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><b>'.$role.'</b><br />'.
                           '<select name="helproles_'.$num.'_pos"'.$chgstr.'>';                            '<select name="helproles_'.$num.'_pos"'.$chgstr.'>';
             for (my $k=0; $k<=$maxnum; $k++) {              for (my $k=0; $k<=$maxnum; $k++) {
                 my $vpos = $k+1;                  my $vpos = $k+1;
Line 4804  sub print_helpsettings { Line 3556  sub print_helpsettings {
         &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);          &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);
         my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);          my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
         my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$count."_pos'".');"';          my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$count."_pos'".');"';
         $datatable .= '<tr '.$css_class.'><td valign="top"><span class="LC_nobreak"><label>'.          $datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><span class="LC_nobreak"><label>'.
                       '<input type="hidden" name="helproles_maxnum" value="'.$maxnum.'" />'."\n".                        '<input type="hidden" name="helproles_maxnum" value="'.$maxnum.'" />'."\n".
                       '<select name="helproles_'.$count.'_pos"'.$chgstr.'>';                        '<select name="helproles_'.$count.'_pos"'.$chgstr.'>';
         for (my $k=0; $k<$maxnum+1; $k++) {          for (my $k=0; $k<$maxnum+1; $k++) {
Line 4834  sub print_helpsettings { Line 3586  sub print_helpsettings {
                                                                 \@templateroles,$newcust).                                                                  \@templateroles,$newcust).
                       &Apache::lonuserutils::custom_role_table('Course',\%full,\%levels,                        &Apache::lonuserutils::custom_role_table('Course',\%full,\%levels,
                                                                \%levelscurrent,$newcust).                                                                 \%levelscurrent,$newcust).
                       '</fieldset>'.                        '</fieldset></td></tr>';
                       &helpsettings_javascript(\@roles_by_num,$maxnum,$hiddenstr,$formname).  
                       '</td></tr>';  
         $count ++;          $count ++;
         $$rowtotal += $count;          $$rowtotal += $count;
     }      }
Line 5053  sub helpdeskroles_access { Line 3803  sub helpdeskroles_access {
   
 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 5085  sub radiobutton_prefs { Line 3835  sub radiobutton_prefs {
     foreach my $item (@{$toggles}) {      foreach my $item (@{$toggles}) {
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $datatable .=          $datatable .=
             '<tr'.$css_class.'><td valign="top">'.              '<tr'.$css_class.'><td style="vertical-align: top">'.
             '<span class="LC_nobreak">'.$choices->{$item}.              '<span class="LC_nobreak">'.$choices->{$item}.
             '</span></td>';              '</span></td>';
         if ($align eq 'left') {          if ($align eq 'left') {
Line 5093  sub radiobutton_prefs { Line 3843  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 {  sub print_ltitools {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($dom,$settings,$rowtotal) = @_;
     my (%rules,%encrypt,%privkeys,%linkprot);      my $rownum = 0;
       my $css_class;
       my $itemcount = 1;
       my $maxnum = 0;
       my %ordered;
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if ($position eq 'top') {          foreach my $item (keys(%{$settings})) {
             if (exists($settings->{'encrypt'})) {              if (ref($settings->{$item}) eq 'HASH') {
                 if (ref($settings->{'encrypt'}) eq 'HASH') {                  my $num = $settings->{$item}{'order'};
                     foreach my $key (keys(%{$settings->{'encrypt'}})) {                  $ordered{$num} = $item;
                         $encrypt{'toolsec_'.$key} = $settings->{'encrypt'}{$key};  
                     }  
                 }  
             }              }
             if (exists($settings->{'private'})) {          }
                 if (ref($settings->{'private'}) eq 'HASH') {      }
                     if (ref($settings->{'private'}) eq 'HASH') {      my $confname = $dom.'-domainconfig';
                         if (ref($settings->{'private'}{'keys'}) eq 'ARRAY') {      my $switchserver = &check_switchserver($dom,$confname);
                             map { $privkeys{$_} = 1; } (@{$settings->{'private'}{'keys'}});      my $maxnum = scalar(keys(%ordered));
                         }      my $datatable = &ltitools_javascript($settings);
                     }      my %lt = &ltitools_names();
       my @courseroles = ('cc','in','ta','ep','st');
       my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner);
       my @fields = ('fullname','firstname','lastname','email','user','roles');
       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 ($title,$key,$secret,$url,$imgsrc);
               if (ref($settings->{$item}) eq 'HASH') {
                   $title = $settings->{$item}->{'title'};
                   $url = $settings->{$item}->{'url'};
                   $key = $settings->{$item}->{'key'};
                   $secret = $settings->{$item}->{'secret'};
                   my $image = $settings->{$item}->{'image'};
                   if ($image ne '') {
                       $imgsrc = '<img src="'.$image.'" alt="'.&mt('Tool Provider icon').'" />';
                 }                  }
             }              }
         } elsif ($position eq 'middle') {              my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'ltitools_".$item."'".');"';
             if (exists($settings->{'rules'})) {              $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
                 if (ref($settings->{'rules'}) eq 'HASH') {                           .'<select name="ltitools_'.$item.'"'.$chgstr.'>';
                     %rules = %{$settings->{'rules'}};              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>';
             }              }
         } else {              $datatable .= '</select>'.('&nbsp;'x2).
             foreach my $key ('encrypt','private','rules') {                  '<label><input type="checkbox" name="ltitools_del" value="'.$item.'" />'.
                 if (exists($settings->{$key})) {                  &mt('Delete?').'</label></span></td>'.
                     delete($settings->{$key});                  '<td colspan="2">'.
                 }                  '<fieldset><legend>'.&mt('Required settings').'</legend>'.
                   '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="30" name="ltitools_title_'.$i.'" value="'.$title.'" /></span> '.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'version'}.':<select name="ltitools_version_'.$i.'">'.
                   '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'msgtype'}.':<select name="ltitools_msgtype_'.$i.'">'.
                   '<option value="basic-lti-launch-request" selected="selected">Launch</option></select></span> '.
                   '<br /><br />'.
                   '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="30" name="ltitools_url_'.$i.'"'.
                   ' value="'.$url.'" /></span>'.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'key'}.
                   '<input type="text" size="25" name="ltitools_key_'.$i.'" value="'.$key.'" /></span> '.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'secret'}.':'.
                   '<input type="password" size="20" name="ltitools_secret_'.$i.'" value="'.$secret.'" />'.
                   '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltitools_secret_'.$i.'.type='."'text'".' } else { this.form.ltitools_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.
                   '<input type="hidden" name="ltitools_id_'.$i.'" value="'.$item.'" /></span>'.
                   '</fieldset>'.
                   '<fieldset><legend>'.&mt('Optional settings').'</legend>'.
                   '<span class="LC_nobreak">'.&mt('Display target:');
               my %currdisp;
               if (ref($settings->{$item}->{'display'}) eq 'HASH') {
                   if ($settings->{$item}->{'display'}->{'target'} eq 'window') {
                       $currdisp{'window'} = ' checked="checked"';
                   } elsif ($settings->{$item}->{'display'}->{'target'} eq 'tab') {
                       $currdisp{'tab'} = ' checked="checked"';
                   } else {
                       $currdisp{'iframe'} = ' checked="checked"';
                   }
                   if ($settings->{$item}->{'display'}->{'width'} =~ /^(\d+)$/) {
                       $currdisp{'width'} = $1;
                   }
                   if ($settings->{$item}->{'display'}->{'height'} =~ /^(\d+)$/) {
                        $currdisp{'height'} = $1;
                   }
                   $currdisp{'linktext'} = $settings->{$item}->{'display'}->{'linktext'};
                   $currdisp{'explanation'} = $settings->{$item}->{'display'}->{'explanation'};
               } else {
                   $currdisp{'iframe'} = ' checked="checked"';
               }
               foreach my $disp ('iframe','tab','window') {
                   $datatable .= '<label><input type="radio" name="ltitools_target_'.$i.'" value="'.$disp.'"'.$currdisp{$disp}.' />'.
                                 $lt{$disp}.'</label>'.('&nbsp;'x2);
               }
               $datatable .= ('&nbsp;'x4);
               foreach my $dimen ('width','height') {
                   $datatable .= '<label>'.$lt{$dimen}.'&nbsp;'.
                                 '<input type="text" name="ltitools_'.$dimen.'_'.$i.'" size="5" value="'.$currdisp{$dimen}.'" /></label>'.
                                 ('&nbsp;'x2);
               }
               $datatable .= '<br />'.
                             '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'.
                             '<input type="text" name="ltitools_linktext_'.$i.'" size="25" value="'.$currdisp{'linktext'}.'" /></label></div>'.
                             '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'.
                             '<textarea name="ltitools_explanation_'.$i.'" rows="5" cols="40">'.$currdisp{'explanation'}.
                             '</textarea></div><div style=""></div><br />';
               $datatable .= '<br />';
               foreach my $extra ('passback','roster') {
                   my $checkedon = '';
                   my $checkedoff = ' checked="checked"';
                   if ($settings->{$item}->{$extra}) {
                       $checkedon = $checkedoff;
                       $checkedoff = '';
                   }
                   $datatable .= $lt{$extra}.'&nbsp;'.
                                 '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="1"'.$checkedon.' />'.
                                 &mt('Yes').'</label>'.('&nbsp;'x2).
                                 '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="0"'.$checkedoff.' />'.
                                 &mt('No').'</label>'.('&nbsp;'x4);
               }
               $datatable .= '<br /><br /><span class="LC_nobreak">'.$lt{'icon'}.':&nbsp;';
               if ($imgsrc) {
                   $datatable .= $imgsrc.
                                 '<label><input type="checkbox" name="ltitools_image_del"'.
                                 ' value="'.$item.'" />'.&mt('Delete?').'</label></span> '.
                                 '<span class="LC_nobreak">&nbsp;'.&mt('Replace:').'&nbsp;';
               } else {
                   $datatable .= '('.&mt('if larger than 21x21 pixels, image will be scaled').')&nbsp;';
             }              }
         }              if ($switchserver) {
     }                  $datatable .= &mt('Upload to library server: [_1]',$switchserver);
     my $datatable;              } else {
     my $itemcount = 1;                  $datatable .= '<input type="file" name="ltitools_image_'.$i.'" value="" />';
     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 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,%suggestions);  
     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'})) {              $datatable .= '</span></fieldset>';
                 if (ref($settings->{'private'}) eq 'HASH') {              my (%checkedfields,%rolemaps);
                     if (ref($settings->{'private'}) eq 'HASH') {              if (ref($settings->{$item}) eq 'HASH') {
                         if (ref($settings->{'private'}{'keys'}) eq 'ARRAY') {                  if (ref($settings->{$item}->{'fields'}) eq 'HASH') {
                             map { $privkeys{$_} = 1; } (@{$settings->{'private'}{'keys'}});                      %checkedfields = %{$settings->{$item}->{'fields'}};
                         }  
                     }  
                 }                  }
             }                  if (ref($settings->{$item}->{'roles'}) eq 'HASH') {
         } elsif ($position eq 'upper') {                      %rolemaps = %{$settings->{$item}->{'roles'}};
             if (exists($settings->{'rules'})) {                      $checkedfields{'roles'} = 1;
                 if (ref($settings->{'rules'}) eq 'HASH') {  
                     %rules = %{$settings->{'rules'}};  
                 }                  }
             }              }
         } elsif ($position eq 'middle') {              $datatable .= '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'.
             if (exists($settings->{'suggested'})) {                            '<span class="LC_nobreak">';
                 if (ref($settings->{'suggested'}) eq 'HASH') {              foreach my $field (@fields) {
                     %suggestions = %{$settings->{'suggested'}};                  my $checked;
                   if ($checkedfields{$field}) {
                       $checked = ' checked="checked"';
                 }                  }
                   $datatable .= '<label>'.
                                 '<input type="checkbox" name="ltitools_fields_'.$i.'" value="'.$field.'"'.$checked.' />'.
                                 $lt{$field}.'</label>'.('&nbsp;' x2);
             }              }
         } elsif ($position eq 'lower') {              $datatable .= '</span></fieldset>'.
             if (exists($settings->{'linkprot'})) {                            '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>';
                 if (ref($settings->{'linkprot'}) eq 'HASH') {              foreach my $role (@courseroles) {
                     %linkprot = %{$settings->{'linkprot'}};                  my ($selected,$selectnone);
                     if ($linkprot{'lock'}) {                  if (!$rolemaps{$role}) {
                         delete($linkprot{'lock'});                      $selectnone = ' selected="selected"';
                   }
                   $datatable .= '<td style="text-align: center">'. 
                                 &Apache::lonnet::plaintext($role,'Course').'<br />'.
                                 '<select name="ltitools_roles_'.$role.'_'.$i.'">'.
                                 '<option value=""'.$selectnone.'>'.&mt('Select').'</option>';
                   foreach my $ltirole (@ltiroles) {
                       unless ($selectnone) {
                           if ($rolemaps{$role} eq $ltirole) {
                               $selected = ' selected="selected"';
                           } else {
                               $selected = '';
                           }
                     }                      }
                       $datatable .= '<option value="'.$ltirole.'"'.$selected.'>'.$ltirole.'</option>';
                 }                  }
                   $datatable .= '</select></td>';
             }              }
         } else {              $datatable .= '</tr></table></fieldset>';
             foreach my $key ('encrypt','private','rules','linkprot','suggestions') {              my %courseconfig;
                 if (exists($settings->{$key})) {              if (ref($settings->{$item}) eq 'HASH') {
                     delete($settings->{$key});                  if (ref($settings->{$item}->{'crsconf'}) eq 'HASH') {
                       %courseconfig = %{$settings->{$item}->{'crsconf'}};
                 }                  }
             }              }
         }              $datatable .= '<fieldset><legend>'.&mt('Configurable in course').'</legend><span class="LC_nobreak">';
     }              foreach my $item ('label','title','target','linktext','explanation','append') {
     if ($position eq 'top') {                  my $checked;
         $datatable = &secrets_form($dom,'ltisec',\%encrypt,\%privkeys,$rowtotal);                  if ($courseconfig{$item}) {
     } elsif ($position eq 'upper') {                      $checked = ' checked="checked"';
         $datatable = &password_rules('ltisecrets',\$itemcount,\%rules);  
         $$rowtotal += $itemcount;  
     } elsif ($position eq 'middle') {  
         $datatable = &linkprot_suggestions(\%suggestions,\$itemcount);  
         $$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;  
                 }                  }
                   $datatable .= '<label>'.
                          '<input type="checkbox" name="ltitools_courseconfig_'.$i.'" value="'.$item.'"'.$checked.' />'.
                          $lt{'crs'.$item}.'</label>'.('&nbsp;' x2)."\n";
             }              }
         }              $datatable .= '</span></fieldset>'.
         $maxnum = scalar(keys(%ordered));                            '<fieldset><legend>'.&mt('Custom items sent on launch').'</legend>'.
         my %lt = &lti_names();                            '<table><tr><th>'.&mt('Action').'</th><th>'.&mt('Name').'</th><th>'.&mt('Value').'</th></tr>';
         if (keys(%ordered)) {              if (ref($settings->{$item}->{'custom'}) eq 'HASH') {
             my @items = sort { $a <=> $b } keys(%ordered);                  my %custom = %{$settings->{$item}->{'custom'}};
             for (my $i=0; $i<@items; $i++) {                  if (keys(%custom) > 0) {
                 $css_class = $itemcount%2?' class="LC_odd_row"':'';                      foreach my $key (sort(keys(%custom))) {
                 my $item = $ordered{$items[$i]};                          $datatable .= '<tr><td><span class="LC_nobreak">'.
                 my ($key,$secret,$usable,$lifetime,$consumer,$requser,$crsinc,$current);                                        '<label><input type="checkbox" name="ltitools_customdel_'.$i.'" value="'.
                 if (ref($settings->{$item}) eq 'HASH') {                                        $key.'" />'.&mt('Delete').'</label></span></td><td>'.$key.'</td>'.
                     $key = $settings->{$item}->{'key'};                                        '<td><input type="text" name="ltitools_customval_'.$key.'_'.$i.'"'.
                     $usable = $settings->{$item}->{'usable'};                                        ' value="'.$custom{$key}.'" /></td></tr>';
                     $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 ++;  
             }              }
               $datatable .= '<tr><td><span class="LC_nobreak">'.
                             '<label><input type="checkbox" name="ltitools_customadd" value="'.$i.'" />'.
                             &mt('Add').'</label></span></td><td><input type="text" name="ltitools_custom_name_'.$i.'" />'.
                             '</td><td><input type="text" name="ltitools_custom_value_'.$i.'" /></td></tr>';
               $datatable .= '</table></fieldset></td></tr>'."\n";
               $itemcount ++;
         }          }
         $css_class = $itemcount%2?' class="LC_odd_row"':'';      }
         my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_add'".');"';      $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".      my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'ltitools_add_pos'".');"';
                       '<input type="hidden" name="lti_maxnum" value="'.$maxnum.'" />'."\n".      $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
                       '<select name="lti_pos_add"'.$chgstr.'>';                    '<input type="hidden" name="ltitools_maxnum" value="'.$maxnum.'" />'."\n".
         for (my $k=0; $k<$maxnum+1; $k++) {                    '<select name="ltitools_add_pos"'.$chgstr.'>';
             my $vpos = $k+1;      for (my $k=0; $k<$maxnum+1; $k++) {
             my $selstr;          my $vpos = $k+1;
             if ($k == $maxnum) {          my $selstr;
                 $selstr = ' selected="selected" ';          if ($k == $maxnum) {
             }              $selstr = ' selected="selected" ';
             $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';  
         }          }
         $datatable .= '</select>&nbsp;'."\n".          $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
                       '<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;      $datatable .= '</select>&nbsp;'."\n".
                     '<input type="checkbox" name="ltitools_add" value="1" />'.&mt('Add').'</td>'."\n".
                     '<td colspan="2">'.
                     '<fieldset><legend>'.&mt('Required settings').'</legend>'.
                     '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="30" name="ltitools_add_title" value="" /></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'version'}.':<select name="ltitools_add_version">'.
                     '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'msgtype'}.':<select name="ltitools_add_msgtype">'.
                     '<option value="basic-lti-launch-request" selected="selected">Launch</option></select></span> '.
                     '<br />'.
                     '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="30" name="ltitools_add_url" value="" /></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="ltitools_add_key" value="" /></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="ltitools_add_secret" value="" />'.
                     '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltitools_add_secret.type='."'text'".' } else { this.form.ltitools_add_secret.type='."'password'".' }" />'.&mt('Visible input').'</label></span> '."\n".
                     '</fieldset>'.
                     '<fieldset><legend>'.&mt('Optional settings').'</legend>'.
                     '<span class="LC_nobreak">'.&mt('Display target:');
       my %defaultdisp;
       $defaultdisp{'iframe'} = ' checked="checked"';
       foreach my $disp ('iframe','tab','window') {
           $datatable .= '<label><input type="radio" name="ltitools_add_target" value="'.$disp.'"'.$defaultdisp{$disp}.' />'.
                         $lt{$disp}.'</label>'.('&nbsp;'x2);
       }
       $datatable .= ('&nbsp;'x4);
       foreach my $dimen ('width','height') {
           $datatable .= '<label>'.$lt{$dimen}.'&nbsp;'.
                         '<input type="text" name="ltitools_add_'.$dimen.'" size="5" /></label>'.
                         ('&nbsp;'x2);
       }
       $datatable .= '<br />'.
                     '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'.
                     '<input type="text" name="ltitools_add_linktext" size="5" /></label></div>'.
                     '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'.
                     '<textarea name=ltitools_add_explanation" rows="5" cols="40"></textarea>'.
                     '</div><div style=""></div><br />';
       foreach my $extra ('passback','roster') {
           $datatable .= $lt{$extra}.'&nbsp;'.
                         '<label><input type="radio" name="ltitools_add_'.$extra.'" value="1" />'.
                         &mt('Yes').'</label>'.('&nbsp;'x2).
                         '<label><input type="radio" name="ltitools_add_'.$extra.'" value="0" checked="checked" />'.
                         &mt('No').'</label>'.('&nbsp;'x4);
       }
       $datatable .= '<br /><br /><span class="LC_nobreak">'.$lt{'icon'}.':&nbsp;'.
                     '('.&mt('if larger than 21x21 pixels, image will be scaled').')&nbsp;';
       if ($switchserver) {
           $datatable .= &mt('Upload to library server: [_1]',$switchserver);
       } else {
           $datatable .= '<input type="file" name="ltitools_add_image" value="" />';
       }
       $datatable .= '</span></fieldset>'.
                     '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'.
                     '<span class="LC_nobreak">';
       foreach my $field (@fields) {
           $datatable .= '<label>'.
                         '<input type="checkbox" name="ltitools_add_fields" value="'.$field.'" />'.
                         $lt{$field}.'</label>'.('&nbsp;' x2);
       }
       $datatable .= '</span></fieldset>'.
                     '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>';
       foreach my $role (@courseroles) {
           my ($checked,$checkednone);
           $datatable .= '<td style="text-align: center">'.
                         &Apache::lonnet::plaintext($role,'Course').'<br />'.
                         '<select name="ltitools_add_roles_'.$role.'">'.
                         '<option value="" selected="selected">'.&mt('Select').'</option>';
           foreach my $ltirole (@ltiroles) {
               $datatable .= '<option value="'.$ltirole.'">'.$ltirole.'</option>';
           }
           $datatable .= '</select></td>';
       }
       $datatable .= '</tr></table></fieldset>'.
                     '<fieldset><legend>'.&mt('Configurable in course').'</legend><span class="LC_nobreak">';
       foreach my $item ('label','title','target','linktext','explanation','append') {
           $datatable .= '<label>'.
                         '<input type="checkbox" name="ltitools_courseconfig" value="'.$item.'" checked="checked" />'.
                         $lt{'crs'.$item}.'</label>'.('&nbsp;' x2)."\n";
       }
       $datatable .= '</span></fieldset>'.
                     '<fieldset><legend>'.&mt('Custom items sent on launch').'</legend>'.
                     '<table><tr><th>'.&mt('Action').'</th><th>'.&mt('Name').'</th><th>'.&mt('Value').'</th></tr>'.
                     '<tr><td><span class="LC_nobreak">'.
                     '<label><input type="checkbox" name="ltitools_add_custom" value="1" />'.
                     &mt('Add').'</label></span></td><td><input type="text" name="ltitools_add_custom_name" />'.
                     '</td><td><input type="text" name="ltitools_add_custom_value" /></td></tr>'.
                     '</table></fieldset></td></tr>'."\n".
                     '</td>'."\n".
                     '</tr>'."\n";
       $itemcount ++;
     return $datatable;      return $datatable;
 }  }
   
 sub lti_names {  sub ltitools_names {
     my %lt = &Apache::lonlocal::texthash(      my %lt = &Apache::lonlocal::texthash(
                                           'version'   => 'LTI Version',                                            'title'          => 'Title',
                                           'url'       => 'URL',                                            'version'        => 'Version',
                                           'key'       => 'Key',                                            'msgtype'        => 'Message Type',
                                           'lifetime'  => 'Nonce lifetime (s)',                                            'url'            => 'URL',
                                           'consumer'  => 'Consumer',                                            'key'            => 'Key',
                                           'secret'    => 'Secret',                                            'secret'         => 'Secret',
                                           'requser'   => "User's identity sent",                                            'icon'           => 'Icon',   
                                           'crsinc'    => "Course's identity sent",                                            'user'           => 'Username:domain',
                                           'email'     => 'Email address',                                            'fullname'       => 'Full Name',
                                           'sourcedid' => 'User ID',                                            'firstname'      => 'First Name',
                                           'other'     => 'Other',                                            'lastname'       => 'Last Name',
                                           'passback'  => 'Can return grades to Consumer:',                                            'email'          => 'E-mail',
                                           'roster'    => 'Can retrieve roster from Consumer:',                                            'roles'          => 'Role',
                                           'topmenu'   => 'Display LON-CAPA page header',                                            'window'         => 'Window',
                                           'inlinemenu'=> 'Display LON-CAPA inline menu',                                            '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;      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 linkprot_suggestions {  
     my ($suggested,$itemcount) = @_;  
     my $count = 0;  
     my $next = 1;  
     my %lt = &Apache::lonlocal::texthash(  
                                           'name' => 'Suggested Launcher',  
                                           'info' => 'Recommendations',  
                                         );  
     my ($datatable,$css_class,$dest);  
     if (ref($suggested) eq 'HASH') {  
         my @current = sort { $a <=> $b } keys(%{$suggested});  
         $next += $current[-1];  
         for (my $i=0; $i<@current; $i++) {  
             my $num = $current[$i];  
             my %values;  
             if (ref($suggested->{$num}) eq 'HASH') {  
                 %values = %{$suggested->{$num}};  
             } else {  
                 next;  
             }  
             $css_class = $$itemcount%2?' class="LC_odd_row"':'';  
             $datatable .=  
                 '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".  
                 '<label><input type="checkbox" name="linkprot_suggested_del" value="'.$i.'" />'."\n".  
                 &mt('Delete?').'</label></span></td><td>'."\n".  
                 '<div class="LC_floatleft"><fieldset><legend>'.$lt{'name'}.'</legend>'."\n".  
                 '<input type="text" size="15" name="linkprot_suggested_name_'.$i.'" value="'.$values{'name'}.'" autocomplete="off" />'."\n".  
                 '</fieldset></div>'.  
                 '<div class="LC_floatleft"><fieldset><legend>'.$lt{'info'}.'</legend>'."\n".  
                 '<textarea cols="55" rows="5" name="linkprot_suggested_info_'.$i.'">'.$values{'info'}.'</textarea>'.  
                 '</fieldset></div>'.  
                 '<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n".  
                 '<input type="hidden" name="linkprot_suggested_id_'.$i.'" value="'.$num.'" /></td></tr>'."\n";  
             $$itemcount ++;  
         }  
     }  
     $css_class = $$itemcount%2?' class="LC_odd_row"':'';  
     $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".  
                   '<input type="hidden" name="linkprot_suggested_maxnum" value="'.$next.'" />'."\n".  
                   '<input type="checkbox" name="linkprot_suggested_add" value="1" />'.&mt('Add').'</span></td>'."\n".  
                   '<td>'."\n".  
                   '<div class="LC_floatleft"><fieldset><legend>'.$lt{'name'}.'</legend>'."\n".  
                   '<input type="text" size="15" name="linkprot_suggested_name_add" value="" autocomplete="off" />'."\n".  
                   '</fieldset></div>'.  
                   '<div class="LC_floatleft"><fieldset><legend>'.$lt{'info'}.'</legend>'."\n".  
                   '<textarea cols="55" rows="5" name="linkprot_suggested_info_add"></textarea>'.  
                   '</fieldset></div>'.  
                   '<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n".  
                   '</td></tr>'."\n";  
     return $datatable;  
 }  
   
 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 (MB)',  
         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',          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)",          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',          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)',  
         crseditors           => 'Available editors for web pages and/or problems created in a course/community',  
     );      );
     my %staticdefaults = (      my %staticdefaults = (
                              texengine            => 'MathJax',
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
                            coursequota          => 20,  
                            postsubmit           => 60,                             postsubmit           => 60,
                            mysqltables          => 172800,                             mysqltables          => 172800,
                            domexttool           => 1,  
                            exttool              => 0,  
                            crseditors           => ['edit','xml'],  
                          );                           );
     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',                              'canclone'        => 'none',
                           );                            );
         @toggles = ('uselcmath','usejsme','inline_chem');          @toggles = ('canuse_pdfforms','uselcmath','usejsme');
         my $deftex = $Apache::lonnet::deftex;          my $deftex = $staticdefaults{'texengine'};
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ($settings->{'texengine'}) {              if ($settings->{'texengine'}) {
                 if ($settings->{'texengine'} =~ /^(MathJax|mimetex|tth)$/) {                  if ($settings->{'texengine'} =~ /^(MathJax|mimetex|tth)$/) {
Line 6052  sub print_coursedefaults { Line 4287  sub print_coursedefaults {
         $datatable = $mathdisp.$datatable;          $datatable = $mathdisp.$datatable;
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $datatable .=          $datatable .=
             '<tr'.$css_class.'><td valign="top">'.              '<tr'.$css_class.'><td style="vertical-align: top">'.
             '<span class="LC_nobreak">'.$choices{'canclone'}.              '<span class="LC_nobreak">'.$choices{'canclone'}.
             '</span></td><td class="LC_left_item">';              '</span></td><td class="LC_left_item">';
         my $currcanclone = 'none';          my $currcanclone = 'none';
         my $onclick;          my $onclick;
         my @cloneoptions = ('none','domain');          my @cloneoptions = ('none','domain');
         my %clonetitles = &Apache::lonlocal::texthash (          my %clonetitles = (
                              none     => 'No additional course requesters',                               none     => 'No additional course requesters',
                              domain   => "Any course requester in course's domain",                               domain   => "Any course requester in course's domain",
                              instcode => 'Course requests for official courses ...',                               instcode => 'Course requests for official courses ...',
Line 6123  sub print_coursedefaults { Line 4358  sub print_coursedefaults {
         $itemcount ++;          $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,%currmysql);
             %deftimeout,%currmysql);  
         my $currusecredits = 0;          my $currusecredits = 0;
         my $postsubmitclient = 1;          my $postsubmitclient = 1;
         my $ltiauth = 0;          my @types = ('official','unofficial','community','textbook','placement');
         my %domexttool;  
         my %exttool;  
         my %crseditors;  
         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"';  
                     }  
                 }  
             }  
             if (ref($settings->{'crseditors'}) eq 'ARRAY') {  
                 foreach my $editor (@{$settings->{'crseditors'}}) {  
                     $crseditors{$editor} = ' checked="checked"';  
                 }  
             } else {  
                 foreach my $editor (@{$staticdefaults{'crseditors'}}) {  
                     $crseditors{$editor} = ' 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 6221  sub print_coursedefaults { Line 4414  sub print_coursedefaults {
         } 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"';  
                 }  
             }  
             foreach my $editor (@{$staticdefaults{'crseditors'}}) {  
                 $crseditors{$editor} = ' checked="checked"';  
             }              }
         }          }
         if (!$currdefresponder) {          if (!$currdefresponder) {
Line 6238  sub print_coursedefaults { Line 4425  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 6255  sub print_coursedefaults { Line 4439  sub print_coursedefaults {
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.          $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
                       $choices{'uploadquota'}.                        $choices{'uploadquota'}.
                       '</span></td>'.                        '</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="uploadquota_'.$type.'"'.  
                            ' value="'.$curruploadquota{$type}.'" size="5" /></td>';  
         }  
         $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{'coursequota'}.  
                       '</span></td>'.  
                       '<td style="text-align: right" class="LC_right_item">'.                        '<td style="text-align: right" class="LC_right_item">'.
                       '<table><tr>';                        '<table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.              $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="coursequota_'.$type.'"'.                             '<input type="text" name="uploadquota_'.$type.'"'.
                            ' value="'.$currcoursequota{$type}.'" size="5" /></td>';                             ' value="'.$curruploadquota{$type}.'" size="5" /></td>';
         }          }
         $datatable .= '</tr></table></td></tr>'."\n";          $datatable .= '</tr></table></td></tr>'."\n";
         $itemcount ++;          $itemcount ++;
Line 6286  sub print_coursedefaults { Line 4457  sub print_coursedefaults {
                          '<i>'.&mt('Default credits').'</i><br /><table><tr>';                           '<i>'.&mt('Default credits').'</i><br /><table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             next if ($type eq 'community');              next if ($type eq 'community');
             $additional .= '<td align="center">'.&mt($type).'<br />'.              $additional .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="'.$type.'_credits"'.                             '<input type="text" name="'.$type.'_credits"'.
                            ' value="'.$defcredits{$type}.'" size="3" /></td>';                             ' value="'.$defcredits{$type}.'" size="3" /></td>';
         }          }
Line 6310  sub print_coursedefaults { Line 4481  sub print_coursedefaults {
                       '<i>'.&mt('Enter 0 to remain disabled until page reload.').'</i><br />'.                        '<i>'.&mt('Enter 0 to remain disabled until page reload.').'</i><br />'.
                       '<table><tr>';                        '<table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             $additional .= '<td align="center">'.&mt($type).'<br />'.              $additional .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="'.$type.'_timeout" value="'.                             '<input type="text" name="'.$type.'_timeout" value="'.
                            $deftimeout{$type}.'" size="5" /></td>';                             $deftimeout{$type}.'" size="5" /></td>';
         }          }
Line 6328  sub print_coursedefaults { Line 4499  sub print_coursedefaults {
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.          $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
                       $choices{'mysqltables'}.                        $choices{'mysqltables'}.
                       '</span></td>'.                        '</span></td>'.
                       '<td align="right" class="LC_right_item">'.                        '<td style="text-align: right" class="LC_right_item">'.
                       '<table><tr>';                        '<table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             $datatable .= '<td align="center">'.&mt($type).'<br />'.              $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="mysqltables_'.$type.'"'.                             '<input type="text" name="mysqltables_'.$type.'"'.
                            ' value="'.$currmysql{$type}.'" size="8" /></td>';                             ' value="'.$currmysql{$type}.'" size="8" /></td>';
         }          }
         $datatable .= '</tr></table></td></tr>'."\n";          $datatable .= '</tr></table></td></tr>'."\n";
         $itemcount ++;          $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">'.  
                           '<label><input type="checkbox" name="domexttool"'.  
                           ' value="'.$type.'"'.$domexttool{$type}.' />'.  
                           &mt($type).'</label></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">'.  
                           '<label><input type="checkbox" name="exttool"'.  
                           ' value="'.$type.'"'.$exttool{$type}.' />'.  
                           &mt($type).'</label></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{'crseditors'}.  
                       '</span></td>'.  
                       '<td style="text-align: right" class="LC_right_item">'.  
                       '<table><tr>';  
         my @editors = ('edit','xml','daxe');  
         my %editornames = &crseditor_titles();  
         foreach my $editor (@editors) {  
             $datatable .= '<td style="text-align: left">'.  
                           '<span class="LC_nobreak">'.  
                           '<label><input type="checkbox" name="crseditors"'.  
                           ' value="'.$editor.'"'.$crseditors{$editor}.' />'.  
                           $editornames{$editor}.'</label></span></td>'."\n";  
         }  
         $datatable .= '</tr></table></td></tr>'."\n";  
     }  
     $$rowtotal += $itemcount;  
     return $datatable;  
 }  
   
 sub crseditor_titles {  
     return &Apache::lonlocal::texthash(  
                edit  => 'Standard editor (Edit)',  
                xml   => 'Text editor (EditXML)',  
                daxe  => 'Daxe editor (Daxe)',  
            );  
 }  
   
 sub print_authordefaults {  
     my ($position,$dom,$settings,$rowtotal) = @_;  
     my ($css_class,$datatable,%checkedon,%checkedoff);  
     my $itemcount = 1;  
     my %titles = &authordefaults_titles();  
     if ($position eq 'top') {  
         my %defaultchecked = (  
                             'nocodemirror' => 'off',  
                             'daxecollapse' => 'off',  
                             'domcoordacc'  => 'on',  
                           );  
         my @toggles = ('nocodemirror','daxecollapse','domcoordacc');  
         ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,  
                                                      \%titles,$itemcount);  
         my %staticdefaults = (  
                                 'copyright'    => 'default',  
                                 'sourceavail'  => 'closed',  
                              );  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         my %currrights;  
         foreach my $item ('copyright','sourceavail') {  
             $currrights{$item} = $staticdefaults{$item};  
             if (ref($settings) eq 'HASH') {  
                 if (exists($settings->{$item})) {  
                     $currrights{$item} = $settings->{$item};  
                 }  
             }  
         }  
         $datatable .= '<tr'.$css_class.'><td style="vertical-align: top">'.  
                       '<span class="LC_nobreak">'.$titles{'copyright'}.  
                       '</span></td><td class="LC_right_item">'.  
                       &selectbox('copyright',$currrights{'copyright'},'',  
                                  \&Apache::loncommon::copyrightdescription,  
                                  (grep !/^priv|custom$/,(&Apache::loncommon::copyrightids))).  
                       '</td></tr>'."\n";  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td style="vertical-align: top">'.  
                       '<span class="LC_nobreak">'.$titles{'sourceavail'}.  
                       '</span></td><td class="LC_right_item">'.  
                       &selectbox('sourceavail',$currrights{'sourceavail'},'',  
                                  \&Apache::loncommon::source_copyrightdescription,  
                                  (&Apache::loncommon::source_copyrightids)).  
                       '</td></tr>'."\n";  
     } else {  
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
         my $curreditors;  
         my %staticdefaults = (  
                                 editors => ['edit','xml'],  
                                 authorquota => 500,  
                                 webdav => 0,  
                              );  
         my $curreditors = $staticdefaults{'editors'};  
         if ((ref($settings) eq 'HASH') &&  
             (ref($settings->{'editors'}) eq 'ARRAY')) {  
             $curreditors = $settings->{'editors'};  
         } else {  
             $curreditors = $staticdefaults{'editors'};  
         }  
         my @editors = ('edit','xml','daxe');  
         $datatable = '<tr'.$css_class.'>'."\n".  
                      '<td>'.$titles{'editors'}.'</td>'."\n".  
                      '<td class="LC_left_item">'."\n".  
                      '<span class="LC_nobreak">';  
         foreach my $editor (@editors) {  
             my $checked;  
             if (grep(/^\Q$editor\E$/,@{$curreditors})) {  
                 $checked = ' checked="checked"';  
             }  
             $datatable .= '<label>'.  
                           '<input type="checkbox" name="author_editors" '.  
                           $checked.' value="'.$editor.'" '.  
                           'onclick="javascript:checkEditors(this.form,'."'author_editors'".',this);" />'.  
                           $titles{$editor}.'</label>&nbsp;';  
         }  
         $datatable .= '</span>'."\n".'</td>'."\n".'</tr>'."\n";  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
         my @insttypes;  
         if (ref($types) eq 'ARRAY') {  
             @insttypes = @{$types};  
         }  
         my $typecount = 0;  
         my %domconf = &Apache::lonnet::get_dom('configuration',['quotas'],$dom);  
         my @items = ('webdav','authorquota');  
         my %quotas;  
         if (ref($domconf{'quotas'}) eq 'HASH') {  
             %quotas = %{$domconf{'quotas'}};  
             foreach my $item (@items) {  
                 if (ref($quotas{$item}) eq 'HASH') {  
                     foreach my $type (@insttypes,'default') {  
                         if ($item eq 'authorquota') {  
                             if ($quotas{$item}{$type} !~ /^\d+$/) {  
                                 $quotas{$item}{$type} = $staticdefaults{$item};  
                             }  
                         } elsif ($item eq 'webdav') {  
                             if ($quotas{$item}{$type} !~ /^(0|1)$/) {  
                                 $quotas{$item}{$type} = $staticdefaults{$item};  
                             }  
                         }  
                     }  
                 } else {  
                     foreach my $type (@insttypes,'default') {  
                         $quotas{$item}{$type} = $staticdefaults{$item};  
                     }  
                 }  
             }  
         } else {  
             foreach my $item (@items) {  
                 foreach my $type (@insttypes,'default') {  
                     $quotas{$item}{$type} = $staticdefaults{$item};  
                 }  
             }  
         }  
         if (ref($usertypes) eq 'HASH') {  
             my $numinrow = 4;  
             my $onclick = '';  
             $datatable .= &insttypes_row(\%quotas,$types,$usertypes,$dom,  
                                          $numinrow,$othertitle,'authorquota',  
                                          \$itemcount,$onclick);  
             $itemcount ++;  
             $datatable .= &insttypes_row(\%quotas,$types,$usertypes,$dom,  
                                          $numinrow,$othertitle,'webdav',  
                                          \$itemcount);  
             $itemcount ++;  
         }  
         my $checkedno = ' checked="checked"';  
         my ($checkedon,$checkedoff);  
         if (ref($quotas{'webdav'}) eq 'HASH') {  
             if ($quotas{'webdav'}{'_LC_adv'} =~ /^0|1$/) {  
                 if ($quotas{'webdav'}{'_LC_adv'}) {  
                     $checkedon = $checkedno;  
                 } else {  
                     $checkedoff = $checkedno;  
                 }  
                 undef($checkedno);  
             }  
         }  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'>'.  
                       '<td>'.$titles{'webdav_LC_adv'}.'<br />'.  
                              $titles{'webdav_LC_adv_over'}.  
                       '</td>'.  
                       '<td class="LC_left_item">';  
         foreach my $option ('none','off','on') {  
             my ($text,$val,$checked);  
             if ($option eq 'none') {  
                 $text = $titles{'none'};  
                 $val = '';  
                 $checked = $checkedno;  
             } elsif ($option eq 'off') {  
                 $text = $titles{'overoff'};  
                 $val = 0;  
                 $checked = $checkedoff;  
             } elsif ($option eq 'on') {  
                 $text = $titles{'overon'};  
                 $val = 1;  
                 $checked = $checkedon;  
             }  
             $datatable .= '<span class="LC_nobreak"><label>'.  
                           '<input type="radio" name="webdav_LC_adv"'.  
                           ' value="'.$val.'"'.$checked.' />'.  
                           $text.'</label></span>&nbsp; ';  
         }  
         $datatable .= '</td></tr>';  
         $itemcount ++;  
         my %defchecked = (  
                                 'archive' => 'off',  
                              );  
         my @toggles = ('archive');  
         (my $archive,$itemcount) = &radiobutton_prefs($settings,['archive'],  
                                                       {'archive' => 'off'},  
                                                       \%titles,$itemcount);  
         $datatable .= $archive."\n";  
         $itemcount ++;  
     }      }
     $$rowtotal += $itemcount;      $$rowtotal += $itemcount;
     return $datatable;      return $datatable;
 }  }
   
 sub authordefaults_titles {  
     return &Apache::lonlocal::texthash(  
                copyright => 'Copyright/Distribution',  
                sourceavail => ' Source Available',  
                editors => 'Available Editors',  
                webdav => 'WebDAV',  
                authorquota => 'Authoring Space quotas (MB)',  
                nocodemirror => 'Deactivate CodeMirror for EditXML editor',  
                daxecollapse => 'Daxe editor: LON-CAPA standard menus start collapsed',  
                domcoordacc => 'Dom. Coords. can enter Authoring Spaces in domain',  
                edit  => 'Standard editor (Edit)',  
                xml   => 'Text editor (EditXML)',  
                daxe  => 'Daxe editor (Daxe)',  
                webdav_LC_adv => 'WebDAV access for LON-CAPA "advanced" users',  
                webdav_LC_adv_over => '(overrides access based on affiliation, if set)',  
                none => 'No override set',  
                overon => 'Override -- webDAV on',  
                overoff => 'Override -- webDAV off',  
                archive => 'Authors can download tar.gz file of Authoring Space',  
     );  
 }  
   
 sub selectbox {  
     my ($name,$value,$readonly,$functionref,@idlist)=@_;  
     my $selout = '<select name="'.$name.'">';  
     foreach my $id (@idlist) {  
         $selout.='<option value="'.$id.'"';  
         if ($id eq $value) {  
             $selout.=' selected="selected"';  
         }  
         if ($readonly) {  
             $selout .= ' disabled="disabled"';  
         }  
         $selout.='>'.&{$functionref}($id).'</option>';  
     }  
     $selout.='</select>';  
     return $selout;  
 }  
   
 sub print_selfenrollment {  sub print_selfenrollment {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable);      my ($css_class,$datatable);
     my $itemcount = 1;      my $itemcount = 1;
     my @types = ('official','unofficial','community','textbook');      my @types = ('official','unofficial','community','textbook','placement');
     if (($position eq 'top') || ($position eq 'middle')) {      if (($position eq 'top') || ($position eq 'middle')) {
         my ($rowsref,$titlesref) = &Apache::lonuserutils::get_selfenroll_titles();          my ($rowsref,$titlesref) = &Apache::lonuserutils::get_selfenroll_titles();
         my %descs = &Apache::lonuserutils::selfenroll_default_descs();          my %descs = &Apache::lonuserutils::selfenroll_default_descs();
Line 6813  sub print_validation_rows { Line 4702  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 6835  sub print_validation_rows { Line 4724  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 6850  sub print_validation_rows { Line 4739  sub print_validation_rows {
     return $datatable;      return $datatable;
 }  }
   
 sub print_passwords {  sub print_usersessions {
     my ($position,$dom,$confname,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($datatable,$css_class);      my ($css_class,$datatable,$itemcount,%checked,%choices);
     my $itemcount = 0;      my (%by_ip,%by_location,@intdoms,@instdoms);
     my %titles = &Apache::lonlocal::texthash (      &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
         captcha        => '"Forgot Password" CAPTCHA validation',  
         link           => 'Reset link expiration (hours)',      my @alldoms = &Apache::lonnet::all_domains();
         case           => 'Case-sensitive usernames/e-mail',      my %serverhomes = %Apache::lonnet::serverhomeIDs;
         prelink        => 'Information required (form 1)',      my %servers = &Apache::lonnet::internet_dom_servers($dom);
         postlink       => 'Information required (form 2)',      my %altids = &id_for_thisdom(%servers);
         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') {      if ($position eq 'top') {
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);          if (keys(%serverhomes) > 1) {
         my $shownlinklife = 2;              my %spareid = &current_offloads_to($dom,$settings,\%servers);
         my $prelink = 'both';              my $curroffloadnow;
         my (%casesens,%postlink,%emailsrc,$nostdtext,$customurl);              if (ref($settings) eq 'HASH') {
         if (ref($settings) eq 'HASH') {                  if (ref($settings->{'offloadnow'}) eq 'HASH') {
             if ($settings->{resetlink} =~ /^\d+(|\.\d*)$/) {                      $curroffloadnow = $settings->{'offloadnow'};
                 $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>';  
             }              }
         }              $datatable .= &spares_row($dom,\%servers,\%spareid,\%serverhomes,\%altids,$curroffloadnow,$rowtotal);
         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 {          } else {
             $datatable .='<span class="LC_nobreak">&nbsp;'.              $datatable .= '<tr'.$css_class.'><td colspan="2">'.
                          '<input type="file" name="passwords_customfile" /></span>';                            &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.').
         }                            '</td></tr>';
         $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 {      } else {
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);          my %titles = &usersession_titles();
         my %ownerchg = (          my ($prefix,@types);
                           by  => {},          if ($position eq 'bottom') {
                           for => {},              $prefix = 'remote';
                        );              @types = ('version','excludedomain','includedomain');
         my %ownertitles = &Apache::lonlocal::texthash (          } else {
                             by  => 'Course owner status(es) allowed',              $prefix = 'hosted';
                             for => 'Student status(es) allowed',              @types = ('excludedomain','includedomain');
                           );  
         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>'.          ($datatable,$itemcount) = &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
                       '<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;  
     }      }
       $$rowtotal += $itemcount;
     return $datatable;      return $datatable;
 }  }
   
 sub print_wafproxy {  sub rules_by_location {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($settings,$prefix,$by_location,$by_ip,$types,$titles) = @_; 
     my $css_class;      my ($datatable,$itemcount,$css_class);
     my $itemcount = 0;      if (keys(%{$by_location}) == 0) {
     my $datatable;          $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
     my %servers = &Apache::lonnet::internet_dom_servers($dom);          $datatable = '<tr'.$css_class.'><td colspan="2">'.
     my (%othercontrol,%otherdoms,%aliases,%saml,%values,$setdom,$showdom);                       &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.').
     my %lt = &wafproxy_titles();                       '</td></tr>';
     foreach my $server (sort(keys(%servers))) {          $itemcount = 1;
         my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});      } else {
         next if ($serverhome eq '');          $itemcount = 0;
         my $serverdom;          my $numinrow = 5;
         if ($serverhome ne $server) {          my (%current,%checkedon,%checkedoff);
             $serverdom = &Apache::lonnet::host_domain($serverhome);          my @locations = sort(keys(%{$by_location}));
             if (($serverdom ne '') && (&Apache::lonnet::domain($serverdom) ne '')) {          foreach my $type (@{$types}) {
                 $othercontrol{$server} = $serverdom;              $checkedon{$type} = '';
             }              $checkedoff{$type} = ' checked="checked"';
         } 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') {          if (ref($settings) eq 'HASH') {
             foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') {              if (ref($settings->{$prefix}) eq 'HASH') {
                 $values{$dom}{$item} = $settings->{$item};                  foreach my $key (keys(%{$settings->{$prefix}})) {
             }                      $current{$key} = $settings->{$prefix}{$key};
         }                      if ($key eq 'version') {
     }                          if ($current{$key} ne '') {
     if (keys(%othercontrol)) {                              $checkedon{$key} = ' checked="checked"';
         %otherdoms = reverse(%othercontrol);                              $checkedoff{$key} = '';
         foreach my $domain (keys(%otherdoms)) {                          }
             %{$values{$domain}} = ();                      } elsif (ref($current{$key}) eq 'ARRAY') {
             my %config = &Apache::lonnet::get_dom('configuration',['wafproxy'],$domain);                          $checkedon{$key} = ' checked="checked"';
             if (ref($config{'wafproxy'}) eq 'HASH') {                          $checkedoff{$key} = '';
                 $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').': '.  
                             '<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 {          foreach my $type (@{$types}) {
         my %ip_methods = &remoteip_methods();              next if ($type ne 'version' && !@locations);
         if ($setdom) {  
             $itemcount ++;  
             $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';              $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
             my ($nowafstyle,$wafstyle,$curr_remotip,$currwafdisplay,$vpndircheck,$vpnaliascheck,              $datatable .= '<tr'.$css_class.'>
                 $currwafvpn,$wafrangestyle,$alltossl,$ssltossl);                             <td><span class="LC_nobreak">'.$titles->{$type}.'</span><br />
             $wafstyle = ' style="display:none;"';                             <span class="LC_nobreak">&nbsp;
             $nowafstyle = ' style="display:table-row;"';                             <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedoff{$type}.' value="0" />'.&mt('Not in use').'</label>&nbsp;
             $currwafdisplay = ' style="display: none"';                             <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedon{$type}.' value="1" />'.&mt('In use').'</label></span></td><td>';
             $wafrangestyle = ' style="display: none"';              if ($type eq 'version') {
             $curr_remotip = 'n';                  my @lcversions = &Apache::lonnet::all_loncaparevs();
             $ssltossl = ' checked="checked"';                  my $selector = '<select name="'.$prefix.'_version">';
             if ($showdom) {                  foreach my $version (@lcversions) {
                 $wafstyle = ' style="display:table-row;"';                      my $selected = '';
                 $nowafstyle =  ' style="display:none;"';                      if ($current{'version'} eq $version) {
                 if (keys(%{$values{$dom}})) {                          $selected = ' selected="selected"';
                     if ($values{$dom}{remoteip} =~ /^[nmh]$/) {                      }
                         $curr_remotip = $values{$dom}{remoteip};                      $selector .= ' <option value="'.$version.'"'.
                     }                                   $selected.'>'.$version.'</option>';
                     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;"';  
                 }                  }
             }                  $selector .= '</select> ';
             $datatable .= '<tr'.$css_class.' id="nowafproxyrow_'.$dom.'"'.$wafstyle.'>'.                  $datatable .= &mt('remote server must be version: [_1] or later',$selector);
                           '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'</td>'.              } else {
                           '<td class="LC_right_item">'.&mt('WAF not in use, nothing to set').'</td>'.                  $datatable.= '<div><input type="button" value="'.&mt('check all').'" '.
                           '</tr>'.                               'onclick="javascript:checkAll(document.display.'.$prefix.'_'.$type.')"'.
                           '<tr'.$css_class.' id="wafproxyrow_'.$dom.'"'.$wafstyle.'>'.                               ' />'.('&nbsp;'x2).
                           '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'<br /><br />'.                               '<input type="button" value="'.&mt('uncheck all').'" '.
                           '<div id="wafproxyranges_'.$dom.'">'.&mt('Format for comma separated IP ranges').':<br />'.                               'onclick="javascript:uncheckAll(document.display.'.$prefix.'_'.$type.')" />'.
                           &mt('A.B.C.D/N or A.B.C.D-E.F.G.H').'<br />'.                               "\n".
                           &mt('Range(s) stored in CIDR notation').'</div></td>'.                               '</div><div><table>';
                           '<td class="LC_left_item"><table>'.                  my $rem;
                           '<tr>'.                  for (my $i=0; $i<@locations; $i++) {
                           '<td valign="top">'.$lt{'remoteip'}.':&nbsp;'.                      my ($showloc,$value,$checkedtype);
                           '<select name="wafproxy_remoteip" id="wafproxy_remoteip" onchange="javascript:updateWAF();">';                      if (ref($by_location->{$locations[$i]}) eq 'ARRAY') {
             foreach my $option ('m','h','n') {                          my $ip = $by_location->{$locations[$i]}->[0];
                 my $sel;                          if (ref($by_ip->{$ip}) eq 'ARRAY') {
                 if ($option eq $curr_remotip) {                              $value = join(':',@{$by_ip->{$ip}});
                    $sel = ' selected="selected"';                              $showloc = join(', ',@{$by_ip->{$ip}});
                 }                              if (ref($current{$type}) eq 'ARRAY') {
                 $datatable .= '<option value="'.$option.'"'.$sel.'>'.                                  foreach my $loc (@{$by_ip->{$ip}}) {
                               $ip_methods{$option}.'</option>';                                      if (grep(/^\Q$loc\E$/,@{$current{$type}})) {
             }                                          $checkedtype = ' checked="checked"';
             $datatable .= '</select></td></tr>'."\n".                                          last;
                           '<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>'.                      $rem = $i%($numinrow);
                                   '<td>'.$lt{$item}.':&nbsp;'.$showval.'</td></tr>';                      if ($rem == 0) {
                           if ($i > 0) {
                               $datatable .= '</tr>';
                           }
                           $datatable .= '<tr>';
                       }
                       $datatable .= '<td class="LC_left_item">'.
                                     '<span class="LC_nobreak"><label>'.
                                     '<input type="checkbox" name="'.$prefix.'_'.$type.
                                     '" value="'.$value.'"'.$checkedtype.' />'.$showloc.
                                     '</label></span></td>';
                 }                  }
                 $datatable .= '</table></td></tr>';                  $rem = @locations%($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 .= '</tr></table>';
             }              }
               $datatable .= '</td></tr>';
               $itemcount ++;
         }          }
     }      }
     $$rowtotal += $itemcount;      return ($datatable,$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_ssl {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable,%checked,%choices);      my ($css_class,$datatable);
     my (%by_ip,%by_location,@intdoms);  
     &build_location_hashes(\@intdoms,\%by_ip,\%by_location);  
   
     my @alldoms = &Apache::lonnet::all_domains();  
     my %serverhomes = %Apache::lonnet::serverhomeIDs;  
     my %servers = &Apache::lonnet::internet_dom_servers($dom);  
     my %altids = &id_for_thisdom(%servers);  
     my $itemcount = 1;      my $itemcount = 1;
     if ($position eq 'top') {      if ($position eq 'top') {
         if (keys(%serverhomes) > 1) {          my $primary_id = &Apache::lonnet::domain($dom,'primary');
             my %spareid = &current_offloads_to($dom,$settings,\%servers);          my $intdom = &Apache::lonnet::internet_dom($primary_id);
             my ($curroffloadnow,$curroffloadoth);          my $same_institution;
             if (ref($settings) eq 'HASH') {          if ($intdom ne '') {
                 if (ref($settings->{'offloadnow'}) eq 'HASH') {              my $internet_names = &Apache::lonnet::get_internet_names($Apache::lonnet::perlvar{'lonHostID'});
                     $curroffloadnow = $settings->{'offloadnow'};              if (ref($internet_names) eq 'ARRAY') {
                 }                  if (grep(/^\Q$intdom\E$/,@{$internet_names})) {
                 if (ref($settings->{'offloadoth'}) eq 'HASH') {                      $same_institution = 1;
                     $curroffloadoth = $settings->{'offloadoth'};  
                 }                  }
             }              }
             my $other_insts = scalar(keys(%by_location));          }
             $datatable .= &spares_row($dom,\%servers,\%spareid,\%serverhomes,\%altids,          $css_class = $itemcount%2?' class="LC_odd_row"':'';
                                       $other_insts,$curroffloadnow,$curroffloadoth,$rowtotal);          $datatable = '<tr'.$css_class.'><td colspan="2">';
           if ($same_institution) {
               my %domservers = &Apache::lonnet::get_servers($dom);
               $datatable .= &LONCAPA::SSL::print_certstatus(\%domservers,'web','domprefs');
         } else {          } else {
             $datatable .= '<tr'.$css_class.'><td colspan="2">'.              $datatable .= &mt("You need to be logged into one of your own domain's servers to display information about the status of LON-CAPA SSL certificates.");
                           &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.').  
                           '</td></tr>';  
         }          }
           $datatable .= '</td></tr>';
           $itemcount ++;
     } else {      } else {
         if (keys(%by_location) == 0) {          my %titles = &ssl_titles();
             $datatable .= '<tr'.$css_class.'><td colspan="2">'.          my (%by_ip,%by_location,@intdoms,@instdoms);
                           &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.').          &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
                           '</td></tr>';          my @alldoms = &Apache::lonnet::all_domains();
         } else {          my %serverhomes = %Apache::lonnet::serverhomeIDs;
             my %lt = &usersession_titles();          my @domservers = &Apache::lonnet::get_servers($dom);
             my $numinrow = 5;          my %servers = &Apache::lonnet::internet_dom_servers($dom);
             my $prefix;          my %altids = &id_for_thisdom(%servers);
             my @types;          if (($position eq 'connto') || ($position eq 'connfrom')) {
             if ($position eq 'bottom') {              my $legacy;
                 $prefix = 'remote';              unless (ref($settings) eq 'HASH') {
                 @types = ('version','excludedomain','includedomain');                  my $name;
             } else {                  if ($position eq 'connto') {
                 $prefix = 'hosted';                      $name = 'loncAllowInsecure';
                 @types = ('excludedomain','includedomain');                  } else {
             }                      $name = 'londAllowInsecure';
             my (%current,%checkedon,%checkedoff);                  }
             my @lcversions = &Apache::lonnet::all_loncaparevs();                  my $primarylibserv = &Apache::lonnet::domain($dom,'primary');
             my @locations = sort(keys(%by_location));                  my @ids=&Apache::lonnet::current_machine_ids();
             foreach my $type (@types) {                  if (($primarylibserv ne '') && (!grep(/^\Q$primarylibserv\E$/,@ids))) {
                 $checkedon{$type} = '';                      my %what = (
                 $checkedoff{$type} = ' checked="checked"';                                     $name => 1,
             }                                 );
             if (ref($settings) eq 'HASH') {                      my ($result,$returnhash) =
                 if (ref($settings->{$prefix}) eq 'HASH') {                          &Apache::lonnet::get_remote_globals($primarylibserv,\%what);
                     foreach my $key (keys(%{$settings->{$prefix}})) {                      if ($result eq 'ok') {
                         $current{$key} = $settings->{$prefix}{$key};                          if (ref($returnhash) eq 'HASH') {
                         if ($key eq 'version') {                              $legacy = $returnhash->{$name};
                             if ($current{$key} ne '') {  
                                 $checkedon{$key} = ' checked="checked"';  
                                 $checkedoff{$key} = '';  
                             }  
                         } elsif (ref($current{$key}) eq 'ARRAY') {  
                             $checkedon{$key} = ' checked="checked"';  
                             $checkedoff{$key} = '';  
                         }                          }
                     }                      }
                   } else {
                       $legacy = $Apache::lonnet::perlvar{$name};
                 }                  }
             }              }
             foreach my $type (@types) {              foreach my $type ('dom','intdom','other') {
                 next if ($type ne 'version' && !@locations);                  my %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>'.$titles{$type}.'</td>'.
                                <td><span class="LC_nobreak">'.$lt{$type}.'</span><br />                                '<td class="LC_right_item">';
                                <span class="LC_nobreak">&nbsp;                  my $skip; 
                                <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedoff{$type}.' value="0" />'.&mt('Not in use').'</label>&nbsp;                  if ($type eq 'dom') {
                                <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedon{$type}.' value="1" />'.&mt('In use').'</label></span></td><td>';                      unless (keys(%servers) > 1) {
                 if ($type eq 'version') {                          $datatable .= &mt('Nothing to set here, as there are no other servers/VMs');    
                     my $selector = '<select name="'.$prefix.'_version">';                          $skip = 1;
                     foreach my $version (@lcversions) {  
                         my $selected = '';  
                         if ($current{'version'} eq $version) {  
                             $selected = ' selected="selected"';  
                         }  
                         $selector .= ' <option value="'.$version.'"'.  
                                      $selected.'>'.$version.'</option>';  
                     }                      }
                     $selector .= '</select> ';                  }
                     $datatable .= &mt('remote server must be version: [_1] or later',$selector);                  if ($type eq 'intdom') {
                 } else {                      unless (@instdoms > 1) {
                     $datatable.= '<div><input type="button" value="'.&mt('check all').'" '.                          $datatable .= &mt('Nothing to set here, as there are no other domains for this institution');
                                  'onclick="javascript:checkAll(document.display.'.$prefix.'_'.$type.')"'.                          $skip = 1;
                                  ' />'.('&nbsp;'x2).                      } 
                                  '<input type="button" value="'.&mt('uncheck all').'" '.                  } elsif ($type eq 'other') {
                                  'onclick="javascript:uncheckAll(document.display.'.$prefix.'_'.$type.')" />'.                      if (keys(%by_location) == 0) {
                                  "\n".                          $datatable .= &mt('Nothing to set here, as there are no other institutions');
                                  '</div><div><table>';                          $skip = 1;
                     my $rem;                      }
                     for (my $i=0; $i<@locations; $i++) {                  }
                         my ($showloc,$value,$checkedtype);                  unless ($skip) {
                         if (ref($by_location{$locations[$i]}) eq 'ARRAY') {                      $checked{'yes'} = ' checked="checked"'; 
                             my $ip = $by_location{$locations[$i]}->[0];                      if (ref($settings) eq 'HASH') {
                             if (ref($by_ip{$ip}) eq 'ARRAY') {                          if (ref($settings->{$position}) eq 'HASH') {
                                  $value = join(':',@{$by_ip{$ip}});                              if ($settings->{$position}->{$type} =~ /^(no|req)$/) {
                                 $showloc = join(', ',@{$by_ip{$ip}});                                  $checked{$1} = $checked{'yes'};
                                 if (ref($current{$type}) eq 'ARRAY') {                                  delete($checked{'yes'}); 
                                     foreach my $loc (@{$by_ip{$ip}}) {    
                                         if (grep(/^\Q$loc\E$/,@{$current{$type}})) {  
                                             $checkedtype = ' checked="checked"';  
                                             last;  
                                         }  
                                     }  
                                 }  
                             }                              }
                         }                          }
                         $rem = $i%($numinrow);                      } else {
                         if ($rem == 0) {                          if ($legacy == 0) {
                             if ($i > 0) {                              $checked{'req'} = $checked{'yes'};
                                 $datatable .= '</tr>';                              delete($checked{'yes'});    
                             }                          }
                             $datatable .= '<tr>';  
                         }  
                         $datatable .= '<td class="LC_left_item">'.  
                                       '<span class="LC_nobreak"><label>'.  
                                       '<input type="checkbox" name="'.$prefix.'_'.$type.  
                                       '" value="'.$value.'"'.$checkedtype.' />'.$showloc.  
                                       '</label></span></td>';  
                     }                      }
                     $rem = @locations%($numinrow);                      foreach my $option ('no','yes','req') {
                     my $colsleft = $numinrow - $rem;                          $datatable .= '<span class="LC_nobreak"><label>'.
                     if ($colsleft > 1 ) {                                        '<input type="radio" name="'.$position.'_'.$type.'" '.
                         $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.                                        'value="'.$option.'"'.$checked{$option}.' />'.$titles{$option}.
                                       '&nbsp;</td>';                                        '</label></span>'.('&nbsp;'x2);
                     } elsif ($colsleft == 1) {  
                         $datatable .= '<td class="LC_left_item">&nbsp;</td>';  
                     }                      }
                     $datatable .= '</tr></table>';  
                 }                  }
                 $datatable .= '</td></tr>';                  $datatable .= '</td></tr>';
                   $itemcount ++; 
               }
           } else {
               my $prefix = 'replication';
               my @types = ('certreq','nocertreq');
               if (keys(%by_location) == 0) {
                   $datatable .= '<tr'.$css_class.'><td>'.
                                 &mt('Nothing to set here, as there are no other institutions').
                                 '</td></tr>';
                 $itemcount ++;                  $itemcount ++;
               } else {
                   ($datatable,$itemcount) = 
                       &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
             }              }
         }          }
     }      }
Line 7763  sub print_usersessions { Line 5018  sub print_usersessions {
     return $datatable;      return $datatable;
 }  }
   
   sub ssl_titles {
       return &Apache::lonlocal::texthash (
                  dom           => 'LON-CAPA servers/VMs from same domain',
                  intdom        => 'LON-CAPA servers/VMs from same "internet" domain',
                  other         => 'External LON-CAPA servers/VMs',
                  connto        => 'Connections to other servers',
                  connfrom      => 'Connections from other servers',
                  replication   => 'Replicating content to other institutions',
                  certreq       => 'Client certificate required, but specific domains exempt',
                  nocertreq     => 'No client certificate required, except for specific domains',
                  no            => 'SSL not used',
                  yes           => 'SSL Optional (used if available)',
                  req           => 'SSL Required',
       );
   }
   
   sub print_trust {
       my ($prefix,$dom,$settings,$rowtotal) = @_;
       my ($css_class,$datatable,%checked,%choices);
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
       my $itemcount = 1;
       my %titles = &trust_titles();
       my @types = ('exc','inc');
       if ($prefix eq 'top') {
           $prefix = 'content';
       } elsif ($prefix eq 'bottom') {
           $prefix = 'msg';
       }
       ($datatable,$itemcount) = &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
       $$rowtotal += $itemcount;
       return $datatable;
   }
   
   sub trust_titles {
       return &Apache::lonlocal::texthash(
                  content  => "Access to this domain's content by others",
                  shared   => "Access to other domain's content by this domain",
                  enroll   => "Enrollment in this domain's courses by others", 
                  othcoau  => "Co-author roles in this domain for others",
                  coaurem  => "Co-author roles for this domain's users elsewhere", 
                  domroles => "Domain roles in this domain assignable to others",
                  catalog  => "Course Catalog for this domain displayed elsewhere",
                  reqcrs   => "Requests for creation of courses in this domain by others",
                  msg      => "Users in other domains can send messages to this domain",
                  exc      => "Allow all, but exclude specific domains",
                  inc      => "Deny all, but include specific domains",
              );
   } 
   
 sub build_location_hashes {  sub build_location_hashes {
     my ($intdoms,$by_ip,$by_location) = @_;      my ($intdoms,$by_ip,$by_location,$instdoms) = @_;
     return unless((ref($intdoms) eq 'ARRAY') && (ref($by_ip) eq 'HASH') &&      return unless((ref($intdoms) eq 'ARRAY') && (ref($by_ip) eq 'HASH') &&
                   (ref($by_location) eq 'HASH'));                     (ref($by_location) eq 'HASH') && (ref($instdoms) eq 'ARRAY'));
     my %iphost = &Apache::lonnet::get_iphost();      my %iphost = &Apache::lonnet::get_iphost();
     my $primary_id = &Apache::lonnet::domain($env{'request.role.domain'},'primary');      my $primary_id = &Apache::lonnet::domain($env{'request.role.domain'},'primary');
     my $primary_ip = &Apache::lonnet::get_host_ip($primary_id);      my $primary_ip = &Apache::lonnet::get_host_ip($primary_id);
Line 7783  sub build_location_hashes { Line 5088  sub build_location_hashes {
             foreach my $id (@{$iphost{$ip}}) {              foreach my $id (@{$iphost{$ip}}) {
                 my $location = &Apache::lonnet::internet_dom($id);                  my $location = &Apache::lonnet::internet_dom($id);
                 if ($location) {                  if ($location) {
                     next if (grep(/^\Q$location\E$/,@{$intdoms}));                      if (grep(/^\Q$location\E$/,@{$intdoms})) {
                           my $dom = &Apache::lonnet::host_domain($id);
                           unless (grep(/^\Q$dom\E/,@{$instdoms})) {
                               push(@{$instdoms},$dom);
                           }
                           next;
                       }
                     if (ref($by_ip->{$ip}) eq 'ARRAY') {                      if (ref($by_ip->{$ip}) eq 'ARRAY') {
                         unless(grep(/^\Q$location\E$/,@{$by_ip->{$ip}})) {                          unless(grep(/^\Q$location\E$/,@{$by_ip->{$ip}})) {
                             push(@{$by_ip->{$ip}},$location);                              push(@{$by_ip->{$ip}},$location);
Line 7891  sub current_offloads_to { Line 5202  sub current_offloads_to {
 }  }
   
 sub spares_row {  sub spares_row {
     my ($dom,$servers,$spareid,$serverhomes,$altids,$other_insts,      my ($dom,$servers,$spareid,$serverhomes,$altids,$curroffloadnow,$rowtotal) = @_;
         $curroffloadnow,$curroffloadoth,$rowtotal) = @_;  
     my $css_class;      my $css_class;
     my $numinrow = 4;      my $numinrow = 4;
     my $itemcount = 1;      my $itemcount = 1;
Line 7912  sub spares_row { Line 5222  sub spares_row {
                 }                  }
             }              }
             next unless (ref($spareid->{$server}) eq 'HASH');              next unless (ref($spareid->{$server}) eq 'HASH');
             my ($checkednow,$checkedoth);              my $checkednow;
             if (ref($curroffloadnow) eq 'HASH') {              if (ref($curroffloadnow) eq 'HASH') {
                 if ($curroffloadnow->{$server}) {                  if ($curroffloadnow->{$server}) {
                     $checkednow = ' checked="checked"';                      $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">
Line 7931  sub spares_row { Line 5236  sub spares_row {
                               ,'<b>'.$server.'</b>').'</span><br />'.                                ,'<b>'.$server.'</b>').'</span><br />'.
                           '<span class="LC_nobreak">'."\n".                            '<span class="LC_nobreak">'."\n".
                           '<label><input type="checkbox" name="offloadnow" value="'.$server.'"'.$checkednow.' />'.                            '<label><input type="checkbox" name="offloadnow" value="'.$server.'"'.$checkednow.' />'.
                           '&nbsp;'.&mt('Switch any active user on next access').'</label></span>'.                            '&nbsp;'.&mt('Switch active users on next access').'</label></span>'.
                           "\n";                            "\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";  
             }  
             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 8063  sub print_loadbalancing { Line 5361  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 8103  sub print_loadbalancing { Line 5401  sub print_loadbalancing {
         my $disabled_div_style = 'display: block';          my $disabled_div_style = 'display: block';
         my $homedom_div_style = 'display: none';          my $homedom_div_style = 'display: none';
         $datatable .= '<tr class="'.$css_class[$cssidx].'">'.          $datatable .= '<tr class="'.$css_class[$cssidx].'">'.
                       '<td rowspan="'.$rownum.'" valign="top">'.                        '<td rowspan="'.$rownum.'" style="vertical-align: top">'.
                       '<p>';                        '<p>';
         if ($lonhost eq '') {          if ($lonhost eq '') {
             $datatable .= '<span class="LC_nobreak">';              $datatable .= '<span class="LC_nobreak">';
Line 8136  sub print_loadbalancing { Line 5434  sub print_loadbalancing {
                 $homedom_div_style = 'display: block';                  $homedom_div_style = 'display: block';
             }              }
         }          }
         $datatable .= '</p></td><td rowspan="'.$rownum.'" valign="top">'.          $datatable .= '</p></td><td rowspan="'.$rownum.'" style="vertical-align: top">'.
                   '<div id="loadbalancing_disabled_'.$balnum.'" style="'.                    '<div id="loadbalancing_disabled_'.$balnum.'" style="'.
                   $disabled_div_style.'">'.$disabledtext.'</div>'."\n".                    $disabled_div_style.'">'.$disabledtext.'</div>'."\n".
                   '<div id="loadbalancing_targets_'.$balnum.'" style="'.$targets_div_style.'">'.&mt('Offloads to:').'<br />';                    '<div id="loadbalancing_targets_'.$balnum.'" style="'.$targets_div_style.'">'.&mt('Offloads to:').'<br />';
Line 8146  sub print_loadbalancing { Line 5444  sub print_loadbalancing {
         my %hostherechecked = (          my %hostherechecked = (
                                   no => ' checked="checked"',                                    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 8204  sub print_loadbalancing { Line 5499  sub print_loadbalancing {
                 }                  }
             }              }
         }          }
         if ($currcookies{$lonhost}) {  
             %balcookiechecked = (  
                                     yes => ' checked="checked"',  
                                 );  
         }  
         $datatable .= &mt('Hosting on balancer itself').'<br />'.          $datatable .= &mt('Hosting on balancer itself').'<br />'.
                       '<label><input type="radio" name="loadbalancing_target_'.$balnum.'_hosthere" value="no"'.                        '<label><input type="radio" name="loadbalancing_target_'.$balnum.'_hosthere" value="no"'.
                       $hostherechecked{'no'}.' />'.&mt('No').'</label><br />';                        $hostherechecked{'no'}.' />'.&mt('No').'</label><br />';
Line 8217  sub print_loadbalancing { Line 5507  sub print_loadbalancing {
                           'value="'.$sparetype.'"'.$hostherechecked{$sparetype}.' /><i>'.$typetitles{$sparetype}.                            'value="'.$sparetype.'"'.$hostherechecked{$sparetype}.' /><i>'.$typetitles{$sparetype}.
                           '</i></label><br />';                            '</i></label><br />';
         }          }
         $datatable .= &mt('Use balancer cookie').'<br />'.          $datatable .= '</div></td></tr>'.
                       '<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 8236  sub print_loadbalancing { Line 5521  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 8259  sub get_loadbalancers_config { Line 5543  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 8368  sub loadbalance_rule_row { Line 5649  sub loadbalance_rule_row {
         $space = '<div style="display:inline-block;">&nbsp;</div>';          $space = '<div style="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 style="vertical-align: top">'.$space.
         '<div id="balanceruletitle_'.$balnum.'_'.$type.'" style="'.$style.'">'.$title.'</div></td>'."\n".          '<div id="balanceruletitle_'.$balnum.'_'.$type.'" style="'.$style.'">'.$title.'</div></td>'."\n".
         '<td valaign="top">'.$space.          '<td valaign="top">'.$space.
         '<div id="balancerule_'.$balnum.'_'.$type.'" style="'.$style.'">'."\n";          '<div id="balancerule_'.$balnum.'_'.$type.'" style="'.$style.'">'."\n";
Line 8457  sub contact_titles { Line 5738  sub contact_titles {
                    '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 8502  sub tool_titles { Line 5778  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',
                      portfolio  => 'Portfolio',                       portfolio  => 'Portfolio',
                      portaccess => 'Share portfolio files',  
                      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',
                      textbook   => 'Textbook courses',                       textbook   => 'Textbook courses',
                        placement  => 'Placement tests',
                  );                   );
     return %titles;      return %titles;
 }  }
Line 8519  sub courserequest_titles { Line 5795  sub courserequest_titles {
                                    unofficial => 'Unofficial',                                     unofficial => 'Unofficial',
                                    community  => 'Communities',                                     community  => 'Communities',
                                    textbook   => 'Textbook',                                     textbook   => 'Textbook',
                                    lti        => 'LTI Provider',                                     placement  => 'Placement tests',
                                    norequest  => 'Not allowed',                                     norequest  => 'Not allowed',
                                    approval   => 'Approval by Dom. Coord.',                                     approval   => 'Approval by Dom. Coord.',
                                    validate   => 'With validation',                                     validate   => 'With validation',
Line 8610  sub print_usercreation { Line 5886  sub print_usercreation {
             }              }
             $datatable .= '<tr'.$css_class.'>'.              $datatable .= '<tr'.$css_class.'>'.
                          '<td><span class="LC_nobreak">'.$lt{$item}.                           '<td><span class="LC_nobreak">'.$lt{$item}.
                          '</span></td><td align="right">';                           '</span></td><td style="text-align: right">';
             my @options = ('any');              my @options = ('any');
             if (ref($rules) eq 'HASH') {              if (ref($rules) eq 'HASH') {
                 if (keys(%{$rules}) > 0) {                  if (keys(%{$rules}) > 0) {
Line 8633  sub print_usercreation { Line 5909  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 8732  sub print_selfcreation { Line 6008  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;
           
         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,
Line 8750  sub print_selfcreation { Line 6026  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 8869  sub print_selfcreation { Line 6145  sub print_selfcreation {
                 my $currstyle = 'display:none';                  my $currstyle = 'display:none';
                 if (grep(/^\Q$status\E$/,@ordered)) {                  if (grep(/^\Q$status\E$/,@ordered)) {
                     $currstyle = $rowstyle;                      $currstyle = $rowstyle;
                     $hidden = 0;                      $hidden = 0; 
                 }                  }
                 $datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain,                  $datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain,
                                              $emailrules,$emailruleorder,$settings,$status,$rowid,                                               $emailrules,$emailruleorder,$settings,$status,$rowid,
Line 8896  sub print_selfcreation { Line 6172  sub print_selfcreation {
             foreach my $status (@posstypes) {              foreach my $status (@posstypes) {
                 my $rowid = $classprefix.$status;                  my $rowid = $classprefix.$status;
                 my $datarowstyle = 'display:none';                  my $datarowstyle = 'display:none';
                 if (grep(/^\Q$status\E$/,@ordered)) {                  if (grep(/^\Q$status\E$/,@ordered)) { 
                     $datarowstyle = $rowstyle;                      $datarowstyle = $rowstyle; 
                 }                  }
                 $datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings,                  $datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings,
                                                        $numinrow,$$rowtotal,\%usertypeshash,$infofields,                                                         $numinrow,$$rowtotal,\%usertypeshash,$infofields,
Line 8999  function toggleEmailOptions(form,radio,p Line 6275  function toggleEmailOptions(form,radio,p
                     document.getElementById(altprefix+'_inst_'+status).style.display = 'none';                      document.getElementById(altprefix+'_inst_'+status).style.display = 'none';
                     document.getElementById(altprefix+'_noninst_'+status).style.display = 'none';                      document.getElementById(altprefix+'_noninst_'+status).style.display = 'none';
                     if (curr == 'custom') {                      if (curr == 'custom') {
                         if (prefix) {                          if (prefix) { 
                             document.getElementById(prefix+'_'+status).style.display = 'inline';                              document.getElementById(prefix+'_'+status).style.display = 'inline';
                         }                          }
                     } else if (curr == 'inst') {                      } else if (curr == 'inst') {
Line 9022  ENDSCRIPT Line 6298  ENDSCRIPT
   
 sub noninst_users {  sub noninst_users {
     my ($processing,$emailverified,$emailoptions,$emaildomain,$emailrules,      my ($processing,$emailverified,$emailoptions,$emaildomain,$emailrules,
         $emailruleorder,$settings,$type,$rowid,$typetitle,$css_class,$rowstyle,$intdom) = @_;          $emailruleorder,$settings,$type,$rowid,$typetitle,$css_class,$rowstyle,$intdom) = @_; 
     my $class = 'LC_left_item';      my $class = 'LC_left_item';
     if ($css_class) {      if ($css_class) {
         $css_class = ' class="'.$css_class.'"';          $css_class = ' class="'.$css_class.'"'; 
     }      }
     if ($rowid) {      if ($rowid) {
         $rowid = ' id="'.$rowid.'"';          $rowid = ' id="'.$rowid.'"';
Line 9040  sub noninst_users { Line 6316  sub noninst_users {
         $description = &mt('Requests for: [_1] (status self-reported)',$typetitle);          $description = &mt('Requests for: [_1] (status self-reported)',$typetitle);
     }      }
     $output = '<tr'.$css_class.$rowid.$rowstyle.'>'.      $output = '<tr'.$css_class.$rowid.$rowstyle.'>'.
               "<td>$description</td>\n".                "<td>$description</td>\n".           
               '<td class="'.$class.'" colspan="2">'.                '<td class="'.$class.'" colspan="2">'.
               '<table><tr>';                '<table><tr>';
     my %headers = &Apache::lonlocal::texthash(      my %headers = &Apache::lonlocal::texthash( 
               approve  => 'Processing',                approve  => 'Processing',
               email    => 'E-mail',                email    => 'E-mail',
               username => 'Username',                username => 'Username',
Line 9053  sub noninst_users { Line 6329  sub noninst_users {
     }      }
     $output .= '</tr><tr>';      $output .= '</tr><tr>';
     foreach my $item ('approve','email','username') {      foreach my $item ('approve','email','username') {
         $output .= '<td valign="top">';          $output .= '<td style="vertical-align: top">';
         my (%choices,@options,$hashref,$defoption,$name,$onclick,$hascustom);          my (%choices,@options,$hashref,$defoption,$name,$onclick,$hascustom);
         if ($item eq 'approve') {          if ($item eq 'approve') {
             %choices = &Apache::lonlocal::texthash (              %choices = &Apache::lonlocal::texthash (
Line 9168  sub noninst_users { Line 6444  sub noninst_users {
                     my $value;                      my $value;
                     if (ref($emaildomain) eq 'HASH') {                      if (ref($emaildomain) eq 'HASH') {
                         if (ref($emaildomain->{$type}) eq 'HASH') {                          if (ref($emaildomain->{$type}) eq 'HASH') {
                             $value = $emaildomain->{$type}->{$option};                              $value = $emaildomain->{$type}->{$option}; 
                         }                          }
                     }                      }
                     if ($value eq '') {                      if ($value eq '') {
Line 9198  sub captcha_choice { Line 6474  sub captcha_choice {
         $vertext,$currver);          $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 9245  sub captcha_choice { Line 6517  sub captcha_choice {
         $css_class .= ' style="'.$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 9284  sub user_formats_row { Line 6556  sub user_formats_row {
                    'username' => 'new usernames',                     'username' => 'new usernames',
                    'id'       => 'IDs',                     'id'       => 'IDs',
                );                 );
     unless (($type eq 'email') || ($type eq 'unamemap')) {      unless ($type eq 'email') {
         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">'.
Line 9339  sub user_formats_row { Line 6611  sub user_formats_row {
     } 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>';
     unless (($type eq 'email') || ($type eq 'unamemap')) {      unless ($type eq 'email') {
         $output .= '</table></td></tr>';          $output .= '</td></tr>';
     }      }
     return $output;      return $output;
 }  }
Line 9377  sub authtype_names { Line 6649  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 9404  sub print_usermodification { Line 6675  sub print_usermodification {
             $$rowtotal ++;              $$rowtotal ++;
             $rowcount ++;              $rowcount ++;
         }          }
     } elsif ($position eq 'middle') {  
         $rowcount = 0;  
         $context = 'coauthor';  
         foreach my $role ('ca','aa') {  
             $datatable .= &modifiable_userdata_row($context,$role,$settings,  
                                                    $numinrow,$rowcount);  
             $$rowtotal ++;  
             $rowcount ++;  
         }  
     } elsif ($position eq 'bottom') {      } elsif ($position eq 'bottom') {
         $context = 'course';          $context = 'course';
         $rowcount = 0;          $rowcount = 0;
Line 9455  sub print_defaults { Line 6717  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 9482  sub print_defaults { Line 6743  sub print_defaults {
             } elsif ($item eq 'lang_def') {              } elsif ($item eq 'lang_def') {
                 my $includeempty = 1;                  my $includeempty = 1;
                 $datatable .= &Apache::loncommon::select_language($item,$defaults{$item},$includeempty);                  $datatable .= &Apache::loncommon::select_language($item,$defaults{$item},$includeempty);
             } elsif ($item eq 'portal_def') {              } else {
                   my $size;
                   if ($item eq 'portal_def') {
                       $size = ' size="25"';
                   }
                 $datatable .= '<input type="text" name="'.$item.'" value="'.                  $datatable .= '<input type="text" name="'.$item.'" value="'.
                               $defaults{$item}.'" size="25" onkeyup="portalExtras(this);" />';                                $defaults{$item}.'"'.$size.' />';
                 my $portalsty = 'none';              }
                 if ($defaults{$item}) {              $datatable .= '</td></tr>';
                     $portalsty = 'block';              $rownum ++;
                 }          }
                 foreach my $field ('email','web') {      } elsif ($position eq 'middle') {
                     my $checkedoff = ' checked="checked"';          my @items = ('intauth_cost','intauth_check','intauth_switch');
                     my $checkedon;          my %defaults;
                     if ($defaults{$item.'_'.$field}) {          if (ref($settings) eq 'HASH') {
                         $checkedon = $checkedoff;              %defaults = %{$settings};
                         $checkedoff = '';              if ($defaults{'intauth_cost'} !~ /^\d+$/) {
                     }                  $defaults{'intauth_cost'} = 10;
                     $datatable .= '<div id="'.$item.'_'.$field.'_div" style="display:'.$portalsty.'">'.              }
                               '<span class="LC_nobreak">'.$titles->{$field}.'&nbsp;'.              if ($defaults{'intauth_check'} !~ /^(0|1|2)$/) {
                               '<label><input type="radio" name="'.$item.'_'.$field.'" value="1"'.$checkedon.'/>'.&mt('Yes').'</label>'.                  $defaults{'intauth_check'} = 0;
                               ('&nbsp;'x2).              }
                               '<label><input type="radio" name="'.$item.'_'.$field.'" value="0"'.$checkedoff.'/>'.&mt('No').'</label>'.              if ($defaults{'intauth_switch'} !~ /^(0|1|2)$/) {
                               '</div>';                  $defaults{'intauth_switch'} = 0;
               }
           } else {
               %defaults = (
                             'intauth_cost'   => 10,
                             'intauth_check'  => 0,
                             'intauth_switch' => 0,
                           );
           }
           foreach my $item (@items) {
               if ($rownum%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 wisth="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 {              } else {
                 $datatable .= '<input type="text" name="'.$item.'" value="'.$defaults{$item}.'" />';                  $datatable .= '<input type="text" name="'.$item.'" value="'.
                                 $defaults{$item}.'" size="3" onblur="javascript:warnIntAuth(this);" />'; 
             }              }
             $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')) {
Line 9533  sub print_defaults { Line 6857  sub print_defaults {
                     $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" colspan="2"><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></tr>';
                 }                  }
Line 9552  sub print_defaults { Line 6876  sub print_defaults {
                 $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="" />'.
                               '&nbsp;'.&mt('(new)').                                '&nbsp;'.&mt('(new)').
                               '</span></td><td class="LC_left_item"><span class="LC_nobreak">'.                                '</span></td><td class="LC_left_item" colspan="2"><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>'.
                               '</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 9600  sub defaults_titles { Line 6908  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_cost'   => 'Encryption cost for bcrypt (positive integer)',
                    'intauth_check'  => 'Check bcrypt cost if authenticated',                     'intauth_check'  => 'Check bcrypt cost if authenticated',
                    'intauth_switch' => 'Existing crypt-based switched to bcrypt on authentication',                     'intauth_switch' => 'Existing crypt-based switched to bcrypt on authentication',
Line 9619  sub defaults_titles { Line 6925  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 9697  sub print_scantronformat { Line 6951  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 9707  sub print_scantronformat { Line 6961  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 9718  sub print_scantronformat { Line 6972  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 9787  sub print_scantronformat { Line 7041  sub print_scantronformat {
         }          }
         $datatable .= '</span></td>';          $datatable .= '</span></td>';
         if (keys(%error) == 0) {           if (keys(%error) == 0) { 
             $datatable .= '<td valign="bottom">';              $datatable .= '<td style="vertical-align: bottom">';
             if (!$switchserver) {              if (!$switchserver) {
                 $datatable .= &mt('Upload:').'<br />';                  $datatable .= &mt('Upload:').'<br />';
             }              }
Line 9834  sub legacy_scantronformat { Line 7088  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 10012  sub print_coursecategories { Line 7140  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 10025  sub print_coursecategories { Line 7153  sub print_coursecategories {
         my $toggle_catscomm_dom = ' checked="checked" ';          my $toggle_catscomm_dom = ' checked="checked" ';
         my $can_catcomm_comm = ' ';          my $can_catcomm_comm = ' ';
         my $can_catcomm_dom = ' checked="checked" ';          my $can_catcomm_dom = ' checked="checked" ';
           my $toggle_catsplace_place = ' ';
           my $toggle_catsplace_dom = ' checked="checked" ';
           my $can_catplace_place = ' ';
           my $can_catplace_dom = ' checked="checked" ';
   
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ($settings->{'togglecats'} eq 'crs') {              if ($settings->{'togglecats'} eq 'crs') {
Line 10043  sub print_coursecategories { Line 7175  sub print_coursecategories {
                 $can_catcomm_comm = $can_catcomm_dom;                  $can_catcomm_comm = $can_catcomm_dom;
                 $can_catcomm_dom = ' ';                  $can_catcomm_dom = ' ';
             }              }
               if ($settings->{'togglecatsplace'} eq 'place') {
                   $toggle_catsplace_place = $toggle_catsplace_dom;
                   $toggle_catsplace_dom = ' ';
               }
               if ($settings->{'categorizeplace'} eq 'place') {
                   $can_catplace_place = $can_catplace_dom;
                   $can_catplace_dom = ' ';
               }
         }          }
         my %title = &Apache::lonlocal::texthash (          my %title = &Apache::lonlocal::texthash (
                      togglecats     => 'Show/Hide a course in catalog',                       togglecats      => 'Show/Hide a course in catalog',
                      togglecatscomm => 'Show/Hide a community in catalog',                       togglecatscomm  => 'Show/Hide a community in catalog',
                      categorize     => 'Assign a category to a course',                       togglecatsplace => 'Show/Hide a placement test in catalog',
                      categorizecomm => 'Assign a category to a community',                       categorize      => 'Assign a category to a course',
                        categorizecomm  => 'Assign a category to a community',
                        categorizeplace => 'Assign a category to a placement test',
                     );                      );
         my %level = &Apache::lonlocal::texthash (          my %level = &Apache::lonlocal::texthash (
                      dom  => 'Set in Domain',                       dom   => 'Set in Domain',
                      crs  => 'Set in Course',                       crs   => 'Set in Course',
                      comm => 'Set in Community',                       comm  => 'Set in Community',
                        place => 'Set in Placement Test',
                     );                      );
         $datatable = '<tr class="LC_odd_row">'.          $datatable = '<tr class="LC_odd_row">'.
                   '<td>'.$title{'togglecats'}.'</td>'.                    '<td>'.$title{'togglecats'}.'</td>'.
Line 10083  sub print_coursecategories { Line 7226  sub print_coursecategories {
                   $can_catcomm_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.                    $can_catcomm_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.
                   '<label><input type="radio" name="categorizecomm"'.                    '<label><input type="radio" name="categorizecomm"'.
                   $can_catcomm_comm.'value="comm" />'.$level{'comm'}.'</label></span></td>'.                    $can_catcomm_comm.'value="comm" />'.$level{'comm'}.'</label></span></td>'.
                     '</tr><tr>'.
                     '<td>'.$title{'togglecatsplace'}.'</td>'.
                     '<td class="LC_right_item"><span class="LC_nobreak"><label>'.
                     '<input type="radio" name="togglecatsplace"'.
                     $toggle_catsplace_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.
                     '<label><input type="radio" name="togglecatscomm"'.
                     $toggle_catsplace_place.' value="comm" />'.$level{'place'}.'</label></span></td>'.
                     '</tr><tr>'.
                     '<td>'.$title{'categorizeplace'}.'</td>'.
                     '<td class="LC_right_item"><span class="LC_nobreak">'.
                     '<label><input type="radio" name="categorizeplace"'.
                     $can_catplace_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.
                     '<label><input type="radio" name="categorizeplace"'.
                     $can_catplace_place.'value="place" />'.$level{'place'}.'</label></span></td>'.
                   '</tr>';                    '</tr>';
         $$rowtotal += 4;          $$rowtotal += 6;
     } else {      } else {
         my $css_class;          my $css_class;
         my $itemcount = 1;          my $itemcount = 1;
Line 10109  sub print_coursecategories { Line 7266  sub print_coursecategories {
                     my %default_names = (                      my %default_names = (
                           instcode    => &mt('Official courses'),                            instcode    => &mt('Official courses'),
                           communities => &mt('Communities'),                            communities => &mt('Communities'),
                             placement   => &mt('Placement Tests'),
                     );                      );
   
                     if ((!grep(/^instcode$/,@{$cats[0]})) ||                       if ((!grep(/^instcode$/,@{$cats[0]})) || 
                         ($cathash->{'instcode::0'} eq '') ||                          ($cathash->{'instcode::0'} eq '') ||
                         (!grep(/^communities$/,@{$cats[0]})) ||                           (!grep(/^communities$/,@{$cats[0]})) || 
                         ($cathash->{'communities::0'} eq '')) {                          ($cathash->{'communities::0'} eq '') ||
                           (!grep(/^placement$/,@{$cats[0]})) ||
                           ($cathash->{'placement::0'} eq '')) {
                         $maxnum ++;                          $maxnum ++;
                     }                      }
                     my $lastidx;                      my $lastidx;
Line 10135  sub print_coursecategories { Line 7295  sub print_coursecategories {
                             $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';                              $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
                         }                          }
                         $datatable .= '</select></span></td><td>';                          $datatable .= '</select></span></td><td>';
                         if ($parent eq 'instcode' || $parent eq 'communities') {                          if ($parent eq 'instcode' || $parent eq 'communities' || $parent eq 'placement') {
                             $datatable .=  '<span class="LC_nobreak">'                              $datatable .=  '<span class="LC_nobreak">'
                                            .$default_names{$parent}.'</span>';                                             .$default_names{$parent}.'</span>';
                             if ($parent eq 'instcode') {                              if ($parent eq 'instcode') {
Line 10158  sub print_coursecategories { Line 7318  sub print_coursecategories {
                             $datatable .= '<label><input type="radio" name="'                              $datatable .= '<label><input type="radio" name="'
                                           .$parent.'" value="0" />'                                            .$parent.'" value="0" />'
                                           .&mt('Do not display').'</label></span>';                                            .&mt('Do not display').'</label></span>';
                             if ($parent eq 'communities') {                              if (($parent eq 'communities') || ($parent eq 'placement')) {
                                 $datatable .= '</td></tr></table>';                                  $datatable .= '</td></tr></table>';
                             }                              }
                             $datatable .= '</td>';                              $datatable .= '</td>';
Line 10190  sub print_coursecategories { Line 7350  sub print_coursecategories {
                                   .'<input type="text" size="20" name="addcategory_name" value="" /></td>'                                    .'<input type="text" size="20" name="addcategory_name" value="" /></td>'
                                   .'</tr>'."\n";                                    .'</tr>'."\n";
                     $itemcount ++;                      $itemcount ++;
                     foreach my $default ('instcode','communities') {                      foreach my $default ('instcode','communities','placement') {
                         if ((!grep(/^\Q$default\E$/,@{$cats[0]})) || ($cathash->{$default.'::0'} eq '')) {                          if ((!grep(/^\Q$default\E$/,@{$cats[0]})) || ($cathash->{$default.'::0'} eq '')) {
                             $css_class = $itemcount%2?' class="LC_odd_row"':'';                              $css_class = $itemcount%2?' class="LC_odd_row"':'';
                             my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','$lastidx'".');"';                              my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','$lastidx'".');"';
Line 10223  sub print_coursecategories { Line 7383  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 10271  sub print_serverstatuses { Line 7431  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 10279  sub print_serverstatuses { Line 7439  sub print_serverstatuses {
   
 sub serverstatus_pages {  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','certstatus','metadata_keywords',
             'takeoffline','takeonline','showenv','toggledebug','ping','domconf',              'metadata_harvest','takeoffline','takeonline','showenv','toggledebug',
             'uniquecodes','diskusage','coursecatalog');              'ping','domconf','uniquecodes','diskusage','coursecatalog');
 }  }
   
 sub defaults_javascript {  sub defaults_javascript {
     my ($settings) = @_;      my ($settings) = @_;
     return unless (ref($settings) eq 'HASH');      my $intauthcheck = &mt('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.');
     my $portal_js = <<"ENDPORTAL";      my $intauthcost = &mt('Warning: bcrypt encryption cost for internal authentication must be an integer.');
       &js_escape(\$intauthcheck);
       &js_escape(\$intauthcost);
       my $intauthjs = <<"ENDSCRIPT";
   
 function portalExtras(caller) {  function warnIntAuth(field) {
     var x = caller.value;      if (field.name == 'intauth_check') {
     var y = new Array('email','web');          if (field.value == '2') {
     for (var i=0; i<y.length; i++) {              alert('$intauthcheck');
         if (document.getElementById('portal_def_'+y[i]+'_div')) {          }
             var z = document.getElementById('portal_def_'+y[i]+'_div');      }
             if (x.length > 0) {      if (field.name == 'intauth_cost') {
                 z.style.display = 'block';          field.value.replace(/\s/g,'');
             } else {          if (field.value != '') {
                 z.style.display = 'none';              var regexdigit=/^\\d+\$/;
               if (!regexdigit.test(field.value)) {
                   alert('$intauthcost');
             }              }
         }          }
     }      }
       return;
 }  }
 ENDPORTAL  
   ENDSCRIPT
   
       if (ref($settings) ne 'HASH') {
           return &Apache::lonhtmlcommon::scripttag($intauthjs);
       }
     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 10357  $jstext Line 7528  $jstext
     return;      return;
 }  }
   
 $portal_js  $intauthjs
   
 // ]]>  
 </script>  
   
 ENDSCRIPT  
     } else {  
 return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
 $portal_js  
 // ]]>  // ]]>
 </script>  </script>
   
 ENDSCRIPT  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 {      } else {
         if (field.value == '0') {          return &Apache::lonhtmlcommon::scripttag($intauthjs);
             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 10489  sub coursecategories_javascript { Line 7563  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 $placement_reserved = &mt('The name: [_1] is a reserved category.','"placement"');
     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(\$instcode_reserved);
     &js_escape(\$communities_reserved);      &js_escape(\$communities_reserved);
       &js_escape(\$placement_reserved);
     &js_escape(\$choose_again);      &js_escape(\$choose_again);
     $output = <<"ENDSCRIPT";      $output = <<"ENDSCRIPT";
 <script type="text/javascript">  <script type="text/javascript">
Line 10561  function categoryCheck(form) { Line 7637  function categoryCheck(form) {
         alert('$communities_reserved\\n$choose_again');          alert('$communities_reserved\\n$choose_again');
         return false;          return false;
     }      }
       if (form.elements['addcategory_name'].value == 'placement') {
           alert('$placement_reserved\\n$choose_again');
           return false;
       }
     return true;      return true;
 }  }
   
Line 10574  ENDSCRIPT Line 7654  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',
                         placement   => 'Placement Tests',
                         );                          );
     my $select0 = ' selected="selected"';      my $select0 = ' selected="selected"';
     my $select1 = '';      my $select1 = '';
     foreach my $default ('instcode','communities') {      foreach my $default ('instcode','communities','placement') {
         $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') || ($default eq 'placement')) {
             $select1 = $select0;              $select1 = $select0;
             $select0 = '';              $select0 = '';
         }          }
Line 10607  sub initialize_categories { Line 7688  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 10664  sub build_category_rows { Line 7744  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 10687  sub build_category_rows { Line 7767  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 10697  sub build_category_rows { Line 7777  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) = @_;          $rowid,$customcss,$rowstyle) = @_;
     my ($role,$rolename,$statustype);      my ($role,$rolename,$statustype);
     $role = $item;      $role = $item;
     if ($context eq 'cancreate') {      if ($context eq 'cancreate') {
Line 10718  sub modifiable_userdata_row { Line 7798  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 10763  sub modifiable_userdata_row { Line 7841  sub modifiable_userdata_row {
     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);      my $total = scalar(@fields);
     for (my $i=0; $i<$total; $i++) {      for (my $i=0; $i<$total; $i++) {
         $rem = $i%($numinrow);          $rem = $i%($numinrow);
Line 10804  sub modifiable_userdata_row { Line 7882  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 10815  sub modifiable_userdata_row { Line 7893  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 10826  sub modifiable_userdata_row { Line 7903  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';  
             } elsif ($context eq 'coauthor') {  
                 $prefix = 'cacanmodify';  
             }  
             $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>';
         }          }
Line 10862  sub insttypes_row { Line 7934  sub insttypes_row {
     my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rowtotal,$onclick,      my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rowtotal,$onclick,
         $customcss,$rowstyle) = @_;          $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',                        selfassign    => 'Self-reportable affiliations',
                       overrides      => "Override domain's helpdesk settings based on requester's affiliation",                        overrides     => "Override domain's helpdesk settings based on requester's affiliation",
                       webdav         => 'WebDAV access available',  
                       authorquota    => 'Authoring Space quota (MB)',  
              );               );
     my ($showdom,$defaultquota);      my $showdom;
     if ($context eq 'cansearch') {      if ($context eq 'cansearch') {
         $showdom = ' ('.$dom.')';          $showdom = ' ('.$dom.')';
     } elsif ($context eq 'authorquota') {  
         $defaultquota = 500;  
     }      }
     my $class = 'LC_left_item';      my $class = 'LC_left_item';
     if ($context eq 'statustocreate') {      if ($context eq 'statustocreate') {
Line 10911  sub insttypes_row { Line 7979  sub insttypes_row {
                     }                      }
                     $output .= '<tr>';                      $output .= '<tr>';
                 }                  }
                 if ($context eq 'authorquota') {                  my $check = ' ';
                     my $currquota;                  if (ref($settings) eq 'HASH') {
                     if ($settings->{$context}->{$types->[$i]} =~ /^\d+$/) {                      if (ref($settings->{$context}) eq 'ARRAY') {
                         $currquota = $settings->{$context}->{$types->[$i]};                          if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) {
                     } else {  
                         $currquota = $defaultquota;  
                     }  
                     $output .= '<td class="LC_left_item">'."\n".  
                                '<label><span class="LC_nobreak">'."\n".  
                                $usertypes->{$types->[$i]}.'</span><br />'."\n".  
                                '<input type="text" name="'.$context.'_'.$types->[$i].'" '.  
                                'value="'.$currquota.'" size="5"'.$onclick.'/>'."\n".  
                                '</label></td>';  
                 } else {  
                     my $check = ' ';  
                     if (ref($settings) eq 'HASH') {  
                         if (ref($settings->{$context}) eq 'ARRAY') {  
                             if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) {  
                                 $check = ' checked="checked" ';  
                             }  
                         } elsif (ref($settings->{$context}) eq 'HASH') {  
                             if (ref($settings->{$context}->{$types->[$i]}) eq 'HASH') {  
                                 $check = ' checked="checked" ';  
                             } elsif ($context eq 'webdav') {  
                                 if ($settings->{$context}->{$types->[$i]}) {  
                                     $check = ' checked="checked" ';  
                                 }  
                             }  
                         } elsif ($context eq 'statustocreate') {  
                             $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') {
                           $check = ' checked="checked" ';
                     }                      }
                     $output .= '<td class="LC_left_item">'.  
                                '<span class="LC_nobreak"><label>'.  
                                '<input type="checkbox" name="'.$context.'" '.  
                                'value="'.$types->[$i].'"'.$check.$onclick.'/>'.  
                                $usertypes->{$types->[$i]}.'</label></span></td>';  
                 }                  }
                   $output .= '<td class="LC_left_item">'.
                              '<span class="LC_nobreak"><label>'.
                              '<input type="checkbox" name="'.$context.'" '.
                              'value="'.$types->[$i].'"'.$check.$onclick.' />'.
                              $usertypes->{$types->[$i]}.'</label></span></td>';
             }              }
         }          }
         $rem = @{$types}%($numinrow);          $rem = @{$types}%($numinrow);
Line 10960  sub insttypes_row { Line 8009  sub insttypes_row {
         } else {          } else {
             $output .= '<td class="LC_left_item">';              $output .= '<td class="LC_left_item">';
         }          }
         $output .= '&nbsp;';          $output .= '&nbsp;';  
     } else {      } else {
         if ($rem == 0) {          if (($rem == 0) && (@{$types} > 0)) {
             $output .= '<tr>';              $output .= '<tr>';
         }          }
         if ($colsleft > 1) {          if ($colsleft > 1) {
Line 10970  sub insttypes_row { Line 8019  sub insttypes_row {
         } else {          } else {
             $output .= '<td class="LC_left_item">';              $output .= '<td class="LC_left_item">';
         }          }
         if ($context eq 'authorquota') {          my $defcheck = ' ';
             my $currquota = 500;          if (ref($settings) eq 'HASH') {  
             if ((ref($settings) eq 'HASH') && (ref($settings->{$context}) eq 'HASH')) {              if (ref($settings->{$context}) eq 'ARRAY') {
                 if ($settings->{$context}{'default'} =~ /^\d+$/) {                  if (grep(/^default$/,@{$settings->{$context}})) {
                     $currquota = $settings->{$context}{'default'};  
                 }  
             }  
             $output .= '<label><span class="LC_nobreak">'.$othertitle.'</span><br />'."\n".  
                        '<input type="text" name="'.$context.'_default" '.  
                        'value="'.$currquota.'" size="5"'.$onclick.'/>'."\n".  
                        '</label>';  
         } else {  
             my $defcheck = ' ';  
             if (ref($settings) eq 'HASH') {  
                 if (ref($settings->{$context}) eq 'ARRAY') {  
                     if (grep(/^default$/,@{$settings->{$context}})) {  
                         $defcheck = ' checked="checked" ';  
                     }  
                 } elsif (ref($settings->{$context}) eq 'HASH') {  
                     if (ref($settings->{$context}->{'default'}) eq 'HASH') {  
                         $defcheck = ' checked="checked" ';  
                     } elsif ($context eq 'webdav') {  
                         if ($settings->{$context}->{'default'}) {  
                             $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 .= '<span class="LC_nobreak"><label>'.
                      '<input type="checkbox" name="'.$context.'" '.
                      'value="default"'.$defcheck.$onclick.' />'.
                      $othertitle.'</label></span>';
     }      }
     $output .= '</td></tr></table></td></tr>';      $output .= '</td></tr></table></td></tr>';
     return $output;      return $output;
Line 11083  sub usertype_update_row { Line 8111  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 11098  sub modify_login { Line 8124  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 11251  sub modify_login { Line 8262  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 11273  sub modify_login { Line 8281  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 11331  sub modify_login { Line 8338  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 11355  sub modify_login { Line 8359  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 11367  sub modify_login { Line 8370  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 11500  sub modify_login { Line 8410  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 11604  sub modify_login { Line 8489  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 11725  sub check_exempt_addresses { Line 8575  sub check_exempt_addresses {
 sub color_font_choices {  sub color_font_choices {
     my %choices =      my %choices =
         &Apache::lonlocal::texthash (          &Apache::lonlocal::texthash (
               img => "Header",
             bgs => "Background colors",              bgs => "Background colors",
             links => "Link colors",              links => "Link colors",
             images => "Images",              images => "Images",
Line 11740  sub color_font_choices { Line 8591  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 ($position,%current);  
         if ($idx eq 'add') {  
             $position = $env{'form.ipaccess_pos_add'};  
         } else {  
             $position = $env{'form.ipaccess_pos_'.$itemid};  
             if (ref($domconfig{'ipaccess'}{$itemid}) eq 'HASH') {  
                 %current = %{$domconfig{'ipaccess'}{$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_authordefaults {  
     my ($dom,$lastactref,%domconfig) = @_;  
 #  
 # Retrieve current domain configuration for webDAV and Authoring Space quotas from $domconfig{'quotas'}.  
 #  
     my (%curr_quotas,%save_quotas,%confhash,%changes,%newvalues);  
     if (ref($domconfig{'quotas'}) eq 'HASH') {  
         foreach my $key (keys(%{$domconfig{'quotas'}})) {  
             if ($key =~ /^webdav|authorquota$/) {  
                 $curr_quotas{$key} = $domconfig{'quotas'}{$key};  
             } else {  
                 $save_quotas{$key} = $domconfig{'quotas'}{$key};  
             }  
         }  
     }  
     my %staticdefaults = (  
                            'copyright'    => 'default',  
                            'sourceavail'  => 'closed',  
                            'nocodemirror' => 'off',  
                            'daxecollapse' => 'off',  
                            'domcoordacc'  => 'on',  
                            'editors'      => ['edit','xml'],  
                            'authorquota'  => 500,  
                            'webdav'       => 0,  
                            'archive'      => 'off',  
                          );  
     my %titles = &authordefaults_titles();  
     foreach my $item ('nocodemirror','daxecollapse','domcoordacc','archive') {  
         if ($env{'form.'.$item} =~ /^(0|1)$/) {  
             $confhash{$item} = $env{'form.'.$item};  
         }  
     }  
     if ($env{'form.copyright'} =~ /^(default|domain|public)$/) {  
         $confhash{'copyright'} = $1;  
     }  
     if ($env{'form.sourceavail'} =~ /^(closed|open)$/) {  
         $confhash{'sourceavail'} = $1;  
     }  
     my @posseditors =  &Apache::loncommon::get_env_multiple('form.author_editors');  
     my @okeditors = ('edit','xml','daxe');  
     my @editors;  
     foreach my $item (@posseditors) {  
         if (grep(/^\Q$item\E$/,@okeditors)) {  
             push(@editors,$item);  
         }  
     }  
     $confhash{'editors'} = \@editors;  
   
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
     my @insttypes;  
     if (ref($types) eq 'ARRAY') {  
         @insttypes = @{$types};  
     }  
     my @webdavon = &Apache::loncommon::get_env_multiple('form.webdav');  
     my %webdav;  
     map { $webdav{$_} = 1; } @webdavon;  
     foreach my $type (@insttypes,'default') {  
         my $possquota = $env{'form.authorquota_'.$type};  
         if ($possquota =~ /^\d+$/) {  
             $save_quotas{'authorquota'}{$type} = $possquota;  
         }  
         if ($webdav{$type}) {  
             $save_quotas{'webdav'}{$type} = 1;  
         } else {  
             $save_quotas{'webdav'}{$type} = 0;  
         }  
     }  
     if ($env{'form.webdav_LC_adv'} =~ /^(0|1)$/) {  
         $save_quotas{'webdav'}{'_LC_adv'} = $env{'form.webdav_LC_adv'};  
     }  
     if (ref($domconfig{'authordefaults'}) eq 'HASH') {  
         foreach my $item ('nocodemirror','daxecollapse','domcoordacc','copyright','sourceavail','archive') {  
             if ($domconfig{'authordefaults'}{$item} ne $confhash{$item}) {  
                 $changes{$item} = 1;  
              }  
         }  
         if (ref($domconfig{'authordefaults'}{'editors'}) eq 'ARRAY') {  
             my @diffs =  
                 &Apache::loncommon::compare_arrays($confhash{'editors'},  
                                                    $domconfig{'authordefaults'}{'editors'});  
             unless (@diffs == 0) {  
                 $changes{'editors'} = 1;  
             }  
         } else {  
             my @diffs =  
                 &Apache::loncommon::compare_arrays($confhash{'editors'},  
                                                    $staticdefaults{'editors'});  
             unless (@diffs == 0) {  
                 $changes{'editors'} = 1;  
             }  
         }  
     } else {  
         my @offon = ('off','on');  
         foreach my $item ('nocodemirror','daxecollapse','domcoordacc','archive') {  
             if ($offon[$confhash{$item}] ne $staticdefaults{$item}) {  
                 $changes{$item} = 1;  
             }  
         }  
         foreach my $item ('copyright','sourceavail') {  
             if ($confhash{$item} ne $staticdefaults{$item}) {  
                 $changes{$item} = 1;  
             }  
         }  
         my @diffs =  
             &Apache::loncommon::compare_arrays($confhash{'editors'},  
                                                $staticdefaults{'editors'});  
         unless (@diffs == 0) {  
             $changes{'editors'} = 1;  
         }  
     }  
     foreach my $key ('authorquota','webdav') {  
         if (ref($curr_quotas{$key}) eq 'HASH') {  
             foreach my $type (@insttypes,'default') {  
                 if (exists($save_quotas{$key}{$type})) {  
                     if ($save_quotas{$key}{$type} ne $curr_quotas{$key}{$type}) {  
                         $changes{$key}{$type} = 1;  
                     }  
                 } elsif (exists($curr_quotas{$key}{$type})) {  
                     $save_quotas{$key}{$type} = $curr_quotas{$key}{$type};  
                 } else {  
                     $save_quotas{$key}{$type} = $staticdefaults{$key};  
                 }  
             }  
         } else {  
             foreach my $type (@insttypes,'default') {  
                 if (exists($save_quotas{$key}{$type})) {  
                     unless ($save_quotas{$key}{$type} eq $staticdefaults{$key}) {  
                         $changes{$key}{$type} = 1;  
                     }  
                 } else {  
                     $save_quotas{$key}{$type} = $staticdefaults{$key};  
                 }  
             }  
         }  
     }  
     if (ref($curr_quotas{'webdav'}) eq 'HASH') {  
         if (exists($save_quotas{'webdav'}{'_LC_adv'})) {  
             if ($save_quotas{'webdav'}{'_LC_adv'} ne $curr_quotas{'webdav'}{'_LC_adv'}) {  
                 $changes{'webdav_LC_adv'} = 1;  
             }  
         } elsif (exists($curr_quotas{'webdav'}{'_LC_adv'})) {  
             $changes{'webdav_LC_adv'} = 1;  
         }  
     } elsif (exists($save_quotas{'webdav'}{'_LC_adv'})) {  
         $changes{'webdav_LC_adv'} = 1;  
     }  
     my %confighash = (  
                         quotas  => \%save_quotas,  
                         authordefaults => \%confhash,  
                      );  
     my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,  
                                              $dom);  
     my $resulttext;  
     if ($putresult eq 'ok') {  
         if (keys(%changes)) {  
             my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);  
             if ((exists($changes{'authorquota'})) || (exists($changes{'webdav'})) ||  
                 ($changes{'webdav_LC_adv'})) {  
                 if ((exists($changes{'authorquota'})) && (ref($save_quotas{'authorquota'}) eq 'HASH')) {  
                     $domdefaults{'authorquota'} = $save_quotas{'authorquota'};  
                 }  
                 if (((exists($changes{'webdav'})) || ($changes{'webdav_LC_adv'})) &&  
                     (ref($save_quotas{'webdav'}) eq 'HASH')) {  
                     $domdefaults{'webdav'} = $save_quotas{'webdav'};  
                 }  
             }  
             $resulttext = &mt('Changes made:').'<ul>';  
             my $authoroverride;  
             foreach my $key ('nocodemirror','daxecollapse','domcoordacc','copyright','sourceavail') {  
                 if (exists($changes{$key})) {  
                     $domdefaults{$key} = $confhash{$key};  
                     my $shown;  
                     unless ($authoroverride) {  
                         $resulttext .= '<li>'.&mt('Defaults which can be overridden by Author').'<ul>';  
                         $authoroverride = 1;  
                     }  
                     if (($key eq 'nocodemirror') || ($key eq 'daxecollapse') || ($key eq 'domcoordacc')) {  
                         $shown = ($confhash{$key} ? &mt('Yes') : &mt('No'));  
                     } elsif ($key eq 'copyright') {  
                         $shown = &Apache::loncommon::copyrightdescription($confhash{$key});  
                     } elsif ($key eq 'sourceavail') {  
                         $shown = &Apache::loncommon::source_copyrightdescription($confhash{$key});  
                     }  
                     $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{$key},$shown).'</li>';  
                 }  
             }  
             if ($authoroverride) {  
                 $resulttext .= '</ul></li>';  
             }  
             my $domcoordoverride;  
             foreach my $key ('editors','authorquota','webdav','webdav_LC_adv','archive') {  
                 if (exists($changes{$key})) {  
                     my $shown;  
                     unless ($domcoordoverride) {  
                         $resulttext .= '<li>'.&mt('Defaults which can be overridden by a Domain Coodinator').'<ul>';  
                         $domcoordoverride = 1;  
                     }  
                     if ($key eq 'editors') {  
                         if (ref($confhash{'editors'}) eq 'ARRAY') {  
                             $domdefaults{'editors'} = join(',',@{$confhash{'editors'}});  
                             if (@{$confhash{'editors'}}) {  
                                 $shown = join(', ', map { $titles{$_} } @{$confhash{'editors'}});  
                             } else {  
                                 $shown = &mt('None');  
                             }  
                         }  
                     } elsif ($key eq 'authorquota') {  
                         foreach my $type (@insttypes) {  
                             $shown .= $usertypes->{$type}.' -- '.$save_quotas{$key}{$type}.', ';  
                         }  
                         $shown .= $othertitle.' -- '.$save_quotas{$key}{'default'};  
                     } elsif ($key eq 'webdav') {  
                         foreach my $type (@insttypes) {  
                             $shown .= $usertypes->{$type}.' -- '. ($save_quotas{$key}{$type} ? &mt('Yes') : &mt('No')).', ';  
                         }  
                         $shown .= $othertitle.' -- '. ($save_quotas{$key}{'default'} ? &mt('Yes') : &mt('No'));  
                     } elsif ($key eq 'webdav_LC_adv') {  
                         if (exists($save_quotas{'webdav'}{'_LC_adv'})) {  
                             $shown = ($save_quotas{'webdav'}{'_LC_adv'} ? $titles{'overon'} : $titles{'overoff'});  
                         } else {  
                             $shown = $titles{'none'};  
                         }  
                     } elsif ($key eq 'archive') {  
                         $domdefaults{$key} = $confhash{$key};  
                         $shown = ($confhash{$key} ? &mt('Yes') : &mt('No'));  
                     }  
                     $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{$key},$shown).'</li>';  
                 }     
             }  
             if ($domcoordoverride) {  
                 $resulttext .= '</ul></li>';  
             }  
             $resulttext .= '</ul>';  
             my $cachetime = 24*60*60;  
             &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);  
             if (ref($lastactref) eq 'HASH') {  
                 $lastactref->{'domdefaults'} = 1;  
             }  
         } else {  
             $resulttext = &mt('No changes made to Authoring Space defaults');  
         }  
     }  
     return $resulttext;  
 }  
   
 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 12320  sub modify_colors { Line 8647  sub modify_colors {
             @images = ('img','logo','domlogo','login');              @images = ('img','logo','domlogo','login');
             @bgs = ('pgbg','mainbg','sidebg');              @bgs = ('pgbg','mainbg','sidebg');
         } else {          } else {
             @images = ();              @images = ('img');
             @bgs = ('pgbg','tabbg','sidebg');              @bgs = ('pgbg','tabbg','sidebg');
         }          }
         my %defaults = &role_defaults($role,\@bgs,\@links,\@images,\@logintext);          my %defaults = &role_defaults($role,\@bgs,\@links,\@images,\@logintext);
         $env{'form.'.$role.'_font'} = lc($env{'form.'.$role.'_font'});          unless ($env{'form.'.$role.'_font'} eq $defaults{'font'}) {
         if ($env{'form.'.$role.'_font'} =~ /^\w+/) {  
             $env{'form.'.$role.'_font'} = '#'.$env{'form.'.$role.'_font'};  
         }  
         unless ($env{'form.'.$role.'_font'} eq lc($defaults{'font'})) {  
             $confhash->{$role}{'font'} = $env{'form.'.$role.'_font'};              $confhash->{$role}{'font'} = $env{'form.'.$role.'_font'};
         }          }
         if ($role eq 'login') {          if ($role eq 'login') {
Line 12346  sub modify_colors { Line 8669  sub modify_colors {
             if ($env{'form.'.$role.'_fontmenu'} =~ /^\w+/) {              if ($env{'form.'.$role.'_fontmenu'} =~ /^\w+/) {
                 $env{'form.'.$role.'_fontmenu'} = '#'.$env{'form.'.$role.'_fontmenu'};                  $env{'form.'.$role.'_fontmenu'} = '#'.$env{'form.'.$role.'_fontmenu'};
             }              }
             unless ($env{'form.'.$role.'_fontmenu'} eq lc($defaults{'fontmenu'})) {              unless($env{'form.'.$role.'_fontmenu'} eq lc($defaults{'fontmenu'})) {
                 $confhash->{$role}{'fontmenu'} = $env{'form.'.$role.'_fontmenu'};                  $confhash->{$role}{'fontmenu'} = $env{'form.'.$role.'_fontmenu'};
             }              }
         }          }
Line 12375  sub modify_colors { Line 8698  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 12403  sub modify_colors { Line 8721  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 12433  sub modify_colors { Line 8748  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 12467  sub modify_colors { Line 8779  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 12600  sub default_change_checker { Line 8898  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 12643  sub display_colorchgs { Line 8936  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 {
                             my $newitem = $confhash->{$role}{$item};                              my $newitem = $confhash->{$role}{$item};
                             if ($key eq 'images') {                              if ($key eq 'images') {
                                 $newitem = '<img src="'.$confhash->{$role}{$item}.'" alt="'.$choices{$item}.'" valign="bottom" />';                                  $newitem = '<img src="'.$confhash->{$role}{$item}.'" alt="'.$choices{$item}.'" style="vertical-align: bottom" />';
                             }                              }
                             $resulttext .= '<li>'.&mt("$choices{$item} set to [_1]",$newitem).'</li>';                              $resulttext .= '<li>'.&mt("$choices{$item} set to [_1]",$newitem).'</li>';
                         }                          }
Line 12708  sub check_configuser { Line 8994  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 12735  sub check_authorstatus { Line 9021  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,$madethumb);
         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;
                           my @args = ('convert','-sample',$thumbsize,$inputfile,$outfile);
                           system({$args[0]} @args);
                           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;
                                   }
                                   $madethumb = 1;
                               } else {
                                   print $logfile "\nUnable to write ".$copyfile.
                                                  ':'.$!."\n";
                               }
                           }
                       }
                   }
               }
           } else {
               $output = $versionresult;
           }
       }
       return ($output,$logourl,$madethumb);
   }
   
   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 12795  sub subscribed_hosts { Line 9294  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 12821  sub modify_quotas { Line 9314  sub modify_quotas {
         $author_ok,$switchserver,$errors,$validationitemsref,$validationnamesref,          $author_ok,$switchserver,$errors,$validationitemsref,$validationnamesref,
         $validationfieldsref);          $validationfieldsref);
     if ($action eq 'quotas') {      if ($action eq 'quotas') {
         $context = 'tools';          $context = 'tools'; 
     } else {      } else {
         $context = $action;          $context = $action;
     }      }
     if ($context eq 'requestcourses') {      if ($context eq 'requestcourses') {
         @usertools = ('official','unofficial','community','textbook','lti');          @usertools = ('official','unofficial','community','textbook','placement');
         @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 12841  sub modify_quotas { Line 9334  sub modify_quotas {
         @usertools = ('author');          @usertools = ('author');
         %titles = &authorrequest_titles();          %titles = &authorrequest_titles();
     } else {      } else {
         @usertools = ('aboutme','blog','portfolio','portaccess','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 12864  sub modify_quotas { Line 9357  sub modify_quotas {
         } else {          } else {
             if ($key =~ /^form\.quota_(.+)$/) {              if ($key =~ /^form\.quota_(.+)$/) {
                 $confhash{'defaultquota'}{$1} = $env{$key};                  $confhash{'defaultquota'}{$1} = $env{$key};
               } elsif ($key =~ /^form\.authorquota_(.+)$/) {
                   $confhash{'authorquota'}{$1} = $env{$key};
             } elsif ($key =~ /^form\.\Q$context\E_(.+)$/) {              } elsif ($key =~ /^form\.\Q$context\E_(.+)$/) {
                 @{$toolshash{$1}} = &Apache::loncommon::get_env_multiple($key);                  @{$toolshash{$1}} = &Apache::loncommon::get_env_multiple($key);
             }              }
Line 12873  sub modify_quotas { Line 9368  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','placement');
         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 13157  sub modify_quotas { Line 9652  sub modify_quotas {
         }          }
     } else {      } else {
         $confhash{'defaultquota'}{'default'} = $env{'form.defaultquota'};          $confhash{'defaultquota'}{'default'} = $env{'form.defaultquota'};
           $confhash{'authorquota'}{'default'} = $env{'form.authorquota'};
     }      }
     foreach my $item (@usertools) {      foreach my $item (@usertools) {
         foreach my $type (@{$types},'default','_LC_adv') {          foreach my $type (@{$types},'default','_LC_adv') {
Line 13245  sub modify_quotas { Line 9741  sub modify_quotas {
                 }                  }
             }              }
             if (ref($domconfig{'quotas'}{'authorquota'}) eq 'HASH') {              if (ref($domconfig{'quotas'}{'authorquota'}) eq 'HASH') {
                 $confhash{'authorquota'} = $domconfig{'quotas'}{'authorquota'};                  foreach my $key (keys(%{$domconfig{'quotas'}{'authorquota'}})) {
             }                      if (exists($confhash{'authorquota'}{$key})) {
             if (ref($domconfig{'quotas'}{'webdav'}) eq 'HASH') {                          if ($confhash{'authorquota'}{$key} ne $domconfig{'quotas'}{'authorquota'}{$key}) {
                 $confhash{'webdav'} = $domconfig{'quotas'}{'webdav'};                              $changes{'authorquota'}{$key} = 1;
                           }
                       } else {
                           $confhash{'authorquota'}{$key} = $domconfig{'quotas'}{'authorquota'}{$key};
                       }
                   }
             }              }
         }          }
         if (ref($confhash{'defaultquota'}) eq 'HASH') {          if (ref($confhash{'defaultquota'}) eq 'HASH') {
Line 13268  sub modify_quotas { Line 9769  sub modify_quotas {
                 }                  }
             }              }
         }          }
           if (ref($confhash{'authorquota'}) eq 'HASH') {
               foreach my $key (keys(%{$confhash{'authorquota'}})) {
                   if (ref($domconfig{'quotas'}) eq 'HASH') {
                       if (ref($domconfig{'quotas'}{'authorquota'}) eq 'HASH') {
                           if (!exists($domconfig{'quotas'}{'authorquota'}{$key})) {
                               $changes{'authorquota'}{$key} = 1;
                           }
                       } else {
                           $changes{'authorquota'}{$key} = 1;
                       }
                   } else {
                       $changes{'authorquota'}{$key} = 1;
                   }
               }
           }
     }      }
   
     if ($context eq 'requestauthor') {      if ($context eq 'requestauthor') {
Line 13308  sub modify_quotas { Line 9824  sub modify_quotas {
                     }                      }
                     $resulttext .= '</ul></li>';                      $resulttext .= '</ul></li>';
                 }                  }
                   if (ref($changes{'authorquota'}) eq 'HASH') {
                       $resulttext .= '<li>'.&mt('Authoring Space default quotas').'<ul>';
                       foreach my $type (@{$types},'default') {
                           if (defined($changes{'authorquota'}{$type})) {
                               my $typetitle = $usertypes->{$type};
                               if ($type eq 'default') {
                                   $typetitle = $othertitle;
                               }
                               $resulttext .= '<li>'.&mt('[_1] set to [_2] MB',$typetitle,$confhash{'authorquota'}{$type}).'</li>';
                           }
                       }
                       $resulttext .= '</ul></li>';
                   }
             }              }
             my %newenv;              my %newenv;
             foreach my $item (@usertools) {              foreach my $item (@usertools) {
Line 13459  sub modify_quotas { Line 9988  sub modify_quotas {
                             $resulttext .= '<li>'.&mt('Validated course requests identified as processed by: [_1]',                              $resulttext .= '<li>'.&mt('Validated course requests identified as processed by: [_1]',
                                                      '<b>'.$changes{'validation'}{'dc'}.'</b>').'</li>';                                                       '<b>'.$changes{'validation'}{'dc'}.'</b>').'</li>';
                         }                          }
                         $resulttext .= '</ul></li>';  
                     }                      }
                 }                  }
             }              }
Line 13497  sub process_textbook_image { Line 10025  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/$cdom/$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 13519  sub process_textbook_image { Line 10044  sub process_textbook_image {
   
 sub modify_ltitools {  sub modify_ltitools {
     my ($r,$dom,$action,$lastactref,%domconfig) = @_;      my ($r,$dom,$action,$lastactref,%domconfig) = @_;
     my (%currtoolsec,%secchanges,%newtoolsec,%newkeyset);      my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
     &fetch_secrets($dom,'toolsec',\%domconfig,\%currtoolsec,\%secchanges,\%newtoolsec,\%newkeyset);      my ($newid,@allpos,%changes,%confhash,%encconfig,$errors,$resulttext);
   
     my $confname = $dom.'-domainconfig';      my $confname = $dom.'-domainconfig';
     my $servadm = $r->dir_config('lonAdmEMail');      my $servadm = $r->dir_config('lonAdmEMail');
     my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);      my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);
       my (%posslti,%possfield);
     my ($resulttext,$ltitoolsoutput,$is_home,$errors,%ltitoolschg,%newtoolsenc,%newltitools);      my @courseroles = ('cc','in','ta','ep','st');
     my $toolserror =      my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner);
         &Apache::courseprefs::process_ltitools($r,$dom,$confname,$domconfig{'ltitools'},\%ltitoolschg,'domain',      map { $posslti{$_} = 1; } @ltiroles;
                                                $lastactref,$configuserok,$switchserver,$author_ok);      my @allfields = ('fullname','firstname','lastname','email','user','roles');
       map { $possfield{$_} = 1; } @allfields;
     my $home = &Apache::lonnet::domain($dom,'primary');      my %lt = &ltitools_names(); 
     unless (($home eq 'no_host') || ($home eq '')) {      if ($env{'form.ltitools_add'}) {
         my @ids=&Apache::lonnet::current_machine_ids();          my $title = $env{'form.ltitools_add_title'};
         foreach my $id (@ids) { if ($id eq $home) { $is_home=1; last; } }          $title =~ s/(`)/'/g;
     }          ($newid,my $error) = &get_ltitools_id($dom,$title);
           if ($newid) {
     if (keys(%ltitoolschg)) {              my $position = $env{'form.ltitools_add_pos'};
         foreach my $id (keys(%ltitoolschg)) {              $position =~ s/\D+//g;
             if (ref($ltitoolschg{$id}) eq 'HASH') {              if ($position ne '') {
                 foreach my $inner (keys(%{$ltitoolschg{$id}})) {                  $allpos[$position] = $newid;
                     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;  
             }              }
         }              $changes{$newid} = 1;
     }              foreach my $item ('title','url','key','secret') {
     my $secrets;                  $env{'form.ltitools_add_'.$item} =~ s/(`)/'/g;
     if ($context eq 'ltisec') {                  if ($env{'form.ltitools_add_'.$item}) {
         $secrets = 'ltisecrets';                      if (($item eq 'key') || ($item eq 'secret')) {
     } else {                          $encconfig{$newid}{$item} = $env{'form.ltitools_add_'.$item};
         $secrets = 'toolsecrets';                      } else {
     }                          $confhash{$newid}{$item} = $env{'form.ltitools_add_'.$item};
     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};  
                 }                  }
             }              }
         }              if ($env{'form.ltitools_add_version'} eq 'LTI-1p0') {
     }                  $confhash{$newid}{'version'} = $env{'form.ltitools_add_version'};
 }  
   
 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) {              if ($env{'form.ltitools_add_msgtype'} eq 'basic-lti-launch-request') {
                 my $shown = $encrypted{$type}{'off'};                  $confhash{$newid}{'msgtype'} = $env{'form.ltitools_add_msgtype'};
                 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') {              foreach my $item ('width','height','linktext','explanation') {
             my %titles = &Apache::lonlocal::texthash(                  $env{'form.ltitools_add_'.$item} =~ s/^\s+//;
                                       min   => 'Minimum password length',                  $env{'form.ltitools_add_'.$item} =~ s/\s+$//;
                                       max   => 'Maximum password length',                  if (($item eq 'width') || ($item eq 'height')) {
                                       chars => 'Required characters',                      if ($env{'form.ltitools_add_'.$item} =~ /^\d+$/) {
                          );                          $confhash{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item};
             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 {                  } else {
                     $output .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$newsec->{rules}{$rule}).'</li>';                      if ($env{'form.ltitools_add_'.$item} ne '') {
                           $confhash{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item}; 
                       }
                 }                  }
             }              }
             if (ref($newsec->{'rules'}{'chars'}) eq 'ARRAY') {              if ($env{'form.ltitools_add_target'} eq 'window') {
                 if (@{$newsec->{'rules'}{'chars'}} > 0) {                  $confhash{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'};
                     my %rulenames = &Apache::lonlocal::texthash(              } elsif ($env{'form.ltitools_add_target'} eq 'tab') {
                                              uc => 'At least one upper case letter',                  $confhash{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'};
                                              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 {              } else {
                 $output .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';                  $confhash{$newid}{'display'}{'target'} = 'iframe';
             }  
         } elsif ($item eq 'private') {  
             $needs_update = 1;  
             if ($context eq 'lti') {  
                 undef($domdefaults{'ltiprivhosts'});  
             } elsif ($context eq 'ltitools') {  
                 undef($domdefaults{'toolprivhosts'});  
             }              }
             if (keys(%{$newkeyset})) {              foreach my $item ('passback','roster') {
                 my @privhosts;                  if ($env{'form.ltitools_add_'.$item}) {
                 foreach my $hostid (sort(keys(%{$newkeyset}))) {                      $confhash{$newid}{$item} = 1;
                     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') {              if ($env{'form.ltitools_add_image.filename'} ne '') {
             next;                  my ($imageurl,$error) =
         } elsif ($item eq 'suggested') {                      &process_ltitools_image($r,$dom,$confname,'ltitools_add_image',$newid,
             if ((ref($secchanges->{'suggested'}) eq 'HASH') &&                                              $configuserok,$switchserver,$author_ok);
                 (ref($newsec->{'suggested'}) eq 'HASH')) {                  if ($imageurl) {
                 my $suggestions;                      $confhash{$newid}{'image'} = $imageurl;
                 foreach my $id (sort { $a <=> $b } keys(%{$secchanges->{'suggested'}})) {  
                     if (ref($newsec->{'suggested'}->{$id}) eq 'HASH') {  
                         my $name = $newsec->{'suggested'}->{$id}->{'name'};  
                         my $info = $newsec->{'suggested'}->{$id}->{'info'};  
                         $suggestions .= '<li>'.&mt('Launcher: [_1]',$name).'<br />'.  
                                                &mt('Recommend: [_1]','<pre>'.$info.'</pre>').  
                                         '</li>';  
                     } else {  
                         $suggestions .= '<li>'.&mt('Recommendations deleted for Launcher: [_1]',  
                                                    $newsec->{'suggested'}->{$id}).'</li>';  
                     }  
                 }  
                 if ($suggestions) {  
                     $output .= '<li>'.&mt('Hints in Courses for Link Protector Configuration').  
                                '<ul>'.$suggestions.'</ul>'.  
                                '</li>';  
                 }                  }
             }                  if ($error) {
         }                      &Apache::lonnet::logthis($error);
     }                      $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
     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};  
             }              }
         }              my @fields = &Apache::loncommon::get_env_multiple('form.ltitools_add_fields');
         $linkprotoutput = &Apache::courseprefs::store_linkprot($dom,'','domain',\%linkprotchg,\%oldlinkprot);              foreach my $field (@fields) {
         if (keys(%linkprotchg)) {                  if ($possfield{$field}) {
             %{$newltisec{'linkprot'}} = %linkprotchg;                      if ($field eq 'roles') {
         }                          foreach my $role (@courseroles) {
     }                              my $choice = $env{'form.ltitools_add_roles_'.$role};
     if (ref($currltisec{'linkprot'}) eq 'HASH') {                              if (($choice ne '') && ($posslti{$choice})) {
         foreach my $id (keys(%{$currltisec{'linkprot'}})) {                                  $confhash{$newid}{'roles'}{$role} = $choice;
             next if ($id !~ /^\d+$/);                                  if ($role eq 'cc') {
             unless (exists($linkprotchg{$id})) {                                      $confhash{$newid}{'roles'}{'co'} = $choice; 
                 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 (%delsuggested,%suggids,@suggested);;  
     if (ref($currltisec{'suggested'}) eq 'HASH') {  
         my $maxnum = $env{'form.linkprot_suggested_maxnum'};  
         my @todelete = &Apache::loncommon::get_env_multiple('form.linkprot_suggested_del');  
         for (my $i=0; $i<$maxnum; $i++) {  
             my $itemid = $env{'form.linkprot_suggested_id_'.$i};  
             $itemid =~ s/\D+//g;  
             if ($itemid) {  
                 if (ref($currltisec{'suggested'}->{$itemid}) eq 'HASH') {  
                     push(@suggested,$i);  
                     $suggids{$i} = $itemid;  
                     if ((@todelete > 0) && (grep(/^$i$/,@todelete))) {  
                         if (ref($currltisec{'suggested'}{$itemid}) eq 'HASH') {  
                             $delsuggested{$itemid} = $currltisec{'suggested'}{$itemid}{'name'};  
                         }                          }
                     } else {                      } else {
                         if ($env{'form.linkprot_suggested_name_'.$i} eq '') {                          $confhash{$newid}{'fields'}{$field} = 1;
                             $delsuggested{$itemid} = $currltisec{'suggested'}{$itemid}{'name'};  
                         } else {  
                             $env{'form.linkprot_suggested_name_'.$i} =~ s/(`)/'/g;  
                             $env{'form.linkprot_suggested_info_'.$i} =~ s/(`)/'/g;  
                             $newltisec{'suggested'}{$itemid}{'name'} = $env{'form.linkprot_suggested_name_'.$i};  
                             $newltisec{'suggested'}{$itemid}{'info'} = $env{'form.linkprot_suggested_info_'.$i};  
                             if (($currltisec{'suggested'}{$itemid}{'name'} ne $newltisec{'suggested'}{$itemid}{'name'}) ||  
                                 ($currltisec{'suggested'}{$itemid}{'info'} ne $newltisec{'suggested'}{$itemid}{'info'})) {  
                                 $secchanges{'suggested'}{$itemid} = 1;  
                             }  
                         }  
                     }                      }
                 }                  }
             }              }
         }              my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig');
     }              foreach my $item (@courseconfig) {
     foreach my $key (keys(%delsuggested)) {                  $confhash{$newid}{'crsconf'}{$item} = 1;
         $newltisec{'suggested'}{$key} = $delsuggested{$key};  
         $secchanges{'suggested'}{$key} = 1;  
     }  
     if (($env{'form.linkprot_suggested_add'}) &&  
         ($env{'form.linkprot_suggested_name_add'} ne '')) {  
         $env{'form.linkprot_suggested_name_add'} =~ s/(`)/'/g;  
         $env{'form.linkprot_suggested_info_add'} =~ s/(`)/'/g;  
         my ($newsuggid,$errormsg) = &get_lti_id($dom,$env{'form.linkprot_suggested_name_add'},'suggested');  
         if ($newsuggid) {  
             $newltisec{'suggested'}{$newsuggid}{'name'} = $env{'form.linkprot_suggested_name_add'};  
             $newltisec{'suggested'}{$newsuggid}{'info'} = $env{'form.linkprot_suggested_info_add'};  
             $secchanges{'suggested'}{$newsuggid} = 1;  
         } else {  
             my $error = &mt('Failed to acquire unique ID for new Link Protectors in Courses Suggestion');  
             if ($errormsg) {  
                 $error .= ' ('.$errormsg.')';  
             }              }
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';              if ($env{'form.ltitools_add_custom'}) {
         }                  my $name = $env{'form.ltitools_add_custom_name'};
     }                  my $value = $env{'form.ltitools_add_custom_value'};
     my (@items,%deletions,%itemids);                  $value =~ s/(`)/'/g;
     if ($env{'form.lti_add'}) {                  $name =~ s/(`)/'/g;
         my $consumer = $env{'form.lti_consumer_add'};                  $confhash{$newid}{'custom'}{$name} = $value;
         $consumer =~ s/(`)/'/g;  
         ($newid,my $errormsg) = &get_lti_id($dom,$consumer,'lti');  
         if ($newid) {  
             $itemids{'add'} = $newid;  
             push(@items,'add');  
             $changes{$newid} = 1;  
         } else {  
             my $error = &mt('Failed to acquire unique ID for new LTI configuration');  
             if ($errormsg) {  
                 $error .= ' ('.$errormsg.')';  
             }              }
           } else {
               my $error = &mt('Failed to acquire unique ID for new external tool');   
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';              $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
         }          }
     }      }
     if (ref($domconfig{$action}) eq 'HASH') {      if (ref($domconfig{$action}) eq 'HASH') {
         my @todelete = &Apache::loncommon::get_env_multiple('form.lti_del');          my %deletions;
           my @todelete = &Apache::loncommon::get_env_multiple('form.ltitools_del');
         if (@todelete) {          if (@todelete) {
             map { $deletions{$_} = 1; } @todelete;              map { $deletions{$_} = 1; } @todelete;
         }          }
         my $maxnum = $env{'form.lti_maxnum'};          my %customadds;
         for (my $i=0; $i<$maxnum; $i++) {          my @newcustom = &Apache::loncommon::get_env_multiple('form.ltitools_customadd');
             my $itemid = $env{'form.lti_id_'.$i};          if (@newcustom) {
               map { $customadds{$_} = 1; } @newcustom;
           } 
           my %imgdeletions;
           my @todeleteimages = &Apache::loncommon::get_env_multiple('form.ltitools_image_del');
           if (@todeleteimages) {
               map { $imgdeletions{$_} = 1; } @todeleteimages;
           }
           my $maxnum = $env{'form.ltitools_maxnum'};
           for (my $i=0; $i<=$maxnum; $i++) {
               my $itemid = $env{'form.ltitools_id_'.$i};
             $itemid =~ s/\D+//g;              $itemid =~ s/\D+//g;
             if (ref($domconfig{$action}{$itemid}) eq 'HASH') {              if (ref($domconfig{$action}{$itemid}) eq 'HASH') {
                 if ($deletions{$itemid}) {                  if ($deletions{$itemid}) {
                     $changes{$itemid} = $domconfig{$action}{$itemid}{'consumer'};                      if ($domconfig{$action}{$itemid}{'image'}) {
                 } else {                          #FIXME need to obsolete item in RES space
                     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;  
                         }  
                     }                      }
                       $changes{$itemid} = $domconfig{$action}{$itemid}{'title'};
                       next;
                 } else {                  } else {
                     $confhash{$itemid}{'lcauth'} = 'lti';                      my $newpos = $env{'form.ltitools_'.$itemid};
                 }                      $newpos =~ s/\D+//g;
             }                      foreach my $item ('title','url') {
             my @possinstdata =  &Apache::loncommon::get_env_multiple('form.lti_instdata_'.$idx);                          $confhash{$itemid}{$item} = $env{'form.ltitools_'.$item.'_'.$i};
             if (@possinstdata) {                          if ($domconfig{$action}{$itemid}{$item} ne $confhash{$itemid}{$item}) {
                 foreach my $field (@possinstdata) {                              $changes{$itemid} = 1;
                     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);  
                     }                      }
                 }                      foreach my $item ('key','secret') {
             }                          $encconfig{$itemid}{$item} = $env{'form.ltitools_'.$item.'_'.$i};
             if ($confhash{$itemid}{'crsinc'}) {                          if ($domconfig{$action}{$itemid}{$item} ne $encconfig{$itemid}{$item}) {
                 if (($env{'form.lti_mapcrs_'.$idx} eq 'course_offering_sourcedid') ||                              $changes{$itemid} = 1;
                     ($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);  
                     }                      }
                 }                      if ($env{'form.ltitools_version_'.$i} eq 'LTI-1p0') {
                 $confhash{$itemid}{'mapcrstype'} = \@crstypes;                          $confhash{$itemid}{'version'} = $env{'form.ltitools_version_'.$i};
                 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;  
                     }                      }
                 }                      if ($env{'form.ltitools_msgtype_'.$i} eq 'basic-lti-launch-request') {
                 my @possenroll = &Apache::loncommon::get_env_multiple('form.lti_selfenroll_'.$idx);                          $confhash{$itemid}{'msgtype'} = $env{'form.ltitools_msgtype_'.$i};
                 my @selfenroll;  
                 foreach my $type (sort(@possenroll)) {  
                     if ($posslticrs{$type}) {  
                         push(@selfenroll,$type);  
                     }                      }
                 }                      foreach my $size ('width','height') {
                 $confhash{$itemid}{'selfenroll'} = \@selfenroll;                          $env{'form.ltitools_'.$size.'_'.$i} =~ s/^\s+//;
                 if ($env{'form.lti_crssec_'.$idx}) {                          $env{'form.ltitools_'.$size.'_'.$i} =~ s/\s+$//;
                     if ($env{'form.lti_crssecsrc_'.$idx} eq 'course_section_sourcedid') {                          if ($env{'form.ltitools_'.$size.'_'.$i} =~ /^\d+$/) {
                         $confhash{$itemid}{'section'} = $env{'form.lti_crssecsrc_'.$idx};                              $confhash{$itemid}{'display'}{$size} = $env{'form.ltitools_'.$size.'_'.$i};
                     } elsif ($env{'form.lti_crssecsrc_'.$idx} eq 'other') {                              if (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {
                         my $section = $env{'form.lti_customsection_'.$idx};                                  if ($domconfig{$action}{$itemid}{'display'}{$size} ne $confhash{$itemid}{'display'}{$size}) {
                         $section =~ s/(`)/'/g;                                      $changes{$itemid} = 1;
                         $section =~ s/^\s+|\s+$//g;                                  }
                         if ($section ne '') {                              } else {
                             $confhash{$itemid}{'section'} = $section;                                  $changes{$itemid} = 1;
                               }
                           } elsif (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {
                               if ($domconfig{$action}{$itemid}{'display'}{$size} ne '') {
                                   $changes{$itemid} = 1;
                               }
                         }                          }
                     }                      }
                 }                      foreach my $item ('linktext','explanation') {
                 foreach my $field ('passback','roster') {                          $env{'form.ltitools_'.$item.'_'.$i} =~ s/^\s+//;
                     if ($env{'form.lti_'.$field.'_'.$idx}) {                          $env{'form.ltitools_'.$item.'_'.$i} =~ s/\s+$//;
                         $confhash{$itemid}{$field} = 1;                          if ($env{'form.ltitools_'.$item.'_'.$i} ne '') {
                               $confhash{$itemid}{'display'}{$item} = $env{'form.ltitools_'.$item.'_'.$i};
                               if (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {
                                   if ($domconfig{$action}{$itemid}{'display'}{$item} ne $confhash{$itemid}{'display'}{$item}) {
                                       $changes{$itemid} = 1;
                                   }
                               } else {
                                   $changes{$itemid} = 1;
                               }
                           } elsif (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {
                               if ($domconfig{$action}{$itemid}{'display'}{$item} ne '') {
                                   $changes{$itemid} = 1;
                               }
                           }
                     }                      }
                 }                      if ($env{'form.ltitools_target_'.$i} eq 'window') {
                 if ($env{'form.lti_passback_'.$idx}) {                          $confhash{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i};
                     if ($env{'form.lti_passbackformat_'.$idx} eq '1.0') {                      } elsif ($env{'form.ltitools_target_'.$i} eq 'tab') {
                         $confhash{$itemid}{'passbackformat'} = '1.0';                          $confhash{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i};
                     } else {                      } else {
                         $confhash{$itemid}{'passbackformat'} = '1.1';                          $confhash{$itemid}{'display'}{'target'} = 'iframe';
                     }                      }
                 }                      if (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {
             }                          if ($domconfig{$action}{$itemid}{'display'}{'target'} ne $confhash{$itemid}{'display'}{'target'}) {
             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;                              $changes{$itemid} = 1;
                         }                          }
                       } else {
                           $changes{$itemid} = 1;
                     }                      }
                     unless ($changes{$itemid}) {                      foreach my $extra ('passback','roster') {
                         if ($currlti{'passback'} eq $confhash{$itemid}{'passback'}) {                          if ($env{'form.ltitools_'.$extra.'_'.$i}) {
                             if ($currlti{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) {                              $confhash{$itemid}{$extra} = 1;
                                 $changes{$itemid} = 1;                          }
                             }                          if ($domconfig{$action}{$itemid}{$extra} ne $confhash{$itemid}{$extra}) {
                               $changes{$itemid} = 1;
                         }                          }
                     }                      }
                     foreach my $field ('mapcrstype','selfenroll') {                      my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig_'.$i);
                         unless ($changes{$itemid}) {                      foreach my $item ('label','title','target','linktext','explanation','append') {
                             if (ref($currlti{$field}) eq 'ARRAY') {                          if (grep(/^\Q$item\E$/,@courseconfig)) {
                                 if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {                              $confhash{$itemid}{'crsconf'}{$item} = 1;
                                     my @diffs = &Apache::loncommon::compare_arrays($currlti{$field},                              if (ref($domconfig{$action}{$itemid}{'crsconf'}) eq 'HASH') {
                                                                                    $confhash{$itemid}{$field});                                  if ($domconfig{$action}{$itemid}{'crsconf'}{$item} ne $confhash{$itemid}{'crsconf'}{$item}) {
                                     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;                                      $changes{$itemid} = 1;
                                 }                                  }
                               } else {
                                   $changes{$itemid} = 1;
                             }                              }
                         }                          }
                     }                      }
                     unless ($changes{$itemid}) {                      my @fields = &Apache::loncommon::get_env_multiple('form.ltitools_fields_'.$i);
                         if (ref($currlti{'maproles'}) eq 'HASH') {                      foreach my $field (@fields) {
                             if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {                          if ($possfield{$field}) {
                                 foreach my $ltirole (keys(%{$currlti{'maproles'}})) {                              if ($field eq 'roles') {
                                     if ($currlti{'maproles'}{$ltirole} ne                                  foreach my $role (@courseroles) {
                                         $confhash{$itemid}{'maproles'}{$ltirole}) {                                      my $choice = $env{'form.ltitools_roles_'.$role.'_'.$i};
                                         $changes{$itemid} = 1;                                      if (($choice ne '') && ($posslti{$choice})) {
                                         last;                                          $confhash{$itemid}{'roles'}{$role} = $choice;
                                           if ($role eq 'cc') {
                                               $confhash{$itemid}{'roles'}{'co'} = $choice;
                                           }
                                     }                                      }
                                 }                                      if (ref($domconfig{$action}{$itemid}{'roles'}) eq 'HASH') {
                                 unless ($changes{$itemid}) {                                          if ($domconfig{$action}{$itemid}{'roles'}{$role} ne $confhash{$itemid}{'roles'}{$role}) {
                                     foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) {  
                                         if ($confhash{$itemid}{'maproles'}{$ltirole} ne  
                                             $currlti{'maproles'}{$ltirole}) {  
                                             $changes{$itemid} = 1;                                              $changes{$itemid} = 1;
                                             last;  
                                         }                                          }
                                       } elsif ($confhash{$itemid}{'roles'}{$role}) {
                                           $changes{$itemid} = 1;
                                     }                                      }
                                 }                                  }
                             } elsif (keys(%{$currlti{'maproles'}}) > 0) {                              } else {
                                 $changes{$itemid} = 1;                                  $confhash{$itemid}{'fields'}{$field} = 1;
                             }                                  if (ref($domconfig{$action}{$itemid}{'fields'}) eq 'HASH') {
                         } elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {                                      if ($domconfig{$action}{$itemid}{'fields'}{$field} ne $confhash{$itemid}{'fields'}{$field}) {
                             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;                                          $changes{$itemid} = 1;
                                     }                                      }
                                 } elsif (@{$currlti{$field}} > 0) {                                  } else {
                                     $changes{$itemid} = 1;  
                                 }  
                             } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {  
                                 if (@{$confhash{$itemid}{$field}} > 0) {  
                                     $changes{$itemid} = 1;                                      $changes{$itemid} = 1;
                                 }                                  }
                             }                              }
                         }                          }
                     }                      }
                       $allpos[$newpos] = $itemid;
                 }                  }
             }                  if ($imgdeletions{$itemid}) {
         }                      $changes{$itemid} = 1;
         if ($is_home) {                      #FIXME need to obsolete item in RES space
             my $keyitem = 'form.lti_key_'.$idx;                  } elsif ($env{'form.ltitools_image_'.$i.'.filename'}) {
             $env{$keyitem} =~ s/(`)/'/g;                      my ($imgurl,$error) = &process_ltitools_image($r,$dom,$confname,'ltitools_image_'.$i,
             if ($env{$keyitem} ne '') {                                                                   $itemid,$configuserok,$switchserver,
                 $ltienc{$itemid}{'key'} = $env{$keyitem};                                                                   $author_ok);
                 unless ($changes{$itemid}) {                      if ($imgurl) {
                     if ($currlti{'key'} ne $env{$keyitem}) {                          $confhash{$itemid}{'image'} = $imgurl;
                         $changes{$itemid} = 1;                          $changes{$itemid} = 1;
                     }                      }
                 }                      if ($error) {
             }                          &Apache::lonnet::logthis($error);
             my $secretitem = 'form.lti_secret_'.$idx;                          $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
             $env{$secretitem} =~ s/(`)/'/g;                      }
             if ($currlti{'usable'}) {                  } elsif ($domconfig{$action}{$itemid}{'image'}) {
                 if ($env{'form.lti_changesecret_'.$idx}) {                      $confhash{$itemid}{'image'} =
                     if ($env{$secretitem} ne '') {                         $domconfig{$action}{$itemid}{'image'};
                         if ($privnum && $cipher) {                  }
                             $ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});                  if ($customadds{$i}) {
                             $confhash{$itemid}{'cipher'} = $privnum;                      my $name = $env{'form.ltitools_custom_name_'.$i};
                         } else {                      $name =~ s/(`)/'/g;
                             $ltienc{$itemid}{'secret'} = $env{$secretitem};                      $name =~ s/^\s+//;
                         }                      $name =~ s/\s+$//;
                       my $value = $env{'form.ltitools_custom_value_'.$i};
                       $value =~ s/(`)/'/g;
                       $value =~ s/^\s+//;
                       $value =~ s/\s+$//;
                       if ($name ne '') {
                           $confhash{$itemid}{'custom'}{$name} = $value;
                         $changes{$itemid} = 1;                          $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 '') {                  my %customdels;
                 if ($privnum && $cipher) {                  my @customdeletions = &Apache::loncommon::get_env_multiple('form.ltitools_customdel_'.$i); 
                     $ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});                  if (@customdeletions) {
                     $confhash{$itemid}{'cipher'} = $privnum;                      $changes{$itemid} = 1;
                 } else {  
                     $ltienc{$itemid}{'secret'} = $env{$secretitem};  
                 }                  }
                 if (ref($ltienc{$itemid}) eq 'HASH') {                  map { $customdels{$_} = 1; } @customdeletions;
                     if (($ltienc{$itemid}{'key'} ne '') && ($ltienc{$itemid}{'key'} ne '')) {                  if (ref($domconfig{$action}{$itemid}{'custom'}) eq 'HASH') {
                         $confhash{$itemid}{'usable'} = 1;                      foreach my $key (keys(%{$domconfig{$action}{$itemid}{'custom'}})) {
                           unless ($customdels{$key}) {
                               if ($env{'form.ltitools_customval_'.$key.'_'.$i} ne '') {
                                   $confhash{$itemid}{'custom'}{$key} = $env{'form.ltitools_customval_'.$key.'_'.$i}; 
                               }
                               if ($domconfig{$action}{$itemid}{'custom'}{$key} ne $env{'form.ltitools_customval_'.$key.'_'.$i}) {
                                   $changes{$itemid} = 1;
                               }
                           }
                     }                      }
                 }                  }
                 $changes{$itemid} = 1;                  unless ($changes{$itemid}) {
             }                      foreach my $key (keys(%{$domconfig{$action}{$itemid}})) {
         }                          if (ref($domconfig{$action}{$itemid}{$key}) eq 'HASH') {
         unless ($changes{$itemid}) {                              if (ref($confhash{$itemid}{$key}) eq 'HASH') {
             foreach my $key (keys(%currlti)) {                                  foreach my $innerkey (keys(%{$domconfig{$action}{$itemid}{$key}})) {
                 if (ref($currlti{$key}) eq 'HASH') {                                      unless (exists($confhash{$itemid}{$key}{$innerkey})) {
                     if (ref($confhash{$itemid}{$key}) eq 'HASH') {                                          $changes{$itemid} = 1;
                         foreach my $innerkey (keys(%{$currlti{$key}})) {                                          last;
                             unless (exists($confhash{$itemid}{$key}{$innerkey})) {                                      }
                                   }
                               } elsif (keys(%{$domconfig{$action}{$itemid}{$key}}) > 0) {
                                 $changes{$itemid} = 1;                                  $changes{$itemid} = 1;
                                 last;  
                             }                              }
                         }                          }
                     } elsif (keys(%{$currlti{$key}}) > 0) {                          last if ($changes{$itemid});
                         $changes{$itemid} = 1;  
                     }                      }
                 }                  }
                 last if ($changes{$itemid});  
             }              }
         }          }
     }      }
Line 14420  sub modify_lti { Line 10394  sub modify_lti {
             }              }
         }          }
     }      }
       my %ltitoolshash = (
     if ((keys(%changes) == 0) && (keys(%secchanges) == 0)) {                            $action => { %confhash }
         return &mt('No changes made.');                         );
     }      my $putresult = &Apache::lonnet::put_dom('configuration',\%ltitoolshash,
                                                $dom);
     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 ($putresult eq 'ok') {
         if (keys(%ltienchash)) {          my %ltienchash = (
             &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1);                               $action => { %encconfig }
         }                           );
         $resulttext = &mt('Changes made:').'<ul>';          &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom);
         if (keys(%secchanges) > 0) {  
             $resulttext .= &lti_security_results($dom,'lti',\%secchanges,\%newltisec,\%newkeyset,\%keystore);  
             if (exists($secchanges{'linkprot'})) {  
                 $resulttext .= $linkprotoutput;  
             }  
         }  
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
             my $cachetime = 24*60*60;              my $cachetime = 24*60*60;
             &Apache::lonnet::do_cache_new('lti',$dom,\%confhash,$cachetime);              my %ltiall = %confhash;
               foreach my $id (keys(%ltiall)) {
                   if (ref($encconfig{$id}) eq 'HASH') {
                       foreach my $item ('key','secret') {
                           $ltiall{$id}{$item} = $encconfig{$id}{$item};
                       }
                   }
               }
               &Apache::lonnet::do_cache_new('ltitools',$dom,\%ltiall,$cachetime);
             if (ref($lastactref) eq 'HASH') {              if (ref($lastactref) eq 'HASH') {
                 $lastactref->{'lti'} = 1;                  $lastactref->{'ltitools'} = 1;
             }              }
               $resulttext = &mt('Changes made:').'<ul>';
             my %bynum;              my %bynum;
             foreach my $itemid (sort(keys(%changes))) {              foreach my $itemid (sort(keys(%changes))) {
                 if (ref($confhash{$itemid}) eq 'HASH') {                  my $position = $confhash{$itemid}{'order'};
                     my $position = $confhash{$itemid}{'order'};                  $bynum{$position} = $itemid;
                     $bynum{$position} = $itemid;  
                 }  
             }              }
             foreach my $pos (sort { $a <=> $b } keys(%bynum)) {              foreach my $pos (sort { $a <=> $b } keys(%bynum)) {
                 my $itemid = $bynum{$pos};                  my $itemid = $bynum{$pos}; 
                 if (ref($confhash{$itemid}) eq 'HASH') {                  if (ref($confhash{$itemid}) ne 'HASH') {
                     $resulttext .= '<li><b>'.$confhash{$itemid}{'consumer'}.'</b><ul>';                      $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';
                   } else {
                       $resulttext .= '<li><b>'.$confhash{$itemid}{'title'}.'</b>';
                       if ($confhash{$itemid}{'image'}) {
                           $resulttext .= '&nbsp;'.
                                          '<img src="'.$confhash{$itemid}{'image'}.'"'.
                                          ' alt="'.&mt('Tool Provider icon').'" />';
                       }
                       $resulttext .= '</li><ul>';
                     my $position = $pos + 1;                      my $position = $pos + 1;
                     $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';                      $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';
                     foreach my $item ('version','lifetime') {                      foreach my $item ('version','msgtype','url') {
                         if ($confhash{$itemid}{$item} ne '') {                          if ($confhash{$itemid}{$item} ne '') {
                             $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{$item}.'</li>';                              $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{$item}.'</li>';
                         }                          }
                     }                      }
                     if ($ltienc{$itemid}{'key'} ne '') {                      if ($encconfig{$itemid}{'key'} ne '') {
                         $resulttext .= '<li>'.$lt{'key'}.':&nbsp;'.$ltienc{$itemid}{'key'}.'</li>';                          $resulttext .= '<li>'.$lt{'key'}.':&nbsp;'.$encconfig{$itemid}{'key'}.'</li>';
                     }                      }
                     if ($ltienc{$itemid}{'secret'} ne '') {                      if ($encconfig{$itemid}{'secret'} ne '') {
                         $resulttext .= '<li>'.$lt{'secret'}.':&nbsp;['.&mt('not shown').']</li>';                          $resulttext .= '<li>'.$lt{'secret'}.':&nbsp;';
                           my $num = length($encconfig{$itemid}{'secret'});
                           $resulttext .= ('*'x$num).'</li>';
                       }
                       $resulttext .= '<li>'.&mt('Configurable in course:');
                       my @possconfig = ('label','title','target','linktext','explanation','append');
                       my $numconfig = 0; 
                       if (ref($confhash{$itemid}{'crsconf'}) eq 'HASH') { 
                           foreach my $item (@possconfig) {
                               if ($confhash{$itemid}{'crsconf'}{$item}) {
                                   $numconfig ++;
                                   $resulttext .= ' "'.$lt{'crs'.$item}.'"';
                               }
                           }
                       }
                       if (!$numconfig) {
                           $resulttext .= &mt('None');
                     }                      }
                     if ($confhash{$itemid}{'requser'}) {                      $resulttext .= '</li>';
                         if ($confhash{$itemid}{'callback'}) {                      foreach my $item ('passback','roster') {
                             $resulttext .= '<li>'.&mt('Callback setting').': '.$confhash{$itemid}{'callback'}.'</li>';                          $resulttext .= '<li>'.$lt{$item}.'&nbsp;';
                           if ($confhash{$itemid}{$item}) {
                               $resulttext .= &mt('Yes');
                         } else {                          } else {
                             $resulttext .= '<li>'.&mt('Callback to logout LON-CAPA on log out from Consumer').'</li>';                              $resulttext .= &mt('No');
                         }                          }
                         if ($confhash{$itemid}{'mapuser'}) {                          $resulttext .= '</li>';
                             my $shownmapuser;                      }
                             if ($confhash{$itemid}{'mapuser'} eq 'lis_person_sourcedid') {                      if (ref($confhash{$itemid}{'display'}) eq 'HASH') {
                                 $shownmapuser = $lt{'sourcedid'}.' (lis_person_sourcedid)';                          my $displaylist;
                             } elsif ($confhash{$itemid}{'mapuser'} eq 'lis_person_contact_email_primary') {                          if ($confhash{$itemid}{'display'}{'target'}) {
                                 $shownmapuser = $lt{'email'}.' (lis_person_contact_email_primary)';                              $displaylist = &mt('Display target').':&nbsp;'.
                             } else {                                             $confhash{$itemid}{'display'}{'target'}.',';
                                 $shownmapuser = &mt('Other').' ('.$confhash{$itemid}{'mapuser'}.')';  
                             }  
                             $resulttext .= '<li>'.&mt('LON-CAPA username').': '.$shownmapuser.'</li>';  
                         }                          }
                         if (ref($confhash{$itemid}{'makeuser'}) eq 'ARRAY') {                          foreach my $size ('width','height') { 
                             if (@{$confhash{$itemid}{'makeuser'}} > 0) {                              if ($confhash{$itemid}{'display'}{$size}) {
                                 $resulttext .= '<li>'.&mt('Following roles may create user accounts: [_1]',                                  $displaylist .= ('&nbsp;'x2).$lt{$size}.':&nbsp;'.
                                                           join(', ',@{$confhash{$itemid}{'makeuser'}})).'<br />';                                                  $confhash{$itemid}{'display'}{$size}.',';
                                 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 ($displaylist) {
                             if (@{$confhash{$itemid}{'instdata'}} > 0) {                              $displaylist =~ s/,$//;
                                 $resulttext .= '<li>'.&mt('Institutional data will be used when creating a new user for: [_1]',                              $resulttext .= '<li>'.$displaylist.'</li>';
                                                           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') {                          foreach my $item ('linktext','explanation') {
                             $resulttext .= '<li>'.$lt{$item}.':&nbsp;';                              if ($confhash{$itemid}{'display'}{$item}) {
                             if ($confhash{$itemid}{$item}) {                                  $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{'display'}{$item}.'</li>';
                                 $resulttext .= &mt('Yes');  
                             } else {  
                                 $resulttext .= &mt('No');  
                             }                              }
                             $resulttext .= '</li>';  
                         }                          }
                         if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') {                      }
                             if (@{$confhash{$itemid}{'lcmenu'}} > 0) {                      if (ref($confhash{$itemid}{'fields'}) eq 'HASH') {
                                 $resulttext .= '<li>'.&mt('Menu items:').' '.                          my $fieldlist;
                                                join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>';                          foreach my $field (@allfields) {
                             } else {                              if ($confhash{$itemid}{'fields'}{$field}) {
                                 $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>';                                  $fieldlist .= ('&nbsp;'x2).$lt{$field}.',';
                             }                              }
                         }                          }
                         if ($confhash{$itemid}{'crsinc'}) {                          if ($fieldlist) {
                             if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {                              $fieldlist =~ s/,$//;
                                 my $rolemaps;                              $resulttext .= '<li>'.&mt('Data sent').':'.$fieldlist.'</li>';
                                 foreach my $role (@ltiroles) {                          }
                                     if ($confhash{$itemid}{'maproles'}{$role}) {                      }
                                         $rolemaps .= ('&nbsp;'x2).$role.'='.                      if (ref($confhash{$itemid}{'roles'}) eq 'HASH') {
                                                      &Apache::lonnet::plaintext($confhash{$itemid}{'maproles'}{$role},                          my $rolemaps;
                                                                                 'Course').',';                          foreach my $role (@courseroles) {
                                     }                              if ($confhash{$itemid}{'roles'}{$role}) {
                                 }                                  $rolemaps .= ('&nbsp;'x2).&Apache::lonnet::plaintext($role,'Course').'='.
                                 if ($rolemaps) {                                               $confhash{$itemid}{'roles'}{$role}.',';
                                     $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>';  
                                 }  
                             }                              }
                         }                          }
                           if ($rolemaps) {
                               $rolemaps =~ s/,$//; 
                               $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>';
                           }
                     }                      }
                       if (ref($confhash{$itemid}{'custom'}) eq 'HASH') {
                           my $customlist;
                           if (keys(%{$confhash{$itemid}{'custom'}})) {
                               foreach my $key (sort(keys(%{$confhash{$itemid}{'custom'}}))) {
                                   $customlist .= $key.':'.$confhash{$itemid}{'custom'}{$key}.('&nbsp;'x2);
                               } 
                           }
                           if ($customlist) {
                               $resulttext .= '<li>'.&mt('Custom items').': '.$customlist.'</li>';
                           }
                       } 
                     $resulttext .= '</ul></li>';                      $resulttext .= '</ul></li>';
                 }                  }
             }              }
             if (keys(%deletions)) {              $resulttext .= '</ul>';
                 foreach my $itemid (sort { $a <=> $b } keys(%deletions)) {          } else {
                     $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';              $resulttext = &mt('No changes made.');
                 }  
             }  
         }  
         $resulttext .= '</ul>';  
         if (ref($lastactref) eq 'HASH') {  
             if (($secchanges{'encrypt'}) || ($secchanges{'private'}) || (exists($secchanges{'suggested'}))) {  
                 &Apache::lonnet::get_domain_defaults($dom,1);  
                 $lastactref->{'domdefaults'} = 1;  
             }  
         }          }
     } else {      } else {
         $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';          $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';
Line 14658  sub modify_lti { Line 10550  sub modify_lti {
     return $resulttext;      return $resulttext;
 }  }
   
 sub get_priv_creds {  sub process_ltitools_image {
     my ($dom,$home,$encchg,$encrypt,$storedsec) = @_;      my ($r,$dom,$confname,$caller,$itemid,$configuserok,$switchserver,$author_ok) = @_;
     my ($needenc,$cipher,$privnum);      my $filename = $env{'form.'.$caller.'.filename'};
     my %domdefs = &Apache::lonnet::get_domain_defaults($dom);      my ($error,$url);
     if (($encchg) && (ref($encrypt) eq 'HASH')) {      my ($width,$height) = (21,21);
         $needenc = $encrypt->{'consumers'}      if ($configuserok eq 'ok') {
     } else {          if ($switchserver) {
         $needenc = $domdefs{'ltienc_consumers'};              $error = &mt('Upload of Tool Provider (LTI) icon is not permitted to this server: [_1]',
     }                           $switchserver);
     if ($needenc) {          } elsif ($author_ok eq 'ok') {
         if (($storedsec eq 'ok') || ((ref($domdefs{'ltiprivhosts'}) eq 'ARRAY') &&              my ($result,$imageurl,$madethumb) =
                                      (grep(/^\Q$home\E$/,@{$domdefs{'ltiprivhosts'}})))) {                  &publishlogo($r,'upload',$caller,$dom,$confname,
                         my %privhash  = &Apache::lonnet::restore_dom('lti','private',$dom,$home,1);                               "ltitools/$itemid/icon",$width,$height);
             my $privkey = $privhash{'key'};              if ($result eq 'ok') {
             $privnum = $privhash{'version'};                  if ($madethumb) {
             if (($privnum) && ($privkey ne '')) {                      my ($path,$imagefile) = ($imageurl =~ m{^(.+)/([^/]+)$});
                 $cipher = Crypt::CBC->new({'key'     => $privkey,                      my $imagethumb = "$path/tn-".$imagefile;
                                           'cipher'  => 'DES'});                      $url = $imagethumb;
                   } else {
                       $url = $imageurl;
                   }
               } else {
                   $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$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].",$filename,$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].",$filename,$confname,$dom,$configuserok);
     }      }
     return ($cipher,$privnum);      return ($url,$error);
 }  }
   
 sub get_lti_id {  sub get_ltitools_id {
     my ($domain,$consumer,$dbname) = @_;      my ($cdom,$title) = @_;
     unless (($dbname eq 'lti') || ($dbname eq 'suggested')) {      # get lock on ltitools db
         return ('','invalid db');  
     }  
     # get lock on db  
     my $lockhash = {      my $lockhash = {
                       lock => $env{'user.name'}.                        lock => $env{'user.name'}.
                               ':'.$env{'user.domain'},                                ':'.$env{'user.domain'},
                    };                     };
     my $tries = 0;      my $tries = 0;
     my $gotlock = &Apache::lonnet::newput_dom($dbname,$lockhash,$domain);      my $gotlock = &Apache::lonnet::newput_dom('ltitools',$lockhash,$cdom);
     my ($id,$error);      my ($id,$error);
    
     while (($gotlock ne 'ok') && ($tries<10)) {      while (($gotlock ne 'ok') && ($tries<10)) {
         $tries ++;          $tries ++;
         sleep (0.1);          sleep (0.1);
         $gotlock = &Apache::lonnet::newput_dom($dbname,$lockhash,$domain);          $gotlock = &Apache::lonnet::newput_dom('ltitools',$lockhash,$cdom);
     }      }
     if ($gotlock eq 'ok') {      if ($gotlock eq 'ok') {
         my %currids = &Apache::lonnet::dump_dom($dbname,$domain);          my %currids = &Apache::lonnet::dump_dom('ltitools',$cdom);
         if ($currids{'lock'}) {          if ($currids{'lock'}) {
             delete($currids{'lock'});              delete($currids{'lock'});
             if (keys(%currids)) {              if (keys(%currids)) {
Line 14714  sub get_lti_id { Line 10612  sub get_lti_id {
                 $id = 1;                  $id = 1;
             }              }
             if ($id) {              if ($id) {
                 unless (&Apache::lonnet::newput_dom($dbname,{ $id => $consumer },$domain) eq 'ok') {                  unless (&Apache::lonnet::newput_dom('ltitools',{ $id => $title },$cdom) eq 'ok') {
                     $error = 'nostore';                      $error = 'nostore';
                 }                  }
             } else {              } else {
                 $error = 'nonumber';                  $error = 'nonumber';
             }              }
         }          }
         my $dellockoutcome = &Apache::lonnet::del_dom($dbname,['lock'],$domain);          my $dellockoutcome = &Apache::lonnet::del_dom('ltitools',['lock'],$cdom);
     } else {      } else {
         $error = 'nolock';          $error = 'nolock';
     }      }
Line 14741  sub modify_autoenroll { Line 10639  sub modify_autoenroll {
     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');                    failsafe => '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 14751  sub modify_autoenroll { Line 10649  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'};      my $failsafe = $env{'form.autoenroll_failsafe'};
     unless (($failsafe eq 'zero') || ($failsafe eq 'any')) {      $failsafe =~ s{^\s+|\s+$}{}g;
         $failsafe = 'off';      if ($failsafe =~ /\D/) {
         undef($autofailsafe);          undef($failsafe);
     }      }
     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,                                         'autofailsafe' => $failsafe,
                                        'failsafe' => $failsafe,  
                                 }                                  }
                      );                       );
     my $putresult = &Apache::lonnet::put_dom('configuration',\%autoenrollhash,      my $putresult = &Apache::lonnet::put_dom('configuration',\%autoenrollhash,
Line 14795  sub modify_autoenroll { Line 10687  sub modify_autoenroll {
         } elsif ($coowners) {          } elsif ($coowners) {
             $changes{'coowners'} = 1;              $changes{'coowners'} = 1;
         }          }
         if ($currautoenroll{'autofailsafe'} ne $autofailsafe) {          if ($currautoenroll{'autofailsafe'} ne $failsafe) {
             $changes{'autofailsafe'} = 1;              $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 14821  sub modify_autoenroll { Line 10710  sub modify_autoenroll {
                 }                  }
             }              }
             if ($changes{'autofailsafe'}) {              if ($changes{'autofailsafe'}) {
                 if ($autofailsafe ne '') {                  if ($failsafe ne '') {
                     $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section set to: [_1]',$autofailsafe).'</li>';                      $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section set to: [_1]',$failsafe).'</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 {                  } else {
                     $resulttext .= '<li>'.&mt('Failsafe applies if retrieved section enrollment is zero or greater').'</li>';                      $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section: deleted');
                 }                  }
             }  
             if (($changes{'autofailsafe'}) || ($changes{'failsafe'})) {  
                 &Apache::lonnet::get_domain_defaults($dom,1);                  &Apache::lonnet::get_domain_defaults($dom,1);
                 if (ref($lastactref) eq 'HASH') {                  if (ref($lastactref) eq 'HASH') {
                     $lastactref->{'domdefaults'} = 1;                      $lastactref->{'domdefaults'} = 1;
Line 14865  sub modify_autoupdate { Line 10741  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 14912  sub modify_autoupdate { Line 10786  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 14974  sub modify_autoupdate { Line 10837  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 15046  sub modify_autoupdate { Line 10899  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 15363  sub modify_contacts { Line 11211  sub modify_contacts {
     my (%others,%to,%bcc,%includestr,%includeloc);      my (%others,%to,%bcc,%includestr,%includeloc);
     my @contacts = ('supportemail','adminemail');      my @contacts = ('supportemail','adminemail');
     my @mailings = ('errormail','packagesmail','helpdeskmail','otherdomsmail',      my @mailings = ('errormail','packagesmail','helpdeskmail','otherdomsmail',
                     'lonstatusmail','requestsmail','updatesmail','idconflictsmail','hostipmail');                      'lonstatusmail','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();      my ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields();
     foreach my $type (@mailings) {      foreach my $type (@mailings) {
         @{$newsetting{$type}} =           @{$newsetting{$type}} = 
Line 15398  sub modify_contacts { Line 11245  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')) {      if ((ref($fields) eq 'ARRAY') && (ref($possoptions) eq 'HASH')) {
         foreach my $field (@{$fields}) {          foreach my $field (@{$fields}) {
             if (ref($possoptions->{$field}) eq 'ARRAY') {              if (ref($possoptions->{$field}) eq 'ARRAY') {
Line 15487  sub modify_contacts { Line 11299  sub modify_contacts {
                     $contacts_hash{'contacts'}{'overrides'}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type});                      $contacts_hash{'contacts'}{'overrides'}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type});
                     $newsetting{'override_'.$type}{'include'} = $contacts_hash{'contacts'}{'overrides'}{$type}{'include'};                      $newsetting{'override_'.$type}{'include'} = $contacts_hash{'contacts'}{'overrides'}{$type}{'include'};
                 }                  }
             }              }     
         }          }
     }      }
     if (keys(%currsetting) > 0) {      if (keys(%currsetting) > 0) {
Line 15545  sub modify_contacts { Line 11357  sub modify_contacts {
             }              }
         }          }
         if (@statuses) {          if (@statuses) {
             if (ref($currsetting{'overrides'}) eq 'HASH') {              if (ref($currsetting{'overrides'}) eq 'HASH') { 
                 foreach my $key (keys(%{$currsetting{'overrides'}})) {                  foreach my $key (keys(%{$currsetting{'overrides'}})) {
                     if (ref($currsetting{'overrides'}{$key}) eq 'HASH') {                      if (ref($currsetting{'overrides'}{$key}) eq 'HASH') {
                         if (ref($newsetting{'override_'.$key}) eq 'HASH') {                          if (ref($newsetting{'override_'.$key}) eq 'HASH') {
                             foreach my $item (@contacts,'bcc','others','include') {                              foreach my $item (@contacts,'bcc','others','include') {
                                 if ($currsetting{'overrides'}{$key}{$item} ne $newsetting{'override_'.$key}{$item}) {                                  if ($currsetting{'overrides'}{$key}{$item} ne $newsetting{'override_'.$key}{$item}) { 
                                     push(@{$changes{'overrides'}},$key);                                      push(@{$changes{'overrides'}},$key);
                                     last;                                      last;
                                 }                                  }
Line 15567  sub modify_contacts { Line 11379  sub modify_contacts {
                 }                  }
             } else {              } else {
                 foreach my $key (@overrides) {                  foreach my $key (@overrides) {
                     push(@{$changes{'overrides'}},$key);                      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);  
                     }  
                 }                  }
             }              }
         }          }
Line 15652  sub modify_contacts { Line 11394  sub modify_contacts {
         $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;
Line 15686  sub modify_contacts { Line 11427  sub modify_contacts {
                 }                  }
             }              }
         }          }
         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);  
                 }  
             }  
         }  
     }      }
     foreach my $item (@toggles) {      foreach my $item (@toggles) {
         if (($env{'form.'.$item} == 1) && ($currsetting{$item} == 0)) {          if (($env{'form.'.$item} == 1) && ($currsetting{$item} == 0)) {
Line 15749  sub modify_contacts { Line 11483  sub modify_contacts {
                             $resulttext .= $bcctext.': <span class="LC_cusr_emph">'.$bcc{$type}.'</span>';                              $resulttext .= $bcctext.': <span class="LC_cusr_emph">'.$bcc{$type}.'</span>';
                         } elsif (!@text) {                          } elsif (!@text) {
                             $resulttext .= &mt('No one');                              $resulttext .= &mt('No one');
                         }                          }   
                         if ($includestr{$type} ne '') {                          if ($includestr{$type} ne '') {
                             if ($includeloc{$type} eq 'b') {                              if ($includeloc{$type} eq 'b') {
                                 $resulttext .= '<br />'.&mt('Text automatically added to e-mail body:').' '.$includestr{$type};                                  $resulttext .= '<br />'.&mt('Text automatically added to e-mail body:').' '.$includestr{$type};
Line 15773  sub modify_contacts { Line 11507  sub modify_contacts {
                             if (ref($newsetting{'override_'.$type}) eq 'HASH') {                              if (ref($newsetting{'override_'.$type}) eq 'HASH') {
                                 my @text;                                  my @text;
                                 foreach my $item (@contacts) {                                  foreach my $item (@contacts) {
                                     if ($newsetting{'override_'.$type}{$item}) {                                      if ($newsetting{'override_'.$type}{$item}) { 
                                         push(@text,$short_titles->{$item});                                          push(@text,$short_titles->{$item});
                                     }                                      }
                                 }                                  }
                                 if ($newsetting{'override_'.$type}{'others'} ne '') {                                  if ($newsetting{'override_'.$type}{'others'} ne '') {
                                     push(@text,$newsetting{'override_'.$type}{'others'});                                      push(@text,$newsetting{'override_'.$type}{'others'});
                                 }                                  }
     
                                 if (@text) {                                  if (@text) {
                                     $resulttext .= &mt('Helpdesk e-mail sent to: [_1]',                                      $resulttext .= &mt('Helpdesk e-mail sent to: [_1]',
                                                        '<span class="LC_cusr_emph">'.join(', ',@text).'</span>');                                                         '<span class="LC_cusr_emph">'.join(', ',@text).'</span>');
Line 15818  sub modify_contacts { Line 11552  sub modify_contacts {
                 }                  }
             }              }
             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')) {              if ((ref($changes{'helpform'}) eq 'ARRAY') && (ref($fields) eq 'ARRAY')) {
                 my (@optional,@required,@unused,$maxsizechg);                  my (@optional,@required,@unused,$maxsizechg);
                 foreach my $field (@{$changes{'helpform'}}) {                  foreach my $field (@{$changes{'helpform'}}) {
Line 15937  sub modify_contacts { Line 11614  sub modify_contacts {
         }          }
     } 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>';
     }      }
     return $resulttext;      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>';  
         } else {  
             $resulttext = &mt('No changes made to password settings');  
         }  
         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 {  
         $resulttext = '<span class="LC_error">'.  
             &mt('An error occurred: [_1]',$putresult).'</span>';  
     }  
     if ($errors) {  
         $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.  
                        $errors.'</ul></p>';  
     }  
     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 16587  sub modify_usercreation { Line 11703  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 16851  sub modify_selfcreation { Line 11967  sub modify_selfcreation {
                             if (($chosen eq 'inst') || ($chosen eq 'noninst')) {                              if (($chosen eq 'inst') || ($chosen eq 'noninst')) {
                                 my $emaildom;                                  my $emaildom;
                                 if ($env{'form.cancreate_emaildomain_'.$chosen.'_'.$type} =~ /^\@[^\@]+$/) {                                  if ($env{'form.cancreate_emaildomain_'.$chosen.'_'.$type} =~ /^\@[^\@]+$/) {
                                     $emaildom = $env{'form.cancreate_emaildomain_'.$chosen.'_'.$type};                                      $emaildom = $env{'form.cancreate_emaildomain_'.$chosen.'_'.$type}; 
                                     $cancreate{'emaildomain'}{$type}{$chosen} = $emaildom;                                      $cancreate{'emaildomain'}{$type}{$chosen} = $emaildom;
                                     if (ref($curremaildom{$type}) eq 'HASH') {                                      if (ref($curremaildom{$type}) eq 'HASH') {
                                         if (exists($curremaildom{$type}{$chosen})) {                                          if (exists($curremaildom{$type}{$chosen})) {
Line 16863  sub modify_selfcreation { Line 11979  sub modify_selfcreation {
                                         }                                          }
                                     } elsif ($emaildom ne '') {                                      } elsif ($emaildom ne '') {
                                         push(@{$changes{'cancreate'}},'emaildomain');                                          push(@{$changes{'cancreate'}},'emaildomain');
                                     }                                      } 
                                 }                                  }
                                 $cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type};                                  $cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type};
                             } elsif ($chosen eq 'custom') {                              } elsif ($chosen eq 'custom') {
Line 17290  sub modify_selfcreation { Line 12406  sub modify_selfcreation {
                                                                   );                                                                    );
                         if (@types) {                          if (@types) {
                             if (@statuses) {                              if (@statuses) {
                                 $chgtext .= &mt('Processing of requests to create account with e-mail verification set as follows:').                                  $chgtext .= &mt('Processing of requests to create account with e-mail verification set as follows:'). 
                                             '<ul>';                                              '<ul>';
                                 foreach my $status (@statuses) {                                  foreach my $status (@statuses) {
                                     if ($status eq 'default') {                                      if ($status eq 'default') {
Line 17316  sub modify_selfcreation { Line 12432  sub modify_selfcreation {
                                 $chgtext .= &mt('For self-created accounts verified by e-mail address, username is set as follows:').                                  $chgtext .= &mt('For self-created accounts verified by e-mail address, username is set as follows:').
                                             '<ul>';                                              '<ul>';
                                 foreach my $status (@statuses) {                                  foreach my $status (@statuses) {
                                     if ($status eq 'default') {                                      if ($type eq 'default') {
                                         $chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';                                          $chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';
                                     } else {                                      } else {
                                         $chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';                                          $chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';
Line 17376  sub modify_selfcreation { Line 12492  sub modify_selfcreation {
                                                 $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';                                                  $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';
                                             } else {                                              } else {
                                                 $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address needs to end: [_1]",                                                  $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address needs to end: [_1]",
                                                                                               $cancreate{'emaildomain'}{$type}{'inst'}).'</li>';                                                                                                $cancreate{'emaildomain'}{$type}{'inst'}).'</li>'; 
                                             }                                              }
                                         }                                          }
                                     } elsif ($cancreate{'emailoptions'}{$type} eq 'noninst') {                                      } elsif ($cancreate{'emailoptions'}{$type} eq 'noninst') {
Line 17394  sub modify_selfcreation { Line 12510  sub modify_selfcreation {
                                                 $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';                                                  $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';
                                             } else {                                              } else {
                                                 $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address must not end: [_1]",                                                  $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address must not end: [_1]",
                                                                                                 $cancreate{'emaildomain'}{$type}{'noninst'}).'</li>';                                                                                                  $cancreate{'emaildomain'}{$type}{'noninst'}).'</li>';   
                                             }                                              }
                                         }                                          }
                                     }                                      }
Line 17498  sub modify_selfcreation { Line 12614  sub modify_selfcreation {
                                 $typename = $othertitle;                                  $typename = $othertitle;
                             } else {                              } else {
                                 $typename = $usertypes{$type};                                  $typename = $usertypes{$type};
                             }                              } 
                             $chgtext .= &mt('(Affiliation: [_1])',$typename);                              $chgtext .= &mt('(Affiliation: [_1])',$typename);
                         }                          }
                         if (@{$email_rule{$type}} > 0) {                          if (@{$email_rule{$type}} > 0) {
Line 17585  sub modify_selfcreation { Line 12701  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;
         }          }
Line 17625  sub process_captcha { Line 12735  sub process_captcha {
         }          }
         $newsettings->{'recaptchaversion'} = $newversion;          $newsettings->{'recaptchaversion'} = $newversion;
     }      }
     if (ref($current{'recaptchakeys'}) eq 'HASH') {      if (ref($current->{'recaptchakeys'}) eq 'HASH') {
         $currpub = $current{'recaptchakeys'}{'public'};          $currpub = $current->{'recaptchakeys'}{'public'};
         $currpriv = $current{'recaptchakeys'}{'private'};          $currpriv = $current->{'recaptchakeys'}{'private'};
         unless ($newsettings->{'captcha'} eq 'recaptcha') {          unless ($newsettings->{'captcha'} eq 'recaptcha') {
             $newsettings->{'recaptchakeys'} = {              $newsettings->{'recaptchakeys'} = {
                                                  public  => '',                                                   public  => '',
Line 17635  sub process_captcha { Line 12745  sub process_captcha {
                                               }                                                }
         }          }
     }      }
     if ($current{'captcha'} eq 'recaptcha') {      if ($current->{'captcha'} eq 'recaptcha') {
         $currversion = $current{'recaptchaversion'};          $currversion = $current->{'recaptchaversion'};
         if ($currversion ne '2') {          if ($currversion ne '2') {
             $currversion = 1;              $currversion = 1;
         }          }
Line 17648  sub process_captcha { Line 12758  sub process_captcha {
             } elsif (!defined($changes->{'cancreate'})) {              } elsif (!defined($changes->{'cancreate'})) {
                 $changes->{'cancreate'} = ['recaptchaversion'];                  $changes->{'cancreate'} = ['recaptchaversion'];
             }              }
         } elsif ($container eq 'passwords') {  
             $changes->{'reset'} = 1;  
         } else {          } else {
             $changes->{'recaptchaversion'} = 1;              $changes->{'recaptchaversion'} = 1;
         }          }
Line 17661  sub process_captcha { Line 12769  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 17682  sub modify_usermodification { Line 12788  sub modify_usermodification {
             }              }
         }          }
     }      }
     my @contexts = ('author','coauthor','course');      my @contexts = ('author','course');
     my %context_title = (      my %context_title = (
                            author => 'In author context',                             author => 'In author context',
                            coauthor => 'As co-author manager',   
                            course => 'In course context',                             course => 'In course context',
                         );                          );
     my @fields = ('lastname','firstname','middlename','generation',      my @fields = ('lastname','firstname','middlename','generation',
                   'permanentemail','id');                    'permanentemail','id');
     my %roles = (      my %roles = (
                   author => ['ca','aa'],                    author => ['ca','aa'],
                   coauthor => ['ca','aa'],  
                   course => ['st','ep','ta','in','cr'],                    course => ['st','ep','ta','in','cr'],
                 );                  );
     my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();      my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
     foreach my $context (@contexts) {      foreach my $context (@contexts) {
         my $prefix = 'canmodify';  
         if ($context eq 'coauthor') {  
             $prefix = 'cacanmodify';  
         }  
         foreach my $role (@{$roles{$context}}) {          foreach my $role (@{$roles{$context}}) {
             my @modifiable =  &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$role);              my @modifiable =  &Apache::loncommon::get_env_multiple('form.canmodify_'.$role);
             foreach my $item (@fields) {              foreach my $item (@fields) {
                 if (grep(/^\Q$item\E$/,@modifiable)) {                  if (grep(/^\Q$item\E$/,@modifiable)) {
                     $modifyhash{$context}{$role}{$item} = 1;                      $modifyhash{$context}{$role}{$item} = 1;
Line 17784  sub modify_defaults { Line 12884  sub modify_defaults {
     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','intauth_cost','intauth_check','intauth_switch');
     my @authtypes = ('internal','krb4','krb5','localauth','lti');      my @authtypes = ('internal','krb4','krb5','localauth');
     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 17822  sub modify_defaults { Line 12922  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);
                 }                  }
             }              }
         }          } elsif ($item eq 'intauth_cost') {
         if (grep(/^\Q$item\E$/,@errors)) {              if ($newvalues{$item} ne '') {
             $newvalues{$item} = $domdefaults{$item};                  if ($newvalues{$item} =~ /\D/) {
             if ($item eq 'portal_def') {                      push(@errors,$item);
                 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 ($item eq 'intauth_check') {
             $changes{$item} = 1;              if ($newvalues{$item} ne '') {
         }                  unless ($newvalues{$item} =~ /^(0|1|2)$/) {
         if ($item eq 'portal_def') {                      push(@errors,$item);
             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});  
                         }  
                     }  
                 }                  }
             }              }
         }          } elsif ($item eq 'intauth_switch') {
         $domdefaults{$item} = $newvalues{$item};              if ($newvalues{$item} ne '') {
     }                  unless ($newvalues{$item} =~ /^(0|1|2)$/) {
     my %staticdefaults = (                      push(@errors,$item);
                            '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 (grep(/^\Q$item\E$/,@errors)) {
     if (ref($domdefaults{'unamemap_rule'}) eq 'ARRAY') {              $newvalues{$item} = $domdefaults{$item};
         if (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') {          } elsif ($domdefaults{$item} ne $newvalues{$item}) {
             my @rulediffs = &Apache::loncommon::compare_arrays($domdefaults{'unamemap_rule'},              $changes{$item} = 1;
                                                                $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'};  
         }          }
           $domdefaults{$item} = $newvalues{$item};
     }      }
     my %defaults_hash = (      my %defaults_hash = (
                          defaults => \%newvalues,                           defaults => \%newvalues,
Line 17943  sub modify_defaults { Line 12972  sub modify_defaults {
     my @allpos;      my @allpos;
     my %alltypes;      my %alltypes;
     my @inststatusguest;      my @inststatusguest;
     if (ref($currinststatus) eq 'HASH') {      if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') {
         if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') {          foreach my $type (@{$currinststatus->{'inststatusguest'}}) {
             foreach my $type (@{$currinststatus->{'inststatusguest'}}) {              unless (grep(/^\Q$type\E$/,@todelete)) {
                 unless (grep(/^\Q$type\E$/,@todelete)) {                  push(@inststatusguest,$type);
                     push(@inststatusguest,$type);  
                 }  
             }              }
         }          }
     }      }
Line 18036  sub modify_defaults { Line 13063  sub modify_defaults {
                             $resulttext =~ s/, $//;                              $resulttext =~ s/, $//;
                             $resulttext .= '</li>';                              $resulttext .= '</li>';
                         } else {                          } else {
                             $resulttext .= '<li>'.&mt('Institutional user status types deleted').'</li>';                              $resulttext .= '<li>'.&mt('Institutional user status types deleted').'</li>'; 
                         }  
                     }  
                 } elsif ($item eq 'unamemap_rule') {  
                     if (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') {  
                         my @rulenames;  
                         if (ref($unamemaprules) eq 'HASH') {  
                             foreach my $rule (@{$newvalues{'unamemap_rule'}}) {  
                                 if (ref($unamemaprules->{$rule}) eq 'HASH') {  
                                     push(@rulenames,$unamemaprules->{$rule}->{'name'});  
                                 }  
                             }  
                         }  
                         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 18070  sub modify_defaults { Line 13077  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}};
                     }                      } elsif ($item eq 'intauth_switch') {
                     $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$item},$value).'</li>';                          my %optiondesc = &Apache::lonlocal::texthash (
                     $mailmsgtext .= "$title->{$item} set to $value\n";                                              0 => 'No',
                     if ($item eq 'portal_def') {                                              1 => 'Yes',
                         if ($env{'form.'.$item} ne '') {                                              2 => 'Yes, and copy existing passwd file to passwd.bak file',
                             foreach my $field ('email','web') {                                           );
                                 $value = $env{'form.'.$item.'_'.$field};                          if ($value =~ /^(0|1|2)$/) {
                                 if ($value) {                              $value = $optiondesc{$value};
                                     $value = &mt('Yes');                          } else {
                                 } else {                              $value = &mt('none -- defaults to No');
                                     $value = &mt('No');                          }
                                 }                      } elsif ($item eq 'intauth_check') {
                                 $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$field},$value).'</li>';                          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]"',$title->{$item},$value).'</li>';
                       $mailmsgtext .= "$title->{$item} set to $value\n";  
                 }                  }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
Line 18134  sub modify_scantron { Line 13149  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 18143  sub modify_scantron { Line 13158  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 18172  sub modify_scantron { Line 13184  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 18243  sub modify_scantron { Line 13194  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 18333  sub modify_coursecategories { Line 13249  sub modify_coursecategories {
         if ($domconfig{'coursecategories'}{'categorizecomm'} ne $env{'form.categorizecomm'}) {          if ($domconfig{'coursecategories'}{'categorizecomm'} ne $env{'form.categorizecomm'}) {
             $changes{'categorizecomm'} = 1;              $changes{'categorizecomm'} = 1;
             $domconfig{'coursecategories'}{'categorizecomm'} = $env{'form.categorizecomm'};              $domconfig{'coursecategories'}{'categorizecomm'} = $env{'form.categorizecomm'};
   
           }
           if ($domconfig{'coursecategories'}{'togglecatsplace'} ne $env{'form.togglecatsplace'}) {
               $changes{'togglecatsplace'} = 1;
               $domconfig{'coursecategories'}{'togglecatsplace'} = $env{'form.togglecatsplace'};
           }
           if ($domconfig{'coursecategories'}{'categorizeplace'} ne $env{'form.categorizeplace'}) {
               $changes{'categorizeplace'} = 1;
               $domconfig{'coursecategories'}{'categorizeplace'} = $env{'form.categorizeplace'};
         }          }
         foreach my $item (@catitems) {          foreach my $item (@catitems) {
             if (grep(/^\Q$env{'form.coursecat_'.$item}\E$/,@cattypes)) {              if (grep(/^\Q$env{'form.coursecat_'.$item}\E$/,@cattypes)) {
Line 18347  sub modify_coursecategories { Line 13272  sub modify_coursecategories {
         $changes{'categorize'} = 1;          $changes{'categorize'} = 1;
         $changes{'togglecatscomm'} = 1;          $changes{'togglecatscomm'} = 1;
         $changes{'categorizecomm'} = 1;          $changes{'categorizecomm'} = 1;
           $changes{'togglecatsplace'} = 1;
           $changes{'categorizeplace'} = 1;
         $domconfig{'coursecategories'} = {          $domconfig{'coursecategories'} = {
                                              togglecats => $env{'form.togglecats'},                                               togglecats => $env{'form.togglecats'},
                                              categorize => $env{'form.categorize'},                                               categorize => $env{'form.categorize'},
                                              togglecatscomm => $env{'form.togglecatscomm'},                                               togglecatscomm => $env{'form.togglecatscomm'},
                                              categorizecomm => $env{'form.categorizecomm'},                                               categorizecomm => $env{'form.categorizecomm'},
                                                togglecatsplace => $env{'form.togglecatsplace'},
                                                categorizeplace => $env{'form.categorizeplace'},
                                          };                                           };
         foreach my $item (@catitems) {          foreach my $item (@catitems) {
             if ($env{'form.coursecat_'.$item} ne 'std') {              if ($env{'form.coursecat_'.$item} ne 'std') {
Line 18369  sub modify_coursecategories { Line 13298  sub modify_coursecategories {
         if (($domconfig{'coursecategories'}{'cats'}{'communities::0'} ne '')  && ($env{'form.communities'} == 0)) {          if (($domconfig{'coursecategories'}{'cats'}{'communities::0'} ne '')  && ($env{'form.communities'} == 0)) {
             push(@deletecategory,'communities::0');              push(@deletecategory,'communities::0');
         }          }
           if (($domconfig{'coursecategories'}{'cats'}{'placement::0'} ne '')  && ($env{'form.placement'} == 0)) {
               push(@deletecategory,'placement::0');
           }
     }      }
     my (@predelcats,@predeltrails,%predelallitems,%sort_by_deltrail);      my (@predelcats,@predeltrails,%predelallitems,%sort_by_deltrail);
     if (ref($cathash) eq 'HASH') {      if (ref($cathash) eq 'HASH') {
Line 18431  sub modify_coursecategories { Line 13363  sub modify_coursecategories {
             $adds{$newitem} = 1;              $adds{$newitem} = 1;
         }          }
     }      }
       if ($env{'form.placement'} eq '1') {
           if (ref($cathash) eq 'HASH') {
               my $newitem = 'placement::0';
               if ($cathash->{$newitem} eq '') {
                   $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.placement_pos'};
                   $adds{$newitem} = 1;
               }
           } else {
               my $newitem = 'placement::0';
               $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.placement_pos'};
               $adds{$newitem} = 1;
           }
       }
     if ($env{'form.addcategory_name'} ne '') {      if ($env{'form.addcategory_name'} ne '') {
         if (($env{'form.addcategory_name'} ne 'instcode') &&          if (($env{'form.addcategory_name'} ne 'instcode') &&
             ($env{'form.addcategory_name'} ne 'communities')) {              ($env{'form.addcategory_name'} ne 'communities') &&
               ($env{'form.addcategory_name'} ne 'placement')) {
             my $newitem = &escape($env{'form.addcategory_name'}).'::0';              my $newitem = &escape($env{'form.addcategory_name'}).'::0';
             $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos'};              $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos'};
             $adds{$newitem} = 1;              $adds{$newitem} = 1;
Line 18549  sub modify_coursecategories { Line 13495  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 19032  sub modify_coursedefaults { Line 13974  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','uploadquota_placement',
                    'coursequota_unofficial','coursequota_community','coursequota_textbook',  
                    'mysqltables_official','mysqltables_unofficial','mysqltables_community',                     'mysqltables_official','mysqltables_unofficial','mysqltables_community',
                    'mysqltables_textbook');                     'mysqltables_textbook','mysqltables_placement');
     my @types = ('official','unofficial','community','textbook');      my @types = ('official','unofficial','community','textbook','placement');
     my %staticdefaults = (      my %staticdefaults = (
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
                            coursequota          => 20,  
                            postsubmit           => 60,                             postsubmit           => 60,
                            mysqltables          => 172800,                             mysqltables          => 172800,
                            domexttool           => 1,  
                            crseditors           => ['edit','xml'],  
                          );                           );
     my %texoptions = (      my %texoptions = (
                         MathJax  => 'MathJax',                          MathJax  => 'MathJax',
                         mimetex  => &mt('Convert to Images'),                          mimetex  => &mt('Convert to Images'),
                         tth      => &mt('TeX to HTML'),                          tth      => &mt('TeX to HTML'),
                      );                       );
   
     my @editors = ('edit','xml','daxe');  
     my %editornames = &crseditor_titles();  
   
     $defaultshash{'coursedefaults'} = {};      $defaultshash{'coursedefaults'} = {};
   
     if (ref($domconfig{'coursedefaults'}) ne 'HASH') {      if (ref($domconfig{'coursedefaults'}) ne 'HASH') {
Line 19100  sub modify_coursedefaults { Line 14033  sub modify_coursedefaults {
                 }                  }
                 $defaultshash{'coursedefaults'}{$item} = $newdef;                  $defaultshash{'coursedefaults'}{$item} = $newdef;
             } else {              } else {
                 my ($setting,$type) = ($item =~ /^(uploadquota|coursequota|mysqltables)_(\w+)$/);                  my ($setting,$type) = ($item =~ /^(uploadquota|mysqltables)_(\w+)$/);
                 if (ref($domconfig{'coursedefaults'}{$setting}) eq 'HASH') {                  if (ref($domconfig{'coursedefaults'}{$setting}) eq 'HASH') {
                     $currdef = $domconfig{'coursedefaults'}{$setting}{$type};                      $currdef = $domconfig{'coursedefaults'}{$setting}{$type};
                 }                  }
Line 19108  sub modify_coursedefaults { Line 14041  sub modify_coursedefaults {
                 $defaultshash{'coursedefaults'}{$setting}{$type} = $newdef;                  $defaultshash{'coursedefaults'}{$setting}{$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)_/) {                  } elsif ($item =~ /^(uploadquota|mysqltables)_/) {
                     my $setting = $1;                      my $setting = $1;
                     unless (($currdef eq '') && ($newdef == $staticdefaults{$setting})) {                      unless (($currdef eq '') && ($newdef == $staticdefaults{$setting})) {
                         $changes{$setting} = 1;                          $changes{$setting} = 1;
Line 19123  sub modify_coursedefaults { Line 14057  sub modify_coursedefaults {
         my $texengine;          my $texengine;
         if ($env{'form.texengine'} =~ /^(MathJax|mimetex|tth)$/) {          if ($env{'form.texengine'} =~ /^(MathJax|mimetex|tth)$/) {
             $texengine = $env{'form.texengine'};              $texengine = $env{'form.texengine'};
             my $currdef = $domconfig{'coursedefaults'}{'texengine'};              if ($defaultshash{'coursedefaults'}{'texengine'} eq '') {
             if ($currdef eq '') {                  unless ($texengine eq 'MathJax') {
                 unless ($texengine eq $Apache::lonnet::deftex) {  
                     $changes{'texengine'} = 1;                      $changes{'texengine'} = 1;
                 }                  }
             } elsif ($currdef ne $texengine) {              } elsif ($defaultshash{'coursedefaults'}{'texengine'} ne $texengine) {
                 $changes{'texengine'} = 1;                  $changes{'texengine'} = 1;
             }              }
         }          }
Line 19247  sub modify_coursedefaults { Line 14180  sub modify_coursedefaults {
                 $changes{'postsubmit'} = 1;                  $changes{'postsubmit'} = 1;
             }              }
         }          }
         my (%newdomexttool,%newexttool,%olddomexttool,%oldexttool,%posscrseditors);  
         map { $newdomexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.domexttool');  
         map { $newexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.exttool');  
         map { $posscrseditors{$_} = 1; } &Apache::loncommon::get_env_multiple('form.crseditors');  
         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;  
                }  
             }  
         }  
         my @newcrseditors = ();  
         foreach my $editor (@editors) {  
             if ($posscrseditors{$editor}) {  
                 push(@newcrseditors,$editor);  
             }  
         }  
         if (ref($domconfig{'coursedefaults'}{'crseditors'}) eq 'ARRAY') {  
             my @diffs =  
                 &Apache::loncommon::compare_arrays($domconfig{'coursedefaults'}{'crseditors'},  
                                                    \@newcrseditors);  
             if (@diffs) {  
                 $changes{'crseditors'} = 1;  
             }  
         } else {  
             my @diffs =  
                 &Apache::loncommon::compare_arrays($staticdefaults{'crseditors'},  
                                                    \@newcrseditors);  
             unless (@diffs == 0) {  
                 $changes{'crseditors'} = 1;  
             }  
         }  
         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;  
         $defaultshash{'coursedefaults'}{'crseditors'} = \@newcrseditors;  
     }      }
     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'}) ||                  ($changes{'canclone'}) || ($changes{'mysqltables'}) || ($changes{'texengine'})) {
                 ($changes{'inline_chem'}) || ($changes{'ltiauth'}) || ($changes{'domexttool'}) ||                  foreach my $item ('canuse_pdfforms','uselcmath','usejsme','texengine') {
                 ($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};
                     }                      }
Line 19353  sub modify_coursedefaults { Line 14220  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 ($changes{'canclone'}) {
                     if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') {                      if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') {
                         if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {                          if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {
Line 19372  sub modify_coursedefaults { Line 14232  sub modify_coursedefaults {
                         $domdefaults{'canclone'}=$defaultshash{'coursedefaults'}{'canclone'};                          $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};  
                         }  
                     }  
                 }  
                 if ($changes{'crseditors'}) {  
                     if (ref($defaultshash{'coursedefaults'}{'crseditors'}) eq 'ARRAY') {  
                         $domdefaults{'crseditors'}=join(',',@{$defaultshash{'coursedefaults'}{'crseditors'}});  
                     }  
                 }  
                 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 19399  sub modify_coursedefaults { Line 14240  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 19411  sub modify_coursedefaults { Line 14258  sub modify_coursedefaults {
                     } 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') {                  } elsif ($item eq 'texengine') {
                     if ($defaultshash{'coursedefaults'}{'texengine'} ne '') {                      if ($defaultshash{'coursedefaults'}{'texengine'} ne '') {
                         $resulttext .= '<li>'.&mt('Default method to display mathematics set to: "[_1]"',                          $resulttext .= '<li>'.&mt('Default method to display mathematics set to: "[_1]"',
Line 19430  sub modify_coursedefaults { Line 14271  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('Placement tests: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'placement'}.'</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') {                  } elsif ($item eq 'mysqltables') {
                     if (ref($defaultshash{'coursedefaults'}{'mysqltables'}) eq 'HASH') {                      if (ref($defaultshash{'coursedefaults'}{'mysqltables'}) eq 'HASH') {
                         $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver').'<ul>'.                          $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('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('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('Textbook courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'textbook'}.'</b>').'</li>'.
                                          '<li>'.&mt('Placement tests: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'placement'}.'</b>').'</li>'.
                                        '<li>'.&mt('Communities: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'community'}.'</b>').'</li>'.                                         '<li>'.&mt('Communities: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'community'}.'</b>').'</li>'.
                                        '</ul>'.                                         '</ul>'.
                                        '</li>';                                         '</li>';
Line 19489  sub modify_coursedefaults { Line 14320  sub modify_coursedefaults {
                                     $resulttext .= &mt('Unofficial courses');                                      $resulttext .= &mt('Unofficial courses');
                                 } elsif ($type eq 'textbook') {                                  } elsif ($type eq 'textbook') {
                                     $resulttext .= &mt('Textbook courses');                                      $resulttext .= &mt('Textbook courses');
                                   } elsif ($type eq 'placement') {
                                       $resulttext .= &mt('Placement tests');
                                 }                                  }
                                 $resulttext .= ' -- '.$display.'</li>';                                  $resulttext .= ' -- '.$display.'</li>';
                             }                              }
Line 19524  sub modify_coursedefaults { Line 14357  sub modify_coursedefaults {
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('By default, only course owner and coordinators may clone a course.').'</li>';                          $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>';  
                     }  
                 } elsif ($item eq 'crseditors') {  
                     if (ref($defaultshash{'coursedefaults'}{$item}) eq 'ARRAY') {  
                         my $shown;  
                         if (@{$defaultshash{'coursedefaults'}{$item}}) {  
                             $shown = join(', ', map { $editornames{$_} } @{$defaultshash{'coursedefaults'}{$item}});  
                         } else {  
                             $shown = &mt('None');  
                         }  
                         $resulttext .= '<li>'.&mt('Available editors for course/community resources: [_1]',$shown).'</li>';  
                     }  
                 }                  }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
Line 19584  sub modify_coursedefaults { Line 14373  sub modify_coursedefaults {
 sub modify_selfenrollment {  sub modify_selfenrollment {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,$errors,%changes,%selfenrollhash,%ordered);      my ($resulttext,$errors,%changes,%selfenrollhash,%ordered);
     my @types = ('official','unofficial','community','textbook');      my @types = ('official','unofficial','community','textbook','placement');
     my %titles = &tool_titles();      my %titles = &tool_titles();
     my %descs = &Apache::lonuserutils::selfenroll_default_descs();      my %descs = &Apache::lonuserutils::selfenroll_default_descs();
     ($ordered{'admin'},my $titlesref) = &Apache::lonuserutils::get_selfenroll_titles();      ($ordered{'admin'},my $titlesref) = &Apache::lonuserutils::get_selfenroll_titles();
Line 19820  sub modify_selfenrollment { Line 14609  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 20170  sub modify_usersessions { Line 14620  sub modify_usersessions {
                 );                  );
     my @prefixes = ('remote','hosted','spares');      my @prefixes = ('remote','hosted','spares');
     my @lcversions = &Apache::lonnet::all_loncaparevs();      my @lcversions = &Apache::lonnet::all_loncaparevs();
     my (%by_ip,%by_location,@intdoms);      my (%by_ip,%by_location,@intdoms,@instdoms);
     &build_location_hashes(\@intdoms,\%by_ip,\%by_location);      &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
     my @locations = sort(keys(%by_location));      my @locations = sort(keys(%by_location));
     my (%defaultshash,%changes);      my (%defaultshash,%changes);
     foreach my $prefix (@prefixes) {      foreach my $prefix (@prefixes) {
Line 20326  sub modify_usersessions { Line 14776  sub modify_usersessions {
         }          }
     }      }
     $defaultshash{'usersessions'}{'offloadnow'} = {};      $defaultshash{'usersessions'}{'offloadnow'} = {};
     $defaultshash{'usersessions'}{'offloadoth'} = {};  
     my @offloadnow = &Apache::loncommon::get_env_multiple('form.offloadnow');      my @offloadnow = &Apache::loncommon::get_env_multiple('form.offloadnow');
     my @okoffload;      my @okoffload;
     if (@offloadnow) {      if (@offloadnow) {
Line 20343  sub modify_usersessions { Line 14792  sub modify_usersessions {
             }              }
         }          }
     }      }
     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 20369  sub modify_usersessions { Line 14802  sub modify_usersessions {
         } else {          } else {
             $savespares = 1;              $savespares = 1;
         }          }
         foreach my $offload ('offloadnow','offloadoth') {          if (ref($domconfig{'usersessions'}{'offloadnow'}) eq 'HASH') {
             if (ref($domconfig{'usersessions'}{$offload}) eq 'HASH') {              foreach my $lonhost (keys(%{$domconfig{'usersessions'}{'offloadnow'}})) {
                 foreach my $lonhost (keys(%{$domconfig{'usersessions'}{$offload}})) {                  unless ($defaultshash{'usersessions'}{'offloadnow'}{$lonhost}) {
                     unless ($defaultshash{'usersessions'}{$offload}{$lonhost}) {                      $changes{'offloadnow'} = 1;
                         $changes{$offload} = 1;                      last;
                         last;  
                     }  
                 }                  }
                 unless ($changes{$offload}) {              }
                     foreach my $lonhost (keys(%{$defaultshash{'usersessions'}{$offload}})) {              unless ($changes{'offloadnow'}) {
                         unless ($domconfig{'usersessions'}{$offload}{$lonhost}) {                  foreach my $lonhost (keys(%{$defaultshash{'usersessions'}{'offloadnow'}})) {
                             $changes{$offload} = 1;                      unless ($domconfig{'usersessions'}{'offloadnow'}{$lonhost}) {
                             last;                          $changes{'offloadnow'} = 1;
                         }                          last;
                     }                      }
                 }                  }
             } else {  
                 if (($offload eq 'offloadnow') && (@okoffload)) {  
                      $changes{'offloadnow'} = 1;  
                 }  
                 if (($offload eq 'offloadoth') && (@okoffloadoth)) {  
                     $changes{'offloadoth'} = 1;  
                 }  
             }              }
         }          } elsif (@okoffload) {
     } else {  
         if (@okoffload) {  
             $changes{'offloadnow'} = 1;              $changes{'offloadnow'} = 1;
         }          }
         if (@okoffloadoth) {      } elsif (@okoffload) {
             $changes{'offloadoth'} = 1;          $changes{'offloadnow'} = 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)) {
Line 20417  sub modify_usersessions { Line 14838  sub modify_usersessions {
                 if (ref($defaultshash{'usersessions'}{'offloadnow'}) eq 'HASH') {                  if (ref($defaultshash{'usersessions'}{'offloadnow'}) eq 'HASH') {
                     $domdefaults{'offloadnow'} = $defaultshash{'usersessions'}{'offloadnow'};                      $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);
Line 20480  sub modify_usersessions { Line 14898  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 20493  sub modify_usersessions { Line 14911  sub modify_usersessions {
                 if ($changes{'offloadnow'}) {                  if ($changes{'offloadnow'}) {
                     if (ref($defaultshash{'usersessions'}{'offloadnow'}) eq 'HASH') {                      if (ref($defaultshash{'usersessions'}{'offloadnow'}) eq 'HASH') {
                         if (keys(%{$defaultshash{'usersessions'}{'offloadnow'}}) > 0) {                          if (keys(%{$defaultshash{'usersessions'}{'offloadnow'}}) > 0) {
                             $resulttext .= '<li>'.&mt('Switch any active user on next access, for server(s):').'<ul>';                              $resulttext .= '<li>'.&mt('Switch active users on next access, for server(s):').'<ul>';
                             foreach my $lonhost (sort(keys(%{$defaultshash{'usersessions'}{'offloadnow'}}))) {                              foreach my $lonhost (sort(keys(%{$defaultshash{'usersessions'}{'offloadnow'}}))) {
                                 $resulttext .= '<li>'.$lonhost.'</li>';                                  $resulttext .= '<li>'.$lonhost.'</li>';
                             }                              }
                             $resulttext .= '</ul>';                              $resulttext .= '</ul>';
                         } else {                          } else {
                             $resulttext .= '<li>'.&mt('No servers now set to switch any active user on next access.');                              $resulttext .= '<li>'.&mt('No servers now set to switch active users on next access.');
                         }                          }
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('No servers now set to switch any active user on next access.').'</li>';                          $resulttext .= '<li>'.&mt('No servers now set to switch active users on next access.').'</li>';
                     }                      }
                 }                  }
                 if ($changes{'offloadoth'}) {                  $resulttext .= '</ul>';
                     if (ref($defaultshash{'usersessions'}{'offloadoth'}) eq 'HASH') {              } else {
                         if (keys(%{$defaultshash{'usersessions'}{'offloadoth'}}) > 0) {                  $resulttext = $nochgmsg;
                             $resulttext .= '<li>'.&mt('Switch other institutions on next access, for server(s):').'<ul>';              }
                             foreach my $lonhost (sort(keys(%{$defaultshash{'usersessions'}{'offloadoth'}}))) {          } else {
                                 $resulttext .= '<li>'.$lonhost.'</li>';              $resulttext = '<span class="LC_error">'.
                             &mt('An error occurred: [_1]',$putresult).'</span>';
           }
       } else {
           $resulttext = $nochgmsg;
       }
       return $resulttext;
   }
   
   sub modify_ssl {
       my ($dom,$lastactref,%domconfig) = @_;
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
       my @locations = sort(keys(%by_location));
       my %servers = &Apache::lonnet::internet_dom_servers($dom);
       my (%defaultshash,%changes);
       my $action = 'ssl';
       my @prefixes = ('connto','connfrom','replication');
       foreach my $prefix (@prefixes) {
           $defaultshash{$action}{$prefix} = {};
       }
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my $resulttext;
       my %iphost = &Apache::lonnet::get_iphost();
       my @reptypes = ('certreq','nocertreq');
       my @connecttypes = ('dom','intdom','other');
       my %types = (
                     connto      => \@connecttypes,
                     connfrom    => \@connecttypes,
                     replication => \@reptypes,
                   );
       foreach my $prefix (sort(keys(%types))) {
           foreach my $type (@{$types{$prefix}}) {
               if (($prefix eq 'connto') || ($prefix eq 'connfrom')) {
                   my $value = 'yes';
                   if ($env{'form.'.$prefix.'_'.$type} =~ /^(no|req)$/) {
                       $value = $env{'form.'.$prefix.'_'.$type};
                   }
                   if (ref($domconfig{$action}{$prefix}) eq 'HASH') {
                       if ($domconfig{$action}{$prefix}{$type} ne '') {
                           if ($value ne $domconfig{$action}{$prefix}{$type}) {
                               $changes{$prefix}{$type} = 1;
                           }
                           $defaultshash{$action}{$prefix}{$type} = $value;
                       } else {
                           $defaultshash{$action}{$prefix}{$type} = $value;
                           $changes{$prefix}{$type} = 1;
                       }
                   } else {
                       $defaultshash{$action}{$prefix}{$type} = $value;
                       $changes{$prefix}{$type} = 1;
                   }
                   if (($type eq 'dom') && (keys(%servers) == 1)) {
                       delete($changes{$prefix}{$type});
                   } elsif (($type eq 'intdom') && (@instdoms == 1)) {
                       delete($changes{$prefix}{$type});
                   } elsif (($type eq 'other') && (keys(%by_location) == 0)) { 
                       delete($changes{$prefix}{$type});
                   }
               } elsif ($prefix eq 'replication') {
                   if (@locations > 0) {
                       my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'};
                       my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type);
                       my @okvals;
                       foreach my $val (@vals) {
                           if ($val =~ /:/) {
                               my @items = split(/:/,$val);
                               foreach my $item (@items) {
                                   if (ref($by_location{$item}) eq 'ARRAY') {
                                       push(@okvals,$item);
                                   }
                               }
                           } else {
                               if (ref($by_location{$val}) eq 'ARRAY') {
                                   push(@okvals,$val);
                               }
                           }
                       }
                       @okvals = sort(@okvals);
                       if (ref($domconfig{$action}) eq 'HASH') {
                           if (ref($domconfig{$action}{$prefix}) eq 'HASH') {
                               if (ref($domconfig{$action}{$prefix}{$type}) eq 'ARRAY') {
                                   if ($inuse == 0) {
                                       $changes{$prefix}{$type} = 1;
                                   } else {
                                       $defaultshash{$action}{$prefix}{$type} = \@okvals;
                                       my @changed = &Apache::loncommon::compare_arrays($domconfig{$action}{$prefix}{$type},$defaultshash{$action}{$prefix}{$type});
                                       if (@changed > 0) {
                                           $changes{$prefix}{$type} = 1;
                                       }
                                   }
                               } else {
                                   if ($inuse == 1) {
                                       $defaultshash{$action}{$prefix}{$type} = \@okvals;
                                       $changes{$prefix}{$type} = 1;
                                   }
                             }                              }
                             $resulttext .= '</ul>';  
                         } else {                          } else {
                             $resulttext .= '<li>'.&mt('No servers now set to switch other institutions on next access.');                              if ($inuse == 1) {
                                   $defaultshash{$action}{$prefix}{$type} = \@okvals;
                                   $changes{$prefix}{$type} = 1;
                               }
                         }                          }
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('No servers now set to switch other institutions on next access.').'</li>';                          if ($inuse == 1) {
                               $defaultshash{$action}{$prefix}{$type} = \@okvals;
                               $changes{$prefix}{$type} = 1;
                           }
                       }
                   }
               }
           }
       }
       my $nochgmsg = &mt('No changes made to LON-CAPA SSL settings');
       if (keys(%changes) > 0) {
           my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                                    $dom);
           if ($putresult eq 'ok') {
               if (ref($defaultshash{$action}) eq 'HASH') {
                   if (ref($defaultshash{$action}{'replication'}) eq 'HASH') {
                       $domdefaults{'replication'} = $defaultshash{$action}{'replication'};
                   }
                   if (ref($defaultshash{$action}{'connto'}) eq 'HASH') {
                       $domdefaults{'connto'} = $domconfig{$action}{'connto'};
                   }
                   if (ref($defaultshash{$action}{'connfrom'}) eq 'HASH') {
                       $domdefaults{'connfrom'} = $domconfig{$action}{'connfrom'};
                   }
               }
               my $cachetime = 24*60*60;
               &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'domdefaults'} = 1;
               }
               if (keys(%changes) > 0) {
                   my %titles = &ssl_titles();
                   $resulttext = &mt('Changes made:').'<ul>';
                   foreach my $prefix (@prefixes) {
                       if (ref($changes{$prefix}) eq 'HASH') {
                           $resulttext .= '<li>'.$titles{$prefix}.'<ul>';
                           foreach my $type (@{$types{$prefix}}) {
                               if (defined($changes{$prefix}{$type})) {
                                   my $newvalue;
                                   if (ref($defaultshash{$action}) eq 'HASH') {
                                       if (ref($defaultshash{$action}{$prefix})) {
                                           if (($prefix eq 'connto') || ($prefix eq 'connfrom')) {
                                               $newvalue = $titles{$defaultshash{$action}{$prefix}{$type}};
                                           } elsif (ref($defaultshash{$action}{$prefix}{$type}) eq 'ARRAY') {
                                               if (@{$defaultshash{$action}{$prefix}{$type}} > 0) {
                                                   $newvalue = join(', ',@{$defaultshash{$action}{$prefix}{$type}});
                                               }
                                           }
                                       }
                                       if ($newvalue eq '') {
                                           $resulttext .= '<li>'.&mt('[_1] set to: none',$titles{$type}).'</li>';
                                       } else {
                                           $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$titles{$type},$newvalue).'</li>';
                                       }
                                   }
                               }
                           }
                           $resulttext .= '</ul>';
                       }
                   }
               } else {
                   $resulttext = $nochgmsg;
               }
           } else {
               $resulttext = '<span class="LC_error">'.
                             &mt('An error occurred: [_1]',$putresult).'</span>';
           }
       } else {
           $resulttext = $nochgmsg;
       }
       return $resulttext;
   }
   
   sub modify_trust {
       my ($dom,$lastactref,%domconfig) = @_;
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
       my @locations = sort(keys(%by_location));
       my @prefixes = qw(content shared enroll othcoau coaurem domroles catalog reqcrs msg);
       my @types = ('exc','inc');
       my (%defaultshash,%changes);
       foreach my $prefix (@prefixes) {
           $defaultshash{'trust'}{$prefix} = {};
       }
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my $resulttext;
       foreach my $prefix (@prefixes) {
           foreach my $type (@types) {
               my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'};
               my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type);
               my @okvals;
               foreach my $val (@vals) {
                   if ($val =~ /:/) {
                       my @items = split(/:/,$val);
                       foreach my $item (@items) {
                           if (ref($by_location{$item}) eq 'ARRAY') {
                               push(@okvals,$item);
                           }
                       }
                   } else {
                       if (ref($by_location{$val}) eq 'ARRAY') {
                           push(@okvals,$val);
                       }
                   }
               }
               @okvals = sort(@okvals);
               if (ref($domconfig{'trust'}) eq 'HASH') {
                   if (ref($domconfig{'trust'}{$prefix}) eq 'HASH') {
                       if (ref($domconfig{'trust'}{$prefix}{$type}) eq 'ARRAY') {
                           if ($inuse == 0) {
                               $changes{$prefix}{$type} = 1;
                           } else {
                               $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                               my @changed = &Apache::loncommon::compare_arrays($domconfig{'trust'}{$prefix}{$type},$defaultshash{'trust'}{$prefix}{$type});
                               if (@changed > 0) {
                                   $changes{$prefix}{$type} = 1;
                               }
                           }
                       } else {
                           if ($inuse == 1) {
                               $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                               $changes{$prefix}{$type} = 1;
                           }
                       }
                   } else {
                       if ($inuse == 1) {
                           $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                           $changes{$prefix}{$type} = 1;
                       }
                   }
               } else {
                   if ($inuse == 1) {
                       $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                       $changes{$prefix}{$type} = 1;
                   }
               }
           }
       }
       my $nochgmsg = &mt('No changes made to trust settings.');
       if (keys(%changes) > 0) {
           my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                                    $dom);
           if ($putresult eq 'ok') {
               if (ref($defaultshash{'trust'}) eq 'HASH') {
                   foreach my $prefix (@prefixes) {
                       if (ref($defaultshash{'trust'}{$prefix}) eq 'HASH') {
                           $domdefaults{'trust'.$prefix} = $defaultshash{'trust'}{$prefix};
                       }
                   }
               }
               my $cachetime = 24*60*60;
               &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'domdefaults'} = 1;
               }
               if (keys(%changes) > 0) {
                   my %lt = &trust_titles();
                   $resulttext = &mt('Changes made:').'<ul>';
                   foreach my $prefix (@prefixes) {
                       if (ref($changes{$prefix}) eq 'HASH') {
                           $resulttext .= '<li>'.$lt{$prefix}.'<ul>';
                           foreach my $type (@types) {
                               if (defined($changes{$prefix}{$type})) {
                                   my $newvalue;
                                   if (ref($defaultshash{'trust'}) eq 'HASH') {
                                       if (ref($defaultshash{'trust'}{$prefix})) {
                                           if (ref($defaultshash{'trust'}{$prefix}{$type}) eq 'ARRAY') {
                                               if (@{$defaultshash{'trust'}{$prefix}{$type}} > 0) {
                                                   $newvalue = join(', ',@{$defaultshash{'trust'}{$prefix}{$type}});
                                               }
                                           }
                                       }
                                   }
                                   if ($newvalue eq '') {
                                       $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';
                                   } else {
                                       $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>';
                                   }
                               }
                           }
                           $resulttext .= '</ul>';
                     }                      }
                 }                  }
                 $resulttext .= '</ul>';                  $resulttext .= '</ul>';
Line 20545  sub modify_loadbalancing { Line 15240  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 20602  sub modify_loadbalancing { Line 15297  sub modify_loadbalancing {
             }              }
             $defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype} = \@offloadto;              $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') {
             foreach my $sparetype (@sparestypes) {              foreach my $sparetype (@sparestypes) {
                 if (ref($currtargets{$balancer}{$sparetype}) eq 'ARRAY') {                  if (ref($currtargets{$balancer}{$sparetype}) eq 'ARRAY') {
Line 20767  sub modify_loadbalancing { Line 15450  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 21005  sub lonbalance_targets_js { Line 15679  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 21363  function updateNewSpares(formname,lonhos Line 16037  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 21497  function toggleDisplay(domForm,caller) { Line 16171  function toggleDisplay(domForm,caller) {
         var dispval = 'block';          var dispval = 'block';
         var selfcreateRegExp = /^cancreate_emailverified/;          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;
Line 21552  sub devalidate_remote_domconfs { Line 16226  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','ltitools','usersessions','directorysrch');
                       'directorysrch','passwdconf','cats','proxyalias','proxysaml',  
                       '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)) {      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.27  
changed lines
  Added in v.1.318


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