Diff for /loncom/interface/domainprefs.pm between versions 1.160.6.118.2.9 and 1.323

version 1.160.6.118.2.9, 2022/08/30 20:03:05 version 1.323, 2017/12/30 14:03:53
Line 27 Line 27
 #  #
 #  #
 ###############################################################  ###############################################################
 ##############################################################  ###############################################################
   
 =pod  =pod
   
Line 104  $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, and textbook).  In each case the radio buttons   (official, unofficial, community, textbook, and placement).  
 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 170  use Apache::loncoursequeueadmin(); Line 170  use Apache::loncoursequeueadmin();
 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 Net::CIDR;  use Time::HiRes qw( sleep );
   
 my $registered_cleanup;  my $registered_cleanup;
 my $modified_urls;  my $modified_urls;
Line 218  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','ltisec','wafproxy','ipaccess'],$dom);                  'ltitools','ssl','trust','lti'],$dom);
     my %encconfig =      my %encconfig =
         &Apache::lonnet::get_dom('encconfig',['ltitools','linkprot'],$dom,undef,1);          &Apache::lonnet::get_dom('encconfig',['ltitools','lti'],$dom);
     if (ref($domconfig{'ltitools'}) eq 'HASH') {      if (ref($domconfig{'ltitools'}) eq 'HASH') {
         if (ref($encconfig{'ltitools'}) eq 'HASH') {          if (ref($encconfig{'ltitools'}) eq 'HASH') {
             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') {                      foreach my $item ('key','secret') {
                         $domconfig{'ltitools'}{$id}{$item} = $encconfig{'ltitools'}{$id}{$item};                          $domconfig{'ltitools'}{$id}{$item} = $encconfig{'ltitools'}{$id}{$item};
                     }                      }
Line 232  sub handler { Line 234  sub handler {
             }              }
         }          }
     }      }
     if (ref($domconfig{'ltisec'}) eq 'HASH') {      if (ref($domconfig{'lti'}) eq 'HASH') {
         if (ref($domconfig{'ltisec'}{'linkprot'}) eq 'HASH') {          if (ref($encconfig{'lti'}) eq 'HASH') {
             if (ref($encconfig{'linkprot'}) eq 'HASH') {              foreach my $id (keys(%{$domconfig{'lti'}})) {
                 foreach my $id (keys(%{$domconfig{'ltisec'}{'linkprot'}})) {                  if ((ref($domconfig{'lti'}{$id}) eq 'HASH') &&
                     unless ($id =~ /^\d+$/) {                      (ref($encconfig{'lti'}{$id}) eq 'HASH')) {
                         delete($domconfig{'ltisec'}{'linkprot'}{$id});                      foreach my $item ('key','secret') {
                     }                          $domconfig{'lti'}{$id}{$item} = $encconfig{'lti'}{$id}{$item};
                     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',
                        'ltitools','selfenrollment','usersessions','lti');                         'ltitools','selfenrollment','usersessions','ssl','trust','lti');
     my %existing;      my %existing;
     if (ref($domconfig{'loadbalancing'}) eq 'HASH') {      if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
         %existing = %{$domconfig{'loadbalancing'}};          %existing = %{$domconfig{'loadbalancing'}};
Line 285  sub handler { Line 282  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 297  sub handler { Line 291  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 web pages, webDAV/quotas, portfolios',                      { text => 'Blogs, personal web pages, webDAV/quotas, portfolios',
                       help => 'Domain_Configuration_Quotas',                        help => 'Domain_Configuration_Quotas',
Line 383  sub handler { Line 352  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 425  sub handler { Line 392  sub handler {
                     modify => \&modify_usermodification,                      modify => \&modify_usermodification,
                   },                    },
         'scantron' =>          'scantron' =>
                   { text => 'Bubblesheet format',                    { text => 'Bubblesheet format file',
                     help => 'Domain_Configuration_Scantron_Format',                      help => 'Domain_Configuration_Scantron_Format',
                     header => [ {col1 => 'Bubblesheet format file',                      header => [ {col1 => 'Item',
                                  col2 => ''},                                   col2 => '',
                                 {col1 => 'Bubblesheet data upload formats',                                }],
                                  col2 => 'Settings'}],  
                     print => \&print_scantron,                      print => \&print_scantron,
                     modify => \&modify_scantron,                      modify => \&modify_scantron,
                   },                    },
Line 515  sub handler { Line 481  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 538  sub handler { Line 512  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 => 'Setting',                    header => [{col1 => 'Setting',
Line 546  sub handler { Line 520  sub handler {
                   print => \&print_ltitools,                    print => \&print_ltitools,
                   modify => \&modify_ltitools,                    modify => \&modify_ltitools,
                  },                   },
           'ssl' =>
                    {text  => 'LON-CAPA Network (SSL)',
                     help  => 'Domain_Configuration_Network_SSL',
                     header => [{col1 => 'Server',
                                 col2 => 'Certificate Status'},
                                {col1 => 'Connections to other servers',
                                 col2 => 'Rules'},
                                {col1 => 'Connections from other servers',
                                 col2 => 'Rules'},
                                {col1 => "Replicating domain's published content",
                                 col2 => 'Rules'}],
                     print => \&print_ssl,
                     modify => \&modify_ssl,
                    },
           '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,
                    },
           'lti' =>            'lti' =>
                  {text => 'LTI Link Protection and LTI Consumers',                   {text => 'LTI Provider',
                   help => 'Domain_Configuration_LTI_Provider',                    help => 'Domain_Configuration_LTI_Provider',
                   header => [{col1 => 'Encryption of shared secrets',                    header => [{col1 => 'Setting',
                               col2 => 'Settings'},                                col2 => 'Value',}],
                              {col1 => 'Rules for shared secrets',  
                               col2 => 'Settings'},  
                              {col1 => 'Link Protectors',  
                               col2 => 'Settings'},],  
                   print => \&print_lti,                    print => \&print_lti,
                   modify => \&modify_lti,                    modify => \&modify_lti,
                  },                   },
          'ipaccess' =>  
                        {text => 'IP-based access control',  
                         help => 'Domain_Configuration_IP_Access',  
                         header => [{col1 => 'Setting',  
                                     col2 => 'Value'},],  
                         print  => \&print_ipaccess,  
                         modify => \&modify_ipaccess,  
                        },  
     );      );
     if (keys(%servers) > 1) {      if (keys(%servers) > 1) {
         $prefs{'login'}  = { text   => 'Log-in page options',          $prefs{'login'}  = { text   => 'Log-in page options',
Line 573  sub handler { Line 573  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 621  $javascript_validations Line 618  $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 630  END Line 625  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 753  sub process_changes { Line 745  sub process_changes {
         $output = &modify_usersessions($dom,$lastactref,%domconfig);          $output = &modify_usersessions($dom,$lastactref,%domconfig);
     } elsif ($action eq 'loadbalancing') {      } elsif ($action eq 'loadbalancing') {
         $output = &modify_loadbalancing($dom,%domconfig);          $output = &modify_loadbalancing($dom,%domconfig);
     } elsif ($action eq 'lti') {  
         $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);  
     } elsif ($action eq 'passwords') {  
         $output = &modify_passwords($r,$dom,$confname,$lastactref,%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 'wafproxy') {      } elsif ($action eq 'ssl') {
         $output = &modify_wafproxy($dom,$action,$lastactref,%domconfig);          $output = &modify_ssl($dom,$lastactref,%domconfig);
     } elsif ($action eq 'ipaccess') {      } elsif ($action eq 'trust') {
         $output = &modify_ipaccess($dom,$lastactref,%domconfig);          $output = &modify_trust($dom,$lastactref,%domconfig);
       } elsif ($action eq 'lti') {
           $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);
     }      }
     return $output;      return $output;
 }  }
Line 775  sub print_config_box { Line 765  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 791  sub print_config_box { Line 779  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 .= &ltitools_javascript($settings);  
     } elsif ($action eq 'lti') {  
         $output .= &passwords_javascript('secrets')."\n".  
                    &lti_javascript($dom,$settings);  
     } elsif ($action eq 'wafproxy') {  
         $output .= &wafproxy_javascript($dom);  
     } elsif ($action eq 'autoupdate') {  
         $output .= &autoupdate_javascript();  
     } elsif ($action eq 'autoenroll') {  
         $output .= &autoenroll_javascript();  
     } elsif ($action eq 'login') {  
         $output .= &saml_javascript();  
     } elsif ($action eq 'ipaccess') {  
         $output .= &ipaccess_javascript($settings);  
     }      }
     $output .=      $output .=
          '<table class="LC_nested_outer">           '<table class="LC_nested_outer">
Line 824  sub print_config_box { Line 797  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 'lti')) {              ($action eq 'directorysrch') || ($action eq 'trust') || ($action eq 'helpsettings') ||
               ($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 882  sub print_config_box { Line 848  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')) {  
             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);
             } else {              } else {
                 $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);                  $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);
             }              }
             $output .= '              if ($action eq 'trust') {
                   $output .= '
               </table>
             </td>
            </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 904  sub print_config_box { Line 898  sub print_config_box {
               <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
               <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'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);
                 }                  }
                 $output .= '              }
              </tr>              $rowtotal ++;
           } 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'}->[3]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
               <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'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 'usermodification') || ($action eq 'coursedefaults') ||                <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 968  sub print_config_box { Line 956  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 980  sub print_config_box { Line 968  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 1033  sub print_config_box { Line 1001  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 1049  sub print_config_box { Line 1017  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 1079  sub print_config_box { Line 1047  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 1111  sub print_config_box { Line 1079  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 1119  sub print_config_box { Line 1087  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 'ltitools') || ($action eq 'ipaccess')) {                   ($action eq 'ltitools') || ($action eq 'lti')) {
             $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 1134  sub print_config_box { Line 1104  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 1227  sub print_login { Line 1193  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 1269  sub print_login { Line 1234  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 1342  sub print_login { Line 1300  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 1427  sub print_login { Line 1393  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 1442  sub print_login { Line 1408  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 1462  sub print_login { Line 1436  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->{'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 1596  sub login_choices { Line 1475  sub login_choices {
             headtag       => "Custom markup",              headtag       => "Custom markup",
             action        => "Action",              action        => "Action",
             current       => "Current",              current       => "Current",
             samllanding   => "Dual login?",  
             samloptions   => "Options",  
             alttext       => "Alt text",  
         );          );
     return %choices;      return %choices;
 }  }
   
 sub login_file_options {  
       return &Apache::lonlocal::texthash(  
                                            del     => 'Delete?',  
                                            rep     => 'Replace:',  
                                            upl     => 'Upload:',  
                                            curr    => 'View contents',  
                                            default => 'Default',  
                                            custom  => 'Custom',  
                                            none    => 'None',  
       );  
 }  
   
 sub print_ipaccess {  
     my ($dom,$settings,$rowtotal) = @_;  
     my $css_class;  
     my $itemcount = 0;  
     my $datatable;  
     my %ordered;  
     if (ref($settings) eq 'HASH') {  
         foreach my $item (keys(%{$settings})) {  
             if (ref($settings->{$item}) eq 'HASH') {  
                 my $num = $settings->{$item}{'order'};  
                 if ($num eq '') {  
                     $num = scalar(keys(%{$settings}));  
                 }  
                 $ordered{$num} = $item;  
             }  
         }  
     }  
     my $maxnum = scalar(keys(%ordered));  
     if (keys(%ordered)) {  
         my @items = sort { $a <=> $b } keys(%ordered);  
         for (my $i=0; $i<@items; $i++) {  
             $css_class = $itemcount%2?' class="LC_odd_row"':'';  
             my $item = $ordered{$items[$i]};  
             my ($name,$ipranges,%commblocks,%courses);  
             if (ref($settings->{$item}) eq 'HASH') {  
                 $name = $settings->{$item}->{'name'};  
                 $ipranges = $settings->{$item}->{'ip'};  
                 if (ref($settings->{$item}->{'commblocks'}) eq 'HASH') {  
                     %commblocks = %{$settings->{$item}->{'commblocks'}};  
                 }  
                 if (ref($settings->{$item}->{'courses'}) eq 'HASH') {  
                     %courses = %{$settings->{$item}->{'courses'}};  
                 }  
             }  
             my $chgstr = ' onchange="javascript:reorderIPaccess(this.form,'."'ipaccess_pos_".$item."'".');"';  
             $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'  
                          .'<select name="ipaccess_pos_'.$item.'"'.$chgstr.'>';  
             for (my $k=0; $k<=$maxnum; $k++) {  
                 my $vpos = $k+1;  
                 my $selstr;  
                 if ($k == $i) {  
                     $selstr = ' selected="selected" ';  
                 }  
                 $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';  
             }  
             $datatable .= '</select>'.('&nbsp;'x2).  
                 '<label><input type="checkbox" name="ipaccess_del" value="'.$item.'" />'.  
                 &mt('Delete?').'</label></span></td>'.  
                 '<td colspan="2"><input type="hidden" name="ipaccess_id_'.$i.'" value="'.$item.'" />'.  
                 &ipaccess_options($i,$itemcount,$dom,$name,$ipranges,\%commblocks,\%courses).  
                 '</td></tr>';  
             $itemcount ++;  
         }  
     }  
     $css_class = $itemcount%2?' class="LC_odd_row"':'';  
     my $chgstr = ' onchange="javascript:reorderIPaccess(this.form,'."'ipaccess_pos_add'".');"';  
     $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".  
                   '<input type="hidden" name="ipaccess_maxnum" value="'.$maxnum.'" />'."\n".  
                   '<select name="ipaccess_pos_add"'.$chgstr.'>';  
     for (my $k=0; $k<$maxnum+1; $k++) {  
         my $vpos = $k+1;  
         my $selstr;  
         if ($k == $maxnum) {  
             $selstr = ' selected="selected" ';  
         }  
         $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';  
     }  
     $datatable .= '</select>&nbsp;'."\n".  
                   '<input type="checkbox" name="ipaccess_add" value="1" />'.&mt('Add').'</span></td>'."\n".  
                   '<td colspan="2">'.  
                   &ipaccess_options('add',$itemcount,$dom).  
                   '</td>'."\n".  
                   '</tr>'."\n";  
     $$rowtotal ++;  
     return $datatable;  
 }  
   
 sub ipaccess_options {  
     my ($num,$itemcount,$dom,$name,$ipranges,$blocksref,$coursesref) = @_;  
     my (%currblocks,%currcourses,$output);  
     if (ref($blocksref) eq 'HASH') {  
         %currblocks = %{$blocksref};  
     }  
     if (ref($coursesref) eq 'HASH') {  
         %currcourses = %{$coursesref};  
     }  
     $output = '<fieldset><legend>'.&mt('Location(s)').'</legend>'.  
               '<span class="LC_nobreak">'.&mt('Name').':&nbsp;'.  
               '<input type="text" name="ipaccess_name_'.$num.'" value="'.$name.'" />'.  
               '</span></fieldset>'.  
               '<fieldset><legend>'.&mt('IP Range(s)').'</legend>'.  
               &mt('Format for each IP range').': '.&mt('A.B.C.D/N or A.B.C.D-E.F.G.H').'<br />'.  
               &mt('Range(s) will be stored as IP netblock(s) in CIDR notation (comma separated)').'<br />'.  
               '<textarea name="ipaccess_range_'.$num.'" rows="3" cols="80">'.  
               $ipranges.'</textarea></fieldset>'.  
               '<fieldset><legend>'.&mt('Functionality Blocked?').'</legend>'.  
               &blocker_checkboxes($num,$blocksref).'</fieldset>'.  
               '<fieldset><legend>'.&mt('Courses/Communities allowed').'</legend>'.  
               '<table>';  
     foreach my $cid (sort(keys(%currcourses))) {  
         my %courseinfo = &Apache::lonnet::coursedescription($cid,{'one_time' => 1});  
         $output .= '<tr><td><span class="LC_nobreak">'.  
                    '<label><input type="checkbox" name="ipaccess_course_delete_'.$num.'" value="'.$cid.'" />'.  
                    &mt('Delete?').'&nbsp;<span class="LC_cusr_emph">'.$courseinfo{'description'}.'</span></label></span>'.  
                    ' <span class="LC_fontsize_medium">('.$cid.')</span></td></tr>';  
     }  
     $output .= '<tr><td><span class="LC_nobreak">'.&mt('Add').':&nbsp;'.  
                '<input type="text" name="ipaccess_cdesc_'.$num.'" value="" onfocus="this.blur();opencrsbrowser('."'display','ipaccess_cnum_$num','ipaccess_cdom_$num','ipaccess_cdesc_$num'".');" />'.  
                 &Apache::loncommon::selectcourse_link('display','ipaccess_cnum_'.$num,'ipaccess_cdom_'.$num,'ipaccess_cdesc_'.$num,$dom,undef,'Course/Community').  
                '<input type="hidden" name="ipaccess_cnum_'.$num.'" value="" />'.  
                '<input type="hidden" name="ipaccess_cdom_'.$num.'" value="" />'.  
                '</span></td></tr></table>'."\n".  
                '</fieldset>';  
     return $output;  
 }  
   
 sub blocker_checkboxes {  
     my ($num,$blocks) = @_;  
     my ($typeorder,$types) = &commblocktype_text();  
     my $numinrow = 6;  
     my $output = '<table>';  
     for (my $i=0; $i<@{$typeorder}; $i++) {  
         my $block = $typeorder->[$i];  
         my $blockstatus;  
         if (ref($blocks) eq 'HASH') {  
             if ($blocks->{$block} eq 'on') {  
                 $blockstatus = 'checked="checked"';  
             }  
         }  
         my $rem = $i%($numinrow);  
         if ($rem == 0) {  
             if ($i > 0) {  
                 $output .= '</tr>';  
             }  
             $output .= '<tr>';  
         }  
         if ($i == scalar(@{$typeorder})-1) {  
             my $colsleft = $numinrow-$rem;  
             if ($colsleft > 1) {  
                 $output .= '<td colspan="'.$colsleft.'">';  
             } else {  
                 $output .= '<td>';  
             }  
         } else {  
             $output .= '<td>';  
         }  
         my $item = 'ipaccess_block_'.$num;  
         if ($blockstatus) {  
             $blockstatus = ' '.$blockstatus;  
         }  
         $output .= '<span class="LC_nobreak"><label>'."\n".  
                    '<input type="checkbox" name="'.$item.'"'.  
                    $blockstatus.' value="'.$block.'"'.' />'.  
                    $types->{$block}.'</label></span>'."\n".  
                    '<br /></td>';  
     }  
     $output .= '</tr></table>';  
     return $output;  
 }  
   
 sub commblocktype_text {  
     my %types = &Apache::lonlocal::texthash(  
         'com' => 'Messaging',  
         'chat' => 'Chat Room',  
         'boards' => 'Discussion',  
         'port' => 'Portfolio',  
         'groups' => 'Groups',  
         'blogs' => 'Blogs',  
         'about' => 'User Information',  
         'printout' => 'Printouts',  
         'passwd' => 'Change Password',  
         'grades' => 'Gradebook',  
         'search' => 'Course search',  
         'wishlist' => 'Stored links',  
         'annotate' => 'Annotations',  
     );  
     my $typeorder = ['com','chat','boards','port','groups','blogs','about','wishlist','printout','grades','search','annotate','passwd'];  
     return ($typeorder,\%types);  
 }  
   
 sub print_rolecolors {  sub print_rolecolors {
     my ($phase,$role,$dom,$confname,$settings,$rowtotal) = @_;      my ($phase,$role,$dom,$confname,$settings,$rowtotal) = @_;
     my %choices = &color_font_choices();      my %choices = &color_font_choices();
Line 1912  sub display_color_options { Line 1596  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 1921  sub display_color_options { Line 1605  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 1936  sub display_color_options { Line 1620  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 1944  sub display_color_options { Line 1628  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 1952  sub display_color_options { Line 1636  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 2050  sub display_color_options { Line 1729  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 2064  sub display_color_options { Line 1738  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 2076  sub display_color_options { Line 1750  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 2092  sub display_color_options { Line 1766  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 2104  sub display_color_options { Line 1778  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 2165  sub login_text_colors { Line 1839  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 2178  sub image_changes { Line 1852  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 2198  sub image_changes { Line 1874  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 2217  sub print_quotas { Line 1893  sub print_quotas {
     my $typecount = 0;      my $typecount = 0;
     my ($css_class,%titles);      my ($css_class,%titles);
     if ($context eq 'requestcourses') {      if ($context eq 'requestcourses') {
         @usertools = ('official','unofficial','community','textbook');          @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 2681  sub print_studentcode { Line 2357  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');      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 2808  sub print_textbookcourses { Line 2484  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 2825  sub print_textbookcourses { Line 2501  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 3012  sub ltitools_toggle_js { Line 2688  sub ltitools_toggle_js {
 function toggleLTITools(form,setting,item) {  function toggleLTITools(form,setting,item) {
     var radioname = '';      var radioname = '';
     var divid = '';      var divid = '';
     if (setting == 'user') {      if ((setting == 'passback') || (setting == 'roster')) {
         divid = 'ltitools_'+setting+'_div_'+item;          radioname = 'ltitools_'+setting+'_'+item;
         var checkid = 'ltitools_'+setting+'_field_'+item;          divid = 'ltitools_'+setting+'time_'+item;
         if (document.getElementById(divid)) {          var num = form.elements[radioname].length;
             if (document.getElementById(checkid)) {          if (num) {
                 if (document.getElementById(checkid).checked) {              var setvis = '';
                     document.getElementById(divid).style.display = 'inline-block';              for (var i=0; i<num; i++) {
                 } else {                  if (form.elements[radioname][i].checked) {
                     document.getElementById(divid).style.display = 'none';                      if (form.elements[radioname][i].value == '1') {
                 }                          if (document.getElementById(divid)) {
             }                              document.getElementById(divid).style.display = 'inline-block';
         }  
     }  
     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();  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
   
 $linkprot_js  
   
 // ]]>  
 </script>  
   
 $togglejs  
   
 ENDSCRIPT  
 }  
   
 sub lti_toggle_js {  
     my ($dom) = @_;  
     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 toggleLTIEncKey(form) {  
     var shownhosts = new Array();  
     var hiddenhosts = new Array();  
     var forcourse = new Array($course_servers);  
     var fromdomain = '$primary';  
     var crsradio = form.elements['ltisec_crslinkprot'];  
     if (crsradio.length) {  
         for (var i=0; i<crsradio.length; i++) {  
             if (crsradio[i].checked) {  
                 if (crsradio[i].value == 1) {  
                     if (forcourse.length > 0) {  
                         for (var j=0; j<forcourse.length; j++) {  
                             if (!shownhosts.includes(forcourse[j])) {  
                                 shownhosts.push(forcourse[j]);  
                             }  
                         }  
                     }  
                 } else {  
                     if (forcourse.length > 0) {  
                         for (var j=0; j<forcourse.length; j++) {  
                             if (!hiddenhosts.includes(forcourse[j])) {  
                                 hiddenhosts.push(forcourse[j]);  
                             }  
                         }  
                     }  
                 }  
             }  
         }  
     }  
     var domradio = form.elements['ltisec_domlinkprot'];  
     if (domradio.length) {  
         for (var i=0; i<domradio.length; i++) {  
             if (domradio[i].checked) {  
                 if (domradio[i].value == 1) {  
                     if (!shownhosts.includes(fromdomain)) {  
                         shownhosts.push(fromdomain);  
                     }  
                 } else {  
                     if (!hiddenhosts.includes(fromdomain)) {  
                         hiddenhosts.push(fromdomain);  
                     }  
                 }  
             }  
         }  
     }  
     if (shownhosts.length > 0) {  
         for (var i=0; i<shownhosts.length; i++) {  
             if (document.getElementById('ltisec_info_'+shownhosts[i])) {  
                 document.getElementById('ltisec_info_'+shownhosts[i]).style.display = 'block';  
             }  
         }  
         if (document.getElementById('ltisec_noprivkey')) {  
             document.getElementById('ltisec_noprivkey').style.display = 'none';  
         }  
     } else {  
         if (document.getElementById('ltisec_noprivkey')) {  
             document.getElementById('ltisec_noprivkey').style.display = 'inline-block';  
         }  
     }  
     if (hiddenhosts.length > 0) {  
         for (var i=0; i<hiddenhosts.length; i++) {  
             if (!shownhosts.includes(hiddenhosts[i])) {  
                 if (document.getElementById('ltisec_info_'+hiddenhosts[i])) {  
                     document.getElementById('ltisec_info_'+hiddenhosts[i]).style.display = 'none';  
                 }  
             }  
         }  
     }  
     return;  
 }  
   
 function togglePrivKey(form,hostid) {  
     var radioname = '';  
     var currdivid = '';  
     var newdivid = '';  
     if ((document.getElementById('ltisec_divcurrprivkey_'+hostid)) &&  
         (document.getElementById('ltisec_divchgprivkey_'+hostid))) {  
         currdivid = document.getElementById('ltisec_divcurrprivkey_'+hostid);  
         newdivid = document.getElementById('ltisec_divchgprivkey_'+hostid);  
         radioname = form.elements['ltisec_changeprivkey_'+hostid];  
         if (radioname) {  
             if (radioname.length > 0) {  
                 var setvis;  
                 for (var i=0; i<radioname.length; i++) {  
                     if (radioname[i].checked == true) {  
                         if (radioname[i].value == 1) {  
                             newdivid.style.display = 'inline-block';  
                             currdivid.style.display = 'none';  
                             setvis = 1;  
                         }                          }
                         break;                          setvis = 1;
                     }  
                 }  
                 if (!setvis) {  
                     newdivid.style.display = 'none';  
                     currdivid.style.display = 'inline-block';  
                 }  
             }  
         }  
     }  
 }  
   
 // ]]>  
 </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;
                 }                  }
                 break;  
             }              }
         }          }
         if (!setvis) {          if (!setvis) {
Line 3352  function toggleFailsafe(form) { Line 2720  function toggleFailsafe(form) {
 ENDSCRIPT  ENDSCRIPT
 }  }
   
 sub saml_javascript {  sub lti_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 ($settings) = @_;
       my $togglejs = &lti_toggle_js();
       unless (ref($settings) eq 'HASH') {
           return $togglejs;
       }
     my (%ordered,$total,%jstext);      my (%ordered,$total,%jstext);
     $total = 0;      $total = 0;
     if (ref($settings) eq 'HASH') {      foreach my $item (keys(%{$settings})) {
         foreach my $item (keys(%{$settings})) {          if (ref($settings->{$item}) eq 'HASH') {
             if (ref($settings->{$item}) eq 'HASH') {              my $num = $settings->{$item}{'order'};
                 my $num = $settings->{$item}{'order'};              $ordered{$num} = $item;
                 $ordered{$num} = $item;  
             }  
         }          }
         $total = scalar(keys(%{$settings}));  
     }      }
       $total = scalar(keys(%{$settings}));
     my @jsarray = ();      my @jsarray = ();
     foreach my $item (sort {$a <=> $b } (keys(%ordered))) {      foreach my $item (sort {$a <=> $b } (keys(%ordered))) {
         push(@jsarray,$ordered{$item});          push(@jsarray,$ordered{$item});
     }      }
     my $jstext = '    var ipaccess = Array('."'".join("','",@jsarray)."'".');'."\n";      my $jstext = '    var lti = Array('."'".join("','",@jsarray)."'".');'."\n";
     return <<"ENDSCRIPT";      return <<"ENDSCRIPT";
 <script type="text/javascript">  <script type="text/javascript">
 // <![CDATA[  // <![CDATA[
 function reorderIPaccess(form,item) {  function reorderLTI(form,item) {
     var changedVal;      var changedVal;
 $jstext  $jstext
     var newpos = 'ipaccess_pos_add';      var newpos = 'lti_pos_add';
     var maxh = 1 + $total;      var maxh = 1 + $total;
     var current = new Array;      var current = new Array;
     var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;      var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;
Line 3428  $jstext Line 2756  $jstext
         changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;          changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;
         current[newitemVal] = newpos;          current[newitemVal] = newpos;
     }      }
     for (var i=0; i<ipaccess.length; i++) {      for (var i=0; i<lti.length; i++) {
         var elementName = 'ipaccess_pos_'+ipaccess[i];          var elementName = 'lti_pos_'+lti[i];
         if (elementName != item) {          if (elementName != item) {
             if (form.elements[elementName]) {              if (form.elements[elementName]) {
                 var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;                  var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
Line 3459  $jstext Line 2787  $jstext
 // ]]>  // ]]>
 </script>  </script>
   
   $togglejs
   
   ENDSCRIPT
   }
   
   sub lti_toggle_js {
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   
   function toggleLTI(form,setting,item) {
       if ((setting == 'user') || (setting == 'crs')) {
           var radioname = '';
           var divid = '';
           if (setting == 'user') {
               radioname = 'lti_mapuser_'+item;
               divid = 'lti_userfield_'+item;
           } else {
               radioname = 'lti_mapcrs_'+item;
               divid = 'lti_crsfield_'+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 == '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';
                   }
               }
           }
       }
       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 3504  sub print_autoenroll { Line 2916  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 3560  sub print_autoenroll { Line 2956  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>'.&mt($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 3877  sub print_contacts { Line 3240  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 3888  sub print_contacts { Line 3251  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 3910  sub print_contacts { Line 3267  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 3971  sub print_contacts { Line 3328  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 4032  sub print_contacts { Line 3388  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 4043  sub print_contacts { Line 3399  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 4077  sub print_contacts { Line 3433  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 4090  sub print_contacts { Line 3446  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 4215  sub print_contacts { Line 3485  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 4227  sub print_contacts { Line 3497  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 4261  sub print_contacts { Line 3531  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 4294  sub overridden_helpdesk { Line 3559  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 4316  sub overridden_helpdesk { Line 3581  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 4373  function toggleHelpdeskRow(form,checkbox Line 3638  function toggleHelpdeskRow(form,checkbox
     return;      return;
 }  }
   
   
 // ]]>  // ]]>
 </script>  </script>
   
Line 4478  sub print_helpsettings { Line 3744  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 4517  sub print_helpsettings { Line 3783  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 4547  sub print_helpsettings { Line 3813  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 4766  sub helpdeskroles_access { Line 4030  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 4798  sub radiobutton_prefs { Line 4062  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 4806  sub radiobutton_prefs { Line 4070  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="'.  
                 $item.'" '.$checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').  
                 '</label>&nbsp;<label><input type="radio" name="'.$item.'" '.  
                 $checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').'</label>';  
         } else {  
             $datatable .=  
             '<label><input type="radio" name="'.              '<label><input type="radio" name="'.
             $item.'" '.$checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').              $item.'" '.$checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').
             '</label>&nbsp;<label><input type="radio" name="'.$item.'" '.              '</label>&nbsp;<label><input type="radio" name="'.$item.'" '.
             $checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').'</label>';              $checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').'</label>'.
         }              '</span>'.$additional.
         $datatable .= '</span>'.$additional.'</td></tr>';              '</td>'.
               '</tr>';
         $itemcount ++;          $itemcount ++;
     }      }
     return ($datatable,$itemcount);      return ($datatable,$itemcount);
Line 4844  sub print_ltitools { Line 4102  sub print_ltitools {
     my $confname = $dom.'-domainconfig';      my $confname = $dom.'-domainconfig';
     my $switchserver = &check_switchserver($dom,$confname);      my $switchserver = &check_switchserver($dom,$confname);
     my $maxnum = scalar(keys(%ordered));      my $maxnum = scalar(keys(%ordered));
     my $datatable;      my $datatable = &ltitools_javascript($settings);
     my %lt = &ltitools_names();      my %lt = &ltitools_names();
     my @courseroles = ('cc','in','ta','ep','st');      my @courseroles = ('cc','in','ta','ep','st');
     my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner);      my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner);
     my @fields = ('fullname','firstname','lastname','email','roles','user');      my @fields = ('fullname','firstname','lastname','email','user','roles');
     if (keys(%ordered)) {      if (keys(%ordered)) {
         my @items = sort { $a <=> $b } keys(%ordered);          my @items = sort { $a <=> $b } keys(%ordered);
         for (my $i=0; $i<@items; $i++) {          for (my $i=0; $i<@items; $i++) {
Line 4945  sub print_ltitools { Line 4203  sub print_ltitools {
                               '<input type="text" name="ltitools_'.$dimen.'_'.$i.'" size="5" value="'.$currdisp{$dimen}.'" /></label>'.                                '<input type="text" name="ltitools_'.$dimen.'_'.$i.'" size="5" value="'.$currdisp{$dimen}.'" /></label>'.
                               ('&nbsp;'x2);                                ('&nbsp;'x2);
             }              }
             $datatable .= '</span><br />'.              $datatable .= '<br />'.
                           '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'.                            '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'.
                           '<input type="text" name="ltitools_linktext_'.$i.'" size="25" value="'.$currdisp{'linktext'}.'" /></div>'.                            '<input type="text" name="ltitools_linktext_'.$i.'" size="25" value="'.$currdisp{'linktext'}.'" /></label></div>'.
                           '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'.                            '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'.
                           '<textarea name="ltitools_explanation_'.$i.'" rows="5" cols="40">'.$currdisp{'explanation'}.                            '<textarea name="ltitools_explanation_'.$i.'" rows="5" cols="40">'.$currdisp{'explanation'}.
                           '</textarea></div><div style=""></div>'.                            '</textarea></div><div style=""></div><br />';
                           '<div style="padding:0;clear:both;margin:0;border:0"></div>';              my %units = (
                             'passback' => 'days',
                             'roster'   => 'seconds',
                           );
               foreach my $extra ('passback','roster') {
                   my $validsty = 'none';
                   my $currvalid;
                   my $checkedon = '';
                   my $checkedoff = ' checked="checked"';
                   if ($settings->{$item}->{$extra}) {
                       $checkedon = $checkedoff;
                       $checkedoff = '';
                       $validsty = 'inline-block';
                       if ($settings->{$item}->{$extra.'valid'} =~ /^\d+\.?\d*$/) {
                           $currvalid = $settings->{$item}->{$extra.'valid'};
                       }
                   }
                   my $onclick = ' onclick="toggleLTITools(this.form,'."'$extra','$i'".');"';
                   $datatable .= '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{$extra}.'&nbsp;'.
                                 '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="0"'.$checkedoff.$onclick.' />'.
                                 &mt('No').'</label>'.('&nbsp;'x2).
                                 '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="1"'.$checkedon.$onclick.' />'.
                                 &mt('Yes').'</label></span></div>'.
                                 '<div class="LC_floatleft" style="display:'.$validsty.';" id="ltitools_'.$extra.'time_'.$i.'">'.
                                 '<span class="LC_nobreak">'.
                                 &mt("at least [_1] $units{$extra} after launch",
                                     '<input type="text" name="ltitools_'.$extra.'valid_'.$i.'" value="'.$currvalid.'" />').
                                 '</span></div><div style="padding:0;clear:both;margin:0;border:0"></div>';
               }
             $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.':&nbsp;';              $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.':&nbsp;';
             if ($imgsrc) {              if ($imgsrc) {
                 $datatable .= $imgsrc.                  $datatable .= $imgsrc.
Line 4967  sub print_ltitools { Line 4253  sub print_ltitools {
                 $datatable .= '<input type="file" name="ltitools_image_'.$i.'" value="" />';                  $datatable .= '<input type="file" name="ltitools_image_'.$i.'" value="" />';
             }              }
             $datatable .= '</span></fieldset>';              $datatable .= '</span></fieldset>';
             my (%checkedfields,%rolemaps,$userincdom);              my (%checkedfields,%rolemaps);
             if (ref($settings->{$item}) eq 'HASH') {              if (ref($settings->{$item}) eq 'HASH') {
                 if (ref($settings->{$item}->{'fields'}) eq 'HASH') {                  if (ref($settings->{$item}->{'fields'}) eq 'HASH') {
                     %checkedfields = %{$settings->{$item}->{'fields'}};                      %checkedfields = %{$settings->{$item}->{'fields'}};
                 }                  }
                 $userincdom = $settings->{$item}->{'incdom'};  
                 if (ref($settings->{$item}->{'roles'}) eq 'HASH') {                  if (ref($settings->{$item}->{'roles'}) eq 'HASH') {
                     %rolemaps = %{$settings->{$item}->{'roles'}};                      %rolemaps = %{$settings->{$item}->{'roles'}};
                     $checkedfields{'roles'} = 1;                      $checkedfields{'roles'} = 1;
Line 4980  sub print_ltitools { Line 4265  sub print_ltitools {
             }              }
             $datatable .= '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'.              $datatable .= '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'.
                           '<span class="LC_nobreak">';                            '<span class="LC_nobreak">';
             my $userfieldstyle = 'display:none;';  
             my $seluserdom = '';  
             my $unseluserdom = ' selected="selected"';  
             foreach my $field (@fields) {              foreach my $field (@fields) {
                 my ($checked,$onclick,$id,$spacer);                  my $checked;
                 if ($checkedfields{$field}) {                  if ($checkedfields{$field}) {
                     $checked = ' checked="checked"';                      $checked = ' checked="checked"';
                 }                  }
                 if ($field eq 'user') {  
                     $id = ' id="ltitools_user_field_'.$i.'"';  
                     $onclick = ' onclick="toggleLTITools(this.form,'."'$field','$i'".')"';  
                     if ($checked) {  
                         $userfieldstyle = 'display:inline-block';  
                         if ($userincdom) {  
                             $seluserdom = $unseluserdom;  
                             $unseluserdom = '';  
                         }  
                     }  
                 } else {  
                     $spacer = ('&nbsp;' x2);  
                 }  
                 $datatable .= '<label>'.                  $datatable .= '<label>'.
                               '<input type="checkbox" name="ltitools_fields_'.$i.'" value="'.$field.'"'.$id.$checked.$onclick.' />'.                                '<input type="checkbox" name="ltitools_fields_'.$i.'" value="'.$field.'"'.$checked.' />'.
                               $lt{$field}.'</label>'.$spacer;                                $lt{$field}.'</label>'.('&nbsp;' x2);
             }              }
             $datatable .= '</span>';              $datatable .= '</span></fieldset>'.
             $datatable .= '<div style="'.$userfieldstyle.'" id="ltitools_user_div_'.$i.'">'.  
                           '<span class="LC_nobreak"> : '.  
                           '<select name="ltitools_userincdom_'.$i.'">'.  
                           '<option value="">'.&mt('Select').'</option>'.  
                           '<option value="0"'.$unseluserdom.'>'.&mt('username').'</option>'.  
                           '<option value="1"'.$seluserdom.'>'.&mt('username:domain').'</option>'.  
                           '</select></span></div>';  
             $datatable .= '</fieldset>'.  
                           '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>';                            '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>';
             foreach my $role (@courseroles) {              foreach my $role (@courseroles) {
                 my ($selected,$selectnone);                  my ($selected,$selectnone);
                 if (!$rolemaps{$role}) {                  if (!$rolemaps{$role}) {
                     $selectnone = ' selected="selected"';                      $selectnone = ' selected="selected"';
                 }                  }
                 $datatable .= '<td align="center">'.                  $datatable .= '<td style="text-align: center">'. 
                               &Apache::lonnet::plaintext($role,'Course').'<br />'.                                &Apache::lonnet::plaintext($role,'Course').'<br />'.
                               '<select name="ltitools_roles_'.$role.'_'.$i.'">'.                                '<select name="ltitools_roles_'.$role.'_'.$i.'">'.
                               '<option value=""'.$selectnone.'>'.&mt('Select').'</option>';                                '<option value=""'.$selectnone.'>'.&mt('Select').'</option>';
Line 5090  sub print_ltitools { Line 4351  sub print_ltitools {
         $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="ltitools_add" value="1" />'.&mt('Add').'</span></td>'."\n".                    '<input type="checkbox" name="ltitools_add" value="1" />'.&mt('Add').'</td>'."\n".
                   '<td colspan="2">'.                    '<td colspan="2">'.
                   '<fieldset><legend>'.&mt('Required settings').'</legend>'.                    '<fieldset><legend>'.&mt('Required settings').'</legend>'.
                   '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="20" name="ltitools_add_title" value="" /></span> '."\n".                    '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="20" name="ltitools_add_title" value="" /></span> '."\n".
Line 5127  sub print_ltitools { Line 4388  sub print_ltitools {
                       '<input type="text" name="ltitools_add_'.$dimen.'" size="5" /></label>'.                        '<input type="text" name="ltitools_add_'.$dimen.'" size="5" /></label>'.
                       ('&nbsp;'x2);                        ('&nbsp;'x2);
     }      }
     $datatable .= '</span><br />'.      $datatable .= '<br />'.
                   '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'.                    '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'.
                   '<input type="text" name="ltitools_add_linktext" size="5" /></div>'.                    '<input type="text" name="ltitools_add_linktext" size="5" /></label></div>'.
                   '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'.                    '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'.
                   '<textarea name="ltitools_add_explanation" rows="5" cols="40"></textarea>'.                    '<textarea name=ltitools_add_explanation" rows="5" cols="40"></textarea>'.
                   '</div><div style=""></div>'.                    '</div><div style=""></div><br />';
                   '<div style="padding:0;clear:both;margin:0;border:0"></div>';      my %units = (
                     'passback' => 'days',
                     'roster'   => 'seconds',
                   );
       my %defaulttimes = (
                        'passback' => '7',
                        'roster'   => '300',
                      );
       foreach my $extra ('passback','roster') {
           my $onclick = ' onclick="toggleLTITools(this.form,'."'$extra','add'".');"';
           $datatable .= '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{$extra}.'&nbsp;'.
                         '<label><input type="radio" name="ltitools_'.$extra.'_add" value="0" checked="checked"'.$onclick.' />'.
                         &mt('No').'</label></span>'.('&nbsp;'x2).'<span class="LC_nobreak">'.
                         '<label><input type="radio" name="ltitools_'.$extra.'_add" value="1"'.$onclick.' />'.
                         &mt('Yes').'</label></span></div>'.
                         '<div class="LC_floatleft" style="display:none;" id="ltitools_'.$extra.'time_add">'.
                         '<span class="LC_nobreak">'.
                         &mt("at least [_1] $units{$extra} after launch",
                             '<input type="text" name="ltitools_'.$extra.'valid_add" value="'.$defaulttimes{$extra}.'" />').
                         '</span></div><div style="padding:0;clear:both;margin:0;border:0"></div>';
       }
     $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.':&nbsp;'.      $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.':&nbsp;'.
                   '('.&mt('if larger than 21x21 pixels, image will be scaled').')&nbsp;';                    '('.&mt('if larger than 21x21 pixels, image will be scaled').')&nbsp;';
     if ($switchserver) {      if ($switchserver) {
Line 5145  sub print_ltitools { Line 4426  sub print_ltitools {
                   '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'.                    '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'.
                   '<span class="LC_nobreak">';                    '<span class="LC_nobreak">';
     foreach my $field (@fields) {      foreach my $field (@fields) {
         my ($id,$onclick,$spacer);  
         if ($field eq 'user') {  
             $id = ' id="ltitools_user_field_add"';  
             $onclick = ' onclick="toggleLTITools(this.form,'."'$field','add'".')"';  
         } else {  
             $spacer = ('&nbsp;' x2);  
         }  
         $datatable .= '<label>'.          $datatable .= '<label>'.
                       '<input type="checkbox" name="ltitools_add_fields" value="'.$field.'"'.$id.$onclick.' />'.                        '<input type="checkbox" name="ltitools_add_fields" value="'.$field.'" />'.
                       $lt{$field}.'</label>'.$spacer;                        $lt{$field}.'</label>'.('&nbsp;' x2);
     }      }
     $datatable .= '</span>'.      $datatable .= '</span></fieldset>'.
                   '<div style="display:none;" id="ltitools_user_div_add">'.                    '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>';
                   '<span class="LC_nobreak"> : '.  
                   '<select name="ltitools_userincdom_add">'.  
                   '<option value="" selected="selected">'.&mt('Select').'</option>'.  
                   '<option value="0">'.&mt('username').'</option>'.  
                   '<option value="1">'.&mt('username:domain').'</option>'.  
                   '</select></span></div></fieldset>';  
     $datatable .= '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>';  
     foreach my $role (@courseroles) {      foreach my $role (@courseroles) {
         my ($checked,$checkednone);          my ($checked,$checkednone);
         $datatable .= '<td align="center">'.          $datatable .= '<td style="text-align: center">'.
                       &Apache::lonnet::plaintext($role,'Course').'<br />'.                        &Apache::lonnet::plaintext($role,'Course').'<br />'.
                       '<select name="ltitools_add_roles_'.$role.'">'.                        '<select name="ltitools_add_roles_'.$role.'">'.
                       '<option value="" selected="selected">'.&mt('Select').'</option>';                        '<option value="" selected="selected">'.&mt('Select').'</option>';
Line 5190  sub print_ltitools { Line 4457  sub print_ltitools {
                   '<label><input type="checkbox" name="ltitools_add_custom" value="1" />'.                    '<label><input type="checkbox" name="ltitools_add_custom" value="1" />'.
                   &mt('Add').'</label></span></td><td><input type="text" name="ltitools_add_custom_name" />'.                    &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>'.                    '</td><td><input type="text" name="ltitools_add_custom_value" /></td></tr>'.
                   '</table></fieldset>'."\n".                    '</table></fieldset></td></tr>'."\n".
                   '</td>'."\n".                    '</td>'."\n".
                   '</tr>'."\n";                    '</tr>'."\n";
     $itemcount ++;      $itemcount ++;
Line 5207  sub ltitools_names { Line 4474  sub ltitools_names {
                                           'key'            => 'Key',                                            'key'            => 'Key',
                                           'lifetime'       => 'Nonce lifetime (s)',                                            'lifetime'       => 'Nonce lifetime (s)',
                                           'secret'         => 'Secret',                                            'secret'         => 'Secret',
                                           'icon'           => 'Icon',                                            'icon'           => 'Icon',   
                                           'user'           => 'User',                                            'user'           => 'Username:domain',
                                           'fullname'       => 'Full Name',                                            'fullname'       => 'Full Name',
                                           'firstname'      => 'First Name',                                            'firstname'      => 'First Name',
                                           'lastname'       => 'Last Name',                                            'lastname'       => 'Last Name',
Line 5221  sub ltitools_names { Line 4488  sub ltitools_names {
                                           'width'          => 'Width',                                            'width'          => 'Width',
                                           'linktext'       => 'Default Link Text',                                            'linktext'       => 'Default Link Text',
                                           'explanation'    => 'Default Explanation',                                            'explanation'    => 'Default Explanation',
                                             'passback'       => 'Tool can return grades:',
                                             'roster'         => 'Tool can retrieve roster:',
                                           'crstarget'      => 'Display target',                                            'crstarget'      => 'Display target',
                                           'crslabel'       => 'Course label',                                            'crslabel'       => 'Course label',
                                           'crstitle'       => 'Course title',                                            'crstitle'       => 'Course title', 
                                           'crslinktext'    => 'Link Text',                                            'crslinktext'    => 'Link Text',
                                           'crsexplanation' => 'Explanation',                                            'crsexplanation' => 'Explanation',
                                           'crsappend'      => 'Provider URL',                                            'crsappend'      => 'Provider URL',
                                         );                                          );
   
     return %lt;      return %lt;
 }  }
   
 sub print_lti {  sub print_lti {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($dom,$settings,$rowtotal) = @_;
     my $itemcount = 1;      my $itemcount = 1;
     my ($datatable,$css_class);      my $maxnum = 0;
     my (%rules,%encrypt,%privkeys,%linkprot);      my $css_class;
       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{'ltisec_'.$key.'linkprot'} = $settings->{'encrypt'}{$key};  
                     }  
                 }  
             }  
             if (exists($settings->{'private'})) {  
                 if (ref($settings->{'private'}) eq 'HASH') {  
                     if (ref($settings->{'private'}) eq 'HASH') {  
                         if (ref($settings->{'private'}{'keys'}) eq 'ARRAY') {  
                             map { $privkeys{$_} = 1; } (@{$settings->{'private'}{'keys'}});  
                         }  
                     }  
                 }  
             }              }
         } elsif ($position eq 'middle') {          }
             if (exists($settings->{'rules'})) {      }
                 if (ref($settings->{'rules'}) eq 'HASH') {      my $maxnum = scalar(keys(%ordered));
                     %rules = %{$settings->{'rules'}};      my $datatable = &lti_javascript($settings);
                 }      my %lt = &lti_names();
       if (keys(%ordered)) {
           my @items = sort { $a <=> $b } keys(%ordered);
           for (my $i=0; $i<@items; $i++) {
               $css_class = $itemcount%2?' class="LC_odd_row"':'';
               my $item = $ordered{$items[$i]};
               my ($key,$secret,$lifetime,$consumer,$current);
               if (ref($settings->{$item}) eq 'HASH') {
                   $key = $settings->{$item}->{'key'};
                   $secret = $settings->{$item}->{'secret'};
                   $lifetime = $settings->{$item}->{'lifetime'};
                   $consumer = $settings->{$item}->{'consumer'};
                   $current = $settings->{$item};
             }              }
         } elsif ($position eq 'bottom') {              my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_".$item."'".');"';
             if (exists($settings->{'linkprot'})) {              $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
                 if (ref($settings->{'linkprot'}) eq 'HASH') {                           .'<select name="lti_pos_'.$item.'"'.$chgstr.'>';
                     %linkprot = %{$settings->{'linkprot'}};              for (my $k=0; $k<=$maxnum; $k++) {
                     if ($linkprot{'lock'}) {                  my $vpos = $k+1;
                         delete($linkprot{'lock'});                  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="20" 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="5" /></span>'.
                   '<br /><br />'.
                   '<span class="LC_nobreak">'.$lt{'key'}.
                   ':<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" /></span> '.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'secret'}.':'.
                   '<input type="password" size="20" name="lti_secret_'.$i.'" value="'.$secret.'" />'.
                   '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.
                   '<input type="hidden" name="lti_id_'.$i.'" value="'.$item.'" /></span>'.
                   '</fieldset>'.&lti_options($i,$current,%lt).'</td></tr>';
               $itemcount ++;
         }          }
     }      }
     if ($position eq 'top') {      $css_class = $itemcount%2?' class="LC_odd_row"':'';
         my @ids=&Apache::lonnet::current_machine_ids();      my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_add'".');"';
         my %servers = &Apache::lonnet::get_servers($dom,'library');      $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
         my $primary = &Apache::lonnet::domain($dom,'primary');                    '<input type="hidden" name="lti_maxnum" value="'.$maxnum.'" />'."\n".
         my ($extra,$numshown);                    '<select name="lti_pos_add"'.$chgstr.'>';
         foreach my $hostid (sort(keys(%servers))) {      for (my $k=0; $k<$maxnum+1; $k++) {
             my ($showextra,$divsty,$switch);          my $vpos = $k+1;
             if ($hostid eq $primary) {          my $selstr;
                 if ($encrypt{'ltisec_domlinkprot'}) {          if ($k == $maxnum) {
                     $showextra = 1;              $selstr = ' selected="selected" ';
                 }  
             }  
             if ($encrypt{'ltisec_crslinkprot'}) {  
                 $showextra = 1;  
             }  
             unless (grep(/^\Q$hostid\E$/,@ids)) {  
                 $switch = 1;  
             }  
             if ($showextra) {  
                 $numshown ++;  
                 $divsty = 'display:inline-block';  
             } else {  
                 $divsty = 'display:none';  
             }  
             $extra .= '<fieldset id="ltisec_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="ltisec_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="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" checked="checked" />'.&mt('No').'</label>'.  
                               ('&nbsp;'x2).  
                               '<label><input type="radio" value="1" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" />'.&mt('Yes').  
                               '</label>&nbsp;&nbsp;</span><div id="ltisec_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="ltisec_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="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" checked="checked" />'.&mt('No').'</label>'.  
                           ('&nbsp;'x2).  
                           '<label><input type="radio" value="1" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" />'.&mt('Yes').  
                           '</label>&nbsp;&nbsp;</span><div id="ltisec_divchgprivkey_'.$hostid.'" style="display:none" />'.  
                           '<span class="LC_nobreak">'.&mt('New Key').':'.  
                           '<input type="password" size="20" name="ltisec_privkey_'.$hostid.'" value="" autocomplete="off" />'.  
                           '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltisec_privkey_'.$hostid.'.type='."'text'".' } else { this.form.ltisec_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="ltisec_privkey_'.$hostid.'" value="" autocomplete="off" />'.  
                           '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltisec_privkey_'.$hostid.'.type='."'text'".' } else { this.form.ltisec_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>';  
             }  
             $extra .= '</fieldset>';  
         }          }
         my %choices = &Apache::lonlocal::texthash (          $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
                                                       ltisec_crslinkprot => 'Encrypt stored link protection secrets defined in courses',      }
                                                       ltisec_domlinkprot => 'Encrypt stored link protection secrets defined in domain',      $datatable .= '</select>&nbsp;'."\n".
                                                   );                    '<input type="checkbox" name="lti_add" value="1" />'.&mt('Add').'</td>'."\n".
         my @toggles = qw(ltisec_crslinkprot ltisec_domlinkprot);                    '<td colspan="2">'.
         my %defaultchecked = (                    '<fieldset><legend>'.&mt('Required settings').'</legend>'.
                                'ltisec_crslinkprot' => 'off',                    '<span class="LC_nobreak">'.$lt{'consumer'}.
                                'ltisec_domlinkprot' => 'off',                    ':<input type="text" size="20" name="lti_consumer_add" value="" /></span> '."\n".
                              );                    ('&nbsp;'x2).
         my ($onclick,$itemcount);                    '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_add">'.
         $onclick = 'javascript:toggleLTIEncKey(this.form);';                    '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".
         ($datatable,$itemcount) = &radiobutton_prefs(\%encrypt,\@toggles,\%defaultchecked,                    ('&nbsp;'x2).
                                                      \%choices,$itemcount,$onclick,'','left','no');                    '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="5" name="lti_lifetime_add" value="300" /></span> '."\n".
                     '<br /><br />'.
                     '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="lti_key_add" value="" /></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="lti_secret_add" value="" />'.
                     '<label><input type="checkbox" name="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".
                     '</fieldset>'.&lti_options('add',undef,%lt).
                     '</td>'."\n".
                     '</tr>'."\n";
       $$rowtotal ++;
       return $datatable;;
   }
   
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  sub lti_names {
         my $noprivkeysty = 'display:inline-block';      my %lt = &Apache::lonlocal::texthash(
         if ($numshown) {                                            'version'   => 'LTI Version',
             $noprivkeysty = 'display:none';                                            'url'       => 'URL',
         }                                            'key'       => 'Key',
         $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.&mt('Encryption Key(s)').'</td>'.                                            'lifetime'  => 'Nonce lifetime (s)',
                       '<td><div id="ltisec_noprivkey" style="'.$noprivkeysty.'" >'.                                            'consumer'  => 'LTI Consumer', 
                       '<span class="LC_nobreak">'.&mt('Not in use').'</span></div>'.                                            'secret'    => 'Secret',
                       $extra.                                            'email'     => 'Email address',
                       '</td></tr>';                                            'sourcedid' => 'User ID',
         $itemcount ++;                                            'other'     => 'Other',
         $$rowtotal += $itemcount;                                            'passback'  => 'Can return grades to Consumer:',
     } elsif ($position eq 'middle') {                                            'roster'    => 'Can retrieve roster from Consumer:',
         $datatable = &password_rules('secrets',\$itemcount,\%rules);                                          );
         $$rowtotal += $itemcount;      return %lt;
     } elsif ($position eq 'bottom') {  }
          $datatable .= &Apache::courseprefs::print_linkprotection($dom,'',$settings,$rowtotal,'','','domain');  
   sub lti_options {
       my ($num,$current,%lt) = @_;
       my (%checked,%rolemaps,$crssecsrc,$userfield,$cidfield);
       $checked{'mapuser'}{'sourcedid'} = ' checked="checked"';
       $checked{'mapcrs'}{'course_offering_sourcedid'} = ' checked="checked"';
       $checked{'makecrs'}{'N'} = '  checked="checked"';
       $checked{'mapcrstype'} = {};
       $checked{'makeuser'} = {};
       $checked{'selfenroll'} = {};
       $checked{'crssec'} = {};
       $checked{'crssecsrc'} = {};
   
       my $userfieldsty = 'none';
       my $crsfieldsty = 'none';
       my $crssecfieldsty = 'none';
       my $secsrcfieldsty = 'none';
   
       if (ref($current) eq 'HASH') {
           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->{'makecrs'}) { 
               $checked{'makecrs'}{'Y'} = '  checked="checked"';
           } 
           if (ref($current->{'makeuser'}) eq 'ARRAY') {
               foreach my $role (@{$current->{'makeuser'}}) {
                   $checked{'makeuser'}{$role} = ' checked="checked"';
               }
           }
           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"';
           }
       } else {
           $checked{'makecrs'}{'N'} = ' checked="checked"';
           $checked{'crssec'}{'N'} = ' checked="checked"';
     }      }
     return $datatable;      my @coursetypes = ('official','unofficial','community','textbook','placement');
       my %coursetypetitles = &Apache::lonlocal::texthash (
                                  official   => 'Official',
                                  unofficial => 'Unofficial',
                                  community  => 'Community',
                                  textbook   => 'Textbook',
                                  placement  => 'Placement Test',
       );
       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 $onclicksecsrc = ' onclick="toggleLTI(this.form,'."'secsrc','$num'".')"';
       my $output = '<fieldset><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><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><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><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 .= '</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></fieldset>'.
                  '<fieldset><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><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><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></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>'; 
       foreach my $extra ('passback','roster') {
           my $checkedon = '';
           my $checkedoff = ' checked="checked"';
           if (ref($current) eq 'HASH') {
               if (($current->{$extra})) {
                   $checkedon = $checkedoff;
                   $checkedoff = '';
               }
           }
           $output .= $lt{$extra}.'&nbsp;'.
                      '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="0"'.$checkedoff.' />'.
                      &mt('No').'</label>'.('&nbsp;'x2).
                      '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="1"'.$checkedon.' />'.
                      &mt('Yes').'</label><br />';
       }
       $output .= '</span></fieldset>';
   #        '<fieldset><legend>'.&mt('Assigning author roles').'</legend>';
   #
   #    $output .= '</fieldset>'.
   #        '<fieldset><legend>'.&mt('Assigning domain roles').'</legend>';
       return $output;
 }  }
   
 sub print_coursedefaults {  sub print_coursedefaults {
Line 5377  sub print_coursedefaults { Line 4826  sub print_coursedefaults {
     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)',
         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',  
     );      );
     my %staticdefaults = (      my %staticdefaults = (
                              texengine            => 'MathJax',
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
                            postsubmit           => 60,                             postsubmit           => 60,
Line 5397  sub print_coursedefaults { Line 4846  sub print_coursedefaults {
                          );                           );
     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 5435  sub print_coursedefaults { Line 4884  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 5479  sub print_coursedefaults { Line 4928  sub print_coursedefaults {
                     if ($checked) {                      if ($checked) {
                         $show = 'block';                          $show = 'block';
                     }                      }
                     $additional = '<div id="cloneinstcode" style="display:'.$show.'" />'.                      $additional = '<div id="cloneinstcode" style="display:'.$show.';" />'.
                                   &mt('Institutional codes for new and cloned course have identical:').                                    &mt('Institutional codes for new and cloned course have identical:').
                                   '<br />';                                    '<br />';
                     foreach my $item (@code_order) {                      foreach my $item (@code_order) {
Line 5509  sub print_coursedefaults { Line 4958  sub print_coursedefaults {
         my ($currdefresponder,%defcredits,%curruploadquota,%deftimeout,%currmysql);          my ($currdefresponder,%defcredits,%curruploadquota,%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 @types = ('official','unofficial','community','textbook');  
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ($settings->{'ltiauth'}) {  
                 $ltiauth = 1;  
             }  
             $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'}})) {
Line 5591  sub print_coursedefaults { Line 5036  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">'.                        '<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="uploadquota_'.$type.'"'.                             '<input type="text" name="uploadquota_'.$type.'"'.
                            ' value="'.$curruploadquota{$type}.'" size="5" /></td>';                             ' value="'.$curruploadquota{$type}.'" size="5" /></td>';
         }          }
Line 5609  sub print_coursedefaults { Line 5054  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 5633  sub print_coursedefaults { Line 5078  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 5651  sub print_coursedefaults { Line 5096  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;  
         $itemcount ++;  
     }      }
     $$rowtotal += $itemcount;      $$rowtotal += $itemcount;
     return $datatable;      return $datatable;
Line 5679  sub print_selfenrollment { Line 5115  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 5863  sub print_validation_rows { Line 5299  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 5885  sub print_validation_rows { Line 5321  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 5900  sub print_validation_rows { Line 5336  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>';  
             }  
         }  
         if (ref($postlink{'default'}) eq 'ARRAY') {  
             map { $postlinked{$_} = 1; } (@{$postlink{'default'}});  
         }  
         $datatable .= '<fieldset style="display: inline-block;">'.  
                       '<legend>'.$othertitle.'</legend>';  
         foreach my $field ('email','username') {  
             my $checked;  
             if ($postlinked{$field}) {  
                 $checked = ' checked="checked"';  
             }  
             $datatable .= '<span class="LC_nobreak"><label>'.  
                           '<input type="checkbox" name="passwords_postlink_default" value="'.  
                           $field.'"'.$checked.' />'.$field.'</label>'.  
                           '<span>&nbsp;&nbsp; ';  
         }  
         $datatable .= '</fieldset></td></tr>';  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'emailsrc'}.'</td>'.  
                       '<td class="LC_left_item">';  
         foreach my $type ('permanent','critical','notify') {  
             my $checkedemail;  
             if ($emailsrc{$type}) {  
                 $checkedemail = ' checked="checked"';  
             }  
             $datatable .= '<span class="LC_nobreak"><label>'.  
                           '<input type="checkbox" name="passwords_emailsrc" value="'.  
                           $type.'"'.$checkedemail.' />'.$titles{$type}.'</label>'.  
                           '<span>&nbsp;&nbsp; ';  
         }  
         $datatable .= '</td></tr>';  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         my $switchserver = &check_switchserver($dom,$confname);  
         my ($showstd,$noshowstd);  
         if ($nostdtext) {  
             $noshowstd = ' checked="checked"';  
         } else {  
             $showstd = ' checked="checked"';  
         }  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'customtext'}.'</td>'.  
                       '<td class="LC_left_item"><span class="LC_nobreak">'.  
                       &mt('Retain standard text:').  
                       '<label><input type="radio" name="passwords_stdtext" value="1"'.$showstd.' />'.  
                       &mt('Yes').'</label>'.'&nbsp;'.  
                       '<label><input type="radio" name="passwords_stdtext" value="0"'.$noshowstd.' />'.  
                       &mt('No').'</label></span><br />'.  
                       '<span class="LC_fontsize_small">'.  
                       &mt('(If you use the same account ...  reset a password from this page.)').'</span><br /><br />'.  
                       &mt('Include custom text:');  
         if ($customurl) {  
             my $link =  &Apache::loncommon::modal_link($customurl,&mt('custom text'),600,500,  
                                                        undef,undef,undef,undef,'background-color:#ffffff');  
             $datatable .= '<span class="LC_nobreak">&nbsp;'.$link.  
                           '<label><input type="checkbox" name="passwords_custom_del"'.  
                           ' value="1" />'.&mt('Delete?').'</label></span>'.  
                           ' <span class="LC_nobreak">&nbsp;'.&mt('Replace:').'</span>';  
         }  
         if ($switchserver) {  
             $datatable .= '<span class="LC_nobreak">&nbsp;'.&mt('Upload to library server: [_1]',$switchserver).'</span>';  
         } else {  
             $datatable .='<span class="LC_nobreak">&nbsp;'.  
                          '<input type="file" name="passwords_customfile" /></span>';  
         }  
         $datatable .= '</td></tr>';  
     } elsif ($position eq 'middle') {  
         my %domconf = &Apache::lonnet::get_dom('configuration',['defaults'],$dom);  
         my @items = ('intauth_cost','intauth_check','intauth_switch');  
         my %defaults;  
         if (ref($domconf{'defaults'}) eq 'HASH') {  
             %defaults = %{$domconf{'defaults'}};  
             if ($defaults{'intauth_cost'} !~ /^\d+$/) {  
                 $defaults{'intauth_cost'} = 10;  
             }  
             if ($defaults{'intauth_check'} !~ /^(0|1|2)$/) {  
                 $defaults{'intauth_check'} = 0;  
             }  
             if ($defaults{'intauth_switch'} !~ /^(0|1|2)$/) {  
                 $defaults{'intauth_switch'} = 0;  
             }              }
               $datatable .= &spares_row($dom,\%servers,\%spareid,\%serverhomes,\%altids,$curroffloadnow,$rowtotal);
         } else {          } else {
             %defaults = (              $datatable .= '<tr'.$css_class.'><td colspan="2">'.
                           'intauth_cost'   => 10,                            &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.').
                           'intauth_check'  => 0,                            '</td></tr>';
                           '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>';          ($datatable,$itemcount) = &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
     }      }
       $$rowtotal += $itemcount;
     return $datatable;      return $datatable;
 }  }
   
 sub password_rules {  sub rules_by_location {
     my ($prefix,$itemcountref,$settings) = @_;      my ($settings,$prefix,$by_location,$by_ip,$types,$titles) = @_; 
     my ($min,$max,%chars,$numsaved,$numinrow);      my ($datatable,$itemcount,$css_class);
     my %titles;      if (keys(%{$by_location}) == 0) {
     if ($prefix eq 'passwords') {          $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
         %titles = &Apache::lonlocal::texthash (          $datatable = '<tr'.$css_class.'><td colspan="2">'.
             min            => 'Minimum password length',                       &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.').
             max            => 'Maximum password length',                       '</td></tr>';
             chars          => 'Required characters',          $itemcount = 1;
         );      } else {
     } elsif ($prefix eq 'secrets') {          $itemcount = 0;
         %titles = &Apache::lonlocal::texthash (          my $numinrow = 5;
             min            => 'Minimum secret length',          my (%current,%checkedon,%checkedoff);
             max            => 'Maximum secret length',          my @locations = sort(keys(%{$by_location}));
             chars          => 'Required characters',          foreach my $type (@{$types}) {
         );              $checkedon{$type} = '';
     }              $checkedoff{$type} = ' checked="checked"';
     $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>'.          if (ref($settings) eq 'HASH') {
                       '<input type="checkbox" name="'.$prefix.'_chars" value="'.$possrules[$i].'"'.$checked.' />'.              if (ref($settings->{$prefix}) eq 'HASH') {
                       $rulenames{$possrules[$i]}.'</label></span></td>';                  foreach my $key (keys(%{$settings->{$prefix}})) {
     }                      $current{$key} = $settings->{$prefix}{$key};
     my $rem = @possrules%($numinrow);                      if ($key eq 'version') {
     my $colsleft = $numinrow - $rem;                          if ($current{$key} ne '') {
     if ($colsleft > 1 ) {                              $checkedon{$key} = ' checked="checked"';
         $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.                              $checkedoff{$key} = '';
                       '&nbsp;</td>';  
     } elsif ($colsleft == 1) {  
         $datatable .= '<td class="LC_left_item">&nbsp;</td>';  
     }  
     $datatable .='</table></td></tr>';  
     $itemcount ++;  
     if ($prefix eq 'passwords') {  
         $titles{'numsaved'} = &mt('Number of previous passwords to save and disallow reuse');  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'numsaved'}.'</td>'.  
                       '<td class="LC_left_item"><span class="LC_nobreak">'.  
                       '<input type="text" name="'.$prefix.'_numsaved" value="'.$numsaved.'" size="3" '.  
                       'onblur="javascript:warnInt'.$prefix.'(this);" />'.  
                       '<span class="LC_fontsize_small"> '.&mt('(Leave blank to not save previous passwords)').'</span>'.  
                       '</span></td></tr>';  
         $itemcount ++;  
     }  
     if (ref($itemcountref)) {  
         $$itemcountref += $itemcount;  
     }  
     return $datatable;  
 }  
   
 sub print_wafproxy {  
     my ($position,$dom,$settings,$rowtotal) = @_;  
     my $css_class;  
     my $itemcount = 0;  
     my $datatable;  
     my %servers = &Apache::lonnet::internet_dom_servers($dom);  
     my (%othercontrol,%otherdoms,%aliases,%saml,%values,$setdom,$showdom);  
     my %lt = &wafproxy_titles();  
     foreach my $server (sort(keys(%servers))) {  
         my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});  
         next if ($serverhome eq '');  
         my $serverdom;  
         if ($serverhome ne $server) {  
             $serverdom = &Apache::lonnet::host_domain($serverhome);  
             if (($serverdom ne '') && (&Apache::lonnet::domain($serverdom) ne '')) {  
                 $othercontrol{$server} = $serverdom;  
             }  
         } else {  
             $serverdom = &Apache::lonnet::host_domain($server);  
             next if (($serverdom eq '') || (&Apache::lonnet::domain($serverdom) eq ''));  
             if ($serverdom ne $dom) {  
                 $othercontrol{$server} = $serverdom;  
             } else {  
                 $setdom = 1;  
                 if (ref($settings) eq 'HASH') {  
                     if (ref($settings->{'alias'}) eq 'HASH') {  
                         $aliases{$dom} = $settings->{'alias'};  
                         if ($aliases{$dom} ne '') {  
                             $showdom = 1;  
                         }                          }
                     }                      } elsif (ref($current{$key}) eq 'ARRAY') {
                     if (ref($settings->{'saml'}) eq 'HASH') {                          $checkedon{$key} = ' checked="checked"';
                         $saml{$dom} = $settings->{'saml'};                          $checkedoff{$key} = '';
                     }                      }
                 }                  }
             }              }
         }          }
     }          foreach my $type (@{$types}) {
     if ($setdom) {              next if ($type ne 'version' && !@locations);
         %{$values{$dom}} = ();  
         if (ref($settings) eq 'HASH') {  
             foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') {  
                 $values{$dom}{$item} = $settings->{$item};  
             }  
         }  
     }  
     if (keys(%othercontrol)) {  
         %otherdoms = reverse(%othercontrol);  
         foreach my $domain (keys(%otherdoms)) {  
             %{$values{$domain}} = ();  
             my %config = &Apache::lonnet::get_dom('configuration',['wafproxy'],$domain);  
             if (ref($config{'wafproxy'}) eq 'HASH') {  
                 $aliases{$domain} = $config{'wafproxy'}{'alias'};  
                 if (exists($config{'wafproxy'}{'saml'})) {  
                     $saml{$domain} = $config{'wafproxy'}{'saml'};  
                 }  
                 foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') {  
                     $values{$domain}{$item} = $config{'wafproxy'}{$item};  
                 }  
             }  
         }  
     }  
     if ($position eq 'top') {  
         my %servers = &Apache::lonnet::internet_dom_servers($dom);  
         my %aliasinfo;  
         foreach my $server (sort(keys(%servers))) {  
             $itemcount ++;  
             my $dom_in_effect;  
             my $aliasrows = '<tr>'.  
                             '<td class="LC_left_item" style="vertical-align: baseline;">'.  
                             &mt('Hostname').':&nbsp;'.  
                             '<i>'.&Apache::lonnet::hostname($server).'</i></td><td>&nbsp;</td>';  
             if ($othercontrol{$server}) {  
                 $dom_in_effect = $othercontrol{$server};  
                 my ($current,$forsaml);  
                 if (ref($aliases{$dom_in_effect}) eq 'HASH') {  
                     $current = $aliases{$dom_in_effect}{$server};  
                 }  
                 if (ref($saml{$dom_in_effect}) eq 'HASH') {  
                     if ($saml{$dom_in_effect}{$server}) {  
                         $forsaml = 1;  
                     }  
                 }  
                 $aliasrows .= '<td class="LC_left_item" style="vertical-align: baseline;">'.  
                               &mt('Alias').':&nbsp';  
                 if ($current) {  
                     $aliasrows .= $current;  
                     if ($forsaml) {  
                          $aliasrows .= '&nbsp;('.&mt('also for SSO Auth').')';  
                     }  
                 } else {  
                     $aliasrows .= &mt('None');  
                 }  
                 $aliasrows .= '&nbsp;<span class="LC_small">('.  
                               &mt('controlled by domain: [_1]',  
                                   '<b>'.$dom_in_effect.'</b>').')</span></td>';  
             } else {  
                 $dom_in_effect = $dom;  
                 my ($current,$samlon,$samloff);  
                 $samloff = ' checked="checked"';  
                 if (ref($aliases{$dom}) eq 'HASH') {  
                     if ($aliases{$dom}{$server}) {  
                         $current = $aliases{$dom}{$server};  
                     }  
                 }  
                 if (ref($saml{$dom}) eq 'HASH') {  
                     if ($saml{$dom}{$server}) {  
                         $samlon = $samloff;  
                         undef($samloff);  
                     }  
                 }  
                 $aliasrows .= '<td class="LC_left_item" style="vertical-align: baseline;">'.  
                               &mt('Alias').':&nbsp;'.  
                               '<input type="text" name="wafproxy_alias_'.$server.'" '.  
                               'value="'.$current.'" size="30" />'.  
                               ('&nbsp;'x2).'<span class="LC_nobreak">'.  
                               &mt('Alias used for SSO Auth').':&nbsp;<label>'.  
                               '<input type="radio" value="0"'.$samloff.' name="wafproxy_alias_saml_'.$server.'" />'.  
                               &mt('No').'</label>&nbsp;<label>'.  
                               '<input type="radio" value="1"'.$samlon.' name="wafproxy_alias_saml_'.$server.'" />'.  
                               &mt('Yes').'</label></span>'.  
                               '</td>';  
             }  
             $aliasrows .= '</tr>';  
             $aliasinfo{$dom_in_effect} .= $aliasrows;  
         }  
         if ($aliasinfo{$dom}) {  
             my ($onclick,$wafon,$wafoff,$showtable);  
             $onclick = ' onclick="javascript:toggleWAF();"';  
             $wafoff = ' checked="checked"';  
             $showtable = ' style="display:none";';  
             if ($showdom) {  
                 $wafon = $wafoff;  
                 $wafoff = '';  
                 $showtable = ' style="display:inline;"';  
             }  
             $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
             $datatable = '<tr'.$css_class.'>'.  
                          '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'<br />'.  
                          '<span class="LC_nobreak">'.&mt('WAF in use?').'&nbsp;<label>'.  
                          '<input type="radio" name="wafproxy_'.$dom.'" value="1"'.$wafon.$onclick.' />'.  
                          &mt('Yes').'</label>'.('&nbsp;'x2).'<label>'.  
                          '<input type="radio" name="wafproxy_'.$dom.'" value="0"'.$wafoff.$onclick.' />'.  
                          &mt('No').'</label></span></td>'.  
                          '<td class="LC_left_item">'.  
                          '<table id="wafproxy_table"'.$showtable.'>'.$aliasinfo{$dom}.  
                          '</table></td></tr>';  
             $itemcount++;  
         }  
         if (keys(%otherdoms)) {  
             foreach my $key (sort(keys(%otherdoms))) {  
                 $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
                 $datatable .= '<tr'.$css_class.'>'.  
                               '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$key.'</b>').'</td>'.  
                               '<td class="LC_left_item"><table>'.$aliasinfo{$key}.  
                               '</table></td></tr>';  
                 $itemcount++;  
             }  
         }  
     } else {  
         my %ip_methods = &remoteip_methods();  
         if ($setdom) {  
             $itemcount ++;  
             $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';              $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.');  
         }          }
           $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);
         } else {          my @alldoms = &Apache::lonnet::all_domains();
             my %lt = &usersession_titles();          my %serverhomes = %Apache::lonnet::serverhomeIDs;
             my $numinrow = 5;          my @domservers = &Apache::lonnet::get_servers($dom);
             my $prefix;          my %servers = &Apache::lonnet::internet_dom_servers($dom);
             my @types;          my %altids = &id_for_thisdom(%servers);
             if ($position eq 'bottom') {          if (($position eq 'connto') || ($position eq 'connfrom')) {
                 $prefix = 'remote';              my $legacy;
                 @types = ('version','excludedomain','includedomain');              unless (ref($settings) eq 'HASH') {
             } else {                  my $name;
                 $prefix = 'hosted';                  if ($position eq 'connto') {
                 @types = ('excludedomain','includedomain');                      $name = 'loncAllowInsecure';
             }                  } else {
             my (%current,%checkedon,%checkedoff);                      $name = 'londAllowInsecure';
             my @lcversions = &Apache::lonnet::all_loncaparevs();                  }
             my @locations = sort(keys(%by_location));                  my $primarylibserv = &Apache::lonnet::domain($dom,'primary');
             foreach my $type (@types) {                  my @ids=&Apache::lonnet::current_machine_ids();
                 $checkedon{$type} = '';                  if (($primarylibserv ne '') && (!grep(/^\Q$primarylibserv\E$/,@ids))) {
                 $checkedoff{$type} = ' checked="checked"';                      my %what = (
             }                                     $name => 1,
             if (ref($settings) eq 'HASH') {                                 );
                 if (ref($settings->{$prefix}) eq 'HASH') {                      my ($result,$returnhash) =
                     foreach my $key (keys(%{$settings->{$prefix}})) {                          &Apache::lonnet::get_remote_globals($primarylibserv,\%what);
                         $current{$key} = $settings->{$prefix}{$key};                      if ($result eq 'ok') {
                         if ($key eq 'version') {                          if (ref($returnhash) eq 'HASH') {
                             if ($current{$key} ne '') {                              $legacy = $returnhash->{$name};
                                 $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 6810  sub print_usersessions { Line 5615  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 6830  sub build_location_hashes { Line 5685  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 6938  sub current_offloads_to { Line 5799  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 6959  sub spares_row { Line 5819  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 6978  sub spares_row { Line 5833  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";  
             if ($other_insts) {  
                 $datatable .= '<br />'.  
                               '<span class="LC_nobreak">'."\n".  
                           '<label><input type="checkbox" name="offloadoth" value="'.$server.'"'.$checkedoth.' />'.  
                           '&nbsp;'.&mt('Switch other institutions on next access').'</label></span>'.  
                           "\n";                            "\n";
             }  
             my (%current,%canselect);              my (%current,%canselect);
             my @choices =               my @choices = 
                 &possible_newspares($server,$spareid->{$server},$serverhomes,$altids);                  &possible_newspares($server,$spareid->{$server},$serverhomes,$altids);
Line 7110  sub print_loadbalancing { Line 5958  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 7150  sub print_loadbalancing { Line 5998  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 7183  sub print_loadbalancing { Line 6031  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 7193  sub print_loadbalancing { Line 6041  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 7251  sub print_loadbalancing { Line 6096  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 7264  sub print_loadbalancing { Line 6104  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 7283  sub print_loadbalancing { Line 6118  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 7306  sub get_loadbalancers_config { Line 6140  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 7412  sub loadbalance_rule_row { Line 6243  sub loadbalance_rule_row {
     }      }
     my $space;      my $space;
     if ($islast && $num == 1) {      if ($islast && $num == 1) {
         $space = '<div 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 7504  sub contact_titles { Line 6335  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 7555  sub tool_titles { Line 6381  sub tool_titles {
                      unofficial => 'Unofficial courses',                       unofficial => 'Unofficial courses',
                      community  => 'Communities',                       community  => 'Communities',
                      textbook   => 'Textbook courses',                       textbook   => 'Textbook courses',
                        placement  => 'Placement tests',
                  );                   );
     return %titles;      return %titles;
 }  }
Line 7565  sub courserequest_titles { Line 6392  sub courserequest_titles {
                                    unofficial => 'Unofficial',                                     unofficial => 'Unofficial',
                                    community  => 'Communities',                                     community  => 'Communities',
                                    textbook   => 'Textbook',                                     textbook   => 'Textbook',
                                      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 7655  sub print_usercreation { Line 6483  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 7777  sub print_selfcreation { Line 6605  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 7795  sub print_selfcreation { Line 6623  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 7914  sub print_selfcreation { Line 6742  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 7941  sub print_selfcreation { Line 6769  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 8044  function toggleEmailOptions(form,radio,p Line 6872  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 8067  ENDSCRIPT Line 6895  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 8085  sub noninst_users { Line 6913  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 8098  sub noninst_users { Line 6926  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 8213  sub noninst_users { Line 7041  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 8240  sub noninst_users { Line 7068  sub noninst_users {
 sub captcha_choice {  sub captcha_choice {
     my ($context,$settings,$itemcount,$customcss,$rowstyle) = @_;      my ($context,$settings,$itemcount,$customcss,$rowstyle) = @_;
     my ($keyentry,$currpub,$currpriv,%checked,$rowname,$pubtext,$privtext,      my ($keyentry,$currpub,$currpriv,%checked,$rowname,$pubtext,$privtext,
         $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 8290  sub captcha_choice { Line 7114  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 8329  sub user_formats_row { Line 7153  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 8384  sub user_formats_row { Line 7208  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 8528  sub print_defaults { Line 7352  sub print_defaults {
             $rownum ++;              $rownum ++;
         }          }
     } elsif ($position eq 'middle') {      } elsif ($position eq 'middle') {
           my @items = ('intauth_cost','intauth_check','intauth_switch');
           my %defaults;
           if (ref($settings) eq 'HASH') {
               %defaults = %{$settings};
               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 ($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 {
                   $datatable .= '<input type="text" name="'.$item.'" value="'.
                                 $defaults{$item}.'" size="3" onblur="javascript:warnIntAuth(this);" />'; 
               }
               $datatable .= '</td></tr>';
               $rownum ++;
           }
       } 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 8551  sub print_defaults { Line 7454  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 8570  sub print_defaults { Line 7473  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 8635  sub defaults_titles { Line 7522  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 8713  sub print_scantronformat { Line 7548  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 8723  sub print_scantronformat { Line 7558  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 8734  sub print_scantronformat { Line 7569  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 8803  sub print_scantronformat { Line 7638  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 8860  sub legacy_scantronformat { Line 7695  sub legacy_scantronformat {
     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 9025  sub print_coursecategories { Line 7737  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 9038  sub print_coursecategories { Line 7750  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 9056  sub print_coursecategories { Line 7772  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 9096  sub print_coursecategories { Line 7823  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 9122  sub print_coursecategories { Line 7863  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 9148  sub print_coursecategories { Line 7892  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 9171  sub print_coursecategories { Line 7915  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 9203  sub print_coursecategories { Line 7947  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 9236  sub print_coursecategories { Line 7980  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 9284  sub print_serverstatuses { Line 8028  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 9292  sub print_serverstatuses { Line 8036  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 $intauthcost = &mt('Warning: bcrypt encryption cost for internal authentication must be an integer.');
       &js_escape(\$intauthcheck);
       &js_escape(\$intauthcost);
       my $intauthjs = <<"ENDSCRIPT";
   
   function warnIntAuth(field) {
       if (field.name == 'intauth_check') {
           if (field.value == '2') {
               alert('$intauthcheck');
           }
       }
       if (field.name == 'intauth_cost') {
           field.value.replace(/\s/g,'');
           if (field.value != '') {
               var regexdigit=/^\\d+\$/;
               if (!regexdigit.test(field.value)) {
                   alert('$intauthcost');
               }
           }
       }
       return;
   }
   
   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 9353  $jstext Line 8125  $jstext
     return;      return;
 }  }
   
   $intauthjs
   
 // ]]>  // ]]>
 </script>  </script>
   
 ENDSCRIPT  ENDSCRIPT
     }  
 }  
   
 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 'secrets') {  
         %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 9473  sub coursecategories_javascript { Line 8160  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 9545  function categoryCheck(form) { Line 8234  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 9558  ENDSCRIPT Line 8251  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 9591  sub initialize_categories { Line 8285  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 9648  sub build_category_rows { Line 8341  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 9671  sub build_category_rows { Line 8364  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 9739  sub modifiable_userdata_row { Line 8432  sub modifiable_userdata_row {
     if ($rowid) {      if ($rowid) {
         $rowid = ' id="'.$rowid.'"';          $rowid = ' id="'.$rowid.'"';
     }      }
   
     $output = '<tr '.$css_class.$rowid.'>'.      $output = '<tr '.$css_class.$rowid.'>'.
               '<td><span class="LC_nobreak">'.$rolename.'</span></td>'.                '<td><span class="LC_nobreak">'.$rolename.'</span></td>'.
               '<td class="LC_left_item" colspan="2"><table>';                '<td class="LC_left_item" colspan="2"><table>';
Line 9774  sub modifiable_userdata_row { Line 8466  sub modifiable_userdata_row {
             }              }
         }          }
     }      }
    
     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 9787  sub modifiable_userdata_row { Line 8479  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]}
             } else {              } else {
                 if ($role eq 'st') {                  if ($role eq 'st') {
                     if (ref($settings) ne 'HASH') {                      if (ref($settings) ne 'HASH') {
Line 9901  sub insttypes_row { Line 8593  sub insttypes_row {
                 $output .= '<td class="LC_left_item">'.                  $output .= '<td class="LC_left_item">'.
                            '<span class="LC_nobreak"><label>'.                             '<span class="LC_nobreak"><label>'.
                            '<input type="checkbox" name="'.$context.'" '.                             '<input type="checkbox" name="'.$context.'" '.
                            'value="'.$types->[$i].'"'.$check.$onclick.'/>'.                             'value="'.$types->[$i].'"'.$check.$onclick.' />'.
                            $usertypes->{$types->[$i]}.'</label></span></td>';                             $usertypes->{$types->[$i]}.'</label></span></td>';
             }              }
         }          }
Line 9914  sub insttypes_row { Line 8606  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 10016  sub usertype_update_row { Line 8708  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 10031  sub modify_login { Line 8721  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 10292  sub modify_login { Line 8967  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') {  
                 foreach my $lonhost (@newsamlimgs) {  
                     my $formelem = 'saml_img_'.$lonhost;  
                     my ($result,$imgurl) = &publishlogo($r,'upload',$formelem,$dom,$confname,  
                                                         "login/saml/$lonhost",'','',  
                                                         $env{'form.saml_img_'.$lonhost.'.filename'});  
                     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>';  
                     }  
                 }  
             } 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 10421  sub modify_login { Line 9007  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 10525  sub modify_login { Line 9086  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 10662  sub color_font_choices { Line 9188  sub color_font_choices {
     return %choices;      return %choices;
 }  }
   
 sub modify_ipaccess {  
     my ($dom,$lastactref,%domconfig) = @_;  
     my (@allpos,%changes,%confhash,$errors,$resulttext);  
     my (@items,%deletions,%itemids,@warnings);  
     my ($typeorder,$types) = &commblocktype_text();  
     if ($env{'form.ipaccess_add'}) {  
         my $name = $env{'form.ipaccess_name_add'};  
         my ($newid,$error) = &get_ipaccess_id($dom,$name);  
         if ($newid) {  
             $itemids{'add'} = $newid;  
             push(@items,'add');  
             $changes{$newid} = 1;  
         } else {  
             $error = &mt('Failed to acquire unique ID for new IP access control item');  
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';  
         }  
     }  
     if (ref($domconfig{'ipaccess'}) eq 'HASH') {  
         my @todelete = &Apache::loncommon::get_env_multiple('form.ipaccess_del');  
         if (@todelete) {  
             map { $deletions{$_} = 1; } @todelete;  
         }  
         my $maxnum = $env{'form.ipaccess_maxnum'};  
         for (my $i=0; $i<$maxnum; $i++) {  
             my $itemid = $env{'form.ipaccess_id_'.$i};  
             $itemid =~ s/\D+//g;  
             if (ref($domconfig{'ipaccess'}{$itemid}) eq 'HASH') {  
                 if ($deletions{$itemid}) {  
                     $changes{$itemid} = $domconfig{'ipaccess'}{$itemid}{'name'};  
                 } else {  
                     push(@items,$i);  
                     $itemids{$i} = $itemid;  
                 }  
             }  
         }  
     }  
     foreach my $idx (@items) {  
         my $itemid = $itemids{$idx};  
         next unless ($itemid);  
         my %current;  
         unless ($idx eq 'add') {  
             if (ref($domconfig{'ipaccess'}{$itemid}) eq 'HASH') {  
                 %current = %{$domconfig{'ipaccess'}{$itemid}};  
             }  
         }  
         my $position = $env{'form.ipaccess_pos_'.$itemid};  
         $position =~ s/\D+//g;  
         if ($position ne '') {  
             $allpos[$position] = $itemid;  
         }  
         my $name = $env{'form.ipaccess_name_'.$idx};  
         $name =~ s/^\s+|\s+$//g;  
         $confhash{$itemid}{'name'} = $name;  
         my $possrange = $env{'form.ipaccess_range_'.$idx};  
         $possrange =~ s/^\s+|\s+$//g;  
         unless ($possrange eq '') {  
             $possrange =~ s/[\r\n]+/\s/g;  
             $possrange =~ s/\s*-\s*/-/g;  
             $possrange =~ s/\s+/,/g;  
             $possrange =~ s/,+/,/g;  
             if ($possrange ne '') {  
                 my (@ok,$count);  
                 $count = 0;  
                 foreach my $poss (split(/\,/,$possrange)) {  
                     $count ++;  
                     $poss = &validate_ip_pattern($poss);  
                     if ($poss ne '') {  
                         push(@ok,$poss);  
                     }  
                 }  
                 my $diff = $count - scalar(@ok);  
                 if ($diff) {  
                     $errors .= '<li><span class="LC_error">'.  
                                &mt('[quant,_1,IP] invalid and excluded from saved value for IP range(s) for [_2]',  
                                    $diff,$name).  
                                '</span></li>';  
                 }  
                 if (@ok) {  
                     my @cidr_list;  
                     foreach my $item (@ok) {  
                         @cidr_list = &Net::CIDR::cidradd($item,@cidr_list);  
                     }  
                     $confhash{$itemid}{'ip'} = join(',',@cidr_list);  
                 }  
             }  
         }  
         foreach my $field ('name','ip') {  
             unless (($idx eq 'add') || ($changes{$itemid})) {  
                 if ($current{$field} ne $confhash{$itemid}{$field}) {  
                     $changes{$itemid} = 1;  
                     last;  
                 }  
             }  
         }  
         $confhash{$itemid}{'commblocks'} = {};  
   
         my %commblocks;  
         map { $commblocks{$_} = 1; } &Apache::loncommon::get_env_multiple('form.ipaccess_block_'.$idx);  
         foreach my $type (@{$typeorder}) {  
             if ($commblocks{$type}) {  
                 $confhash{$itemid}{'commblocks'}{$type} = 'on';  
             }  
             unless (($idx eq 'add') || ($changes{$itemid})) {  
                 if (ref($current{'commblocks'}) eq 'HASH') {  
                     if ($confhash{$itemid}{'commblocks'}{$type} ne $current{'commblocks'}{$type}) {  
                         $changes{$itemid} = 1;  
                     }  
                 } elsif ($confhash{$itemid}{'commblocks'}{$type}) {  
                     $changes{$itemid} = 1;  
                 }  
             }  
         }  
         $confhash{$itemid}{'courses'} = {};  
         my %crsdeletions;  
         my @delcrs = &Apache::loncommon::get_env_multiple('form.ipaccess_course_delete_'.$idx);  
         if (@delcrs) {  
             map { $crsdeletions{$_} = 1; } @delcrs;  
         }  
         if (ref($current{'courses'}) eq 'HASH') {  
             foreach my $cid (sort(keys(%{$current{'courses'}}))) {  
                 if ($crsdeletions{$cid}) {  
                     $changes{$itemid} = 1;  
                 } else {  
                     $confhash{$itemid}{'courses'}{$cid} = 1;  
                 }  
             }  
         }  
         $env{'form.ipaccess_cnum_'.$idx} =~ s/^\s+|\s+$//g;  
         $env{'form.ipaccess_cdom_'.$idx} =~ s/^\s+|\s+$//g;  
         if (($env{'form.ipaccess_cnum_'.$idx} =~ /^$match_courseid$/) &&  
             ($env{'form.ipaccess_cdom_'.$idx} =~ /^$match_domain$/)) {  
             if (&Apache::lonnet::homeserver($env{'form.ipaccess_cnum_'.$idx},  
                                             $env{'form.ipaccess_cdom_'.$idx}) eq 'no_host') {  
                 $errors .= '<li><span class="LC_error">'.  
                            &mt('Invalid courseID [_1] omitted from list of allowed courses',  
                                $env{'form.ipaccess_cdom_'.$idx}.'_'.$env{'form.ipaccess_cnum_'.$idx}).  
                            '</span></li>';  
             } else {  
                 $confhash{$itemid}{'courses'}{$env{'form.ipaccess_cdom_'.$idx}.'_'.$env{'form.ipaccess_cnum_'.$idx}} = 1;  
                 $changes{$itemid} = 1;  
             }  
         }  
     }  
     if (@allpos > 0) {  
         my $idx = 0;  
         foreach my $itemid (@allpos) {  
             if ($itemid ne '') {  
                 $confhash{$itemid}{'order'} = $idx;  
                 unless ($changes{$itemid}) {  
                     if (ref($domconfig{'ipaccess'}) eq 'HASH') {  
                         if (ref($domconfig{'ipaccess'}{$itemid}) eq 'HASH') {  
                             if ($domconfig{'ipaccess'}{$itemid}{'order'} ne $idx) {  
                                 $changes{$itemid} = 1;  
                             }  
                         }  
                     }  
                 }  
                 $idx ++;  
             }  
         }  
     }  
     if (keys(%changes)) {  
         my %defaultshash = (  
                               ipaccess => \%confhash,  
                            );  
         my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,  
                                                  $dom);  
         if ($putresult eq 'ok') {  
             my $cachetime = 1800;  
             &Apache::lonnet::do_cache_new('ipaccess',$dom,\%confhash,$cachetime);  
             if (ref($lastactref) eq 'HASH') {  
                 $lastactref->{'ipaccess'} = 1;  
             }  
             $resulttext = &mt('Changes made:').'<ul>';  
             my %bynum;  
             foreach my $itemid (sort(keys(%changes))) {  
                 if (ref($confhash{$itemid}) eq 'HASH') {  
                     my $position = $confhash{$itemid}{'order'};  
                     if ($position =~ /^\d+$/) {  
                         $bynum{$position} = $itemid;  
                     }  
                 }  
             }  
             if (keys(%deletions)) {  
                 foreach my $itemid (sort { $a <=> $b } keys(%deletions)) {  
                     $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';  
                 }  
             }  
             foreach my $pos (sort { $a <=> $b } keys(%bynum)) {  
                 my $itemid = $bynum{$pos};  
                 if (ref($confhash{$itemid}) eq 'HASH') {  
                     $resulttext .= '<li><b>'.$confhash{$itemid}{'name'}.'</b><ul>';  
                     my $position = $pos + 1;  
                     $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';  
                     if ($confhash{$itemid}{'ip'} eq '') {  
                         $resulttext .= '<li>'.&mt('No IP Range(s) set').'</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('IP Range(s): [_1]',$confhash{$itemid}{'ip'}).'</li>';  
                     }  
                     if (keys(%{$confhash{$itemid}{'commblocks'}})) {  
                         $resulttext .= '<li>'.&mt('Functionality Blocked: [_1]',  
                                                   join(', ', map { $types->{$_}; } sort(keys(%{$confhash{$itemid}{'commblocks'}})))).  
                                        '</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('No functionality blocked').'</li>';  
                     }  
                     if (keys(%{$confhash{$itemid}{'courses'}})) {  
                         my @courses;  
                         foreach my $cid (sort(keys(%{$confhash{$itemid}{'courses'}}))) {  
                             my %courseinfo = &Apache::lonnet::coursedescription($cid,{'one_time' => 1});  
                             push(@courses,$courseinfo{'description'}.' ('.$cid.')');  
                         }  
                         $resulttext .= '<li>'.&mt('Courses/Communities allowed').':<ul><li>'.  
                                              join('</li><li>',@courses).'</li></ul>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('No courses allowed').'</li>';  
                     }  
                     $resulttext .= '</ul></li>';  
                 }  
             }  
             $resulttext .= '</ul>';  
         } else {  
             $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';  
         }  
     } else {  
         $resulttext = &mt('No changes made');  
     }  
     if ($errors) {  
         $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.  
                        $errors.'</ul></p>';  
     }  
     return $resulttext;  
 }  
   
 sub get_ipaccess_id {  
     my ($domain,$location) = @_;  
     # get lock on ipaccess db  
     my $lockhash = {  
                       lock => $env{'user.name'}.  
                               ':'.$env{'user.domain'},  
                    };  
     my $tries = 0;  
     my $gotlock = &Apache::lonnet::newput_dom('ipaccess',$lockhash,$domain);  
     my ($id,$error);  
   
     while (($gotlock ne 'ok') && ($tries<10)) {  
         $tries ++;  
         sleep (0.1);  
         $gotlock = &Apache::lonnet::newput_dom('ipaccess',$lockhash,$domain);  
     }  
     if ($gotlock eq 'ok') {  
         my %currids = &Apache::lonnet::dump_dom('ipaccess',$domain);  
         if ($currids{'lock'}) {  
             delete($currids{'lock'});  
             if (keys(%currids)) {  
                 my @curr = sort { $a <=> $b } keys(%currids);  
                 if ($curr[-1] =~ /^\d+$/) {  
                     $id = 1 + $curr[-1];  
                 }  
             } else {  
                 $id = 1;  
             }  
             if ($id) {  
                 unless (&Apache::lonnet::newput_dom('ipaccess',{ $id => $location },$domain) eq 'ok') {  
                     $error = 'nostore';  
                 }  
             } else {  
                 $error = 'nonumber';  
             }  
         }  
         my $dellockoutcome = &Apache::lonnet::del_dom('ipaccess',['lock'],$domain);  
     } else {  
         $error = 'nolock';  
     }  
     return ($id,$error);  
 }  
   
 sub modify_rolecolors {  sub modify_rolecolors {
     my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_;      my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_;
     my ($resulttext,%rolehash);      my ($resulttext,%rolehash);
Line 11046  sub modify_colors { Line 9295  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 11132  sub modify_colors { Line 9376  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 11265  sub default_change_checker { Line 9495  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 11308  sub display_colorchgs { Line 9533  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 11373  sub check_configuser { Line 9591  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 11402  sub check_authorstatus { Line 9620  sub check_authorstatus {
   
 sub publishlogo {  sub publishlogo {
     my ($r,$action,$formname,$dom,$confname,$subdir,$thumbwidth,$thumbheight,$savefileas) = @_;      my ($r,$action,$formname,$dom,$confname,$subdir,$thumbwidth,$thumbheight,$savefileas) = @_;
     my ($output,$fname,$logourl);      my ($output,$fname,$logourl,$madethumb);
     if ($action eq 'upload') {      if ($action eq 'upload') {
         $fname=$env{'form.'.$formname.'.filename'};          $fname=$env{'form.'.$formname.'.filename'};
         chop($env{'form.'.$formname});          chop($env{'form.'.$formname});
Line 11531  $env{'user.name'}.':'.$env{'user.domain' Line 9749  $env{'user.name'}.':'.$env{'user.domain'
                                     $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);                                      $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);
                                     $registered_cleanup=1;                                      $registered_cleanup=1;
                                 }                                  }
                                   $madethumb = 1;
                             } else {                              } else {
                                 print $logfile "\nUnable to write ".$copyfile.                                  print $logfile "\nUnable to write ".$copyfile.
                                                ':'.$!."\n";                                                 ':'.$!."\n";
Line 11543  $env{'user.name'}.':'.$env{'user.domain' Line 9762  $env{'user.name'}.':'.$env{'user.domain'
             $output = $versionresult;              $output = $versionresult;
         }          }
     }      }
     return ($output,$logourl);      return ($output,$logourl,$madethumb);
 }  }
   
 sub logo_versioning {  sub logo_versioning {
Line 11697  sub modify_quotas { Line 9916  sub modify_quotas {
         $context = $action;          $context = $action;
     }      }
     if ($context eq 'requestcourses') {      if ($context eq 'requestcourses') {
         @usertools = ('official','unofficial','community','textbook');          @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 11746  sub modify_quotas { Line 9965  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');          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 11868  sub modify_quotas { Line 10087  sub modify_quotas {
                                             &Apache::lonnet::logthis($error);                                              &Apache::lonnet::logthis($error);
                                             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';                                              $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
                                         }                                          }
                                     }                                       }
                                 } elsif ($domconfig{$action}{$type}{$key}{'image'}) {                                  } elsif ($domconfig{$action}{$type}{$key}{'image'}) {
                                     $confhash{$type}{$key}{'image'} =                                       $confhash{$type}{$key}{'image'} = 
                                         $domconfig{$action}{$type}{$key}{'image'};                                          $domconfig{$action}{$type}{$key}{'image'};
Line 12433  sub modify_ltitools { Line 10652  sub modify_ltitools {
     map { $posslti{$_} = 1; } @ltiroles;      map { $posslti{$_} = 1; } @ltiroles;
     my @allfields = ('fullname','firstname','lastname','email','user','roles');      my @allfields = ('fullname','firstname','lastname','email','user','roles');
     map { $possfield{$_} = 1; } @allfields;      map { $possfield{$_} = 1; } @allfields;
     my %lt = &ltitools_names();      my %lt = &ltitools_names(); 
     if ($env{'form.ltitools_add'}) {      if ($env{'form.ltitools_add'}) {
         my $title = $env{'form.ltitools_add_title'};          my $title = $env{'form.ltitools_add_title'};
         $title =~ s/(`)/'/g;          $title =~ s/(`)/'/g;
Line 12478  sub modify_ltitools { Line 10697  sub modify_ltitools {
                     }                      }
                 } else {                  } else {
                     if ($env{'form.ltitools_add_'.$item} ne '') {                      if ($env{'form.ltitools_add_'.$item} ne '') {
                         $confhash{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item};                          $confhash{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item}; 
                     }                      }
                 }                  }
             }              }
Line 12489  sub modify_ltitools { Line 10708  sub modify_ltitools {
             } else {              } else {
                 $confhash{$newid}{'display'}{'target'} = 'iframe';                  $confhash{$newid}{'display'}{'target'} = 'iframe';
             }              }
               foreach my $item ('passback','roster') {
                   if ($env{'form.ltitools_'.$item.'_add'}) {
                       $confhash{$newid}{$item} = 1;
                       if ($env{'form.ltitools_'.$item.'valid_add'} ne '') {
                           my $lifetime = $env{'form.ltitools_'.$item.'valid_add'};
                           $lifetime =~ s/^\s+|\s+$//g;
                           if ($lifetime =~ /^\d+\.?\d*$/) {
                               $confhash{$newid}{$item.'valid'} = $lifetime;
                           }
                       }
                   }
               }
             if ($env{'form.ltitools_add_image.filename'} ne '') {              if ($env{'form.ltitools_add_image.filename'} ne '') {
                 my ($imageurl,$error) =                  my ($imageurl,$error) =
                     &process_ltitools_image($r,$dom,$confname,'ltitools_add_image',$newid,                      &process_ltitools_image($r,$dom,$confname,'ltitools_add_image',$newid,
Line 12510  sub modify_ltitools { Line 10741  sub modify_ltitools {
                             if (($choice ne '') && ($posslti{$choice})) {                              if (($choice ne '') && ($posslti{$choice})) {
                                 $confhash{$newid}{'roles'}{$role} = $choice;                                  $confhash{$newid}{'roles'}{$role} = $choice;
                                 if ($role eq 'cc') {                                  if ($role eq 'cc') {
                                     $confhash{$newid}{'roles'}{'co'} = $choice;                                      $confhash{$newid}{'roles'}{'co'} = $choice; 
                                 }                                  }
                             }                              }
                         }                          }
Line 12519  sub modify_ltitools { Line 10750  sub modify_ltitools {
                     }                      }
                 }                  }
             }              }
             if (ref($confhash{$newid}{'fields'}) eq 'HASH') {  
                 if ($confhash{$newid}{'fields'}{'user'}) {  
                     if ($env{'form.ltitools_userincdom_add'}) {  
                         $confhash{$newid}{'incdom'} = 1;  
                     }  
                 }  
             }  
             my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig');              my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig');
             foreach my $item (@courseconfig) {              foreach my $item (@courseconfig) {
                 $confhash{$newid}{'crsconf'}{$item} = 1;                  $confhash{$newid}{'crsconf'}{$item} = 1;
Line 12538  sub modify_ltitools { Line 10762  sub modify_ltitools {
                 $confhash{$newid}{'custom'}{$name} = $value;                  $confhash{$newid}{'custom'}{$name} = $value;
             }              }
         } else {          } else {
             my $error = &mt('Failed to acquire unique ID for new external tool');              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>';
         }          }
     }      }
Line 12552  sub modify_ltitools { Line 10776  sub modify_ltitools {
         my @newcustom = &Apache::loncommon::get_env_multiple('form.ltitools_customadd');          my @newcustom = &Apache::loncommon::get_env_multiple('form.ltitools_customadd');
         if (@newcustom) {          if (@newcustom) {
             map { $customadds{$_} = 1; } @newcustom;              map { $customadds{$_} = 1; } @newcustom;
         }          } 
         my %imgdeletions;          my %imgdeletions;
         my @todeleteimages = &Apache::loncommon::get_env_multiple('form.ltitools_image_del');          my @todeleteimages = &Apache::loncommon::get_env_multiple('form.ltitools_image_del');
         if (@todeleteimages) {          if (@todeleteimages) {
Line 12593  sub modify_ltitools { Line 10817  sub modify_ltitools {
                     if ($env{'form.ltitools_sigmethod_'.$i} eq 'HMAC-SHA256') {                      if ($env{'form.ltitools_sigmethod_'.$i} eq 'HMAC-SHA256') {
                         $confhash{$itemid}{'sigmethod'} = $env{'form.ltitools_sigmethod_'.$i};                          $confhash{$itemid}{'sigmethod'} = $env{'form.ltitools_sigmethod_'.$i};
                     } else {                      } else {
                         $confhash{$itemid}{'sigmethod'} = 'HMAC-SHA1';                          $confhash{$itemid}{'sigmethod'} = 'HMAC-SHA1'; 
                     }                      }
                     if ($domconfig{$action}{$itemid}{'sigmethod'} eq '') {                      if ($domconfig{$action}{$itemid}{'sigmethod'} eq '') {
                         if ($confhash{$itemid}{'sigmethod'} ne 'HMAC-SHA1') {                          if ($confhash{$itemid}{'sigmethod'} ne 'HMAC-SHA1') {
Line 12652  sub modify_ltitools { Line 10876  sub modify_ltitools {
                     } else {                      } else {
                         $changes{$itemid} = 1;                          $changes{$itemid} = 1;
                     }                      }
                       foreach my $extra ('passback','roster') {
                           if ($env{'form.ltitools_'.$extra.'_'.$i}) {
                               $confhash{$itemid}{$extra} = 1;
                               if ($env{'form.ltitools_'.$extra.'valid_'.$i} ne '') {
                                   my $lifetime = $env{'form.ltitools_'.$extra.'valid_add'};
                                   $lifetime =~ s/^\s+|\s+$//g;
                                   if ($lifetime =~ /^\d+\.?\d*$/) {
                                       $confhash{$itemid}{$extra.'valid'} = $lifetime;
                                   }
                               }
                           }
                           if ($domconfig{$action}{$itemid}{$extra} ne $confhash{$itemid}{$extra}) {
                               $changes{$itemid} = 1;
                           }
                           if ($domconfig{$action}{$itemid}{$extra.'valid'} ne $confhash{$itemid}{$extra.'valid'}) {
                               $changes{$itemid} = 1;
                           }
                       }
                     my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig_'.$i);                      my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig_'.$i);
                     foreach my $item ('label','title','target','linktext','explanation','append') {                      foreach my $item ('label','title','target','linktext','explanation','append') {
                         if (grep(/^\Q$item\E$/,@courseconfig)) {                          if (grep(/^\Q$item\E$/,@courseconfig)) {
Line 12697  sub modify_ltitools { Line 10939  sub modify_ltitools {
                             }                              }
                         }                          }
                     }                      }
                     if (ref($confhash{$itemid}{'fields'}) eq 'HASH') {  
                         if ($confhash{$itemid}{'fields'}{'user'}) {  
                             if ($env{'form.ltitools_userincdom_'.$i}) {  
                                 $confhash{$itemid}{'incdom'} = 1;  
                             }  
                             if ($domconfig{$action}{$itemid}{'incdom'} ne $confhash{$itemid}{'incdom'}) {  
                                 $changes{$itemid} = 1;  
                             }  
                         }  
                     }  
                     $allpos[$newpos] = $itemid;                      $allpos[$newpos] = $itemid;
                 }                  }
                 if ($imgdeletions{$itemid}) {                  if ($imgdeletions{$itemid}) {
Line 12743  sub modify_ltitools { Line 10975  sub modify_ltitools {
                     }                      }
                 }                  }
                 my %customdels;                  my %customdels;
                 my @customdeletions = &Apache::loncommon::get_env_multiple('form.ltitools_customdel_'.$i);                  my @customdeletions = &Apache::loncommon::get_env_multiple('form.ltitools_customdel_'.$i); 
                 if (@customdeletions) {                  if (@customdeletions) {
                     $changes{$itemid} = 1;                      $changes{$itemid} = 1;
                 }                  }
Line 12752  sub modify_ltitools { Line 10984  sub modify_ltitools {
                     foreach my $key (keys(%{$domconfig{$action}{$itemid}{'custom'}})) {                      foreach my $key (keys(%{$domconfig{$action}{$itemid}{'custom'}})) {
                         unless ($customdels{$key}) {                          unless ($customdels{$key}) {
                             if ($env{'form.ltitools_customval_'.$key.'_'.$i} ne '') {                              if ($env{'form.ltitools_customval_'.$key.'_'.$i} ne '') {
                                 $confhash{$itemid}{'custom'}{$key} = $env{'form.ltitools_customval_'.$key.'_'.$i};                                  $confhash{$itemid}{'custom'}{$key} = $env{'form.ltitools_customval_'.$key.'_'.$i}; 
                             }                              }
                             if ($domconfig{$action}{$itemid}{'custom'}{$key} ne $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;
Line 12805  sub modify_ltitools { Line 11037  sub modify_ltitools {
         my %ltienchash = (          my %ltienchash = (
                              $action => { %encconfig }                               $action => { %encconfig }
                          );                           );
         &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1);          &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom);
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
             my $cachetime = 24*60*60;              my $cachetime = 24*60*60;
             my %ltiall = %confhash;              my %ltiall = %confhash;
Line 12827  sub modify_ltitools { Line 11059  sub modify_ltitools {
                 $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}) ne 'HASH') {                  if (ref($confhash{$itemid}) ne 'HASH') {
                     $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';                      $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';
                 } else {                  } else {
Line 12855  sub modify_ltitools { Line 11087  sub modify_ltitools {
                     }                      }
                     $resulttext .= '<li>'.&mt('Configurable in course:');                      $resulttext .= '<li>'.&mt('Configurable in course:');
                     my @possconfig = ('label','title','target','linktext','explanation','append');                      my @possconfig = ('label','title','target','linktext','explanation','append');
                     my $numconfig = 0;                      my $numconfig = 0; 
                     if (ref($confhash{$itemid}{'crsconf'}) eq 'HASH') {                      if (ref($confhash{$itemid}{'crsconf'}) eq 'HASH') { 
                         foreach my $item (@possconfig) {                          foreach my $item (@possconfig) {
                             if ($confhash{$itemid}{'crsconf'}{$item}) {                              if ($confhash{$itemid}{'crsconf'}{$item}) {
                                 $numconfig ++;                                  $numconfig ++;
Line 12868  sub modify_ltitools { Line 11100  sub modify_ltitools {
                         $resulttext .= &mt('None');                          $resulttext .= &mt('None');
                     }                      }
                     $resulttext .= '</li>';                      $resulttext .= '</li>';
                       foreach my $item ('passback','roster') {
                           $resulttext .= '<li>'.$lt{$item}.'&nbsp;';
                           if ($confhash{$itemid}{$item}) {
                               $resulttext .= &mt('Yes');
                               if ($confhash{$itemid}{$item.'valid'}) {
                                   if ($item eq 'passback') {
                                       $resulttext .= ' '.&mt('valid for at least [quant,_1,day] after launch',
                                                              $confhash{$itemid}{$item.'valid'});
                                   } else {
                                       $resulttext .= ' '.&mt('valid for at least [quant,_1,second] after launch',
                                                              $confhash{$itemid}{$item.'valid'});
                                   }
                               }
                           } else {
                               $resulttext .= &mt('No');
                           }
                           $resulttext .= '</li>';
                       }
                     if (ref($confhash{$itemid}{'display'}) eq 'HASH') {                      if (ref($confhash{$itemid}{'display'}) eq 'HASH') {
                         my $displaylist;                          my $displaylist;
                         if ($confhash{$itemid}{'display'}{'target'}) {                          if ($confhash{$itemid}{'display'}{'target'}) {
                             $displaylist = &mt('Display target').':&nbsp;'.                              $displaylist = &mt('Display target').':&nbsp;'.
                                            $confhash{$itemid}{'display'}{'target'}.',';                                             $confhash{$itemid}{'display'}{'target'}.',';
                         }                          }
                         foreach my $size ('width','height') {                          foreach my $size ('width','height') { 
                             if ($confhash{$itemid}{'display'}{$size}) {                              if ($confhash{$itemid}{'display'}{$size}) {
                                 $displaylist .= ('&nbsp;'x2).$lt{$size}.':&nbsp;'.                                  $displaylist .= ('&nbsp;'x2).$lt{$size}.':&nbsp;'.
                                                 $confhash{$itemid}{'display'}{$size}.',';                                                  $confhash{$itemid}{'display'}{$size}.',';
Line 12899  sub modify_ltitools { Line 11149  sub modify_ltitools {
                         }                          }
                         if ($fieldlist) {                          if ($fieldlist) {
                             $fieldlist =~ s/,$//;                              $fieldlist =~ s/,$//;
                             if ($confhash{$itemid}{'fields'}{'user'}) {  
                                 if ($confhash{$itemid}{'incdom'}) {  
                                     $fieldlist .= ' ('.&mt('username:domain').')';  
                                 } else {  
                                     $fieldlist .= ' ('.&mt('username').')';  
                                 }  
                             }  
                             $resulttext .= '<li>'.&mt('Data sent').':'.$fieldlist.'</li>';                              $resulttext .= '<li>'.&mt('Data sent').':'.$fieldlist.'</li>';
                         }                          }
                     }                      }
Line 12918  sub modify_ltitools { Line 11161  sub modify_ltitools {
                             }                              }
                         }                          }
                         if ($rolemaps) {                          if ($rolemaps) {
                             $rolemaps =~ s/,$//;                              $rolemaps =~ s/,$//; 
                             $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>';                              $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>';
                         }                          }
                     }                      }
Line 12927  sub modify_ltitools { Line 11170  sub modify_ltitools {
                         if (keys(%{$confhash{$itemid}{'custom'}})) {                          if (keys(%{$confhash{$itemid}{'custom'}})) {
                             foreach my $key (sort(keys(%{$confhash{$itemid}{'custom'}}))) {                              foreach my $key (sort(keys(%{$confhash{$itemid}{'custom'}}))) {
                                 $customlist .= $key.':'.$confhash{$itemid}{'custom'}{$key}.('&nbsp;'x2);                                  $customlist .= $key.':'.$confhash{$itemid}{'custom'}{$key}.('&nbsp;'x2);
                             }                              } 
                         }                          }
                         if ($customlist) {                          if ($customlist) {
                             $resulttext .= '<li>'.&mt('Custom items').': '.$customlist.'</li>';                              $resulttext .= '<li>'.&mt('Custom items').': '.$customlist.'</li>';
                         }                          }
                     }                      } 
                     $resulttext .= '</ul></li>';                      $resulttext .= '</ul></li>';
                 }                  }
             }              }
Line 12993  sub get_ltitools_id { Line 11236  sub get_ltitools_id {
     my $tries = 0;      my $tries = 0;
     my $gotlock = &Apache::lonnet::newput_dom('ltitools',$lockhash,$cdom);      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);
Line 13029  sub get_ltitools_id { Line 11272  sub get_ltitools_id {
 sub modify_lti {  sub modify_lti {
     my ($r,$dom,$action,$lastactref,%domconfig) = @_;      my ($r,$dom,$action,$lastactref,%domconfig) = @_;
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);      my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
     my (%encconfig,$errors,$resulttext);      my ($newid,@allpos,%changes,%confhash,%encconfig,$errors,$resulttext);
       my (%posslti,%posslticrs,%posscrstype);
     my (%currltisec,%secchanges,%newltisec,%newltienc,%keyset,%newkeyset);      my @courseroles = ('cc','in','ta','ep','st');
     $newltisec{'private'}{'keys'} = [];      my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator);
     $newltisec{'encrypt'} = {};      my @lticourseroles = qw(Instructor TeachingAssistant Mentor Learner);
     $newltisec{'rules'} = {};      my @coursetypes = ('official','unofficial','community','textbook','placement');
     $newltisec{'linkprot'} = {};      my %coursetypetitles = &Apache::lonlocal::texthash (
     if (ref($domconfig{'ltisec'}) eq 'HASH') {                                 official   => 'Official',
         %currltisec = %{$domconfig{'ltisec'}};                                 unofficial => 'Unofficial',
         if (ref($currltisec{'linkprot'}) eq 'HASH') {                                 community  => 'Community',
             foreach my $id (keys(%{$currltisec{'linkprot'}})) {                                 textbook   => 'Textbook',
                 unless ($id =~ /^\d+$/) {                                 placement  => 'Placement Test',
                     delete($currltisec{'linkprot'}{$id});      );
                 }      my %lt = &lti_names();
             }      map { $posslti{$_} = 1; } @ltiroles;
         }      map { $posslticrs{$_} = 1; } @lticourseroles;
         if (ref($currltisec{'private'}) eq 'HASH') {      map { $posscrstype{$_} = 1; } @coursetypes;
             if (ref($currltisec{'private'}{'keys'}) eq 'ARRAY') {      
                 $newltisec{'private'}{'keys'} = $currltisec{'private'}{'keys'};      my (@items,%deletions,%itemids);
                 map { $keyset{$_} = 1; } @{$currltisec{'private'}{'keys'}};      if ($env{'form.lti_add'}) {
             }          my $consumer = $env{'form.lti_consumer_add'};
           $consumer =~ s/(`)/'/g;
           ($newid,my $error) = &get_lti_id($dom,$consumer);
           if ($newid) {
               $itemids{'add'} = $newid;
               push(@items,'add');
               $changes{$newid} = 1;
           } else {
               my $error = &mt('Failed to acquire unique ID for new LTI configuration');
               $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
         }          }
     }      }
     foreach my $item ('crs','dom') {      if (ref($domconfig{$action}) eq 'HASH') {
         my $formelement = 'form.ltisec_'.$item.'linkprot';          my @todelete = &Apache::loncommon::get_env_multiple('form.lti_del');
         if ($env{$formelement}) {          if (@todelete) {
             $newltisec{'encrypt'}{$item} = 1;              map { $deletions{$_} = 1; } @todelete;
             if (ref($currltisec{'encrypt'}) eq 'HASH') {          }
                 unless ($currltisec{'encrypt'}{$item}) {          my $maxnum = $env{'form.lti_maxnum'};
                     $secchanges{'encrypt'} = 1;          for (my $i=0; $i<=$maxnum; $i++) {
               my $itemid = $env{'form.lti_id_'.$i};
               $itemid =~ s/\D+//g;
               if (ref($domconfig{$action}{$itemid}) eq 'HASH') {
                   if ($deletions{$itemid}) {
                       $changes{$itemid} = $domconfig{$action}{$itemid}{'consumer'};
                   } else {
                      push(@items,$i);
                      $itemids{$i} = $itemid;
                 }                  }
             } else {  
                 $secchanges{'encrypt'} = 1;  
             }  
         } elsif (ref($currltisec{'encrypt'}) eq 'HASH') {  
             if ($currltisec{'encrypt'}{$item}) {  
                 $secchanges{'encrypt'} = 1;  
             }              }
         }          }
     }      }
     unless (exists($currltisec{'rules'})) {      foreach my $idx (@items) {
         $currltisec{'rules'} = {};          my $itemid = $itemids{$idx};
     }          next unless ($itemid);
     &password_rule_changes('secrets',$newltisec{'rules'},$currltisec{'rules'},\%secchanges);          my $position = $env{'form.lti_pos_'.$idx};
           $position =~ s/\D+//g;
     my @ids=&Apache::lonnet::current_machine_ids();          if ($position ne '') {
     my %servers = &Apache::lonnet::get_servers($dom,'library');              $allpos[$position] = $itemid;
           }
     foreach my $hostid (keys(%servers)) {          foreach my $item ('consumer','key','secret','lifetime') {
         if (($hostid ne '') && (grep(/^\Q$hostid\E$/,@ids))) {              my $formitem = 'form.lti_'.$item.'_'.$idx;
             my $newkey;              $env{$formitem} =~ s/(`)/'/g;
             my $keyitem = 'form.ltisec_privkey_'.$hostid;              if ($item eq 'lifetime') {
             if (exists($env{$keyitem})) {                  $env{$formitem} =~ s/[^\d.]//g;
                 $env{$keyitem} =~ s/(`)/'/g;              }
                 if ($keyset{$hostid}) {              if ($env{$formitem} ne '') {
                     if ($env{'form.ltisec_changeprivkey_'.$hostid}) {                  if (($item eq 'key') || ($item eq 'secret')) {
                         if ($env{$keyitem} ne '') {                      $encconfig{$itemid}{$item} = $env{$formitem};
                             $secchanges{'private'} = 1;                  } else {
                             $newkeyset{$hostid} = $env{$keyitem};                      $confhash{$itemid}{$item} = $env{$formitem};
                       unless (($idx eq 'add') || ($changes{$itemid})) {
                           if ($domconfig{$action}{$itemid}{$item} ne $confhash{$itemid}{$item}) {
                               $changes{$itemid} = 1;
                         }                          }
                     }                      }
                 } elsif ($env{$keyitem} ne '') {  
                     unless (grep(/^\Q$hostid\E$/,@{$newltisec{'private'}{'keys'}})) {  
                         push(@{$newltisec{'private'}{'keys'}},$hostid);  
                     }  
                     $secchanges{'private'} = 1;  
                     $newkeyset{$hostid} = $env{$keyitem};  
                 }                  }
             }              }
         }          }
     }          if ($env{'form.lti_version_'.$idx} eq 'LTI-1p0') {
               $confhash{$itemid}{'version'} = $env{'form.lti_version_'.$idx};
     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 ($env{'form.lti_mapuser_'.$idx} eq 'sourcedid') {
             if (ref($linkprotchg{$id}) eq 'HASH') {              $confhash{$itemid}{'mapuser'} = 'lis_person_sourcedid'; 
                 foreach my $inner (keys(%{$linkprotchg{$id}})) {          } elsif ($env{'form.lti_mapuser_'.$idx} eq 'email') {
                     if (($inner eq 'secret') || ($inner eq 'key')) {              $confhash{$itemid}{'mapuser'} = 'lis_person_contact_email_primary';
                         if ($is_home) {          } elsif ($env{'form.lti_mapuser_'.$idx} eq 'other') {
                             $newltienc{$id}{$inner} = $linkprotchg{$id}{$inner};              my $mapuser = $env{'form.lti_customuser_'.$idx};
                         }              $mapuser =~ s/(`)/'/g;
                     }              $mapuser =~ s/^\s+|\s+$//g; 
               $confhash{$itemid}{'mapuser'} = $mapuser; 
           }
           foreach my $ltirole (@lticourseroles) {
               my $possrole = $env{'form.lti_maprole_'.$ltirole.'_'.$idx};
               if (grep(/^\Q$possrole\E$/,@courseroles)) {
                   $confhash{$itemid}{'maproles'}{$ltirole} = $possrole;
               }
           }
           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 (($env{'form.lti_mapcrs_'.$idx} eq 'course_offering_sourcedid') ||
               ($env{'form.lti_mapcrs_'.$idx} eq 'context_id'))  {
               $confhash{$itemid}{'mapcrs'} = $env{'form.lti_mapcrs_'.$idx};
           } elsif ($env{'form.lti_mapcrs_'.$idx} eq 'other') {
               my $mapcrs = $env{'form.lti_mapcrsfield_'.$idx}; 
               $mapcrs =~ s/(`)/'/g;
               $mapcrs =~ s/^\s+|\s+$//g;
               $confhash{$itemid}{'mapcrs'} = $mapcrs;
           }
           my @posstypes = &Apache::loncommon::get_env_multiple('form.lti_mapcrstype_'.$idx);
           my @crstypes;
           foreach my $type (sort(@posstypes)) {
               if ($posscrstype{$type}) {
                   push(@crstypes,$type);
               }
           }
           $confhash{$itemid}{'mapcrstype'} = \@crstypes;
           if ($env{'form.lti_makecrs_'.$idx}) {
               $confhash{$itemid}{'makecrs'} = 1;
           }
           my @possenroll = &Apache::loncommon::get_env_multiple('form.lti_selfenroll_'.$idx);
           my @selfenroll;
           foreach my $type (sort(@possenroll)) {
               if ($posslticrs{$type}) {
                   push(@selfenroll,$type);
               }
           }
           $confhash{$itemid}{'selfenroll'} = \@selfenroll;
           if ($env{'form.lti_crssec_'.$idx}) {
               if ($env{'form.lti_crssecsrc_'.$idx} eq 'course_section_sourcedid') {
                   $confhash{$itemid}{'section'} = $env{'form.lti_crssecsrc_'.$idx};
               } elsif ($env{'form.lti_crssecsrc_'.$idx} eq 'other') {
                   my $section = $env{'form.lti_customsection_'.$idx};
                   $section =~ s/(`)/'/g;
                   $section =~ s/^\s+|\s+$//g;
                   if ($section ne '') {
                       $confhash{$itemid}{'section'} = $section;
                 }                  }
             } else {  
                 $newltisec{'linkprot'}{$id} = $linkprotchg{$id};  
             }              }
         }          }
         $linkprotoutput = &Apache::courseprefs::store_linkprot($dom,'','domain',\%linkprotchg,\%oldlinkprot);          foreach my $field ('passback','roster') {
         if (keys(%linkprotchg)) {              if ($env{'form.lti_'.$field.'_'.$idx}) {
             %{$newltisec{'linkprot'}} = %linkprotchg;                  $confhash{$itemid}{$field} = 1;
               }
         }          }
     }          unless (($idx eq 'add') || ($changes{$itemid})) {
     if (ref($currltisec{'linkprot'}) eq 'HASH') {              foreach my $field ('mapuser','mapcrs','section','passback','roster') {
         foreach my $id (%{$currltisec{'linkprot'}}) {                  if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) {
             next if ($id !~ /^\d+$/);                      $changes{$itemid} = 1;
             unless (exists($linkprotchg{$id})) {                  }
                 if (ref($currltisec{'linkprot'}{$id}) eq 'HASH') {              }
                     foreach my $inner (keys(%{$currltisec{'linkprot'}{$id}})) {              foreach my $field ('makeuser','mapcrstype','selfenroll') {
                         if (($inner eq 'secret') || ($inner eq 'key')) {                  unless ($changes{$itemid}) {
                             if ($is_home) {                      if (ref($domconfig{$action}{$itemid}{$field}) eq 'ARRAY') {
                                 $newltienc{$id}{$inner} = $currltisec{'linkprot'}{$id}{$inner};                          if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
                               my @diffs = &Apache::loncommon::compare_arrays($domconfig{$action}{$itemid}{$field},
                                                                              $confhash{$itemid}{$field});
                               if (@diffs) {
                                   $changes{$itemid} = 1;
                               }
                           } elsif (@{$domconfig{$action}{$itemid}{$field}} > 0) {
                               $changes{$itemid} = 1;
                           }
                       } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
                           if (@{$confhash{$itemid}{$field}} > 0) {
                               $changes{$itemid} = 1;
                           }
                       } 
                   }
               }
               unless ($changes{$itemid}) {
                   if (ref($domconfig{$action}{$itemid}{'maproles'}) eq 'HASH') {
                       if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
                           foreach my $ltirole (keys(%{$domconfig{$action}{$itemid}{'maproles'}})) {
                               if ($domconfig{$action}{$itemid}{'maproles'}{$ltirole} ne 
                                   $confhash{$itemid}{'maproles'}{$ltirole}) {
                                   $changes{$itemid} = 1;
                                   last;
                               }
                           }
                           unless ($changes{$itemid}) {
                               foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) {
                                   if ($confhash{$itemid}{'maproles'}{$ltirole} ne 
                                       $domconfig{$action}{$itemid}{'maproles'}{$ltirole}) {
                                       $changes{$itemid} = 1;
                                       last;
                                   }
                             }                              }
                         } else {                          }
                             $newltisec{'linkprot'}{$id}{$inner} = $currltisec{'linkprot'}{$id}{$inner};                      } elsif (keys(%{$domconfig{$action}{$itemid}{'maproles'}}) > 0) {
                           $changes{$itemid} = 1;
                       }
                   } elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
                       unless ($changes{$itemid}) {
                           if (keys(%{$confhash{$itemid}{'maproles'}}) > 0) {
                               $changes{$itemid} = 1;
                         }                          }
                     }                      }
                 } else {  
                     $newltisec{'linkprot'}{$id} = $currltisec{'linkprot'}{$id};  
                 }                  }
             }              }
         }          }
     }      }
     if ($proterror) {      if (@allpos > 0) {
         $errors .= '<li>'.$proterror.'</li>';          my $idx = 0;
           foreach my $itemid (@allpos) {
               if ($itemid ne '') {
                   $confhash{$itemid}{'order'} = $idx;
                   if (ref($domconfig{$action}) eq 'HASH') {
                       if (ref($domconfig{$action}{$itemid}) eq 'HASH') {
                           if ($domconfig{$action}{$itemid}{'order'} ne $idx) {
                               $changes{$itemid} = 1;
                           }
                       }
                   }
                   $idx ++;
               }
           }
     }      }
       my %ltihash = (
     my ($putresult,%keystore);                            $action => { %confhash }
     if (keys(%secchanges)) {                         );
         my %ltienchash;      my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,
         my %ltihash = (                                               $dom);
                           'ltisec' => { %newltisec }      if ($putresult eq 'ok') {
                       );          my %ltienchash = (
         $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,$dom);                               $action => { %encconfig }
         if ($putresult eq 'ok') {                           );
             if ($secchanges{'private'}) {          &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom);
                 my $who = &escape($env{'user.name'}.':'.$env{'user.domain'});          if (keys(%changes) > 0) {
                 foreach my $hostid (keys(%newkeyset)) {              my $cachetime = 24*60*60;
                     my $storehash = {              my %ltiall = %confhash;
                                        key => $newkeyset{$hostid},              foreach my $id (keys(%ltiall)) {
                                        who => $env{'user.name'}.':'.$env{'user.domain'},                  if (ref($encconfig{$id}) eq 'HASH') {
                                     };                      foreach my $item ('key','secret') {
                     $keystore{$hostid} = &Apache::lonnet::store_dom($storehash,'lti','private',                          $ltiall{$id}{$item} = $encconfig{$id}{$item};
                                                                     $dom,$hostid);                      }
                 }                  }
             }              }
               &Apache::lonnet::do_cache_new('lti',$dom,\%ltiall,$cachetime);
             if (ref($lastactref) eq 'HASH') {              if (ref($lastactref) eq 'HASH') {
                 if (($secchanges{'encrypt'}) || ($secchanges{'private'})) {                  $lastactref->{'lti'} = 1;
                     $lastactref->{'domdefaults'} = 1;  
                 }  
             }              }
             if (($secchanges{'linkprot'}) && ($is_home)) {              $resulttext = &mt('Changes made:').'<ul>';
                 my %ltienchash = (              my %bynum;
                                      'linkprot' =>  { %newltienc }              foreach my $itemid (sort(keys(%changes))) {
                                  );                  my $position = $confhash{$itemid}{'order'};
                 &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1);                  $bynum{$position} = $itemid;
             }              }
         }              foreach my $pos (sort { $a <=> $b } keys(%bynum)) {
     } else {                  my $itemid = $bynum{$pos};
         return &mt('No changes made.');                  if (ref($confhash{$itemid}) ne 'HASH') {
     }                      $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';
     if ($putresult eq 'ok') {                  } else {
         $resulttext = &mt('Changes made:').'<ul>';                      $resulttext .= '<li><b>'.$confhash{$itemid}{'consumer'}.'</b></li><ul>';
         foreach my $item (keys(%secchanges)) {                      my $position = $pos + 1;
             if ($item eq 'encrypt') {                      $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';
                 my %encrypted = (                      foreach my $item ('version','lifetime') {
                           crs  => {                          if ($confhash{$itemid}{$item} ne '') {
                                     on => &mt('Encryption of stored link protection secrets defined in courses enabled'),                              $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{$item}.'</li>';
                                     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'),  
                                  },  
                 );  
                 foreach my $type ('crs','dom') {  
                     my $shown = $encrypted{$type}{'off'};  
                     if (ref($newltisec{$item}) eq 'HASH') {  
                         if ($newltisec{$item}{$type}) {  
                             $shown = $encrypted{$type}{'on'};  
                         }                          }
                     }                      }
                     $resulttext .= '<li>'.$shown.'</li>';                      if ($encconfig{$itemid}{'key'} ne '') {
                 }                          $resulttext .= '<li>'.$lt{'key'}.':&nbsp;'.$encconfig{$itemid}{'key'}.'</li>';
             } elsif ($item eq 'rules') {                      }
                 my %titles = &Apache::lonlocal::texthash(                      if ($encconfig{$itemid}{'secret'} ne '') {
                                   min   => 'Minimum password length',                          $resulttext .= '<li>'.$lt{'secret'}.':&nbsp;';
                                   max   => 'Maximum password length',                          my $num = length($encconfig{$itemid}{'secret'});
                                   chars => 'Required characters',                          $resulttext .= ('*'x$num).'</li>';
                 );                      }
                 foreach my $rule ('min','max') {                      if ($confhash{$itemid}{'mapuser'}) {
                     if ($newltisec{rules}{$rule} eq '') {                          my $shownmapuser;
                         if ($rule eq 'min') {                          if ($confhash{$itemid}{'mapuser'} eq 'lis_person_sourcedid') {
                             $resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule});                              $shownmapuser = $lt{'sourcedid'}.' (lis_person_sourcedid)';
                                            ' '.&mt('Default of [_1] will be used',                          } elsif ($confhash{$itemid}{'mapuser'} eq 'lis_person_contact_email_primary') {
                                                        $Apache::lonnet::passwdmin).'</li>';                              $shownmapuser = $lt{'email'}.' (lis_person_contact_email_primary)';
                         } else {                          } else {
                             $resulttext .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>';                              $shownmapuser = &mt('Other').' ('.$confhash{$itemid}{'mapuser'}.')';
                           } 
                           $resulttext .= '<li>'.&mt('LON-CAPA username').': '.$shownmapuser.'</li>';
                       }
                       if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
                           my $rolemaps;
                           foreach my $role (@ltiroles) {
                               if ($confhash{$itemid}{'maproles'}{$role}) {
                                   $rolemaps .= ('&nbsp;'x2).$role.'='.
                                                &Apache::lonnet::plaintext($confhash{$itemid}{'maproles'}{$role},
                                                                           'Course').',';
                               }
                         }                          }
                           if ($rolemaps) {
                               $rolemaps =~ s/,$//;
                               $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>';
                           }
                       }
                       if (ref($confhash{$itemid}{'makeuser'}) eq 'ARRAY') {
                           if (@{$confhash{$itemid}{'makeuser'}} > 0) { 
                               $resulttext .= '<li>'.&mt('Following roles may create user accounts: [_1]',
                                                         join(', ',@{$confhash{$itemid}{'makeuser'}})).'</li>';
                           } else {
                               $resulttext .= '<li>'.&mt('User account creation not permitted.').'</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}{'makecrs'}) {
                           $resulttext .= '<li>'.&mt('Instructor may create course (if absent).').'</li>';
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$newltisec{rules}{$rule}).'</li>';                          $resulttext .= '<li>'.&mt('Instructor may not create course (if absent).').'</li>';
                     }                      }
                 }                      if (ref($confhash{$itemid}{'selfenroll'}) eq 'ARRAY') {
                 if (ref($newltisec{'rules'}{'chars'}) eq 'ARRAY') {                          if (@{$confhash{$itemid}{'selfenroll'}} > 0) {
                     if (@{$newltisec{'rules'}{'chars'}} > 0) {                              $resulttext .= '<li>'.&mt('Self-enrollment for following roles: [_1]',
                         my %rulenames = &Apache::lonlocal::texthash(                                                        join(', ',@{$confhash{$itemid}{'selfenroll'}})).
                                             uc => 'At least one upper case letter',                                             '</li>';
                                             lc => 'At least one lower case letter',                          } else {
                                             num => 'At least one number',                              $resulttext .= '<li>'.&mt('Self-enrollment not permitted').'</li>';
                                             spec => 'At least one non-alphanumeric',                          }
                                             );                      }
                         my $needed = '<ul><li>'.                      if ($confhash{$itemid}{'section'}) {
                                      join('</li><li>',map {$rulenames{$_} } @{$newltisec{'rules'}{'chars'}}).                          if ($confhash{$itemid}{'section'} eq 'course_section_sourcedid') {
                                      '</li></ul>';                              $resulttext .= '<li>'.&mt('User section from standard field:').
                         $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>';                                                   ' (course_section_sourcedid)'.'</li>';  
                           } else {
                               $resulttext .= '<li>'.&mt('User section from:').' '.
                                                     $confhash{$itemid}{'section'}.'</li>';
                           }
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';                          $resulttext .= '<li>'.&mt('No section assignment').'</li>';
                     }                      }
                 } else {                      foreach my $item ('passback','roster') {
                     $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';                          $resulttext .= '<li>'.$lt{$item}.'&nbsp;';
                 }                          if ($confhash{$itemid}{$item}) {
             } elsif ($item eq 'private') {                              $resulttext .= &mt('Yes');
                 if (keys(%newkeyset)) {                          } else {
                     foreach my $hostid (sort(keys(%newkeyset))) {                              $resulttext .= &mt('No');
                         if ($keystore{$hostid} eq 'ok') {  
                             $resulttext .= '<li>'.&mt('Encryption key for storage of shared secrets saved for [_1]',$hostid).'</li>';  
                         }                          }
                           $resulttext .= '</li>';
                     }                      }
                       $resulttext .= '</ul></li>';
                 }                  }
             } elsif ($item eq 'linkprot') {  
                 $resulttext .= $linkprotoutput;  
             }              }
               $resulttext .= '</ul>';
           } else {
               $resulttext = &mt('No changes made.');
         }          }
         $resulttext .= '</ul>';  
     } 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 13275  sub modify_lti { Line 11642  sub modify_lti {
     return $resulttext;      return $resulttext;
 }  }
   
   sub get_lti_id {
       my ($domain,$consumer) = @_;
       # get lock on lti db
       my $lockhash = {
                         lock => $env{'user.name'}.
                                 ':'.$env{'user.domain'},
                      };
       my $tries = 0;
       my $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);
       my ($id,$error);
   
       while (($gotlock ne 'ok') && ($tries<10)) {
           $tries ++;
           sleep (0.1);
           $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);
       }
       if ($gotlock eq 'ok') {
           my %currids = &Apache::lonnet::dump_dom('lti',$domain);
           if ($currids{'lock'}) {
               delete($currids{'lock'});
               if (keys(%currids)) {
                   my @curr = sort { $a <=> $b } keys(%currids);
                   if ($curr[-1] =~ /^\d+$/) {
                       $id = 1 + $curr[-1];
                   }
               } else {
                   $id = 1;
               }
               if ($id) {
                   unless (&Apache::lonnet::newput_dom('lti',{ $id => $consumer },$domain) eq 'ok') {
                       $error = 'nostore';
                   }
               } else {
                   $error = 'nonumber';
               }
           }
           my $dellockoutcome = &Apache::lonnet::del_dom('lti',['lock'],$domain);
       } else {
           $error = 'nolock';
       }
       return ($id,$error);
   }
   
 sub modify_autoenroll {  sub modify_autoenroll {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,%changes);      my ($resulttext,%changes);
Line 13288  sub modify_autoenroll { Line 11698  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 13298  sub modify_autoenroll { Line 11708  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 13342  sub modify_autoenroll { Line 11746  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 13368  sub modify_autoenroll { Line 11769  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 {                  } else {
                     $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section not in use').'</li>';                      $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section: deleted');
                 }                  }
             }  
             if ($changes{'failsafe'}) {  
                 if ($failsafe eq 'off') {  
                     unless ($changes{'autofailsafe'}) {  
                         $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section not in use').'</li>';  
                     }  
                 } elsif ($failsafe eq 'zero') {  
                     $resulttext .= '<li>'.&mt('Failsafe applies if retrieved section enrollment is zero').'</li>';  
                 } else {  
                     $resulttext .= '<li>'.&mt('Failsafe applies if retrieved section enrollment is zero or greater').'</li>';  
                 }  
             }  
             if (($changes{'autofailsafe'}) || ($changes{'failsafe'})) {  
                 &Apache::lonnet::get_domain_defaults($dom,1);                  &Apache::lonnet::get_domain_defaults($dom,1);
                 if (ref($lastactref) eq 'HASH') {                  if (ref($lastactref) eq 'HASH') {
                     $lastactref->{'domdefaults'} = 1;                      $lastactref->{'domdefaults'} = 1;
Line 13412  sub modify_autoupdate { Line 11800  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 13459  sub modify_autoupdate { Line 11845  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 13521  sub modify_autoupdate { Line 11896  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 13593  sub modify_autoupdate { Line 11958  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 13910  sub modify_contacts { Line 12270  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 13945  sub modify_contacts { Line 12304  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 14034  sub modify_contacts { Line 12358  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 14092  sub modify_contacts { Line 12416  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 14114  sub modify_contacts { Line 12438  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 14199  sub modify_contacts { Line 12453  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 14233  sub modify_contacts { Line 12486  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 14296  sub modify_contacts { Line 12542  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 14320  sub modify_contacts { Line 12566  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 14365  sub modify_contacts { Line 12611  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',
                                           &mt('LON-CAPA core group - MSU'),600,500)).
                                 '</li>';                                  '</li>';
             }              }
             if ($changes{'reportstatus'}) {  
                 $resulttext .= '<li>'.  
                                 &mt('E-mail status if errors above threshold to [_1] set to "'.  
                                     $offon[$env{'form.reportstatus'}].'".',  
                                     $corelink).  
                                 '</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 14489  sub modify_contacts { Line 12678  sub modify_contacts {
     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 $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 ($result,$customurl) =  
                         &publishlogo($r,'upload','passwords_customfile',$dom,  
                                      $confname,'customtext/resetpw','','',$customfn);  
                     if ($result eq 'ok') {  
                         $newvalues{'resetcustom'} = $customurl;  
                         $changes{'reset'} = 1;  
                     } 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 'secrets') {  
         @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 15347  sub modify_selfcreation { Line 12977  sub modify_selfcreation {
 # Populate $cancreate{'selfcreate'} array reference with types of user, for which self-creation of user accounts  # Populate $cancreate{'selfcreate'} array reference with types of user, for which self-creation of user accounts
 # is permitted.  # is permitted.
 #  #
   
     my ($emailrules,$emailruleorder) = &Apache::lonnet::inst_userrules($dom,'email');      my ($emailrules,$emailruleorder) = &Apache::lonnet::inst_userrules($dom,'email');
   
     my (@statuses,%email_rule);      my (@statuses,%email_rule);
Line 15397  sub modify_selfcreation { Line 13026  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 15409  sub modify_selfcreation { Line 13038  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 15836  sub modify_selfcreation { Line 13465  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 15862  sub modify_selfcreation { Line 13491  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 15922  sub modify_selfcreation { Line 13551  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 15940  sub modify_selfcreation { Line 13569  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 16044  sub modify_selfcreation { Line 13673  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 16131  sub modify_selfcreation { Line 13760  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 16171  sub process_captcha { Line 13794  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 16181  sub process_captcha { Line 13804  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 16194  sub process_captcha { Line 13817  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 16207  sub process_captcha { Line 13828  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 16324  sub modify_defaults { Line 13943  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');      my @authtypes = ('internal','krb4','krb5','localauth');
     foreach my $item (@items) {      foreach my $item (@items) {
         $newvalues{$item} = $env{'form.'.$item};          $newvalues{$item} = $env{'form.'.$item};
Line 16366  sub modify_defaults { Line 13985  sub modify_defaults {
                     push(@errors,$item);                      push(@errors,$item);
                 }                  }
             }              }
           } elsif ($item eq 'intauth_cost') {
               if ($newvalues{$item} ne '') {
                   if ($newvalues{$item} =~ /\D/) {
                       push(@errors,$item);
                   }
               }
           } elsif ($item eq 'intauth_check') {
               if ($newvalues{$item} ne '') {
                   unless ($newvalues{$item} =~ /^(0|1|2)$/) {
                       push(@errors,$item);
                   }
               }
           } elsif ($item eq 'intauth_switch') {
               if ($newvalues{$item} ne '') {
                   unless ($newvalues{$item} =~ /^(0|1|2)$/) {
                       push(@errors,$item);
                   }
               }
         }          }
         if (grep(/^\Q$item\E$/,@errors)) {          if (grep(/^\Q$item\E$/,@errors)) {
             $newvalues{$item} = $domdefaults{$item};              $newvalues{$item} = $domdefaults{$item};
Line 16374  sub modify_defaults { Line 14011  sub modify_defaults {
         }          }
         $domdefaults{$item} = $newvalues{$item};          $domdefaults{$item} = $newvalues{$item};
     }      }
     my %staticdefaults = (  
                            'intauth_cost'   => 10,  
                            'intauth_check'  => 0,  
                            'intauth_switch' => 0,  
                          );  
     foreach my $item ('intauth_cost','intauth_check','intauth_switch') {  
         if (exists($domdefaults{$item})) {  
             $newvalues{$item} = $domdefaults{$item};  
         } else {  
             $newvalues{$item} = $staticdefaults{$item};  
         }  
     }  
     my ($unamemaprules,$ruleorder);  
     my @possunamemaprules = &Apache::loncommon::get_env_multiple('form.unamemap_rule');  
     if (@possunamemaprules) {  
         ($unamemaprules,$ruleorder) =  
             &Apache::lonnet::inst_userrules($dom,'unamemap');  
         if ((ref($unamemaprules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {  
             if (@{$ruleorder} > 0) {  
                 my %possrules;  
                 map { $possrules{$_} = 1; } @possunamemaprules;  
                 foreach my $rule (@{$ruleorder}) {  
                     if ($possrules{$rule}) {  
                         push(@{$newvalues{'unamemap_rule'}},$rule);  
                     }  
                 }  
             }  
         }  
     }  
     if (ref($domdefaults{'unamemap_rule'}) eq 'ARRAY') {  
         if (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') {  
             my @rulediffs = &Apache::loncommon::compare_arrays($domdefaults{'unamemap_rule'},  
                                                                $newvalues{'unamemap_rule'});  
             if (@rulediffs) {  
                 $changes{'unamemap_rule'} = 1;  
                 $domdefaults{'unamemap_rule'} = $newvalues{'unamemap_rule'};  
             }  
         } elsif (@{$domdefaults{'unamemap_rule'}} > 0) {  
             $changes{'unamemap_rule'} = 1;  
             delete($domdefaults{'unamemap_rule'});  
         }  
     } elsif (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') {  
         if (@{$newvalues{'unamemap_rule'}} > 0) {  
             $changes{'unamemap_rule'} = 1;  
             $domdefaults{'unamemap_rule'} = $newvalues{'unamemap_rule'};  
         }  
     }  
     my %defaults_hash = (      my %defaults_hash = (
                          defaults => \%newvalues,                           defaults => \%newvalues,
                         );                          );
Line 16441  sub modify_defaults { Line 14031  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 16534  sub modify_defaults { Line 14122  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 16570  sub modify_defaults { Line 14138  sub modify_defaults {
                                           localauth  => 'loc',                                            localauth  => 'loc',
                         );                          );
                         $value = $authnames{$shortauth{$value}};                          $value = $authnames{$shortauth{$value}};
                       } elsif ($item eq 'intauth_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 'intauth_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]"',$title->{$item},$value).'</li>';                      $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$item},$value).'</li>';
                     $mailmsgtext .= "$title->{$item} set to $value\n";                        $mailmsgtext .= "$title->{$item} set to $value\n";  
Line 16618  sub modify_scantron { Line 14208  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 16653  sub modify_scantron { Line 14243  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 16724  sub modify_scantron { Line 14253  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 .= &mt('The following errors occurred: ').'<ul>'.          $resulttext .= &mt('The following errors occurred: ').'<ul>'.
Line 16814  sub modify_coursecategories { Line 14308  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 16828  sub modify_coursecategories { Line 14331  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 16850  sub modify_coursecategories { Line 14357  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 16912  sub modify_coursecategories { Line 14422  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 17030  sub modify_coursecategories { Line 14554  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 17513  sub modify_coursedefaults { Line 15033  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','mysqltables_official',                     'uploadquota_community','uploadquota_textbook','uploadquota_placement',
                    'mysqltables_unofficial','mysqltables_community','mysqltables_textbook');                     'mysqltables_official','mysqltables_unofficial','mysqltables_community',
     my @types = ('official','unofficial','community','textbook');                     'mysqltables_textbook','mysqltables_placement');
       my @types = ('official','unofficial','community','textbook','placement');
     my %staticdefaults = (      my %staticdefaults = (
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
Line 17580  sub modify_coursedefaults { Line 15100  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;
Line 17595  sub modify_coursedefaults { Line 15116  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 17725  sub modify_coursedefaults { Line 15245  sub modify_coursedefaults {
     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'})) {                  foreach my $item ('canuse_pdfforms','uselcmath','usejsme','texengine') {
                 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 17780  sub modify_coursedefaults { Line 15299  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 17792  sub modify_coursedefaults { Line 15317  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 17811  sub modify_coursedefaults { Line 15330  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>';
Line 17824  sub modify_coursedefaults { Line 15343  sub modify_coursedefaults {
                                        '<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 17859  sub modify_coursedefaults { Line 15379  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 17894  sub modify_coursedefaults { Line 15416  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>';  
                     }  
                 }                  }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
Line 17916  sub modify_coursedefaults { Line 15432  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 18152  sub modify_selfenrollment { Line 15668  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>';  
                             }  
                         }  
                     }  
                 }  
             }  
         } 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 18501  sub modify_usersessions { Line 15679  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 18657  sub modify_usersessions { Line 15835  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 18674  sub modify_usersessions { Line 15851  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 18700  sub modify_usersessions { Line 15861  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 18748  sub modify_usersessions { Line 15897  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 18824  sub modify_usersessions { Line 15970  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);
                                   }
                             }                              }
                             $resulttext .= '</ul>';  
                         } else {                          } else {
                             $resulttext .= '<li>'.&mt('No servers now set to switch other institutions on next access.');                              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;
                                   }
                               }
                           } else {
                               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 18876  sub modify_loadbalancing { Line 16299  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 18933  sub modify_loadbalancing { Line 16356  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 19098  sub modify_loadbalancing { Line 16509  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 19336  sub lonbalance_targets_js { Line 16738  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 19883  sub devalidate_remote_domconfs { Line 17285  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.9  
changed lines
  Added in v.1.323


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