Diff for /loncom/interface/domainprefs.pm between versions 1.419 and 1.437

version 1.419, 2023/02/14 21:44:15 version 1.437, 2024/03/03 00:08:37
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 178  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 221  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','ltisec','privacy','passwords',                  'ltitools','toolsec','ssl','trust','lti','ltisec',
                 'proctoring','wafproxy','ipaccess'],$dom);                  'privacy','passwords','proctoring','wafproxy',
                   'ipaccess','authordefaults'],$dom);
     my %encconfig =      my %encconfig =
         &Apache::lonnet::get_dom('encconfig',['ltitools','lti','proctoring','linkprot'],$dom,undef,1);          &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 239  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'};
                     }                      }
                 }                  }
             }              }
Line 283  sub handler { Line 305  sub handler {
                        '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 360  sub handler { Line 382  sub handler {
                       modify => \&modify_passwords,                        modify => \&modify_passwords,
                     },                      },
         'quotas' =>           'quotas' => 
                     { text => 'Blogs, personal pages/timezones, webDAV/quotas, portfolio',                      { 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 => 'Portfolio quota (MB)',}],
                       print => \&print_quotas,                        print => \&print_quotas,
                       modify => \&modify_quotas,                        modify => \&modify_quotas,
                     },                      },
Line 546  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 582  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 636  sub handler { Line 662  sub handler {
                   print => \&print_trust,                    print => \&print_trust,
                   modify => \&modify_trust,                    modify => \&modify_trust,
                  },                   },
           'lti' =>          'lti' =>
                  {text => 'LTI Link Protection and LTI Consumers',                   {text => 'LTI Link Protection and LTI Consumers',
                   help => 'Domain_Configuration_LTI_Provider',                    help => 'Domain_Configuration_LTI_Provider',
                   header => [{col1 => 'Encryption of shared secrets',                    header => [{col1 => 'Encryption of shared secrets',
                               col2 => 'Settings'},                                col2 => 'Settings'},
                              {col1 => 'Rules for shared secrets',                                {col1 => 'Rules for shared secrets',
                               col2 => 'Settings'},                                col2 => 'Settings'},
                                {col1 => 'Link Protectors in Courses',
                                 col2 => 'Values'},
                              {col1 => 'Link Protectors',                               {col1 => 'Link Protectors',
                               col2 => 'Settings'},                                col2 => 'Settings'},
                              {col1 => 'Consumers',                               {col1 => 'Consumers',
Line 650  sub handler { Line 678  sub handler {
                   print => \&print_lti,                    print => \&print_lti,
                   modify => \&modify_lti,                    modify => \&modify_lti,
                  },                   },
            'ipaccess' =>          'ipaccess' =>
                        {text => 'IP-based access control',                         {text => 'IP-based access control',
                         help => 'Domain_Configuration_IP_Access',                          help => 'Domain_Configuration_IP_Access',
                         header => [{col1 => 'Setting',                          header => [{col1 => 'Setting',
Line 658  sub handler { Line 686  sub handler {
                         print  => \&print_ipaccess,                          print  => \&print_ipaccess,
                         modify => \&modify_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 856  sub process_changes { Line 894  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') {      } elsif ($action eq 'ipaccess') {
         $output = &modify_ipaccess($dom,$lastactref,%domconfig);          $output = &modify_ipaccess($dom,$lastactref,%domconfig);
       } elsif ($action eq 'authordefaults') {
           $output = &modify_authordefaults($dom,$lastactref,%domconfig);
     }      }
     return $output;      return $output;
 }  }
Line 891  sub print_config_box { Line 931  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 .= &passwords_javascript('secrets')."\n".          $output .= &passwords_javascript('ltisecrets')."\n".
                    &lti_javascript($dom,$settings);                     &lti_javascript($dom,$settings);
     } elsif ($action eq 'proctoring') {      } elsif ($action eq 'proctoring') {
         $output .= &proctoring_javascript($settings);          $output .= &proctoring_javascript($settings);
Line 910  sub print_config_box { Line 950  sub print_config_box {
         $output .= &saml_javascript();          $output .= &saml_javascript();
     } elsif ($action eq 'ipaccess') {      } elsif ($action eq 'ipaccess') {
         $output .= &ipaccess_javascript($settings);          $output .= &ipaccess_javascript($settings);
       } elsif ($action eq 'authordefaults') {
           $output .= &authordefaults_javascript();
     }      }
     $output .=      $output .=
          '<table class="LC_nested_outer">           '<table class="LC_nested_outer">
Line 951  sub print_config_box { Line 993  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 'lti')) {              ($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 987  sub print_config_box { Line 1030  sub print_config_box {
             ($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 'defaults') ||              ($action eq 'trust') || ($action eq 'contacts') || ($action eq 'defaults') ||
             ($action eq 'privacy') || ($action eq 'passwords') || ($action eq 'lti')) {              ($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 995  sub print_config_box { Line 1039  sub print_config_box {
                 $output .= $item->{'print'}->('shared',$dom,$settings,\$rowtotal);                  $output .= $item->{'print'}->('shared',$dom,$settings,\$rowtotal);
             } elsif ($action eq 'passwords') {              } elsif ($action eq 'passwords') {
                 $output .= $item->{'print'}->('middle',$dom,$confname,$settings,\$rowtotal);                  $output .= $item->{'print'}->('middle',$dom,$confname,$settings,\$rowtotal);
               } elsif ($action eq 'lti') {
                   $output .= $item->{'print'}->('upper',$dom,$settings,\$rowtotal).'
                              </table>
                             </td>
                            </tr>
                            <tr>
                             <td>
                             <table class="LC_nested">
                              <tr class="LC_info_row">
                               <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
                               <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td>
                              </tr>'."\n".
                              $item->{'print'}->('middle',$dom,$settings,\$rowtotal);
             } else {              } else {
                 $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);                  $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);
             }              }
Line 1027  sub print_config_box { Line 1084  sub print_config_box {
               <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col2'}).'</td></tr>'.                <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col2'}).'</td></tr>'.
                            $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);                             $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
             } else {              } else {
                   my $hdridx = 2;
                   if ($action eq 'lti') {
                       $hdridx = 3;
                   }
                 $output .= '                  $output .= '
            </table>             </table>
           </td>            </td>
Line 1035  sub print_config_box { Line 1096  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col1'}).'</td>
               <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td>                <td class="LC_right_item">'.&mt($item->{'header'}->[$hdridx]->{'col2'}).'</td>
              </tr>'."\n";               </tr>'."\n";
                 if ($action eq 'coursecategories') {                  if ($action eq 'coursecategories') {
                     $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);                      $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);
Line 1047  sub print_config_box { Line 1108  sub print_config_box {
                     } else {                      } else {
                         $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal);                          $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal);
                     }                      }
                       $hdridx ++;
                     $output .= '                      $output .= '
              </tr>               </tr>
             </table>              </table>
Line 1056  sub print_config_box { Line 1118  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>                <td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col1'}).'</td>
               <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'."\n";                <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col2'}).'</td></tr>'."\n";
                     if ($action eq 'passwords') {                      if ($action eq 'passwords') {
                         $output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal);                          $output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal);
                     } else {                      } else {
Line 1075  sub print_config_box { Line 1137  sub print_config_box {
             $rowtotal ++;              $rowtotal ++;
         } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||          } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||
                  ($action eq 'directorysrch') || ($action eq 'helpsettings') ||                   ($action eq 'directorysrch') || ($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 1278  sub print_config_box { Line 1340  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 'proctoring') ||                   ($action eq 'proctoring') || ($action eq 'ipaccess')) {
                  ($action eq 'ipaccess')) {  
             $output .= $item->{'print'}->($dom,$settings,\$rowtotal);              $output .= $item->{'print'}->($dom,$settings,\$rowtotal);
         }          }
     }      }
Line 2370  sub print_quotas { Line 2431  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 2384  sub print_quotas { Line 2445  sub print_quotas {
         @options = ('norequest','approval','automatic');          @options = ('norequest','approval','automatic');
         %titles = &authorrequest_titles();          %titles = &authorrequest_titles();
     } else {      } else {
         @usertools = ('aboutme','blog','webdav','portfolio','timezone');          @usertools = ('aboutme','blog','portfolio','portaccess','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 2398  sub print_quotas { Line 2459  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 2518  sub print_quotas { Line 2576  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 2533  sub print_quotas { Line 2587  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 2654  sub print_quotas { Line 2704  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 3526  sub lti_toggle_js { Line 3573  sub lti_toggle_js {
     my %servers = &Apache::lonnet::get_servers($dom,'library');      my %servers = &Apache::lonnet::get_servers($dom,'library');
     my $primary = &Apache::lonnet::domain($dom,'primary');      my $primary = &Apache::lonnet::domain($dom,'primary');
     my $course_servers = "'".join("','",keys(%servers))."'";      my $course_servers = "'".join("','",keys(%servers))."'";
   
     return <<"ENDSCRIPT";      return <<"ENDSCRIPT";
 <script type="text/javascript">  <script type="text/javascript">
 // <![CDATA[  // <![CDATA[
Line 3625  function toggleLTI(form,setting,item) { Line 3671  function toggleLTI(form,setting,item) {
                            break;                             break;
                        }                         }
                    }                     }
                }                  }
             }              }
             if (!setvis) {              if (!setvis) {
                 if (document.getElementById(divid)) {                  if (document.getElementById(divid)) {
Line 3702  function toggleLTI(form,setting,item) { Line 3748  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 3730  function toggleLTI(form,setting,item) { Line 3776  function toggleLTI(form,setting,item) {
     return;      return;
 }  }
   
 function toggleLTIEncKey(form) {  
     var shownhosts = new Array();  
     var hiddenhosts = new Array();  
     var forcourse = new Array($course_servers);  
     var fromdomain = '$primary';  
     var crsradio = form.elements['ltisec_crslinkprot'];  
     if (crsradio.length) {  
         for (var i=0; i<crsradio.length; i++) {  
             if (crsradio[i].checked) {  
                 if (crsradio[i].value == 1) {  
                     if (forcourse.length > 0) {  
                         for (var j=0; j<forcourse.length; j++) {  
                             if (!shownhosts.includes(forcourse[j])) {  
                                 shownhosts.push(forcourse[j]);  
                             }  
                         }  
                     }  
                 } else {  
                     if (forcourse.length > 0) {  
                         for (var j=0; j<forcourse.length; j++) {  
                             if (!hiddenhosts.includes(forcourse[j])) {   
                                 hiddenhosts.push(forcourse[j]);  
                             }  
                         }  
                     }   
                 }  
             }  
         }  
     }  
     var domradio = form.elements['ltisec_domlinkprot'];  
     if (domradio.length) {  
         for (var i=0; i<domradio.length; i++) {  
             if (domradio[i].checked) {  
                 if (domradio[i].value == 1) {  
                     if (!shownhosts.includes(fromdomain)) {   
                         shownhosts.push(fromdomain);  
                     }  
                 } else {  
                     if (!hiddenhosts.includes(fromdomain)) {  
                         hiddenhosts.push(fromdomain);  
                     }  
                 }  
             }  
         }  
     }  
     var consumersradio = form.elements['ltisec_consumers'];  
     if (consumersradio.length) {  
         for (var i=0; i<consumersradio.length; i++) {  
             if (consumersradio[i].checked) {  
                 if (consumersradio[i].value == 1) {  
                     if (!shownhosts.includes(fromdomain)) {       
                         shownhosts.push(fromdomain);  
                     }  
                 } else {  
                     if (!hiddenhosts.includes(fromdomain)) {  
                         hiddenhosts.push(fromdomain);  
                     }  
                 }  
             }  
         }  
     }  
     if (shownhosts.length > 0) {  
         for (var i=0; i<shownhosts.length; i++) {  
             if (document.getElementById('ltisec_info_'+shownhosts[i])) {  
                 document.getElementById('ltisec_info_'+shownhosts[i]).style.display = 'block';                   
             }  
         }  
         if (document.getElementById('ltisec_noprivkey')) {  
             document.getElementById('ltisec_noprivkey').style.display = 'none';  
         }  
     } else {  
         if (document.getElementById('ltisec_noprivkey')) {  
             document.getElementById('ltisec_noprivkey').style.display = 'inline-block';  
         }  
     }  
     if (hiddenhosts.length > 0) {  
         for (var i=0; i<hiddenhosts.length; i++) {  
             if (!shownhosts.includes(hiddenhosts[i])) {  
                 if (document.getElementById('ltisec_info_'+hiddenhosts[i])) {  
                     document.getElementById('ltisec_info_'+hiddenhosts[i]).style.display = 'none';  
                 }  
             }  
         }  
     }  
     return;  
 }  
   
 function togglePrivKey(form,hostid) {  
     var radioname = '';  
     var currdivid = '';  
     var newdivid = '';  
     if ((document.getElementById('ltisec_divcurrprivkey_'+hostid)) &&  
         (document.getElementById('ltisec_divchgprivkey_'+hostid))) {  
         currdivid = document.getElementById('ltisec_divcurrprivkey_'+hostid);  
         newdivid = document.getElementById('ltisec_divchgprivkey_'+hostid);  
         radioname = form.elements['ltisec_changeprivkey_'+hostid];  
         if (radioname) {  
             if (radioname.length > 0) {  
                 var setvis;  
                 for (var i=0; i<radioname.length; i++) {  
                     if (radioname[i].checked == true) {  
                         if (radioname[i].value == 1) {  
                             newdivid.style.display = 'inline-block';  
                             currdivid.style.display = 'none';  
                             setvis = 1;  
                         }  
                         break;  
                     }  
                 }  
                 if (!setvis) {  
                     newdivid.style.display = 'none';  
                     currdivid.style.display = 'inline-block';  
                 }  
             }  
         }  
     }  
 }  
   
 // ]]>  // ]]>
 </script>  </script>
   
Line 3928  sub saml_javascript { Line 3856  sub saml_javascript {
     return <<"ENDSCRIPT";      return <<"ENDSCRIPT";
 <script type="text/javascript">  <script type="text/javascript">
 // <![CDATA[  // <![CDATA[
 function toggleSamlOptions(form,hostid) {   function toggleSamlOptions(form,hostid) {
     var radioname = 'saml_'+hostid;      var radioname = 'saml_'+hostid;
     var tablecellon = 'samloptionson_'+hostid;      var tablecellon = 'samloptionson_'+hostid;
     var tablecelloff = 'samloptionsoff_'+hostid;      var tablecelloff = 'samloptionsoff_'+hostid;
     var num = form.elements[radioname].length;      var num = form.elements[radioname].length;
     if (num) {      if (num) {
         var setvis = '';           var setvis = '';
         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') {
                     if (document.getElementById(tablecellon)) {                      if (document.getElementById(tablecellon)) {
                         document.getElementById(tablecellon).style.display='';                          document.getElementById(tablecellon).style.display='';
                     }                      }
Line 4034  $jstext Line 3962  $jstext
 ENDSCRIPT  ENDSCRIPT
 }  }
   
   sub authordefaults_javascript {
       my %alert = &Apache::lonlocal::texthash (
                       reqd => 'Warning: at least one editor needs to be available.',
                       rest => 'Unchecking this editor disallowed while others unchecked.',
       );
       &js_escape(\%alert);
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   
   function checkEditors(form,checkbox,current) {
       if (form.elements[checkbox].length != undefined) {
           var count = 0;
           for (var i=0; i<form.elements[checkbox].length; i++) {
               if (form.elements[checkbox][i].checked) {
                   count ++;
               }
           }
           if (count == 0) {
               if (current.type =='radio') {
                   current.checked = true;
                   alert('$alert{reqd}\\n$alert{rest}');
               }
           }
       }
       return;
   }
   // ]]>
   </script>
   
   ENDSCRIPT
   }
   
 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),
Line 4705  sub print_contacts { Line 4666  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 4787  sub print_contacts { Line 4748  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 4799  sub print_contacts { Line 4760  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 4866  sub overridden_helpdesk { Line 4826  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 4945  function toggleHelpdeskRow(form,checkbox Line 4905  function toggleHelpdeskRow(form,checkbox
     return;      return;
 }  }
   
   
 // ]]>  // ]]>
 </script>  </script>
   
Line 5399  sub radiobutton_prefs { Line 5358  sub radiobutton_prefs {
 }  }
   
 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 5827  sub ltitools_names { Line 5415  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 5845  sub ltitools_names { Line 5433  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 5853  sub ltitools_names { Line 5441  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 6491  sub print_lti { Line 6196  sub print_lti {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my $itemcount = 1;      my $itemcount = 1;
     my ($datatable,$css_class);      my ($datatable,$css_class);
     my (%rules,%encrypt,%privkeys,%linkprot);      my (%rules,%encrypt,%privkeys,%linkprot,%suggestions);
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if ($position eq 'top') {          if ($position eq 'top') {
             if (exists($settings->{'encrypt'})) {              if (exists($settings->{'encrypt'})) {
Line 6514  sub print_lti { Line 6219  sub print_lti {
                     }                      }
                 }                  }
             }              }
         } elsif ($position eq 'middle') {          } elsif ($position eq 'upper') {
             if (exists($settings->{'rules'})) {              if (exists($settings->{'rules'})) {
                 if (ref($settings->{'rules'}) eq 'HASH') {                  if (ref($settings->{'rules'}) eq 'HASH') {
                     %rules = %{$settings->{'rules'}};                      %rules = %{$settings->{'rules'}};
                 }                  }
             }              }
           } elsif ($position eq 'middle') {
               if (exists($settings->{'suggested'})) {
                   if (ref($settings->{'suggested'}) eq 'HASH') {
                       %suggestions = %{$settings->{'suggested'}};
                   }
               }
         } elsif ($position eq 'lower') {          } elsif ($position eq 'lower') {
             if (exists($settings->{'linkprot'})) {              if (exists($settings->{'linkprot'})) {
                 if (ref($settings->{'linkprot'}) eq 'HASH') {                  if (ref($settings->{'linkprot'}) eq 'HASH') {
Line 6530  sub print_lti { Line 6241  sub print_lti {
                 }                  }
             }              }
         } else {          } else {
             foreach my $key ('encrypt','private','rules','linkprot') {              foreach my $key ('encrypt','private','rules','linkprot','suggestions') {
                 if (exists($settings->{$key})) {                  if (exists($settings->{$key})) {
                     delete($settings->{$key});                      delete($settings->{$key});
                 }                  }
Line 6538  sub print_lti { Line 6249  sub print_lti {
         }          }
     }      }
     if ($position eq 'top') {      if ($position eq 'top') {
         my @ids=&Apache::lonnet::current_machine_ids();          $datatable = &secrets_form($dom,'ltisec',\%encrypt,\%privkeys,$rowtotal);
         my %servers = &Apache::lonnet::get_servers($dom,'library');      } elsif ($position eq 'upper') {
         my $primary = &Apache::lonnet::domain($dom,'primary');          $datatable = &password_rules('ltisecrets',\$itemcount,\%rules);
         my ($extra,$numshown);  
         foreach my $hostid (sort(keys(%servers))) {  
             my ($showextra,$divsty,$switch);  
             if ($hostid eq $primary) {  
                 if (($encrypt{'ltisec_consumers'}) || ($encrypt{'ltisec_domlinkprot'})) {  
                     $showextra = 1;  
                 }  
             }  
             if ($encrypt{'ltisec_crslinkprot'}) {  
                 $showextra = 1;  
             }  
             unless (grep(/^\Q$hostid\E$/,@ids)) {  
                 $switch = 1;  
             }  
             if ($showextra) {  
                 $numshown ++;  
                 $divsty = 'display:inline-block';   
             } else {  
                 $divsty = 'display:none';  
             }   
             $extra .= '<fieldset id="ltisec_info_'.$hostid.'" style="'.$divsty.'">'.  
                       '<legend>'.$hostid.'</legend>';  
             if ($switch) {  
                 my $switchserver = '<a href="/adm/switchserver?otherserver='.$hostid.'&amp;role='.  
                                    &HTML::Entities::encode($env{'request.role'},'\'<>"&').  
                                    '&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';  
                 if (exists($privkeys{$hostid})) {  
                     $extra .= '<div id="ltisec_divcurrprivkey_'.$hostid.'" style="display:inline-block" />'.  
                               '<span class="LC_nobreak">'.  
                               &mt('Encryption Key').': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.  
                               '<span class="LC_nobreak">'.&mt('Change?').  
                               '<label><input type="radio" value="0" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" checked="checked" />'.&mt('No').'</label>'.  
                               ('&nbsp;'x2).  
                               '<label><input type="radio" value="1" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" />'.&mt('Yes').  
                               '</label>&nbsp;&nbsp;</span><div id="ltisec_divchgprivkey_'.$hostid.'" style="display:none" />'.  
                               '<span class="LC_nobreak"> - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver).  
                               '</span></div>';  
                 } else {  
                     $extra .= '<span class="LC_nobreak">'.  
                               &mt('Key required').' - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver).  
                               '</span>'."\n";  
                 }  
             } elsif (exists($privkeys{$hostid})) {  
                 $extra .= '<div id="ltisec_divcurrprivkey_'.$hostid.'" style="display:inline-block" /><span class="LC_nobreak">'.  
                           &mt('Encryption Key').': ['.&mt('not shown').'] '.('&nbsp;'x2).'</span></div>'.  
                           '<span class="LC_nobreak">'.&mt('Change?').  
                           '<label><input type="radio" value="0" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" checked="checked" />'.&mt('No').'</label>'.  
                           ('&nbsp;'x2).  
                           '<label><input type="radio" value="1" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" />'.&mt('Yes').  
                           '</label>&nbsp;&nbsp;</span><div id="ltisec_divchgprivkey_'.$hostid.'" style="display:none" />'.  
                           '<span class="LC_nobreak">'.&mt('New Key').':'.  
                           '<input type="password" size="20" name="ltisec_privkey_'.$hostid.'" value="" autocomplete="new-password" />'.  
                           '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltisec_privkey_'.$hostid.'.type='."'text'".' } else { this.form.ltisec_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.  
                           '</span></div>';  
             } else {  
                 $extra .= '<span class="LC_nobreak">'.&mt('Encryption Key').':'.  
                           '<input type="password" size="20" name="ltisec_privkey_'.$hostid.'" value="" autocomplete="new-password" />'.  
                           '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltisec_privkey_'.$hostid.'.type='."'text'".' } else { this.form.ltisec_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>';  
             }  
             $extra .= '</fieldset>';  
         }  
         my %choices = &Apache::lonlocal::texthash (  
                                                       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',  
                                                   );  
         my @toggles = qw(ltisec_crslinkprot ltisec_domlinkprot ltisec_consumers);  
         my %defaultchecked = (  
                                'ltisec_crslinkprot' => 'off',  
                                'ltisec_domlinkprot' => 'off',  
                                'ltisec_consumers'   => 'off',  
                              );  
         my ($onclick,$itemcount);  
         $onclick = 'javascript:toggleLTIEncKey(this.form);';  
         ($datatable,$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';   
         }  
         $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.&mt('Encryption Key(s)').'</td>'.  
                       '<td><div id="ltisec_noprivkey" style="'.$noprivkeysty.'" >'.  
                       '<span class="LC_nobreak">'.&mt('Not in use').'</span></div>'.  
                       $extra.  
                       '</td></tr>';  
         $itemcount ++;                  
         $$rowtotal += $itemcount;          $$rowtotal += $itemcount;
     } elsif ($position eq 'middle') {      } elsif ($position eq 'middle') {
         $datatable = &password_rules('secrets',\$itemcount,\%rules);          $datatable = &linkprot_suggestions(\%suggestions,\$itemcount);
         $$rowtotal += $itemcount;          $$rowtotal += $itemcount;
     } elsif ($position eq 'lower') {      } elsif ($position eq 'lower') {
          $datatable .= &Apache::courseprefs::print_linkprotection($dom,'',$settings,$rowtotal,'','','domain');          $datatable .= &Apache::courseprefs::print_linkprotection($dom,'',$settings,$rowtotal,'','','domain');
     } else {      } else {
           my ($switchserver,$switchmessage);
           $switchserver = &check_switchserver($dom);
           $switchmessage = &mt("submit from domain's primary library server: [_1].",$switchserver);
         my $maxnum = 0;          my $maxnum = 0;
         my %ordered;          my %ordered;
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
Line 6656  sub print_lti { Line 6282  sub print_lti {
             for (my $i=0; $i<@items; $i++) {              for (my $i=0; $i<@items; $i++) {
                 $css_class = $itemcount%2?' class="LC_odd_row"':'';                  $css_class = $itemcount%2?' class="LC_odd_row"':'';
                 my $item = $ordered{$items[$i]};                  my $item = $ordered{$items[$i]};
                 my ($key,$secret,$lifetime,$consumer,$requser,$crsinc,$current);                  my ($key,$secret,$usable,$lifetime,$consumer,$requser,$crsinc,$current);
                 if (ref($settings->{$item}) eq 'HASH') {                  if (ref($settings->{$item}) eq 'HASH') {
                     $key = $settings->{$item}->{'key'};                      $key = $settings->{$item}->{'key'};
                     $secret = $settings->{$item}->{'secret'};                      $usable = $settings->{$item}->{'usable'};
                     $lifetime = $settings->{$item}->{'lifetime'};                      $lifetime = $settings->{$item}->{'lifetime'};
                     $consumer = $settings->{$item}->{'consumer'};                      $consumer = $settings->{$item}->{'consumer'};
                     $requser = $settings->{$item}->{'requser'};                      $requser = $settings->{$item}->{'requser'};
Line 6707  sub print_lti { Line 6333  sub print_lti {
                     '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '.                      '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '.
                     ('&nbsp;'x2).                      ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" name="lti_lifetime_'.$i.'"'.                      '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" name="lti_lifetime_'.$i.'"'.
                     'value="'.$lifetime.'" size="3" /></span>'.                      'value="'.$lifetime.'" size="3" /></span><br /><br />';
                     ('&nbsp;'x2).                  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'}.':'.                      '<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="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".                      '<label><input type="radio" name="lti_requser_'.$i.'" value="0"'.$onclickrequser.$checkedrequser{no}.' />'.&mt('No').'</label></span>'."\n".
Line 6717  sub print_lti { Line 6391  sub print_lti {
                     '<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="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".                      '<label><input type="radio" name="lti_crsinc_'.$i.'" value="0"'.$onclickcrsinc.$checkedcrsinc{no}.' />'.&mt('No').'</label></span>'."\n".
                     ('&nbsp;'x4).                      ('&nbsp;'x4).
                     '<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>'.                      '<input type="hidden" name="lti_id_'.$i.'" value="'.$item.'" /></span>'.
                     '</fieldset>'.&lti_options($i,$current,$itemcount,%lt).'</td></tr>';                      '</fieldset>'.&lti_options($i,$current,$itemcount,%lt).'</td></tr>';
                 $itemcount ++;                  $itemcount ++;
Line 6751  sub print_lti { Line 6419  sub print_lti {
                       '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_add">'.                        '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_add">'.
                       '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".                        '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".
                       ('&nbsp;'x2).                        ('&nbsp;'x2).
                       '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="3" name="lti_lifetime_add" value="300" /></span> '."\n".                        '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="3" name="lti_lifetime_add" value="300" /></span><br /><br />'."\n";
                       ('&nbsp;'x2).          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'}.':'.                        '<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="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".                        '<label><input type="radio" name="lti_requser_add" value="0" onclick="toggleLTI(this.form,'."'requser','add'".');" />'.&mt('No').'</label></span>'."\n".
Line 6760  sub print_lti { Line 6436  sub print_lti {
                       '<span class="LC_nobreak">'.$lt{'crsinc'}.':'.                        '<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="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".                        '<label><input type="radio" name="lti_crsinc_add" value="0" onclick="toggleLTI(this.form,'."'crsinc','add'".');" />'.&mt('No').'</label></span>'."\n".
                       ('&nbsp;'x4).  
                       '<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).                        '</fieldset>'.&lti_options('add',undef,$itemcount,%lt).
                       '</td>'."\n".                        '</td>'."\n".
                       '</tr>'."\n";                        '</tr>'."\n";
Line 6837  sub lti_options { Line 6508  sub lti_options {
         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 6847  sub lti_options { Line 6518  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 6875  sub lti_options { Line 6546  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 6892  sub lti_options { Line 6563  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 6938  sub lti_options { Line 6609  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 6993  sub lti_options { Line 6664  sub lti_options {
                '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Roles which may create user accounts').'</legend>';                 '<fieldset class="ltioption_usr_'.$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_usr_'.$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>'.
Line 7125  sub lti_options { Line 6796  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 7173  sub ltimenu_titles { Line 6844  sub ltimenu_titles {
     );      );
 }  }
   
 sub check_switchserver {  sub linkprot_suggestions {
     my ($home) = @_;      my ($suggested,$itemcount) = @_;
     my $switchserver;      my $count = 0;
     if ($home ne '') {      my $next = 1;
         my $allowed;      my %lt = &Apache::lonlocal::texthash(
         my @ids=&Apache::lonnet::current_machine_ids();                                            'name' => 'Suggested Launcher',
         foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }                                            'info' => 'Recommendations',
         if (!$allowed) {                                          );
             $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&amp;role='.      my ($datatable,$css_class,$dest);
                           &HTML::Entities::encode($env{'request.role'},'\'<>"&').      if (ref($suggested) eq 'HASH') {
                           '&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';          my @current = sort { $a <=> $b } keys(%{$suggested});
           $next += $current[-1];
           for (my $i=0; $i<@current; $i++) {
               my $num = $current[$i];
               my %values;
               if (ref($suggested->{$num}) eq 'HASH') {
                   %values = %{$suggested->{$num}};
               } else {
                   next;
               }
               $css_class = $$itemcount%2?' class="LC_odd_row"':'';
               $datatable .=
                   '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
                   '<label><input type="checkbox" name="linkprot_suggested_del" value="'.$i.'" />'."\n".
                   &mt('Delete?').'</label></span></td><td>'."\n".
                   '<div class="LC_floatleft"><fieldset><legend>'.$lt{'name'}.'</legend>'."\n".
                   '<input type="text" size="15" name="linkprot_suggested_name_'.$i.'" value="'.$values{'name'}.'" autocomplete="off" />'."\n".
                   '</fieldset></div>'.
                   '<div class="LC_floatleft"><fieldset><legend>'.$lt{'info'}.'</legend>'."\n".
                   '<textarea cols="55" rows="5" name="linkprot_suggested_info_'.$i.'">'.$values{'info'}.'</textarea>'.
                   '</fieldset></div>'.
                   '<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n".
                   '<input type="hidden" name="linkprot_suggested_id_'.$i.'" value="'.$num.'" /></td></tr>'."\n";
               $$itemcount ++;
         }          }
     }      }
     return $switchserver;      $css_class = $$itemcount%2?' class="LC_odd_row"':'';
       $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
                     '<input type="hidden" name="linkprot_suggested_maxnum" value="'.$next.'" />'."\n".
                     '<input type="checkbox" name="linkprot_suggested_add" value="1" />'.&mt('Add').'</span></td>'."\n".
                     '<td>'."\n".
                     '<div class="LC_floatleft"><fieldset><legend>'.$lt{'name'}.'</legend>'."\n".
                     '<input type="text" size="15" name="linkprot_suggested_name_add" value="" autocomplete="off" />'."\n".
                     '</fieldset></div>'.
                     '<div class="LC_floatleft"><fieldset><legend>'.$lt{'info'}.'</legend>'."\n".
                     '<textarea cols="55" rows="5" name="linkprot_suggested_info_add"></textarea>'.
                     '</fieldset></div>'.
                     '<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n".
                     '</td></tr>'."\n";
       return $datatable;
 }  }
   
 sub print_coursedefaults {  sub print_coursedefaults {
Line 7196  sub print_coursedefaults { Line 6903  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 (MB)',
         anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys',          anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys',
         coursecredits        => 'Credits can be specified for courses',          coursecredits        => 'Credits can be specified for courses',
         uselcmath            => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)',          uselcmath            => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)',
Line 7206  sub print_coursedefaults { Line 6914  sub print_coursedefaults {
         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',          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)',
           crsauthor            => 'Standard LON-CAPA problems can be created within a course/community (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,
                              crsauthor            => 1,
                          );                           );
     if ($position eq 'top') {      if ($position eq 'top') {
         %defaultchecked = (          %defaultchecked = (
Line 7325  sub print_coursedefaults { Line 7040  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 $ltiauth = 0;
           my %domexttool;
           my %exttool;
           my %crsauthor;
         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'}) {              if ($settings->{'ltiauth'}) {
                 $ltiauth = 1;                  $ltiauth = 1;
             }              }
               if (ref($settings->{'domexttool'}) eq 'HASH') {
                   foreach my $type (@types) {
                       if ($settings->{'domexttool'}->{$type}) {
                           $domexttool{$type} = ' checked="checked"';
                       }
                   }
               } else {
                   foreach my $type (@types) {
                       if ($staticdefaults{'domexttool'}) {
                           $domexttool{$type} = ' checked="checked"';
                       }
                   }
               }
               if (ref($settings->{'exttool'}) eq 'HASH') {
                   foreach my $type (@types) {
                       if ($settings->{'exttool'}->{$type}) {
                           $exttool{$type} = ' checked="checked"';
                       }
                   }
               }
               if (ref($settings->{'crsauthor'}) eq 'HASH') {
                   foreach my $type (@types) {
                       if ($settings->{'crsauthor'}->{$type}) {
                           $crsauthor{$type} = ' checked="checked"';
                       }
                   }
               } else {
                   foreach my $type (@types) {
                       if ($staticdefaults{'crsauthor'}) {
                           $crsauthor{$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 7385  sub print_coursedefaults { Line 7142  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 ($staticdefaults{'crsauthor'}) {
                       $crsauthor{$type} = ' checked="checked"';
                   }
             }              }
         }          }
         if (!$currdefresponder) {          if (!$currdefresponder) {
Line 7396  sub print_coursedefaults { Line 7159  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 7419  sub print_coursedefaults { Line 7185  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 7488  sub print_coursedefaults { Line 7267  sub print_coursedefaults {
             &radiobutton_prefs($current,\@toggles,\%defaultchecked,              &radiobutton_prefs($current,\@toggles,\%defaultchecked,
                                \%choices,$itemcount,undef,undef,'left');                                 \%choices,$itemcount,undef,undef,'left');
         $datatable .= $table;          $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 ++;          $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";
           $itemcount ++;
           $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
           $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
                         $choices{'crsauthor'}.
                         '</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="crsauthor"'.
                             ' value="'.$type.'"'.$crsauthor{$type}.' />'.
                             &mt($type).'</span></td>'."\n";
           }
           $datatable .= '</tr></table></td></tr>'."\n";
     }      }
     $$rowtotal += $itemcount;      $$rowtotal += $itemcount;
     return $datatable;      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',
                               'daxecollapse' => 'off',
                               'domcoordacc'  => 'on',
                             );
           my @toggles = ('nocodemirror','daxecollapse','domcoordacc');
           ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
                                                        \%titles,$itemcount);
           my %staticdefaults = (
                                   'copyright'    => 'default',
                                   'sourceavail'  => 'closed',
                                );
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           my %currrights;
           foreach my $item ('copyright','sourceavail') {
               $currrights{$item} = $staticdefaults{$item};
               if (ref($settings) eq 'HASH') {
                   if (exists($settings->{$item})) {
                       $currrights{$item} = $settings->{$item};
                   }
               }
           }
           $datatable .= '<tr'.$css_class.'><td style="vertical-align: top">'.
                         '<span class="LC_nobreak">'.$titles{'copyright'}.
                         '</span></td><td class="LC_right_item">'.
                         &selectbox('copyright',$currrights{'copyright'},'',
                                    \&Apache::loncommon::copyrightdescription,
                                    (grep !/^priv|custom$/,(&Apache::loncommon::copyrightids))).
                         '</td></tr>'."\n";
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td style="vertical-align: top">'.
                         '<span class="LC_nobreak">'.$titles{'sourceavail'}.
                         '</span></td><td class="LC_right_item">'.
                         &selectbox('sourceavail',$currrights{'sourceavail'},'',
                                    \&Apache::loncommon::source_copyrightdescription,
                                    (&Apache::loncommon::source_copyrightids)).
                         '</td></tr>'."\n";        
       } else {
           $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
           my $curreditors;
           my %staticdefaults = (
                                   editors => ['edit','xml'],
                                   authorquota => 500,
                                   webdav => 0,
                                );
           my $curreditors = $staticdefaults{'editors'};
           if ((ref($settings) eq 'HASH') &&
               (ref($settings->{'editors'}) eq 'ARRAY')) {
               $curreditors = $settings->{'editors'};
           } else {
               $curreditors = $staticdefaults{'editors'};
           }
           my @editors = ('edit','xml','daxe');
           $datatable = '<tr'.$css_class.'>'."\n".
                        '<td>'.$titles{'editors'}.'</td>'."\n".
                        '<td class="LC_left_item">'."\n".
                        '<span class="LC_nobreak">';
           foreach my $editor (@editors) {
               my $checked;
               if (grep(/^\Q$editor\E$/,@{$curreditors})) {
                   $checked = ' checked="checked"';
               }
               $datatable .= '<label>'.
                             '<input type="checkbox" name="author_editors" '.
                             $checked.' value="'.$editor.'" '.
                             'onclick="javascript:checkEditors(this.form,'."'author_editors'".',this);" />'.
                             $titles{$editor}.'</label>&nbsp;';
           }
           $datatable .= '</span>'."\n".'</td>'."\n".'</tr>'."\n";
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
           my @insttypes;
           if (ref($types) eq 'ARRAY') {
               @insttypes = @{$types};
           }
           my $typecount = 0;
           my %domconf = &Apache::lonnet::get_dom('configuration',['quotas'],$dom);
           my @items = ('webdav','authorquota');
           my %quotas;
           if (ref($domconf{'quotas'}) eq 'HASH') {
               %quotas = %{$domconf{'quotas'}};
               foreach my $item (@items) {
                   if (ref($quotas{$item}) eq 'HASH') {
                       foreach my $type (@insttypes,'default') {
                           if ($item eq 'authorquota') {
                               if ($quotas{$item}{$type} !~ /^\d+$/) {
                                   $quotas{$item}{$type} = $staticdefaults{$item};
                               }
                           } elsif ($item eq 'webdav') {
                               if ($quotas{$item}{$type} !~ /^(0|1)$/) {
                                   $quotas{$item}{$type} = $staticdefaults{$item};
                               }
                           }
                       }
                   } else {
                       foreach my $type (@insttypes,'default') {
                           $quotas{$item}{$type} = $staticdefaults{$item};
                       }
                   }
               }
           } else {
               foreach my $item (@items) {
                   foreach my $type (@insttypes,'default') {
                       $quotas{$item}{$type} = $staticdefaults{$item};
                   }
               }
           }
           if (ref($usertypes) eq 'HASH') {
               my $numinrow = 4;
               my $onclick = '';
               $datatable .= &insttypes_row(\%quotas,$types,$usertypes,$dom,
                                            $numinrow,$othertitle,'authorquota',
                                            \$itemcount,$onclick);
               $itemcount ++;
               $datatable .= &insttypes_row(\%quotas,$types,$usertypes,$dom,
                                            $numinrow,$othertitle,'webdav',
                                            \$itemcount);
               $itemcount ++;
           }
           my $checkedno = ' checked="checked"';
           my ($checkedon,$checkedoff);
           if (ref($quotas{'webdav'}) eq 'HASH') {
               if ($quotas{'webdav'}{'_LC_adv'} =~ /^0|1$/) {
                   if ($quotas{'webdav'}{'_LC_adv'}) {
                       $checkedon = $checkedno;
                   } else {
                       $checkedoff = $checkedno;
                   }
                   undef($checkedno);
               }
           }
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'>'.
                         '<td>'.$titles{'webdav_LC_adv'}.'<br />'.
                                $titles{'webdav_LC_adv_over'}.
                         '</td>'.
                         '<td class="LC_left_item">';
           foreach my $option ('none','off','on') {
               my ($text,$val,$checked);
               if ($option eq 'none') {
                   $text = $titles{'none'};
                   $val = '';
                   $checked = $checkedno;
               } elsif ($option eq 'off') {
                   $text = $titles{'overoff'};
                   $val = 0;
                   $checked = $checkedoff;
               } elsif ($option eq 'on') {
                   $text = $titles{'overon'};
                   $val = 1;
                   $checked = $checkedon;
               }
               $datatable .= '<span class="LC_nobreak"><label>'.
                             '<input type="radio" name="webdav_LC_adv"'.
                             ' value="'.$val.'"'.$checked.' />'.
                             $text.'</label></span>&nbsp; ';
           }
           $datatable .= '</td></tr>';
           $itemcount ++;
       }
       $$rowtotal += $itemcount;
       return $datatable;
   }
   
   sub authordefaults_titles {
       return &Apache::lonlocal::texthash(
                  copyright => 'Copyright/Distribution',
                  sourceavail => ' Source Available',
                  editors => 'Available Editors',
                  webdav => 'WebDAV',
                  authorquota => 'Authoring Space quotas (MB)',
                  nocodemirror => 'Deactivate CodeMirror for EditXML editor',
                  daxecollapse => 'Daxe editor: LON-CAPA standard menus start collapsed',
                  domcoordacc => 'Dom. Coords. can enter Authoring Spaces in domain',
                  edit  => 'Standard editor (Edit)',
                  xml   => 'Text editor (EditXML)',
                  daxe  => 'Daxe editor (Daxe)',
                  webdav_LC_adv => 'WebDAV access for LON-CAPA "advanced" users',
                  webdav_LC_adv_over => '(overrides access based on affiliation, if set)',
                  none => 'No override set',
                  overon => 'Override -- webDAV on',
                  overoff => 'Override -- webDAV off',
       );
   }
   
   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 8237  sub password_rules { Line 8269  sub password_rules {
             max            => 'Maximum password length',              max            => 'Maximum password length',
             chars          => 'Required characters',              chars          => 'Required characters',
         );          );
     } elsif ($prefix eq 'secrets') {      } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {
         %titles = &Apache::lonlocal::texthash (          %titles = &Apache::lonlocal::texthash (
             min            => 'Minimum secret length',              min            => 'Minimum secret length',
             max            => 'Maximum secret length',              max            => 'Maximum secret length',
Line 8260  sub password_rules { Line 8292  sub password_rules {
         if (ref($settings->{chars}) eq 'ARRAY') {          if (ref($settings->{chars}) eq 'ARRAY') {
             map { $chars{$_} = 1; } (@{$settings->{chars}});              map { $chars{$_} = 1; } (@{$settings->{chars}});
         }          }
         if ($prefix eq 'passwords') {           if ($prefix eq 'passwords') {
             if ($settings->{expire}) {              if ($settings->{expire}) {
                 $expire = $settings->{expire};                  $expire = $settings->{expire};
             }              }
Line 8403  sub print_wafproxy { Line 8435  sub print_wafproxy {
             my %config = &Apache::lonnet::get_dom('configuration',['wafproxy'],$domain);              my %config = &Apache::lonnet::get_dom('configuration',['wafproxy'],$domain);
             if (ref($config{'wafproxy'}) eq 'HASH') {              if (ref($config{'wafproxy'}) eq 'HASH') {
                 $aliases{$domain} = $config{'wafproxy'}{'alias'};                  $aliases{$domain} = $config{'wafproxy'}{'alias'};
                 if (exists($config{'wafproxy'}{'saml'})) {                   if (exists($config{'wafproxy'}{'saml'})) {
                     $saml{$domain} = $config{'wafproxy'}{'saml'};                      $saml{$domain} = $config{'wafproxy'}{'saml'};
                 }                  }
                 foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') {                  foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') {
Line 8420  sub print_wafproxy { Line 8452  sub print_wafproxy {
             my $dom_in_effect;              my $dom_in_effect;
             my $aliasrows = '<tr>'.              my $aliasrows = '<tr>'.
                             '<td class="LC_left_item" style="vertical-align: baseline;">'.                              '<td class="LC_left_item" style="vertical-align: baseline;">'.
                             &mt('Hostname').':&nbsp;'.                              &mt('Hostname').': '.
                             '<i>'.&Apache::lonnet::hostname($server).'</i></td><td>&nbsp;</td>';                              '<span class="LC_nobreak LC_cusr_emph">'.
                               &Apache::lonnet::hostname($server).
                               '</span></td><td>&nbsp;</td>';
             if ($othercontrol{$server}) {              if ($othercontrol{$server}) {
                 $dom_in_effect = $othercontrol{$server};                  $dom_in_effect = $othercontrol{$server};
                 my ($current,$forsaml);                  my ($current,$forsaml);
Line 8468  sub print_wafproxy { Line 8502  sub print_wafproxy {
                               ('&nbsp;'x2).'<span class="LC_nobreak">'.                                ('&nbsp;'x2).'<span class="LC_nobreak">'.
                               &mt('Alias used for SSO Auth').':&nbsp;<label>'.                                &mt('Alias used for SSO Auth').':&nbsp;<label>'.
                               '<input type="radio" value="0"'.$samloff.' name="wafproxy_alias_saml_'.$server.'" />'.                                '<input type="radio" value="0"'.$samloff.' name="wafproxy_alias_saml_'.$server.'" />'.
                               &mt('No').'</label>&nbsp;<label>'.                                 &mt('No').'</label>&nbsp;<label>'.
                               '<input type="radio" value="1"'.$samlon.' name="wafproxy_alias_saml_'.$server.'" />'.                                '<input type="radio" value="1"'.$samlon.' name="wafproxy_alias_saml_'.$server.'" />'.
                               &mt('Yes').'</label></span>'.                                &mt('Yes').'</label></span>'.
                               '</td>';                                 '</td>';
             }              }
             $aliasrows .= '</tr>';              $aliasrows .= '</tr>';
             $aliasinfo{$dom_in_effect} .= $aliasrows;              $aliasinfo{$dom_in_effect} .= $aliasrows;
Line 9381  sub print_loadbalancing { Line 9415  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 9736  sub tool_titles { Line 9770  sub tool_titles {
     my %titles = &Apache::lonlocal::texthash (      my %titles = &Apache::lonlocal::texthash (
                      aboutme    => 'Personal web page',                       aboutme    => 'Personal web page',
                      blog       => 'Blog',                       blog       => 'Blog',
                      webdav     => 'WebDAV',  
                      portfolio  => 'Portfolio',                       portfolio  => 'Portfolio',
                        portaccess => 'Share portfolio files',
                      timezone   => 'Can set time zone',                       timezone   => 'Can set time zone',
                      official   => 'Official courses (with institutional codes)',                       official   => 'Official courses (with institutional codes)',
                      unofficial => 'Unofficial courses',                       unofficial => 'Unofficial courses',
Line 9968  sub print_selfcreation { Line 10002  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 10105  sub print_selfcreation { Line 10139  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 10132  sub print_selfcreation { Line 10166  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 10235  function toggleEmailOptions(form,radio,p Line 10269  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 10258  ENDSCRIPT Line 10292  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 10276  sub noninst_users { Line 10310  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 10404  sub noninst_users { Line 10438  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 10722  sub print_defaults { Line 10756  sub print_defaults {
                     if ($defaults{$item.'_'.$field}) {                      if ($defaults{$item.'_'.$field}) {
                         $checkedon = $checkedoff;                          $checkedon = $checkedoff;
                         $checkedoff = '';                          $checkedoff = '';
                     }                       }
                     $datatable .= '<div id="'.$item.'_'.$field.'_div" style="display:'.$portalsty.'">'.                      $datatable .= '<div id="'.$item.'_'.$field.'_div" style="display:'.$portalsty.'">'.
                               '<span class="LC_nobreak">'.$titles->{$field}.'&nbsp;'.                                '<span class="LC_nobreak">'.$titles->{$field}.'&nbsp;'.
                               '<label><input type="radio" name="'.$item.'_'.$field.'" value="1"'.$checkedon.'/>'.&mt('Yes').'</label>'.                                '<label><input type="radio" name="'.$item.'_'.$field.'" value="1"'.$checkedon.'/>'.&mt('Yes').'</label>'.
Line 11061  sub legacy_scantronformat { Line 11095  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 11548  sub defaults_javascript { Line 11585  sub defaults_javascript {
 function portalExtras(caller) {  function portalExtras(caller) {
     var x = caller.value;      var x = caller.value;
     var y = new Array('email','web');      var y = new Array('email','web');
     for (var i=0; i<y.length; i++) {       for (var i=0; i<y.length; i++) {
         if (document.getElementById('portal_def_'+y[i]+'_div')) {          if (document.getElementById('portal_def_'+y[i]+'_div')) {
             var z = document.getElementById('portal_def_'+y[i]+'_div');              var z = document.getElementById('portal_def_'+y[i]+'_div');
             if (x.length > 0) {              if (x.length > 0) {
Line 11644  sub passwords_javascript { Line 11681  sub passwords_javascript {
             passexp => 'Warning: days before password expiration 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).',              passnum => 'Warning: number of previous passwords to save must be a positive integer (or blank).',
         );          );
     } elsif ($prefix eq 'secrets') {      } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {
         %intalert = &Apache::lonlocal::texthash (          %intalert = &Apache::lonlocal::texthash (
             passmin => 'Warning: minimum secret length must be a positive integer greater than 6.',              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).',              passmax => 'Warning: maximum secret length must be a positive integer (or blank).',
Line 11652  sub passwords_javascript { Line 11689  sub passwords_javascript {
     }      }
     &js_escape(\%intalert);      &js_escape(\%intalert);
     my $defmin = $Apache::lonnet::passwdmin;      my $defmin = $Apache::lonnet::passwdmin;
     my $intauthjs;       my $intauthjs;
     if ($prefix eq 'passwords') { $intauthjs = <<"ENDSCRIPT";      if ($prefix eq 'passwords') { $intauthjs = <<"ENDSCRIPT";
   
 function warnIntAuth(field) {  function warnIntAuth(field) {
Line 12046  sub modifiable_userdata_row { Line 12083  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 12072  sub modifiable_userdata_row { Line 12108  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 12084  sub modifiable_userdata_row { Line 12120  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 12173  sub insttypes_row { Line 12208  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 12218  sub insttypes_row { Line 12257  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 12248  sub insttypes_row { Line 12306  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 12258  sub insttypes_row { Line 12316  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 12518  sub modify_login { Line 12597  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 12537  sub modify_login { Line 12619  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 12594  sub modify_login { Line 12677  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 12615  sub modify_login { Line 12701  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 12670  sub modify_login { Line 12757  sub modify_login {
                 $currsaml{$lonhost}{$item} = $env{'form.saml_'.$item.'_'.$lonhost};                  $currsaml{$lonhost}{$item} = $env{'form.saml_'.$item.'_'.$lonhost};
             }              }
         } else {          } else {
             if ($saml{$lonhost}) {                if ($saml{$lonhost}) {
                 $changes{'saml'}{$lonhost} = 1;                  $changes{'saml'}{$lonhost} = 1;
                 delete($currsaml{$lonhost});                  delete($currsaml{$lonhost});
             }              }
         }          }
     }      }
     foreach my $posshost (keys(%currsaml)) {      foreach my $posshost (keys(%currsaml)) {
         unless (exists($domservers{$posshost})) {           unless (exists($domservers{$posshost})) {
             delete($currsaml{$posshost});               delete($currsaml{$posshost});
         }          }
     }      }
     %{$loginhash{'login'}{'saml'}} = %currsaml;      %{$loginhash{'login'}{'saml'}} = %currsaml;
Line 12689  sub modify_login { Line 12776  sub modify_login {
             if ($switchserver) {              if ($switchserver) {
                 $error = &mt("Upload of SSO Button Image is not permitted to this server: [_1].",$switchserver);                  $error = &mt("Upload of SSO Button Image is not permitted to this server: [_1].",$switchserver);
             } elsif ($author_ok eq 'ok') {              } elsif ($author_ok eq 'ok') {
                   my $modified = [];
                 foreach my $lonhost (@newsamlimgs) {                  foreach my $lonhost (@newsamlimgs) {
                     my $formelem = 'saml_img_'.$lonhost;                      my $formelem = 'saml_img_'.$lonhost;
                     my ($result,$imgurl) = &publishlogo($r,'upload',$formelem,$dom,$confname,                      my ($result,$imgurl) =
                                                         "login/saml/$lonhost",'','',                          &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,
                                                         $env{'form.saml_img_'.$lonhost.'.filename'});                                                                  "login/saml/$lonhost",'','',
                                                                   $env{'form.saml_img_'.$lonhost.'.filename'},
                                                                   $modified);
                     if ($result eq 'ok') {                      if ($result eq 'ok') {
                         $currsaml{$lonhost}{'img'} = $imgurl;                          $currsaml{$lonhost}{'img'} = $imgurl;
                         $loginhash{'login'}{'saml'}{$lonhost}{'img'} = $imgurl;                          $loginhash{'login'}{'saml'}{$lonhost}{'img'} = $imgurl;
Line 12704  sub modify_login { Line 12794  sub modify_login {
                         $errors .= '<li><span class="LC_error">'.$puberror.'</span></li>';                          $errors .= '<li><span class="LC_error">'.$puberror.'</span></li>';
                     }                      }
                 }                  }
                   &update_modify_urls($r,$modified);
             } else {              } 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);                  $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);
             }              }
Line 13058  sub modify_ipaccess { Line 13149  sub modify_ipaccess {
             $possrange =~ s/,+/,/g;              $possrange =~ s/,+/,/g;
             if ($possrange ne '') {              if ($possrange ne '') {
                 my (@ok,$count);                  my (@ok,$count);
                 $count = 0;                   $count = 0;
                 foreach my $poss (split(/\,/,$possrange)) {                  foreach my $poss (split(/\,/,$possrange)) {
                     $count ++;                      $count ++;
                     $poss = &validate_ip_pattern($poss);                      $poss = &validate_ip_pattern($poss);
Line 13091  sub modify_ipaccess { Line 13182  sub modify_ipaccess {
             }              }
         }          }
         $confhash{$itemid}{'commblocks'} = {};          $confhash{$itemid}{'commblocks'} = {};
            
         my %commblocks;          my %commblocks;
         map { $commblocks{$_} = 1; } &Apache::loncommon::get_env_multiple('form.ipaccess_block_'.$idx);            map { $commblocks{$_} = 1; } &Apache::loncommon::get_env_multiple('form.ipaccess_block_'.$idx);
         foreach my $type (@{$typeorder}) {          foreach my $type (@{$typeorder}) {
             if ($commblocks{$type}) {              if ($commblocks{$type}) {
                 $confhash{$itemid}{'commblocks'}{$type} = 'on';                  $confhash{$itemid}{'commblocks'}{$type} = 'on';
Line 13125  sub modify_ipaccess { Line 13216  sub modify_ipaccess {
         }          }
         $env{'form.ipaccess_cnum_'.$idx} =~ s/^\s+|\s+$//g;          $env{'form.ipaccess_cnum_'.$idx} =~ s/^\s+|\s+$//g;
         $env{'form.ipaccess_cdom_'.$idx} =~ s/^\s+|\s+$//g;          $env{'form.ipaccess_cdom_'.$idx} =~ s/^\s+|\s+$//g;
         if (($env{'form.ipaccess_cnum_'.$idx} =~ /^$match_courseid$/) &&           if (($env{'form.ipaccess_cnum_'.$idx} =~ /^$match_courseid$/) &&
             ($env{'form.ipaccess_cdom_'.$idx} =~ /^$match_domain$/)) {              ($env{'form.ipaccess_cdom_'.$idx} =~ /^$match_domain$/)) {
             if (&Apache::lonnet::homeserver($env{'form.ipaccess_cnum_'.$idx},              if (&Apache::lonnet::homeserver($env{'form.ipaccess_cnum_'.$idx},
                                             $env{'form.ipaccess_cdom_'.$idx}) eq 'no_host') {                                              $env{'form.ipaccess_cdom_'.$idx}) eq 'no_host') {
Line 13205  sub modify_ipaccess { Line 13296  sub modify_ipaccess {
                     if (keys(%{$confhash{$itemid}{'courses'}})) {                      if (keys(%{$confhash{$itemid}{'courses'}})) {
                         my @courses;                          my @courses;
                         foreach my $cid (sort(keys(%{$confhash{$itemid}{'courses'}}))) {                          foreach my $cid (sort(keys(%{$confhash{$itemid}{'courses'}}))) {
                             my %courseinfo = &Apache::lonnet::coursedescription($cid,{'one_time' => 1});                               my %courseinfo = &Apache::lonnet::coursedescription($cid,{'one_time' => 1});
                             push(@courses,$courseinfo{'description'}.' ('.$cid.')');                              push(@courses,$courseinfo{'description'}.' ('.$cid.')');
                         }                          }
                         $resulttext .= '<li>'.&mt('Courses/Communities allowed').':<ul><li>'.                          $resulttext .= '<li>'.&mt('Courses/Communities allowed').':<ul><li>'.
Line 13273  sub get_ipaccess_id { Line 13364  sub get_ipaccess_id {
     return ($id,$error);      return ($id,$error);
 }  }
   
   sub modify_authordefaults {
       my ($dom,$lastactref,%domconfig) = @_;
   #
   # Retrieve current domain configuration for webDAV and Authoring Space quotas from $domconfig{'quotas'}.
   #
       my (%curr_quotas,%save_quotas,%confhash,%changes,%newvalues);
       if (ref($domconfig{'quotas'}) eq 'HASH') {
           foreach my $key (keys(%{$domconfig{'quotas'}})) {
               if ($key =~ /^webdav|authorquota$/) {
                   $curr_quotas{$key} = $domconfig{'quotas'}{$key};
               } else {
                   $save_quotas{$key} = $domconfig{'quotas'}{$key};
               }
           }
       }
       my %staticdefaults = (
                              'copyright'    => 'default',
                              'sourceavail'  => 'closed',
                              'nocodemirror' => 'off',
                              'daxecollapse' => 'off',
                              'domcoordacc'  => 'on',
                              'editors'      => ['edit','xml'].
                              'authorquota'  => 500,
                              'webdav'       => 0,
                            );
       my %titles = &authordefaults_titles();
       foreach my $item ('nocodemirror','daxecollapse','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','daxecollapse','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','daxecollapse','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)) {
               my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
               if ((exists($changes{'authorquota'})) || (exists($changes{'webdav'})) ||
                   ($changes{'webdav_LC_adv'})) {
                   if ((exists($changes{'authorquota'})) && (ref($save_quotas{'authorquota'}) eq 'HASH')) {
                       $domdefaults{'authorquota'} = $save_quotas{'authorquota'};
                   }
                   if (((exists($changes{'webdav'})) || ($changes{'webdav_LC_adv'})) &&
                       (ref($save_quotas{'webdav'}) eq 'HASH')) {
                       $domdefaults{'webdav'} = $save_quotas{'webdav'};
                   }
               }
               $resulttext = &mt('Changes made:').'<ul>';
               my $authoroverride;
               foreach my $key ('nocodemirror','daxecollapse','domcoordacc','copyright','sourceavail') {
                   if (exists($changes{$key})) {
                       $domdefaults{$key} = $confhash{$key};
                       my $shown;
                       unless ($authoroverride) {
                           $resulttext .= '<li>'.&mt('Defaults which can be overridden by Author').'<ul>';
                           $authoroverride = 1;
                       }
                       if (($key eq 'nocodemirror') || ($key eq 'daxecollapse') || ($key eq 'domcoordacc')) {
                           $shown = ($confhash{$key} ? &mt('Yes') : &mt('No'));
                       } elsif ($key eq 'copyright') {
                           $shown = &Apache::loncommon::copyrightdescription($confhash{$key});
                       } elsif ($key eq 'sourceavail') {
                           $shown = &Apache::loncommon::source_copyrightdescription($confhash{$key});
                       }
                       $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{$key},$shown).'</li>';
                   }
               }
               if ($authoroverride) {
                   $resulttext .= '</ul></li>';
               }
               my $domcoordoverride;
               foreach my $key ('editors','authorquota','webdav','webdav_LC_adv') {
                   if (exists($changes{$key})) {
                       my $shown;
                       unless ($domcoordoverride) {
                           $resulttext .= '<li>'.&mt('Defaults which can be overridden by a Domain Coodinator').'<ul>';
                           $domcoordoverride = 1;
                       }
                       if ($key eq 'editors') {
                           if (ref($confhash{'editors'}) eq 'ARRAY') {
                               $domdefaults{'editors'} = join(',',@{$confhash{'editors'}});
                               if (@{$confhash{'editors'}}) {
                                   $shown = join(', ', map { $titles{$_} } @{$confhash{'editors'}});
                               } else {
                                   $shown = &mt('None');
                               }
                           }
                       } elsif ($key eq 'authorquota') {
                           foreach my $type (@insttypes) {
                               $shown .= $usertypes->{$type}.' -- '.$save_quotas{$key}{$type}.', ';
                           }
                           $shown .= $othertitle.' -- '.$save_quotas{$key}{'default'};
                       } elsif ($key eq 'webdav') {
                           foreach my $type (@insttypes) {
                               $shown .= $usertypes->{$type}.' -- '. ($save_quotas{$key}{$type} ? &mt('Yes') : &mt('No')).', ';
                           }
                           $shown .= $othertitle.' -- '. ($save_quotas{$key}{'default'} ? &mt('Yes') : &mt('No'));
                       } elsif ($key eq 'webdav_LC_adv') {
                           if (exists($save_quotas{'webdav'}{'_LC_adv'})) {
                               $shown = ($save_quotas{'webdav'}{'_LC_adv'} ? $titles{'overon'} : $titles{'overoff'});
                           } else {
                               $shown = $titles{'none'};
                           }
                       }
                       $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{$key},$shown).'</li>';
                   }
               }
               if ($domcoordoverride) {
                   $resulttext .= '</ul></li>';
               }
               my $cachetime = 24*60*60;
               &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'domdefaults'} = 1;
               }
           } else {
               $resulttext = &mt('No changes made to Authoring Space defaults');
           }
       }
       return $resulttext;
   }
   
 sub modify_rolecolors {  sub modify_rolecolors {
     my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_;      my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_;
     my ($resulttext,%rolehash);      my ($resulttext,%rolehash);
Line 13408  sub modify_colors { Line 13733  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 13435  sub modify_colors { Line 13763  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 13734  sub check_authorstatus { Line 14065  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 14007  sub subscribed_hosts { Line 14125  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 14027  sub modify_quotas { Line 14151  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 14047  sub modify_quotas { Line 14171  sub modify_quotas {
         @usertools = ('author');          @usertools = ('author');
         %titles = &authorrequest_titles();          %titles = &authorrequest_titles();
     } else {      } else {
         @usertools = ('aboutme','blog','webdav','portfolio','timezone');          @usertools = ('aboutme','blog','portfolio','portaccess','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 14070  sub modify_quotas { Line 14194  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 14365  sub modify_quotas { Line 14487  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 14454  sub modify_quotas { Line 14575  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 14482  sub modify_quotas { Line 14598  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 14537  sub modify_quotas { Line 14638  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 14738  sub process_textbook_image { Line 14826  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 14757  sub process_textbook_image { Line 14848  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>';  
         }  
     }  
     if (ref($domconfig{$action}) eq 'HASH') {  
         my %deletions;  
         my @todelete = &Apache::loncommon::get_env_multiple('form.ltitools_del');  
         if (@todelete) {  
             map { $deletions{$_} = 1; } @todelete;  
         }          }
         my %customadds;          $ltitoolsoutput = &Apache::courseprefs::store_ltitools($dom,'','domain',\%ltitoolschg,$domconfig{'ltitools'});
         my @newcustom = &Apache::loncommon::get_env_multiple('form.ltitools_customadd');          if (keys(%ltitoolschg)) {
         if (@newcustom) {              %newltitools = %ltitoolschg;
             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,undef,1);                                     $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;
           } elsif ($item eq 'suggested') {
               if ((ref($secchanges->{'suggested'}) eq 'HASH') &&
                   (ref($newsec->{'suggested'}) eq 'HASH')) {
                   my $suggestions;
                   foreach my $id (sort { $a <=> $b } keys(%{$secchanges->{'suggested'}})) {
                       if (ref($newsec->{'suggested'}->{$id}) eq 'HASH') {
                           my $name = $newsec->{'suggested'}->{$id}->{'name'};
                           my $info = $newsec->{'suggested'}->{$id}->{'info'};
                           $suggestions .= '<li>'.&mt('Launcher: [_1]',$name).'<br />'.
                                                  &mt('Recommend: [_1]','<pre>'.$info.'</pre>').
                                           '</li>';
                       } else {
                           $suggestions .= '<li>'.&mt('Recommendations deleted for Launcher: [_1]',
                                                      $newsec->{'suggested'}->{$id}).'</li>';
                       }
                   }
                   if ($suggestions) {
                       $output .= '<li>'.&mt('Hints in Courses for Link Protector Configuration').
                                  '<ul>'.$suggestions.'</ul>'.
                                  '</li>';
                   }
             }              }
         }          }
         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 15916  sub process_proctoring_image { Line 15733  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 15927  sub process_proctoring_image { Line 15746  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 15942  sub process_proctoring_image { Line 15762  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);
Line 15963  sub modify_lti { Line 15783  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);
   
     my (%currltisec,%secchanges,%newltisec,%newltienc,%keyset,%newkeyset);      &fetch_secrets($dom,'ltisec',\%domconfig,\%currltisec,\%secchanges,\%newltisec,\%newkeyset);
     $newltisec{'private'}{'keys'} = [];  
     $newltisec{'encrypt'} = {};  
     $newltisec{'rules'} = {};  
     $newltisec{'linkprot'} = {};  
     if (ref($domconfig{'ltisec'}) eq 'HASH') {  
         %currltisec = %{$domconfig{'ltisec'}};  
         if (ref($currltisec{'linkprot'}) eq 'HASH') {  
             foreach my $id (keys(%{$currltisec{'linkprot'}})) {  
                 unless ($id =~ /^\d+$/) {  
                     delete($currltisec{'linkprot'}{$id});  
                 }  
             }  
         }  
         if (ref($currltisec{'private'}) eq 'HASH') {  
             if (ref($currltisec{'private'}{'keys'}) eq 'ARRAY') {  
                 $newltisec{'private'}{'keys'} = $currltisec{'private'}{'keys'};  
                 map { $keyset{$_} = 1; } @{$currltisec{'private'}{'keys'}};  
             }  
         }  
     }  
     foreach my $item ('crs','dom','consumers') {  
         my $formelement;  
         if ($item eq 'consumers') {   
             $formelement = 'form.ltisec_'.$item;  
         } else {  
             $formelement = 'form.ltisec_'.$item.'linkprot';  
         }  
         if ($env{$formelement}) {  
             $newltisec{'encrypt'}{$item} = 1;  
             if (ref($currltisec{'encrypt'}) eq 'HASH') {  
                 unless ($currltisec{'encrypt'}{$item}) {  
                     $secchanges{'encrypt'} = 1;  
                 }  
             } else {  
                 $secchanges{'encrypt'} = 1;  
             }  
         } elsif (ref($currltisec{'encrypt'}) eq 'HASH') {  
             if ($currltisec{'encrypt'}{$item}) {  
                 $secchanges{'encrypt'} = 1;  
             }  
         }  
     }  
     unless (exists($currltisec{'rules'})) {  
         $currltisec{'rules'} = {};  
     }  
     &password_rule_changes('secrets',$newltisec{'rules'},$currltisec{'rules'},\%secchanges);  
   
     my @ids=&Apache::lonnet::current_machine_ids();  
     my %servers = &Apache::lonnet::get_servers($dom,'library');  
      
     foreach my $hostid (keys(%servers)) {  
         if (($hostid ne '') && (grep(/^\Q$hostid\E$/,@ids))) {  
             my $newkey;  
             my $keyitem = 'form.ltisec_privkey_'.$hostid;  
             if (exists($env{$keyitem})) {  
                 $env{$keyitem} =~ s/(`)/'/g;  
                 if ($keyset{$hostid}) {  
                     if ($env{'form.ltisec_changeprivkey_'.$hostid}) {  
                         if ($env{$keyitem} ne '') {  
                             $secchanges{'private'} = 1;  
                             $newkeyset{$hostid} = $env{$keyitem};  
                         }  
                     }  
                 } elsif ($env{$keyitem} ne '') {  
                     unless (grep(/^\Q$hostid\E$/,@{$newltisec{'private'}{'keys'}})) {   
                         push(@{$newltisec{'private'}{'keys'}},$hostid);  
                     }  
                     $secchanges{'private'} = 1;  
                     $newkeyset{$hostid} = $env{$keyitem};  
                 }  
             }  
         }  
     }  
   
     my (%linkprotchg,$linkprotoutput,$is_home);      my (%linkprotchg,$linkprotoutput,$is_home);
     my $proterror = &Apache::courseprefs::process_linkprot($dom,'',$currltisec{'linkprot'},      my $proterror = &Apache::courseprefs::process_linkprot($dom,'',$currltisec{'linkprot'},
Line 16073  sub modify_lti { Line 15821  sub modify_lti {
         }          }
     }      }
     if (ref($currltisec{'linkprot'}) eq 'HASH') {      if (ref($currltisec{'linkprot'}) eq 'HASH') {
         foreach my $id (%{$currltisec{'linkprot'}}) {          foreach my $id (keys(%{$currltisec{'linkprot'}})) {
             next if ($id !~ /^\d+$/);              next if ($id !~ /^\d+$/);
             unless (exists($linkprotchg{$id})) {              unless (exists($linkprotchg{$id})) {
                 if (ref($currltisec{'linkprot'}{$id}) eq 'HASH') {                  if (ref($currltisec{'linkprot'}{$id}) eq 'HASH') {
Line 16095  sub modify_lti { Line 15843  sub modify_lti {
     if ($proterror) {      if ($proterror) {
         $errors .= '<li>'.$proterror.'</li>';          $errors .= '<li>'.$proterror.'</li>';
     }      }
   
       my (%delsuggested,%suggids,@suggested);;
       if (ref($currltisec{'suggested'}) eq 'HASH') {
           my $maxnum = $env{'form.linkprot_suggested_maxnum'};
           my @todelete = &Apache::loncommon::get_env_multiple('form.linkprot_suggested_del');
           for (my $i=0; $i<$maxnum; $i++) {
               my $itemid = $env{'form.linkprot_suggested_id_'.$i};
               $itemid =~ s/\D+//g;
               if ($itemid) {
                   if (ref($currltisec{'suggested'}->{$itemid}) eq 'HASH') {
                       push(@suggested,$i);
                       $suggids{$i} = $itemid;
                       if ((@todelete > 0) && (grep(/^$i$/,@todelete))) {
                           if (ref($currltisec{'suggested'}{$itemid}) eq 'HASH') {
                               $delsuggested{$itemid} = $currltisec{'suggested'}{$itemid}{'name'};
                           }
                       } else {
                           if ($env{'form.linkprot_suggested_name_'.$i} eq '') {
                               $delsuggested{$itemid} = $currltisec{'suggested'}{$itemid}{'name'};
                           } else {
                               $env{'form.linkprot_suggested_name_'.$i} =~ s/(`)/'/g;
                               $env{'form.linkprot_suggested_info_'.$i} =~ s/(`)/'/g;
                               $newltisec{'suggested'}{$itemid}{'name'} = $env{'form.linkprot_suggested_name_'.$i};
                               $newltisec{'suggested'}{$itemid}{'info'} = $env{'form.linkprot_suggested_info_'.$i};
                               if (($currltisec{'suggested'}{$itemid}{'name'} ne $newltisec{'suggested'}{$itemid}{'name'}) ||
                                   ($currltisec{'suggested'}{$itemid}{'info'} ne $newltisec{'suggested'}{$itemid}{'info'})) {
                                   $secchanges{'suggested'}{$itemid} = 1;
                               }
                           }
                       }
                   }
               }
           }
       }
       foreach my $key (keys(%delsuggested)) {
           $newltisec{'suggested'}{$key} = $delsuggested{$key};
           $secchanges{'suggested'}{$key} = 1;
       }
       if (($env{'form.linkprot_suggested_add'}) &&
           ($env{'form.linkprot_suggested_name_add'} ne '')) {
           $env{'form.linkprot_suggested_name_add'} =~ s/(`)/'/g;
           $env{'form.linkprot_suggested_info_add'} =~ s/(`)/'/g;
           my ($newsuggid,$errormsg) = &get_lti_id($dom,$env{'form.linkprot_suggested_name_add'},'suggested');
           if ($newsuggid) {
               $newltisec{'suggested'}{$newsuggid}{'name'} = $env{'form.linkprot_suggested_name_add'};
               $newltisec{'suggested'}{$newsuggid}{'info'} = $env{'form.linkprot_suggested_info_add'};
               $secchanges{'suggested'}{$newsuggid} = 1;
           } else {
               my $error = &mt('Failed to acquire unique ID for new Link Protectors in Courses Suggestion');
               if ($errormsg) {
                   $error .= ' ('.$errormsg.')';
               }
               $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
           }
       }
     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'};
         $consumer =~ s/(`)/'/g;          $consumer =~ s/(`)/'/g;
         ($newid,my $error) = &get_lti_id($dom,$consumer);          ($newid,my $errormsg) = &get_lti_id($dom,$consumer,'lti');
         if ($newid) {          if ($newid) {
             $itemids{'add'} = $newid;              $itemids{'add'} = $newid;
             push(@items,'add');              push(@items,'add');
             $changes{$newid} = 1;              $changes{$newid} = 1;
         } else {          } else {
             my $error = &mt('Failed to acquire unique ID for new LTI configuration');              my $error = &mt('Failed to acquire unique ID for new LTI configuration');
               if ($errormsg) {
                   $error .= ' ('.$errormsg.')';
               }
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';              $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
         }          }
     }      }
Line 16128  sub modify_lti { Line 15934  sub modify_lti {
             }              }
         }          }
     }      }
       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 %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};          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','crsinc') {          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 16291  sub modify_lti { Line 16111  sub modify_lti {
             unless (($idx eq 'add') || ($changes{$itemid})) {              unless (($idx eq 'add') || ($changes{$itemid})) {
                 if ($confhash{$itemid}{'crsinc'}) {                  if ($confhash{$itemid}{'crsinc'}) {
                     foreach my $field ('mapcrs','storecrs','makecrs','section','passback','roster') {                      foreach my $field ('mapcrs','storecrs','makecrs','section','passback','roster') {
                         if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) {                          if ($currlti{$field} ne $confhash{$itemid}{$field}) {
                             $changes{$itemid} = 1;                              $changes{$itemid} = 1;
                         }                          }
                     }                      }
                     unless ($changes{$itemid}) {                      unless ($changes{$itemid}) {
                         if ($domconfig{$action}{$itemid}{'passback'} eq $confhash{$itemid}{'passback'}) {                          if ($currlti{'passback'} eq $confhash{$itemid}{'passback'}) {
                             if ($domconfig{$action}{$itemid}{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) {                              if ($currlti{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) {
                                 $changes{$itemid} = 1;                                  $changes{$itemid} = 1;
                             }                              }
                         }                          }
                     }                      }
                     foreach my $field ('mapcrstype','selfenroll') {                      foreach my $field ('mapcrstype','selfenroll') {
                         unless ($changes{$itemid}) {                          unless ($changes{$itemid}) {
                             if (ref($domconfig{$action}{$itemid}{$field}) eq 'ARRAY') {                              if (ref($currlti{$field}) eq 'ARRAY') {
                                 if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {                                  if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
                                     my @diffs = &Apache::loncommon::compare_arrays($domconfig{$action}{$itemid}{$field},                                      my @diffs = &Apache::loncommon::compare_arrays($currlti{$field},
                                                                                    $confhash{$itemid}{$field});                                                                                     $confhash{$itemid}{$field});
                                     if (@diffs) {                                      if (@diffs) {
                                         $changes{$itemid} = 1;                                          $changes{$itemid} = 1;
                                     }                                      }
                                 } elsif (@{$domconfig{$action}{$itemid}{$field}} > 0) {                                  } elsif (@{$currlti{$field}} > 0) {
                                     $changes{$itemid} = 1;                                      $changes{$itemid} = 1;
                                 }                                  }
                             } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {                              } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
Line 16322  sub modify_lti { Line 16142  sub modify_lti {
                         }                          }
                     }                      }
                     unless ($changes{$itemid}) {                      unless ($changes{$itemid}) {
                         if (ref($domconfig{$action}{$itemid}{'maproles'}) eq 'HASH') {                          if (ref($currlti{'maproles'}) eq 'HASH') {
                             if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {                              if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
                                 foreach my $ltirole (keys(%{$domconfig{$action}{$itemid}{'maproles'}})) {                                  foreach my $ltirole (keys(%{$currlti{'maproles'}})) {
                                     if ($domconfig{$action}{$itemid}{'maproles'}{$ltirole} ne                                       if ($currlti{'maproles'}{$ltirole} ne 
                                         $confhash{$itemid}{'maproles'}{$ltirole}) {                                          $confhash{$itemid}{'maproles'}{$ltirole}) {
                                         $changes{$itemid} = 1;                                          $changes{$itemid} = 1;
                                         last;                                          last;
Line 16334  sub modify_lti { Line 16154  sub modify_lti {
                                 unless ($changes{$itemid}) {                                  unless ($changes{$itemid}) {
                                     foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) {                                      foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) {
                                         if ($confhash{$itemid}{'maproles'}{$ltirole} ne                                           if ($confhash{$itemid}{'maproles'}{$ltirole} ne 
                                             $domconfig{$action}{$itemid}{'maproles'}{$ltirole}) {                                              $currlti{'maproles'}{$ltirole}) {
                                             $changes{$itemid} = 1;                                              $changes{$itemid} = 1;
                                             last;                                              last;
                                         }                                          }
                                     }                                      }
                                 }                                  }
                             } elsif (keys(%{$domconfig{$action}{$itemid}{'maproles'}}) > 0) {                              } elsif (keys(%{$currlti{'maproles'}}) > 0) {
                                 $changes{$itemid} = 1;                                  $changes{$itemid} = 1;
                             }                              }
                         } elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {                          } elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
Line 16354  sub modify_lti { Line 16174  sub modify_lti {
                 }                  }
                 unless ($changes{$itemid}) {                  unless ($changes{$itemid}) {
                     foreach my $field ('mapuser','lcauth','lcauthparm','topmenu','inlinemenu','callback') {                      foreach my $field ('mapuser','lcauth','lcauthparm','topmenu','inlinemenu','callback') {
                         if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) {                          if ($currlti{$field} ne $confhash{$itemid}{$field}) {
                             $changes{$itemid} = 1;                              $changes{$itemid} = 1;
                         }                          }
                     }                      }
                     unless ($changes{$itemid}) {                      unless ($changes{$itemid}) {
                         foreach my $field ('makeuser','lcmenu') {                          foreach my $field ('makeuser','lcmenu') {
                             if (ref($domconfig{$action}{$itemid}{$field}) eq 'ARRAY') {                              if (ref($currlti{$field}) eq 'ARRAY') {
                                 if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {                                  if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
                                     my @diffs = &Apache::loncommon::compare_arrays($domconfig{$action}{$itemid}{$field},                                      my @diffs = &Apache::loncommon::compare_arrays($currlti{$field},
                                                                                    $confhash{$itemid}{$field});                                                                                     $confhash{$itemid}{$field});
                                     if (@diffs) {                                      if (@diffs) {
                                         $changes{$itemid} = 1;                                          $changes{$itemid} = 1;
                                     }                                      }
                                 } elsif (@{$domconfig{$action}{$itemid}{$field}} > 0) {                                  } elsif (@{$currlti{$field}} > 0) {
                                     $changes{$itemid} = 1;                                      $changes{$itemid} = 1;
                                 }                                  }
                             } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {                              } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
Line 16380  sub modify_lti { Line 16200  sub modify_lti {
                 }                  }
             }              }
         }          }
           if ($is_home) {
               my $keyitem = 'form.lti_key_'.$idx;
               $env{$keyitem} =~ s/(`)/'/g;
               if ($env{$keyitem} ne '') {
                   $ltienc{$itemid}{'key'} = $env{$keyitem};
                   unless ($changes{$itemid}) {
                       if ($currlti{'key'} ne $env{$keyitem}) {
                           $changes{$itemid} = 1;
                       }
                   }
               }
               my $secretitem = 'form.lti_secret_'.$idx;
               $env{$secretitem} =~ s/(`)/'/g;
               if ($currlti{'usable'}) {
                   if ($env{'form.lti_changesecret_'.$idx}) {
                       if ($env{$secretitem} ne '') {
                           if ($privnum && $cipher) {
                               $ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
                               $confhash{$itemid}{'cipher'} = $privnum;
                           } else {
                               $ltienc{$itemid}{'secret'} = $env{$secretitem};
                           }
                           $changes{$itemid} = 1;
                       }
                   } else {
                       $ltienc{$itemid}{'secret'} = $currlti{'secret'};
                       $confhash{$itemid}{'cipher'} = $currlti{'cipher'};
                   }
                   if (ref($ltienc{$itemid}) eq 'HASH') {
                       if (($ltienc{$itemid}{'key'} ne '') && ($ltienc{$itemid}{'secret'} ne '')) {
                           $confhash{$itemid}{'usable'} = 1;
                       }
                   }
               } elsif ($env{$secretitem} ne '') {
                   if ($privnum && $cipher) {
                       $ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
                       $confhash{$itemid}{'cipher'} = $privnum;
                   } else {
                       $ltienc{$itemid}{'secret'} = $env{$secretitem};
                   }
                   if (ref($ltienc{$itemid}) eq 'HASH') {
                       if (($ltienc{$itemid}{'key'} ne '') && ($ltienc{$itemid}{'key'} ne '')) {
                           $confhash{$itemid}{'usable'} = 1;
                       }
                   }
                   $changes{$itemid} = 1;
               }
           }
           unless ($changes{$itemid}) {
               foreach my $key (keys(%currlti)) {
                   if (ref($currlti{$key}) eq 'HASH') {
                       if (ref($confhash{$itemid}{$key}) eq 'HASH') {
                           foreach my $innerkey (keys(%{$currlti{$key}})) {
                               unless (exists($confhash{$itemid}{$key}{$innerkey})) {
                                   $changes{$itemid} = 1;
                                   last;
                               }
                           }
                       } elsif (keys(%{$currlti{$key}}) > 0) {
                           $changes{$itemid} = 1;
                       }
                   }
                   last if ($changes{$itemid});
               }
           }
     }      }
     if (@allpos > 0) {      if (@allpos > 0) {
         my $idx = 0;          my $idx = 0;
Line 16397  sub modify_lti { Line 16282  sub modify_lti {
             }              }
         }          }
     }      }
   
       if ((keys(%changes) == 0) && (keys(%secchanges) == 0)) {
           return &mt('No changes made.');
       }
   
     my %ltihash = (      my %ltihash = (
                       $action => { %confhash }                        $action => { %confhash }
                   );                    );
     my %ltienchash = (      my %ltienchash;
                          $action => { %encconfig }  
                      );      if ($is_home) {
           %ltienchash = (
                            $action => { %ltienc }
                         );
       }
     if (keys(%secchanges)) {      if (keys(%secchanges)) {
         $ltihash{'ltisec'} = \%newltisec;          $ltihash{'ltisec'} = \%newltisec;
         if ($secchanges{'linkprot'}) {          if ($secchanges{'linkprot'}) {
Line 16413  sub modify_lti { Line 16307  sub modify_lti {
     }      }
     my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,$dom);      my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,$dom);
     if ($putresult eq 'ok') {      if ($putresult eq 'ok') {
         my %keystore;          if (keys(%ltienchash)) {
         if (keys(%secchanges)) {              &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1);
             if ($secchanges{'private'}) {  
                 my $who = &escape($env{'user.name'}.':'.$env{'user.domain'});  
                 foreach my $hostid (keys(%newkeyset)) {  
                     my $storehash = {  
                                        key => $newkeyset{$hostid},  
                                        who => $env{'user.name'}.':'.$env{'user.domain'},  
                                     };  
                     $keystore{$hostid} = &Apache::lonnet::store_dom($storehash,'lti','private',  
                                                                     $dom,$hostid);  
                 }  
             }  
             if (ref($lastactref) eq 'HASH') {  
                 if (($secchanges{'encrypt'}) || ($secchanges{'private'})) {  
                     $lastactref->{'domdefaults'} = 1;  
                 }  
             }  
         }  
         &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1);  
         if ((keys(%changes) == 0) && (keys(%secchanges) == 0)) {  
             return &mt('No changes made.');  
         }          }
         $resulttext = &mt('Changes made:').'<ul>';          $resulttext = &mt('Changes made:').'<ul>';
         if (keys(%secchanges) > 0) {          if (keys(%secchanges) > 0) {
             foreach my $item (keys(%secchanges)) {              $resulttext .= &lti_security_results($dom,'lti',\%secchanges,\%newltisec,\%newkeyset,\%keystore);
                 if ($item eq 'encrypt') {              if (exists($secchanges{'linkprot'})) {
                     my %encrypted = (                  $resulttext .= $linkprotoutput;
                               crs  => {  
                                         on => &mt('Encryption of stored link protection secrets defined in courses enabled'),  
                                         off => &mt('Encryption of stored link protection secrets defined in courses disabled'),  
                                       },  
                               dom => {  
                                        on => &mt('Encryption of stored link protection secrets defined in domain enabled'),  
                                        off => &mt('Encryption of stored link protection secrets defined in domain disabled'),  
                                      },  
                               consumers => {  
                                              on => &mt('Encryption of stored consumer secrets defined in domain enabled'),  
                                              off => &mt('Encryption of stored consumer secrets defined in domain disabled'),  
                                            },  
                             );  
                     foreach my $type ('crs','dom','consumers') {  
                         my $shown = $encrypted{$type}{'off'};  
                         if (ref($newltisec{$item}) eq 'HASH') {  
                             if ($newltisec{$item}{$type}) {  
                                 $shown = $encrypted{$type}{'on'};   
                             }  
                         }  
                         $resulttext .= '<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 ($newltisec{rules}{$rule} eq '') {  
                              if ($rule eq 'min') {  
                                  $resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule});  
                                                 ' '.&mt('Default of [_1] will be used',  
                                                             $Apache::lonnet::passwdmin).'</li>';  
                              } else {  
                                  $resulttext .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>';  
                              }  
                          } else {  
                              $resulttext .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$newltisec{rules}{$rule}).'</li>';  
                          }  
                      }  
                      if (ref($newltisec{'rules'}{'chars'}) eq 'ARRAY') {  
                          if (@{$newltisec{'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{$_} } @{$newltisec{'rules'}{'chars'}}).  
                                           '</li></ul>';  
                              $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>';  
                          } else {  
                              $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';  
                          }  
                      } else {  
                          $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';  
                      }  
                 } elsif ($item eq 'private') {  
                     if (keys(%newkeyset)) {  
                         foreach my $hostid (sort(keys(%newkeyset))) {  
                             if ($keystore{$hostid} eq 'ok') {  
                                 $resulttext .= '<li>'.&mt('Encryption key for storage of shared secrets saved for [_1]',$hostid).'</li>';  
                             }  
                         }  
                     }  
                 } elsif ($item eq '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;
             }              }
             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>';  
                 } else {  
                     $resulttext .= '<li><b>'.$confhash{$itemid}{'consumer'}.'</b><ul>';                      $resulttext .= '<li><b>'.$confhash{$itemid}{'consumer'}.'</b><ul>';
                     my $position = $pos + 1;                      my $position = $pos + 1;
                     $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';                      $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';
Line 16545  sub modify_lti { Line 16341  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'}) {                          if ($confhash{$itemid}{'callback'}) {
Line 16703  sub modify_lti { Line 16497  sub modify_lti {
                     $resulttext .= '</ul></li>';                      $resulttext .= '</ul></li>';
                 }                  }
             }              }
               if (keys(%deletions)) {
                   foreach my $itemid (sort { $a <=> $b } keys(%deletions)) {
                       $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';
                   }
               }
         }          }
         $resulttext .= '</ul>';          $resulttext .= '</ul>';
           if (ref($lastactref) eq 'HASH') {
               if (($secchanges{'encrypt'}) || ($secchanges{'private'}) || (exists($secchanges{'suggested'}))) {
                   &Apache::lonnet::get_domain_defaults($dom,1);
                   $lastactref->{'domdefaults'} = 1;
               }
           }
     } else {      } else {
         $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';          $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';
     }      }
Line 16715  sub modify_lti { Line 16520  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,$dbname) = @_;
     # get lock on lti db      unless (($dbname eq 'lti') || ($dbname eq 'suggested')) {
           return ('','invalid db');
       }
       # get lock on db
     my $lockhash = {      my $lockhash = {
                       lock => $env{'user.name'}.                        lock => $env{'user.name'}.
                               ':'.$env{'user.domain'},                                ':'.$env{'user.domain'},
                    };                     };
     my $tries = 0;      my $tries = 0;
     my $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);      my $gotlock = &Apache::lonnet::newput_dom($dbname,$lockhash,$domain);
     my ($id,$error);      my ($id,$error);
   
     while (($gotlock ne 'ok') && ($tries<10)) {      while (($gotlock ne 'ok') && ($tries<10)) {
         $tries ++;          $tries ++;
         sleep (0.1);          sleep (0.1);
         $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);          $gotlock = &Apache::lonnet::newput_dom($dbname,$lockhash,$domain);
     }      }
     if ($gotlock eq 'ok') {      if ($gotlock eq 'ok') {
         my %currids = &Apache::lonnet::dump_dom('lti',$domain);          my %currids = &Apache::lonnet::dump_dom($dbname,$domain);
         if ($currids{'lock'}) {          if ($currids{'lock'}) {
             delete($currids{'lock'});              delete($currids{'lock'});
             if (keys(%currids)) {              if (keys(%currids)) {
Line 16744  sub get_lti_id { Line 16576  sub get_lti_id {
                 $id = 1;                  $id = 1;
             }              }
             if ($id) {              if ($id) {
                 unless (&Apache::lonnet::newput_dom('lti',{ $id => $consumer },$domain) eq 'ok') {                  unless (&Apache::lonnet::newput_dom($dbname,{ $id => $consumer },$domain) eq 'ok') {
                     $error = 'nostore';                      $error = 'nostore';
                 }                  }
             } else {              } else {
                 $error = 'nonumber';                  $error = 'nonumber';
             }              }
         }          }
         my $dellockoutcome = &Apache::lonnet::del_dom('lti',['lock'],$domain);          my $dellockoutcome = &Apache::lonnet::del_dom($dbname,['lock'],$domain);
     } else {      } else {
         $error = 'nolock';          $error = 'nolock';
     }      }
Line 17517  sub modify_contacts { Line 17349  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 17575  sub modify_contacts { Line 17407  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 17597  sub modify_contacts { Line 17429  sub modify_contacts {
                 }                  }
             } else {              } else {
                 foreach my $key (@overrides) {                  foreach my $key (@overrides) {
                     push(@{$changes{'overrides'}},$key);                       push(@{$changes{'overrides'}},$key);
                 }                  }
             }              }
         }          }
Line 17779  sub modify_contacts { Line 17611  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 17803  sub modify_contacts { Line 17635  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 17973  sub modify_contacts { Line 17805  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 18208  sub modify_privacy { Line 18040  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 18394  sub modify_passwords { Line 18249  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 18647  sub modify_passwords { Line 18505  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 18720  sub password_rule_changes { Line 18578  sub password_rule_changes {
     my (@rules,%staticdefaults);      my (@rules,%staticdefaults);
     if ($prefix eq 'passwords') {      if ($prefix eq 'passwords') {
         @rules = ('min','max','expire','numsaved');          @rules = ('min','max','expire','numsaved');
     } elsif ($prefix eq 'secrets') {      } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {
         @rules = ('min','max');          @rules = ('min','max');
     }      }
     $staticdefaults{'min'} = $Apache::lonnet::passwdmin;      $staticdefaults{'min'} = $Apache::lonnet::passwdmin;
Line 19130  sub modify_selfcreation { Line 18988  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 19142  sub modify_selfcreation { Line 19000  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 19569  sub modify_selfcreation { Line 19427  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 19655  sub modify_selfcreation { Line 19513  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 19673  sub modify_selfcreation { Line 19531  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 19777  sub modify_selfcreation { Line 19635  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 20122  sub modify_defaults { Line 19980  sub modify_defaults {
         }          }
         if ($item eq 'portal_def') {          if ($item eq 'portal_def') {
             unless (grep(/^\Q$item\E$/,@errors)) {              unless (grep(/^\Q$item\E$/,@errors)) {
                 if ($newvalues{$item} eq '') {                   if ($newvalues{$item} eq '') {
                     foreach my $field ('email','web') {                      foreach my $field ('email','web') {
                         if (exists($domdefaults{$item.'_'.$field})) {                          if (exists($domdefaults{$item.'_'.$field})) {
                             delete($domdefaults{$item.'_'.$field});                              delete($domdefaults{$item.'_'.$field});
Line 20307  sub modify_defaults { Line 20165  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') {                  } elsif ($item eq 'unamemap_rule') {
Line 20414  sub modify_scantron { Line 20272  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 21339  sub modify_coursedefaults { Line 21200  sub modify_coursedefaults {
     my @toggles = ('canuse_pdfforms','uselcmath','usejsme','inline_chem','ltiauth');      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,
                              crsauthor            => 1,
                          );                           );
     my %texoptions = (      my %texoptions = (
                         MathJax  => 'MathJax',                          MathJax  => 'MathJax',
Line 21391  sub modify_coursedefaults { Line 21257  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 21403  sub modify_coursedefaults { Line 21269  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 21538  sub modify_coursedefaults { Line 21404  sub modify_coursedefaults {
                 $changes{'postsubmit'} = 1;                  $changes{'postsubmit'} = 1;
             }              }
         }          }
           my (%newdomexttool,%newexttool,%newcrsauthor,%olddomexttool,%oldexttool,%oldcrsauthor);
           map { $newdomexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.domexttool');
           map { $newexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.exttool');
           map { $newcrsauthor{$_} = 1; } &Apache::loncommon::get_env_multiple('form.crsauthor');
           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;
                  }
               }
           }
           if (ref($domconfig{'coursedefaults'}{'crsauthor'}) eq 'HASH') {
               %oldcrsauthor = %{$domconfig{'coursedefaults'}{'crsauthor'}};
           } else {
               foreach my $type (@types) {
                  if ($staticdefaults{'crsauthor'}) {
                      $oldcrsauthor{$type} = 1;
                  } else {
                      $oldcrsauthor{$type} = 0;
                  }
               }
           }
           foreach my $type (@types) {
               unless ($newdomexttool{$type}) {
                   $newdomexttool{$type} = 0;
               }
               unless ($newexttool{$type}) {
                   $newexttool{$type} = 0;
               }
               unless ($newcrsauthor{$type}) {
                   $newcrsauthor{$type} = 0;
               }
               if ($newdomexttool{$type} != $olddomexttool{$type}) {
                   $changes{'domexttool'} = 1;
               }
               if ($newexttool{$type} != $oldexttool{$type}) {
                   $changes{'exttool'} = 1;
               }
               if ($newcrsauthor{$type} != $oldcrsauthor{$type}) {
                   $changes{'crsauthor'} = 1;
               }
           }
           $defaultshash{'coursedefaults'}{'domexttool'} = \%newdomexttool;
           $defaultshash{'coursedefaults'}{'exttool'} = \%newexttool;
           $defaultshash{'coursedefaults'}{'crsauthor'} = \%newcrsauthor;
     }      }
     my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,      my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                              $dom);                                               $dom);
Line 21547  sub modify_coursedefaults { Line 21473  sub modify_coursedefaults {
             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'}) ||
                 ($changes{'inline_chem'}) || ($changes{'ltiauth'})) {                  ($changes{'inline_chem'}) || ($changes{'ltiauth'}) || ($changes{'domexttool'}) ||
                 foreach my $item ('canuse_pdfforms','uselcmath','usejsme','inline_chem','texengine','ltiauth') {                  ($changes{'exttool'}) || ($changes{'coursequota'}) || ($changes{'crsauthor'})) {
                   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 21579  sub modify_coursedefaults { Line 21507  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 21591  sub modify_coursedefaults { Line 21526  sub modify_coursedefaults {
                         $domdefaults{'canclone'}=$defaultshash{'coursedefaults'}{'canclone'};                          $domdefaults{'canclone'}=$defaultshash{'coursedefaults'}{'canclone'};
                     }                      }
                 }                  }
                   if ($changes{'domexttool'}) {
                       if (ref($defaultshash{'coursedefaults'}{'domexttool'}) eq 'HASH') {
                           foreach my $type (@types) {
                               $domdefaults{$type.'domexttool'}=$defaultshash{'coursedefaults'}{'domexttool'}{$type};
                           }
                       }
                   }
                   if ($changes{'exttool'}) {
                       if (ref($defaultshash{'coursedefaults'}{'exttool'}) eq 'HASH') {
                           foreach my $type (@types) {
                               $domdefaults{$type.'exttool'}=$defaultshash{'coursedefaults'}{'exttool'}{$type};
                           }
                       }
                   }
                   if ($changes{'crsauthor'}) {
                       if (ref($defaultshash{'coursedefaults'}{'crsauthor'}) eq 'HASH') {
                           foreach my $type (@types) {
                               $domdefaults{$type.'crsauthor'}=$defaultshash{'coursedefaults'}{'crsauthor'}{$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 21643  sub modify_coursedefaults { Line 21599  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 21728  sub modify_coursedefaults { Line 21697  sub modify_coursedefaults {
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('LTI launch of deep-linked URL will require re-authentication').'</li>';                          $resulttext .= '<li>'.&mt('LTI launch of deep-linked URL will require re-authentication').'</li>';
                     }                      }
                   } elsif (($item eq 'domexttool') || ($item eq 'exttool') || ($item eq 'crsauthor')) {
                       my @noyes = (&mt('no'),&mt('yes'));
                       my %status = (
                                      domexttool => {
                                                     ishash => &mt('External Tools defined in the domain may be used as follows:'), 
                                                     default => &mt('External Tools defined in the domain may be used in all course types, by default'),
                                                    },
                                      exttool => {
                                                     ishash => &mt('External Tools can be defined and configured in course containers as follows:'),
                                                     default => &mt('External Tools can not be defined in any course types, by default'),
                                                 },
                                      crsauthor => {
                                                     ishash => &mt('Standard Problems can be created within course containers as follows:'),
                                                     default => &mt('Standard Problems can be created within any course type, by default'),
                                                   },
                                    );
                                      
                       if (ref($defaultshash{'coursedefaults'}{$item}) eq 'HASH') {
                           $resulttext .= '<li>'.$status{$item}{'ishash'}.'<ul>'.
                                          '<li>'.&mt('Official courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'official'}].'</b>').'</li>'.
                                          '<li>'.&mt('Unofficial courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'unofficial'}].'</b>').'</li>'.
                                          '<li>'.&mt('Textbook courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'textbook'}].'</b>').'</li>'.
                                          '<li>'.&mt('Placement tests: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'placement'}].'</b>').'</li>'.
                                          '<li>'.&mt('Communities: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'community'}].'</b>').'</li>'.
                                          '</ul>'.
                                          '</li>';
                       } else {
                           $resulttext .= '<li>'.$status{$item}{'default'}.'</li>';
                       }
                 }                  }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
Line 22121  sub modify_wafproxy { Line 22119  sub modify_wafproxy {
                 }                  }
             } elsif ($currvalue{$item}) {              } elsif ($currvalue{$item}) {
                 $changes{$item} = 1;                  $changes{$item} = 1;
             }               }
         }          }
     } else {      } else {
         if (keys(%curralias)) {          if (keys(%curralias)) {
Line 22129  sub modify_wafproxy { Line 22127  sub modify_wafproxy {
         }          }
         if (keys(%currsaml)) {          if (keys(%currsaml)) {
             $changes{'saml'} = 1;              $changes{'saml'} = 1;
         }           }
         if (keys(%currvalue)) {          if (keys(%currvalue)) {
             foreach my $key (keys(%currvalue)) {              foreach my $key (keys(%currvalue)) {
                 $changes{$key} = 1;                  $changes{$key} = 1;
Line 22139  sub modify_wafproxy { Line 22137  sub modify_wafproxy {
     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') {
Line 22155  sub modify_wafproxy { Line 22153  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 22222  sub modify_wafproxy { Line 22220  sub modify_wafproxy {
                             $output .= '<li>'.&mt('Aliases deleted for hostnames').'</li>';                              $output .= '<li>'.&mt('Aliases deleted for hostnames').'</li>';
                         }                          }
                     } elsif ($item eq 'saml') {                      } elsif ($item eq 'saml') {
                         my $shown;                           my $shown;
                         if (ref($wafproxy{'saml'}) eq 'HASH') {                          if (ref($wafproxy{'saml'}) eq 'HASH') {
                             if (keys(%{$wafproxy{'saml'}})) {                              if (keys(%{$wafproxy{'saml'}})) {
                                 $shown = join(', ',sort(keys(%{$wafproxy{'saml'}})));                                  $shown = join(', ',sort(keys(%{$wafproxy{'saml'}})));
Line 22286  sub modify_wafproxy { Line 22284  sub modify_wafproxy {
                     }                      }
                 }                  }
             }              }
               $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 22551  sub modify_usersessions { Line 22550  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 23089  sub modify_loadbalancing { Line 23088  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 23775  function balancerChange(balnum,baltotal, Line 23774  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);

Removed from v.1.419  
changed lines
  Added in v.1.437


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