Diff for /loncom/interface/domainprefs.pm between versions 1.378 and 1.429

version 1.378, 2021/02/01 15:58:41 version 1.429, 2023/09/06 13:57:05
Line 95  about default quota sizes for portfolio Line 95  about default quota sizes for portfolio
 institutional affiliation in the domain (e.g., Faculty, Staff, Student etc.),   institutional affiliation in the domain (e.g., Faculty, Staff, Student etc.), 
 but is now also used to manage availability of user tools:   but is now also used to manage availability of user tools: 
 i.e., blogs, aboutme page, and portfolios, and the course request tool,  i.e., blogs, aboutme page, and portfolios, and the course request tool,
 used by course owners to request creation of a course, and to display/store  used by course owners to request creation of a course.
 default quota sizes for Authoring Spaces.  
   
 Outputs: 1  Outputs: 1
   
Line 105  $datatable  - HTML containing form eleme Line 104  $datatable  - HTML containing form eleme
 In the case of course requests, radio buttons are displayed for each institutional  In the case of course requests, radio buttons are displayed for each institutional
 affiliate type (and also default, and _LC_adv) for each of the course types   affiliate type (and also default, and _LC_adv) for each of the course types 
 (official, unofficial, community, textbook, placement, and lti).    (official, unofficial, community, textbook, placement, and lti).  
 In each case the radio buttons allow the selection of one of four values:    In each case the radio buttons allow the selection of one of four values:
   
 0, approval, validate, autolimit=N (where N is blank, or a positive integer).  0, approval, validate, autolimit=N (where N is blank, or a positive integer).
 which have the following effects:  which have the following effects:
Line 167  use Apache::lonmsg(); Line 166  use Apache::lonmsg();
 use Apache::lonconfigsettings;  use Apache::lonconfigsettings;
 use Apache::lonuserutils();  use Apache::lonuserutils();
 use Apache::loncoursequeueadmin();  use Apache::loncoursequeueadmin();
   use Apache::courseprefs();
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
 use LONCAPA::Enrollment;  use LONCAPA::Enrollment;
 use LONCAPA::lonauthcgi();  use LONCAPA::lonauthcgi();
Line 177  use DateTime::TimeZone; Line 177  use DateTime::TimeZone;
 use DateTime::Locale;  use DateTime::Locale;
 use Time::HiRes qw( sleep );  use Time::HiRes qw( sleep );
 use Net::CIDR;  use Net::CIDR;
   use Crypt::CBC;
   
 my $registered_cleanup;  my $registered_cleanup;
 my $modified_urls;  my $modified_urls;
Line 220  sub handler { Line 221  sub handler {
                 'serverstatuses','requestcourses','helpsettings',                  'serverstatuses','requestcourses','helpsettings',
                 'coursedefaults','usersessions','loadbalancing',                  'coursedefaults','usersessions','loadbalancing',
                 'requestauthor','selfenrollment','inststatus',                  'requestauthor','selfenrollment','inststatus',
                 'ltitools','ssl','trust','lti','privacy','passwords',                  'ltitools','toolsec','ssl','trust','lti','ltisec',
                 'proctoring','wafproxy'],$dom);                  'privacy','passwords','proctoring','wafproxy',
                   'ipaccess','authordefaults'],$dom);
     my %encconfig =      my %encconfig =
         &Apache::lonnet::get_dom('encconfig',['ltitools','lti','proctoring'],$dom);          &Apache::lonnet::get_dom('encconfig',['ltitools','lti','proctoring','linkprot'],$dom,undef,1);
       my ($checked_is_home,$is_home);
     if (ref($domconfig{'ltitools'}) eq 'HASH') {      if (ref($domconfig{'ltitools'}) eq 'HASH') {
         if (ref($encconfig{'ltitools'}) eq 'HASH') {          if (ref($encconfig{'ltitools'}) eq 'HASH') {
               my $home = &Apache::lonnet::domain($dom,'primary');
               unless (($home eq 'no_host') || ($home eq '')) {
                   my @ids=&Apache::lonnet::current_machine_ids();
                   if (grep(/^\Q$home\E$/,@ids)) {
                       $is_home = 1;
                   }
               }
               $checked_is_home = 1;
             foreach my $id (keys(%{$domconfig{'ltitools'}})) {              foreach my $id (keys(%{$domconfig{'ltitools'}})) {
                 if ((ref($domconfig{'ltitools'}{$id}) eq 'HASH') &&                  if ((ref($domconfig{'ltitools'}{$id}) eq 'HASH') &&
                     (ref($encconfig{'ltitools'}{$id}) eq 'HASH')) {                      (ref($encconfig{'ltitools'}{$id}) eq 'HASH')) {
                     foreach my $item ('key','secret') {                      $domconfig{'ltitools'}{$id}{'key'} = $encconfig{'ltitools'}{$id}{'key'};
                         $domconfig{'ltitools'}{$id}{$item} = $encconfig{'ltitools'}{$id}{$item};                      if (($is_home) && ($phase eq 'process')) {
                           $domconfig{'ltitools'}{$id}{'secret'} = $encconfig{'ltitools'}{$id}{'secret'};
                     }                      }
                 }                  }
             }              }
Line 238  sub handler { Line 250  sub handler {
     }      }
     if (ref($domconfig{'lti'}) eq 'HASH') {      if (ref($domconfig{'lti'}) eq 'HASH') {
         if (ref($encconfig{'lti'}) eq 'HASH') {          if (ref($encconfig{'lti'}) eq 'HASH') {
               unless ($checked_is_home) {
                   my $home = &Apache::lonnet::domain($dom,'primary');
                   unless (($home eq 'no_host') || ($home eq '')) {
                       my @ids=&Apache::lonnet::current_machine_ids();
                       if (grep(/^\Q$home\E$/,@ids)) {
                           $is_home = 1;
                       }
                   }
                   $checked_is_home = 1;
               }
             foreach my $id (keys(%{$domconfig{'lti'}})) {              foreach my $id (keys(%{$domconfig{'lti'}})) {
                 if ((ref($domconfig{'lti'}{$id}) eq 'HASH') &&                  if ((ref($domconfig{'lti'}{$id}) eq 'HASH') &&
                     (ref($encconfig{'lti'}{$id}) eq 'HASH')) {                      (ref($encconfig{'lti'}{$id}) eq 'HASH')) {
                     foreach my $item ('key','secret') {                      $domconfig{'lti'}{$id}{'key'} = $encconfig{'lti'}{$id}{'key'};
                         $domconfig{'lti'}{$id}{$item} = $encconfig{'lti'}{$id}{$item};                      if (($is_home) && ($phase eq 'process')) {
                           $domconfig{'lti'}{$id}{'secret'} = $encconfig{'lti'}{$id}{'secret'};
                       }
                   }
               }
           }
       }
       if (ref($domconfig{'ltisec'}) eq 'HASH') {
           if (ref($domconfig{'ltisec'}{'linkprot'}) eq 'HASH') {
               if (ref($encconfig{'linkprot'}) eq 'HASH') {
                   foreach my $id (keys(%{$domconfig{'ltisec'}{'linkprot'}})) {
                       unless ($id =~ /^\d+$/) {
                           delete($domconfig{'ltisec'}{'linkprot'}{$id});
                       }
                       if ((ref($domconfig{'ltisec'}{'linkprot'}{$id}) eq 'HASH') &&
                           (ref($encconfig{'linkprot'}{$id}) eq 'HASH')) {
                           foreach my $item ('key','secret') {
                               $domconfig{'ltisec'}{'linkprot'}{$id}{$item} = $encconfig{'linkprot'}{$id}{$item};
                           }
                     }                      }
                 }                  }
             }              }
Line 260  sub handler { Line 300  sub handler {
             }              }
         }          }
     }      }
     my @prefs_order = ('rolecolors','login','defaults','wafproxy','passwords','quotas',      my @prefs_order = ('rolecolors','login','ipaccess','defaults','wafproxy','passwords',
                        'autoenroll','autoupdate','autocreate','directorysrch',                         'quotas','autoenroll','autoupdate','autocreate','directorysrch',
                        'contacts','privacy','usercreation','selfcreation',                         'contacts','privacy','usercreation','selfcreation',
                        'usermodification','scantron','requestcourses','requestauthor',                         'usermodification','scantron','requestcourses','requestauthor',
                        'coursecategories','serverstatuses','helpsettings','coursedefaults',                         'coursecategories','serverstatuses','helpsettings','coursedefaults',
                        'ltitools','proctoring','selfenrollment','usersessions','ssl',                         'authordefaults','ltitools','proctoring','selfenrollment',
                        'trust','lti');                         '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 297  sub handler { Line 337  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 307  sub handler { Line 350  sub handler {
                       header => [{col1 => 'Setting',                        header => [{col1 => 'Setting',
                                   col2 => 'Value'},                                    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' =>            'wafproxy' =>
                     { text => 'Web Application Firewall/Reverse Proxy',                        { text => 'Web Application Firewall/Reverse Proxy',
                       help => 'Domain_Configuration_WAF_Proxy',                        help => 'Domain_Configuration_WAF_Proxy',
                       header => [{col1 => 'Domain server',                        header => [{col1 => 'Domain(s)',
                                   col2 => 'Alias for WAF/Reverse Proxy',                                    col2 => 'Servers and WAF/Reverse Proxy alias(es)',
                                  },                                   },
                                  {col1 => 'Setting',                                   {col1 => 'Domain(s)',
                                   col2 => 'Value',}],                                    col2 => 'WAF Configuration',}],
                       print => \&print_wafproxy,                        print => \&print_wafproxy,
                       modify => \&modify_wafproxy,                         modify => \&modify_wafproxy,
                     },                      },
         'passwords' =>          'passwords' =>
                     { text => 'Passwords (Internal authentication)',                      { text => 'Passwords (Internal authentication)',
Line 337  sub handler { Line 382  sub handler {
                       modify => \&modify_passwords,                        modify => \&modify_passwords,
                     },                      },
         'quotas' =>           'quotas' => 
                     { text => 'Blogs, personal web pages, webDAV/quotas, portfolios',                      { text => 'Blogs, personal pages/timezones, portfolio/quotas',
                       help => 'Domain_Configuration_Quotas',                        help => 'Domain_Configuration_Quotas',
                       header => [{col1 => 'User affiliation',                        header => [{col1 => 'User affiliation',
                                   col2 => 'Available tools',                                    col2 => 'Available tools',
                                   col3 => 'Quotas, MB; (Authoring requires role)',}],                                    col3 => 'Portfilo quota (MB)',}],
                       print => \&print_quotas,                        print => \&print_quotas,
                       modify => \&modify_quotas,                        modify => \&modify_quotas,
                     },                      },
Line 523  sub handler { Line 568  sub handler {
                   modify => \&modify_selfenrollment,                    modify => \&modify_selfenrollment,
                  },                   },
         'privacy' =>           'privacy' => 
                  {text   => 'Availability of User Information',                   {text   => 'Role assignments and user privacy',
                   help   => 'Domain_Configuration_User_Privacy',                    help   => 'Domain_Configuration_User_Privacy',
                   header => [{col1 => 'Role assigned in different domain',                    header => [{col1 => 'Role assigned in different domain',
                               col2 => 'Approval options'},                                col2 => 'Approval options'},
Line 559  sub handler { Line 604  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 => 'Encryption of shared secrets',
                               col2 => 'Value',}],                                col2 => 'Settings'},
                                {col1 => 'Rules for shared secrets',
                                 col2 => 'Settings'},
                                {col1 => 'Providers',
                                 col2 => 'Settings',}],
                   print => \&print_ltitools,                    print => \&print_ltitools,
                   modify => \&modify_ltitools,                    modify => \&modify_ltitools,
                  },                   },
Line 613  sub handler { Line 662  sub handler {
                   print => \&print_trust,                    print => \&print_trust,
                   modify => \&modify_trust,                    modify => \&modify_trust,
                  },                   },
           'lti' =>          'lti' =>
                  {text => 'LTI Provider',                   {text => 'LTI Link Protection and LTI Consumers',
                   help => 'Domain_Configuration_LTI_Provider',                    help => 'Domain_Configuration_LTI_Provider',
                   header => [{col1 => 'Setting',                    header => [{col1 => 'Encryption of shared secrets',
                               col2 => 'Value',}],                                col2 => 'Settings'},
                                {col1 => 'Rules for shared secrets',
                                 col2 => 'Settings'},
                                {col1 => 'Link Protectors',
                                 col2 => 'Settings'},
                                {col1 => 'Consumers',
                                 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,
                          },
           'authordefaults' => 
                               {text => 'Authoring Space defaults',
                                help => 'Domain_Configuration_Author_Defaults',
                                header => [{col1 => 'Defaults which can be overridden by Author',
                                            col2 => 'Settings',},
                                           {col1 => 'Defaults which can be overridden by a Dom. Coord.',
                                            col2 => 'Settings',},],
                                print => \&print_authordefaults,
                                modify => \&modify_authordefaults,
                               },
     );      );
     if (keys(%servers) > 1) {      if (keys(%servers) > 1) {
         $prefs{'login'}  = { text   => 'Log-in page options',          $prefs{'login'}  = { text   => 'Log-in page options',
Line 628  sub handler { Line 701  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 => ''},                                          col2 => 'Settings'},
                                        {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 673  $javascript_validations Line 749  $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 814  sub process_changes { Line 892  sub process_changes {
     } elsif ($action eq 'lti') {      } elsif ($action eq 'lti') {
         $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);          $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);
     } elsif ($action eq 'privacy') {      } elsif ($action eq 'privacy') {
         $output = &modify_privacy($dom,%domconfig);          $output = &modify_privacy($dom,$lastactref,%domconfig);
     } elsif ($action eq 'passwords') {      } elsif ($action eq 'passwords') {
         $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);          $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);
     } elsif ($action eq 'wafproxy') {      } elsif ($action eq 'wafproxy') {
         $output = &modify_wafproxy($dom,$action,$lastactref,%domconfig);          $output = &modify_wafproxy($dom,$action,$lastactref,%domconfig);
       } elsif ($action eq 'ipaccess') {
           $output = &modify_ipaccess($dom,$lastactref,%domconfig);
       } elsif ($action eq 'authordefaults') {
           $output = &modify_authordefaults($dom,$lastactref,%domconfig);
     }      }
     return $output;      return $output;
 }  }
Line 832  sub print_config_box { Line 914  sub print_config_box {
     } elsif ($action eq 'defaults') {      } elsif ($action eq 'defaults') {
         $output = &defaults_javascript($settings);           $output = &defaults_javascript($settings); 
     } elsif ($action eq 'passwords') {      } elsif ($action eq 'passwords') {
         $output = &passwords_javascript();          $output = &passwords_javascript($action);
     } elsif ($action eq 'helpsettings') {      } elsif ($action eq 'helpsettings') {
         my (%privs,%levelscurrent);          my (%privs,%levelscurrent);
         my %full=();          my %full=();
Line 847  sub print_config_box { Line 929  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') {      } elsif ($action eq 'ltitools') {
         $output .= &ltitools_javascript($settings);          $output .= &Apache::lonconfigsettings::ltitools_javascript($settings);
     } elsif ($action eq 'lti') {      } elsif ($action eq 'lti') {
         $output .= &lti_javascript($settings);          $output .= &passwords_javascript('ltisecrets')."\n".
                      &lti_javascript($dom,$settings);
     } elsif ($action eq 'proctoring') {      } elsif ($action eq 'proctoring') {
         $output .= &proctoring_javascript($settings);          $output .= &proctoring_javascript($settings);
       } elsif ($action eq 'wafproxy') {
           $output .= &wafproxy_javascript($dom);
       } elsif ($action eq 'autoupdate') {
           $output .= &autoupdate_javascript();
       } elsif ($action eq 'autoenroll') {
           $output .= &autoenroll_javascript();
       } elsif ($action eq 'login') {
           $output .= &saml_javascript();
       } elsif ($action eq 'ipaccess') {
           $output .= &ipaccess_javascript($settings);
       } elsif ($action eq 'authordefaults') {
           $output .= &authordefaults_javascript();
     }      }
     $output .=      $output .=
          '<table class="LC_nested_outer">           '<table class="LC_nested_outer">
Line 874  sub print_config_box { Line 969  sub print_config_box {
         my $leftnobr = '';          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 < 4))) {              (($action eq 'login') && ($numheaders < 5))) {
             $colspan = ' colspan="2"';              $colspan = ' colspan="2"';
         }          }
         if ($action eq 'usersessions') {          if ($action eq 'usersessions') {
Line 896  sub print_config_box { Line 991  sub print_config_box {
             ($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 'ssl') ||              ($action eq 'selfenrollment') || ($action eq 'usersessions') || ($action eq 'ssl') ||
             ($action eq 'directorysrch') || ($action eq 'trust') || ($action eq 'helpsettings') ||              ($action eq 'directorysrch') || ($action eq 'trust') || ($action eq 'helpsettings') ||
             ($action eq 'contacts') || ($action eq 'privacy') || ($action eq 'wafproxy')) {              ($action eq 'contacts') || ($action eq 'privacy') || ($action eq 'wafproxy') ||
               ($action eq 'lti') || ($action eq 'ltitools') || ($action eq 'authordefaults')) {
             $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);              $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'passwords') {          } elsif ($action eq 'passwords') {
             $output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);              $output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);
Line 905  sub print_config_box { Line 1001  sub print_config_box {
         } elsif ($action eq 'scantron') {          } elsif ($action eq 'scantron') {
             $output .= $item->{'print'}->($r,'top',$dom,$confname,$settings,\$rowtotal);              $output .= $item->{'print'}->($r,'top',$dom,$confname,$settings,\$rowtotal);
         } elsif ($action eq 'login') {          } elsif ($action eq 'login') {
             if ($numheaders == 4) {              if ($numheaders == 5) {
                 $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 931  sub print_config_box { Line 1027  sub print_config_box {
         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 'trust') || ($action eq 'contacts') ||              ($action eq 'trust') || ($action eq 'contacts') || ($action eq 'defaults') ||
             ($action eq 'privacy') || ($action eq 'passwords')) {              ($action eq 'privacy') || ($action eq 'passwords') || ($action eq 'lti') ||
               ($action eq 'ltitools')) {
             if ($action eq 'coursecategories') {              if ($action eq 'coursecategories') {
                 $output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);                  $output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);
                 $colspan = ' colspan="2"';                  $colspan = ' colspan="2"';
Line 985  sub print_config_box { Line 1082  sub print_config_box {
              </tr>'."\n";               </tr>'."\n";
                 if ($action eq 'coursecategories') {                  if ($action eq 'coursecategories') {
                     $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);                      $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);
                 } elsif (($action eq 'contacts') || ($action eq 'privacy') || ($action eq 'passwords')) {                  } elsif (($action eq 'contacts') || ($action eq 'privacy') || 
                            ($action eq 'passwords') || ($action eq 'lti')) {
                     if ($action eq 'passwords') {                      if ($action eq 'passwords') {
                         $output .= $item->{'print'}->('lower',$dom,$confname,$settings,\$rowtotal);                          $output .= $item->{'print'}->('lower',$dom,$confname,$settings,\$rowtotal);
                     } else {                      } else {
Line 1018  sub print_config_box { Line 1116  sub print_config_box {
             }              }
             $rowtotal ++;              $rowtotal ++;
         } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||          } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||
                  ($action eq 'defaults') || ($action eq 'directorysrch') ||                   ($action eq 'directorysrch') || ($action eq 'helpsettings') ||
                  ($action eq 'helpsettings') || ($action eq 'wafproxy')) {                   ($action eq 'wafproxy') || ($action eq 'authordefaults')) {
             $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);              $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'scantron') {          } elsif ($action eq 'scantron') {
             $output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal);              $output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal);
Line 1046  sub print_config_box { Line 1144  sub print_config_box {
               <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'.                <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'.
                            $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);                             $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'login') {          } elsif ($action eq 'login') {
             if ($numheaders == 4) {              if ($numheaders == 5) {
                 $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).'                  $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).'
            </table>             </table>
           </td>            </td>
Line 1070  sub print_config_box { Line 1168  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 == 4) {              if ($numheaders == 5) {
                 $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 1082  sub print_config_box { Line 1180  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 1202  sub print_config_box { Line 1320  sub print_config_box {
             $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 'lti') ||                   ($action eq 'proctoring') || ($action eq 'ipaccess')) {
                  ($action eq 'proctoring')) {  
             $output .= $item->{'print'}->($dom,$settings,\$rowtotal);              $output .= $item->{'print'}->($dom,$settings,\$rowtotal);
         }          }
     }      }
Line 1217  sub print_config_box { Line 1334  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);      my ($css_class,$datatable,$switchserver,%lt);
     my %choices = &login_choices();      my %choices = &login_choices();
       if (($caller eq 'help') || ($caller eq 'headtag') || ($caller eq 'saml')) {
           %lt = &login_file_options();
           $switchserver = &check_switchserver($dom,$confname);
       }
     if ($caller eq 'service') {      if ($caller eq 'service') {
         my %servers = &Apache::lonnet::internet_dom_servers($dom);          my %servers = &Apache::lonnet::internet_dom_servers($dom);
         my $choice = $choices{'disallowlogin'};          my $choice = $choices{'disallowlogin'};
Line 1306  sub print_login { Line 1426  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 1347  sub print_login { Line 1468  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 1413  sub print_login { Line 1541  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,%lt,%langchoices);          my ($defaulturl,$defaulttype,%url,%type,%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 1521  sub print_login { Line 1641  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 1552  sub print_login { Line 1664  sub print_login {
             $datatable .= '</td><td><input type="text" name="loginheadtagexempt_'.$lonhost.'" value="'.$exempt.'" /></td></tr>';              $datatable .= '</td><td><input type="text" name="loginheadtagexempt_'.$lonhost.'" value="'.$exempt.'" /></td></tr>';
         }          }
         $datatable .= '</table></td></tr>';          $datatable .= '</table></td></tr>';
       } elsif ($caller eq 'saml') {
           my %domservers = &Apache::lonnet::get_servers($dom);
           $datatable .= '<tr><td colspan="3" style="text-align: left">'.
                         '<table><tr><th>'.$choices{'hostid'}.'</th>'.
                         '<th>'.$choices{'samllanding'}.'</th>'.
                         '<th>'.$choices{'samloptions'}.'</th></tr>'."\n";
           my (%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlwindow,%samlnotsso,%styleon,%styleoff);
           foreach my $lonhost (keys(%domservers)) {
               $samlurl{$lonhost} = '/adm/sso';
               $styleon{$lonhost} = 'display:none';
               $styleoff{$lonhost} = '';
           }
           if ((ref($settings) eq 'HASH') && (ref($settings->{'saml'}) eq 'HASH')) {
               foreach my $lonhost (keys(%{$settings->{'saml'}})) {
                   if (ref($settings->{'saml'}{$lonhost}) eq 'HASH') {
                       $saml{$lonhost} = 1;
                       $samltext{$lonhost} = $settings->{'saml'}{$lonhost}{'text'};
                       $samlimg{$lonhost} = $settings->{'saml'}{$lonhost}{'img'};
                       $samlalt{$lonhost} = $settings->{'saml'}{$lonhost}{'alt'};
                       $samlurl{$lonhost} = $settings->{'saml'}{$lonhost}{'url'};
                       $samltitle{$lonhost} = $settings->{'saml'}{$lonhost}{'title'};
                       $samlwindow{$lonhost} = $settings->{'saml'}{$lonhost}{'window'};
                       $samlnotsso{$lonhost} = $settings->{'saml'}{$lonhost}{'notsso'};
                       $styleon{$lonhost} = '';
                       $styleoff{$lonhost} = 'display:none';
                   } else {
                       $styleon{$lonhost} = 'display:none';
                       $styleoff{$lonhost} = '';
                   }
               }
           }
           my $itemcount = 1;
           foreach my $lonhost (sort(keys(%domservers))) {
               my $samlon = ' ';
               my $samloff = ' checked="checked" ';
               if ($saml{$lonhost}) {
                   $samlon = $samloff;
                   $samloff = ' ';
               }
               my $samlwinon = '';
               my $samlwinoff = ' checked="checked"';
               if ($samlwindow{$lonhost}) {
                   $samlwinon = $samlwinoff;
                   $samlwinoff = '';
               }
               my $css_class = $itemcount%2?' class="LC_odd_row"':'';
               $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.$domservers{$lonhost}.'</span></td>'.
                             '<td><span class="LC_nobreak"><label><input type="radio" name="saml_'.$lonhost.'"'.$samloff.
                             'onclick="toggleSamlOptions(this.form,'."'$lonhost'".');" value="0" />'.
                             &mt('No').'</label>'.('&nbsp;'x2).
                             '<label><input type="radio" name="saml_'.$lonhost.'"'.$samlon.
                             'onclick="toggleSamlOptions(this.form,'."'$lonhost'".');" value="1" />'.
                             &mt('Yes').'</label></span></td>'.
                             '<td id="samloptionson_'.$lonhost.'" style="'.$styleon{$lonhost}.'" width="100%">'.
                             '<table width="100%"><tr><th colspan="3" align="center">'.&mt('SSO').'</th></tr>'.
                             '<tr><th>'.&mt('Text').'</th><th>'.&mt('Image').'</th>'.
                             '<th>'.&mt('Alt Text').'</th></tr>'.
                             '<tr'.$css_class.'><td><input type="text" name="saml_text_'.$lonhost.'" size="20" value="'.
                             $samltext{$lonhost}.'" /></td><td>';
               if ($samlimg{$lonhost}) {
                   $datatable .= '<img src="'.$samlimg{$lonhost}.'" /><br />'.
                                 '<span class="LC_nobreak"><label>'.
                                 '<input type="checkbox" name="saml_img_del" value="'.$lonhost.'" />'.
                                 $lt{'del'}.'</label>&nbsp;'.$lt{'rep'}.'</span>';
               } else {
                   $datatable .= $lt{'upl'};
               }
               $datatable .='<br />';
               if ($switchserver) {
                   $datatable .= &mt('Upload to library server: [_1]',$switchserver);
               } else {
                   $datatable .= '<input type="file" name="saml_img_'.$lonhost.'" />';
               }
               $datatable .= '</td>'.
                             '<td><input type="text" name="saml_alt_'.$lonhost.'" size="25" '.
                             'value="'.$samlalt{$lonhost}.'" /></td></tr></table><br />'.
                             '<table width="100%"><tr><th colspan="3" align="center">'.&mt('SSO').'</th><th align="center">'.
                             '<span class="LC_nobreak">'.&mt('Non-SSO').'</span></th></tr>'.
                             '<tr><th>'.&mt('URL').'</th><th>'.&mt('Tool Tip').'</th>'.
                             '<th>'.&mt('Pop-up if iframe').'</th><th>'.&mt('Text').'</th></tr>'.
                             '<tr'.$css_class.'>'.
                             '<td><input type="text" name="saml_url_'.$lonhost.'" size="30" '.
                             'value="'.$samlurl{$lonhost}.'" /></td>'.
                             '<td><textarea name="saml_title_'.$lonhost.'" rows="3" cols="20">'.
                             $samltitle{$lonhost}.'</textarea></td>'.
                             '<td><label><input type="radio" name="saml_window_'.$lonhost.'" value=""'.$samlwinoff.'>'.
                             &mt('No').'</label>'.('&nbsp;'x2).'<label><input type="radio" '.
                             'name="saml_window_'.$lonhost.'" value="1"'.$samlwinon.'>'.&mt('Yes').'</label></td>'.
                             '<td><input type="text" name="saml_notsso_'.$lonhost.'" size="12" '.
                             'value="'.$samlnotsso{$lonhost}.'" /></td></tr>'.
                             '</table></td>'.
                             '<td id="samloptionsoff_'.$lonhost.'" style="'.$styleoff{$lonhost}.'" width="100%">&nbsp;</td></tr>';
              $itemcount ++;
           }
           $datatable .= '</table></td></tr>';
     }      }
     return $datatable;      return $datatable;
 }  }
Line 1588  sub login_choices { Line 1795  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 1741  sub display_color_options { Line 2143  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);          my ($imgfile,$img_import,$login_hdr_pick,$logincolors,$alttext);
         if ($role eq 'login') {          if ($role eq 'login') {
             if ($img eq 'login') {              if ($img eq 'login') {
                 $login_hdr_pick =                  $login_hdr_pick =
Line 1749  sub display_color_options { Line 2151  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);
             } elsif ($img ne 'domlogo') {              } else {
                 $datatable.= &logo_display_options($img,$defaults,$designs);                  if ($img ne 'domlogo') {
                       $datatable.= &logo_display_options($img,$defaults,$designs);
                   }
                   if (ref($designs->{'alttext'}) eq 'HASH') {
                       $alttext = $designs->{'alttext'}{$img};
                   }
             }              }
         }          }
         $datatable .= '</td>';          $datatable .= '</td>';
Line 1842  sub display_color_options { Line 2249  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 1999  sub print_quotas { Line 2411  sub print_quotas {
     } else {      } else {
         $context = $action;          $context = $action;
     }      }
     my ($datatable,$defaultquota,$authorquota,@usertools,@options,%validations);      my ($datatable,$defaultquota,@usertools,@options,%validations);
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);      my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
     my $typecount = 0;      my $typecount = 0;
     my ($css_class,%titles);      my ($css_class,%titles);
Line 2013  sub print_quotas { Line 2425  sub print_quotas {
         @options = ('norequest','approval','automatic');          @options = ('norequest','approval','automatic');
         %titles = &authorrequest_titles();          %titles = &authorrequest_titles();
     } else {      } else {
         @usertools = ('aboutme','blog','webdav','portfolio');          @usertools = ('aboutme','blog','portfolio','timezone');
         %titles = &tool_titles();          %titles = &tool_titles();
     }      }
     if (ref($types) eq 'ARRAY') {      if (ref($types) eq 'ARRAY') {
         foreach my $type (@{$types}) {          foreach my $type (@{$types}) {
             my ($currdefquota,$currauthorquota);              my $currdefquota;
             unless (($context eq 'requestcourses') ||              unless (($context eq 'requestcourses') ||
                     ($context eq 'requestauthor')) {                      ($context eq 'requestauthor')) {
                 if (ref($settings) eq 'HASH') {                  if (ref($settings) eq 'HASH') {
Line 2027  sub print_quotas { Line 2439  sub print_quotas {
                     } else {                      } else {
                         $currdefquota = $settings->{$type};                          $currdefquota = $settings->{$type};
                     }                      }
                     if (ref($settings->{authorquota}) eq 'HASH') {  
                         $currauthorquota = $settings->{authorquota}->{$type};  
                     }  
                 }                  }
             }              }
             if (defined($usertypes->{$type})) {              if (defined($usertypes->{$type})) {
Line 2117  sub print_quotas { Line 2526  sub print_quotas {
                         }                          }
                     } else {                      } else {
                         my $checked = 'checked="checked" ';                          my $checked = 'checked="checked" ';
                           if ($item eq 'timezone') {
                               $checked = '';
                           }
                         if (ref($settings) eq 'HASH') {                          if (ref($settings) eq 'HASH') {
                             if (ref($settings->{$item}) eq 'HASH') {                              if (ref($settings->{$item}) eq 'HASH') {
                                 if ($settings->{$item}->{$type} == 0) {                                  if (!$settings->{$item}->{$type}) {
                                     $checked = '';                                      $checked = '';
                                 } elsif ($settings->{$item}->{$type} == 1) {                                  } elsif ($settings->{$item}->{$type} == 1) {
                                     $checked =  'checked="checked" ';                                      $checked =  'checked="checked" ';
Line 2144  sub print_quotas { Line 2556  sub print_quotas {
                         ($context eq 'requestauthor')) {                          ($context eq 'requestauthor')) {
                     $datatable .=                       $datatable .= 
                               '<td class="LC_right_item">'.                                '<td class="LC_right_item">'.
                               '<span class="LC_nobreak">'.&mt('Portfolio').':&nbsp;'.                                '<span class="LC_nobreak">'.
                               '<input type="text" name="quota_'.$type.                                '<input type="text" name="quota_'.$type.
                               '" value="'.$currdefquota.                                '" value="'.$currdefquota.
                               '" size="5" /></span>'.('&nbsp;' x 2).  
                               '<span class="LC_nobreak">'.&mt('Authoring').':&nbsp;'.  
                               '<input type="text" name="authorquota_'.$type.  
                               '" value="'.$currauthorquota.  
                               '" size="5" /></span></td>';                                '" size="5" /></span></td>';
                 }                  }
                 $datatable .= '</tr>';                  $datatable .= '</tr>';
Line 2159  sub print_quotas { Line 2567  sub print_quotas {
     }      }
     unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {      unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
         $defaultquota = '20';          $defaultquota = '20';
         $authorquota = '500';  
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if (ref($settings->{'defaultquota'}) eq 'HASH') {              if (ref($settings->{'defaultquota'}) eq 'HASH') {
                 $defaultquota = $settings->{'defaultquota'}->{'default'};                  $defaultquota = $settings->{'defaultquota'}->{'default'};
             } elsif (defined($settings->{'default'})) {              } elsif (defined($settings->{'default'})) {
                 $defaultquota = $settings->{'default'};                  $defaultquota = $settings->{'default'};
             }              }
             if (ref($settings->{'authorquota'}) eq 'HASH') {  
                 $authorquota = $settings->{'authorquota'}->{'default'};  
             }  
         }          }
     }      }
     $typecount ++;      $typecount ++;
Line 2280  sub print_quotas { Line 2684  sub print_quotas {
     $datatable .= '</td>';      $datatable .= '</td>';
     unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {      unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
         $datatable .= '<td class="LC_right_item">'.          $datatable .= '<td class="LC_right_item">'.
                       '<span class="LC_nobreak">'.&mt('Portfolio').':&nbsp;'.                        '<span class="LC_nobreak">'.
                       '<input type="text" name="defaultquota" value="'.                        '<input type="text" name="defaultquota" value="'.
                       $defaultquota.'" size="5" /></span>'.('&nbsp;' x2).                        $defaultquota.'" size="5" /></span></td>';
                       '<span class="LC_nobreak">'.&mt('Authoring').':&nbsp;'.  
                       '<input type="text" name="authorquota" value="'.  
                       $authorquota.'" size="5" /></span></td>';  
     }      }
     $datatable .= '</tr>';      $datatable .= '</tr>';
     $typecount ++;      $typecount ++;
Line 2844  function toggleLTITools(form,setting,ite Line 3245  function toggleLTITools(form,setting,ite
 ENDSCRIPT  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 proctoring_javascript {  sub proctoring_javascript {
     my ($settings) = @_;      my ($settings) = @_;
     my (%ordered,$total,%jstext);      my (%ordered,$total,%jstext);
Line 2941  ENDSCRIPT Line 3457  ENDSCRIPT
   
   
 sub lti_javascript {  sub lti_javascript {
     my ($settings) = @_;      my ($dom,$settings) = @_;
     my $togglejs = &lti_toggle_js();      my $togglejs = &lti_toggle_js($dom);
       my $linkprot_js = &Apache::courseprefs::linkprot_javascript();
     unless (ref($settings) eq 'HASH') {      unless (ref($settings) eq 'HASH') {
         return $togglejs;          return $togglejs.'
   <script type="text/javascript">
   // <![CDATA[
   
   '.$linkprot_js.'
   
   // ]]>
   </script>
   ';
     }      }
     my (%ordered,$total,%jstext);      my (%ordered,$total,%jstext);
     $total = 0;      $total = scalar(keys(%{$settings}));
     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'};
               if ($num eq '') {
                   $num = $total - 1;
               }
             $ordered{$num} = $item;              $ordered{$num} = $item;
         }          }
     }      }
     $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});
Line 3004  $jstext Line 3531  $jstext
     }      }
     return;      return;
 }  }
   
   $linkprot_js
   
 // ]]>  // ]]>
 </script>  </script>
   
Line 3013  ENDSCRIPT Line 3543  ENDSCRIPT
 }  }
   
 sub lti_toggle_js {  sub lti_toggle_js {
       my ($dom) = @_;
     my %lcauthparmtext = &Apache::lonlocal::texthash (      my %lcauthparmtext = &Apache::lonlocal::texthash (
                             localauth => 'Local auth argument',                              localauth => 'Local auth argument',
                             krb       => 'Kerberos domain',                              krb       => 'Kerberos domain',
                          );                           );
       my $crsincalert = &mt('"User\'s identity sent" needs to be set to "Yes" first,[_1] before setting "Course\'s identity sent" to "Yes"',"\n");
       &js_escape(\$crsincalert);
       my %servers = &Apache::lonnet::get_servers($dom,'library');
       my $primary = &Apache::lonnet::domain($dom,'primary');
       my $course_servers = "'".join("','",keys(%servers))."'";
     return <<"ENDSCRIPT";      return <<"ENDSCRIPT";
 <script type="text/javascript">  <script type="text/javascript">
 // <![CDATA[  // <![CDATA[
   
 function toggleLTI(form,setting,item) {  function toggleLTI(form,setting,item) {
     if (setting == 'requser') {      if ((setting == 'requser') || (setting == 'crsinc')) {
         var fieldsets = document.getElementsByClassName('ltioption_'+item);          var usrfieldsets = document.getElementsByClassName('ltioption_usr_'+item);
         if (fieldsets.length) {          var setvis = '';
             var radioname = 'lti_'+setting+'_'+item;          var radioname = 'lti_requser_'+item;
           var num = form.elements[radioname].length;
           if (num) {
               for (var i=0; i<num; i++) {
                   if (form.elements[radioname][i].checked) {
                       if (form.elements[radioname][i].value == '1') {
                           setvis = 1;
                           break;
                       }
                   }
               }
           }
           if (usrfieldsets.length) {
               for (var j=0; j<usrfieldsets.length; j++) {
                   if (setvis) {
                       usrfieldsets[j].style.display = 'block';
                   } else {
                       usrfieldsets[j].style.display = 'none';
                   }
               }
           }
           var crsfieldsets = document.getElementsByClassName('ltioption_crs_'+item);
           if (crsfieldsets.length) {
               radioname = 'lti_crsinc_'+item;
             var num = form.elements[radioname].length;              var num = form.elements[radioname].length;
             if (num) {              if (num) {
                 var setvis = '';                  var crsvis = '';
                 for (var i=0; i<num; i++) {                  for (var i=0; i<num; i++) {
                     if (form.elements[radioname][i].checked) {                      if (form.elements[radioname][i].checked) {
                         if (form.elements[radioname][i].value == '1') {                          if (form.elements[radioname][i].value == '1') {
                            setvis = 1;                              if (setvis == '') {
                            break;                                  if (setting == 'crsinc'){
                                       alert("$crsincalert");
                                       form.elements[radioname][0].checked = true;
                                   }
                               } else {
                                   crsvis = 1;
                               }
                               break;
                         }                          }
                     }                      }
                 }                  }
                 for (var j=0; j<fieldsets.length; j++) {                  setvis = crsvis;
                     if (setvis) {              }
                         fieldsets[j].style.display = 'block';              for (var j=0; j<crsfieldsets.length; j++) {
                     } else {                  if (setvis) {
                         fieldsets[j].style.display = 'none';                      crsfieldsets[j].style.display = 'block';
                     }                  } else {
                       crsfieldsets[j].style.display = 'none';
                 }                  }
             }              }
         }          }
Line 3084  function toggleLTI(form,setting,item) { Line 3651  function toggleLTI(form,setting,item) {
                            break;                             break;
                        }                         }
                    }                     }
                }                  }
             }              }
             if (!setvis) {              if (!setvis) {
                 if (document.getElementById(divid)) {                  if (document.getElementById(divid)) {
Line 3161  function toggleLTI(form,setting,item) { Line 3728  function toggleLTI(form,setting,item) {
         var divid = 'lti_menufield_'+item;          var divid = 'lti_menufield_'+item;
         var setvis = '';          var setvis = '';
         for (var i=0; i<menus.length; i++) {          for (var i=0; i<menus.length; i++) {
             var radioname = menus[i];                var radioname = menus[i];
             var num = form.elements[radioname].length;              var num = form.elements[radioname].length;
             if (num) {              if (num) {
                 for (var j=0; j<num; j++) {                  for (var j=0; j<num; j++) {
Line 3188  function toggleLTI(form,setting,item) { Line 3755  function toggleLTI(form,setting,item) {
     }      }
     return;      return;
 }  }
   
   // ]]>
   </script>
   
   ENDSCRIPT
   }
   
   sub autoupdate_javascript {
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   function toggleLastActiveDays(form) {
       var radioname = 'lastactive';
       var divid = 'lastactive_div';
       var num = form.elements[radioname].length;
       if (num) {
           var setvis = '';
           for (var i=0; i<num; i++) {
               if (form.elements[radioname][i].checked) {
                   if (form.elements[radioname][i].value == '1') {
                       if (document.getElementById(divid)) {
                           document.getElementById(divid).style.display = 'inline-block';
                       }
                       setvis = 1;
                   }
                   break;
               }
           }
           if (!setvis) {
               if (document.getElementById(divid)) {
                   document.getElementById(divid).style.display = 'none';
               }
           }
       }
       return;
   }
   // ]]>
   </script>
   
   ENDSCRIPT
   }
   
   sub autoenroll_javascript {
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   function toggleFailsafe(form) {
       var radioname = 'autoenroll_failsafe';
       var divid = 'autoenroll_failsafe_div';
       var num = form.elements[radioname].length;
       if (num) {
           var setvis = '';
           for (var i=0; i<num; i++) {
               if (form.elements[radioname][i].checked) {
                   if ((form.elements[radioname][i].value == 'zero') || (form.elements[radioname][i].value == 'any')) {
                       if (document.getElementById(divid)) {
                           document.getElementById(divid).style.display = 'inline-block';
                       }
                       setvis = 1;
                   }
                   break;
               }
           }
           if (!setvis) {
               if (document.getElementById(divid)) {
                   document.getElementById(divid).style.display = 'none';
               }
           }
       }
       return;
   }
   // ]]>
   </script>
   
   ENDSCRIPT
   }
   
   sub saml_javascript {
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   function toggleSamlOptions(form,hostid) {
       var radioname = 'saml_'+hostid;
       var tablecellon = 'samloptionson_'+hostid;
       var tablecelloff = 'samloptionsoff_'+hostid;
       var num = form.elements[radioname].length;
       if (num) {
           var setvis = '';
           for (var i=0; i<num; i++) {
               if (form.elements[radioname][i].checked) {
                   if (form.elements[radioname][i].value == '1') {
                       if (document.getElementById(tablecellon)) {
                           document.getElementById(tablecellon).style.display='';
                       }
                       if (document.getElementById(tablecelloff)) {
                           document.getElementById(tablecelloff).style.display='none';
                       }
                       setvis = 1;
                   }
                   break;
               }
           }
           if (!setvis) {
               if (document.getElementById(tablecellon)) {
                   document.getElementById(tablecellon).style.display='none';
               }
               if (document.getElementById(tablecelloff)) {
                   document.getElementById(tablecelloff).style.display='';
               }
           }
       }
       return;
   }
   // ]]>
   </script>
   
   ENDSCRIPT
   }
   
   sub ipaccess_javascript {
       my ($settings) = @_;
       my (%ordered,$total,%jstext);
       $total = 0;
       if (ref($settings) eq 'HASH') {
           foreach my $item (keys(%{$settings})) {
               if (ref($settings->{$item}) eq 'HASH') {
                   my $num = $settings->{$item}{'order'};
                   $ordered{$num} = $item;
               }
           }
           $total = scalar(keys(%{$settings}));
       }
       my @jsarray = ();
       foreach my $item (sort {$a <=> $b } (keys(%ordered))) {
           push(@jsarray,$ordered{$item});
       }
       my $jstext = '    var ipaccess = Array('."'".join("','",@jsarray)."'".');'."\n";
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   function reorderIPaccess(form,item) {
       var changedVal;
   $jstext
       var newpos = 'ipaccess_pos_add';
       var maxh = 1 + $total;
       var current = new Array;
       var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;
       if (item == newpos) {
           changedVal = newitemVal;
       } else {
           changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;
           current[newitemVal] = newpos;
       }
       for (var i=0; i<ipaccess.length; i++) {
           var elementName = 'ipaccess_pos_'+ipaccess[i];
           if (elementName != item) {
               if (form.elements[elementName]) {
                   var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
                   current[currVal] = elementName;
               }
           }
       }
       var oldVal;
       for (var j=0; j<maxh; j++) {
           if (current[j] == undefined) {
               oldVal = j;
           }
       }
       if (oldVal < changedVal) {
           for (var k=oldVal+1; k<=changedVal ; k++) {
              var elementName = current[k];
              form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;
           }
       } else {
           for (var k=changedVal; k<oldVal; k++) {
               var elementName = current[k];
               form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;
           }
       }
       return;
   }
   // ]]>
   </script>
   
   ENDSCRIPT
   }
   
   sub authordefaults_javascript {
       my %alert = &Apache::lonlocal::texthash (
                       reqd => 'Warning: at least one editor needs to be available.',
                       rest => 'Unchecking this editor disallowed while others unchecked.',
       );
       &js_escape(\%alert);
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   
   function checkEditors(form,checkbox,current) {
       if (form.elements[checkbox].length != undefined) {
           var count = 0;
           for (var i=0; i<form.elements[checkbox].length; i++) {
               if (form.elements[checkbox][i].checked) {
                   count ++;
               }
           }
           if (count == 0) {
               if (current.type =='radio') {
                   current.checked = true;
                   alert('$alert{reqd}\\n$alert{rest}');
               }
           }
       }
       return;
   }
 // ]]>  // ]]>
 </script>  </script>
   
Line 3197  ENDSCRIPT Line 3978  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,$failsafe);      my ($defdom,$runon,$runoff,$coownerson,$coownersoff,
           $failsafe,$autofailsafe,$failsafesty,%failsafechecked);
       $failsafesty = 'none';
       %failsafechecked = (
           off => ' checked="checked"',
       );
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if (exists($settings->{'run'})) {          if (exists($settings->{'run'})) {
             if ($settings->{'run'} eq '0') {              if ($settings->{'run'} eq '0') {
Line 3231  sub print_autoenroll { Line 4017  sub print_autoenroll {
         if (exists($settings->{'sender_domain'})) {          if (exists($settings->{'sender_domain'})) {
             $defdom = $settings->{'sender_domain'};              $defdom = $settings->{'sender_domain'};
         }          }
         if (exists($settings->{'autofailsafe'})) {          if (exists($settings->{'failsafe'})) {
             $failsafe = $settings->{'autofailsafe'};              $failsafe = $settings->{'failsafe'};
               if ($failsafe eq 'zero') {
                   $failsafechecked{'zero'} = ' checked="checked"';
                   $failsafechecked{'off'} = '';
                   $failsafesty = 'inline-block';
               } elsif ($failsafe eq 'any') {
                   $failsafechecked{'any'} = ' checked="checked"';
                   $failsafechecked{'off'} = '';
               }
               $autofailsafe = $settings->{'autofailsafe'};
           } elsif (exists($settings->{'autofailsafe'})) {
               $autofailsafe = $settings->{'autofailsafe'};
               if ($autofailsafe ne '') {
                   $failsafechecked{'zero'} = ' checked="checked"';
                   $failsafe = 'zero';
                   $failsafechecked{'off'} = '';
               }
         }          }
     } else {      } else {
         if ($autorun) {          if ($autorun) {
Line 3271  sub print_autoenroll { Line 4073  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_right_item"><span class="LC_nobreak">'.                    '<td class="LC_left_item"><span class="LC_nobreak">'.
                   '<input type="text" name="autoenroll_failsafe"'.                    '<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; '.
                   ' value="'.$failsafe.'" size="4" /></span></td></tr>';                    '<span class="LC_nobreak"><label><input type="radio" name="autoenroll_failsafe" value="zero" onclick="toggleFailsafe(this.form)"'.$failsafechecked{'zero'}.' />'.&mt('Retrieved section enrollment is zero').'</label></span><br />'.
                     '<span class="LC_nobreak"><label><input type="radio" name="autoenroll_failsafe" value="any" onclick="toggleFailsafe(this.form)"'.$failsafechecked{'any'}.' />'.&mt('Retrieved section enrollment is zero or greater').'</label></span>'.
                     '<div class="LC_floatleft" style="display:'.$failsafesty.';" id="autoenroll_failsafe_div">'.
                     '<span class="LC_nobreak">'.
                     &mt('Threshold for number of students in section to drop: [_1]',
                         '<input type="text" name="autoenroll_autofailsafe" value="'.$autofailsafe.'" size="4" />').
                     '</span></div></td></tr>';
     $$rowtotal += 4;      $$rowtotal += 4;
     return $datatable;      return $datatable;
 }  }
   
 sub print_autoupdate {  sub print_autoupdate {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my $datatable;      my ($enable,$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 = ' ';  
             }  
         }          }
         my %title = (          $enable = '<tr class="LC_odd_row">'.
                    run => 'Auto-update active?',                    '<td>'.$choices{'run'}.'</td>'.
                    classlists => 'Update information in classlists?',                    '<td class="LC_left_item"><span class="LC_nobreak"><label>'.
                     );  
         $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"'.
                   $updateon.' value="1" />'.&mt('Yes').'</label>&nbsp;'.                    $updateoff.'value="0" />'.&mt('No').'</label>&nbsp;'.
                   '<label><input type="radio" name="autoupdate_run"'.                    '<label><input type="radio" name="autoupdate_run"'.
                   $updateoff.'value="0" />'.&mt('No').'</label></span></td>'.                    $updateon.'value="1" />'.&mt('Yes').'</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>';
         $$rowtotal += 2;          my @toggles = ('classlists','unexpired');
           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 3811  sub print_contacts { Line 4646  sub print_contacts {
                 map {$excluded{$_} = 1; } @{$lonstatus{'excluded'}};                  map {$excluded{$_} = 1; } @{$lonstatus{'excluded'}};
             }              }
         }          }
         foreach my $item ('errorthreshold','errorsysmail') {           foreach my $item ('errorthreshold','errorsysmail') {
             $css_class = $rownum%2?' class="LC_odd_row"':'';              $css_class = $rownum%2?' class="LC_odd_row"':'';
             $datatable .= '<tr'.$css_class.'>'.              $datatable .= '<tr'.$css_class.'>'.
                           '<td class="LC_left_item"><span class="LC_nobreak">'.                            '<td class="LC_left_item"><span class="LC_nobreak">'.
Line 3893  sub print_contacts { Line 4728  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 3905  sub print_contacts { Line 4740  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 3972  sub overridden_helpdesk { Line 4806  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 4051  function toggleHelpdeskRow(form,checkbox Line 4885  function toggleHelpdeskRow(form,checkbox
     return;      return;
 }  }
   
   
 // ]]>  // ]]>
 </script>  </script>
   
Line 4444  sub helpdeskroles_access { Line 5277  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) = @_;          $additional,$align,$firstval) = @_;
     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 4484  sub radiobutton_prefs { Line 5317  sub radiobutton_prefs {
         } else {          } else {
             $datatable .= '<td class="LC_right_item">';              $datatable .= '<td class="LC_right_item">';
         }          }
         $datatable .=          $datatable .= '<span class="LC_nobreak">';
             '<span class="LC_nobreak">'.          if ($firstval eq 'no') {
             '<label><input type="radio" name="'.              $datatable .=
             $item.'" '.$checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').                  '<label><input type="radio" name="'.
             '</label>&nbsp;<label><input type="radio" name="'.$item.'" '.                  $item.'" '.$checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').
             $checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').'</label>'.                  '</label>&nbsp;<label><input type="radio" name="'.$item.'" '.
             '</span>'.$additional.                  $checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').'</label>';
             '</td>'.          } else {
             '</tr>';              $datatable .=
                   '<label><input type="radio" name="'.
                   $item.'" '.$checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').
                   '</label>&nbsp;<label><input type="radio" name="'.$item.'" '.
                   $checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').'</label>';
           }
           $datatable .= '</span>'.$additional.'</td></tr>';
         $itemcount ++;          $itemcount ++;
     }      }
     return ($datatable,$itemcount);      return ($datatable,$itemcount);
 }  }
   
 sub print_ltitools {  sub print_ltitools {
     my ($dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my $rownum = 0;      my (%rules,%encrypt,%privkeys,%linkprot);
     my $css_class;  
     my $itemcount = 1;  
     my $maxnum = 0;  
     my %ordered;  
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         foreach my $item (keys(%{$settings})) {          if ($position eq 'top') {
             if (ref($settings->{$item}) eq 'HASH') {              if (exists($settings->{'encrypt'})) {
                 my $num = $settings->{$item}{'order'};                  if (ref($settings->{'encrypt'}) eq 'HASH') {
                 $ordered{$num} = $item;                      foreach my $key (keys(%{$settings->{'encrypt'}})) {
             }                          $encrypt{'toolsec_'.$key} = $settings->{'encrypt'}{$key};
         }  
     }  
     my $confname = $dom.'-domainconfig';  
     my $switchserver = &check_switchserver($dom,$confname);  
     my $maxnum = scalar(keys(%ordered));  
     my $datatable;  
     my %lt = &ltitools_names();  
     my @courseroles = ('cc','in','ta','ep','st');  
     my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner);  
     my @fields = ('fullname','firstname','lastname','email','roles','user');  
     if (keys(%ordered)) {  
         my @items = sort { $a <=> $b } keys(%ordered);  
         for (my $i=0; $i<@items; $i++) {  
             $css_class = $itemcount%2?' class="LC_odd_row"':'';  
             my $item = $ordered{$items[$i]};  
             my ($title,$key,$secret,$url,$lifetime,$imgsrc,%sigsel);  
             if (ref($settings->{$item}) eq 'HASH') {  
                 $title = $settings->{$item}->{'title'};  
                 $url = $settings->{$item}->{'url'};  
                 $key = $settings->{$item}->{'key'};  
                 $secret = $settings->{$item}->{'secret'};  
                 $lifetime = $settings->{$item}->{'lifetime'};  
                 my $image = $settings->{$item}->{'image'};  
                 if ($image ne '') {  
                     $imgsrc = '<img src="'.$image.'" alt="'.&mt('Tool Provider icon').'" />';  
                 }  
                 if ($settings->{$item}->{'sigmethod'} eq 'HMAC-256') {  
                     $sigsel{'HMAC-256'} = ' selected="selected"';  
                 } else {  
                     $sigsel{'HMAC-SHA1'} = ' selected="selected"';  
                 }  
             }  
             my $chgstr = ' onchange="javascript:reorderLTITools(this.form,'."'ltitools_".$item."'".');"';  
             $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'  
                          .'<select name="ltitools_'.$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="ltitools_del" value="'.$item.'" />'.  
                 &mt('Delete?').'</label></span></td>'.  
                 '<td colspan="2">'.  
                 '<fieldset><legend>'.&mt('Required settings').'</legend>'.  
                 '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="20" name="ltitools_title_'.$i.'" value="'.$title.'" /></span> '.  
                 ('&nbsp;'x2).  
                 '<span class="LC_nobreak">'.$lt{'version'}.':<select name="ltitools_version_'.$i.'">'.  
                 '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '.  
                 ('&nbsp;'x2).  
                 '<span class="LC_nobreak">'.$lt{'msgtype'}.':<select name="ltitools_msgtype_'.$i.'">'.  
                 '<option value="basic-lti-launch-request" selected="selected">Launch</option></select></span> '.  
                 ('&nbsp;'x2).  
                 '<span class="LC_nobreak">'.$lt{'sigmethod'}.':<select name="ltitools_sigmethod_'.$i.'">'.  
                 '<option value="HMAC-SHA1"'.$sigsel{'HMAC-SHA1'}.'>HMAC-SHA1</option>'.  
                 '<option value="HMAC-SHA256"'.$sigsel{'HMAC-SHA256'}.'>HMAC-SHA256</option></select></span>'.  
                 '<br /><br />'.  
                 '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="40" name="ltitools_url_'.$i.'"'.  
                 ' value="'.$url.'" /></span>'.  
                 ('&nbsp;'x2).  
                 '<span class="LC_nobreak">'.$lt{'key'}.':'.  
                 '<input type="text" size="25" name="ltitools_key_'.$i.'" value="'.$key.'" /></span> '.  
                 ('&nbsp;'x2).  
                 '<span class="LC_nobreak">'.$lt{'lifetime'}.':'.  
                 '<input type="text" size="5" name="ltitools_lifetime_'.$i.'" value="'.$lifetime.'" /></span> '.  
                 ('&nbsp;'x2).  
                 '<span class="LC_nobreak">'.$lt{'secret'}.':'.  
                 '<input type="password" size="20" name="ltitools_secret_'.$i.'" value="'.$secret.'" />'.  
                 '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltitools_secret_'.$i.'.type='."'text'".' } else { this.form.ltitools_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.  
                 '<input type="hidden" name="ltitools_id_'.$i.'" value="'.$item.'" /></span>'.  
                 '</fieldset>'.  
                 '<fieldset><legend>'.&mt('Optional settings').'</legend>'.  
                 '<span class="LC_nobreak">'.&mt('Display target:');  
             my %currdisp;  
             if (ref($settings->{$item}->{'display'}) eq 'HASH') {  
                 if ($settings->{$item}->{'display'}->{'target'} eq 'window') {  
                     $currdisp{'window'} = ' checked="checked"';  
                 } elsif ($settings->{$item}->{'display'}->{'target'} eq 'tab') {  
                     $currdisp{'tab'} = ' checked="checked"';  
                 } else {  
                     $currdisp{'iframe'} = ' checked="checked"';  
                 }  
                 if ($settings->{$item}->{'display'}->{'width'} =~ /^(\d+)$/) {  
                     $currdisp{'width'} = $1;  
                 }  
                 if ($settings->{$item}->{'display'}->{'height'} =~ /^(\d+)$/) {  
                      $currdisp{'height'} = $1;  
                 }  
                 $currdisp{'linktext'} = $settings->{$item}->{'display'}->{'linktext'};  
                 $currdisp{'explanation'} = $settings->{$item}->{'display'}->{'explanation'};  
             } else {  
                 $currdisp{'iframe'} = ' checked="checked"';  
             }  
             foreach my $disp ('iframe','tab','window') {  
                 $datatable .= '<label><input type="radio" name="ltitools_target_'.$i.'" value="'.$disp.'"'.$currdisp{$disp}.' />'.  
                               $lt{$disp}.'</label>'.('&nbsp;'x2);  
             }  
             $datatable .= ('&nbsp;'x4);  
             foreach my $dimen ('width','height') {  
                 $datatable .= '<label>'.$lt{$dimen}.'&nbsp;'.  
                               '<input type="text" name="ltitools_'.$dimen.'_'.$i.'" size="5" value="'.$currdisp{$dimen}.'" /></label>'.  
                               ('&nbsp;'x2);  
             }  
             $datatable .= '</span><br />'.  
                           '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'.  
                           '<input type="text" name="ltitools_linktext_'.$i.'" size="25" value="'.$currdisp{'linktext'}.'" /></div>'.  
                           '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'.  
                           '<textarea name="ltitools_explanation_'.$i.'" rows="5" cols="40">'.$currdisp{'explanation'}.  
                           '</textarea></div><div style=""></div><br />';  
             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;';  
             if ($imgsrc) {  
                 $datatable .= $imgsrc.  
                               '<label><input type="checkbox" name="ltitools_image_del"'.  
                               ' value="'.$item.'" />'.&mt('Delete?').'</label></span> '.  
                               '<span class="LC_nobreak">&nbsp;'.&mt('Replace:').'&nbsp;';  
             } else {  
                 $datatable .= '('.&mt('if larger than 21x21 pixels, image will be scaled').')&nbsp;';  
             }  
             if ($switchserver) {  
                 $datatable .= &mt('Upload to library server: [_1]',$switchserver);  
             } else {  
                 $datatable .= '<input type="file" name="ltitools_image_'.$i.'" value="" />';  
             }  
             $datatable .= '</span></fieldset>';  
             my (%checkedfields,%rolemaps,$userincdom);  
             if (ref($settings->{$item}) eq 'HASH') {  
                 if (ref($settings->{$item}->{'fields'}) eq 'HASH') {  
                     %checkedfields = %{$settings->{$item}->{'fields'}};  
                 }  
                 $userincdom = $settings->{$item}->{'incdom'};  
                 if (ref($settings->{$item}->{'roles'}) eq 'HASH') {  
                     %rolemaps = %{$settings->{$item}->{'roles'}};  
                     $checkedfields{'roles'} = 1;  
                 }  
             }  
             $datatable .= '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'.  
                           '<span class="LC_nobreak">';  
             my $userfieldstyle = 'display:none;';  
             my $seluserdom = '';  
             my $unseluserdom = ' selected="selected"';  
             foreach my $field (@fields) {  
                 my ($checked,$onclick,$id,$spacer);  
                 if ($checkedfields{$field}) {  
                     $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>'.  
                               '<input type="checkbox" name="ltitools_fields_'.$i.'" value="'.$field.'"'.$id.$checked.$onclick.' />'.  
                               $lt{$field}.'</label>'.$spacer;  
             }              }
             $datatable .= '</span>';              if (exists($settings->{'private'})) {
             $datatable .= '<div style="'.$userfieldstyle.'" id="ltitools_user_div_'.$i.'">'.                  if (ref($settings->{'private'}) eq 'HASH') {
                           '<span class="LC_nobreak"> : '.                      if (ref($settings->{'private'}) eq 'HASH') {
                           '<select name="ltitools_userincdom_'.$i.'">'.                          if (ref($settings->{'private'}{'keys'}) eq 'ARRAY') {
                           '<option value="">'.&mt('Select').'</option>'.                              map { $privkeys{$_} = 1; } (@{$settings->{'private'}{'keys'}});
                           '<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>';  
             foreach my $role (@courseroles) {  
                 my ($selected,$selectnone);  
                 if (!$rolemaps{$role}) {  
                     $selectnone = ' selected="selected"';  
                 }  
                 $datatable .= '<td style="text-align: center">'.   
                               &Apache::lonnet::plaintext($role,'Course').'<br />'.  
                               '<select name="ltitools_roles_'.$role.'_'.$i.'">'.  
                               '<option value=""'.$selectnone.'>'.&mt('Select').'</option>';  
                 foreach my $ltirole (@ltiroles) {  
                     unless ($selectnone) {  
                         if ($rolemaps{$role} eq $ltirole) {  
                             $selected = ' selected="selected"';  
                         } else {  
                             $selected = '';  
                         }                          }
                     }                      }
                     $datatable .= '<option value="'.$ltirole.'"'.$selected.'>'.$ltirole.'</option>';  
                 }                  }
                 $datatable .= '</select></td>';  
             }              }
             $datatable .= '</tr></table></fieldset>';          } elsif ($position eq 'middle') {
             my %courseconfig;              if (exists($settings->{'rules'})) {
             if (ref($settings->{$item}) eq 'HASH') {                  if (ref($settings->{'rules'}) eq 'HASH') {
                 if (ref($settings->{$item}->{'crsconf'}) eq 'HASH') {                      %rules = %{$settings->{'rules'}};
                     %courseconfig = %{$settings->{$item}->{'crsconf'}};  
                 }  
             }  
             $datatable .= '<fieldset><legend>'.&mt('Configurable in course').'</legend><span class="LC_nobreak">';  
             foreach my $item ('label','title','target','linktext','explanation','append') {  
                 my $checked;  
                 if ($courseconfig{$item}) {  
                     $checked = ' checked="checked"';  
                 }                  }
                 $datatable .= '<label>'.  
                        '<input type="checkbox" name="ltitools_courseconfig_'.$i.'" value="'.$item.'"'.$checked.' />'.  
                        $lt{'crs'.$item}.'</label>&nbsp; '."\n";  
             }              }
             $datatable .= '</span></fieldset>'.          } else {
                           '<fieldset><legend>'.&mt('Custom items sent on launch').'</legend>'.              foreach my $key ('encrypt','private','rules') {
                           '<table><tr><th>'.&mt('Action').'</th><th>'.&mt('Name').'</th><th>'.&mt('Value').'</th></tr>';                  if (exists($settings->{$key})) {
             if (ref($settings->{$item}->{'custom'}) eq 'HASH') {                      delete($settings->{$key});
                 my %custom = %{$settings->{$item}->{'custom'}};  
                 if (keys(%custom) > 0) {  
                     foreach my $key (sort(keys(%custom))) {  
                         $datatable .= '<tr><td><span class="LC_nobreak">'.  
                                       '<label><input type="checkbox" name="ltitools_customdel_'.$i.'" value="'.  
                                       $key.'" />'.&mt('Delete').'</label></span></td><td>'.$key.'</td>'.  
                                       '<td><input type="text" name="ltitools_customval_'.$key.'_'.$i.'"'.  
                                       ' value="'.$custom{$key}.'" /></td></tr>';  
                     }  
                 }                  }
             }              }
             $datatable .= '<tr><td><span class="LC_nobreak">'.  
                           '<label><input type="checkbox" name="ltitools_customadd" value="'.$i.'" />'.  
                           &mt('Add').'</label></span></td><td><input type="text" name="ltitools_custom_name_'.$i.'" />'.  
                           '</td><td><input type="text" name="ltitools_custom_value_'.$i.'" /></td></tr>';  
             $datatable .= '</table></fieldset></td></tr>'."\n";  
             $itemcount ++;  
         }          }
     }      }
     $css_class = $itemcount%2?' class="LC_odd_row"':'';      my $datatable;
     my $chgstr = ' onchange="javascript:reorderLTITools(this.form,'."'ltitools_add_pos'".');"';      my $itemcount = 1;
     $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".      if ($position eq 'top') {
                   '<input type="hidden" name="ltitools_maxnum" value="'.$maxnum.'" />'."\n".          $datatable = &secrets_form($dom,'toolsec',\%encrypt,\%privkeys,$rowtotal);
                   '<select name="ltitools_add_pos"'.$chgstr.'>';      } elsif ($position eq 'middle') {
     for (my $k=0; $k<$maxnum+1; $k++) {          $datatable = &password_rules('toolsecrets',\$itemcount,\%rules);
         my $vpos = $k+1;          $$rowtotal += $itemcount;
         my $selstr;      } else {
         if ($k == $maxnum) {          $datatable = &Apache::courseprefs::print_ltitools($dom,'',$settings,\$rowtotal,'','','domain');
             $selstr = ' selected="selected" ';  
         }  
         $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';  
     }      }
     $datatable .= '</select>&nbsp;'."\n".  
                   '<input type="checkbox" name="ltitools_add" value="1" />'.&mt('Add').'</span></td>'."\n".  
                   '<td colspan="2">'.  
                   '<fieldset><legend>'.&mt('Required settings').'</legend>'.  
                   '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="20" name="ltitools_add_title" value="" /></span> '."\n".  
                   ('&nbsp;'x2).  
                   '<span class="LC_nobreak">'.$lt{'version'}.':<select name="ltitools_add_version">'.  
                   '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".  
                   ('&nbsp;'x2).  
                   '<span class="LC_nobreak">'.$lt{'msgtype'}.':<select name="ltitools_add_msgtype">'.  
                   '<option value="basic-lti-launch-request" selected="selected">Launch</option></select></span> '.  
                   '<span class="LC_nobreak">'.$lt{'sigmethod'}.':<select name="ltitools_add_sigmethod">'.  
                   '<option value="HMAC-SHA1" selected="selected">HMAC-SHA1</option>'.  
                   '<option value="HMAC-SHA256">HMAC-SHA256</option></select></span>'.  
                   '<br />'.  
                   '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="40" name="ltitools_add_url" value="" /></span> '."\n".  
                   ('&nbsp;'x2).  
                   '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="ltitools_add_key" value="" /></span> '."\n".  
                   ('&nbsp;'x2).  
                   '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="5" name="ltitools_add_lifetime" value="300" /></span> '."\n".  
                   ('&nbsp;'x2).  
                   '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="ltitools_add_secret" value="" />'.  
                   '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltitools_add_secret.type='."'text'".' } else { this.form.ltitools_add_secret.type='."'password'".' }" />'.&mt('Visible input').'</label></span> '."\n".  
                   '</fieldset>'.  
                   '<fieldset><legend>'.&mt('Optional settings').'</legend>'.  
                   '<span class="LC_nobreak">'.&mt('Display target:');  
     my %defaultdisp;  
     $defaultdisp{'iframe'} = ' checked="checked"';  
     foreach my $disp ('iframe','tab','window') {  
         $datatable .= '<label><input type="radio" name="ltitools_add_target" value="'.$disp.'"'.$defaultdisp{$disp}.' />'.  
                       $lt{$disp}.'</label>'.('&nbsp;'x2);  
     }  
     $datatable .= ('&nbsp;'x4);  
     foreach my $dimen ('width','height') {  
         $datatable .= '<label>'.$lt{$dimen}.'&nbsp;'.  
                       '<input type="text" name="ltitools_add_'.$dimen.'" size="5" /></label>'.  
                       ('&nbsp;'x2);  
     }  
     $datatable .= '</span><br />'.  
                   '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'.  
                   '<input type="text" name="ltitools_add_linktext" size="5" /></div>'.  
                   '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'.  
                   '<textarea name="ltitools_add_explanation" rows="5" cols="40"></textarea>'.  
                   '</div><div style=""></div><br />';  
     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;'.  
                   '('.&mt('if larger than 21x21 pixels, image will be scaled').')&nbsp;';  
     if ($switchserver) {  
         $datatable .= &mt('Upload to library server: [_1]',$switchserver);  
     } else {  
         $datatable .= '<input type="file" name="ltitools_add_image" value="" />';  
     }  
     $datatable .= '</span></fieldset>'.  
                   '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'.  
                   '<span class="LC_nobreak">';  
     foreach my $field (@fields) {  
         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>'.  
                       '<input type="checkbox" name="ltitools_add_fields" value="'.$field.'"'.$id.$onclick.' />'.  
                       $lt{$field}.'</label>'.$spacer;  
     }  
     $datatable .= '</span>'.  
                   '<div style="display:none;" id="ltitools_user_div_add">'.  
                   '<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) {  
         my ($checked,$checkednone);  
         $datatable .= '<td style="text-align: center">'.  
                       &Apache::lonnet::plaintext($role,'Course').'<br />'.  
                       '<select name="ltitools_add_roles_'.$role.'">'.  
                       '<option value="" selected="selected">'.&mt('Select').'</option>';  
         foreach my $ltirole (@ltiroles) {  
             $datatable .= '<option value="'.$ltirole.'">'.$ltirole.'</option>';  
         }  
         $datatable .= '</select></td>';  
     }  
     $datatable .= '</tr></table></fieldset>'.  
                   '<fieldset><legend>'.&mt('Configurable in course').'</legend><span class="LC_nobreak">';  
     foreach my $item ('label','title','target','linktext','explanation','append') {  
         $datatable .= '<label>'.  
                       '<input type="checkbox" name="ltitools_courseconfig" value="'.$item.'" checked="checked" />'.  
                       $lt{'crs'.$item}.'</label>'.('&nbsp;' x2)."\n";  
     }  
     $datatable .= '</span></fieldset>'.  
                   '<fieldset><legend>'.&mt('Custom items sent on launch').'</legend>'.  
                   '<table><tr><th>'.&mt('Action').'</th><th>'.&mt('Name').'</th><th>'.&mt('Value').'</th></tr>'.  
                   '<tr><td><span class="LC_nobreak">'.  
                   '<label><input type="checkbox" name="ltitools_add_custom" value="1" />'.  
                   &mt('Add').'</label></span></td><td><input type="text" name="ltitools_add_custom_name" />'.  
                   '</td><td><input type="text" name="ltitools_add_custom_value" /></td></tr>'.  
                   '</table></fieldset>'."\n".  
                   '</td>'."\n".  
                   '</tr>'."\n";  
     $itemcount ++;  
     return $datatable;      return $datatable;
 }  }
   
Line 4927  sub ltitools_names { Line 5395  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'           => 'User',
                                           'fullname'       => 'Full Name',                                            'fullname'       => 'Full Name',
                                           'firstname'      => 'First Name',                                            'firstname'      => 'First Name',
Line 4945  sub ltitools_names { Line 5413  sub ltitools_names {
                                           'roster'         => 'Tool can retrieve roster:',                                            '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',
Line 4953  sub ltitools_names { Line 5421  sub ltitools_names {
     return %lt;      return %lt;
 }  }
   
   sub secrets_form {
       my ($dom,$context,$encrypt,$privkeys,$rowtotal) = @_;
       my @ids=&Apache::lonnet::current_machine_ids();
       my %servers = &Apache::lonnet::get_servers($dom,'library');
       my $primary = &Apache::lonnet::domain($dom,'primary');
       my ($css_class,$extra,$numshown,$itemcount,$output);
       $itemcount = 0;
       foreach my $hostid (sort(keys(%servers))) {
           my ($showextra,$divsty,$switch);
           if ($hostid eq $primary) {
               if ($context eq 'ltisec') {
                   if (($encrypt->{'ltisec_consumers'}) || ($encrypt->{'ltisec_domlinkprot'})) {
                       $showextra = 1;
                   }
                   if ($encrypt->{'ltisec_crslinkprot'}) {
                       $showextra = 1;
                   }
               } else {
                   if (($encrypt->{'toolsec_crs'}) || ($encrypt->{'toolsec_dom'})) {
                       $showextra = 1;
                   }
               }
               unless (grep(/^\Q$hostid\E$/,@ids)) {
                   $switch = 1;
               }
               if ($showextra) {
                   $numshown ++;
                   $divsty = 'display:inline-block';
               } else {
                   $divsty = 'display:none';
               }
               $extra .= '<fieldset id="'.$context.'_info_'.$hostid.'" style="'.$divsty.'">'.
                         '<legend>'.$hostid.'</legend>';
               if ($switch) {
                   my $switchserver = '<a href="/adm/switchserver?otherserver='.$hostid.'&amp;role='.
                                      &HTML::Entities::encode($env{'request.role'},'\'<>"&').
                                      '&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';
                   if (exists($privkeys->{$hostid})) {
                       $extra .= '<div id="'.$context.'_divcurrprivkey_'.$hostid.'" style="display:inline-block" />'.
                                 '<span class="LC_nobreak">'.
                                 &mt('Encryption Key').': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.
                                 '<span class="LC_nobreak">'.&mt('Change?').
                                 '<label><input type="radio" value="0" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" checked="checked" />'.&mt('No').'</label>'.
                                 ('&nbsp;'x2).
                                 '<label><input type="radio" value="1" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" />'.&mt('Yes').
                                 '</label>&nbsp;&nbsp;</span><div id="'.$context.'_divchgprivkey_'.$hostid.'" style="display:none" />'.
                                 '<span class="LC_nobreak"> - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver).
                                 '</span></div>';
                   } else {
                       $extra .= '<span class="LC_nobreak">'.
                                 &mt('Key required').' - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver).
                                 '</span>'."\n";
                   }
               } elsif (exists($privkeys->{$hostid})) {
                   $extra .= '<div id="'.$context.'_divcurrprivkey_'.$hostid.'" style="display:inline-block" /><span class="LC_nobreak">'.
                             &mt('Encryption Key').': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.
                             '<span class="LC_nobreak">'.&mt('Change?').
                             '<label><input type="radio" value="0" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" checked="checked" />'.&mt('No').'</label>'.
                             ('&nbsp;'x2).
                             '<label><input type="radio" value="1" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" />'.&mt('Yes').
                             '</label>&nbsp;&nbsp;</span><div id="'.$context.'_divchgprivkey_'.$hostid.'" style="display:none" />'.
                             '<span class="LC_nobreak">'.&mt('New Key').':'.
                             '<input type="password" size="20" name="'.$context.'_privkey_'.$hostid.'" value="" autocomplete="new-password" />'.
                             '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.'.$context.'_privkey_'.$hostid.'.type='."'text'".' } else { this.form.'.$context.'_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.
                             '</span></div>';
               } else {
                   $extra .= '<span class="LC_nobreak">'.&mt('Encryption Key').':'.
                             '<input type="password" size="20" name="'.$context.'_privkey_'.$hostid.'" value="" autocomplete="new-password" />'.
                             '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.'.$context.'_privkey_'.$hostid.'.type='."'text'".' } else { this.form.'.$context.'_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>';
               }
               $extra .= '</fieldset>';
           }
       }
       my (%choices,@toggles,%defaultchecked);
       if ($context eq 'ltisec') {
           %choices = &Apache::lonlocal::texthash (
                                                     ltisec_crslinkprot => 'Encrypt stored link protection secrets defined in courses',
                                                     ltisec_domlinkprot => 'Encrypt stored link protection secrets defined in domain',
                                                     ltisec_consumers   => 'Encrypt stored consumer secrets defined in domain',
                                                  );
           @toggles = qw(ltisec_crslinkprot ltisec_domlinkprot ltisec_consumers);
           %defaultchecked = (
                              'ltisec_crslinkprot' => 'off',
                              'ltisec_domlinkprot' => 'off',
                              'ltisec_consumers'   => 'off',
                             );
       } else {
           %choices = &Apache::lonlocal::texthash (
                                                     toolsec_crs => 'Encrypt stored external tool secrets defined in courses',
                                                     toolsec_dom => 'Encrypt stored external tool secrets defined in domain',
                                                  );
           @toggles = qw(toolsec_crs toolsec_dom);
           %defaultchecked = (
                              'toolsec_crs' => 'off',
                              'toolsec_dom' => 'off',
                             );
       }
       my ($onclick,$itemcount);
       $onclick = 'javascript:toggleLTIEncKey(this.form,'."'$context'".');';
       ($output,$itemcount) = &radiobutton_prefs($encrypt,\@toggles,\%defaultchecked,
                                                 \%choices,$itemcount,$onclick,'','left','no');
   
       $css_class = $itemcount%2?' class="LC_odd_row"':'';
       my $noprivkeysty = 'display:inline-block';
       if ($numshown) {
           $noprivkeysty = 'display:none';
       }
       $output .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.&mt('Encryption Key(s)').'</td>'.
                  '<td><div id="'.$context.'_noprivkey" style="'.$noprivkeysty.'" >'.
                  '<span class="LC_nobreak">'.&mt('Not in use').'</span></div>'.
                  $extra.
                  '</td></tr>';
       $itemcount ++;
       $$rowtotal += $itemcount;
       return $output;
   }
   
 sub print_proctoring {  sub print_proctoring {
     my ($dom,$settings,$rowtotal) = @_;      my ($dom,$settings,$rowtotal) = @_;
     my $itemcount = 1;      my $itemcount = 1;
Line 5588  sub proctoring_providernames { Line 6173  sub proctoring_providernames {
 }  }
   
 sub print_lti {  sub print_lti {
     my ($dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my $itemcount = 1;      my $itemcount = 1;
     my $maxnum = 0;      my ($datatable,$css_class);
     my $css_class;      my (%rules,%encrypt,%privkeys,%linkprot);
     my %ordered;  
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         foreach my $item (keys(%{$settings})) {          if ($position eq 'top') {
             if (ref($settings->{$item}) eq 'HASH') {              if (exists($settings->{'encrypt'})) {
                 my $num = $settings->{$item}{'order'};                  if (ref($settings->{'encrypt'}) eq 'HASH') {
                 $ordered{$num} = $item;                      foreach my $key (keys(%{$settings->{'encrypt'}})) {
                           if ($key eq 'consumers') {
                               $encrypt{'ltisec_'.$key} = $settings->{'encrypt'}{$key};
                           } else {
                               $encrypt{'ltisec_'.$key.'linkprot'} = $settings->{'encrypt'}{$key};
                           }
                       }
                   }
               }
               if (exists($settings->{'private'})) {
                   if (ref($settings->{'private'}) eq 'HASH') {
                       if (ref($settings->{'private'}) eq 'HASH') {
                           if (ref($settings->{'private'}{'keys'}) eq 'ARRAY') {
                               map { $privkeys{$_} = 1; } (@{$settings->{'private'}{'keys'}});
                           }
                       }
                   }
               }
           } elsif ($position eq 'middle') {
               if (exists($settings->{'rules'})) {
                   if (ref($settings->{'rules'}) eq 'HASH') {
                       %rules = %{$settings->{'rules'}};
                   }
               }
           } elsif ($position eq 'lower') {
               if (exists($settings->{'linkprot'})) {
                   if (ref($settings->{'linkprot'}) eq 'HASH') {
                       %linkprot = %{$settings->{'linkprot'}};
                       if ($linkprot{'lock'}) {
                           delete($linkprot{'lock'});
                       }
                   }
               }
           } else {
               foreach my $key ('encrypt','private','rules','linkprot') {
                   if (exists($settings->{$key})) {
                       delete($settings->{$key});
                   }
             }              }
         }          }
     }      }
     my $maxnum = scalar(keys(%ordered));      if ($position eq 'top') {
     my $datatable;          $datatable = &secrets_form($dom,'ltisec',\%encrypt,\%privkeys,$rowtotal);
     my %lt = &lti_names();      } elsif ($position eq 'middle') {
     if (keys(%ordered)) {          $datatable = &password_rules('ltisecrets',\$itemcount,\%rules);
         my @items = sort { $a <=> $b } keys(%ordered);          $$rowtotal += $itemcount;
         for (my $i=0; $i<@items; $i++) {      } elsif ($position eq 'lower') {
             $css_class = $itemcount%2?' class="LC_odd_row"':'';           $datatable .= &Apache::courseprefs::print_linkprotection($dom,'',$settings,$rowtotal,'','','domain');
             my $item = $ordered{$items[$i]};      } else {
             my ($key,$secret,$lifetime,$consumer,$requser,$current);          my ($switchserver,$switchmessage);
             if (ref($settings->{$item}) eq 'HASH') {          $switchserver = &check_switchserver($dom);
                 $key = $settings->{$item}->{'key'};          $switchmessage = &mt("submit from domain's primary library server: [_1].",$switchserver);
                 $secret = $settings->{$item}->{'secret'};          my $maxnum = 0;
                 $lifetime = $settings->{$item}->{'lifetime'};          my %ordered;
                 $consumer = $settings->{$item}->{'consumer'};          if (ref($settings) eq 'HASH') {
                 $requser = $settings->{$item}->{'requser'};              foreach my $item (keys(%{$settings})) {
                 $current = $settings->{$item};                  if (ref($settings->{$item}) eq 'HASH') {
             }                      my $num = $settings->{$item}{'order'};
             my $onclickrequser = ' onclick="toggleLTI(this.form,'."'requser','$i'".');"';                      if ($num eq '') {
             my %checkedrequser = (                          $num = scalar(keys(%{$settings}));
                                    yes => ' checked="checked"',                      }
                                    no  => '',                      $ordered{$num} = $item;
                                  );                  }
             if (!$requser) {  
                 $checkedrequser{'no'} = $checkedrequser{'yes'};  
                 $checkedrequser{'yes'} = '';  
             }              }
             my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_".$item."'".');"';          }
             $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'          $maxnum = scalar(keys(%ordered));
                          .'<select name="lti_pos_'.$item.'"'.$chgstr.'>';          my %lt = &lti_names();
             for (my $k=0; $k<=$maxnum; $k++) {          if (keys(%ordered)) {
                 my $vpos = $k+1;              my @items = sort { $a <=> $b } keys(%ordered);
                 my $selstr;              for (my $i=0; $i<@items; $i++) {
                 if ($k == $i) {                  $css_class = $itemcount%2?' class="LC_odd_row"':'';
                     $selstr = ' selected="selected" ';                  my $item = $ordered{$items[$i]};
                   my ($key,$secret,$usable,$lifetime,$consumer,$requser,$crsinc,$current);
                   if (ref($settings->{$item}) eq 'HASH') {
                       $key = $settings->{$item}->{'key'};
                       $usable = $settings->{$item}->{'usable'};
                       $lifetime = $settings->{$item}->{'lifetime'};
                       $consumer = $settings->{$item}->{'consumer'};
                       $requser = $settings->{$item}->{'requser'};
                       $crsinc = $settings->{$item}->{'crsinc'};
                       $current = $settings->{$item};
                   }
                   my $onclickrequser = ' onclick="toggleLTI(this.form,'."'requser','$i'".');"';
                   my %checkedrequser = (
                                          yes => ' checked="checked"',
                                          no  => '',
                                        );
                   if (!$requser) {
                       $checkedrequser{'no'} = $checkedrequser{'yes'};
                       $checkedrequser{'yes'} = '';
                   }
                   my $onclickcrsinc = ' onclick="toggleLTI(this.form,'."'crsinc','$i'".');"';
                   my %checkedcrsinc = (
                                         yes => ' checked="checked"',
                                         no  => '',
                                       );
                   if (!$crsinc) {
                       $checkedcrsinc{'no'} = $checkedcrsinc{'yes'};
                       $checkedcrsinc{'yes'} = '';
                   }
                   my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_".$item."'".');"';
                   $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
                                .'<select name="lti_pos_'.$item.'"'.$chgstr.'>';
                   for (my $k=0; $k<=$maxnum; $k++) {
                       my $vpos = $k+1;
                       my $selstr;
                       if ($k == $i) {
                           $selstr = ' selected="selected" ';
                       }
                       $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
                 }                  }
                 $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';                  $datatable .= '</select>'.('&nbsp;'x2).
                       '<label><input type="checkbox" name="lti_del" value="'.$item.'" />'.
                       &mt('Delete?').'</label></span></td>'.
                       '<td colspan="2">'.
                       '<fieldset><legend>'.&mt('Required settings').'</legend>'.
                       '<span class="LC_nobreak">'.$lt{'consumer'}.
                       ':<input type="text" size="15" name="lti_consumer_'.$i.'" value="'.$consumer.'" /></span> '.
                       ('&nbsp;'x2).
                       '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_'.$i.'">'.
                       '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '.
                       ('&nbsp;'x2).
                       '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" name="lti_lifetime_'.$i.'"'.
                       'value="'.$lifetime.'" size="3" /></span><br /><br />';
                   if ($key ne '') {
                       $datatable .= '<span class="LC_nobreak">'.$lt{'key'};
                       if ($switchserver) {
                           $datatable .= ': ['.&mt('[_1] to view/edit',$switchserver).']';
                       } else {
                           $datatable .= ':<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" autocomplete="off" />';
                       }
                       $datatable .= '</span> '.('&nbsp;'x2);
                   } elsif (!$switchserver) {
                       $datatable .= '<span class="LC_nobreak">'.$lt{'key'}.':'.
                                     '<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" autocomplete="off" />'.
                                     '</span> '.('&nbsp;'x2);
                   }
                   if ($switchserver) {
                       if ($usable ne '') {
                           $datatable .= '<div id="lti_divcurrsecret_'.$i.'" style="display:inline-block" /><span class="LC_nobreak">'.
                                         $lt{'secret'}.': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.
                                         '<span class="LC_nobreak">'.&mt('Change secret?').
                                         '<label><input type="radio" value="0" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" checked="checked" />'.&mt('No').'</label>'.
                                         ('&nbsp;'x2).
                                        '<label><input type="radio" value="1" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" />'.&mt('Yes').'</label>'.('&nbsp;'x2).
                                         '</span><div id="lti_divchgsecret_'.$i.'" style="display:none" />'.
                                         '<span class="LC_nobreak"> - '.$switchmessage.'</span>'.
                                         '</div>';
                       } elsif ($key eq '') {
                           $datatable .= '<span class="LC_nobreak">'.&mt('Key and Secret are required').' - '.$switchmessage.'</span>'."\n";
                       } else {
                           $datatable .= '<span class="LC_nobreak">'.&mt('Secret required').' - '.$switchmessage.'</span>'."\n";
                       }
                   } else {
                       if ($usable ne '') {
                           $datatable .= '<div id="lti_divcurrsecret_'.$i.'" style="display:inline-block" /><span class="LC_nobreak">'.
                                         $lt{'secret'}.': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.
                                         '<span class="LC_nobreak">'.&mt('Change?').
                                         '<label><input type="radio" value="0" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" checked="checked" />'.&mt('No').'</label>'.
                                         ('&nbsp;'x2).
                                         '<label><input type="radio" value="1" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" />'.&mt('Yes').
                                         '</label>&nbsp;&nbsp;</span><div id="lti_divchgsecret_'.$i.'" style="display:none" />'.
                                         '<span class="LC_nobreak">'.&mt('New Secret').':'.
                                         '<input type="password" size="20" name="lti_secret_'.$i.'" value="" autocomplete="new-password" />'.
                                         '<label><input type="checkbox" name="lti_visible_'.$i.'" id="lti_visible_'.$i.'" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label></span></div>';
                       } else {
                           $datatable .=
                               '<span class="LC_nobreak">'.$lt{'secret'}.':'.
                               '<input type="password" size="20" name="lti_secret_'.$i.'" value="" autocomplete="new-password" />'.
                               '<label><input type="checkbox" name="lti_visible_'.$i.'" id="lti_visible_'.$i.'" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>';
                       }
                   }
                   $datatable .= '<br /><br />'.
                       '<span class="LC_nobreak">'.$lt{'requser'}.':'.
                       '<label><input type="radio" name="lti_requser_'.$i.'" value="1"'.$onclickrequser.$checkedrequser{yes}.' />'.&mt('Yes').'</label>&nbsp;'."\n".
                       '<label><input type="radio" name="lti_requser_'.$i.'" value="0"'.$onclickrequser.$checkedrequser{no}.' />'.&mt('No').'</label></span>'."\n".
                       '<br /><br />'.
                       '<span class="LC_nobreak">'.$lt{'crsinc'}.':'.
                       '<label><input type="radio" name="lti_crsinc_'.$i.'" value="1"'.$onclickcrsinc.$checkedcrsinc{yes}.' />'.&mt('Yes').'</label>&nbsp;'."\n".
                       '<label><input type="radio" name="lti_crsinc_'.$i.'" value="0"'.$onclickcrsinc.$checkedcrsinc{no}.' />'.&mt('No').'</label></span>'."\n".
                       ('&nbsp;'x4).
                       '<input type="hidden" name="lti_id_'.$i.'" value="'.$item.'" /></span>'.
                       '</fieldset>'.&lti_options($i,$current,$itemcount,%lt).'</td></tr>';
                   $itemcount ++;
             }              }
             $datatable .= '</select>'.('&nbsp;'x2).  
                 '<label><input type="checkbox" name="lti_del" value="'.$item.'" />'.  
                 &mt('Delete?').'</label></span></td>'.  
                 '<td colspan="2">'.  
                 '<fieldset><legend>'.&mt('Required settings').'</legend>'.  
                 '<span class="LC_nobreak">'.$lt{'consumer'}.  
                 ':<input type="text" size="15" name="lti_consumer_'.$i.'" value="'.$consumer.'" /></span> '.  
                 ('&nbsp;'x2).  
                 '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_'.$i.'">'.  
                 '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '.  
                 ('&nbsp;'x2).  
                 '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" name="lti_lifetime_'.$i.'"'.  
                 'value="'.$lifetime.'" size="3" /></span>'.  
                 ('&nbsp;'x2).  
                  '<span class="LC_nobreak">'.$lt{'requser'}.':'.  
                  '<label><input type="radio" name="lti_requser_'.$i.'" value="1"'.$onclickrequser.$checkedrequser{yes}.' />'.&mt('Yes').'</label>&nbsp;'."\n".  
                  '<label><input type="radio" name="lti_requser_'.$i.'" value="0"'.$onclickrequser.$checkedrequser{no}.' />'.&mt('No').'</label></span>'."\n".  
                 '<br /><br />'.  
                 '<span class="LC_nobreak">'.$lt{'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,$itemcount,%lt).'</td></tr>';  
             $itemcount ++;  
         }          }
     }          $css_class = $itemcount%2?' class="LC_odd_row"':'';
     $css_class = $itemcount%2?' class="LC_odd_row"':'';          my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_add'".');"';
     my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_add'".');"';          $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
     $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".                        '<input type="hidden" name="lti_maxnum" value="'.$maxnum.'" />'."\n".
                   '<input type="hidden" name="lti_maxnum" value="'.$maxnum.'" />'."\n".                        '<select name="lti_pos_add"'.$chgstr.'>';
                   '<select name="lti_pos_add"'.$chgstr.'>';          for (my $k=0; $k<$maxnum+1; $k++) {
     for (my $k=0; $k<$maxnum+1; $k++) {              my $vpos = $k+1;
         my $vpos = $k+1;              my $selstr;
         my $selstr;              if ($k == $maxnum) {
         if ($k == $maxnum) {                  $selstr = ' selected="selected" ';
             $selstr = ' selected="selected" ';              }
               $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
         }          }
         $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';          $datatable .= '</select>&nbsp;'."\n".
                         '<input type="checkbox" name="lti_add" value="1" />'.&mt('Add').'</span></td>'."\n".
                         '<td colspan="2">'.
                         '<fieldset><legend>'.&mt('Required settings').'</legend>'.
                         '<span class="LC_nobreak">'.$lt{'consumer'}.
                         ':<input type="text" size="15" name="lti_consumer_add" value="" /></span> '."\n".
                         ('&nbsp;'x2).
                         '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_add">'.
                         '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".
                         ('&nbsp;'x2).
                         '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="3" name="lti_lifetime_add" value="300" /></span><br /><br />'."\n";
           if ($switchserver) {
               $datatable .= '<span class="LC_nobreak">'.&mt('Key and Secret are required').' - '.$switchmessage.'</span>'."\n";
           } else {
               $datatable .= '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="lti_key_add" value="" autocomplete="off" /></span> '."\n".
                             ('&nbsp;'x2).
                             '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="lti_secret_add" value="" autocomplete="new-password" />'.
                             '<label><input type="checkbox" name="lti_add_visible" id="lti_add_visible" onclick="if (this.checked) { this.form.lti_secret_add.type='."'text'".' } else { this.form.lti_secret_add.type='."'password'".' }" />'.&mt('Visible input').'</label></span> '."\n";
           }
           $datatable .= '<br /><br />'.
                         '<span class="LC_nobreak">'.$lt{'requser'}.':'.
                         '<label><input type="radio" name="lti_requser_add" value="1" onclick="toggleLTI(this.form,'."'requser','add'".');" checked="checked" />'.&mt('Yes').'</label>&nbsp;'."\n".
                         '<label><input type="radio" name="lti_requser_add" value="0" onclick="toggleLTI(this.form,'."'requser','add'".');" />'.&mt('No').'</label></span>'."\n".
                         '<br /><br />'.
                         '<span class="LC_nobreak">'.$lt{'crsinc'}.':'.
                         '<label><input type="radio" name="lti_crsinc_add" value="1" onclick="toggleLTI(this.form,'."'crsinc','add'".');" checked="checked" />'.&mt('Yes').'</label>&nbsp;'."\n".
                         '<label><input type="radio" name="lti_crsinc_add" value="0" onclick="toggleLTI(this.form,'."'crsinc','add'".');" />'.&mt('No').'</label></span>'."\n".
                         '</fieldset>'.&lti_options('add',undef,$itemcount,%lt).
                         '</td>'."\n".
                         '</tr>'."\n";
           $itemcount ++;
     }      }
     $datatable .= '</select>&nbsp;'."\n".      $$rowtotal += $itemcount;
                   '<input type="checkbox" name="lti_add" value="1" />'.&mt('Add').'</span></td>'."\n".      return $datatable;
                   '<td colspan="2">'.  
                   '<fieldset><legend>'.&mt('Required settings').'</legend>'.  
                   '<span class="LC_nobreak">'.$lt{'consumer'}.  
                   ':<input type="text" size="15" name="lti_consumer_add" value="" /></span> '."\n".  
                   ('&nbsp;'x2).  
                   '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_add">'.  
                   '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".  
                   ('&nbsp;'x2).  
                   '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="3" name="lti_lifetime_add" value="300" /></span> '."\n".  
                   ('&nbsp;'x2).  
                   '<span class="LC_nobreak">'.$lt{'requser'}.':'.  
                   '<label><input type="radio" name="lti_requser_add" value="1" onclick="toggleLTI(this.form,'."'requser','add'".');" checked="checked" />'.&mt('Yes').'</label>&nbsp;'."\n".  
                   '<label><input type="radio" name="lti_requser_add" value="0" onclick="toggleLTI(this.form,'."'requser','add'".');" />'.&mt('No').'</label></span>'."\n".  
                   '<br /><br />'.  
                   '<span class="LC_nobreak">'.$lt{'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,$itemcount,%lt).  
                   '</td>'."\n".  
                   '</tr>'."\n";  
     $$rowtotal ++;  
     return $datatable;;  
 }  }
   
 sub lti_names {  sub lti_names {
Line 5716  sub lti_names { Line 6425  sub lti_names {
                                           'consumer'  => 'Consumer',                                            'consumer'  => 'Consumer',
                                           'secret'    => 'Secret',                                            'secret'    => 'Secret',
                                           'requser'   => "User's identity sent",                                            'requser'   => "User's identity sent",
                                             'crsinc'    => "Course's identity sent",
                                           'email'     => 'Email address',                                            'email'     => 'Email address',
                                           'sourcedid' => 'User ID',                                            'sourcedid' => 'User ID',
                                           'other'     => 'Other',                                            'other'     => 'Other',
Line 5732  sub lti_options { Line 6442  sub lti_options {
     my (%checked,%rolemaps,$crssecsrc,$userfield,$cidfield,$callback);      my (%checked,%rolemaps,$crssecsrc,$userfield,$cidfield,$callback);
     $checked{'mapuser'}{'sourcedid'} = ' checked="checked"';      $checked{'mapuser'}{'sourcedid'} = ' checked="checked"';
     $checked{'mapcrs'}{'course_offering_sourcedid'} = ' checked="checked"';      $checked{'mapcrs'}{'course_offering_sourcedid'} = ' checked="checked"';
     $checked{'makecrs'}{'N'} = '  checked="checked"';      $checked{'storecrs'}{'Y'} = ' checked="checked"';
       $checked{'makecrs'}{'N'} = ' checked="checked"';
     $checked{'mapcrstype'} = {};      $checked{'mapcrstype'} = {};
     $checked{'makeuser'} = {};      $checked{'makeuser'} = {};
     $checked{'selfenroll'} = {};      $checked{'selfenroll'} = {};
Line 5750  sub lti_options { Line 6461  sub lti_options {
     my $callbacksty = 'none';      my $callbacksty = 'none';
     my $passbacksty = 'none';      my $passbacksty = 'none';
     my $optionsty = 'block';      my $optionsty = 'block';
       my $crssty = 'block';
     my $lcauthparm;      my $lcauthparm;
     my $lcauthparmstyle = 'display:none';      my $lcauthparmstyle = 'display:none';
     my $lcauthparmtext;      my $lcauthparmtext;
Line 5760  sub lti_options { Line 6472  sub lti_options {
     if (ref($current) eq 'HASH') {      if (ref($current) eq 'HASH') {
         if (!$current->{'requser'}) {          if (!$current->{'requser'}) {
             $optionsty = 'none';              $optionsty = 'none';
               $crssty = 'none';
           } elsif (!$current->{'crsinc'}) {
               $crssty = 'none';
         }          }
         if (($current->{'mapuser'} ne '') && ($current->{'mapuser'} ne 'lis_person_sourcedid')) {          if (($current->{'mapuser'} ne '') && ($current->{'mapuser'} ne 'lis_person_sourcedid')) {
             $checked{'mapuser'}{'sourcedid'} = '';              $checked{'mapuser'}{'sourcedid'} = '';
             if ($current->{'mapuser'} eq 'lis_person_contact_email_primary') {              if ($current->{'mapuser'} eq 'lis_person_contact_email_primary') {
                 $checked{'mapuser'}{'email'} = ' checked="checked"';                   $checked{'mapuser'}{'email'} = ' checked="checked"';
             } else {              } else {
                 $checked{'mapuser'}{'other'} = ' checked="checked"';                  $checked{'mapuser'}{'other'} = ' checked="checked"';
                 $userfield = $current->{'mapuser'};                  $userfield = $current->{'mapuser'};
Line 5774  sub lti_options { Line 6489  sub lti_options {
         if (($current->{'mapcrs'} ne '') && ($current->{'mapcrs'} ne 'course_offering_sourcedid')) {          if (($current->{'mapcrs'} ne '') && ($current->{'mapcrs'} ne 'course_offering_sourcedid')) {
             $checked{'mapcrs'}{'course_offering_sourcedid'} = '';              $checked{'mapcrs'}{'course_offering_sourcedid'} = '';
             if ($current->{'mapcrs'} eq 'context_id') {              if ($current->{'mapcrs'} eq 'context_id') {
                 $checked{'mapcrs'}{'context_id'} = ' checked="checked"';                   $checked{'mapcrs'}{'context_id'} = ' checked="checked"';
             } else {              } else {
                 $checked{'mapcrs'}{'other'} = ' checked="checked"';                  $checked{'mapcrs'}{'other'} = ' checked="checked"';
                 $cidfield = $current->{'mapcrs'};                  $cidfield = $current->{'mapcrs'};
Line 5786  sub lti_options { Line 6501  sub lti_options {
                 $checked{'mapcrstype'}{$type} = ' checked="checked"';                  $checked{'mapcrstype'}{$type} = ' checked="checked"';
             }              }
         }          }
           if (!$current->{'storecrs'}) {
               $checked{'storecrs'}{'N'} = $checked{'storecrs'}{'Y'};
               $checked{'storecrs'}{'Y'} = '';
           }
         if ($current->{'makecrs'}) {          if ($current->{'makecrs'}) {
             $checked{'makecrs'}{'Y'} = '  checked="checked"';              $checked{'makecrs'}{'Y'} = '  checked="checked"';
         }          }
Line 5798  sub lti_options { Line 6517  sub lti_options {
             $checked{'lcauth'}{$1} = ' checked="checked"';              $checked{'lcauth'}{$1} = ' checked="checked"';
             unless (($current->{'lcauth'} eq 'lti') || ($current->{'lcauth'} eq 'internal')) {              unless (($current->{'lcauth'} eq 'lti') || ($current->{'lcauth'} eq 'internal')) {
                 $lcauthparm = $current->{'lcauthparm'};                  $lcauthparm = $current->{'lcauthparm'};
                 $lcauthparmstyle = 'display:table-row';                   $lcauthparmstyle = 'display:table-row';
                 if ($current->{'lcauth'} eq 'localauth') {                  if ($current->{'lcauth'} eq 'localauth') {
                     $lcauthparmtext = &mt('Local auth argument');                      $lcauthparmtext = &mt('Local auth argument');
                 } else {                  } else {
Line 5815  sub lti_options { Line 6534  sub lti_options {
             %rolemaps = %{$current->{'maproles'}};              %rolemaps = %{$current->{'maproles'}};
         }          }
         if ($current->{'section'} ne '') {          if ($current->{'section'} ne '') {
             $checked{'crssec'}{'Y'} = '  checked="checked"';               $checked{'crssec'}{'Y'} = '  checked="checked"';
             $crssecfieldsty = 'inline-block';              $crssecfieldsty = 'inline-block';
             if ($current->{'section'} eq 'course_section_sourcedid') {              if ($current->{'section'} eq 'course_section_sourcedid') {
                 $checked{'crssecsrc'}{'sourcedid'} = ' checked="checked"';                  $checked{'crssecsrc'}{'sourcedid'} = ' checked="checked"';
Line 5861  sub lti_options { Line 6580  sub lti_options {
         $checked{'crssec'}{'N'} = ' checked="checked"';          $checked{'crssec'}{'N'} = ' checked="checked"';
         $checked{'callback'}{'N'} = ' checked="checked"';          $checked{'callback'}{'N'} = ' checked="checked"';
         $checked{'topmenu'}{'N'} = ' checked="checked"';          $checked{'topmenu'}{'N'} = ' checked="checked"';
         $checked{'inlinemenu'}{'Y'} = ' checked="checked"';           $checked{'inlinemenu'}{'Y'} = ' checked="checked"';
         $checked{'menuitem'}{'grades'} = ' checked="checked"';          $checked{'menuitem'}{'grades'} = ' checked="checked"';
         $menusty = 'inline-block';           $menusty = 'inline-block';
     }      }
     my @coursetypes = ('official','unofficial','community','textbook','placement','lti');      my @coursetypes = ('official','unofficial','community','textbook','placement','lti');
     my %coursetypetitles = &Apache::lonlocal::texthash (      my %coursetypetitles = &Apache::lonlocal::texthash (
Line 5892  sub lti_options { Line 6611  sub lti_options {
     my $onclicksecsrc = ' onclick="toggleLTI(this.form,'."'secsrc','$num'".')"';      my $onclicksecsrc = ' onclick="toggleLTI(this.form,'."'secsrc','$num'".')"';
     my $onclicklcauth = ' onclick="toggleLTI(this.form,'."'lcauth','$num'".')"';      my $onclicklcauth = ' onclick="toggleLTI(this.form,'."'lcauth','$num'".')"';
     my $onclickmenu = ' onclick="toggleLTI(this.form,'."'lcmenu','$num'".');"';      my $onclickmenu = ' onclick="toggleLTI(this.form,'."'lcmenu','$num'".');"';
     my $output = '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Mapping users').'</legend>'.      my $output = '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Logout options').'</legend>'.
                    '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Callback to logout LON-CAPA on log out from Consumer').':&nbsp;'.
                    '<label><input type="radio" name="lti_callback_'.$num.'" value="0"'.
                    $checked{'callback'}{'N'}.$onclickcallback.' />'.&mt('No').'</label>'.('&nbsp;'x2).
                    '<label><input type="radio" name="lti_callback_'.$num.'" value="1"'.
                    $checked{'callback'}{'Y'}.$onclickcallback.' />'.&mt('Yes').'</label></span></div>'.
                    '<div class="LC_floatleft" style="display:'.$callbacksty.';" id="lti_callbackfield_'.$num.'">'.
                    '<span class="LC_nobreak">'.&mt('Parameter').': '.
                    '<input type="text" name="lti_callbackparam_'.$num.'" value="'.$callback.'" /></span>'.
                    '</div><div style="padding:0;clear:both;margin:0;border:0"></div></fieldset>'.
                    '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Mapping users').'</legend>'.
                  '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('LON-CAPA username').':&nbsp;';                   '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('LON-CAPA username').':&nbsp;';
     foreach my $option ('sourcedid','email','other') {      foreach my $option ('sourcedid','email','other') {
         $output .= '<label><input type="radio" name="lti_mapuser_'.$num.'" value="'.$option.'"'.          $output .= '<label><input type="radio" name="lti_mapuser_'.$num.'" value="'.$option.'"'.
Line 5903  sub lti_options { Line 6632  sub lti_options {
                '<div class="LC_floatleft" style="display:'.$userfieldsty.';" id="lti_userfield_'.$num.'">'.                 '<div class="LC_floatleft" style="display:'.$userfieldsty.';" id="lti_userfield_'.$num.'">'.
                '<input type="text" name="lti_customuser_'.$num.'" '.                 '<input type="text" name="lti_customuser_'.$num.'" '.
                'value="'.$userfield.'" /></div></fieldset>'.                 'value="'.$userfield.'" /></div></fieldset>'.
                '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Mapping course roles').'</legend><table><tr>';                 '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Roles which may create user accounts').'</legend>';
     foreach my $ltirole (@lticourseroles) {  
         my ($selected,$selectnone);  
         if ($rolemaps{$ltirole} eq '') {  
             $selectnone = ' selected="selected"';  
         }  
         $output .= '<td style="text-align: center">'.$ltirole.'<br />'.  
                    '<select name="lti_maprole_'.$ltirole.'_'.$num.'">'.  
                    '<option value=""'.$selectnone.'>'.&mt('Select').'</option>';  
         foreach my $role (@courseroles) {  
             unless ($selectnone) {  
                 if ($rolemaps{$ltirole} eq $role) {  
                     $selected = ' selected="selected"';  
                 } else {  
                     $selected = '';  
                 }  
             }  
             $output .= '<option value="'.$role.'"'.$selected.'>'.  
                        &Apache::lonnet::plaintext($role,'Course').  
                        '</option>';  
         }  
         $output .= '</select></td>';  
     }  
     $output .= '</tr></table></fieldset>'.  
                '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Roles which may create user accounts').'</legend>';  
     foreach my $ltirole (@ltiroles) {      foreach my $ltirole (@ltiroles) {
         $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_makeuser_'.$num.'" value="'.$ltirole.'"'.          $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_makeuser_'.$num.'" value="'.$ltirole.'"'.
                    $checked{'makeuser'}{$ltirole}.' />'.$ltirole.'</label>&nbsp;</span> ';                          $checked{'makeuser'}{$ltirole}.' />'.$ltirole.'</label>&nbsp;</span> ';
     }      }
     $output .= '</fieldset>'.      $output .= '</fieldset>'.
                '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('New user accounts created for LTI users').'</legend>'.                 '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('New user accounts created for LTI users').'</legend>'.
                '<table>'.                 '<table>'.
                &modifiable_userdata_row('lti','instdata_'.$num,$current,$numinrow,$itemcount).                 &modifiable_userdata_row('lti','instdata_'.$num,$current,$numinrow,$itemcount).
                '</table>'.                 '</table>'.
Line 5956  sub lti_options { Line 6661  sub lti_options {
                '<span id="lti_lcauth_parmtext_'.$num.'">'.$lcauthparmtext.'</span>'.                 '<span id="lti_lcauth_parmtext_'.$num.'">'.$lcauthparmtext.'</span>'.
                '<input type="text" name="lti_lcauthparm_'.$num.'" value="" /></span></td></tr>'.                 '<input type="text" name="lti_lcauthparm_'.$num.'" value="" /></span></td></tr>'.
                '</table></fieldset>'.                 '</table></fieldset>'.
                '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Mapping courses').'</legend>'.                 '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.
                  &mt('LON-CAPA menu items (Course Coordinator can override)').'</legend>'.
                  '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'topmenu'}.':&nbsp;'.
                  '<label><input type="radio" name="lti_topmenu_'.$num.'" value="0"'.
                  $checked{'topmenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.('&nbsp;'x2).
                  '<label><input type="radio" name="lti_topmenu_'.$num.'" value="1"'.
                  $checked{'topmenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>'.
                  '<div style="padding:0;clear:both;margin:0;border:0"></div>'.
                  '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'inlinemenu'}.':&nbsp;'.
                  '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="0"'.
                  $checked{'inlinemenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.('&nbsp;'x2).
                  '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="1"'.
                  $checked{'inlinemenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>';
        $output .='<div style="padding:0;clear:both;margin:0;border:0"></div>'.
                  '<div class="LC_floatleft" style="display:'.$menusty.';" id="lti_menufield_'.$num.'">'.
                  '<span class="LC_nobreak">'.&mt('Menu items').':&nbsp;';
       foreach my $type ('fullname','coursetitle','role','logout','grades') {
           $output .= '<label><input type="checkbox" name="lti_menuitem_'.$num.'" value="'.$type.'"'.
                      $checked{'menuitem'}{$type}.' />'.$menutitles{$type}.'</label>'.
                      ('&nbsp;'x2);
       }
       $output .= '</span></div></fieldset>'.
                  '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Mapping courses').'</legend>'.
                '<div class="LC_floatleft"><span class="LC_nobreak">'.                 '<div class="LC_floatleft"><span class="LC_nobreak">'.
                &mt('Unique course identifier').':&nbsp;';                 &mt('Unique course identifier').':&nbsp;';
     foreach my $option ('course_offering_sourcedid','context_id','other') {      foreach my $option ('course_offering_sourcedid','context_id','other') {
Line 5973  sub lti_options { Line 6700  sub lti_options {
                    $checked{'mapcrstype'}{$type}.' />'.$coursetypetitles{$type}.'</label>'.                     $checked{'mapcrstype'}{$type}.' />'.$coursetypetitles{$type}.'</label>'.
                    ('&nbsp;'x2);                     ('&nbsp;'x2);
     }      }
     $output .= '</span></fieldset>'.      $output .= '</span><br /><br />'.
                '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Creating courses').'</legend>'.                 '<span class="LC_nobreak">'.&mt('Store mapping of course identifier to LON-CAPA CourseID').':&nbsp;'.
                  '<label><input type="radio" name="lti_storecrs_'.$num.'" value="0"'.
                  $checked{'storecrs'}{'N'}.' />'.&mt('No').'</label>'.('&nbsp;'x2).
                  '<label><input type="radio" name="lti_storecrs_'.$num.'" value="1"'.
                  $checked{'storecrs'}{'Y'}.' />'.&mt('Yes').'</label></span>'.
                  '</fieldset>'.
                  '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Mapping course roles').'</legend><table><tr>';
       foreach my $ltirole (@lticourseroles) {
           my ($selected,$selectnone);
           if ($rolemaps{$ltirole} eq '') {
               $selectnone = ' selected="selected"';
           }
           $output .= '<td style="text-align: center">'.$ltirole.'<br />'.
                      '<select name="lti_maprole_'.$ltirole.'_'.$num.'">'.
                      '<option value=""'.$selectnone.'>'.&mt('Select').'</option>';
           foreach my $role (@courseroles) {
               unless ($selectnone) {
                   if ($rolemaps{$ltirole} eq $role) {
                       $selected = ' selected="selected"';
                   } else {
                       $selected = '';
                   }
               }
               $output .= '<option value="'.$role.'"'.$selected.'>'.
                          &Apache::lonnet::plaintext($role,'Course').
                          '</option>';
           }
           $output .= '</select></td>';
       }
       $output .= '</tr></table></fieldset>'.
                  '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Creating courses').'</legend>'.
                '<span class="LC_nobreak">'.&mt('Course created (if absent) on Instructor access').':&nbsp;'.                 '<span class="LC_nobreak">'.&mt('Course created (if absent) on Instructor access').':&nbsp;'.
                '<label><input type="radio" name="lti_makecrs_'.$num.'" value="0"'.                 '<label><input type="radio" name="lti_makecrs_'.$num.'" value="0"'.
                $checked{'makecrs'}{'N'}.' />'.&mt('No').'</label>'.('&nbsp;'x2).                 $checked{'makecrs'}{'N'}.' />'.&mt('No').'</label>'.('&nbsp;'x2).
                '<label><input type="radio" name="lti_makecrs_'.$num.'" value="1"'.                 '<label><input type="radio" name="lti_makecrs_'.$num.'" value="1"'.
                $checked{'makecrs'}{'Y'}.' />'.&mt('Yes').'</label></span>'.                 $checked{'makecrs'}{'Y'}.' />'.&mt('Yes').'</label></span>'.
                '</fieldset>'.                 '</fieldset>'.
                '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Roles which may self-enroll').'</legend>';                 '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Roles which may self-enroll').'</legend>';
     foreach my $lticrsrole (@lticourseroles) {      foreach my $lticrsrole (@lticourseroles) {
         $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_selfenroll_'.$num.'" value="'.$lticrsrole.'"'.          $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_selfenroll_'.$num.'" value="'.$lticrsrole.'"'.
                    $checked{'selfenroll'}{$lticrsrole}.' />'.$lticrsrole.'</label>&nbsp;</span> ';                     $checked{'selfenroll'}{$lticrsrole}.' />'.$lticrsrole.'</label>&nbsp;</span> ';
     }      }
     $output .= '</fieldset>'.      $output .= '</fieldset>'.
                '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Course options').'</legend>'.                 '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Course options').'</legend>'.
                '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Assign users to sections').':&nbsp;'.                 '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Assign users to sections').':&nbsp;'.
                '<label><input type="radio" name="lti_crssec_'.$num.'" value="0"'.                 '<label><input type="radio" name="lti_crssec_'.$num.'" value="0"'.
                $checked{'crssec'}{'N'}.$onclicksec.' />'.&mt('No').'</label>'.('&nbsp;'x2).                 $checked{'crssec'}{'N'}.$onclicksec.' />'.&mt('No').'</label>'.('&nbsp;'x2).
Line 6010  sub lti_options { Line 6767  sub lti_options {
         if ($extra eq 'passback') {          if ($extra eq 'passback') {
             $pb1p1chk = ' checked="checked"';              $pb1p1chk = ' checked="checked"';
             $pb1p0chk = '';              $pb1p0chk = '';
             $onclickpb = ' onclick="toggleLTI(this.form,'."'passback','$num'".');"';               $onclickpb = ' onclick="toggleLTI(this.form,'."'passback','$num'".');"';
         } else {          } else {
             $onclickpb = '';               $onclickpb = '';
         }          }
         if (ref($current) eq 'HASH') {          if (ref($current) eq 'HASH') {
             if (($current->{$extra})) {              if (($current->{$extra})) {
Line 6039  sub lti_options { Line 6796  sub lti_options {
                &mt('Outcomes Service (1.1)').'</label>'.('&nbsp;'x2).                 &mt('Outcomes Service (1.1)').'</label>'.('&nbsp;'x2).
                '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.0"'.$pb1p0chk.'/>'.                 '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.0"'.$pb1p0chk.'/>'.
                &mt('Outcomes Extension (1.0)').'</label></span></div>'.                 &mt('Outcomes Extension (1.0)').'</label></span></div>'.
                '<div style="padding:0;clear:both;margin:0;border:0"></div>'.                 '<div style="padding:0;clear:both;margin:0;border:0"></div></fieldset>';
                '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Callback on logout').':&nbsp;'.  
                '<label><input type="radio" name="lti_callback_'.$num.'" value="0"'.  
                $checked{'callback'}{'N'}.$onclickcallback.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_callback_'.$num.'" value="1"'.  
                $checked{'callback'}{'Y'}.$onclickcallback.' />'.&mt('Yes').'</label></span></div>'.  
                '<div class="LC_floatleft" style="display:'.$callbacksty.';" id="lti_callbackfield_'.$num.'">'.  
                '<span class="LC_nobreak">'.&mt('Parameter').': '.  
                '<input type="text" name="lti_callbackparam_'.$num.'" value="'.$callback.'" /></span>'.  
                '</div><div style="padding:0;clear:both;margin:0;border:0"></div></fieldset>'.  
                '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Course defaults (Course Coordinator can override)').'</legend>'.  
                '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'topmenu'}.':&nbsp;'.  
                '<label><input type="radio" name="lti_topmenu_'.$num.'" value="0"'.  
                $checked{'topmenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_topmenu_'.$num.'" value="1"'.  
                $checked{'topmenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>'.  
                '<div style="padding:0;clear:both;margin:0;border:0"></div>'.  
                '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'inlinemenu'}.':&nbsp;'.  
                '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="0"'.  
                $checked{'inlinemenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.('&nbsp;'x2).  
                '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="1"'.  
                $checked{'inlinemenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>';  
      $output .='<div style="padding:0;clear:both;margin:0;border:0"></div>'.   
                '<div class="LC_floatleft" style="display:'.$menusty.';" id="lti_menufield_'.$num.'">'.  
                '<span class="LC_nobreak">'.&mt('Menu items').':&nbsp;';  
     foreach my $type ('fullname','coursetitle','role','logout','grades') {  
         $output .= '<label><input type="checkbox" name="lti_menuitem_'.$num.'" value="'.$type.'"'.  
                    $checked{'menuitem'}{$type}.' />'.$menutitles{$type}.'</label>'.  
                    ('&nbsp;'x2);  
     }  
     $output .= '</span></div></fieldset>';      $output .= '</span></div></fieldset>';
 #        '<fieldset><legend>'.&mt('Assigning author roles').'</legend>';  #        '<fieldset><legend>'.&mt('Assigning author roles').'</legend>';
 #  #
Line 6094  sub print_coursedefaults { Line 6822  sub print_coursedefaults {
     my %choices =  &Apache::lonlocal::texthash (      my %choices =  &Apache::lonlocal::texthash (
         canuse_pdfforms      => 'Course/Community users can create/upload PDF forms',          canuse_pdfforms      => 'Course/Community users can create/upload PDF forms',
         uploadquota          => 'Default quota for files uploaded directly to course/community using Course Editor (MB)',          uploadquota          => 'Default quota for files uploaded directly to course/community using Course Editor (MB)',
           coursequota          => 'Default cumulative quota for all group portfolio spaces in course',
         anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys',          anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys',
         coursecredits        => 'Credits can be specified for courses',          coursecredits        => 'Credits can be specified for courses',
         uselcmath            => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)',          uselcmath            => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)',
         usejsme              => 'Molecule editor uses JSME (HTML5) in place of JME (Java)',          usejsme              => 'Molecule editor uses JSME (HTML5) in place of JME (Java)',
           inline_chem          => 'Use inline previewer for chemical reaction response in place of pop-up',
         texengine            => 'Default method to display mathematics',          texengine            => 'Default method to display mathematics',
         postsubmit           => 'Disable submit button/keypress following student submission',          postsubmit           => 'Disable submit button/keypress following student submission',
         canclone             => "People who may clone a course (besides course's owner and coordinators)",          canclone             => "People who may clone a course (besides course's owner and coordinators)",
         mysqltables          => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver',          mysqltables          => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver',
           ltiauth              => 'Student username in LTI launch of deep-linked URL can be accepted without re-authentication',
           domexttool           => 'External Tools defined in the domain may be used in courses/communities (by type)',
           exttool              => 'External Tools can be defined and configured in courses/communities (by type)',
     );      );
     my %staticdefaults = (      my %staticdefaults = (
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
                              coursequota          => 20,
                            postsubmit           => 60,                             postsubmit           => 60,
                            mysqltables          => 172800,                             mysqltables          => 172800,
                              domexttool           => 1,
                              exttool              => 0,
                          );                           );
     if ($position eq 'top') {      if ($position eq 'top') {
         %defaultchecked = (          %defaultchecked = (
                             'canuse_pdfforms' => 'off',                              'canuse_pdfforms' => 'off',
                             'uselcmath'       => 'on',                              'uselcmath'       => 'on',
                             'usejsme'         => 'on',                              'usejsme'         => 'on',
                               'inline_chem'     => 'on',
                             'canclone'        => 'none',                              'canclone'        => 'none',
                           );                            );
         @toggles = ('canuse_pdfforms','uselcmath','usejsme');          @toggles = ('canuse_pdfforms','uselcmath','usejsme','inline_chem');
         my $deftex = $Apache::lonnet::deftex;          my $deftex = $Apache::lonnet::deftex;
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ($settings->{'texengine'}) {              if ($settings->{'texengine'}) {
Line 6155  sub print_coursedefaults { Line 6892  sub print_coursedefaults {
         my $currcanclone = 'none';          my $currcanclone = 'none';
         my $onclick;          my $onclick;
         my @cloneoptions = ('none','domain');          my @cloneoptions = ('none','domain');
         my %clonetitles = (          my %clonetitles = &Apache::lonlocal::texthash (
                              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 6220  sub print_coursedefaults { Line 6957  sub print_coursedefaults {
         $itemcount ++;          $itemcount ++;
     } else {      } else {
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';          $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
         my ($currdefresponder,%defcredits,%curruploadquota,%deftimeout,%currmysql);          my ($currdefresponder,%defcredits,%curruploadquota,%currcoursequota,
               %deftimeout,%currmysql);
         my $currusecredits = 0;          my $currusecredits = 0;
         my $postsubmitclient = 1;          my $postsubmitclient = 1;
           my $ltiauth = 0;
           my %domexttool;
           my %exttool;
         my @types = ('official','unofficial','community','textbook','placement');          my @types = ('official','unofficial','community','textbook','placement');
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
               if ($settings->{'ltiauth'}) {
                   $ltiauth = 1;
               }
               if (ref($settings->{'domexttool'}) eq 'HASH') {
                   foreach my $type (@types) {
                       if ($settings->{'domexttool'}->{$type}) {
                           $domexttool{$type} = ' checked="checked"';
                       }
                   }
               } else {
                   foreach my $type (@types) {
                       if ($staticdefaults{'domexttool'}) {
                           $domexttool{$type} = ' checked="checked"';
                       }
                   }
               }
               if (ref($settings->{'exttool'}) eq 'HASH') {
                   foreach my $type (@types) {
                       if ($settings->{'exttool'}->{$type}) {
                           $exttool{$type} = ' checked="checked"';
                       }
                   }
               }
             $currdefresponder = $settings->{'anonsurvey_threshold'};              $currdefresponder = $settings->{'anonsurvey_threshold'};
             if (ref($settings->{'uploadquota'}) eq 'HASH') {              if (ref($settings->{'uploadquota'}) eq 'HASH') {
                 foreach my $type (keys(%{$settings->{'uploadquota'}})) {                  foreach my $type (keys(%{$settings->{'uploadquota'}})) {
                     $curruploadquota{$type} = $settings->{'uploadquota'}{$type};                      $curruploadquota{$type} = $settings->{'uploadquota'}{$type};
                 }                  }
             }              }
               if (ref($settings->{'coursequota'}) eq 'HASH') {
                   foreach my $type (keys(%{$settings->{'coursequota'}})) {
                       $currcoursequota{$type} = $settings->{'coursequota'}{$type};
                   }
               }
             if (ref($settings->{'coursecredits'}) eq 'HASH') {              if (ref($settings->{'coursecredits'}) eq 'HASH') {
                 foreach my $type (@types) {                  foreach my $type (@types) {
                     next if ($type eq 'community');                      next if ($type eq 'community');
Line 6276  sub print_coursedefaults { Line 7045  sub print_coursedefaults {
         } else {          } else {
             foreach my $type (@types) {              foreach my $type (@types) {
                 $deftimeout{$type} = $staticdefaults{'postsubmit'};                  $deftimeout{$type} = $staticdefaults{'postsubmit'};
                   if ($staticdefaults{'domexttool'}) {
                       $domexttool{$type} = ' checked="checked"';
                   }
             }              }
         }          }
         if (!$currdefresponder) {          if (!$currdefresponder) {
Line 6287  sub print_coursedefaults { Line 7059  sub print_coursedefaults {
             if ($curruploadquota{$type} eq '') {              if ($curruploadquota{$type} eq '') {
                 $curruploadquota{$type} = $staticdefaults{'uploadquota'};                  $curruploadquota{$type} = $staticdefaults{'uploadquota'};
             }              }
               if ($currcoursequota{$type} eq '') {
                   $currcoursequota{$type} = $staticdefaults{'coursequota'};
               }
         }          }
         $datatable .=          $datatable .=
                 '<tr'.$css_class.'><td><span class="LC_nobreak">'.                  '<tr'.$css_class.'><td><span class="LC_nobreak">'.
Line 6310  sub print_coursedefaults { Line 7085  sub print_coursedefaults {
         }          }
         $datatable .= '</tr></table></td></tr>'."\n";          $datatable .= '</tr></table></td></tr>'."\n";
         $itemcount ++;          $itemcount ++;
           $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
           $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
                         $choices{'coursequota'}.
                         '</span></td>'.
                         '<td style="text-align: right" class="LC_right_item">'.
                         '<table><tr>';
           foreach my $type (@types) {
               $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.
                              '<input type="text" name="coursequota_'.$type.'"'.
                              ' value="'.$currcoursequota{$type}.'" size="5" /></td>';
           }
           $datatable .= '</tr></table></td></tr>'."\n";
           $itemcount ++;
         my $onclick = "toggleDisplay(this.form,'credits');";          my $onclick = "toggleDisplay(this.form,'credits');";
         my $display = 'none';          my $display = 'none';
         if ($currusecredits) {          if ($currusecredits) {
Line 6370  sub print_coursedefaults { Line 7158  sub print_coursedefaults {
         }          }
         $datatable .= '</tr></table></td></tr>'."\n";          $datatable .= '</tr></table></td></tr>'."\n";
         $itemcount ++;          $itemcount ++;
           %defaultchecked = ('ltiauth' => 'off');
           @toggles = ('ltiauth');
           $current = {
                          'ltiauth' => $ltiauth,
                      };
           ($table,$itemcount) =
               &radiobutton_prefs($current,\@toggles,\%defaultchecked,
                                  \%choices,$itemcount,undef,undef,'left');
           $datatable .= $table;
           $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
           $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
                         $choices{'domexttool'}.
                         '</span></td>'.
                         '<td style="text-align: right" class="LC_right_item">'.
                         '<table><tr>';
           foreach my $type (@types) {
               $datatable .= '<td style="text-align: left">'.
                             '<span class="LC_nobreak">'.
                             '<input type="checkbox" name="domexttool"'.
                             ' value="'.$type.'"'.$domexttool{$type}.' />'.
                             &mt($type).'</span></td>'."\n";
           }
           $datatable .= '</tr></table></td></tr>'."\n";
           $itemcount ++;
           $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
           $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
                         $choices{'exttool'}.
                         '</span></td>'.
                         '<td style="text-align: right" class="LC_right_item">'.
                         '<table><tr>';
           foreach my $type (@types) {
               $datatable .= '<td style="text-align: left">'.
                             '<span class="LC_nobreak">'.
                             '<input type="checkbox" name="exttool"'.
                             ' value="'.$type.'"'.$exttool{$type}.' />'.
                             &mt($type).'</span></td>'."\n";
           }
           $datatable .= '</tr></table></td></tr>'."\n";
       }
       $$rowtotal += $itemcount;
       return $datatable;
   }
   
   sub print_authordefaults {
       my ($position,$dom,$settings,$rowtotal) = @_;
       my ($css_class,$datatable,%checkedon,%checkedoff);
       my $itemcount = 1;
       my %titles = &authordefaults_titles();
       if ($position eq 'top') {
           my %defaultchecked = (
                               'nocodemirror' => 'off',
                               'domcoordacc'  => 'on',
                             );
           my @toggles = ('nocodemirror','domcoordacc');
           ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
                                                        \%titles,$itemcount);
           my %staticdefaults = (
                                   'copyright'    => 'default',
                                   'sourceavail'  => 'closed',
                                );
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           my %currrights;
           foreach my $item ('copyright','sourceavail') {
               $currrights{$item} = $staticdefaults{$item};
               if (ref($settings) eq 'HASH') {
                   if (exists($settings->{$item})) {
                       $currrights{$item} = $settings->{$item};
                   }
               }
           }
           $datatable .= '<tr'.$css_class.'><td style="vertical-align: top">'.
                         '<span class="LC_nobreak">'.$titles{'copyright'}.
                         '</span></td><td class="LC_right_item">'.
                         &selectbox('copyright',$currrights{'copyright'},'',
                                    \&Apache::loncommon::copyrightdescription,
                                    (grep !/^priv|custom$/,(&Apache::loncommon::copyrightids))).
                         '</td></tr>'."\n";
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td style="vertical-align: top">'.
                         '<span class="LC_nobreak">'.$titles{'sourceavail'}.
                         '</span></td><td class="LC_right_item">'.
                         &selectbox('sourceavail',$currrights{'sourceavail'},'',
                                    \&Apache::loncommon::source_copyrightdescription,
                                    (&Apache::loncommon::source_copyrightids)).
                         '</td></tr>'."\n";        
       } else {
           $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
           my $curreditors;
           my %staticdefaults = (
                                   editors => ['edit','xml'],
                                   authorquota => 500,
                                   webdav => 0,
                                );
           my $curreditors = $staticdefaults{'editors'};
           if ((ref($settings) eq 'HASH') &&
               (ref($settings->{'editors'}) eq 'ARRAY')) {
               $curreditors = $settings->{'editors'};
           } else {
               $curreditors = $staticdefaults{'editors'};
           }
           my @editors = ('edit','xml','daxe');
           $datatable = '<tr'.$css_class.'>'."\n".
                        '<td>'.$titles{'editors'}.'</td>'."\n".
                        '<td class="LC_left_item">'."\n".
                        '<span class="LC_nobreak">';
           foreach my $editor (@editors) {
               my $checked;
               if (grep(/^\Q$editor\E$/,@{$curreditors})) {
                   $checked = ' checked="checked"';
               }
               $datatable .= '<label>'.
                             '<input type="checkbox" name="author_editors" '.
                             $checked.' value="'.$editor.'" '.
                             'onclick="javascript:checkEditors(this.form,'."'author_editors'".',this);" />'.
                             $titles{$editor}.'</label>&nbsp;';
           }
           $datatable .= '</span>'."\n".'</td>'."\n".'</tr>'."\n";
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
           my @insttypes;
           if (ref($types) eq 'ARRAY') {
               @insttypes = @{$types};
           }
           my $typecount = 0;
           my %domconf = &Apache::lonnet::get_dom('configuration',['quotas'],$dom);
           my @items = ('webdav','authorquota');
           my %quotas;
           if (ref($domconf{'quotas'}) eq 'HASH') {
               %quotas = %{$domconf{'quotas'}};
               foreach my $item (@items) {
                   if (ref($quotas{$item}) eq 'HASH') {
                       foreach my $type (@insttypes,'default') {
                           if ($item eq 'authorquota') {
                               if ($quotas{$item}{$type} !~ /^\d+$/) {
                                   $quotas{$item}{$type} = $staticdefaults{$item};
                               }
                           } elsif ($item eq 'webdav') {
                               if ($quotas{$item}{$type} !~ /^(0|1)$/) {
                                   $quotas{$item}{$type} = $staticdefaults{$item};
                               }
                           }
                       }
                   } else {
                       foreach my $type (@insttypes,'default') {
                           $quotas{$item}{$type} = $staticdefaults{$item};
                       }
                   }
               }
           } else {
               foreach my $item (@items) {
                   foreach my $type (@insttypes,'default') {
                       $quotas{$item}{$type} = $staticdefaults{$item};
                   }
               }
           }
           if (ref($usertypes) eq 'HASH') {
               my $numinrow = 4;
               my $onclick = '';
               $datatable .= &insttypes_row(\%quotas,$types,$usertypes,$dom,
                                            $numinrow,$othertitle,'authorquota',
                                            \$itemcount,$onclick);
               $itemcount ++;
               $datatable .= &insttypes_row(\%quotas,$types,$usertypes,$dom,
                                            $numinrow,$othertitle,'webdav',
                                            \$itemcount);
               $itemcount ++;
           }
           my $checkedno = ' checked="checked"';
           my ($checkedon,$checkedoff);
           if (ref($quotas{'webdav'}) eq 'HASH') {
               if ($quotas{'webdav'}{'_LC_adv'} =~ /^0|1$/) { 
                   if ($quotas{'webdav'}{'_LC_adv'}) {
                       $checkedon = $checkedno;
                   } else {
                       $checkedoff = $checkedno;
                   }
                   undef($checkedno);
               }
           }
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'>'.
                         '<td>'.$titles{'webdav_LC_adv'}.'<br />'.
                                $titles{'webdav_LC_adv_over'}.
                         '</td>'.
                         '<td class="LC_left_item">';
           foreach my $option ('none','off','on') {
               my ($text,$val,$checked);
               if ($option eq 'none') {
                   $text = $titles{'none'};
                   $val = '';
                   $checked = $checkedno;
               } elsif ($option eq 'off') {
                   $text = $titles{'overoff'};
                   $val = 0;
                   $checked = $checkedoff;
               } elsif ($option eq 'on') {
                   $text = $titles{'overon'};
                   $val = 1;
                   $checked = $checkedon;
               } 
               $datatable .= '<span class="LC_nobreak"><label>'.
                             '<input type="radio" name="webdav_LC_adv"'.
                             ' value="'.$val.'"'.$checked.' />'.
                             $text.'</label></span>&nbsp; ';
           }
           $datatable .= '</td></tr>';
           $itemcount ++;
     }      }
     $$rowtotal += $itemcount;      $$rowtotal += $itemcount;
     return $datatable;      return $datatable;
 }  }
   
   sub authordefaults_titles {
       return &Apache::lonlocal::texthash(
                  copyright => 'Copyright/Distribution',
                  sourceavail => ' Source Available',
                  editors => 'Available Editors',
                  webdav => 'WebDAV',
                  authorquota => 'Authoring Space quotas (MB)',
                  nocodemirror => 'Deactivate CodeMirror for EditXML editor',
                  domcoordacc => 'Dom. Coords. can enter Authoring Spaces in domain',
                  edit  => 'Standard editor (Edit)',
                  xml   => 'Text editor (EditXML)',
                  daxe  => 'Daxe editor (Daxe)',
                  webdav_LC_adv => 'WebDAV access for LON-CAPA "advanced" users',
                  webdav_LC_adv_over => '(overrides access based on affiliation, if set)',
                  none => 'No override set',
                  overon => 'Override -- webDAV on',
                  overoff => 'Override -- webDAV off', 
       );
   }
   
   sub selectbox {
       my ($name,$value,$readonly,$functionref,@idlist)=@_;
       my $selout = '<select name="'.$name.'">';
       foreach my $id (@idlist) {
           $selout.='<option value="'.$id.'"';
           if ($id eq $value) {
               $selout.=' selected="selected"';
           }
           if ($readonly) {
               $selout .= ' disabled="disabled"';
           }
           $selout.='>'.&{$functionref}($id).'</option>';
       }
       $selout.='</select>';
       return $selout;
   }
   
 sub print_selfenrollment {  sub print_selfenrollment {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable);      my ($css_class,$datatable);
Line 6605  sub print_privacy { Line 7638  sub print_privacy {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($datatable,$css_class,$numinrow,@items,%names,$othertitle,$usertypes,$types);      my ($datatable,$css_class,$numinrow,@items,%names,$othertitle,$usertypes,$types);
     my $itemcount = 0;      my $itemcount = 0;
     unless ($position eq 'top') {      if ($position eq 'top') {
           $numinrow = 2;
       } else {
         @items = ('domain','author','course','community');          @items = ('domain','author','course','community');
         %names = &Apache::lonlocal::texthash (          %names = &Apache::lonlocal::texthash (
                      domain => 'Assigned domain role(s)',                       domain => 'Assigned domain role(s)',
                      author => 'Assigned co-author role(s)',                       author => 'Assigned co-author role(s)',
                      course => 'Assigned course role(s)',                       course => 'Assigned course role(s)',
                      community => 'Assigned community role',                       community => 'Assigned community role(s)',
                  );                   );
         $numinrow = 4;          $numinrow = 4;
         ($othertitle,$usertypes,$types) =          ($othertitle,$usertypes,$types) =
Line 6630  sub print_privacy { Line 7665  sub print_privacy {
                 auto   => 'Unrestricted',                  auto   => 'Unrestricted',
                 instdom => 'Other domain shares institution/provider',                  instdom => 'Other domain shares institution/provider',
                 extdom => 'Other domain has different institution/provider',                  extdom => 'Other domain has different institution/provider',
                   notify => 'Notify when role needs authorization',
             );              );
             my %names = &Apache::lonlocal::texthash (              my %names = &Apache::lonlocal::texthash (
                 domain => 'Domain role',                  domain => 'Domain role',
Line 6681  sub print_privacy { Line 7717  sub print_privacy {
                 $datatable .= '</td></tr>';                  $datatable .= '</td></tr>';
                 $itemcount ++;                  $itemcount ++;
             }              }
               $css_class = $itemcount%2?' class="LC_odd_row"':'';
               $datatable .= '<tr'.$css_class.'><td>'.$titles{'notify'}.'</td>'.
                             '<td class="LC_left_item">';
               if ((@instdoms > 1) || (keys(%by_location) > 0)) {
                   my %curr;
                   if (ref($settings) eq 'HASH') {
                       if ($settings->{'notify'} ne '') {
                           map {$curr{$_}=1;} split(/,/,$settings->{'notify'});
                       }
                   }
                   $css_class = $itemcount%2?' class="LC_odd_row"':'';
                   my ($numdc,$table,$rows) = &active_dc_picker($dom,$numinrow,'checkbox',
                                                                'privacy_notify',%curr);
                   if ($numdc > 0) {
                       $datatable .= $table;
                   } else {
                       $datatable .= &mt('There are no active Domain Coordinators');
                   }
               } else {
                   $datatable .= &mt('Nothing to set here, as there are no other domains');
               }
               $datatable .='</td></tr>';
         } elsif ($position eq 'middle') {          } elsif ($position eq 'middle') {
             if ((@instdoms > 1) || (keys(%by_location) > 0)) {              if ((@instdoms > 1) || (keys(%by_location) > 0)) {
                 if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {                  if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
Line 7024  sub print_passwords { Line 8082  sub print_passwords {
             $itemcount ++;              $itemcount ++;
         }          }
     } elsif ($position eq 'lower') {      } elsif ($position eq 'lower') {
         my ($min,$max,%chars,$expire,$numsaved);          $datatable .= &password_rules('passwords',\$itemcount,$settings);
         $min = $Apache::lonnet::passwdmin;  
         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 ($settings->{expire}) {  
                 $expire = $settings->{expire};  
             }  
             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',  
                                                    );  
         $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="passwords_min" value="'.$min.'" size="3" '.  
                       'onblur="javascript:warnIntPass(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="passwords_max" value="'.$max.'" size="3" '.  
                       'onblur="javascript:warnIntPass(this);" />'.  
                       '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no maximum)').'</span>'.  
                       '</span></td></tr>';  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'chars'}.'<br />'.  
                       '<span class="LC_nobreak LC_fontsize_small">'.&mt('(Leave unchecked if not required)').  
                       '</span></td>';  
         my $numinrow = 2;  
         my @possrules = ('uc','lc','num','spec');  
         $datatable .= '<td class="LC_left_item"><table>';  
         for (my $i=0; $i<@possrules; $i++) {  
             my ($rem,$checked);  
             if ($chars{$possrules[$i]}) {  
                 $checked = ' checked="checked"';  
             }  
             $rem = $i%($numinrow);  
             if ($rem == 0) {  
                 if ($i > 0) {  
                     $datatable .= '</tr>';  
                 }  
                 $datatable .= '<tr>';  
             }  
             $datatable .= '<td><span class="LC_nobreak"><label>'.  
                           '<input type="checkbox" name="passwords_chars" value="'.$possrules[$i].'"'.$checked.' />'.  
                           $rulenames{$possrules[$i]}.'</label></span></td>';  
         }  
         my $rem = @possrules%($numinrow);  
         my $colsleft = $numinrow - $rem;  
         if ($colsleft > 1 ) {  
             $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.  
                           '&nbsp;</td>';  
         } elsif ($colsleft == 1) {  
             $datatable .= '<td class="LC_left_item">&nbsp;</td>';  
         }  
         $datatable .='</table></td></tr>';  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'expire'}.'</td>'.  
                       '<td class="LC_left_item"><span class="LC_nobreak">'.  
                       '<input type="text" name="passwords_expire" value="'.$expire.'" size="4" '.  
                       'onblur="javascript:warnIntPass(this);" />'.  
                       '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no expiration)').'</span>'.  
                       '</span></td></tr>';  
         $itemcount ++;  
         $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="passwords_numsaved" value="'.$numsaved.'" size="3" '.  
                       'onblur="javascript:warnIntPass(this);" />'.   
                       '<span class="LC_fontsize_small"> '.&mt('(Leave blank to not save previous passwords)').'</span>'.  
                       '</span></td></tr>';  
     } else {      } else {
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);          my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
         my %ownerchg = (          my %ownerchg = (
Line 7172  sub print_passwords { Line 8142  sub print_passwords {
     return $datatable;      return $datatable;
 }  }
   
   sub password_rules {
       my ($prefix,$itemcountref,$settings) = @_;
       my ($min,$max,%chars,$expire,$numsaved,$numinrow);
       my %titles;
       if ($prefix eq 'passwords') {
           %titles = &Apache::lonlocal::texthash (
               min            => 'Minimum password length',
               max            => 'Maximum password length',
               chars          => 'Required characters',
           );
       } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {
           %titles = &Apache::lonlocal::texthash (
               min            => 'Minimum secret length',
               max            => 'Maximum secret length',
               chars          => 'Required characters',
           );
       }
       $min = $Apache::lonnet::passwdmin;
       my $datatable;
       my $itemcount;
       if (ref($itemcountref)) {
           $itemcount = $$itemcountref;
       }
       if (ref($settings) eq 'HASH') {
           if ($settings->{min}) {
               $min = $settings->{min};
           }
           if ($settings->{max}) {
               $max = $settings->{max};
           }
           if (ref($settings->{chars}) eq 'ARRAY') {
               map { $chars{$_} = 1; } (@{$settings->{chars}});
           }
           if ($prefix eq 'passwords') {
               if ($settings->{expire}) {
                   $expire = $settings->{expire};
               }
               if ($settings->{numsaved}) {
                   $numsaved = $settings->{numsaved};
               }
           }
       }
       my %rulenames = &Apache::lonlocal::texthash(
                                                    uc => 'At least one upper case letter',
                                                    lc => 'At least one lower case letter',
                                                    num => 'At least one number',
                                                    spec => 'At least one non-alphanumeric',
                                                  );
       my $css_class = $itemcount%2?' class="LC_odd_row"':'';
       $datatable .= '<tr'.$css_class.'><td>'.$titles{'min'}.'</td>'.
                     '<td class="LC_left_item"><span class="LC_nobreak">'.
                     '<input type="text" name="'.$prefix.'_min" value="'.$min.'" size="3" '.
                     'onblur="javascript:warnInt'.$prefix.'(this);" />'.
                     '<span class="LC_fontsize_small"> '.&mt('(Enter an integer: 7 or larger)').'</span>'.
                     '</span></td></tr>';
       $itemcount ++;
       $css_class = $itemcount%2?' class="LC_odd_row"':'';
       $datatable .= '<tr'.$css_class.'><td>'.$titles{'max'}.'</td>'.
                     '<td class="LC_left_item"><span class="LC_nobreak">'.
                     '<input type="text" name="'.$prefix.'_max" value="'.$max.'" size="3" '.
                     'onblur="javascript:warnInt'.$prefix.'(this);" />'.
                     '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no maximum)').'</span>'.
                     '</span></td></tr>';
       $itemcount ++;
       $css_class = $itemcount%2?' class="LC_odd_row"':'';
       $datatable .= '<tr'.$css_class.'><td>'.$titles{'chars'}.'<br />'.
                     '<span class="LC_nobreak LC_fontsize_small">'.&mt('(Leave unchecked if not required)').
                     '</span></td>';
       my $numinrow = 2;
       my @possrules = ('uc','lc','num','spec');
       $datatable .= '<td class="LC_left_item"><table>';
       for (my $i=0; $i<@possrules; $i++) {
           my ($rem,$checked);
           if ($chars{$possrules[$i]}) {
               $checked = ' checked="checked"';
           }
           $rem = $i%($numinrow);
           if ($rem == 0) {
               if ($i > 0) {
                   $datatable .= '</tr>';
               }
               $datatable .= '<tr>';
           }
           $datatable .= '<td><span class="LC_nobreak"><label>'.
                         '<input type="checkbox" name="'.$prefix.'_chars" value="'.$possrules[$i].'"'.$checked.' />'.
                         $rulenames{$possrules[$i]}.'</label></span></td>';
       }
       my $rem = @possrules%($numinrow);
       my $colsleft = $numinrow - $rem;
       if ($colsleft > 1 ) {
           $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
                         '&nbsp;</td>';
       } elsif ($colsleft == 1) {
           $datatable .= '<td class="LC_left_item">&nbsp;</td>';
       }
       $datatable .='</table></td></tr>';
       $itemcount ++;
       if ($prefix eq 'passwords') {
           $titles{'expire'} = &mt('Password expiration (days)');
           $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{'expire'}.'</td>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         '<input type="text" name="'.$prefix.'_expire" value="'.$expire.'" size="4" '.
                         'onblur="javascript:warnInt'.$prefix.'(this);" />'.
                         '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no expiration)').'</span>'.
                         '</span></td></tr>';
           $itemcount ++;
           $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 {  sub print_wafproxy {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my $css_class;      my $css_class;
     my $itemcount = 0;      my $itemcount = 0;
     my $datatable;      my $datatable;
     my %servers = &Apache::lonnet::internet_dom_servers($dom);      my %servers = &Apache::lonnet::internet_dom_servers($dom);
     my (%othercontrol,%otherdoms,%aliases,%values,$setdom);      my (%othercontrol,%otherdoms,%aliases,%saml,%values,$setdom,$showdom);
     my %lt = &wafproxy_titles();      my %lt = &wafproxy_titles();
     foreach my $server (sort(keys(%servers))) {      foreach my $server (sort(keys(%servers))) {
         my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});          my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});
           next if ($serverhome eq '');
         my $serverdom;          my $serverdom;
         if ($serverhome ne $server) {          if ($serverhome ne $server) {
             $serverdom = &Apache::lonnet::host_domain($serverhome);              $serverdom = &Apache::lonnet::host_domain($serverhome);
             $othercontrol{$server} = $serverdom;              if (($serverdom ne '') && (&Apache::lonnet::domain($serverdom) ne '')) {
                   $othercontrol{$server} = $serverdom;
               }
         } else {          } else {
             $serverdom = &Apache::lonnet::host_domain($server);              $serverdom = &Apache::lonnet::host_domain($server);
               next if (($serverdom eq '') || (&Apache::lonnet::domain($serverdom) eq ''));
             if ($serverdom ne $dom) {              if ($serverdom ne $dom) {
                 $othercontrol{$server} = $serverdom;                  $othercontrol{$server} = $serverdom;
             } else {              } else {
                 $setdom = 1;                  $setdom = 1;
                 if (ref($settings) eq 'HASH') {                  if (ref($settings) eq 'HASH') {
                     %{$values{$dom}} = ();  
                     if (ref($settings->{'alias'}) eq 'HASH') {                      if (ref($settings->{'alias'}) eq 'HASH') {
                         $aliases{$dom} = $settings->{'alias'};                          $aliases{$dom} = $settings->{'alias'};
                           if ($aliases{$dom} ne '') {
                               $showdom = 1;
                           }
                     }                      }
                     foreach my $item ('ipheader','trusted','vpnint','vpnext') {                      if (ref($settings->{'saml'}) eq 'HASH') {
                         $values{$dom}{$item} = $settings->{$item};                          $saml{$dom} = $settings->{'saml'};
                     }                      }
                 }                  }
             }              }
         }          }
     }      }
       if ($setdom) {
           %{$values{$dom}} = ();
           if (ref($settings) eq 'HASH') {
               foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') {
                   $values{$dom}{$item} = $settings->{$item};
               }
           }
       }
     if (keys(%othercontrol)) {      if (keys(%othercontrol)) {
         %otherdoms = reverse(%othercontrol);          %otherdoms = reverse(%othercontrol);
         foreach my $domain (keys(%otherdoms)) {          foreach my $domain (keys(%otherdoms)) {
             %{$values{$domain}} = ();              %{$values{$domain}} = ();
             my %config = &Apache::lonnet::get_dom('configuration',['wafproxy'],$domain);              my %config = &Apache::lonnet::get_dom('configuration',['wafproxy'],$domain);
             if (ref($config{$domain}) eq 'HASH') {              if (ref($config{'wafproxy'}) eq 'HASH') {
                 if (ref($config{$domain}{'wafproxy'}) eq 'HASH') {                  $aliases{$domain} = $config{'wafproxy'}{'alias'};
                     $aliases{$domain} = $config{$domain}{'wafproxy'}{'alias'};                  if (exists($config{'wafproxy'}{'saml'})) {
                     foreach my $item ('ipheader','trusted','vpnint','vpnext') {                      $saml{$domain} = $config{'wafproxy'}{'saml'};
                         $values{$domain}{$item} = $config{$domain}{'wafproxy'}{$item};                  }
                     }                  foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') {
                       $values{$domain}{$item} = $config{'wafproxy'}{$item};
                 }                  }
             }              }
         }          }
     }      }
     if ($position eq 'top') {      if ($position eq 'top') {
         my %servers = &Apache::lonnet::internet_dom_servers($dom);          my %servers = &Apache::lonnet::internet_dom_servers($dom);
           my %aliasinfo;
         foreach my $server (sort(keys(%servers))) {          foreach my $server (sort(keys(%servers))) {
             $itemcount ++;               $itemcount ++;
             $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';              my $dom_in_effect;
             $datatable .= '<tr'.$css_class.'>'.              my $aliasrows = '<tr>'.
                           '<td>'.&mt('Hostname').':&nbsp;'.                              '<td class="LC_left_item" style="vertical-align: baseline;">'.
                                 &Apache::lonnet::hostname($server).'</td>'.                              &mt('Hostname').':&nbsp;'.
                           '<td class="LC_right_item">';                              '<i>'.&Apache::lonnet::hostname($server).'</i></td><td>&nbsp;</td>';
             if ($othercontrol{$server}) {              if ($othercontrol{$server}) {
                 my $current;                  $dom_in_effect = $othercontrol{$server};
                 if (ref($aliases{$othercontrol{$server}}) eq 'HASH') {                  my ($current,$forsaml);
                     $current = $aliases{$othercontrol{$server}{$server}};                  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) {                  if ($current) {
                     $datatable .= $current;                      $aliasrows .= $current;
                       if ($forsaml) {
                            $aliasrows .= '&nbsp;('.&mt('also for SSO Auth').')';
                       }
                 } else {                  } else {
                     $datatable .= &mt('None in effect');                      $aliasrows .= &mt('None');
                 }                  }
                 $datatable .= '<br /><span class="LC_small">('.                  $aliasrows .= '&nbsp;<span class="LC_small">('.
                               &mt('WAF/Reverse Proxy controlled by domain: [_1]',                                &mt('controlled by domain: [_1]',
                                   '<b>'.$othercontrol{$server}.'</b>').'</span>';                                    '<b>'.$dom_in_effect.'</b>').')</span></td>';
             } else {              } else {
                 my $current;                  $dom_in_effect = $dom;
                   my ($current,$samlon,$samloff);
                   $samloff = ' checked="checked"';
                 if (ref($aliases{$dom}) eq 'HASH') {                  if (ref($aliases{$dom}) eq 'HASH') {
                     if ($aliases{$dom}{$server}) {                      if ($aliases{$dom}{$server}) {
                         $current = $aliases{$dom}{$server};                          $current = $aliases{$dom}{$server};
                     }                      }
                 }                  }
                 $datatable .= '<input type="text" name="wafproxy_alias_'.$server.'" '.                  if (ref($saml{$dom}) eq 'HASH') {
                               'value="'.$current.'" size="30" />';                      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++;
             }              }
             $datatable .= '</td></tr>';  
         }          }
     } else {      } else {
           my %ip_methods = &remoteip_methods();
         if ($setdom) {          if ($setdom) {
             $itemcount ++;              $itemcount ++;
             $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';              $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
             $datatable .= '<tr'.$css_class.'>'.              my ($nowafstyle,$wafstyle,$curr_remotip,$currwafdisplay,$vpndircheck,$vpnaliascheck,
                   $currwafvpn,$wafrangestyle,$alltossl,$ssltossl);
               $wafstyle = ' style="display:none;"';
               $nowafstyle = ' style="display:table-row;"';
               $currwafdisplay = ' style="display: none"';
               $wafrangestyle = ' style="display: none"';
               $curr_remotip = 'n';
               $ssltossl = ' checked="checked"';
               if ($showdom) {
                   $wafstyle = ' style="display:table-row;"';
                   $nowafstyle =  ' style="display:none;"';
                   if (keys(%{$values{$dom}})) {
                       if ($values{$dom}{remoteip} =~ /^[nmh]$/) {
                           $curr_remotip = $values{$dom}{remoteip};
                       }
                       if ($curr_remotip eq 'h') {
                           $currwafdisplay = ' style="display:table-row"';
                           $wafrangestyle = ' style="display:inline-block;"';
                       }
                       if ($values{$dom}{'sslopt'}) {
                           $alltossl = ' checked="checked"';
                           $ssltossl = '';
                       }
                   }
                   if (($values{$dom}{'vpnint'} ne '') || ($values{$dom}{'vpnext'} ne '')) {
                       $vpndircheck = ' checked="checked"';
                       $currwafvpn = ' style="display:table-row;"';
                       $wafrangestyle = ' style="display:inline-block;"';
                   } else {
                       $vpnaliascheck = ' checked="checked"';
                       $currwafvpn = ' style="display:none;"';
                   }
               }
               $datatable .= '<tr'.$css_class.' id="nowafproxyrow_'.$dom.'"'.$wafstyle.'>'.
                             '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'</td>'.
                             '<td class="LC_right_item">'.&mt('WAF not in use, nothing to set').'</td>'.
                             '</tr>'.
                             '<tr'.$css_class.' id="wafproxyrow_'.$dom.'"'.$wafstyle.'>'.
                           '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'<br /><br />'.                            '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'<br /><br />'.
                           &mt('Format for comma separated IP blocks').':<br />'.                            '<div id="wafproxyranges_'.$dom.'">'.&mt('Format for comma separated IP ranges').':<br />'.
                           &mt('A.B.C.D/N or A.B.C.D - E.F.G.H').'</td>'.                            &mt('A.B.C.D/N or A.B.C.D-E.F.G.H').'<br />'.
                           '<td class="LC_left_item"><table>';                            &mt('Range(s) stored in CIDR notation').'</div></td>'.
             foreach my $item ('ipheader','trusted','vpnint','vpnext') {                            '<td class="LC_left_item"><table>'.
                 $datatable .= '<tr>'.                            '<tr>'.
                               '<td valign="top">'.$lt{$item}.':&nbsp;';                            '<td valign="top">'.$lt{'remoteip'}.':&nbsp;'.
                 if ($item eq 'ipheader') {                            '<select name="wafproxy_remoteip" id="wafproxy_remoteip" onchange="javascript:updateWAF();">';
                     $datatable .= '<input type="text" value="'.$values{$dom}{$item}.'" '.              foreach my $option ('m','h','n') {
                                   'name="wafproxy_'.$item.'" />';                  my $sel;
                    if ($option eq $curr_remotip) {
                 } else {                     $sel = ' selected="selected"';
                     $datatable .= '<textarea name="wafproxy_'.$item.'" rows="3" cols="80">'.                  }
                                   $values{$dom}{$item}.'</textarea>';                  $datatable .= '<option value="'.$option.'"'.$sel.'>'.
                 }                                $ip_methods{$option}.'</option>';
                 $datatable .= '</td></tr>';              }
             }              $datatable .= '</select></td></tr>'."\n".
             $datatable .= '</table></td></tr>';                            '<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)) {          if (keys(%otherdoms)) {
             foreach my $domain (sort(keys(%otherdoms))) {              foreach my $domain (sort(keys(%otherdoms))) {
                 $itemcount ++;                  $itemcount ++;
                 $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 class="LC_left_item">'.&mt('Domain: [_1]',$domain).'</td>'.                                '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$domain.'</b>').'</td>'.
                               '<td class="LC_left_item"><table>';                                '<td class="LC_left_item"><table>';
                 foreach my $item ('ipheader','trusted','vpnint','vpnext') {                  foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext','sslopt') {
                     my $showval = &mt('None');                      my $showval = &mt('None');
                       if ($item eq 'ssl') {
                           $showval = $lt{'ssltossl'};
                       }
                     if ($values{$domain}{$item}) {                      if ($values{$domain}{$item}) {
                         $showval = $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>'.                      $datatable .= '<tr>'.
                                   '<td>'.$lt{$item}.':&nbsp;'.$showval.'</td></tr>';                                    '<td>'.$lt{$item}.':&nbsp;'.$showval.'</td></tr>';
                 }                  }
                 $datatable .= '</table></td></tr>';                   $datatable .= '</table></td></tr>';
             }              }
         }          }
     }      }
Line 7302  sub print_wafproxy { Line 8550  sub print_wafproxy {
   
 sub wafproxy_titles {  sub wafproxy_titles {
     return &Apache::lonlocal::texthash(      return &Apache::lonlocal::texthash(
                vpnint => 'Internal IP Range(s) for VPN sessions',                 remoteip   => "Method for determining user's IP",
                vpnext => 'IP Range for backend WAF connections',                 ipheader   => 'Request header containing remote IP',
                trusted => 'Trusted IP range(s)',                 trusted    => 'Trusted IP range(s)',
                ipheader => 'Custom request header',                 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',
            );             );
 }  }
   
Line 8033  sub print_loadbalancing { Line 9296  sub print_loadbalancing {
                                   no => ' checked="checked"',                                    no => ' checked="checked"',
                               );                                );
         my %balcookiechecked = (          my %balcookiechecked = (
                                   no => ' checked="checked"',                                     no => ' checked="checked"',
                                );                                 );
         foreach my $sparetype (@sparestypes) {          foreach my $sparetype (@sparestypes) {
             my $targettable;              my $targettable;
Line 8388  sub tool_titles { Line 9651  sub tool_titles {
     my %titles = &Apache::lonlocal::texthash (      my %titles = &Apache::lonlocal::texthash (
                      aboutme    => 'Personal web page',                       aboutme    => 'Personal web page',
                      blog       => 'Blog',                       blog       => 'Blog',
                      webdav     => 'WebDAV',  
                      portfolio  => 'Portfolio',                       portfolio  => 'Portfolio',
                        timezone   => 'Can set time zone',
                      official   => 'Official courses (with institutional codes)',                       official   => 'Official courses (with institutional codes)',
                      unofficial => 'Unofficial courses',                       unofficial => 'Unofficial courses',
                      community  => 'Communities',                       community  => 'Communities',
Line 8619  sub print_selfcreation { Line 9882  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 8756  sub print_selfcreation { Line 10019  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 8783  sub print_selfcreation { Line 10046  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 8886  function toggleEmailOptions(form,radio,p Line 10149  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 8909  ENDSCRIPT Line 10172  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 8927  sub noninst_users { Line 10190  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 9055  sub noninst_users { Line 10318  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 9171  sub user_formats_row { Line 10434  sub user_formats_row {
                    'username' => 'new usernames',                     'username' => 'new usernames',
                    'id'       => 'IDs',                     'id'       => 'IDs',
                );                 );
     unless ($type eq 'email') {      unless (($type eq 'email') || ($type eq 'unamemap')) {
         my $css_class = $rowcount%2?' class="LC_odd_row"':'';          my $css_class = $rowcount%2?' class="LC_odd_row"':'';
         $output = '<tr '.$css_class.'>'.          $output = '<tr '.$css_class.'>'.
                   '<td><span class="LC_nobreak">'.                    '<td><span class="LC_nobreak">'.
Line 9226  sub user_formats_row { Line 10489  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></table>';      $output .= '</tr>';
     unless ($type eq 'email') {      unless (($type eq 'email') || ($type eq 'unamemap')) {
         $output .= '</td></tr>';          $output .= '</table></td></tr>';
     }      }
     return $output;      return $output;
 }  }
Line 9360  sub print_defaults { Line 10623  sub print_defaults {
             } elsif ($item eq 'lang_def') {              } elsif ($item eq 'lang_def') {
                 my $includeempty = 1;                  my $includeempty = 1;
                 $datatable .= &Apache::loncommon::select_language($item,$defaults{$item},$includeempty);                  $datatable .= &Apache::loncommon::select_language($item,$defaults{$item},$includeempty);
             } else {              } elsif ($item eq 'portal_def') {
                 my $size;  
                 if ($item eq 'portal_def') {  
                     $size = ' size="25"';  
                 }  
                 $datatable .= '<input type="text" name="'.$item.'" value="'.                  $datatable .= '<input type="text" name="'.$item.'" value="'.
                               $defaults{$item}.'"'.$size.' />';                                $defaults{$item}.'" size="25" onkeyup="portalExtras(this);" />';
                   my $portalsty = 'none';
                   if ($defaults{$item}) {
                       $portalsty = 'block';
                   }
                   foreach my $field ('email','web') {
                       my $checkedoff = ' checked="checked"';
                       my $checkedon;
                       if ($defaults{$item.'_'.$field}) {
                           $checkedon = $checkedoff;
                           $checkedoff = '';
                       }
                       $datatable .= '<div id="'.$item.'_'.$field.'_div" style="display:'.$portalsty.'">'.
                                 '<span class="LC_nobreak">'.$titles->{$field}.'&nbsp;'.
                                 '<label><input type="radio" name="'.$item.'_'.$field.'" value="1"'.$checkedon.'/>'.&mt('Yes').'</label>'.
                                 ('&nbsp;'x2).
                                 '<label><input type="radio" name="'.$item.'_'.$field.'" value="0"'.$checkedoff.'/>'.&mt('No').'</label>'.
                                 '</div>';
                   }
               } else {
                   $datatable .= '<input type="text" name="'.$item.'" value="'.$defaults{$item}.'" />';
             }              }
             $datatable .= '</td></tr>';              $datatable .= '</td></tr>';
             $rownum ++;              $rownum ++;
         }          }
     } else {      } elsif ($position eq 'middle') {
         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 9395  sub print_defaults { Line 10674  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" colspan="2"><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 9415  sub print_defaults { Line 10694  sub print_defaults {
                               '<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" colspan="2"><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 9446  sub defaults_titles { Line 10741  sub defaults_titles {
                    'timezone_def'  => 'Default timezone',                     'timezone_def'  => 'Default timezone',
                    'datelocale_def' => 'Default locale for dates',                     'datelocale_def' => 'Default locale for dates',
                    'portal_def'     => 'Portal/Default URL',                     'portal_def'     => 'Portal/Default URL',
                      'email'          => 'Email links use portal URL',
                      'web'            => 'Public web links use portal URL',
                    'intauth_cost'   => 'Encryption cost for bcrypt (positive integer)',                     'intauth_cost'   => 'Encryption cost for bcrypt (positive integer)',
                    'intauth_check'  => 'Check bcrypt cost if authenticated',                     'intauth_check'  => 'Check bcrypt cost if authenticated',
                    'intauth_switch' => 'Existing crypt-based switched to bcrypt on authentication',                     'intauth_switch' => 'Existing crypt-based switched to bcrypt on authentication',
Line 9678  sub legacy_scantronformat { Line 10975  sub legacy_scantronformat {
     my ($url,$error);      my ($url,$error);
     my @statinfo = &Apache::lonnet::stat_file($newurl);      my @statinfo = &Apache::lonnet::stat_file($newurl);
     if ((!@statinfo) || ($statinfo[0] eq 'no_such_dir')) {      if ((!@statinfo) || ($statinfo[0] eq 'no_such_dir')) {
           my $modified = [];
         (my $result,$url) =          (my $result,$url) =
             &publishlogo($r,'copy',$legacyfile,$dom,$confname,'scantron',              &Apache::lonconfigsettings::publishlogo($r,'copy',$legacyfile,$dom,$confname,
                          '','',$newfile);                                                      'scantron','','',$newfile,$modified);
         if ($result ne 'ok') {          if ($result eq 'ok') {
               &update_modify_urls($r,$modified);
           } else {
             $error = &mt("An error occurred publishing the [_1] bubblesheet format file in RES space. Error was: [_2].",$newfile,$result);              $error = &mt("An error occurred publishing the [_1] bubblesheet format file in RES space. Error was: [_2].",$newfile,$result);
         }          }
     }      }
Line 10160  sub serverstatus_pages { Line 11460  sub serverstatus_pages {
 sub defaults_javascript {  sub defaults_javascript {
     my ($settings) = @_;      my ($settings) = @_;
     return unless (ref($settings) eq 'HASH');      return unless (ref($settings) eq 'HASH');
       my $portal_js = <<"ENDPORTAL";
   
   function portalExtras(caller) {
       var x = caller.value;
       var y = new Array('email','web');
       for (var i=0; i<y.length; i++) {
           if (document.getElementById('portal_def_'+y[i]+'_div')) {
               var z = document.getElementById('portal_def_'+y[i]+'_div');
               if (x.length > 0) {
                   z.style.display = 'block';
               } else {
                   z.style.display = 'none';
               }
           }
       }
   }
   ENDPORTAL
     if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {      if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {
         my $maxnum = scalar(@{$settings->{'inststatusorder'}});          my $maxnum = scalar(@{$settings->{'inststatusorder'}});
         if ($maxnum eq '') {          if ($maxnum eq '') {
Line 10213  $jstext Line 11530  $jstext
     return;      return;
 }  }
   
   $portal_js
   
   // ]]>
   </script>
   
   ENDSCRIPT
       } else {
   return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   $portal_js
 // ]]>  // ]]>
 </script>  </script>
   
Line 10222  ENDSCRIPT Line 11550  ENDSCRIPT
 }  }
   
 sub passwords_javascript {  sub passwords_javascript {
     my %intalert = &Apache::lonlocal::texthash (      my ($prefix) = @_;
         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.',      my %intalert;
         authcost => 'Warning: bcrypt encryption cost for internal authentication must be an integer.',      if ($prefix eq 'passwords') {
         passmin => 'Warning: minimum password length must be a positive integer greater than 6.',          %intalert = &Apache::lonlocal::texthash (
         passmax => 'Warning: maximum password length must be a positive integer (or blank).',              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.',
         passexp => 'Warning: days before password expiration must be a positive integer (or blank).',              authcost => 'Warning: bcrypt encryption cost for internal authentication must be an integer.',
         passnum => 'Warning: number of previous passwords to save must be a positive integer (or blank).',              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).',
               passexp => 'Warning: days before password expiration must be a positive integer (or blank).',
               passnum => 'Warning: number of previous passwords to save must be a positive integer (or blank).',
           );
       } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {
           %intalert = &Apache::lonlocal::texthash (
               passmin => 'Warning: minimum secret length must be a positive integer greater than 6.',
               passmax => 'Warning: maximum secret length must be a positive integer (or blank).',
           );
       }
     &js_escape(\%intalert);      &js_escape(\%intalert);
     my $defmin = $Apache::lonnet::passwdmin;      my $defmin = $Apache::lonnet::passwdmin;
     my $intauthjs = <<"ENDSCRIPT";      my $intauthjs;
       if ($prefix eq 'passwords') { $intauthjs = <<"ENDSCRIPT";
   
 function warnIntAuth(field) {  function warnIntAuth(field) {
     if (field.name == 'intauth_check') {      if (field.name == 'intauth_check') {
Line 10252  function warnIntAuth(field) { Line 11590  function warnIntAuth(field) {
     return;      return;
 }  }
   
 function warnIntPass(field) {  ENDSCRIPT
   
        }
   
        $intauthjs .= <<"ENDSCRIPT";
   
   function warnInt$prefix(field) {
     field.value.replace(/^\s+/,'');      field.value.replace(/^\s+/,'');
     field.value.replace(/\s+\$/,'');      field.value.replace(/\s+\$/,'');
     var regexdigit=/^\\d+\$/;      var regexdigit=/^\\d+\$/;
     if (field.name == 'passwords_min') {      if (field.name == '${prefix}_min') {
         if (field.value == '') {          if (field.value == '') {
             alert('$intalert{passmin}');              alert('$intalert{passmin}');
             field.value = '$defmin';              field.value = '$defmin';
Line 10276  function warnIntPass(field) { Line 11620  function warnIntPass(field) {
             field.value = '';              field.value = '';
         }          }
         if (field.value != '') {          if (field.value != '') {
             if (field.name == 'passwords_expire') {              if (field.name == '${prefix}_expire') {
                 var regexpposnum=/^\\d+(|\\.\\d*)\$/;                   var regexpposnum=/^\\d+(|\\.\\d*)\$/; 
                 if (!regexpposnum.test(field.value)) {                  if (!regexpposnum.test(field.value)) {
                     alert('$intalert{passexp}');                      alert('$intalert{passexp}');
Line 10290  function warnIntPass(field) { Line 11634  function warnIntPass(field) {
                 }                  }
             } else {              } else {
                 if (!regexdigit.test(field.value)) {                  if (!regexdigit.test(field.value)) {
                     if (field.name == 'passwords_max') {                      if (field.name == '${prefix}_max') {
                         alert('$intalert{passmax}');                          alert('$intalert{passmax}');
                     } else {                      } else {
                         if (field.name == 'passwords_numsaved') {                          if (field.name == '${prefix}_numsaved') {
                             alert('$intalert{passnum}');                              alert('$intalert{passnum}');
                         }                          }
                     }                      }
Line 10424  ENDSCRIPT Line 11768  ENDSCRIPT
 sub initialize_categories {  sub initialize_categories {
     my ($itemcount) = @_;      my ($itemcount) = @_;
     my ($datatable,$css_class,$chgstr);      my ($datatable,$css_class,$chgstr);
     my %default_names = (      my %default_names = &Apache::lonlocal::texthash (
                       instcode    => 'Official courses (with institutional codes)',                        instcode    => 'Official courses (with institutional codes)',
                       communities => 'Communities',                        communities => 'Communities',
                       placement   => 'Placement Tests',                        placement   => 'Placement Tests',
Line 10619  sub modifiable_userdata_row { Line 11963  sub modifiable_userdata_row {
               '<td class="LC_left_item" colspan="2"><table>';                '<td class="LC_left_item" colspan="2"><table>';
     my $rem;      my $rem;
     my %checks;      my %checks;
     my %current;  
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         my $hashref;          my $hashref;
         if ($context eq 'lti') {          if ($context eq 'lti') {
Line 10645  sub modifiable_userdata_row { Line 11988  sub modifiable_userdata_row {
                 }                  }
             }              }
         }          }
         if (ref($hashref) eq 'HASH') {           if (ref($hashref) eq 'HASH') {
             foreach my $field (@fields) {              foreach my $field (@fields) {
                 if ($hashref->{$field}) {                  if ($hashref->{$field}) {
                     if ($role eq 'emailusername') {                      if ($role eq 'emailusername') {
Line 10657  sub modifiable_userdata_row { Line 12000  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 10746  sub insttypes_row { Line 12088  sub insttypes_row {
     my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rowtotal,$onclick,      my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rowtotal,$onclick,
         $customcss,$rowstyle) = @_;          $customcss,$rowstyle) = @_;
     my %lt = &Apache::lonlocal::texthash (      my %lt = &Apache::lonlocal::texthash (
                       cansearch => 'Users allowed to search',                        cansearch      => 'Users allowed to search',
                       statustocreate => 'Institutional affiliation(s) able to create own account (login/SSO)',                        statustocreate => 'Institutional affiliation(s) able to create own account (login/SSO)',
                       lockablenames => 'User preference to lock name',                        lockablenames  => 'User preference to lock name',
                       selfassign    => 'Self-reportable affiliations',                        selfassign     => 'Self-reportable affiliations',
                       overrides     => "Override domain's helpdesk settings based on requester's affiliation",                        overrides      => "Override domain's helpdesk settings based on requester's affiliation",
                         webdav         => 'WebDAV access available',
                         authorquota    => 'Authoring Space quota (MB)',
              );               );
     my $showdom;      my ($showdom,$defaultquota);
     if ($context eq 'cansearch') {      if ($context eq 'cansearch') {
         $showdom = ' ('.$dom.')';          $showdom = ' ('.$dom.')';
       } elsif ($context eq 'authorquota') {
           $defaultquota = 500;
     }      }
     my $class = 'LC_left_item';      my $class = 'LC_left_item';
     if ($context eq 'statustocreate') {      if ($context eq 'statustocreate') {
Line 10791  sub insttypes_row { Line 12137  sub insttypes_row {
                     }                      }
                     $output .= '<tr>';                      $output .= '<tr>';
                 }                  }
                 my $check = ' ';                  if ($context eq 'authorquota') {
                 if (ref($settings) eq 'HASH') {                      my $currquota;
                     if (ref($settings->{$context}) eq 'ARRAY') {                      if ($settings->{$context}->{$types->[$i]} =~ /^\d+$/) {
                         if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) {                          $currquota = $settings->{$context}->{$types->[$i]};
                             $check = ' checked="checked" ';                      } else {
                         }                          $currquota = $defaultquota;
                     } elsif (ref($settings->{$context}) eq 'HASH') {                      }
                         if (ref($settings->{$context}->{$types->[$i]}) eq 'HASH') {                      $output .= '<td class="LC_left_item">'."\n".
                                  '<label><span class="LC_nobreak">'."\n".
                                  $usertypes->{$types->[$i]}.'</span><br />'."\n".
                                  '<input type="text" name="'.$context.'_'.$types->[$i].'" '.
                                  'value="'.$currquota.'" size="5"'.$onclick.'/>'."\n".
                                  '</label></td>';
                   } else {
                       my $check = ' ';
                       if (ref($settings) eq 'HASH') {
                           if (ref($settings->{$context}) eq 'ARRAY') {
                               if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) {
                                   $check = ' checked="checked" ';
                               }
                           } elsif (ref($settings->{$context}) eq 'HASH') {
                               if (ref($settings->{$context}->{$types->[$i]}) eq 'HASH') {
                                   $check = ' checked="checked" ';
                               } elsif ($context eq 'webdav') {
                                   if ($settings->{$context}->{$types->[$i]}) {
                                       $check = ' checked="checked" ';
                                   }
                               }
                           } elsif ($context eq 'statustocreate') {
                             $check = ' checked="checked" ';                              $check = ' checked="checked" ';
                         }                          }
                     } elsif ($context eq 'statustocreate') {  
                         $check = ' checked="checked" ';  
                     }                      }
                       $output .= '<td class="LC_left_item">'.
                                  '<span class="LC_nobreak"><label>'.
                                  '<input type="checkbox" name="'.$context.'" '.
                                  'value="'.$types->[$i].'"'.$check.$onclick.'/>'.
                                  $usertypes->{$types->[$i]}.'</label></span></td>';
                 }                  }
                 $output .= '<td class="LC_left_item">'.  
                            '<span class="LC_nobreak"><label>'.  
                            '<input type="checkbox" name="'.$context.'" '.  
                            'value="'.$types->[$i].'"'.$check.$onclick.' />'.  
                            $usertypes->{$types->[$i]}.'</label></span></td>';  
             }              }
         }          }
         $rem = @{$types}%($numinrow);          $rem = @{$types}%($numinrow);
Line 10821  sub insttypes_row { Line 12186  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) {
             $output .= '<tr>';              $output .= '<tr>';
Line 10831  sub insttypes_row { Line 12196  sub insttypes_row {
         } else {          } else {
             $output .= '<td class="LC_left_item">';              $output .= '<td class="LC_left_item">';
         }          }
         my $defcheck = ' ';          if ($context eq 'authorquota') {
         if (ref($settings) eq 'HASH') {                my $currquota = 500;
             if (ref($settings->{$context}) eq 'ARRAY') {              if ((ref($settings) eq 'HASH') && (ref($settings->{$context}) eq 'HASH')) {
                 if (grep(/^default$/,@{$settings->{$context}})) {                  if ($settings->{$context}{'default'} =~ /^\d+$/) {
                       $currquota = $settings->{$context}{'default'};
                   }
               }
               $output .= '<label><span class="LC_nobreak">'.$othertitle.'</span><br />'."\n".
                          '<input type="text" name="'.$context.'_default" '.
                          'value="'.$currquota.'" size="5"'.$onclick.'/>'."\n".
                          '</label>';
           } else {
               my $defcheck = ' ';
               if (ref($settings) eq 'HASH') {
                   if (ref($settings->{$context}) eq 'ARRAY') {
                       if (grep(/^default$/,@{$settings->{$context}})) {
                           $defcheck = ' checked="checked" ';
                       }
                   } elsif (ref($settings->{$context}) eq 'HASH') {
                       if (ref($settings->{$context}->{'default'}) eq 'HASH') {
                           $defcheck = ' checked="checked" ';
                       } elsif ($context eq 'webdav') {
                           if ($settings->{$context}->{'default'}) {
                               $defcheck = ' checked="checked" ';
                           }
                       }
                   } elsif ($context eq 'statustocreate') {
                     $defcheck = ' checked="checked" ';                      $defcheck = ' checked="checked" ';
                 }                  }
             } elsif ($context eq 'statustocreate') {  
                 $defcheck = ' checked="checked" ';  
             }              }
               $output .= '<span class="LC_nobreak"><label>'.
                          '<input type="checkbox" name="'.$context.'" '.
                          'value="default"'.$defcheck.$onclick.'/>'.
                          $othertitle.'</label></span>';
         }          }
         $output .= '<span class="LC_nobreak"><label>'.  
                    '<input type="checkbox" name="'.$context.'" '.  
                    'value="default"'.$defcheck.$onclick.' />'.  
                    $othertitle.'</label></span>';  
     }      }
     $output .= '</td></tr></table></td></tr>';      $output .= '</td></tr></table></td></tr>';
     return $output;      return $output;
Line 10923  sub usertype_update_row { Line 12309  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 10936  sub modify_login { Line 12324  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 11074  sub modify_login { Line 12477  sub modify_login {
                 if ($addedfile ne '') {                  if ($addedfile ne '') {
                     push(@allnew,$addedfile);                      push(@allnew,$addedfile);
                 }                  }
                   my $modified = [];
                 foreach my $lang (@allnew) {                  foreach my $lang (@allnew) {
                     my $formelem = 'loginhelpurl_'.$lang;                      my $formelem = 'loginhelpurl_'.$lang;
                     if ($lang eq $env{'form.loginhelpurl_add_lang'}) {                      if ($lang eq $env{'form.loginhelpurl_add_lang'}) {
                         $formelem = 'loginhelpurl_add_file';                          $formelem = 'loginhelpurl_add_file';
                     }                      }
                     (my $result,$newurl{$lang}) = &publishlogo($r,'upload',$formelem,$dom,$confname,                      (my $result,$newurl{$lang}) =
                                                                "help/$lang",'','',$newfile{$lang});                          &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,
                                                                   "help/$lang",'','',$newfile{$lang},
                                                                   $modified);
                     if ($result eq 'ok') {                      if ($result eq 'ok') {
                         $loginhash{'login'}{'helpurl'}{$lang} = $newurl{$lang};                          $loginhash{'login'}{'helpurl'}{$lang} = $newurl{$lang};
                         $changes{'helpurl'}{$lang} = 1;                          $changes{'helpurl'}{$lang} = 1;
Line 11093  sub modify_login { Line 12499  sub modify_login {
                         }                          }
                     }                      }
                 }                  }
                   &update_modify_urls($r,$modified);
             } else {              } else {
                 $error = &mt("Upload of custom log-in help file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);                  $error = &mt("Upload of custom log-in help file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);
             }              }
Line 11150  sub modify_login { Line 12557  sub modify_login {
             if ($switchserver) {              if ($switchserver) {
                 $error = &mt("Upload of custom markup is not permitted to this server: [_1]",$switchserver);                  $error = &mt("Upload of custom markup is not permitted to this server: [_1]",$switchserver);
             } elsif ($author_ok eq 'ok') {              } elsif ($author_ok eq 'ok') {
                   my $modified = [];
                 foreach my $lonhost (@newhosts) {                  foreach my $lonhost (@newhosts) {
                     my $formelem = 'loginheadtag_'.$lonhost;                      my $formelem = 'loginheadtag_'.$lonhost;
                     (my $result,$newheadtagurls{$lonhost}) = &publishlogo($r,'upload',$formelem,$dom,$confname,                      (my $result,$newheadtagurls{$lonhost}) =
                                                                           "login/headtag/$lonhost",'','',                          &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,
                                                                           $env{'form.loginheadtag_'.$lonhost.'.filename'});                                                                  "login/headtag/$lonhost",'','',
                                                                   $env{'form.loginheadtag_'.$lonhost.'.filename'},
                                                                   $modified);
                     if ($result eq 'ok') {                      if ($result eq 'ok') {
                         $loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $newheadtagurls{$lonhost};                          $loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $newheadtagurls{$lonhost};
                         $changes{'headtag'}{$lonhost} = 1;                          $changes{'headtag'}{$lonhost} = 1;
Line 11171  sub modify_login { Line 12581  sub modify_login {
                         }                          }
                     }                      }
                 }                  }
                   &update_modify_urls($r,$modified);
             } else {              } else {
                 $error = &mt("Upload of custom markup file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);                  $error = &mt("Upload of custom markup file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);
             }              }
Line 11182  sub modify_login { Line 12593  sub modify_login {
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';              $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
         }          }
     }      }
       my @delsamlimg = &Apache::loncommon::get_env_multiple('form.saml_img_del');
       my @newsamlimgs;
       foreach my $lonhost (keys(%domservers)) {
           if ($env{'form.saml_'.$lonhost}) {
               if ($env{'form.saml_img_'.$lonhost.'.filename'}) {
                   push(@newsamlimgs,$lonhost);
               }
               foreach my $item ('text','alt','url','title','window','notsso') {
                   $env{'form.saml_'.$item.'_'.$lonhost} =~ s/^\s+|\s+$//g;
               }
               if ($saml{$lonhost}) {
                   if ($env{'form.saml_window_'.$lonhost} ne '1') {
                       $env{'form.saml_window_'.$lonhost} = '';
                   }
                   if (grep(/^\Q$lonhost\E$/,@delsamlimg)) {
   #FIXME Need to obsolete published image
                       delete($currsaml{$lonhost}{'img'});
                       $changes{'saml'}{$lonhost} = 1;
                   }
                   if ($env{'form.saml_alt_'.$lonhost} ne $samlalt{$lonhost}) {
                       $changes{'saml'}{$lonhost} = 1;
                   }
                   if ($env{'form.saml_text_'.$lonhost} ne $samltext{$lonhost}) {
                       $changes{'saml'}{$lonhost} = 1;
                   }
                   if ($env{'form.saml_url_'.$lonhost} ne $samlurl{$lonhost}) {
                       $changes{'saml'}{$lonhost} = 1;
                   }
                   if ($env{'form.saml_title_'.$lonhost} ne $samltitle{$lonhost}) {
                       $changes{'saml'}{$lonhost} = 1;
                   }
                   if ($env{'form.saml_window_'.$lonhost} ne $samlwindow{$lonhost}) {
                       $changes{'saml'}{$lonhost} = 1;
                   }
                   if ($env{'form.saml_notsso_'.$lonhost} ne $samlnotsso{$lonhost}) {
                       $changes{'saml'}{$lonhost} = 1;
                   }
               } else {
                   $changes{'saml'}{$lonhost} = 1;
               }
               foreach my $item ('text','alt','url','title','window','notsso') {
                   $currsaml{$lonhost}{$item} = $env{'form.saml_'.$item.'_'.$lonhost};
               }
           } else {
               if ($saml{$lonhost}) {
                   $changes{'saml'}{$lonhost} = 1;
                   delete($currsaml{$lonhost});
               }
           }
       }
       foreach my $posshost (keys(%currsaml)) {
           unless (exists($domservers{$posshost})) {
               delete($currsaml{$posshost});
           }
       }
       %{$loginhash{'login'}{'saml'}} = %currsaml;
       if (@newsamlimgs) {
           my $error;
           my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);
           if ($configuserok eq 'ok') {
               if ($switchserver) {
                   $error = &mt("Upload of SSO Button Image is not permitted to this server: [_1].",$switchserver);
               } elsif ($author_ok eq 'ok') {
                   my $modified = [];
                   foreach my $lonhost (@newsamlimgs) {
                       my $formelem = 'saml_img_'.$lonhost;
                       my ($result,$imgurl) =
                           &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,
                                                                   "login/saml/$lonhost",'','',
                                                                   $env{'form.saml_img_'.$lonhost.'.filename'},
                                                                   $modified);
                       if ($result eq 'ok') {
                           $currsaml{$lonhost}{'img'} = $imgurl;
                           $loginhash{'login'}{'saml'}{$lonhost}{'img'} = $imgurl;
                           $changes{'saml'}{$lonhost} = 1;
                       } else {
                           my $puberror = &mt("Upload of SSO button image failed for [_1] because an error occurred publishing the file in RES space. Error was: [_2].",
                                              $lonhost,$result);
                           $errors .= '<li><span class="LC_error">'.$puberror.'</span></li>';
                       }
                   }
                   &update_modify_urls($r,$modified);
               } else {
                   $error = &mt("Upload of SSO button image file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2].  Error was: [_3].",$confname,$dom,$author_ok);
               }
           } else {
               $error = &mt("Upload of SSO button image file(s) failed because a Domain Configuration user ([_1]) could not be created in domain: [_2].  Error was: [_3].",$confname,$dom,$configuserok);
           }
           if ($error) {
               &Apache::lonnet::logthis($error);
               $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
           }
       }
     &process_captcha('login',\%changes,$loginhash{'login'},$domconfig{'login'});      &process_captcha('login',\%changes,$loginhash{'login'},$domconfig{'login'});
   
     my $defaulthelpfile = '/adm/loginproblems.html';      my $defaulthelpfile = '/adm/loginproblems.html';
Line 11222  sub modify_login { Line 12726  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 11301  sub modify_login { Line 12830  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 11403  sub color_font_choices { Line 12967  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_authordefaults {
       my ($dom,$lastactref,%domconfig) = @_;
   #
   # Retrieve current domain configuration for webDAV and Authoring Space quotas from $domconfig{'quotas'}.
   #
       my (%curr_quotas,%save_quotas,%confhash,%changes,%newvalues);
       if (ref($domconfig{'quotas'}) eq 'HASH') {
           foreach my $key (keys(%{$domconfig{'quotas'}})) {
               if ($key =~ /^webdav|authorquota$/) {
                   $curr_quotas{$key} = $domconfig{'quotas'}{$key};
               } else {
                   $save_quotas{$key} = $domconfig{'quotas'}{$key};
               }
           }
       }
       my %staticdefaults = (
                              'copyright'    => 'default',
                              'sourceavail'  => 'closed',
                              'nocodemirror' => 'off',
                              'domcoordacc'  => 'on',
                              'editors'      => ['edit','xml'].
                              'authorquota'  => 500,
                              'webdav'       => 0,
                            );
       my %titles = &authordefaults_titles();
       foreach my $item ('nocodemirror','domcoordacc') {
           if ($env{'form.'.$item} =~ /^(0|1)$/) {
               $confhash{$item} = $env{'form.'.$item};
           }
       }
       if ($env{'form.copyright'} =~ /^(default|domain|public)$/) {
           $confhash{'copyright'} = $1;
       }
       if ($env{'form.sourceavail'} =~ /^(closed|open)$/) {
           $confhash{'sourceavail'} = $1;
       }
       my @posseditors =  &Apache::loncommon::get_env_multiple('form.author_editors');
       my @okeditors = ('edit','xml','daxe');
       my @editors;
       foreach my $item (@posseditors) {
           if (grep(/^\Q$item\E$/,@okeditors)) {
               push(@editors,$item);
           }
       }
       $confhash{'editors'} = \@editors;
      
       my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
       my @insttypes;
       if (ref($types) eq 'ARRAY') {
           @insttypes = @{$types};
       }
       my @webdavon = &Apache::loncommon::get_env_multiple('form.webdav');
       my %webdav;
       map { $webdav{$_} = 1; } @webdavon;
       foreach my $type (@insttypes,'default') {
           my $possquota = $env{'form.authorquota_'.$type};
           if ($possquota =~ /^\d+$/) {
               $save_quotas{'authorquota'}{$type} = $possquota;
           }
           if ($webdav{$type}) {
               $save_quotas{'webdav'}{$type} = 1;
           } else {
               $save_quotas{'webdav'}{$type} = 0;
           }
       }
       if ($env{'form.webdav_LC_adv'} =~ /^(0|1)$/) {
           $save_quotas{'webdav'}{'_LC_adv'} = $env{'form.webdav_LC_adv'};
       }
       if (ref($domconfig{'authordefaults'}) eq 'HASH') {
           foreach my $item ('nocodemirror','domcoordacc','copyright','sourceavail') {
               if ($domconfig{'authordefaults'}{$item} ne $confhash{$item}) {
                   $changes{$item} = 1;
                }
           }
           if (ref($domconfig{'authordefaults'}{'editors'}) eq 'ARRAY') {
               my @diffs = 
                   &Apache::loncommon::compare_arrays($confhash{'editors'},
                                                      $domconfig{'authordefaults'}{'editors'});
               unless (@diffs == 0) {
                   $changes{'editors'} = 1;
               }
           } else {
               my @diffs =
                   &Apache::loncommon::compare_arrays($confhash{'editors'},
                                                      $staticdefaults{'editors'});
               unless (@diffs == 0) {
                   $changes{'editors'} = 1;
               }
           }
       } else {
           my @offon = ('off','on');
           foreach my $item ('nocodemirror','domcoordacc') {
               if ($offon[$confhash{$item}] ne $staticdefaults{$item}) { 
                   $changes{$item} = 1; 
               }
           }
           foreach my $item ('copyright','sourceavail') {
               if ($confhash{$item} ne $staticdefaults{$item}) {
                   $changes{$item} = 1;
               }
           }
       }
       foreach my $key ('authorquota','webdav') {
           if (ref($curr_quotas{$key}) eq 'HASH') {
               foreach my $type (@insttypes,'default') {
                   if (exists($save_quotas{$key}{$type})) {
                       if ($save_quotas{$key}{$type} ne $curr_quotas{$key}{$type}) {
                           $changes{$key}{$type} = 1;
                       }
                   } elsif (exists($curr_quotas{$key}{$type})) {
                       $save_quotas{$key}{$type} = $curr_quotas{$key}{$type};
                   } else {
                       $save_quotas{$key}{$type} = $staticdefaults{$key};
                   }
               }
           } else {
               foreach my $type (@insttypes,'default') {
                   if (exists($save_quotas{$key}{$type})) {
                       unless ($save_quotas{$key}{$type} eq $staticdefaults{$key}) {
                           $changes{$key}{$type} = 1;
                       }
                   } else {
                       $save_quotas{$key}{$type} = $staticdefaults{$key};
                   }
               }
           }
       }
       if (ref($curr_quotas{'webdav'}) eq 'HASH') {
           if (exists($save_quotas{'webdav'}{'_LC_adv'})) {
               if ($save_quotas{'webdav'}{'_LC_adv'} ne $curr_quotas{'webdav'}{'_LC_adv'}) { 
                   $changes{'webdav_LC_adv'} = 1;
               }
           } elsif (exists($curr_quotas{'webdav'}{'_LC_adv'})) {
               $changes{'webdav_LC_adv'} = 1;
           }
       } elsif (exists($save_quotas{'webdav'}{'_LC_adv'})) {
           $changes{'webdav_LC_adv'} = 1;
       }
       my %confighash = (
                           quotas  => \%save_quotas,
                           authordefaults => \%confhash,
                        );
       my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,
                                                $dom);
       my $resulttext;
       if ($putresult eq 'ok') {
           if (keys(%changes)) {
               if ((exists($changes{'authorquota'})) || (exists($changes{'webdav'})) ||
                   ($changes{'webdav_LC_adv'})) { 
                   my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
                   if ((exists($changes{'authorquota'})) && (ref($save_quotas{'authorquota'}) eq 'HASH')) {
                       $domdefaults{'authorquota'} = $save_quotas{'authorquota'};
                   }
                   if (((exists($changes{'webdav'})) || ($changes{'webdav_LC_adv'})) &&
                       (ref($save_quotas{'webdav'}) eq 'HASH')) {
                       $domdefaults{'webdav'} = $save_quotas{'webdav'};
                   }
                   my $cachetime = 24*60*60;
                   &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
                   if (ref($lastactref) eq 'HASH') {
                       $lastactref->{'domdefaults'} = 1;
                   }
               }
               $resulttext = &mt('Changes made:').'<ul>';
               my $authoroverride;
               foreach my $key ('nocodemirror','domcoordacc','copyright','sourceavail') {
                   if (exists($changes{$key})) {
                       my $shown;
                       unless ($authoroverride) {
                           $resulttext .= '<li>'.&mt('Defaults which can be overridden by Author').'<ul>';
                           $authoroverride = 1;
                       }
                       if (($key eq 'nocodemirror') || ($key eq 'domcoordacc')) { 
                           $shown = ($confhash{$key} ? &mt('Yes') : &mt('No'));
                       } elsif ($key eq 'copyright') {
                           $shown = &Apache::loncommon::copyrightdescription($confhash{$key});
                       } elsif ($key eq 'sourceavail') {
                           $shown = &Apache::loncommon::source_copyrightdescription($confhash{$key});
                       }
                       $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{$key},$shown).'</li>'; 
                   }
               }
               if ($authoroverride) {
                   $resulttext .= '</ul></li>';
               }
               my $domcoordoverride;
               foreach my $key ('editors','authorquota','webdav','webdav_LC_adv') {
                   if (exists($changes{$key})) {
                       my $shown;
                       unless ($domcoordoverride) {
                           $resulttext .= '<li>'.&mt('Defaults which can be overridden by a Domain Coodinator').'<ul>';
                           $domcoordoverride = 1;
                       }
                       if ($key eq 'editors') {
                           if (@{$confhash{'editors'}}) {
                               $shown = join(', ', map { $titles{$_} } @{$confhash{'editors'}});
                           } else {
                               $shown = &mt('None');
                           }
                       } elsif ($key eq 'authorquota') {
                           foreach my $type (@insttypes) {
                               $shown .= $usertypes->{$type}.' -- '.$save_quotas{$key}{$type}.', ';
                           }
                           $shown .= $othertitle.' -- '.$save_quotas{$key}{'default'};
                       } elsif ($key eq 'webdav') {
                           foreach my $type (@insttypes) {
                               $shown .= $usertypes->{$type}.' -- '. ($save_quotas{$key}{$type} ? &mt('Yes') : &mt('No')).', ';
                           }
                           $shown .= $othertitle.' -- '. ($save_quotas{$key}{'default'} ? &mt('Yes') : &mt('No'));
                       } elsif ($key eq 'webdav_LC_adv') {
                           if (exists($save_quotas{'webdav'}{'_LC_adv'})) {
                               $shown = ($save_quotas{'webdav'}{'_LC_adv'} ? $titles{'overon'} : $titles{'overoff'});
                           } else {
                               $shown = $titles{'none'};
                           }
                       }
                       $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{$key},$shown).'</li>';
                   }                               
               }
               if ($domcoordoverride) {
                   $resulttext .= '</ul></li>';
               }
           } else {
               $resulttext = &mt('No changes made to Authoring Space defaults');
           }
       }
       return $resulttext;
   }
   
 sub modify_rolecolors {  sub modify_rolecolors {
     my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_;      my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_;
     my ($resulttext,%rolehash);      my ($resulttext,%rolehash);
Line 11510  sub modify_colors { Line 13580  sub modify_colors {
             $domconfig->{$role} = {};              $domconfig->{$role} = {};
         }          }
         foreach my $img (@images) {          foreach my $img (@images) {
             if (($role eq 'login') && (($img eq 'img') || ($img eq 'logo'))) {                if ($role eq 'login') {
                 if (defined($env{'form.login_showlogo_'.$img})) {                  if (($img eq 'img') || ($img eq 'logo')) {  
                     $confhash->{$role}{'showlogo'}{$img} = 1;                      if (defined($env{'form.login_showlogo_'.$img})) {
                 } else {                           $confhash->{$role}{'showlogo'}{$img} = 1;
                     $confhash->{$role}{'showlogo'}{$img} = 0;                      } else { 
                           $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 11533  sub modify_colors { Line 13608  sub modify_colors {
                         $error = &mt("Upload of [_1] image for $role page(s) is not permitted to this server: [_2]",$choices{$img},$switchserver);                          $error = &mt("Upload of [_1] image for $role page(s) is not permitted to this server: [_2]",$choices{$img},$switchserver);
                     } else {                      } else {
                         if ($author_ok eq 'ok') {                          if ($author_ok eq 'ok') {
                               my $modified = [];
                             my ($result,$logourl) =                               my ($result,$logourl) = 
                                 &publishlogo($r,'upload',$role.'_'.$img,                                  &Apache::lonconfigsettings::publishlogo($r,'upload',$role.'_'.$img,
                                            $dom,$confname,$img,$width,$height);                                                                          $dom,$confname,$img,$width,$height,
                                                                           '',$modified);
                             if ($result eq 'ok') {                              if ($result eq 'ok') {
                                 $confhash->{$role}{$img} = $logourl;                                  $confhash->{$role}{$img} = $logourl;
                                 $changes{$role}{'images'}{$img} = 1;                                  $changes{$role}{'images'}{$img} = 1;
                                   &update_modify_urls($r,$modified);
                             } else {                              } else {
                                 $error = &mt("Upload of [_1] image for $role page(s) failed because an error occurred publishing the file in RES space. Error was: [_2].",$choices{img},$result);                                  $error = &mt("Upload of [_1] image for $role page(s) failed because an error occurred publishing the file in RES space. Error was: [_2].",$choices{img},$result);
                             }                              }
Line 11560  sub modify_colors { Line 13638  sub modify_colors {
 # is confname an author?  # is confname an author?
                         if ($switchserver eq '') {                          if ($switchserver eq '') {
                             if ($author_ok eq 'ok') {                              if ($author_ok eq 'ok') {
                                   my $modified = [];
                                 my ($result,$logourl) =                                   my ($result,$logourl) = 
                                &publishlogo($r,'copy',$domconfig->{$role}{$img},                                      &Apache::lonconfigsettings::publishlogo($r,'copy',$domconfig->{$role}{$img},
                                             $dom,$confname,$img,$width,$height);                                                                              $dom,$confname,$img,$width,$height,
                                                                               '',$modified);
                                 if ($result eq 'ok') {                                  if ($result eq 'ok') {
                                     $confhash->{$role}{$img} = $logourl;                                      $confhash->{$role}{$img} = $logourl;
     $changes{$role}{'images'}{$img} = 1;      $changes{$role}{'images'}{$img} = 1;
                                       &update_modify_urls($r,$modified);
                                 }                                  }
                             }                              }
                         }                          }
Line 11591  sub modify_colors { Line 13672  sub modify_colors {
                             $changes{$role}{'images'}{$img} = 1;                              $changes{$role}{'images'}{$img} = 1;
                         }                           } 
                     }                      }
                     if (($role eq 'login') && (($img eq 'logo') || ($img eq 'img'))) {                      if ($role eq 'login') {
                         if (ref($domconfig->{'login'}{'showlogo'}) eq 'HASH') {                          if (($img eq 'logo') || ($img eq 'img')) {
                             if ($confhash->{$role}{'showlogo'}{$img} ne                               if (ref($domconfig->{'login'}{'showlogo'}) eq 'HASH') {
                                 $domconfig->{$role}{'showlogo'}{$img}) {                                  if ($confhash->{$role}{'showlogo'}{$img} ne 
                                 $changes{$role}{'showlogo'}{$img} = 1;                                       $domconfig->{$role}{'showlogo'}{$img}) {
                                       $changes{$role}{'showlogo'}{$img} = 1; 
                                   }
                               } else {
                                   if ($confhash->{$role}{'showlogo'}{$img} == 0) {
                                       $changes{$role}{'showlogo'}{$img} = 1;
                                   }
                             }                              }
                         } else {                          }
                             if ($confhash->{$role}{'showlogo'}{$img} == 0) {                          if ($img ne 'login') {
                                 $changes{$role}{'showlogo'}{$img} = 1;                              if (ref($domconfig->{$role}{'alttext'}) eq 'HASH') {
                                   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 11710  sub default_change_checker { Line 13805  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 11748  sub display_colorchgs { Line 13848  sub display_colorchgs {
                             } else {                              } else {
                                 $resulttext .= '<li>'.&mt("$choices{$item} set to not be displayed").'</li>';                                  $resulttext .= '<li>'.&mt("$choices{$item} set to not be displayed").'</li>';
                             }                              }
                           } elsif (($role eq 'login') && ($key eq 'alttext')) {
                               if ($confhash->{$role}{$key}{$item} ne '') {
                                   $resulttext .= '<li>'.&mt("$choices{$key} for $choices{$item} set to [_1].",
                                                  $confhash->{$role}{$key}{$item}).'</li>';
                               } else {
                                   $resulttext .= '<li>'.&mt("$choices{$key} for $choices{$item} deleted.").'</li>';
                               }
                         } elsif ($confhash->{$role}{$item} eq '') {                          } elsif ($confhash->{$role}{$item} eq '') {
                             $resulttext .= '<li>'.&mt("$choices{$item} set to default").'</li>';                              $resulttext .= '<li>'.&mt("$choices{$item} set to default").'</li>';
                         } else {                          } else {
Line 11833  sub check_authorstatus { Line 13940  sub check_authorstatus {
     return $author_ok;      return $author_ok;
 }  }
   
 sub publishlogo {  sub update_modify_urls {
     my ($r,$action,$formname,$dom,$confname,$subdir,$thumbwidth,$thumbheight,$savefileas) = @_;      my ($r,$modified) = @_;
     my ($output,$fname,$logourl,$madethumb);      if ((ref($modified) eq 'ARRAY') && (@{$modified})) {
     if ($action eq 'upload') {          push(@{$modified_urls},$modified);
         $fname=$env{'form.'.$formname.'.filename'};          unless ($registered_cleanup) {
         chop($env{'form.'.$formname});              my $handlers = $r->get_handlers('PerlCleanupHandler');
     } else {              $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);
         ($fname) = ($formname =~ /([^\/]+)$/);              $registered_cleanup=1;
     }  
     if ($savefileas ne '') {  
         $fname = $savefileas;  
     }  
     $fname=&Apache::lonnet::clean_filename($fname);  
 # See if there is anything left  
     unless ($fname) { return ('error: no uploaded file'); }  
     $fname="$subdir/$fname";  
     my $docroot=$r->dir_config('lonDocRoot');  
     my $filepath="$docroot/priv";  
     my $relpath = "$dom/$confname";  
     my ($fnamepath,$file,$fetchthumb);  
     $file=$fname;  
     if ($fname=~m|/|) {  
         ($fnamepath,$file) = ($fname =~ m|^(.*)/([^/]+)$|);  
     }  
     my @parts=split(/\//,"$filepath/$relpath/$fnamepath");  
     my $count;  
     for ($count=5;$count<=$#parts;$count++) {  
         $filepath.="/$parts[$count]";  
         if ((-e $filepath)!=1) {  
             mkdir($filepath,02770);  
         }  
     }  
     # Check for bad extension and disallow upload  
     if ($file=~/\.(\w+)$/ &&  
         (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {  
         $output =   
             &mt('Invalid file extension ([_1]) - reserved for internal use.',$1);   
     } elsif ($file=~/\.(\w+)$/ &&  
         !defined(&Apache::loncommon::fileembstyle($1))) {  
         $output = &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1);  
     } elsif ($file=~/\.(\d+)\.(\w+)$/) {  
         $output = &mt('Filename not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2);  
     } elsif (-d "$filepath/$file") {  
         $output = &mt('Filename is a directory name - rename the file and re-upload');  
     } else {  
         my $source = $filepath.'/'.$file;  
         my $logfile;  
         if (!open($logfile,">>",$source.'.log')) {  
             return (&mt('No write permission to Authoring Space'));  
         }  
         print $logfile  
 "\n================= Publish ".localtime()." ================\n".  
 $env{'user.name'}.':'.$env{'user.domain'}."\n";  
 # Save the file  
         if (!open(FH,">",$source)) {  
             &Apache::lonnet::logthis('Failed to create '.$source);  
             return (&mt('Failed to create file'));  
         }  
         if ($action eq 'upload') {  
             if (!print FH ($env{'form.'.$formname})) {  
                 &Apache::lonnet::logthis('Failed to write to '.$source);  
                 return (&mt('Failed to write file'));  
             }  
         } else {  
             my $original = &Apache::lonnet::filelocation('',$formname);  
             if(!copy($original,$source)) {  
                 &Apache::lonnet::logthis('Failed to copy '.$original.' to '.$source);  
                 return (&mt('Failed to write file'));  
             }  
         }  
         close(FH);  
         chmod(0660, $source); # Permissions to rw-rw---.  
   
         my $targetdir=$docroot.'/res/'.$dom.'/'.$confname .'/'.$fnamepath;  
         my $copyfile=$targetdir.'/'.$file;  
   
         my @parts=split(/\//,$targetdir);  
         my $path="/$parts[1]/$parts[2]/$parts[3]/$parts[4]";  
         for (my $count=5;$count<=$#parts;$count++) {  
             $path.="/$parts[$count]";  
             if (!-e $path) {  
                 print $logfile "\nCreating directory ".$path;  
                 mkdir($path,02770);  
             }  
         }  
         my $versionresult;  
         if (-e $copyfile) {  
             $versionresult = &logo_versioning($targetdir,$file,$logfile);  
         } else {  
             $versionresult = 'ok';  
         }  
         if ($versionresult eq 'ok') {  
             if (copy($source,$copyfile)) {  
                 print $logfile "\nCopied original source to ".$copyfile."\n";  
                 $output = 'ok';  
                 $logourl = '/res/'.$dom.'/'.$confname.'/'.$fname;  
                 push(@{$modified_urls},[$copyfile,$source]);  
                 my $metaoutput =   
                     &write_metadata($dom,$confname,$formname,$targetdir,$file,$logfile);  
                 unless ($registered_cleanup) {  
                     my $handlers = $r->get_handlers('PerlCleanupHandler');  
                     $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);  
                     $registered_cleanup=1;  
                 }  
             } else {  
                 print $logfile "\nUnable to write ".$copyfile.':'.$!."\n";  
                 $output = &mt('Failed to copy file to RES space').", $!";  
             }  
             if (($thumbwidth =~ /^\d+$/) && ($thumbheight =~ /^\d+$/)) {  
                 my $inputfile = $filepath.'/'.$file;  
                 my $outfile = $filepath.'/'.'tn-'.$file;  
                 my ($fullwidth,$fullheight) = &check_dimensions($inputfile);  
                 if ($fullwidth ne '' && $fullheight ne '') {   
                     if ($fullwidth > $thumbwidth && $fullheight > $thumbheight) {  
                         my $thumbsize = $thumbwidth.'x'.$thumbheight;  
                         my @args = ('convert','-sample',$thumbsize,$inputfile,$outfile);  
                         system({$args[0]} @args);  
                         chmod(0660, $filepath.'/tn-'.$file);  
                         if (-e $outfile) {  
                             my $copyfile=$targetdir.'/tn-'.$file;  
                             if (copy($outfile,$copyfile)) {  
                                 print $logfile "\nCopied source to ".$copyfile."\n";  
                                 my $thumb_metaoutput =   
                                     &write_metadata($dom,$confname,$formname,  
                                                     $targetdir,'tn-'.$file,$logfile);  
                                 push(@{$modified_urls},[$copyfile,$outfile]);  
                                 unless ($registered_cleanup) {  
                                     my $handlers = $r->get_handlers('PerlCleanupHandler');  
                                     $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);  
                                     $registered_cleanup=1;  
                                 }  
                                 $madethumb = 1;  
                             } else {  
                                 print $logfile "\nUnable to write ".$copyfile.  
                                                ':'.$!."\n";  
                             }  
                         }  
                     }  
                 }  
             }  
         } else {  
             $output = $versionresult;  
         }          }
     }      }
     return ($output,$logourl,$madethumb);  
 }  
   
 sub logo_versioning {  
     my ($targetdir,$file,$logfile) = @_;  
     my $target = $targetdir.'/'.$file;  
     my ($maxversion,$fn,$extn,$output);  
     $maxversion = 0;  
     if ($file =~ /^(.+)\.(\w+)$/) {  
         $fn=$1;  
         $extn=$2;  
     }  
     opendir(DIR,$targetdir);  
     while (my $filename=readdir(DIR)) {  
         if ($filename=~/\Q$fn\E\.(\d+)\.\Q$extn\E$/) {  
             $maxversion=($1>$maxversion)?$1:$maxversion;  
         }  
     }  
     $maxversion++;  
     print $logfile "\nCreating old version ".$maxversion."\n";  
     my $copyfile=$targetdir.'/'.$fn.'.'.$maxversion.'.'.$extn;  
     if (copy($target,$copyfile)) {  
         print $logfile "Copied old target to ".$copyfile."\n";  
         $copyfile=$copyfile.'.meta';  
         if (copy($target.'.meta',$copyfile)) {  
             print $logfile "Copied old target metadata to ".$copyfile."\n";  
             $output = 'ok';  
         } else {  
             print $logfile "Unable to write metadata ".$copyfile.':'.$!."\n";  
             $output = &mt('Failed to copy old meta').", $!, ";  
         }  
     } else {  
         print $logfile "Unable to write ".$copyfile.':'.$!."\n";  
         $output = &mt('Failed to copy old target').", $!, ";  
     }  
     return $output;  
 }  
   
 sub write_metadata {  
     my ($dom,$confname,$formname,$targetdir,$file,$logfile) = @_;  
     my (%metadatafields,%metadatakeys,$output);  
     $metadatafields{'title'}=$formname;  
     $metadatafields{'creationdate'}=time;  
     $metadatafields{'lastrevisiondate'}=time;  
     $metadatafields{'copyright'}='public';  
     $metadatafields{'modifyinguser'}=$env{'user.name'}.':'.  
                                          $env{'user.domain'};  
     $metadatafields{'authorspace'}=$confname.':'.$dom;  
     $metadatafields{'domain'}=$dom;  
     {  
         print $logfile "\nWrite metadata file for ".$targetdir.'/'.$file;  
         my $mfh;  
         if (open($mfh,">",$targetdir.'/'.$file.'.meta')) {  
             foreach (sort(keys(%metadatafields))) {  
                 unless ($_=~/\./) {  
                     my $unikey=$_;  
                     $unikey=~/^([A-Za-z]+)/;  
                     my $tag=$1;  
                     $tag=~tr/A-Z/a-z/;  
                     print $mfh "\n\<$tag";  
                     foreach (split(/\,/,$metadatakeys{$unikey})) {  
                         my $value=$metadatafields{$unikey.'.'.$_};  
                         $value=~s/\"/\'\'/g;  
                         print $mfh ' '.$_.'="'.$value.'"';  
                     }  
                     print $mfh '>'.  
                         &HTML::Entities::encode($metadatafields{$unikey},'<>&"')  
                             .'</'.$tag.'>';  
                 }  
             }  
             $output = 'ok';  
             print $logfile "\nWrote metadata";  
             close($mfh);  
         } else {  
             print $logfile "\nFailed to open metadata file";  
             $output = &mt('Could not write metadata');  
         }  
     }  
     return $output;  
 }  }
   
 sub notifysubscribed {  sub notifysubscribed {
Line 12106  sub subscribed_hosts { Line 14000  sub subscribed_hosts {
   
 sub check_switchserver {  sub check_switchserver {
     my ($dom,$confname) = @_;      my ($dom,$confname) = @_;
     my ($allowed,$switchserver);      my ($allowed,$switchserver,$home);
     my $home = &Apache::lonnet::homeserver($confname,$dom);      if ($confname eq '') {
     if ($home eq 'no_host') {  
         $home = &Apache::lonnet::domain($dom,'primary');          $home = &Apache::lonnet::domain($dom,'primary');
       } else {
           $home = &Apache::lonnet::homeserver($confname,$dom);
           if ($home eq 'no_host') {
               $home = &Apache::lonnet::domain($dom,'primary');
           }
     }      }
     my @ids=&Apache::lonnet::current_machine_ids();      my @ids=&Apache::lonnet::current_machine_ids();
     foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }      foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
     if (!$allowed) {      if (!$allowed) {
  $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&amp;role=dc./'.$dom.'/&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';   $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&amp;role='.
                         &HTML::Entities::encode($env{'request.role'},'\'<>"&').
                         '&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';
     }      }
     return $switchserver;      return $switchserver;
 }  }
Line 12126  sub modify_quotas { Line 14026  sub modify_quotas {
         $author_ok,$switchserver,$errors,$validationitemsref,$validationnamesref,          $author_ok,$switchserver,$errors,$validationitemsref,$validationnamesref,
         $validationfieldsref);          $validationfieldsref);
     if ($action eq 'quotas') {      if ($action eq 'quotas') {
         $context = 'tools';           $context = 'tools';
     } else {      } else {
         $context = $action;          $context = $action;
     }      }
Line 12146  sub modify_quotas { Line 14046  sub modify_quotas {
         @usertools = ('author');          @usertools = ('author');
         %titles = &authorrequest_titles();          %titles = &authorrequest_titles();
     } else {      } else {
         @usertools = ('aboutme','blog','webdav','portfolio');          @usertools = ('aboutme','blog','portfolio','timezone');
         %titles = &tool_titles();          %titles = &tool_titles();
     }      }
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);      my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
Line 12169  sub modify_quotas { Line 14069  sub modify_quotas {
         } else {          } else {
             if ($key =~ /^form\.quota_(.+)$/) {              if ($key =~ /^form\.quota_(.+)$/) {
                 $confhash{'defaultquota'}{$1} = $env{$key};                  $confhash{'defaultquota'}{$1} = $env{$key};
             } elsif ($key =~ /^form\.authorquota_(.+)$/) {  
                 $confhash{'authorquota'}{$1} = $env{$key};  
             } elsif ($key =~ /^form\.\Q$context\E_(.+)$/) {              } elsif ($key =~ /^form\.\Q$context\E_(.+)$/) {
                 @{$toolshash{$1}} = &Apache::loncommon::get_env_multiple($key);                  @{$toolshash{$1}} = &Apache::loncommon::get_env_multiple($key);
             }              }
Line 12464  sub modify_quotas { Line 14362  sub modify_quotas {
         }          }
     } else {      } else {
         $confhash{'defaultquota'}{'default'} = $env{'form.defaultquota'};          $confhash{'defaultquota'}{'default'} = $env{'form.defaultquota'};
         $confhash{'authorquota'}{'default'} = $env{'form.authorquota'};  
     }      }
     foreach my $item (@usertools) {      foreach my $item (@usertools) {
         foreach my $type (@{$types},'default','_LC_adv') {          foreach my $type (@{$types},'default','_LC_adv') {
Line 12553  sub modify_quotas { Line 14450  sub modify_quotas {
                 }                  }
             }              }
             if (ref($domconfig{'quotas'}{'authorquota'}) eq 'HASH') {              if (ref($domconfig{'quotas'}{'authorquota'}) eq 'HASH') {
                 foreach my $key (keys(%{$domconfig{'quotas'}{'authorquota'}})) {                  $confhash{'authorquota'} = $domconfig{'quotas'}{'authorquota'};
                     if (exists($confhash{'authorquota'}{$key})) {              }
                         if ($confhash{'authorquota'}{$key} ne $domconfig{'quotas'}{'authorquota'}{$key}) {              if (ref($domconfig{'quotas'}{'webdav'}) eq 'HASH') {
                             $changes{'authorquota'}{$key} = 1;                  $confhash{'webdav'} = $domconfig{'quotas'}{'webdav'};
                         }  
                     } else {  
                         $confhash{'authorquota'}{$key} = $domconfig{'quotas'}{'authorquota'}{$key};  
                     }  
                 }  
             }              }
         }          }
         if (ref($confhash{'defaultquota'}) eq 'HASH') {          if (ref($confhash{'defaultquota'}) eq 'HASH') {
Line 12581  sub modify_quotas { Line 14473  sub modify_quotas {
                 }                  }
             }              }
         }          }
         if (ref($confhash{'authorquota'}) eq 'HASH') {  
             foreach my $key (keys(%{$confhash{'authorquota'}})) {  
                 if (ref($domconfig{'quotas'}) eq 'HASH') {  
                     if (ref($domconfig{'quotas'}{'authorquota'}) eq 'HASH') {  
                         if (!exists($domconfig{'quotas'}{'authorquota'}{$key})) {  
                             $changes{'authorquota'}{$key} = 1;  
                         }  
                     } else {  
                         $changes{'authorquota'}{$key} = 1;  
                     }  
                 } else {  
                     $changes{'authorquota'}{$key} = 1;  
                 }  
             }  
         }  
     }      }
   
     if ($context eq 'requestauthor') {      if ($context eq 'requestauthor') {
Line 12636  sub modify_quotas { Line 14513  sub modify_quotas {
                     }                      }
                     $resulttext .= '</ul></li>';                      $resulttext .= '</ul></li>';
                 }                  }
                 if (ref($changes{'authorquota'}) eq 'HASH') {  
                     $resulttext .= '<li>'.&mt('Authoring Space default quotas').'<ul>';  
                     foreach my $type (@{$types},'default') {  
                         if (defined($changes{'authorquota'}{$type})) {  
                             my $typetitle = $usertypes->{$type};  
                             if ($type eq 'default') {  
                                 $typetitle = $othertitle;  
                             }  
                             $resulttext .= '<li>'.&mt('[_1] set to [_2] MB',$typetitle,$confhash{'authorquota'}{$type}).'</li>';  
                         }  
                     }  
                     $resulttext .= '</ul></li>';  
                 }  
             }              }
             my %newenv;              my %newenv;
             foreach my $item (@usertools) {              foreach my $item (@usertools) {
Line 12837  sub process_textbook_image { Line 14701  sub process_textbook_image {
             $error = &mt('Upload of textbook image is not permitted to this server: [_1]',              $error = &mt('Upload of textbook image is not permitted to this server: [_1]',
                          $switchserver);                           $switchserver);
         } elsif ($author_ok eq 'ok') {          } elsif ($author_ok eq 'ok') {
               my $modified = [];
             my ($result,$imageurl) =              my ($result,$imageurl) =
                 &publishlogo($r,'upload',$caller,$dom,$confname,                  &Apache::lonconfigsettings::publishlogo($r,'upload',$caller,$dom,$confname,
                              "$type/$cdom/$cnum/cover",$width,$height);                                                          "$type/$cdom/$cnum/cover",$width,$height,
                                                           '',$modified);
             if ($result eq 'ok') {              if ($result eq 'ok') {
                 $url = $imageurl;                  $url = $imageurl;
                   &update_modify_urls($r,$modified);
             } else {              } else {
                 $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);                  $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);
             }              }
Line 12856  sub process_textbook_image { Line 14723  sub process_textbook_image {
   
 sub modify_ltitools {  sub modify_ltitools {
     my ($r,$dom,$action,$lastactref,%domconfig) = @_;      my ($r,$dom,$action,$lastactref,%domconfig) = @_;
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);      my (%currtoolsec,%secchanges,%newtoolsec,%newkeyset);
     my ($newid,@allpos,%changes,%confhash,%encconfig,$errors,$resulttext);      &fetch_secrets($dom,'toolsec',\%domconfig,\%currtoolsec,\%secchanges,\%newtoolsec,\%newkeyset);
   
     my $confname = $dom.'-domainconfig';      my $confname = $dom.'-domainconfig';
     my $servadm = $r->dir_config('lonAdmEMail');      my $servadm = $r->dir_config('lonAdmEMail');
     my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);      my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);
     my (%posslti,%possfield);  
     my @courseroles = ('cc','in','ta','ep','st');      my ($resulttext,$ltitoolsoutput,$is_home,$errors,%ltitoolschg,%newtoolsenc,%newltitools);
     my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner);      my $toolserror =
     map { $posslti{$_} = 1; } @ltiroles;          &Apache::courseprefs::process_ltitools($r,$dom,$confname,$domconfig{'ltitools'},\%ltitoolschg,'domain',
     my @allfields = ('fullname','firstname','lastname','email','user','roles');                                                 $lastactref,$configuserok,$switchserver,$author_ok);
     map { $possfield{$_} = 1; } @allfields;  
     my %lt = &ltitools_names();       my $home = &Apache::lonnet::domain($dom,'primary');
     if ($env{'form.ltitools_add'}) {      unless (($home eq 'no_host') || ($home eq '')) {
         my $title = $env{'form.ltitools_add_title'};          my @ids=&Apache::lonnet::current_machine_ids();
         $title =~ s/(`)/'/g;          foreach my $id (@ids) { if ($id eq $home) { $is_home=1; last; } }
         ($newid,my $error) = &get_ltitools_id($dom,$title);      }
         if ($newid) {  
             my $position = $env{'form.ltitools_add_pos'};      if (keys(%ltitoolschg)) {
             $position =~ s/\D+//g;          foreach my $id (keys(%ltitoolschg)) {
             if ($position ne '') {              if (ref($ltitoolschg{$id}) eq 'HASH') {
                 $allpos[$position] = $newid;                  foreach my $inner (keys(%{$ltitoolschg{$id}})) {
             }                      if (($inner eq 'secret') || ($inner eq 'key')) {
             $changes{$newid} = 1;                          if ($is_home) {
             foreach my $item ('title','url','key','secret','lifetime') {                              $newtoolsenc{$id}{$inner} = $ltitoolschg{$id}{$inner};
                 $env{'form.ltitools_add_'.$item} =~ s/(`)/'/g;  
                 if ($item eq 'lifetime') {  
                     $env{'form.ltitools_add_'.$item} =~ s/[^\d.]//g;  
                 }  
                 if ($env{'form.ltitools_add_'.$item}) {  
                     if (($item eq 'key') || ($item eq 'secret')) {  
                         $encconfig{$newid}{$item} = $env{'form.ltitools_add_'.$item};  
                     } else {  
                         $confhash{$newid}{$item} = $env{'form.ltitools_add_'.$item};  
                     }  
                 }  
             }  
             if ($env{'form.ltitools_add_version'} eq 'LTI-1p0') {  
                 $confhash{$newid}{'version'} = $env{'form.ltitools_add_version'};  
             }  
             if ($env{'form.ltitools_add_msgtype'} eq 'basic-lti-launch-request') {  
                 $confhash{$newid}{'msgtype'} = $env{'form.ltitools_add_msgtype'};  
             }  
             if ($env{'form.ltitools_add_sigmethod'} eq 'HMAC-SHA256') {  
                 $confhash{$newid}{'sigmethod'} = $env{'form.ltitools_add_sigmethod'};  
             } else {  
                 $confhash{$newid}{'sigmethod'} = 'HMAC-SHA1';  
             }  
             foreach my $item ('width','height','linktext','explanation') {  
                 $env{'form.ltitools_add_'.$item} =~ s/^\s+//;  
                 $env{'form.ltitools_add_'.$item} =~ s/\s+$//;  
                 if (($item eq 'width') || ($item eq 'height')) {  
                     if ($env{'form.ltitools_add_'.$item} =~ /^\d+$/) {  
                         $confhash{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item};  
                     }  
                 } else {  
                     if ($env{'form.ltitools_add_'.$item} ne '') {  
                         $confhash{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item};   
                     }  
                 }  
             }  
             if ($env{'form.ltitools_add_target'} eq 'window') {  
                 $confhash{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'};  
             } elsif ($env{'form.ltitools_add_target'} eq 'tab') {  
                 $confhash{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'};  
             } else {  
                 $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 '') {  
                 my ($imageurl,$error) =  
                     &process_ltitools_image($r,$dom,$confname,'ltitools_add_image',$newid,  
                                             $configuserok,$switchserver,$author_ok);  
                 if ($imageurl) {  
                     $confhash{$newid}{'image'} = $imageurl;  
                 }  
                 if ($error) {  
                     &Apache::lonnet::logthis($error);  
                     $errors .= '<li><span class="LC_error">'.$error.'</span></li>';  
                 }  
             }  
             my @fields = &Apache::loncommon::get_env_multiple('form.ltitools_add_fields');  
             foreach my $field (@fields) {  
                 if ($possfield{$field}) {  
                     if ($field eq 'roles') {  
                         foreach my $role (@courseroles) {  
                             my $choice = $env{'form.ltitools_add_roles_'.$role};  
                             if (($choice ne '') && ($posslti{$choice})) {  
                                 $confhash{$newid}{'roles'}{$role} = $choice;  
                                 if ($role eq 'cc') {  
                                     $confhash{$newid}{'roles'}{'co'} = $choice;   
                                 }  
                             }  
                         }                          }
                     } else {  
                         $confhash{$newid}{'fields'}{$field} = 1;  
                     }                      }
                 }                  }
             }              }
             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');  
             foreach my $item (@courseconfig) {  
                 $confhash{$newid}{'crsconf'}{$item} = 1;  
             }  
             if ($env{'form.ltitools_add_custom'}) {  
                 my $name = $env{'form.ltitools_add_custom_name'};  
                 my $value = $env{'form.ltitools_add_custom_value'};  
                 $value =~ s/(`)/'/g;  
                 $name =~ s/(`)/'/g;  
                 $confhash{$newid}{'custom'}{$name} = $value;  
             }  
         } else {  
             my $error = &mt('Failed to acquire unique ID for new external tool');     
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';  
         }          }
     }          $ltitoolsoutput = &Apache::courseprefs::store_ltitools($dom,'','domain',\%ltitoolschg,$domconfig{'ltitools'});
     if (ref($domconfig{$action}) eq 'HASH') {          if (keys(%ltitoolschg)) {
         my %deletions;              %newltitools = %ltitoolschg;
         my @todelete = &Apache::loncommon::get_env_multiple('form.ltitools_del');  
         if (@todelete) {  
             map { $deletions{$_} = 1; } @todelete;  
         }  
         my %customadds;  
         my @newcustom = &Apache::loncommon::get_env_multiple('form.ltitools_customadd');  
         if (@newcustom) {  
             map { $customadds{$_} = 1; } @newcustom;  
         }   
         my %imgdeletions;  
         my @todeleteimages = &Apache::loncommon::get_env_multiple('form.ltitools_image_del');  
         if (@todeleteimages) {  
             map { $imgdeletions{$_} = 1; } @todeleteimages;  
         }          }
         my $maxnum = $env{'form.ltitools_maxnum'};      }
         for (my $i=0; $i<=$maxnum; $i++) {      if (ref($domconfig{'ltitools'}) eq 'HASH') {
             my $itemid = $env{'form.ltitools_id_'.$i};          foreach my $id (%{$domconfig{'ltitools'}}) {
             $itemid =~ s/\D+//g;              next if ($id !~ /^\d+$/);
             if (ref($domconfig{$action}{$itemid}) eq 'HASH') {              unless (exists($ltitoolschg{$id})) {
                 if ($deletions{$itemid}) {                  if (ref($domconfig{'ltitools'}{$id}) eq 'HASH') {
                     if ($domconfig{$action}{$itemid}{'image'}) {                      foreach my $inner (keys(%{$domconfig{'ltitools'}{$id}})) {
                         #FIXME need to obsolete item in RES space                          if (($inner eq 'secret') || ($inner eq 'key')) {
                     }                              if ($is_home) {
                     $changes{$itemid} = $domconfig{$action}{$itemid}{'title'};                                  $newtoolsenc{$id}{$inner} = $domconfig{'ltitools'}{$id}{$inner};
                     next;  
                 } else {  
                     my $newpos = $env{'form.ltitools_'.$itemid};  
                     $newpos =~ s/\D+//g;  
                     foreach my $item ('title','url','lifetime') {  
                         $confhash{$itemid}{$item} = $env{'form.ltitools_'.$item.'_'.$i};  
                         if ($domconfig{$action}{$itemid}{$item} ne $confhash{$itemid}{$item}) {  
                             $changes{$itemid} = 1;  
                         }  
                     }  
                     foreach my $item ('key','secret') {  
                         $encconfig{$itemid}{$item} = $env{'form.ltitools_'.$item.'_'.$i};  
                         if ($domconfig{$action}{$itemid}{$item} ne $encconfig{$itemid}{$item}) {  
                             $changes{$itemid} = 1;  
                         }  
                     }  
                     if ($env{'form.ltitools_version_'.$i} eq 'LTI-1p0') {  
                         $confhash{$itemid}{'version'} = $env{'form.ltitools_version_'.$i};  
                     }  
                     if ($env{'form.ltitools_msgtype_'.$i} eq 'basic-lti-launch-request') {  
                         $confhash{$itemid}{'msgtype'} = $env{'form.ltitools_msgtype_'.$i};  
                     }  
                     if ($env{'form.ltitools_sigmethod_'.$i} eq 'HMAC-SHA256') {  
                         $confhash{$itemid}{'sigmethod'} = $env{'form.ltitools_sigmethod_'.$i};  
                     } else {  
                         $confhash{$itemid}{'sigmethod'} = 'HMAC-SHA1';   
                     }  
                     if ($domconfig{$action}{$itemid}{'sigmethod'} eq '') {  
                         if ($confhash{$itemid}{'sigmethod'} ne 'HMAC-SHA1') {  
                             $changes{$itemid} = 1;  
                         }  
                     } elsif ($domconfig{$action}{$itemid}{'sigmethod'} ne $confhash{$itemid}{'sigmethod'}) {  
                         $changes{$itemid} = 1;  
                     }  
                     foreach my $size ('width','height') {  
                         $env{'form.ltitools_'.$size.'_'.$i} =~ s/^\s+//;  
                         $env{'form.ltitools_'.$size.'_'.$i} =~ s/\s+$//;  
                         if ($env{'form.ltitools_'.$size.'_'.$i} =~ /^\d+$/) {  
                             $confhash{$itemid}{'display'}{$size} = $env{'form.ltitools_'.$size.'_'.$i};  
                             if (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {  
                                 if ($domconfig{$action}{$itemid}{'display'}{$size} ne $confhash{$itemid}{'display'}{$size}) {  
                                     $changes{$itemid} = 1;  
                                 }  
                             } else {  
                                 $changes{$itemid} = 1;  
                             }  
                         } elsif (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {  
                             if ($domconfig{$action}{$itemid}{'display'}{$size} ne '') {  
                                 $changes{$itemid} = 1;  
                             }  
                         }  
                     }  
                     foreach my $item ('linktext','explanation') {  
                         $env{'form.ltitools_'.$item.'_'.$i} =~ s/^\s+//;  
                         $env{'form.ltitools_'.$item.'_'.$i} =~ s/\s+$//;  
                         if ($env{'form.ltitools_'.$item.'_'.$i} ne '') {  
                             $confhash{$itemid}{'display'}{$item} = $env{'form.ltitools_'.$item.'_'.$i};  
                             if (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {  
                                 if ($domconfig{$action}{$itemid}{'display'}{$item} ne $confhash{$itemid}{'display'}{$item}) {  
                                     $changes{$itemid} = 1;  
                                 }  
                             } else {  
                                 $changes{$itemid} = 1;  
                             }  
                         } elsif (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {  
                             if ($domconfig{$action}{$itemid}{'display'}{$item} ne '') {  
                                 $changes{$itemid} = 1;  
                             }  
                         }  
                     }  
                     if ($env{'form.ltitools_target_'.$i} eq 'window') {  
                         $confhash{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i};  
                     } elsif ($env{'form.ltitools_target_'.$i} eq 'tab') {  
                         $confhash{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i};  
                     } else {  
                         $confhash{$itemid}{'display'}{'target'} = 'iframe';  
                     }  
                     if (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') {  
                         if ($domconfig{$action}{$itemid}{'display'}{'target'} ne $confhash{$itemid}{'display'}{'target'}) {  
                             $changes{$itemid} = 1;  
                         }  
                     } else {  
                         $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_'.$i};  
                                 $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);  
                     foreach my $item ('label','title','target','linktext','explanation','append') {  
                         if (grep(/^\Q$item\E$/,@courseconfig)) {  
                             $confhash{$itemid}{'crsconf'}{$item} = 1;  
                             if (ref($domconfig{$action}{$itemid}{'crsconf'}) eq 'HASH') {  
                                 if ($domconfig{$action}{$itemid}{'crsconf'}{$item} ne $confhash{$itemid}{'crsconf'}{$item}) {  
                                     $changes{$itemid} = 1;  
                                 }  
                             } else {  
                                 $changes{$itemid} = 1;  
                             }  
                         }  
                     }  
                     my @fields = &Apache::loncommon::get_env_multiple('form.ltitools_fields_'.$i);  
                     foreach my $field (@fields) {  
                         if ($possfield{$field}) {  
                             if ($field eq 'roles') {  
                                 foreach my $role (@courseroles) {  
                                     my $choice = $env{'form.ltitools_roles_'.$role.'_'.$i};  
                                     if (($choice ne '') && ($posslti{$choice})) {  
                                         $confhash{$itemid}{'roles'}{$role} = $choice;  
                                         if ($role eq 'cc') {  
                                             $confhash{$itemid}{'roles'}{'co'} = $choice;  
                                         }  
                                     }  
                                     if (ref($domconfig{$action}{$itemid}{'roles'}) eq 'HASH') {  
                                         if ($domconfig{$action}{$itemid}{'roles'}{$role} ne $confhash{$itemid}{'roles'}{$role}) {  
                                             $changes{$itemid} = 1;  
                                         }  
                                     } elsif ($confhash{$itemid}{'roles'}{$role}) {  
                                         $changes{$itemid} = 1;  
                                     }  
                                 }  
                             } else {  
                                 $confhash{$itemid}{'fields'}{$field} = 1;  
                                 if (ref($domconfig{$action}{$itemid}{'fields'}) eq 'HASH') {  
                                     if ($domconfig{$action}{$itemid}{'fields'}{$field} ne $confhash{$itemid}{'fields'}{$field}) {  
                                         $changes{$itemid} = 1;  
                                     }  
                                 } else {  
                                     $changes{$itemid} = 1;  
                                 }  
                             }  
                         }  
                     }  
                     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;  
                 }  
                 if ($imgdeletions{$itemid}) {  
                     $changes{$itemid} = 1;  
                     #FIXME need to obsolete item in RES space  
                 } elsif ($env{'form.ltitools_image_'.$i.'.filename'}) {  
                     my ($imgurl,$error) = &process_ltitools_image($r,$dom,$confname,'ltitools_image_'.$i,  
                                                                  $itemid,$configuserok,$switchserver,  
                                                                  $author_ok);  
                     if ($imgurl) {  
                         $confhash{$itemid}{'image'} = $imgurl;  
                         $changes{$itemid} = 1;  
                     }  
                     if ($error) {  
                         &Apache::lonnet::logthis($error);  
                         $errors .= '<li><span class="LC_error">'.$error.'</span></li>';  
                     }  
                 } elsif ($domconfig{$action}{$itemid}{'image'}) {  
                     $confhash{$itemid}{'image'} =  
                        $domconfig{$action}{$itemid}{'image'};  
                 }  
                 if ($customadds{$i}) {  
                     my $name = $env{'form.ltitools_custom_name_'.$i};  
                     $name =~ s/(`)/'/g;  
                     $name =~ s/^\s+//;  
                     $name =~ s/\s+$//;  
                     my $value = $env{'form.ltitools_custom_value_'.$i};  
                     $value =~ s/(`)/'/g;  
                     $value =~ s/^\s+//;  
                     $value =~ s/\s+$//;  
                     if ($name ne '') {  
                         $confhash{$itemid}{'custom'}{$name} = $value;  
                         $changes{$itemid} = 1;  
                     }  
                 }  
                 my %customdels;  
                 my @customdeletions = &Apache::loncommon::get_env_multiple('form.ltitools_customdel_'.$i);   
                 if (@customdeletions) {  
                     $changes{$itemid} = 1;  
                 }  
                 map { $customdels{$_} = 1; } @customdeletions;  
                 if (ref($domconfig{$action}{$itemid}{'custom'}) eq 'HASH') {  
                     foreach my $key (keys(%{$domconfig{$action}{$itemid}{'custom'}})) {  
                         unless ($customdels{$key}) {  
                             if ($env{'form.ltitools_customval_'.$key.'_'.$i} ne '') {  
                                 $confhash{$itemid}{'custom'}{$key} = $env{'form.ltitools_customval_'.$key.'_'.$i};   
                             }  
                             if ($domconfig{$action}{$itemid}{'custom'}{$key} ne $env{'form.ltitools_customval_'.$key.'_'.$i}) {  
                                 $changes{$itemid} = 1;  
                             }  
                         }  
                     }  
                 }  
                 unless ($changes{$itemid}) {  
                     foreach my $key (keys(%{$domconfig{$action}{$itemid}})) {  
                         if (ref($domconfig{$action}{$itemid}{$key}) eq 'HASH') {  
                             if (ref($confhash{$itemid}{$key}) eq 'HASH') {  
                                 foreach my $innerkey (keys(%{$domconfig{$action}{$itemid}{$key}})) {  
                                     unless (exists($confhash{$itemid}{$key}{$innerkey})) {  
                                         $changes{$itemid} = 1;  
                                         last;  
                                     }  
                                 }  
                             } elsif (keys(%{$domconfig{$action}{$itemid}{$key}}) > 0) {  
                                 $changes{$itemid} = 1;  
                             }                              }
                           } else {
                               $newltitools{$id}{$inner} = $domconfig{'ltitools'}{$id}{$inner};
                         }                          }
                         last if ($changes{$itemid});  
                     }                      }
                   } else {
                       $newltitools{$id} = $domconfig{'ltitools'}{$id};
                 }                  }
             }              }
         }          }
     }      }
     if (@allpos > 0) {      if ($toolserror) {
         my $idx = 0;          $errors = '<li>'.$toolserror.'</li>';
         foreach my $itemid (@allpos) {      }
             if ($itemid ne '') {      if ((keys(%ltitoolschg) == 0) && (keys(%secchanges) == 0)) {
                 $confhash{$itemid}{'order'} = $idx;          $resulttext = &mt('No changes made.');
                 if (ref($domconfig{$action}) eq 'HASH') {          if ($errors) {
                     if (ref($domconfig{$action}{$itemid}) eq 'HASH') {              $resulttext .= '<br />'.&mt('The following errors occurred: ').'<ul>'.
                         if ($domconfig{$action}{$itemid}{'order'} ne $idx) {                                   $errors.'</ul>';
                             $changes{$itemid} = 1;  
                         }  
                     }  
                 }  
                 $idx ++;  
             }  
         }          }
           return $resulttext;
     }      }
     my %ltitoolshash = (      my %ltitoolshash = (
                           $action => { %confhash }                            $action => { %newltitools }
                        );                         );
     my $putresult = &Apache::lonnet::put_dom('configuration',\%ltitoolshash,      if (keys(%secchanges)) {
                                              $dom);          $ltitoolshash{'toolsec'} = \%newtoolsec;
       }
       my $putresult = &Apache::lonnet::put_dom('configuration',\%ltitoolshash,$dom);
     if ($putresult eq 'ok') {      if ($putresult eq 'ok') {
         my %ltienchash = (          my %keystore;
                              $action => { %encconfig }          if ($is_home) {
                          );              my %toolsenchash = (
         &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom);                                     $action => { %newtoolsenc }
         if (keys(%changes) > 0) {                                 );
               &Apache::lonnet::put_dom('encconfig',\%toolsenchash,$dom,undef,1);
             my $cachetime = 24*60*60;              my $cachetime = 24*60*60;
             my %ltiall = %confhash;              &Apache::lonnet::do_cache_new('ltitoolsenc',$dom,\%newtoolsenc,$cachetime);
             foreach my $id (keys(%ltiall)) {              &store_security($dom,'ltitools',\%secchanges,\%newkeyset,\%keystore,$lastactref);
                 if (ref($encconfig{$id}) eq 'HASH') {          }
                     foreach my $item ('key','secret') {          $resulttext = &mt('Changes made:').'<ul>';
                         $ltiall{$id}{$item} = $encconfig{$id}{$item};          if (keys(%secchanges) > 0) {
               $resulttext .= &lti_security_results($dom,'ltitools',\%secchanges,\%newtoolsec,\%newkeyset,\%keystore);
           }
           if (keys(%ltitoolschg) > 0) {
               $resulttext .= $ltitoolsoutput;
           }
           my $cachetime = 24*60*60;
           &Apache::lonnet::do_cache_new('ltitools',$dom,\%newltitools,$cachetime);
           if (ref($lastactref) eq 'HASH') {
               $lastactref->{'ltitools'} = 1;
           }
       } else {
           $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';
       }
       if ($errors) {
           $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.
                          $errors.'</ul></p>';
       }
       return $resulttext;
   }
   
   sub fetch_secrets {
       my ($dom,$context,$domconfig,$currsec,$secchanges,$newsec,$newkeyset) = @_;
       my %keyset;
       %{$currsec} = ();
       $newsec->{'private'}{'keys'} = [];
       $newsec->{'encrypt'} = {};
       $newsec->{'rules'} = {};
       if ($context eq 'ltisec') {
           $newsec->{'linkprot'} = {};
       }
       if (ref($domconfig->{$context}) eq 'HASH') {
           %{$currsec} = %{$domconfig->{$context}};
           if ($context eq 'ltisec') {
               if (ref($currsec->{'linkprot'}) eq 'HASH') {
                   foreach my $id (keys(%{$currsec->{'linkprot'}})) {
                       unless ($id =~ /^\d+$/) {
                           delete($currsec->{'linkprot'}{$id});
                     }                      }
                 }                  }
             }              }
             &Apache::lonnet::do_cache_new('ltitools',$dom,\%ltiall,$cachetime);          }
             if (ref($lastactref) eq 'HASH') {          if (ref($currsec->{'private'}) eq 'HASH') {
                 $lastactref->{'ltitools'} = 1;              if (ref($currsec->{'private'}{'keys'}) eq 'ARRAY') {
                   $newsec->{'private'}{'keys'} = $currsec->{'private'}{'keys'};
                   map { $keyset{$_} = 1; } @{$currsec->{'private'}{'keys'}};
             }              }
             $resulttext = &mt('Changes made:').'<ul>';          }
             my %bynum;      }
             foreach my $itemid (sort(keys(%changes))) {      my @items= ('crs','dom');
                 my $position = $confhash{$itemid}{'order'};      if ($context eq 'ltisec') {
                 $bynum{$position} = $itemid;          push(@items,'consumers');
       }
       foreach my $item (@items) {
           my $formelement;
           if (($context eq 'toolsec') || ($item eq 'consumers')) {
               $formelement = 'form.'.$context.'_'.$item;
           } else {
               $formelement = 'form.'.$context.'_'.$item.'linkprot';
           }
           if ($env{$formelement}) {
               $newsec->{'encrypt'}{$item} = 1;
               if (ref($currsec->{'encrypt'}) eq 'HASH') {
                   unless ($currsec->{'encrypt'}{$item}) {
                       $secchanges->{'encrypt'} = 1;
                   }
               } else {
                   $secchanges->{'encrypt'} = 1;
             }              }
             foreach my $pos (sort { $a <=> $b } keys(%bynum)) {          } elsif (ref($currsec->{'encrypt'}) eq 'HASH') {
                 my $itemid = $bynum{$pos};               if ($currsec->{'encrypt'}{$item}) {
                 if (ref($confhash{$itemid}) ne 'HASH') {                  $secchanges->{'encrypt'} = 1;
                     $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';              }
                 } else {          }
                     $resulttext .= '<li><b>'.$confhash{$itemid}{'title'}.'</b>';      }
                     if ($confhash{$itemid}{'image'}) {      my $secrets;
                         $resulttext .= '&nbsp;'.      if ($context eq 'ltisec') {
                                        '<img src="'.$confhash{$itemid}{'image'}.'"'.          $secrets = 'ltisecrets';
                                        ' alt="'.&mt('Tool Provider icon').'" />';      } else {
                     }          $secrets = 'toolsecrets';
                     $resulttext .= '</li><ul>';      }
                     my $position = $pos + 1;      unless (exists($currsec->{'rules'})) {
                     $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';          $currsec->{'rules'} = {};
                     foreach my $item ('version','msgtype','sigmethod','url','lifetime') {      }
                         if ($confhash{$itemid}{$item} ne '') {      &password_rule_changes($secrets,$newsec->{'rules'},$currsec->{'rules'},$secchanges);
                             $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{$item}.'</li>';  
                         }      my @ids=&Apache::lonnet::current_machine_ids();
                     }      my %servers = &Apache::lonnet::get_servers($dom,'library');
                     if ($encconfig{$itemid}{'key'} ne '') {  
                         $resulttext .= '<li>'.$lt{'key'}.':&nbsp;'.$encconfig{$itemid}{'key'}.'</li>';      foreach my $hostid (keys(%servers)) {
                     }          if (($hostid ne '') && (grep(/^\Q$hostid\E$/,@ids))) {
                     if ($encconfig{$itemid}{'secret'} ne '') {              my $keyitem = 'form.'.$context.'_privkey_'.$hostid;
                         $resulttext .= '<li>'.$lt{'secret'}.':&nbsp;';              if (exists($env{$keyitem})) {
                         my $num = length($encconfig{$itemid}{'secret'});                  $env{$keyitem} =~ s/(`)/'/g;
                         $resulttext .= ('*'x$num).'</li>';                  if ($keyset{$hostid}) {
                     }                      if ($env{'form.'.$context.'_changeprivkey_'.$hostid}) {
                     $resulttext .= '<li>'.&mt('Configurable in course:');                          if ($env{$keyitem} ne '') {
                     my @possconfig = ('label','title','target','linktext','explanation','append');                              $secchanges->{'private'} = 1;
                     my $numconfig = 0;                               $newkeyset->{$hostid} = $env{$keyitem};
                     if (ref($confhash{$itemid}{'crsconf'}) eq 'HASH') {   
                         foreach my $item (@possconfig) {  
                             if ($confhash{$itemid}{'crsconf'}{$item}) {  
                                 $numconfig ++;  
                                 $resulttext .= ' "'.$lt{'crs'.$item}.'"';  
                             }  
                         }  
                     }  
                     if (!$numconfig) {  
                         $resulttext .= '&nbsp;'.&mt('None');  
                     }  
                     $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') {  
                         my $displaylist;  
                         if ($confhash{$itemid}{'display'}{'target'}) {  
                             $displaylist = &mt('Display target').':&nbsp;'.  
                                            $confhash{$itemid}{'display'}{'target'}.',';  
                         }  
                         foreach my $size ('width','height') {   
                             if ($confhash{$itemid}{'display'}{$size}) {  
                                 $displaylist .= ('&nbsp;'x2).$lt{$size}.':&nbsp;'.  
                                                 $confhash{$itemid}{'display'}{$size}.',';  
                             }  
                         }  
                         if ($displaylist) {  
                             $displaylist =~ s/,$//;  
                             $resulttext .= '<li>'.$displaylist.'</li>';  
                         }  
                         foreach my $item ('linktext','explanation') {  
                             if ($confhash{$itemid}{'display'}{$item}) {  
                                 $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{'display'}{$item}.'</li>';  
                             }  
                         }  
                     }  
                     if (ref($confhash{$itemid}{'fields'}) eq 'HASH') {  
                         my $fieldlist;  
                         foreach my $field (@allfields) {  
                             if ($confhash{$itemid}{'fields'}{$field}) {  
                                 $fieldlist .= ('&nbsp;'x2).$lt{$field}.',';  
                             }  
                         }  
                         if ($fieldlist) {  
                             $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>';  
                         }                          }
                     }                      }
                     if (ref($confhash{$itemid}{'roles'}) eq 'HASH') {                  } elsif ($env{$keyitem} ne '') {
                         my $rolemaps;                      unless (grep(/^\Q$hostid\E$/,@{$newsec->{'private'}{'keys'}})) {
                         foreach my $role (@courseroles) {                          push(@{$newsec->{'private'}{'keys'}},$hostid);
                             if ($confhash{$itemid}{'roles'}{$role}) {  
                                 $rolemaps .= ('&nbsp;'x2).&Apache::lonnet::plaintext($role,'Course').'='.  
                                              $confhash{$itemid}{'roles'}{$role}.',';  
                             }  
                         }  
                         if ($rolemaps) {  
                             $rolemaps =~ s/,$//;   
                             $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>';  
                         }  
                     }                      }
                     if (ref($confhash{$itemid}{'custom'}) eq 'HASH') {                      $secchanges->{'private'} = 1;
                         my $customlist;                      $newkeyset->{$hostid} = $env{$keyitem};
                         if (keys(%{$confhash{$itemid}{'custom'}})) {  
                             foreach my $key (sort(keys(%{$confhash{$itemid}{'custom'}}))) {  
                                 $customlist .= $key.':'.$confhash{$itemid}{'custom'}{$key}.('&nbsp;'x2);  
                             }   
                         }  
                         if ($customlist) {  
                             $resulttext .= '<li>'.&mt('Custom items').': '.$customlist.'</li>';  
                         }  
                     }   
                     $resulttext .= '</ul></li>';  
                 }                  }
             }              }
             $resulttext .= '</ul>';  
         } else {  
             $resulttext = &mt('No changes made.');  
         }          }
     } else {  
         $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';  
     }      }
     if ($errors) {  
         $resulttext .= &mt('The following errors occurred: ').'<ul>'.  
                        $errors.'</ul>';  
     }  
     return $resulttext;  
 }  }
   
 sub process_ltitools_image {  sub store_security {
     my ($r,$dom,$confname,$caller,$itemid,$configuserok,$switchserver,$author_ok) = @_;      my ($dom,$context,$secchanges,$newkeyset,$keystore) = @_;
     my $filename = $env{'form.'.$caller.'.filename'};      return unless ((ref($secchanges) eq 'HASH') && (ref($newkeyset) eq 'HASH') &&
     my ($error,$url);                     (ref($keystore) eq 'HASH'));
     my ($width,$height) = (21,21);      if (keys(%{$secchanges})) {
     if ($configuserok eq 'ok') {          if ($secchanges->{'private'}) {
         if ($switchserver) {              my $who = &escape($env{'user.name'}.':'.$env{'user.domain'});
             $error = &mt('Upload of Tool Provider (LTI) icon is not permitted to this server: [_1]',              foreach my $hostid (keys(%{$newkeyset})) {
                          $switchserver);                  my $storehash = {
         } elsif ($author_ok eq 'ok') {                                     key => $newkeyset->{$hostid},
             my ($result,$imageurl,$madethumb) =                                     who => $env{'user.name'}.':'.$env{'user.domain'},
                 &publishlogo($r,'upload',$caller,$dom,$confname,                                  };
                              "ltitools/$itemid/icon",$width,$height);                  $keystore->{$hostid} = &Apache::lonnet::store_dom($storehash,$context,'private',
             if ($result eq 'ok') {                                                                    $dom,$hostid);
                 if ($madethumb) {  
                     my ($path,$imagefile) = ($imageurl =~ m{^(.+)/([^/]+)$});  
                     my $imagethumb = "$path/tn-".$imagefile;  
                     $url = $imagethumb;  
                 } else {  
                     $url = $imageurl;  
                 }  
             } else {  
                 $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);  
             }              }
         } else {  
             $error = &mt("Upload of [_1] failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3].  Error was: [_4].",$filename,$confname,$dom,$author_ok);  
         }          }
     } else {  
         $error = &mt("Upload of [_1] failed because a Domain Configuration user ([_2]) could not be created in domain: [_3].  Error was: [_4].",$filename,$confname,$dom,$configuserok);  
     }      }
     return ($url,$error);  
 }  }
   
 sub get_ltitools_id {  sub lti_security_results {
     my ($cdom,$title) = @_;      my ($dom,$context,$secchanges,$newsec,$newkeyset,$keystore) = @_;
     # get lock on ltitools db      my $output;
     my $lockhash = {      my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
                       lock => $env{'user.name'}.      my $needs_update;
                               ':'.$env{'user.domain'},      foreach my $item (keys(%{$secchanges})) {
                    };          if ($item eq 'encrypt') {
     my $tries = 0;              $needs_update = 1;
     my $gotlock = &Apache::lonnet::newput_dom('ltitools',$lockhash,$cdom);              my %encrypted;
     my ($id,$error);              if ($context eq 'lti') {
                    %encrypted = (
     while (($gotlock ne 'ok') && ($tries<10)) {                                crs  => {
         $tries ++;                                          on => &mt('Encryption of stored link protection secrets defined in courses enabled'),
         sleep (0.1);                                          off => &mt('Encryption of stored link protection secrets defined in courses disabled'),
         $gotlock = &Apache::lonnet::newput_dom('ltitools',$lockhash,$cdom);                                        },
     }                                dom => {
     if ($gotlock eq 'ok') {                                         on => &mt('Encryption of stored link protection secrets defined in domain enabled'),
         my %currids = &Apache::lonnet::dump_dom('ltitools',$cdom);                                         off => &mt('Encryption of stored link protection secrets defined in domain disabled'),
         if ($currids{'lock'}) {                                       },
             delete($currids{'lock'});                                consumers => {
             if (keys(%currids)) {                                               on => &mt('Encryption of stored consumer secrets defined in domain enabled'),
                 my @curr = sort { $a <=> $b } keys(%currids);                                               off => &mt('Encryption of stored consumer secrets defined in domain disabled'),
                 if ($curr[-1] =~ /^\d+$/) {                                             },
                     $id = 1 + $curr[-1];                               );
                 }  
             } else {              } else {
                 $id = 1;                  %encrypted = (
                                 crs  => {
                                           on => &mt('Encryption of stored external tool secrets defined in courses enabled'),
                                           off => &mt('Encryption of stored external tool secrets defined in courses disabled'),
                                         },
                                 dom => {
                                          on => &mt('Encryption of stored external tool secrets defined in domain enabled'),
                                          off => &mt('Encryption of stored external tool secrets defined in domain disabled'),
                                        },
                                );
   
             }              }
             if ($id) {              my @types= ('crs','dom');
                 unless (&Apache::lonnet::newput_dom('ltitools',{ $id => $title },$cdom) eq 'ok') {              if ($context eq 'lti') {
                     $error = 'nostore';                  foreach my $type (@types) {
                       undef($domdefaults{'linkprotenc_'.$type});
                   }
                   push(@types,'consumers');
                   undef($domdefaults{'ltienc_consumers'});
               } elsif ($context eq 'ltitools') {
                   foreach my $type (@types) {
                       undef($domdefaults{'toolenc_'.$type});
                   }
               }
               foreach my $type (@types) {
                   my $shown = $encrypted{$type}{'off'};
                   if (ref($newsec->{$item}) eq 'HASH') {
                       if ($newsec->{$item}{$type}) {
                           if ($context eq 'lti') {
                               if ($type eq 'consumers') {
                                   $domdefaults{'ltienc_consumers'} = 1;
                               } else {
                                   $domdefaults{'linkprotenc_'.$type} = 1;
                               }
                           } elsif ($context eq 'ltitools') {
                               $domdefaults{'toolenc_'.$type} = 1;
                           }
                           $shown = $encrypted{$type}{'on'};
                       }
                   }
                   $output .= '<li>'.$shown.'</li>';
               }
           } elsif ($item eq 'rules') {
               my %titles = &Apache::lonlocal::texthash(
                                         min   => 'Minimum password length',
                                         max   => 'Maximum password length',
                                         chars => 'Required characters',
                            );
               foreach my $rule ('min','max') {
                   if ($newsec->{rules}{$rule} eq '') {
                       if ($rule eq 'min') {
                           $output .= '<li>'.&mt('[_1] not set.',$titles{$rule});
                                      ' '.&mt('Default of [_1] will be used',
                                              $Apache::lonnet::passwdmin).'</li>';
                       } else {
                           $output .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>';
                       }
                   } else {
                       $output .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$newsec->{rules}{$rule}).'</li>';
                   }
               }
               if (ref($newsec->{'rules'}{'chars'}) eq 'ARRAY') {
                   if (@{$newsec->{'rules'}{'chars'}} > 0) {
                       my %rulenames = &Apache::lonlocal::texthash(
                                                uc => 'At least one upper case letter',
                                                lc => 'At least one lower case letter',
                                                num => 'At least one number',
                                                spec => 'At least one non-alphanumeric',
                                       );
                       my $needed = '<ul><li>'.
                                    join('</li><li>',map {$rulenames{$_} } @{$newsec->{'rules'}{'chars'}}).
                                    '</li></ul>';
                       $output .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>';
                   } else {
                       $output .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';
                 }                  }
             } else {              } else {
                 $error = 'nonumber';                  $output .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';
               }
           } elsif ($item eq 'private') {
               $needs_update = 1;
               if ($context eq 'lti') {
                   undef($domdefaults{'ltiprivhosts'});
               } elsif ($context eq 'ltitools') {
                   undef($domdefaults{'toolprivhosts'});
             }              }
               if (keys(%{$newkeyset})) {
                   my @privhosts;
                   foreach my $hostid (sort(keys(%{$newkeyset}))) {
                       if ($keystore->{$hostid} eq 'ok') {
                           $output .= '<li>'.&mt('Encryption key for storage of shared secrets saved for [_1]',$hostid).'</li>';
                           unless (grep(/^\Q$hostid\E$/,@privhosts)) {
                               push(@privhosts,$hostid);
                           }
                       }
                   }
                   if (@privhosts) {
                       if ($context eq 'lti') {
                           $domdefaults{'ltiprivhosts'} = \@privhosts;
                       } elsif ($context eq 'ltitools') {
                           $domdefaults{'toolprivhosts'} = \@privhosts;
                       }
                   }
               }
           } elsif ($item eq 'linkprot') {
               next;
         }          }
         my $dellockoutcome = &Apache::lonnet::del_dom('ltitools',['lock'],$cdom);  
     } else {  
         $error = 'nolock';  
     }      }
     return ($id,$error);      if ($needs_update) {
           my $cachetime = 24*60*60;
           &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
       }
       return $output;
 }  }
   
 sub modify_proctoring {  sub modify_proctoring {
Line 13843  sub modify_proctoring { Line 15415  sub modify_proctoring {
         my %proc_enchash = (          my %proc_enchash = (
                              $action => { %encconfhash }                               $action => { %encconfhash }
                          );                           );
         &Apache::lonnet::put_dom('encconfig',\%proc_enchash,$dom);          &Apache::lonnet::put_dom('encconfig',\%proc_enchash,$dom,undef,1);
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
             my $cachetime = 24*60*60;              my $cachetime = 24*60*60;
             my %procall = %confhash;              my %procall = %confhash;
Line 14015  sub process_proctoring_image { Line 15587  sub process_proctoring_image {
             $error = &mt('Upload of Remote Proctoring Provider icon is not permitted to this server: [_1]',              $error = &mt('Upload of Remote Proctoring Provider icon is not permitted to this server: [_1]',
                          $switchserver);                           $switchserver);
         } elsif ($author_ok eq 'ok') {          } elsif ($author_ok eq 'ok') {
               my $modified = [];
             my ($result,$imageurl,$madethumb) =              my ($result,$imageurl,$madethumb) =
                 &publishlogo($r,'upload',$caller,$dom,$confname,                  &Apache::lonconfigsettings::publishlogo($r,'upload',$caller,$dom,$confname,
                              "proctoring/$provider/icon",$width,$height);                                                          "proctoring/$provider/icon",$width,$height,
                                                           '',$modified);
             if ($result eq 'ok') {              if ($result eq 'ok') {
                 if ($madethumb) {                  if ($madethumb) {
                     my ($path,$imagefile) = ($imageurl =~ m{^(.+)/([^/]+)$});                      my ($path,$imagefile) = ($imageurl =~ m{^(.+)/([^/]+)$});
Line 14026  sub process_proctoring_image { Line 15600  sub process_proctoring_image {
                 } else {                  } else {
                     $url = $imageurl;                      $url = $imageurl;
                 }                  }
                   &update_modify_urls($r,$modified);
             } else {              } else {
                 $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);                  $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);
             }              }
Line 14041  sub process_proctoring_image { Line 15616  sub process_proctoring_image {
 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 ($newid,@allpos,%changes,%confhash,%encconfig,$errors,$resulttext);      my ($newid,@allpos,%changes,%confhash,%ltienc,$errors,$resulttext);
     my (%posslti,%posslticrs,%posscrstype);      my (%posslti,%posslticrs,%posscrstype);
     my @courseroles = ('cc','in','ta','ep','st');      my @courseroles = ('cc','in','ta','ep','st');
     my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator);      my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator);
     my @lticourseroles = qw(Instructor TeachingAssistant Mentor Learner);      my @lticourseroles = qw(Instructor TeachingAssistant Mentor Learner);
     my @coursetypes = ('official','unofficial','community','textbook','placement');      my @coursetypes = ('official','unofficial','community','textbook','placement','lti');
     my %coursetypetitles = &Apache::lonlocal::texthash (      my %coursetypetitles = &Apache::lonlocal::texthash (
                                official   => 'Official',                                 official   => 'Official',
                                unofficial => 'Unofficial',                                 unofficial => 'Unofficial',
                                community  => 'Community',                                 community  => 'Community',
                                textbook   => 'Textbook',                                 textbook   => 'Textbook',
                                placement  => 'Placement Test',                                 placement  => 'Placement Test',
                                  lti        => 'LTI Provider',
     );      );
     my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();      my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
     my %lt = &lti_names();      my %lt = &lti_names();
Line 14061  sub modify_lti { Line 15637  sub modify_lti {
     map { $posscrstype{$_} = 1; } @coursetypes;      map { $posscrstype{$_} = 1; } @coursetypes;
   
     my %menutitles = &ltimenu_titles();      my %menutitles = &ltimenu_titles();
       my (%currltisec,%secchanges,%newltisec,%newltienc,%newkeyset);
   
       &fetch_secrets($dom,'ltisec',\%domconfig,\%currltisec,\%secchanges,\%newltisec,\%newkeyset);
   
       my (%linkprotchg,$linkprotoutput,$is_home);
       my $proterror = &Apache::courseprefs::process_linkprot($dom,'',$currltisec{'linkprot'},
                                                              \%linkprotchg,'domain');
       my $home = &Apache::lonnet::domain($dom,'primary');
       unless (($home eq 'no_host') || ($home eq '')) {
           my @ids=&Apache::lonnet::current_machine_ids();
           foreach my $id (@ids) { if ($id eq $home) { $is_home=1; } }
       }
   
       if (keys(%linkprotchg)) {
           $secchanges{'linkprot'} = 1;
           my %oldlinkprot;
           if (ref($currltisec{'linkprot'}) eq 'HASH') {
               %oldlinkprot = %{$currltisec{'linkprot'}};
           }
           foreach my $id (keys(%linkprotchg)) {
               if (ref($linkprotchg{$id}) eq 'HASH') {
                   foreach my $inner (keys(%{$linkprotchg{$id}})) {
                       if (($inner eq 'secret') || ($inner eq 'key')) {
                           if ($is_home) {
                               $newltienc{$id}{$inner} = $linkprotchg{$id}{$inner};
                           }
                       }
                   }
               } else {
                   $newltisec{'linkprot'}{$id} = $linkprotchg{$id};
               }
           }
           $linkprotoutput = &Apache::courseprefs::store_linkprot($dom,'','domain',\%linkprotchg,\%oldlinkprot);
           if (keys(%linkprotchg)) {
               %{$newltisec{'linkprot'}} = %linkprotchg;
           }
       }
       if (ref($currltisec{'linkprot'}) eq 'HASH') {
           foreach my $id (%{$currltisec{'linkprot'}}) {
               next if ($id !~ /^\d+$/);
               unless (exists($linkprotchg{$id})) {
                   if (ref($currltisec{'linkprot'}{$id}) eq 'HASH') {
                       foreach my $inner (keys(%{$currltisec{'linkprot'}{$id}})) {
                           if (($inner eq 'secret') || ($inner eq 'key')) {
                               if ($is_home) {
                                   $newltienc{$id}{$inner} = $currltisec{'linkprot'}{$id}{$inner};
                               }
                           } else {
                               $newltisec{'linkprot'}{$id}{$inner} = $currltisec{'linkprot'}{$id}{$inner};
                           }
                       }
                   } else {
                       $newltisec{'linkprot'}{$id} = $currltisec{'linkprot'}{$id};
                   }
               }
           }
       }
       if ($proterror) {
           $errors .= '<li>'.$proterror.'</li>';
       }
     my (@items,%deletions,%itemids);      my (@items,%deletions,%itemids);
     if ($env{'form.lti_add'}) {      if ($env{'form.lti_add'}) {
         my $consumer = $env{'form.lti_consumer_add'};          my $consumer = $env{'form.lti_consumer_add'};
Line 14082  sub modify_lti { Line 15717  sub modify_lti {
             map { $deletions{$_} = 1; } @todelete;              map { $deletions{$_} = 1; } @todelete;
         }          }
         my $maxnum = $env{'form.lti_maxnum'};          my $maxnum = $env{'form.lti_maxnum'};
         for (my $i=0; $i<=$maxnum; $i++) {          for (my $i=0; $i<$maxnum; $i++) {
             my $itemid = $env{'form.lti_id_'.$i};              my $itemid = $env{'form.lti_id_'.$i};
             $itemid =~ s/\D+//g;              $itemid =~ s/\D+//g;
             if (ref($domconfig{$action}{$itemid}) eq 'HASH') {              if (ref($domconfig{$action}{$itemid}) eq 'HASH') {
                 if ($deletions{$itemid}) {                  if ($deletions{$itemid}) {
                     $changes{$itemid} = $domconfig{$action}{$itemid}{'consumer'};                      $changes{$itemid} = $domconfig{$action}{$itemid}{'consumer'};
                 } else {                  } else {
                    push(@items,$i);                      push(@items,$i);
                    $itemids{$i} = $itemid;                      $itemids{$i} = $itemid;
                 }                  }
             }              }
         }          }
     }      }
       my (%keystore,$secstored);
       if ($is_home) {
           &store_security($dom,'lti',\%secchanges,\%newkeyset,\%keystore);
       }
   
       my ($cipher,$privnum);
       if ((@items > 0) && ($is_home)) {
           ($cipher,$privnum) = &get_priv_creds($dom,$home,$secchanges{'encrypt'},
                                                $newltisec{'encrypt'},$keystore{$home});
       }
     foreach my $idx (@items) {      foreach my $idx (@items) {
         my $itemid = $itemids{$idx};          my $itemid = $itemids{$idx};
         next unless ($itemid);          next unless ($itemid);
         my $position = $env{'form.lti_pos_'.$idx};          my %currlti;
           unless ($idx eq 'add') {
               if (ref($domconfig{$action}) eq 'HASH') {
                   if (ref($domconfig{$action}{$itemid}) eq 'HASH') {
                       %currlti = %{$domconfig{$action}{$itemid}};
                   }
               }
           }
           my $position = $env{'form.lti_pos_'.$itemid};
         $position =~ s/\D+//g;          $position =~ s/\D+//g;
         if ($position ne '') {          if ($position ne '') {
             $allpos[$position] = $itemid;              $allpos[$position] = $itemid;
         }          }
         foreach my $item ('consumer','key','secret','lifetime','requser') {          foreach my $item ('consumer','lifetime','requser','crsinc') {
             my $formitem = 'form.lti_'.$item.'_'.$idx;              my $formitem = 'form.lti_'.$item.'_'.$idx;
             $env{$formitem} =~ s/(`)/'/g;              $env{$formitem} =~ s/(`)/'/g;
             if ($item eq 'lifetime') {              if ($item eq 'lifetime') {
                 $env{$formitem} =~ s/[^\d.]//g;                  $env{$formitem} =~ s/[^\d.]//g;
             }              }
             if ($env{$formitem} ne '') {              if ($env{$formitem} ne '') {
                 if (($item eq 'key') || ($item eq 'secret')) {                  $confhash{$itemid}{$item} = $env{$formitem};
                     $encconfig{$itemid}{$item} = $env{$formitem};                  unless (($idx eq 'add') || ($changes{$itemid})) {
                 } else {                      if ($currlti{$item} ne $confhash{$itemid}{$item}) {
                     $confhash{$itemid}{$item} = $env{$formitem};                          $changes{$itemid} = 1;
                     unless (($idx eq 'add') || ($changes{$itemid})) {  
                         if ($domconfig{$action}{$itemid}{$item} ne $confhash{$itemid}{$item}) {  
                             $changes{$itemid} = 1;  
                         }  
                     }                      }
                 }                  }
             }              }
Line 14127  sub modify_lti { Line 15776  sub modify_lti {
         }          }
         if ($confhash{$itemid}{'requser'}) {          if ($confhash{$itemid}{'requser'}) {
             if ($env{'form.lti_mapuser_'.$idx} eq 'sourcedid') {              if ($env{'form.lti_mapuser_'.$idx} eq 'sourcedid') {
                 $confhash{$itemid}{'mapuser'} = 'lis_person_sourcedid';                   $confhash{$itemid}{'mapuser'} = 'lis_person_sourcedid';
             } elsif ($env{'form.lti_mapuser_'.$idx} eq 'email') {              } elsif ($env{'form.lti_mapuser_'.$idx} eq 'email') {
                 $confhash{$itemid}{'mapuser'} = 'lis_person_contact_email_primary';                  $confhash{$itemid}{'mapuser'} = 'lis_person_contact_email_primary';
             } elsif ($env{'form.lti_mapuser_'.$idx} eq 'other') {              } elsif ($env{'form.lti_mapuser_'.$idx} eq 'other') {
                 my $mapuser = $env{'form.lti_customuser_'.$idx};                  my $mapuser = $env{'form.lti_customuser_'.$idx};
                 $mapuser =~ s/(`)/'/g;                  $mapuser =~ s/(`)/'/g;
                 $mapuser =~ s/^\s+|\s+$//g;                   $mapuser =~ s/^\s+|\s+$//g;
                 $confhash{$itemid}{'mapuser'} = $mapuser;                   $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 @possmakeuser = &Apache::loncommon::get_env_multiple('form.lti_makeuser_'.$idx);
             my @makeuser;              my @makeuser;
Line 14174  sub modify_lti { Line 15817  sub modify_lti {
                     }                      }
                 }                  }
             }              }
             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;  
                     }  
                 }  
             }  
             if ($env{'form.lti_callback_'.$idx}) {              if ($env{'form.lti_callback_'.$idx}) {
                 if ($env{'form.lti_callbackparam_'.$idx}) {                  if ($env{'form.lti_callbackparam_'.$idx}) {
                     my $callback = $env{'form.lti_callbackparam_'.$idx};                      my $callback = $env{'form.lti_callbackparam_'.$idx};
Line 14221  sub modify_lti { Line 15824  sub modify_lti {
                     $confhash{$itemid}{'callback'} = $callback;                      $confhash{$itemid}{'callback'} = $callback;
                 }                  }
             }              }
             foreach my $field ('passback','roster','topmenu','inlinemenu') {              foreach my $field ('topmenu','inlinemenu') {
                 if ($env{'form.lti_'.$field.'_'.$idx}) {                  if ($env{'form.lti_'.$field.'_'.$idx}) {
                     $confhash{$itemid}{$field} = 1;                      $confhash{$itemid}{$field} = 1;
                 }                  }
             }              }
             if ($env{'form.lti_passback_'.$idx}) {  
                 if ($env{'form.lti_passbackformat_'.$idx} eq '1.0') {  
                     $confhash{$itemid}{'passbackformat'} = '1.0';  
                 } else {  
                     $confhash{$itemid}{'passbackformat'} = '1.1';  
                 }  
             }  
             if ($env{'form.lti_topmenu_'.$idx} || $env{'form.lti_inlinemenu_'.$idx}) {              if ($env{'form.lti_topmenu_'.$idx} || $env{'form.lti_inlinemenu_'.$idx}) {
                 $confhash{$itemid}{lcmenu} = [];                  $confhash{$itemid}{lcmenu} = [];
                 my @possmenu = &Apache::loncommon::get_env_multiple('form.lti_menuitem_'.$idx);                  my @possmenu = &Apache::loncommon::get_env_multiple('form.lti_menuitem_'.$idx);
Line 14245  sub modify_lti { Line 15841  sub modify_lti {
                     }                      }
                 }                  }
             }              }
             unless (($idx eq 'add') || ($changes{$itemid})) {              if ($confhash{$itemid}{'crsinc'}) {
                 foreach my $field ('mapuser','mapcrs','makecrs','section','passback','roster','lcauth','lcauthparm','topmenu','inlinemenu','callback') {                  if (($env{'form.lti_mapcrs_'.$idx} eq 'course_offering_sourcedid') ||
                     if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) {                      ($env{'form.lti_mapcrs_'.$idx} eq 'context_id'))  {
                         $changes{$itemid} = 1;                      $confhash{$itemid}{'mapcrs'} = $env{'form.lti_mapcrs_'.$idx};
                   } elsif ($env{'form.lti_mapcrs_'.$idx} eq 'other') {
                       my $mapcrs = $env{'form.lti_mapcrsfield_'.$idx}; 
                       $mapcrs =~ s/(`)/'/g;
                       $mapcrs =~ s/^\s+|\s+$//g;
                       $confhash{$itemid}{'mapcrs'} = $mapcrs;
                   }
                   my @posstypes = &Apache::loncommon::get_env_multiple('form.lti_mapcrstype_'.$idx);
                   my @crstypes;
                   foreach my $type (sort(@posstypes)) {
                       if ($posscrstype{$type}) {
                           push(@crstypes,$type);
                       }
                   }
                   $confhash{$itemid}{'mapcrstype'} = \@crstypes;
                   if ($env{'form.lti_storecrs_'.$idx}) {
                       $confhash{$itemid}{'storecrs'} = 1;
                   }       
                   if ($env{'form.lti_makecrs_'.$idx}) {
                       $confhash{$itemid}{'makecrs'} = 1;
                   }
                   foreach my $ltirole (@lticourseroles) {
                       my $possrole = $env{'form.lti_maprole_'.$ltirole.'_'.$idx};
                       if (grep(/^\Q$possrole\E$/,@courseroles)) {
                           $confhash{$itemid}{'maproles'}{$ltirole} = $possrole;
                       }
                   }
                   my @possenroll = &Apache::loncommon::get_env_multiple('form.lti_selfenroll_'.$idx);
                   my @selfenroll;
                   foreach my $type (sort(@possenroll)) {
                       if ($posslticrs{$type}) {
                           push(@selfenroll,$type);
                       }
                   }
                   $confhash{$itemid}{'selfenroll'} = \@selfenroll;
                   if ($env{'form.lti_crssec_'.$idx}) {
                       if ($env{'form.lti_crssecsrc_'.$idx} eq 'course_section_sourcedid') {
                           $confhash{$itemid}{'section'} = $env{'form.lti_crssecsrc_'.$idx};
                       } elsif ($env{'form.lti_crssecsrc_'.$idx} eq 'other') {
                           my $section = $env{'form.lti_customsection_'.$idx};
                           $section =~ s/(`)/'/g;
                           $section =~ s/^\s+|\s+$//g;
                           if ($section ne '') {
                               $confhash{$itemid}{'section'} = $section;
                           }
                     }                      }
                 }                  }
                 unless ($changes{$itemid}) {                  foreach my $field ('passback','roster') {
                     if ($domconfig{$action}{$itemid}{'passback'} eq $confhash{$itemid}{'passback'}) {                      if ($env{'form.lti_'.$field.'_'.$idx}) {
                         if ($domconfig{$action}{$itemid}{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) {                          $confhash{$itemid}{$field} = 1;
                       }
                   }
                   if ($env{'form.lti_passback_'.$idx}) {
                       if ($env{'form.lti_passbackformat_'.$idx} eq '1.0') {
                           $confhash{$itemid}{'passbackformat'} = '1.0';
                       } else {
                           $confhash{$itemid}{'passbackformat'} = '1.1';
                       }
                   }
               }
               unless (($idx eq 'add') || ($changes{$itemid})) {
                   if ($confhash{$itemid}{'crsinc'}) {
                       foreach my $field ('mapcrs','storecrs','makecrs','section','passback','roster') {
                           if ($currlti{$field} ne $confhash{$itemid}{$field}) {
                             $changes{$itemid} = 1;                              $changes{$itemid} = 1;
                         }                          }
                     }                      }
                 }  
                 foreach my $field ('makeuser','mapcrstype','selfenroll','instdata','lcmenu') {  
                     unless ($changes{$itemid}) {                      unless ($changes{$itemid}) {
                         if (ref($domconfig{$action}{$itemid}{$field}) eq 'ARRAY') {                          if ($currlti{'passback'} eq $confhash{$itemid}{'passback'}) {
                             if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {                              if ($currlti{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) {
                                 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;                                  $changes{$itemid} = 1;
                             }                              }
                         }                          }
                     }                      }
                 }                      foreach my $field ('mapcrstype','selfenroll') {
                 unless ($changes{$itemid}) {                          unless ($changes{$itemid}) {
                     if (ref($domconfig{$action}{$itemid}{'maproles'}) eq 'HASH') {                              if (ref($currlti{$field}) eq 'ARRAY') {
                         if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {                                  if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
                             foreach my $ltirole (keys(%{$domconfig{$action}{$itemid}{'maproles'}})) {                                      my @diffs = &Apache::loncommon::compare_arrays($currlti{$field},
                                 if ($domconfig{$action}{$itemid}{'maproles'}{$ltirole} ne                                                                                      $confhash{$itemid}{$field});
                                     $confhash{$itemid}{'maproles'}{$ltirole}) {                                      if (@diffs) {
                                           $changes{$itemid} = 1;
                                       }
                                   } elsif (@{$currlti{$field}} > 0) {
                                       $changes{$itemid} = 1;
                                   }
                               } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
                                   if (@{$confhash{$itemid}{$field}} > 0) {
                                     $changes{$itemid} = 1;                                      $changes{$itemid} = 1;
                                     last;  
                                 }                                  }
                             }                              }
                             unless ($changes{$itemid}) {                          }
                                 foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) {                      }
                                     if ($confhash{$itemid}{'maproles'}{$ltirole} ne                       unless ($changes{$itemid}) {
                                         $domconfig{$action}{$itemid}{'maproles'}{$ltirole}) {                          if (ref($currlti{'maproles'}) eq 'HASH') {
                               if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
                                   foreach my $ltirole (keys(%{$currlti{'maproles'}})) {
                                       if ($currlti{'maproles'}{$ltirole} ne 
                                           $confhash{$itemid}{'maproles'}{$ltirole}) {
                                         $changes{$itemid} = 1;                                          $changes{$itemid} = 1;
                                         last;                                          last;
                                     }                                      }
                                 }                                  }
                                   unless ($changes{$itemid}) {
                                       foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) {
                                           if ($confhash{$itemid}{'maproles'}{$ltirole} ne 
                                               $currlti{'maproles'}{$ltirole}) {
                                               $changes{$itemid} = 1;
                                               last;
                                           }
                                       }
                                   }
                               } elsif (keys(%{$currlti{'maproles'}}) > 0) {
                                   $changes{$itemid} = 1;
                             }                              }
                         } elsif (keys(%{$domconfig{$action}{$itemid}{'maproles'}}) > 0) {                          } elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
                               unless ($changes{$itemid}) {
                                   if (keys(%{$confhash{$itemid}{'maproles'}}) > 0) {
                                       $changes{$itemid} = 1;
                                   }
                               }
                           }
                       }
                   }
                   unless ($changes{$itemid}) {
                       foreach my $field ('mapuser','lcauth','lcauthparm','topmenu','inlinemenu','callback') {
                           if ($currlti{$field} ne $confhash{$itemid}{$field}) {
                             $changes{$itemid} = 1;                              $changes{$itemid} = 1;
                         }                          }
                     } elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {                      }
                         unless ($changes{$itemid}) {                      unless ($changes{$itemid}) {
                             if (keys(%{$confhash{$itemid}{'maproles'}}) > 0) {                          foreach my $field ('makeuser','lcmenu') {
                               if (ref($currlti{$field}) eq 'ARRAY') {
                                   if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
                                       my @diffs = &Apache::loncommon::compare_arrays($currlti{$field},
                                                                                      $confhash{$itemid}{$field});
                                       if (@diffs) {
                                           $changes{$itemid} = 1;
                                       }
                                   } elsif (@{$currlti{$field}} > 0) {
                                       $changes{$itemid} = 1;
                                   }
                               } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
                                   if (@{$confhash{$itemid}{$field}} > 0) {
                                       $changes{$itemid} = 1;
                                   }
                               }
                           }
                       }
                   }
               }
           }
           if ($is_home) {
               my $keyitem = 'form.lti_key_'.$idx;
               $env{$keyitem} =~ s/(`)/'/g;
               if ($env{$keyitem} ne '') {
                   $ltienc{$itemid}{'key'} = $env{$keyitem};
                   unless ($changes{$itemid}) {
                       if ($currlti{'key'} ne $env{$keyitem}) {
                           $changes{$itemid} = 1;
                       }
                   }
               }
               my $secretitem = 'form.lti_secret_'.$idx;
               $env{$secretitem} =~ s/(`)/'/g;
               if ($currlti{'usable'}) {
                   if ($env{'form.lti_changesecret_'.$idx}) {
                       if ($env{$secretitem} ne '') {
                           if ($privnum && $cipher) {
                               $ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
                               $confhash{$itemid}{'cipher'} = $privnum;
                           } else {
                               $ltienc{$itemid}{'secret'} = $env{$secretitem};
                           }
                           $changes{$itemid} = 1;
                       }
                   } else {
                       $ltienc{$itemid}{'secret'} = $currlti{'secret'};
                       $confhash{$itemid}{'cipher'} = $currlti{'cipher'};
                   }
                   if (ref($ltienc{$itemid}) eq 'HASH') {
                       if (($ltienc{$itemid}{'key'} ne '') && ($ltienc{$itemid}{'secret'} ne '')) {
                           $confhash{$itemid}{'usable'} = 1;
                       }
                   }
               } elsif ($env{$secretitem} ne '') {
                   if ($privnum && $cipher) {
                       $ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
                       $confhash{$itemid}{'cipher'} = $privnum;
                   } else {
                       $ltienc{$itemid}{'secret'} = $env{$secretitem};
                   }
                   if (ref($ltienc{$itemid}) eq 'HASH') {
                       if (($ltienc{$itemid}{'key'} ne '') && ($ltienc{$itemid}{'key'} ne '')) {
                           $confhash{$itemid}{'usable'} = 1;
                       }
                   }
                   $changes{$itemid} = 1;
               }
           }
           unless ($changes{$itemid}) {
               foreach my $key (keys(%currlti)) {
                   if (ref($currlti{$key}) eq 'HASH') {
                       if (ref($confhash{$itemid}{$key}) eq 'HASH') {
                           foreach my $innerkey (keys(%{$currlti{$key}})) {
                               unless (exists($confhash{$itemid}{$key}{$innerkey})) {
                                 $changes{$itemid} = 1;                                  $changes{$itemid} = 1;
                                   last;
                             }                              }
                         }                          }
                       } elsif (keys(%{$currlti{$key}}) > 0) {
                           $changes{$itemid} = 1;
                     }                      }
                 }                  }
                   last if ($changes{$itemid});
             }              }
         }          }
     }      }
Line 14326  sub modify_lti { Line 16078  sub modify_lti {
             }              }
         }          }
     }      }
   
       if ((keys(%changes) == 0) && (keys(%secchanges) == 0)) {
           return &mt('No changes made.');
       }
   
     my %ltihash = (      my %ltihash = (
                           $action => { %confhash }                        $action => { %confhash }
                        );                    );
     my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,      my %ltienchash;
                                              $dom);  
       if ($is_home) {
           %ltienchash = (
                            $action => { %ltienc }
                         );
       }
       if (keys(%secchanges)) {
           $ltihash{'ltisec'} = \%newltisec;
           if ($secchanges{'linkprot'}) {
               if ($is_home) {
                   $ltienchash{'linkprot'} = \%newltienc;
               }
           }
       }
       my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,$dom);
     if ($putresult eq 'ok') {      if ($putresult eq 'ok') {
         my %ltienchash = (          if (keys(%ltienchash)) {
                              $action => { %encconfig }              &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1);
                          );          }
         &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom);          $resulttext = &mt('Changes made:').'<ul>';
           if (keys(%secchanges) > 0) {
               $resulttext .= &lti_security_results($dom,'lti',\%secchanges,\%newltisec,\%newkeyset,\%keystore);
               if (exists($secchanges{'linkprot'})) {
                   $resulttext .= $linkprotoutput;
               }
           }
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
             my $cachetime = 24*60*60;              my $cachetime = 24*60*60;
             my %ltiall = %confhash;              &Apache::lonnet::do_cache_new('lti',$dom,\%confhash,$cachetime);
             foreach my $id (keys(%ltiall)) {  
                 if (ref($encconfig{$id}) eq 'HASH') {  
                     foreach my $item ('key','secret') {  
                         $ltiall{$id}{$item} = $encconfig{$id}{$item};  
                     }  
                 }  
             }  
             &Apache::lonnet::do_cache_new('lti',$dom,\%ltiall,$cachetime);  
             if (ref($lastactref) eq 'HASH') {              if (ref($lastactref) eq 'HASH') {
                 $lastactref->{'lti'} = 1;                  $lastactref->{'lti'} = 1;
             }              }
             $resulttext = &mt('Changes made:').'<ul>';  
             my %bynum;              my %bynum;
             foreach my $itemid (sort(keys(%changes))) {              foreach my $itemid (sort(keys(%changes))) {
                 my $position = $confhash{$itemid}{'order'};                  if (ref($confhash{$itemid}) eq 'HASH') {
                 $bynum{$position} = $itemid;                      my $position = $confhash{$itemid}{'order'};
                       $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}) eq 'HASH') {
                     $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';                      $resulttext .= '<li><b>'.$confhash{$itemid}{'consumer'}.'</b><ul>';
                 } else {  
                     $resulttext .= '<li><b>'.$confhash{$itemid}{'consumer'}.'</b></li><ul>';  
                     my $position = $pos + 1;                      my $position = $pos + 1;
                     $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';                      $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';
                     foreach my $item ('version','lifetime') {                      foreach my $item ('version','lifetime') {
Line 14369  sub modify_lti { Line 16137  sub modify_lti {
                             $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{$item}.'</li>';                              $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{$item}.'</li>';
                         }                          }
                     }                      }
                     if ($encconfig{$itemid}{'key'} ne '') {                      if ($ltienc{$itemid}{'key'} ne '') {
                         $resulttext .= '<li>'.$lt{'key'}.':&nbsp;'.$encconfig{$itemid}{'key'}.'</li>';                          $resulttext .= '<li>'.$lt{'key'}.':&nbsp;'.$ltienc{$itemid}{'key'}.'</li>';
                     }                      }
                     if ($encconfig{$itemid}{'secret'} ne '') {                      if ($ltienc{$itemid}{'secret'} ne '') {
                         $resulttext .= '<li>'.$lt{'secret'}.':&nbsp;';                          $resulttext .= '<li>'.$lt{'secret'}.':&nbsp;['.&mt('not shown').']</li>';
                         my $num = length($encconfig{$itemid}{'secret'});  
                         $resulttext .= ('*'x$num).'</li>';  
                     }                      }
                     if ($confhash{$itemid}{'requser'}) {                      if ($confhash{$itemid}{'requser'}) {
                           if ($confhash{$itemid}{'callback'}) {
                               $resulttext .= '<li>'.&mt('Callback setting').': '.$confhash{$itemid}{'callback'}.'</li>';
                           } else {
                               $resulttext .= '<li>'.&mt('Callback to logout LON-CAPA on log out from Consumer').'</li>';
                           }
                         if ($confhash{$itemid}{'mapuser'}) {                          if ($confhash{$itemid}{'mapuser'}) {
                             my $shownmapuser;                              my $shownmapuser;
                             if ($confhash{$itemid}{'mapuser'} eq 'lis_person_sourcedid') {                              if ($confhash{$itemid}{'mapuser'} eq 'lis_person_sourcedid') {
Line 14389  sub modify_lti { Line 16160  sub modify_lti {
                             }                              }
                             $resulttext .= '<li>'.&mt('LON-CAPA username').': '.$shownmapuser.'</li>';                              $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 (ref($confhash{$itemid}{'makeuser'}) eq 'ARRAY') {
                             if (@{$confhash{$itemid}{'makeuser'}} > 0) {                               if (@{$confhash{$itemid}{'makeuser'}} > 0) { 
                                 $resulttext .= '<li>'.&mt('Following roles may create user accounts: [_1]',                                  $resulttext .= '<li>'.&mt('Following roles may create user accounts: [_1]',
Line 14435  sub modify_lti { Line 16192  sub modify_lti {
                                 $resulttext .= '<li>'.&mt('No institutional data used when creating a new user.').'</li>';                                  $resulttext .= '<li>'.&mt('No institutional data used when creating a new user.').'</li>';
                             }                              }
                         }                          }
                         if ($confhash{$itemid}{'mapcrs'}) {                          foreach my $item ('topmenu','inlinemenu') {
                             $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 {  
                             $resulttext .= '<li>'.&mt('Instructor may not create course (if absent).').'</li>';  
                         }  
                         if (ref($confhash{$itemid}{'selfenroll'}) eq 'ARRAY') {  
                             if (@{$confhash{$itemid}{'selfenroll'}} > 0) {  
                                 $resulttext .= '<li>'.&mt('Self-enrollment for following roles: [_1]',  
                                                           join(', ',@{$confhash{$itemid}{'selfenroll'}})).  
                                                '</li>';  
                             } else {  
                                 $resulttext .= '<li>'.&mt('Self-enrollment not permitted').'</li>';  
                             }  
                         }  
                         if ($confhash{$itemid}{'section'}) {  
                             if ($confhash{$itemid}{'section'} eq 'course_section_sourcedid') {  
                                 $resulttext .= '<li>'.&mt('User section from standard field:').  
                                                      ' (course_section_sourcedid)'.'</li>';    
                             } else {  
                                 $resulttext .= '<li>'.&mt('User section from:').' '.  
                                                       $confhash{$itemid}{'section'}.'</li>';  
                             }  
                         } else {  
                             $resulttext .= '<li>'.&mt('No section assignment').'</li>';  
                         }  
                         if ($confhash{$itemid}{'callback'}) {  
                             $resulttext .= '<li>'.&mt('Callback setting').': '.$confhash{$itemid}{'callback'}.'</li>';  
                         } else {  
                             $resulttext .= '<li>'.&mt('No callback to logout LON-CAPA session when user logs out of Comsumer');  
                         }  
                         foreach my $item ('passback','roster','topmenu','inlinemenu') {  
                             $resulttext .= '<li>'.$lt{$item}.':&nbsp;';                              $resulttext .= '<li>'.$lt{$item}.':&nbsp;';
                             if ($confhash{$itemid}{$item}) {                              if ($confhash{$itemid}{$item}) {
                                 $resulttext .= &mt('Yes');                                  $resulttext .= &mt('Yes');
                                 if ($item eq 'passback') {  
                                     if ($confhash{$itemid}{'passbackformat'} eq '1.0') {  
                                         $resulttext .= '&nbsp;('.&mt('Outcomes Extension (1.0)').')';  
                                     } elsif ($confhash{$itemid}{'passbackformat'} eq '1.1') {  
                                         $resulttext .= '&nbsp;('.&mt('Outcomes Service (1.1)').')';  
                                     }  
                                 }  
                             } else {                              } else {
                                 $resulttext .= &mt('No');                                  $resulttext .= &mt('No');
                             }                              }
Line 14496  sub modify_lti { Line 16204  sub modify_lti {
                         if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') {                          if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') {
                             if (@{$confhash{$itemid}{'lcmenu'}} > 0) {                              if (@{$confhash{$itemid}{'lcmenu'}} > 0) {
                                 $resulttext .= '<li>'.&mt('Menu items:').' '.                                  $resulttext .= '<li>'.&mt('Menu items:').' '.
                                                join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>';                                                  join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>';
                             } else {                              } else {
                                 $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>';                                   $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>';
                               }
                           }
                           if ($confhash{$itemid}{'crsinc'}) {
                               if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
                                   my $rolemaps;
                                   foreach my $role (@ltiroles) {
                                       if ($confhash{$itemid}{'maproles'}{$role}) {
                                           $rolemaps .= ('&nbsp;'x2).$role.'='.
                                                        &Apache::lonnet::plaintext($confhash{$itemid}{'maproles'}{$role},
                                                                                   'Course').',';
                                       }
                                   }
                                   if ($rolemaps) {
                                       $rolemaps =~ s/,$//;
                                       $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>';
                                   }
                               }
                               if ($confhash{$itemid}{'mapcrs'}) {
                                   $resulttext .= '<li>'.&mt('Unique course identifier').': '.$confhash{$itemid}{'mapcrs'}.'</li>';
                               }
                               if (ref($confhash{$itemid}{'mapcrstype'}) eq 'ARRAY') {
                                   if (@{$confhash{$itemid}{'mapcrstype'}} > 0) {
                                       $resulttext .= '<li>'.&mt('Mapping for the following LON-CAPA course types: [_1]',
                                                      join(', ',map { $coursetypetitles{$_}; } @coursetypes)).
                                                      '</li>';
                                   } else {
                                       $resulttext .= '<li>'.&mt('No mapping to LON-CAPA courses').'</li>';
                                   }
                               }
                               if ($confhash{$itemid}{'storecrs'}) {
                                   $resulttext .= '<li>'.&mt('Store mapping of course identifier to LON-CAPA CourseID').': '.$confhash{$itemid}{'storecrs'}.'</li>';
                               }
                               if ($confhash{$itemid}{'makecrs'}) {
                                   $resulttext .= '<li>'.&mt('Instructor may create course (if absent).').'</li>';
                               } else {
                                   $resulttext .= '<li>'.&mt('Instructor may not create course (if absent).').'</li>';
                               }
                               if (ref($confhash{$itemid}{'selfenroll'}) eq 'ARRAY') {
                                   if (@{$confhash{$itemid}{'selfenroll'}} > 0) {
                                       $resulttext .= '<li>'.&mt('Self-enrollment for following roles: [_1]',
                                                                 join(', ',@{$confhash{$itemid}{'selfenroll'}})).
                                                      '</li>';
                                   } else {
                                       $resulttext .= '<li>'.&mt('Self-enrollment not permitted').'</li>';
                                   }
                               }
                               if ($confhash{$itemid}{'section'}) {
                                   if ($confhash{$itemid}{'section'} eq 'course_section_sourcedid') {
                                       $resulttext .= '<li>'.&mt('User section from standard field:').
                                                            ' (course_section_sourcedid)'.'</li>';  
                                   } else {
                                       $resulttext .= '<li>'.&mt('User section from:').' '.
                                                             $confhash{$itemid}{'section'}.'</li>';
                                   }
                               } else {
                                   $resulttext .= '<li>'.&mt('No section assignment').'</li>';
                               }
                               foreach my $item ('passback','roster','topmenu','inlinemenu') {
                                   $resulttext .= '<li>'.$lt{$item}.':&nbsp;';
                                   if ($confhash{$itemid}{$item}) {
                                       $resulttext .= &mt('Yes');
                                       if ($item eq 'passback') {
                                           if ($confhash{$itemid}{'passbackformat'} eq '1.0') {
                                               $resulttext .= '&nbsp;('.&mt('Outcomes Extension (1.0)').')';
                                           } elsif ($confhash{$itemid}{'passbackformat'} eq '1.1') {
                                               $resulttext .= '&nbsp;('.&mt('Outcomes Service (1.1)').')';
                                           }
                                       }
                                   } else {
                                       $resulttext .= &mt('No');
                                   }
                                   $resulttext .= '</li>';
                               }
                               if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') {
                                   if (@{$confhash{$itemid}{'lcmenu'}} > 0) {
                                       $resulttext .= '<li>'.&mt('Menu items:').' '.
                                                      join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>'; 
                                   } else {
                                       $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>'; 
                                   }
                             }                              }
                         }                          }
                     }                      }
                     $resulttext .= '</ul></li>';                      $resulttext .= '</ul></li>';
                 }                  }
             }              }
             $resulttext .= '</ul>';              if (keys(%deletions)) {
         } else {                  foreach my $itemid (sort { $a <=> $b } keys(%deletions)) {
             $resulttext = &mt('No changes made.');                      $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';
                   }
               }
           }
           $resulttext .= '</ul>';
           if (ref($lastactref) eq 'HASH') {
               if (($secchanges{'encrypt'}) || ($secchanges{'private'})) {
                   $lastactref->{'domdefaults'} = 1;
               }
         }          }
     } else {      } else {
         $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';          $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';
Line 14519  sub modify_lti { Line 16315  sub modify_lti {
     return $resulttext;      return $resulttext;
 }  }
   
   sub get_priv_creds {
       my ($dom,$home,$encchg,$encrypt,$storedsec) = @_;
       my ($needenc,$cipher,$privnum);
       my %domdefs = &Apache::lonnet::get_domain_defaults($dom);
       if (($encchg) && (ref($encrypt) eq 'HASH')) {
           $needenc = $encrypt->{'consumers'} 
       } else {
           $needenc = $domdefs{'ltienc_consumers'};
       }
       if ($needenc) {
           if (($storedsec eq 'ok') || ((ref($domdefs{'ltiprivhosts'}) eq 'ARRAY') &&
                                        (grep(/^\Q$home\E$/,@{$domdefs{'ltiprivhosts'}})))) {
                           my %privhash  = &Apache::lonnet::restore_dom('lti','private',$dom,$home,1);
               my $privkey = $privhash{'key'};
               $privnum = $privhash{'version'};
               if (($privnum) && ($privkey ne '')) {
                   $cipher = Crypt::CBC->new({'key'     => $privkey,
                                             'cipher'  => 'DES'});
               }
           }
       }
       return ($cipher,$privnum);
   }
   
 sub get_lti_id {  sub get_lti_id {
     my ($domain,$consumer) = @_;      my ($domain,$consumer) = @_;
     # get lock on lti db      # get lock on lti db
Line 14575  sub modify_autoenroll { Line 16395  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)',
                   failsafe => 'Failsafe for no drops if institutional data missing for a section');                    autofailsafe => 'Failsafe for no drops if institutional data missing for a section');
     my @offon = ('off','on');      my @offon = ('off','on');
     my $sender_uname = $env{'form.sender_uname'};      my $sender_uname = $env{'form.sender_uname'};
     my $sender_domain = $env{'form.sender_domain'};      my $sender_domain = $env{'form.sender_domain'};
Line 14585  sub modify_autoenroll { Line 16405  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'};
     $failsafe =~ s{^\s+|\s+$}{}g;      unless (($failsafe eq 'zero') || ($failsafe eq 'any')) {
     if ($failsafe =~ /\D/) {          $failsafe = 'off';
         undef($failsafe);          undef($autofailsafe);
     }      }
     my %autoenrollhash =  (      my %autoenrollhash =  (
                        autoenroll => { 'run' => $env{'form.autoenroll_run'},                         autoenroll => { 'run' => $env{'form.autoenroll_run'},
                                        'sender_uname' => $sender_uname,                                         'sender_uname' => $sender_uname,
                                        'sender_domain' => $sender_domain,                                         'sender_domain' => $sender_domain,
                                        'co-owners' => $coowners,                                         'co-owners' => $coowners,
                                        'autofailsafe' => $failsafe,                                         'autofailsafe' => $autofailsafe,
                                          'failsafe' => $failsafe,
                                 }                                  }
                      );                       );
     my $putresult = &Apache::lonnet::put_dom('configuration',\%autoenrollhash,      my $putresult = &Apache::lonnet::put_dom('configuration',\%autoenrollhash,
Line 14623  sub modify_autoenroll { Line 16449  sub modify_autoenroll {
         } elsif ($coowners) {          } elsif ($coowners) {
             $changes{'coowners'} = 1;              $changes{'coowners'} = 1;
         }          }
         if ($currautoenroll{'autofailsafe'} ne $failsafe) {          if ($currautoenroll{'autofailsafe'} ne $autofailsafe) {
             $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 14646  sub modify_autoenroll { Line 16475  sub modify_autoenroll {
                 }                  }
             }              }
             if ($changes{'autofailsafe'}) {              if ($changes{'autofailsafe'}) {
                 if ($failsafe ne '') {                  if ($autofailsafe ne '') {
                     $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section set to: [_1]',$failsafe).'</li>';                      $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section set to: [_1]',$autofailsafe).'</li>';
                   } else {
                       $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section not in use').'</li>';
                   }
               }
               if ($changes{'failsafe'}) {
                   if ($failsafe eq 'off') {
                       unless ($changes{'autofailsafe'}) {
                           $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section not in use').'</li>';
                       }
                   } elsif ($failsafe eq 'zero') {
                       $resulttext .= '<li>'.&mt('Failsafe applies if retrieved section enrollment is zero').'</li>';
                 } else {                  } else {
                     $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section: deleted');                      $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 14677  sub modify_autoupdate { Line 16519  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 14722  sub modify_autoupdate { Line 16566  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')) {          if (($key eq 'run') || ($key eq 'classlists') || ($key eq 'unexpired') || ($key eq 'lastactive')) {
             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 14773  sub modify_autoupdate { Line 16628  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 14835  sub modify_autoupdate { Line 16700  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 15271  sub modify_contacts { Line 17141  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 15329  sub modify_contacts { Line 17199  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 15351  sub modify_contacts { Line 17221  sub modify_contacts {
                 }                  }
             } else {              } else {
                 foreach my $key (@overrides) {                  foreach my $key (@overrides) {
                     push(@{$changes{'overrides'}},$key);                       push(@{$changes{'overrides'}},$key);
                 }                  }
             }              }
         }          }
Line 15533  sub modify_contacts { Line 17403  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 15557  sub modify_contacts { Line 17427  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 15727  sub modify_contacts { Line 17597  sub modify_contacts {
 }  }
   
 sub modify_privacy {  sub modify_privacy {
     my ($dom,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,%current,%changes);      my ($resulttext,%current,%changes);
     if (ref($domconfig{'privacy'}) eq 'HASH') {      if (ref($domconfig{'privacy'}) eq 'HASH') {
         %current = %{$domconfig{'privacy'}};          %current = %{$domconfig{'privacy'}};
Line 15738  sub modify_privacy { Line 17608  sub modify_privacy {
                    domain => 'Assigned domain role(s)',                     domain => 'Assigned domain role(s)',
                    author => 'Assigned co-author role(s)',                     author => 'Assigned co-author role(s)',
                    course => 'Assigned course role(s)',                     course => 'Assigned course role(s)',
                    community => 'Assigned community role',                     community => 'Assigned community role(s)',
                 );                  );
     my %roles = &Apache::lonlocal::texthash (      my %roles = &Apache::lonlocal::texthash (
                    domain => 'Domain role',                     domain => 'Domain role',
Line 15757  sub modify_privacy { Line 17627  sub modify_privacy {
                   user     => 'User authorizes',                    user     => 'User authorizes',
                   domain   => 'Domain Coordinator authorizes',                    domain   => 'Domain Coordinator authorizes',
                   auto     => 'Unrestricted',                    auto     => 'Unrestricted',
                     notify   => 'Notify when role needs authorization',
     );      );
     my %fieldnames = &Apache::lonlocal::texthash (      my %fieldnames = &Apache::lonlocal::texthash (
                         id => 'Student/Employee ID',                          id => 'Student/Employee ID',
Line 15782  sub modify_privacy { Line 17653  sub modify_privacy {
                       );                        );
     foreach my $item (@items) {      foreach my $item (@items) {
         if (@instdoms > 1) {          if (@instdoms > 1) {
             if ($env{'form.privacy_approval_instdom'.$item} =~ /^(none|user|domain|auto)$/) {              if ($env{'form.privacy_approval_instdom_'.$item} =~ /^(none|user|domain|auto)$/) {
                 $privacyhash{'approval'}{'instdom'}{$item} = $env{'form.privacy_approval_instdom_'.$item};                  $privacyhash{'approval'}{'instdom'}{$item} = $env{'form.privacy_approval_instdom_'.$item};
             }              }
             if (ref($current{'approval'}) eq 'HASH') {              if (ref($current{'approval'}) eq 'HASH') {
Line 15874  sub modify_privacy { Line 17745  sub modify_privacy {
                 }                  }
             }              }
         }          }
           my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']);
           my %notify;
           foreach my $possdc (&Apache::loncommon::get_env_multiple('form.privacy_notify')) {
               if (exists($domcoords{$possdc})) {
                   $notify{$possdc} = 1;
               }
           }
           my $notify = join(',',sort(keys(%notify)));
           if ($current{'notify'} ne $notify) {
               $changes{'notify'} = 1;
           }
           $privacyhash{'notify'} = $notify;
     }      }
     my %confighash = (      my %confighash = (
                         privacy => \%privacyhash,                          privacy => \%privacyhash,
Line 15882  sub modify_privacy { Line 17765  sub modify_privacy {
     if ($putresult eq 'ok') {      if ($putresult eq 'ok') {
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
             $resulttext = &mt('Changes made: ').'<ul>';              $resulttext = &mt('Changes made: ').'<ul>';
             foreach my $key ('approval','othdom','priv','unpriv') {              foreach my $key ('approval','notify','othdom','priv','unpriv') {
                 if ($changes{$key}) {                  if ($changes{$key}) {
                     $resulttext .= '<li>'.$titles{$key}.':<ul>';                      $resulttext .= '<li>'.$titles{$key}.':<ul>';
                     if ($key eq 'approval') {                      if ($key eq 'approval') {
Line 15900  sub modify_privacy { Line 17783  sub modify_privacy {
                             }                              }
                             $resulttext .= '</ul></li>';                              $resulttext .= '</ul></li>';
                         }                          }
                       } elsif ($key eq 'notify') {
                           if ($privacyhash{$key}) {
                               foreach my $dc (split(/,/,$privacyhash{$key})) {
                                   my ($dcname,$dcdom) = split(/:/,$dc);
                                   $resulttext .= '<li>'.&Apache::loncommon::plainname($dcname,$dcdom).'</li>';
                               }
                           } else {
                               $resulttext .= '<li>'.&mt('No DCs to notify').'</li>';
                           }
                     } elsif ($key eq 'othdom') {                      } elsif ($key eq 'othdom') {
                         my @statuses;                          my @statuses;
                         if (ref($types) eq 'ARRAY') {                          if (ref($types) eq 'ARRAY') {
Line 15940  sub modify_privacy { Line 17832  sub modify_privacy {
                     $resulttext .= '</ul></li>';                      $resulttext .= '</ul></li>';
                 }                  }
             }              }
               $resulttext .= '</ul>';
               if ($changes{'approval'}) {
                   my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
                   delete($domdefaults{'userapprovals'});
                   if (ref($privacyhash{'approval'}) eq 'HASH') {
                       foreach my $domtype ('instdom','extdom') {
                           if (ref($privacyhash{'approval'}{$domtype}) eq 'HASH') {
                               foreach my $roletype ('domain','author','course','community') {
                                   if ($privacyhash{'approval'}{$domtype}{$roletype} eq 'user') {
                                       $domdefaults{'userapprovals'} = 1;
                                       last;
                                   }
                               }
                           }
                           last if ($domdefaults{'userapprovals'});               
                       }
                   }
                   my $cachetime = 24*60*60;
                   &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
                   if (ref($lastactref) eq 'HASH') {
                       $lastactref->{'domdefaults'} = 1;
                   }
               }
         } else {          } else {
             $resulttext = &mt('No changes made to user information settings');              $resulttext = &mt('No changes made to user information settings');
         }          }
Line 16126  sub modify_passwords { Line 18041  sub modify_passwords {
                 $error = &mt("Upload of file containing domain-specific text is not permitted to this server: [_1]",$switchserver);                  $error = &mt("Upload of file containing domain-specific text is not permitted to this server: [_1]",$switchserver);
             } else {              } else {
                 if ($author_ok eq 'ok') {                  if ($author_ok eq 'ok') {
                       my $modified = [];
                     my ($result,$customurl) =                      my ($result,$customurl) =
                         &publishlogo($r,'upload','passwords_customfile',$dom,                          &Apache::lonconfigsettings::publishlogo($r,'upload','passwords_customfile',$dom,
                                      $confname,'customtext/resetpw','','',$customfn);                                                                  $confname,'customtext/resetpw','','',$customfn,
                                                                   $modified);
                     if ($result eq 'ok') {                      if ($result eq 'ok') {
                         $newvalues{'resetcustom'} = $customurl;                          $newvalues{'resetcustom'} = $customurl;
                         $changes{'reset'} = 1;                          $changes{'reset'} = 1;
                           &update_modify_urls($r,$modified);
                     } else {                      } else {
                         $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$customfn,$result);                          $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$customfn,$result);
                     }                      }
Line 16184  sub modify_passwords { Line 18102  sub modify_passwords {
             $updatedefaults = 1;              $updatedefaults = 1;
         }          }
     }      }
     foreach my $rule ('min','max','expire','numsaved') {      &password_rule_changes('passwords',\%newvalues,\%current,\%changes);
         $env{'form.passwords_'.$rule} =~ s/^\s+|\s+$//g;  
         my $ruleok;  
         if ($rule eq 'expire') {  
             if (($env{'form.passwords_'.$rule} =~ /^\d+(|\.\d*)$/) &&  
                 ($env{'form.passwords_'.$rule} ne '0')) {  
                 $ruleok = 1;  
             }  
         } elsif ($rule eq 'min') {  
             if ($env{'form.passwords_'.$rule} =~ /^\d+$/) {  
                 if ($env{'form.passwords_'.$rule} >= $Apache::lonnet::passwdmin) {  
                     $ruleok = 1;  
                 }  
             }  
         } elsif (($env{'form.passwords_'.$rule} =~ /^\d+$/) &&  
                  ($env{'form.passwords_'.$rule} ne '0')) {  
             $ruleok = 1;  
         }  
         if ($ruleok) {  
             $newvalues{$rule} = $env{'form.passwords_'.$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.passwords_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;  
             }  
         }  
     }  
     my %crsownerchg = (      my %crsownerchg = (
                         by => [],                          by => [],
                         for => [],                          for => [],
Line 16366  sub modify_passwords { Line 18230  sub modify_passwords {
                                 $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>';                                  $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>';
                             }                              }
                         } else {                          } else {
                             $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA usedfor verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>';                              $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'}) {                          if ($confighash{'passwords'}{'resetremove'}) {
                             $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form not shown').'</li>';                              $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form not shown').'</li>';
Line 16433  sub modify_passwords { Line 18297  sub modify_passwords {
                                                    );                                                     );
                                 my $needed = '<ul><li>'.                                  my $needed = '<ul><li>'.
                                              join('</li><li>',map {$rulenames{$_} } @{$confighash{'passwords'}{'chars'}}).                                               join('</li><li>',map {$rulenames{$_} } @{$confighash{'passwords'}{'chars'}}).
                                              '</li></ul>';                                                '</li></ul>';
                                 $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>';                                  $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>';
                             } else {                              } else {
                                 $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';                                  $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';
Line 16498  sub modify_passwords { Line 18362  sub modify_passwords {
     return $resulttext;      return $resulttext;
 }  }
   
   sub password_rule_changes {
       my ($prefix,$newvalues,$current,$changes) = @_;
       return unless ((ref($newvalues) eq 'HASH') &&
                      (ref($current) eq 'HASH') &&
                      (ref($changes) eq 'HASH'));
       my (@rules,%staticdefaults);
       if ($prefix eq 'passwords') {
           @rules = ('min','max','expire','numsaved');
       } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {
           @rules = ('min','max');
       }
       $staticdefaults{'min'} = $Apache::lonnet::passwdmin;
       foreach my $rule (@rules) {
           $env{'form.'.$prefix.'_'.$rule} =~ s/^\s+|\s+$//g;
           my $ruleok;
           if ($rule eq 'expire') {
               if (($env{'form.'.$prefix.'_'.$rule} =~ /^\d+(|\.\d*)$/) &&
                   ($env{'form.'.$prefix.'_'.$rule} ne '0')) {
                   $ruleok = 1;
               }
           } elsif ($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 16846  sub modify_selfcreation { Line 18780  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 16858  sub modify_selfcreation { Line 18792  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 17285  sub modify_selfcreation { Line 19219  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 17371  sub modify_selfcreation { Line 19305  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 17389  sub modify_selfcreation { Line 19323  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 17493  sub modify_selfcreation { Line 19427  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 17811  sub modify_defaults { Line 19745  sub modify_defaults {
             }              }
         } elsif ($item eq 'portal_def') {          } elsif ($item eq 'portal_def') {
             if ($newvalues{$item} ne '') {              if ($newvalues{$item} ne '') {
                 unless ($newvalues{$item} =~ /^https?\:\/\/(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])\/?$/) {                  if ($newvalues{$item} =~ /^https?\:\/\/(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])\/?$/) {
                       foreach my $field ('email','web') {
                           if ($env{'form.'.$item.'_'.$field}) {
                               $newvalues{$item.'_'.$field} = $env{'form.'.$item.'_'.$field};
                           }
                       }
                   } else {
                     push(@errors,$item);                      push(@errors,$item);
                 }                  }
             }              }
         }          }
         if (grep(/^\Q$item\E$/,@errors)) {          if (grep(/^\Q$item\E$/,@errors)) {
             $newvalues{$item} = $domdefaults{$item};              $newvalues{$item} = $domdefaults{$item};
               if ($item eq 'portal_def') {
                   if ($domdefaults{$item}) {
                       foreach my $field ('email','web') {
                           if (exists($domdefaults{$item.'_'.$field})) {
                               $newvalues{$item.'_'.$field} = $domdefaults{$item.'_'.$field};
                           }
                       }
                   }
               }
         } elsif ($domdefaults{$item} ne $newvalues{$item}) {          } elsif ($domdefaults{$item} ne $newvalues{$item}) {
             $changes{$item} = 1;              $changes{$item} = 1;
         }          }
           if ($item eq 'portal_def') {
               unless (grep(/^\Q$item\E$/,@errors)) {
                   if ($newvalues{$item} eq '') {
                       foreach my $field ('email','web') {
                           if (exists($domdefaults{$item.'_'.$field})) {
                               delete($domdefaults{$item.'_'.$field});
                           }
                       }
                   } else {
                       unless ($changes{$item}) {
                           foreach my $field ('email','web') {
                               if ($domdefaults{$item.'_'.$field} ne $newvalues{$item.'_'.$field}) {
                                   $changes{$item} = 1;
                                   last;
                               }
                           }
                       }
                       foreach my $field ('email','web') {
                           if ($newvalues{$item.'_'.$field}) {
                               $domdefaults{$item.'_'.$field} = $newvalues{$item.'_'.$field};
                           } elsif (exists($domdefaults{$item.'_'.$field})) {
                               delete($domdefaults{$item.'_'.$field});
                           }
                       }
                   }
               }
           }
         $domdefaults{$item} = $newvalues{$item};          $domdefaults{$item} = $newvalues{$item};
     }      }
     my %staticdefaults = (      my %staticdefaults = (
Line 17835  sub modify_defaults { Line 19811  sub modify_defaults {
             $newvalues{$item} = $staticdefaults{$item};              $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 17946  sub modify_defaults { Line 19957  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};
                     if ($value eq '') {                      if ($value eq '') {
Line 17965  sub modify_defaults { Line 19996  sub modify_defaults {
                         $value = $authnames{$shortauth{$value}};                          $value = $authnames{$shortauth{$value}};
                     }                      }
                     $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$item},$value).'</li>';                      $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$item},$value).'</li>';
                     $mailmsgtext .= "$title->{$item} set to $value\n";                        $mailmsgtext .= "$title->{$item} set to $value\n";
                       if ($item eq 'portal_def') {
                           if ($env{'form.'.$item} ne '') {
                               foreach my $field ('email','web') {
                                   $value = $env{'form.'.$item.'_'.$field};
                                   if ($value) {
                                       $value = &mt('Yes');
                                   } else {
                                       $value = &mt('No');
                                   }
                                   $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$field},$value).'</li>';
                               }
                           }
                       }
                 }                  }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
Line 18020  sub modify_scantron { Line 20064  sub modify_scantron {
                 $error = &mt("Upload of bubblesheet format file is not permitted to this server: [_1]",$switchserver);                  $error = &mt("Upload of bubblesheet format file is not permitted to this server: [_1]",$switchserver);
             } else {              } else {
                 if ($author_ok eq 'ok') {                  if ($author_ok eq 'ok') {
                       my $modified = [];
                     my ($result,$scantronurl) =                      my ($result,$scantronurl) =
                         &publishlogo($r,'upload','scantronformat',$dom,                          &Apache::lonconfigsettings::publishlogo($r,'upload','scantronformat',$dom,
                                      $confname,'scantron','','',$custom);                                                                  $confname,'scantron','','',$custom,
                                                                   $modified);
                     if ($result eq 'ok') {                      if ($result eq 'ok') {
                         $confhash{'scantron'}{'scantronformat'} = $scantronurl;                          $confhash{'scantron'}{'scantronformat'} = $scantronurl;
                         $changes{'scantronformat'} = 1;                          $changes{'scantronformat'} = 1;
                           &update_modify_urls($r,$modified);
                     } else {                      } else {
                         $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$custom,$result);                          $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$custom,$result);
                     }                      }
Line 18938  sub modify_coursedefaults { Line 20985  sub modify_coursedefaults {
     my %defaultchecked = (      my %defaultchecked = (
                            'canuse_pdfforms' => 'off',                             'canuse_pdfforms' => 'off',
                            'uselcmath'       => 'on',                             'uselcmath'       => 'on',
                            'usejsme'         => 'on'                             'usejsme'         => 'on',
                              'inline_chem'     => 'on',
                              'ltiauth'         => 'off',
                          );                           );
     my @toggles = ('canuse_pdfforms','uselcmath','usejsme');      my @toggles = ('canuse_pdfforms','uselcmath','usejsme','inline_chem','ltiauth');
     my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial',      my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial',
                    'uploadquota_community','uploadquota_textbook','uploadquota_placement',                     'uploadquota_community','uploadquota_textbook','uploadquota_placement',
                    'mysqltables_official','mysqltables_unofficial','mysqltables_community',                     'coursequota_official','coursequota_unofficial','coursequota_community',
                    'mysqltables_textbook','mysqltables_placement');                     'coursequota_textbook','coursequota_placement','mysqltables_official',
                      'mysqltables_unofficial','mysqltables_community','mysqltables_textbook',
                      'mysqltables_placement');
     my @types = ('official','unofficial','community','textbook','placement');      my @types = ('official','unofficial','community','textbook','placement');
     my %staticdefaults = (      my %staticdefaults = (
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
                              coursequota          => 20,
                            postsubmit           => 60,                             postsubmit           => 60,
                            mysqltables          => 172800,                             mysqltables          => 172800,
                              domexttool           => 1,
                          );                           );
     my %texoptions = (      my %texoptions = (
                         MathJax  => 'MathJax',                          MathJax  => 'MathJax',
Line 18995  sub modify_coursedefaults { Line 21048  sub modify_coursedefaults {
                 }                  }
                 $defaultshash{'coursedefaults'}{$item} = $newdef;                  $defaultshash{'coursedefaults'}{$item} = $newdef;
             } else {              } else {
                 my ($setting,$type) = ($item =~ /^(uploadquota|mysqltables)_(\w+)$/);                  my ($setting,$type) = ($item =~ /^(uploadquota|coursequota|mysqltables)_(\w+)$/);
                 if (ref($domconfig{'coursedefaults'}{$setting}) eq 'HASH') {                  if (ref($domconfig{'coursedefaults'}{$setting}) eq 'HASH') {
                     $currdef = $domconfig{'coursedefaults'}{$setting}{$type};                      $currdef = $domconfig{'coursedefaults'}{$setting}{$type};
                 }                  }
Line 19007  sub modify_coursedefaults { Line 21060  sub modify_coursedefaults {
                     unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) {                      unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) {
                         $changes{$item} = 1;                          $changes{$item} = 1;
                     }                      }
                 } elsif ($item =~ /^(uploadquota|mysqltables)_/) {                  } elsif ($item =~ /^(uploadquota|coursequota|mysqltables)_/) {
                     my $setting = $1;                      my $setting = $1;
                     unless (($currdef eq '') && ($newdef == $staticdefaults{$setting})) {                      unless (($currdef eq '') && ($newdef == $staticdefaults{$setting})) {
                         $changes{$setting} = 1;                          $changes{$setting} = 1;
Line 19142  sub modify_coursedefaults { Line 21195  sub modify_coursedefaults {
                 $changes{'postsubmit'} = 1;                  $changes{'postsubmit'} = 1;
             }              }
         }          }
           my (%newdomexttool,%newexttool,%olddomexttool,%oldexttool);
           map { $newdomexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.domexttool');
           map { $newexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.exttool');
           if (ref($domconfig{'coursedefaults'}{'domexttool'}) eq 'HASH') {
               %olddomexttool = %{$domconfig{'coursedefaults'}{'domexttool'}};
           } else {
              foreach my $type (@types) {
                  if ($staticdefaults{'domexttool'}) {
                      $olddomexttool{$type} = 1;
                  } else {
                      $olddomexttool{$type} = 0;
                  }
               }
           }
           if (ref($domconfig{'coursedefaults'}{'exttool'}) eq 'HASH') {
               %oldexttool = %{$domconfig{'coursedefaults'}{'exttool'}};
           } else {
               foreach my $type (@types) {
                  if ($staticdefaults{'exttool'}) {
                      $oldexttool{$type} = 1;
                  } else {
                      $oldexttool{$type} = 0;
                  }
               }
           }
           foreach my $type (@types) {
               unless ($newdomexttool{$type}) {
                   $newdomexttool{$type} = 0;
               }
               unless ($newexttool{$type}) {
                   $newexttool{$type} = 0;
               }
               if ($newdomexttool{$type} != $olddomexttool{$type}) {
                   $changes{'domexttool'} = 1;
               }
               if ($newexttool{$type} != $oldexttool{$type}) {
                   $changes{'exttool'} = 1;
               }
           }
           $defaultshash{'coursedefaults'}{'domexttool'} = \%newdomexttool;
           $defaultshash{'coursedefaults'}{'exttool'} = \%newexttool;
     }      }
     my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,      my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                              $dom);                                               $dom);
Line 19150  sub modify_coursedefaults { Line 21244  sub modify_coursedefaults {
             my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);              my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
             if (($changes{'canuse_pdfforms'}) || ($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'}) ||
                 foreach my $item ('canuse_pdfforms','uselcmath','usejsme','texengine') {                  ($changes{'inline_chem'}) || ($changes{'ltiauth'}) || ($changes{'domexttool'}) ||
                   ($changes{'exttool'}) || ($changes{'coursequota'})) {
                   foreach my $item ('canuse_pdfforms','uselcmath','usejsme','inline_chem','texengine',
                                     'ltiauth') {
                     if ($changes{$item}) {                      if ($changes{$item}) {
                         $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};                          $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};
                     }                      }
Line 19182  sub modify_coursedefaults { Line 21279  sub modify_coursedefaults {
                         }                          }
                     }                      }
                 }                  }
                   if ($changes{'coursequota'}) {
                       if (ref($defaultshash{'coursedefaults'}{'coursequota'}) eq 'HASH') {
                           foreach my $type (@types) {
                               $domdefaults{$type.'coursequota'}=$defaultshash{'coursedefaults'}{'coursequota'}{$type};
                           }
                       }
                   }
                 if ($changes{'canclone'}) {                  if ($changes{'canclone'}) {
                     if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') {                      if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') {
                         if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {                          if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {
Line 19194  sub modify_coursedefaults { Line 21298  sub modify_coursedefaults {
                         $domdefaults{'canclone'}=$defaultshash{'coursedefaults'}{'canclone'};                          $domdefaults{'canclone'}=$defaultshash{'coursedefaults'}{'canclone'};
                     }                      }
                 }                  }
                   if ($changes{'domexttool'}) {
                       if (ref($defaultshash{'coursedefaults'}{'domexttool'}) eq 'HASH') {
                           foreach my $type (@types) {
                               $domdefaults{$type.'domexttool'}=$defaultshash{'coursedefaults'}{'domexttool'}{$type};
                           }
                       }
                   }
                   if ($changes{'exttool'}) {
                       if (ref($defaultshash{'coursedefaults'}{'exttool'}) eq 'HASH') {
                           foreach my $type (@types) {
                               $domdefaults{$type.'exttool'}=$defaultshash{'coursedefaults'}{'exttool'}{$type};
                           }
                       }
                   }
                 my $cachetime = 24*60*60;                  my $cachetime = 24*60*60;
                 &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);                  &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
                 if (ref($lastactref) eq 'HASH') {                  if (ref($lastactref) eq 'HASH') {
Line 19220  sub modify_coursedefaults { Line 21338  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 19240  sub modify_coursedefaults { Line 21364  sub modify_coursedefaults {
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('Default quota for content uploaded via Course Editor remains default: [_1] MB',$staticdefaults{'uploadquota'}).'</li>';                          $resulttext .= '<li>'.&mt('Default quota for content uploaded via Course Editor remains default: [_1] MB',$staticdefaults{'uploadquota'}).'</li>';
                     }                      }
                   } elsif ($item eq 'coursequota') {
                       if (ref($defaultshash{'coursedefaults'}{'coursequota'}) eq 'HASH') {
                           $resulttext .= '<li>'.&mt('Default cumulative quota for all group portfolio spaces in course set as follows:').'<ul>'.
                                          '<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'official'}.'</b>').'</li>'.
                                          '<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'unofficial'}.'</b>').'</li>'.
                                          '<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'textbook'}.'</b>').'</li>'.
                                          '<li>'.&mt('Placement tests: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'placement'}.'</b>').'</li>'.
                                          '<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'community'}.'</b>').'</li>'.
                                          '</ul>'.
                                          '</li>';
                       } else {
                           $resulttext .= '<li>'.&mt('Default cumulative quota for all group portfolio spaces in course remains default: [_1] MB',$staticdefaults{'coursequota'}).'</li>';
                       }
                 } elsif ($item eq 'mysqltables') {                  } elsif ($item eq 'mysqltables') {
                     if (ref($defaultshash{'coursedefaults'}{'mysqltables'}) eq 'HASH') {                      if (ref($defaultshash{'coursedefaults'}{'mysqltables'}) eq 'HASH') {
                         $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver').'<ul>'.                          $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver').'<ul>'.
Line 19319  sub modify_coursedefaults { Line 21456  sub modify_coursedefaults {
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('By default, only course owner and coordinators may clone a course.').'</li>';                          $resulttext .= '<li>'.&mt('By default, only course owner and coordinators may clone a course.').'</li>';
                     }                      }
                   } elsif ($item eq 'ltiauth') {
                       if ($env{'form.'.$item} eq '1') {
                           $resulttext .= '<li>'.&mt('LTI launch of deep-linked URL need not require re-authentication').'</li>';
                       } else {
                           $resulttext .= '<li>'.&mt('LTI launch of deep-linked URL will require re-authentication').'</li>';
                       }
                   } elsif ($item eq 'domexttool') {
                       my @noyes = (&mt('no'),&mt('yes'));
                       if (ref($defaultshash{'coursedefaults'}{'domexttool'}) eq 'HASH') {
                           $resulttext .= '<li>'.&mt('External Tools defined in the domain may be used as follows:').'<ul>'.
                                          '<li>'.&mt('Official courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'official'}].'</b>').'</li>'.
                                          '<li>'.&mt('Unofficial courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'unofficial'}].'</b>').'</li>'.
                                          '<li>'.&mt('Textbook courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'textbook'}].'</b>').'</li>'.
                                          '<li>'.&mt('Placement tests: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'placement'}].'</b>').'</li>'.
                                          '<li>'.&mt('Communities: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'community'}].'</b>').'</li>'.
                                          '</ul>'.
                                          '</li>';
                       } else {
                           $resulttext .= '<li>'.&mt('External Tools defined in the domain may be used in all course types, by default').'</li>';
                       }
                   } elsif ($item eq 'exttool') {
                       my @noyes = (&mt('no'),&mt('yes'));
                       if (ref($defaultshash{'coursedefaults'}{'exttool'}) eq 'HASH') {
                           $resulttext .= '<li>'.&mt('External Tools can be defined and configured in course containers as follows:').'<ul>'.
                                          '<li>'.&mt('Official courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'official'}].'</b>').'</li>'.
                                          '<li>'.&mt('Unofficial courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'unofficial'}].'</b>').'</li>'.
                                          '<li>'.&mt('Textbook courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'textbook'}].'</b>').'</li>'.
                                          '<li>'.&mt('Placement tests: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'placement'}].'</b>').'</li>'.
                                          '<li>'.&mt('Communities: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'community'}].'</b>').'</li>'.
                                          '</ul>'.
                                          '</li>';
                       } else {
                           $resulttext .= '<li>'.&mt('External Tools can not be defined in any course types, by default').'</li>';
                       }
                 }                  }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
Line 19574  sub modify_selfenrollment { Line 21745  sub modify_selfenrollment {
 sub modify_wafproxy {  sub modify_wafproxy {
     my ($dom,$action,$lastactref,%domconfig) = @_;      my ($dom,$action,$lastactref,%domconfig) = @_;
     my %servers = &Apache::lonnet::internet_dom_servers($dom);      my %servers = &Apache::lonnet::internet_dom_servers($dom);
     my (%othercontrol,%canset,%values,%curralias,%currvalue,@warnings,%wafproxy,      my (%othercontrol,%canset,%values,%curralias,%currsaml,%currvalue,@warnings,
         %changes,%expirecache);          %wafproxy,%changes,%expirecache,%expiresaml);
     foreach my $server (sort(keys(%servers))) {      foreach my $server (sort(keys(%servers))) {
         my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});          my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});
         if ($serverhome eq $server) {          if ($serverhome eq $server) {
             my $serverdom = &Apache::lonnet::host_domain($server);              my $serverdom = &Apache::lonnet::host_domain($server);
             if ($serverdom eq $dom) {              if ($serverdom eq $dom) {
                 $canset{$server} = 1;                  $canset{$server} = 1;
                 if (ref($domconfig{'wafproxy'}) eq 'HASH') {  
                     %{$values{$dom}} = ();  
                     if (ref($domconfig{'wafproxy'}{'alias'}) eq 'HASH') {  
                         %curralias = %{$domconfig{'wafproxy'}{'alias'}};  
                     }  
                     foreach my $item ('ipheader','trusted','exempt') {  
                         $currvalue{$item} = $domconfig{'wafproxy'}{$item};  
                     }  
                 }  
             }              }
         }          }
     }      }
       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;      my $output;
     if (keys(%canset)) {      if (keys(%canset)) {
         %{$wafproxy{'alias'}} = ();          %{$wafproxy{'alias'}} = ();
           %{$wafproxy{'saml'}} = ();
         foreach my $key (sort(keys(%canset))) {          foreach my $key (sort(keys(%canset))) {
             $wafproxy{'alias'}{$key} = $env{'form.wafproxy_alias_'.$key};              if ($env{'form.wafproxy_'.$dom}) {
             $wafproxy{'alias'}{$key} =~ s/^\s+|\s+$//g;                  $wafproxy{'alias'}{$key} = $env{'form.wafproxy_alias_'.$key};
             if ($wafproxy{'alias'}{$key} ne $curralias{$key}) {                  $wafproxy{'alias'}{$key} =~ s/^\s+|\s+$//g;
                 $changes{'alias'} = 1;                  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 ($wafproxy{'alias'}{$key} eq '') {
                 if ($curralias{$key}) {                  if ($curralias{$key}) {
Line 19609  sub modify_wafproxy { Line 21801  sub modify_wafproxy {
                 }                  }
                 delete($wafproxy{'alias'}{$key});                  delete($wafproxy{'alias'}{$key});
             }              }
               if ($wafproxy{'saml'}{$key} eq '') {
                   if ($currsaml{$key}) {
                       $expiresaml{$key} = 1;
                   }
                   delete($wafproxy{'saml'}{$key});
               }
         }          }
         unless (keys(%{$wafproxy{'alias'}})) {          unless (keys(%{$wafproxy{'alias'}})) {
             delete($wafproxy{'alias'});              delete($wafproxy{'alias'});
         }          }
         # Localization for values in %warn occus in &mt() calls separately.          unless (keys(%{$wafproxy{'saml'}})) {
               delete($wafproxy{'saml'});
           }
           # Localization for values in %warn occurs in &mt() calls separately.
         my %warn = (          my %warn = (
                      trusted => 'trusted IP range(s)',                       trusted => 'trusted IP range(s)',
                      exempt => 'exempt IP range(s)',                        vpnint => 'internal IP range(s) for VPN sessions(s)',
                        vpnext => 'IP range(s) for backend WAF connections',
                    );                     );
         foreach my $item ('ipheader','trusted','exempt') {          foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext','sslopt') {
             my $possible = $env{'form.wafproxy_'.$item};              my $possible = $env{'form.wafproxy_'.$item};
             $possible =~ s/^\s+|\s+$//g;              $possible =~ s/^\s+|\s+$//g;
             if ($possible ne '') {              if ($possible ne '') {
                 if ($item eq 'ipheader') {                  if ($item eq 'remoteip') {
                     $wafproxy{$item} = $possible;                      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 {                  } else {
                     my (@ok,$count);                      my (@ok,$count);
                     $possible =~ s/[\r\n]+/\s/g;                      if (($item eq 'vpnint') || ($item eq 'vpnext')) {
                     $possible =~ s/\s*-\s*/-/g;                          unless ($env{'form.wafproxy_vpnaccess'}) {
                     $possible =~ s/\s+/,/g;                              $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;                      $count = 0;
                     if ($possible) {                      if ($possible ne '') {
                         foreach my $poss (split(/\,/,$possible)) {                          foreach my $poss (split(/\,/,$possible)) {
                             $count ++;                              $count ++;
                             if (&validate_ip_pattern($poss)) {                              $poss = &validate_ip_pattern($poss);
                               if ($poss ne '') {
                                 push(@ok,$poss);                                  push(@ok,$poss);
                             }                              }
                         }                          }
                         if (@ok) {  
                             $wafproxy{$item} = join(',',@ok);  
                         }  
                         my $diff = $count - scalar(@ok);                          my $diff = $count - scalar(@ok);
                         if ($diff) {                          if ($diff) {
                             push(@warnings,'<li>'.                              push(@warnings,'<li>'.
Line 19647  sub modify_wafproxy { Line 21869  sub modify_wafproxy {
                                      $diff,$warn{$item}).                                       $diff,$warn{$item}).
                                  '</li>');                                   '</li>');
                         }                          }
                         if ($wafproxy{$item} ne $currvalue{$item}) {                          if (@ok) {
                             $changes{$item} = 1;                               my @cidr_list;
                               foreach my $item (@ok) {
                                   @cidr_list = &Net::CIDR::cidradd($item,@cidr_list);
                               }
                               $wafproxy{$item} = join(',',@cidr_list);
                         }                          }
                     }                      }
                 }                  }
             } else {                  if ($wafproxy{$item} ne $currvalue{$item}) {
                 if ($currvalue{$item}) {  
                     $changes{$item} = 1;                      $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)) {      if (keys(%changes)) {
         my %defaultshash = (          my %defaultshash = (
                               wafproxy => \%wafproxy,                                wafproxy => \%wafproxy,
                            );                              );
         my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,          my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                                  $dom);                                                   $dom);
         if ($putresult eq 'ok') {          if ($putresult eq 'ok') {
             my $cachetime = 24*60*60;              my $cachetime = 24*60*60;
             my (%domdefaults,$updatedomdefs);              my (%domdefaults,$updatedomdefs);
             foreach my $item ('ipheader','trusted','exempt') {              foreach my $item ('ipheader','trusted','vpnint','vpnext','sslopt') {
                 if ($changes{$item}) {                  if ($changes{$item}) {
                     unless ($updatedomdefs) {                      unless ($updatedomdefs) {
                         %domdefaults = &Apache::lonnet::get_domain_defaults($dom);                          %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
Line 19678  sub modify_wafproxy { Line 21917  sub modify_wafproxy {
                         $domdefaults{'waf_'.$item} = $wafproxy{$item};                          $domdefaults{'waf_'.$item} = $wafproxy{$item};
                     } elsif (exists($domdefaults{'waf_'.$item})) {                      } elsif (exists($domdefaults{'waf_'.$item})) {
                         delete($domdefaults{'waf_'.$item});                          delete($domdefaults{'waf_'.$item});
                     }                       }
                 }                  }
             }              }
             if ($updatedomdefs) {              if ($updatedomdefs) {
Line 19704  sub modify_wafproxy { Line 21943  sub modify_wafproxy {
                     $lastactref->{'proxyalias'} = \%updates;                      $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>';              $output = &mt('Changes were made to Web Application Firewall/Reverse Proxy').'<ul>';
             foreach my $item ('alias','ipheader','trusted','exempt') {              foreach my $item ('alias','saml','remoteip','ipheader','trusted','vpnint','vpnext','sslopt') {
                 if ($changes{$item}) {                  if ($changes{$item}) {
                     if ($item eq 'alias') {                      if ($item eq 'alias') {
                         my $numaliased = 0;                          my $numaliased = 0;
Line 19727  sub modify_wafproxy { Line 21983  sub modify_wafproxy {
                         unless ($numaliased) {                          unless ($numaliased) {
                             $output .= '<li>'.&mt('Aliases deleted for hostnames').'</li>';                              $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 {                      } else {
                         if ($item eq 'ipheader') {                          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}) {                              if ($wafproxy{$item}) {
                                 $output .= '<li>'.&mt('Custom request header set to [_1]',                                  $output .= '<li>'.&mt('Request header with remote IP set to: [_1]',
                                                       $wafproxy{$item}).'</li>';                                                        $wafproxy{$item}).'</li>';
                             } else {                              } else {
                                 $output .= '<li>'.&mt('Custom request header deleted').'</li>';                                  $output .= '<li>'.&mt('Request header with remote IP deleted').'</li>';
                             }                              }
                         } elsif ($item eq 'trusted') {                          } elsif ($item eq 'trusted') {
                             if ($wafproxy{$item}) {                              if ($wafproxy{$item}) {
                                 $output .= '<li>'.&mt('Trusted IP range(s) set to [_1]',                                  $output .= '<li>'.&mt('Trusted IP range(s) set to: [_1]',
                                                       $wafproxy{$item}).'</li>';                                                        $wafproxy{$item}).'</li>';
                             } else {                              } else {
                                 $output .= '<li>'.&mt('Trusted IP range(s) deleted').'</li>';                                  $output .= '<li>'.&mt('Trusted IP range(s) deleted').'</li>';
                             }                              }
                         } elsif ($item eq 'exempt') {                          } elsif ($item eq 'vpnint') {
                             if ($wafproxy{$item}) {                              if ($wafproxy{$item}) {
                                 $output .= '<li>'.&mt('Exempt IP range(s) set to [_1]',                                  $output .= '<li>'.&mt('Internal IP Range(s) for VPN sessions set to: [_1]',
                                                        $wafproxy{$item}).'</li>';                                                         $wafproxy{$item}).'</li>';
                             } else {                              } else {
                                 $output .= '<li>'.&mt('Exempt IP range(s) deleted').'</li>';                                  $output .= '<li>'.&mt('Internal IP Range(s) for VPN sessions deleted').'</li>';
                               }
                           } elsif ($item eq 'vpnext') {
                               if ($wafproxy{$item}) {
                                   $output .= '<li>'.&mt('IP Range(s) for backend WAF connections set to: [_1]',
                                                          $wafproxy{$item}).'</li>';
                               } else {
                                   $output .= '<li>'.&mt('IP Range(s) for backend WAF connections deleted').'</li>';
                               }
                           } elsif ($item eq 'sslopt') {
                               if ($wafproxy{$item}) {
                                   $output .= '<li>'.&mt('WAF/Reverse Proxy expected to forward requests to https on LON-CAPA node, regardless of original protocol in web browser (http or https).').'</li>';
                               } else {
                                   $output .= '<li>'.&mt('WAF/Reverse Proxy expected to preserve original protocol in web browser (either http or https) when forwarding to LON-CAPA node.').'</li>';
                             }                              }
                         }                          }
                     }                      }
                 }                  }
             }              }
               $output .= '</ul>';
         } else {          } else {
             $output = '<span class="LC_error">'.              $output = '<span class="LC_error">'.
                       &mt('An error occurred: [_1]',$putresult).'</span>';                        &mt('An error occurred: [_1]',$putresult).'</span>';
Line 19772  sub validate_ip_pattern { Line 22068  sub validate_ip_pattern {
     if ($pattern =~ /^([^-]+)\-([^-]+)$/) {      if ($pattern =~ /^([^-]+)\-([^-]+)$/) {
         my ($start,$end) = ($1,$2);          my ($start,$end) = ($1,$2);
         if ((&Net::CIDR::cidrvalidate($start)) && (&Net::CIDR::cidrvalidate($end))) {          if ((&Net::CIDR::cidrvalidate($start)) && (&Net::CIDR::cidrvalidate($end))) {
             return 1;              if (($start !~ m{/}) && ($end !~ m{/})) {
                   return $start.'-'.$end;
               }
           }
       } elsif ($pattern ne '') {
           $pattern = &Net::CIDR::cidrvalidate($pattern);
           if ($pattern ne '') {
               return $pattern;
         }          }
     } elsif (&Net::CIDR::cidrvalidate($pattern)) {  
         return 1;  
     }      }
     return      return;
 }  }
   
 sub modify_usersessions {  sub modify_usersessions {
Line 20013  sub modify_usersessions { Line 22314  sub modify_usersessions {
                 if (($offload eq 'offloadoth') && (@okoffloadoth)) {                  if (($offload eq 'offloadoth') && (@okoffloadoth)) {
                     $changes{'offloadoth'} = 1;                      $changes{'offloadoth'} = 1;
                 }                  }
             }               }
         }          }
     } else {      } else {
         if (@okoffload) {          if (@okoffload) {
Line 20430  sub modify_trust { Line 22731  sub modify_trust {
             }              }
             my $cachetime = 24*60*60;              my $cachetime = 24*60*60;
             &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);              &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               &Apache::lonnet::do_cache_new('trust',$dom,$defaultshash{'trust'},3600);
             if (ref($lastactref) eq 'HASH') {              if (ref($lastactref) eq 'HASH') {
                 $lastactref->{'domdefaults'} = 1;                  $lastactref->{'domdefaults'} = 1;
                   $lastactref->{'trust'} = 1;
             }              }
             if (keys(%changes) > 0) {              if (keys(%changes) > 0) {
                 my %lt = &trust_titles();                  my %lt = &trust_titles();
Line 20549  sub modify_loadbalancing { Line 22852  sub modify_loadbalancing {
         }          }
         if ($env{'form.loadbalancing_cookie_'.$i}) {          if ($env{'form.loadbalancing_cookie_'.$i}) {
             $defaultshash{'loadbalancing'}{$balancer}{'cookie'} = 1;              $defaultshash{'loadbalancing'}{$balancer}{'cookie'} = 1;
             if (exists($currbalancer{$balancer})) {               if (exists($currbalancer{$balancer})) {
                 unless ($currcookies{$balancer}) {                  unless ($currcookies{$balancer}) {
                     $changes{'curr'}{$balancer}{'cookie'} = 1;                      $changes{'curr'}{$balancer}{'cookie'} = 1;
                 }                  }
Line 20713  sub modify_loadbalancing { Line 23016  sub modify_loadbalancing {
                             }                              }
                         }                          }
                         if ($changes{'curr'}{$balancer}{'cookie'}) {                          if ($changes{'curr'}{$balancer}{'cookie'}) {
                             $resulttext .= '<li>'.&mt('Load Balancer: [_1] -- cookie use enabled',                              if ($currcookies{$balancer}) {
                                                       $balancer).'</li>';                                   $resulttext .= '<li>'.&mt('Load Balancer: [_1] -- cookie use disabled',
                                                             $balancer).'</li>';
                               } else {
                                   $resulttext .= '<li>'.&mt('Load Balancer: [_1] -- cookie use enabled',
                                                             $balancer).'</li>';
                               }
                         }                          }
                     }                      }
                 }                  }
Line 21230  function balancerChange(balnum,baltotal, Line 23538  function balancerChange(balnum,baltotal,
 END  END
 }  }
   
   
 sub new_spares_js {  sub new_spares_js {
     my @sparestypes = ('primary','default');      my @sparestypes = ('primary','default');
     my $types = join("','",@sparestypes);      my $types = join("','",@sparestypes);
Line 21494  sub devalidate_remote_domconfs { Line 23801  sub devalidate_remote_domconfs {
     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','passwdconf','cats','proxyalias');                        'directorysrch','passwdconf','cats','proxyalias','proxysaml',
                         'ipaccess','trust');
       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') {                      if (($name eq 'proxyalias') || ($name eq 'proxysaml')) {
                         if (ref($cachekeys->{$name}) eq 'HASH') {                            if (ref($cachekeys->{$name}) eq 'HASH') {
                             foreach my $key (keys(%{$cachekeys->{$name}})) {                              foreach my $key (keys(%{$cachekeys->{$name}})) {
                                 push(@cached,&escape($name).':'.&escape($key));                                  push(@cached,&escape($name).':'.&escape($key));
                             }                              }
Line 21512  sub devalidate_remote_domconfs { Line 23839  sub devalidate_remote_domconfs {
                     }                      }
                 }                  }
             }              }
               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.378  
changed lines
  Added in v.1.429


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