Diff for /loncom/interface/domainprefs.pm between versions 1.258 and 1.367

version 1.258, 2015/03/13 13:30:19 version 1.367, 2019/08/25 14:15:20
Line 19 Line 19
 #  #
 # You should have received a copy of the GNU General Public License  # You should have received a copy of the GNU General Public License
 # along with LON-CAPA; if not, write to the Free Software  # along with LON-CAPA; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA#  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   #
 # /home/httpd/html/adm/gpl.txt  # /home/httpd/html/adm/gpl.txt
 #  #
 # http://www.lon-capa.org/  # http://www.lon-capa.org/
 #  #
 #  #
 ###############################################################  ###############################################################
 ##############################################################  ###############################################################
   
 =pod  =pod
   
Line 103  $datatable  - HTML containing form eleme Line 104  $datatable  - HTML containing form eleme
   
 In the case of course requests, radio buttons are displayed for each institutional  In the case of course requests, radio buttons are displayed for each institutional
 affiliate type (and also default, and _LC_adv) for each of the course types   affiliate type (and also default, and _LC_adv) for each of the course types 
 (official, unofficial, community, and textbook).  In each case the radio buttons   (official, unofficial, community, textbook, placement, and lti).  
 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 169  use Apache::loncoursequeueadmin(); Line 170  use Apache::loncoursequeueadmin();
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
 use LONCAPA::Enrollment;  use LONCAPA::Enrollment;
 use LONCAPA::lonauthcgi();  use LONCAPA::lonauthcgi();
   use LONCAPA::SSL;
 use File::Copy;  use File::Copy;
 use Locale::Language;  use Locale::Language;
 use DateTime::TimeZone;  use DateTime::TimeZone;
 use DateTime::Locale;  use DateTime::Locale;
   use Time::HiRes qw( sleep );
   
 my $registered_cleanup;  my $registered_cleanup;
 my $modified_urls;  my $modified_urls;
Line 215  sub handler { Line 218  sub handler {
                 'contacts','defaults','scantron','coursecategories',                  'contacts','defaults','scantron','coursecategories',
                 'serverstatuses','requestcourses','helpsettings',                  'serverstatuses','requestcourses','helpsettings',
                 'coursedefaults','usersessions','loadbalancing',                  'coursedefaults','usersessions','loadbalancing',
                 'requestauthor','selfenrollment','inststatus'],$dom);                  'requestauthor','selfenrollment','inststatus',
     my @prefs_order = ('rolecolors','login','defaults','quotas','autoenroll',                  'ltitools','ssl','trust','lti','privacy','passwords'],$dom);
                        'autoupdate','autocreate','directorysrch','contacts',      my %encconfig =
           &Apache::lonnet::get_dom('encconfig',['ltitools','lti'],$dom);
       if (ref($domconfig{'ltitools'}) eq 'HASH') {
           if (ref($encconfig{'ltitools'}) eq 'HASH') {
               foreach my $id (keys(%{$domconfig{'ltitools'}})) {
                   if ((ref($domconfig{'ltitools'}{$id}) eq 'HASH') &&
                       (ref($encconfig{'ltitools'}{$id}) eq 'HASH')) {
                       foreach my $item ('key','secret') {
                           $domconfig{'ltitools'}{$id}{$item} = $encconfig{'ltitools'}{$id}{$item};
                       }
                   }
               }
           }
       }
       if (ref($domconfig{'lti'}) eq 'HASH') {
           if (ref($encconfig{'lti'}) eq 'HASH') {
               foreach my $id (keys(%{$domconfig{'lti'}})) {
                   if ((ref($domconfig{'lti'}{$id}) eq 'HASH') &&
                       (ref($encconfig{'lti'}{$id}) eq 'HASH')) {
                       foreach my $item ('key','secret') {
                           $domconfig{'lti'}{$id}{$item} = $encconfig{'lti'}{$id}{$item};
                       }
                   }
               }
           }
       }
       my @prefs_order = ('rolecolors','login','defaults','passwords','quotas','autoenroll',
                          'autoupdate','autocreate','directorysrch','contacts','privacy',
                        'usercreation','selfcreation','usermodification','scantron',                         'usercreation','selfcreation','usermodification','scantron',
                        'requestcourses','requestauthor','coursecategories',                         'requestcourses','requestauthor','coursecategories',
                        'serverstatuses','helpsettings',                         'serverstatuses','helpsettings','coursedefaults',
                        'coursedefaults','selfenrollment','usersessions');                         'ltitools','selfenrollment','usersessions','ssl','trust','lti');
     my %existing;      my %existing;
     if (ref($domconfig{'loadbalancing'}) eq 'HASH') {      if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
         %existing = %{$domconfig{'loadbalancing'}};          %existing = %{$domconfig{'loadbalancing'}};
Line 262  sub handler { Line 292  sub handler {
                       header => [{col1 => 'Setting',                        header => [{col1 => 'Setting',
                                   col2 => 'Value'},                                    col2 => 'Value'},
                                  {col1 => 'Institutional user types',                                   {col1 => 'Institutional user types',
                                   col2 => 'Assignable to e-mail usernames'}],                                    col2 => 'Name displayed'}],
                       print => \&print_defaults,                        print => \&print_defaults,
                       modify => \&modify_defaults,                        modify => \&modify_defaults,
                     },                      },
           'passwords' =>
                       { text => 'Passwords (Internal authentication)',
                         help => 'Domain_Configuration_Passwords',
                         header => [{col1 => 'Resetting Forgotten Password',
                                     col2 => 'Settings'},
                                    {col1 => 'Encryption of Stored Passwords (Internal Auth)',
                                     col2 => 'Settings'},
                                    {col1 => 'Rules for LON-CAPA Passwords',
                                     col2 => 'Settings'},
                                    {col1 => 'Course Owner Changing Student Passwords',
                                     col2 => 'Settings'}],
                         print => \&print_passwords,
                         modify => \&modify_passwords,
                       },
         'quotas' =>           'quotas' => 
                     { text => 'Blogs, personal web pages, webDAV/quotas, portfolios',                      { text => 'Blogs, personal web pages, webDAV/quotas, portfolios',
                       help => 'Domain_Configuration_Quotas',                        help => 'Domain_Configuration_Quotas',
Line 304  sub handler { Line 348  sub handler {
                      modify => \&modify_autocreate,                       modify => \&modify_autocreate,
                   },                    },
         'directorysrch' =>           'directorysrch' => 
                   { text => 'Institutional directory searches',                    { text => 'Directory searches',
                     help => 'Domain_Configuration_InstDirectory_Search',                      help => 'Domain_Configuration_InstDirectory_Search',
                     header => [{col1 => 'Setting',                      header => [{col1 => 'Institutional Directory Setting',
                                   col2 => 'Value',},
                                  {col1 => 'LON-CAPA Directory Setting',
                                 col2 => 'Value',}],                                  col2 => 'Value',}],
                     print => \&print_directorysrch,                      print => \&print_directorysrch,
                     modify => \&modify_directorysrch,                      modify => \&modify_directorysrch,
                   },                    },
         'contacts' =>          'contacts' =>
                   { text => 'Contact Information',                    { text => 'E-mail addresses and helpform',
                     help => 'Domain_Configuration_Contact_Info',                      help => 'Domain_Configuration_Contact_Info',
                     header => [{col1 => 'Setting',                      header => [{col1 => 'Default e-mail addresses',
                                 col2 => 'Value',}],                                  col2 => 'Value',},
                                  {col1 => 'Recipient(s) for notifications',
                                   col2 => 'Value',},
                                  {col1 => 'Nightly status check e-mail',
                                   col2 => 'Settings',},
                                  {col1 => 'Ask helpdesk form settings',
                                   col2 => 'Value',},],
                     print => \&print_contacts,                      print => \&print_contacts,
                     modify => \&modify_contacts,                      modify => \&modify_contacts,
                   },                    },
Line 338  sub handler { Line 390  sub handler {
                                 col2 => 'Enabled?'},                                  col2 => 'Enabled?'},
                                {col1 => 'Institutional user type (login/SSO self-creation)',                                 {col1 => 'Institutional user type (login/SSO self-creation)',
                                 col2 => 'Information user can enter'},                                  col2 => 'Information user can enter'},
                                {col1 => 'Self-creation with e-mail as username',                                 {col1 => 'Self-creation with e-mail verification',
                                 col2 => 'Settings'}],                                  col2 => 'Settings'}],
                     print => \&print_selfcreation,                      print => \&print_selfcreation,
                     modify => \&modify_selfcreation,                      modify => \&modify_selfcreation,
Line 354  sub handler { Line 406  sub handler {
                     modify => \&modify_usermodification,                      modify => \&modify_usermodification,
                   },                    },
         'scantron' =>          'scantron' =>
                   { text => 'Bubblesheet format file',                    { text => 'Bubblesheet format',
                     help => 'Domain_Configuration_Scantron_Format',                      help => 'Domain_Configuration_Scantron_Format',
                     header => [ {col1 => 'Item',                      header => [ {col1 => 'Bubblesheet format file',
                                  col2 => '',                                   col2 => ''},
                               }],                                  {col1 => 'Bubblesheet data upload formats',
                                    col2 => 'Settings'}],
                     print => \&print_scantron,                      print => \&print_scantron,
                     modify => \&modify_scantron,                      modify => \&modify_scantron,
                   },                    },
Line 412  sub handler { Line 465  sub handler {
                   modify => \&modify_serverstatuses,                    modify => \&modify_serverstatuses,
                  },                   },
         'helpsettings' =>          'helpsettings' =>
                  {text   => 'Help page settings',                   {text   => 'Support settings',
                   help   => 'Domain_Configuration_Help_Settings',                    help   => 'Domain_Configuration_Help_Settings',
                   header => [{col1 => 'Help Settings (logged-in users)',                    header => [{col1 => 'Help Page Settings (logged-in users)',
                               col2 => 'Value'}],                                col2 => 'Value'},
                                {col1 => 'Helpdesk Roles',
                                 col2 => 'Settings'},],
                   print  => \&print_helpsettings,                    print  => \&print_helpsettings,
                   modify => \&modify_helpsettings,                    modify => \&modify_helpsettings,
                  },                   },
Line 442  sub handler { Line 497  sub handler {
                   modify => \&modify_selfenrollment,                    modify => \&modify_selfenrollment,
                  },                   },
         'privacy' =>           'privacy' => 
                  {text   => 'User Privacy',                   {text   => 'Availability of User Information',
                   help   => 'Domain_Configuration_User_Privacy',                    help   => 'Domain_Configuration_User_Privacy',
                   header => [{col1 => 'Setting',                    header => [{col1 => 'Role assigned in different domain',
                               col2 => 'Value',}],                                col2 => 'Approval options'},
                                {col1 => 'Role assigned in different domain to user of type',
                                 col2 => 'User information available in that domain'},
                                {col1 => "Role assigned in user's domain",
                                 col2 => 'Information viewable by privileged user'},
                                {col1 => "Role assigned in user's domain",
                                 col2 => 'Information viewable by unprivileged user'}],
                   print => \&print_privacy,                    print => \&print_privacy,
                   modify => \&modify_privacy,                    modify => \&modify_privacy,
                  },                   },
Line 461  sub handler { Line 522  sub handler {
                   print => \&print_usersessions,                    print => \&print_usersessions,
                   modify => \&modify_usersessions,                    modify => \&modify_usersessions,
                  },                   },
          'loadbalancing' =>          'loadbalancing' =>
                  {text  => 'Dedicated Load Balancer(s)',                   {text  => 'Dedicated Load Balancer(s)',
                   help  => 'Domain_Configuration_Load_Balancing',                    help  => 'Domain_Configuration_Load_Balancing',
                   header => [{col1 => 'Balancers',                    header => [{col1 => 'Balancers',
Line 472  sub handler { Line 533  sub handler {
                   print => \&print_loadbalancing,                    print => \&print_loadbalancing,
                   modify => \&modify_loadbalancing,                    modify => \&modify_loadbalancing,
                  },                   },
           'ltitools' => 
                    {text => 'External Tools (LTI)',
                     help => 'Domain_Configuration_LTI_Tools',
                     header => [{col1 => 'Setting',
                                 col2 => 'Value',}],
                     print => \&print_ltitools,
                     modify => \&modify_ltitools,
                    },
           'ssl' =>
                    {text  => 'LON-CAPA Network (SSL)',
                     help  => 'Domain_Configuration_Network_SSL',
                     header => [{col1 => 'Server',
                                 col2 => 'Certificate Status'},
                                {col1 => 'Connections to other servers',
                                 col2 => 'Rules'},
                                {col1 => 'Connections from other servers',
                                 col2 => 'Rules'},
                                {col1 => "Replicating domain's published content",
                                 col2 => 'Rules'}],
                     print => \&print_ssl,
                     modify => \&modify_ssl,
                    },
           'trust' =>
                    {text   => 'Trust Settings',
                     help   => 'Domain_Configuration_Trust',
                     header => [{col1 => "Access to this domain's content by others",
                                 col2 => 'Rules'},
                                {col1 => "Access to other domain's content by this domain",
                                 col2 => 'Rules'},
                                {col1 => "Enrollment in this domain's courses by others",
                                 col2 => 'Rules',},
                                {col1 => "Co-author roles in this domain for others",
                                 col2 => 'Rules',},
                                {col1 => "Co-author roles for this domain's users elsewhere",
                                 col2 => 'Rules',},
                                {col1 => "Domain roles in this domain assignable to others",
                                 col2 => 'Rules'},
                                {col1 => "Course catalog for this domain displayed elsewhere",
                                 col2 => 'Rules'},
                                {col1 => "Requests for creation of courses in this domain by others",
                                 col2 => 'Rules'},
                                {col1 => "Users in other domains can send messages to this domain",
                                 col2 => 'Rules'},],
                     print => \&print_trust,
                     modify => \&modify_trust,
                    },
             'lti' =>
                    {text => 'LTI Provider',
                     help => 'Domain_Configuration_LTI_Provider',
                     header => [{col1 => 'Setting',
                                 col2 => 'Value',}],
                     print => \&print_lti,
                     modify => \&modify_lti,
                    },
     );      );
     if (keys(%servers) > 1) {      if (keys(%servers) > 1) {
         $prefs{'login'}  = { text   => 'Log-in page options',          $prefs{'login'}  = { text   => 'Log-in page options',
Line 525  $javascript_validations Line 640  $javascript_validations
 $coursebrowserjs  $coursebrowserjs
 END  END
         }          }
           if (grep(/^selfcreation$/,@actions)) {
               $js .= &selfcreate_javascript();
           }
           if (grep(/^contacts$/,@actions)) {
               $js .= &contacts_javascript();
           }
           if (grep(/^scantron$/,@actions)) {
               $js .= &scantron_javascript();
           }
         &Apache::lonconfigsettings::display_settings($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname,$js);          &Apache::lonconfigsettings::display_settings($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname,$js);
     } else {      } else {
 # check if domconfig user exists for the domain.  # check if domconfig user exists for the domain.
Line 614  sub process_changes { Line 738  sub process_changes {
     } elsif ($action eq 'autocreate') {      } elsif ($action eq 'autocreate') {
         $output = &modify_autocreate($dom,%domconfig);          $output = &modify_autocreate($dom,%domconfig);
     } elsif ($action eq 'directorysrch') {      } elsif ($action eq 'directorysrch') {
         $output = &modify_directorysrch($dom,%domconfig);          $output = &modify_directorysrch($dom,$lastactref,%domconfig);
     } elsif ($action eq 'usercreation') {      } elsif ($action eq 'usercreation') {
         $output = &modify_usercreation($dom,%domconfig);          $output = &modify_usercreation($dom,%domconfig);
     } elsif ($action eq 'selfcreation') {      } elsif ($action eq 'selfcreation') {
         $output = &modify_selfcreation($dom,%domconfig);          $output = &modify_selfcreation($dom,$lastactref,%domconfig);
     } elsif ($action eq 'usermodification') {      } elsif ($action eq 'usermodification') {
         $output = &modify_usermodification($dom,%domconfig);          $output = &modify_usermodification($dom,%domconfig);
     } elsif ($action eq 'contacts') {      } elsif ($action eq 'contacts') {
Line 636  sub process_changes { Line 760  sub process_changes {
     } elsif ($action eq 'requestauthor') {      } elsif ($action eq 'requestauthor') {
         $output = &modify_quotas($r,$dom,$action,$lastactref,%domconfig);          $output = &modify_quotas($r,$dom,$action,$lastactref,%domconfig);
     } elsif ($action eq 'helpsettings') {      } elsif ($action eq 'helpsettings') {
         $output = &modify_helpsettings($r,$dom,$confname,%domconfig);          $output = &modify_helpsettings($r,$dom,$confname,$lastactref,%domconfig);
     } elsif ($action eq 'coursedefaults') {      } elsif ($action eq 'coursedefaults') {
         $output = &modify_coursedefaults($dom,$lastactref,%domconfig);          $output = &modify_coursedefaults($dom,$lastactref,%domconfig);
     } elsif ($action eq 'selfenrollment') {      } elsif ($action eq 'selfenrollment') {
Line 645  sub process_changes { Line 769  sub process_changes {
         $output = &modify_usersessions($dom,$lastactref,%domconfig);          $output = &modify_usersessions($dom,$lastactref,%domconfig);
     } elsif ($action eq 'loadbalancing') {      } elsif ($action eq 'loadbalancing') {
         $output = &modify_loadbalancing($dom,%domconfig);          $output = &modify_loadbalancing($dom,%domconfig);
       } elsif ($action eq 'ltitools') {
           $output = &modify_ltitools($r,$dom,$action,$lastactref,%domconfig);
       } elsif ($action eq 'ssl') {
           $output = &modify_ssl($dom,$lastactref,%domconfig);
       } elsif ($action eq 'trust') {
           $output = &modify_trust($dom,$lastactref,%domconfig);
       } elsif ($action eq 'lti') {
           $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);
       } elsif ($action eq 'privacy') {
           $output = &modify_privacy($dom,%domconfig);
       } elsif ($action eq 'passwords') {
           $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);
     }      }
     return $output;      return $output;
 }  }
Line 657  sub print_config_box { Line 793  sub print_config_box {
         $output = &coursecategories_javascript($settings);          $output = &coursecategories_javascript($settings);
     } elsif ($action eq 'defaults') {      } elsif ($action eq 'defaults') {
         $output = &defaults_javascript($settings);           $output = &defaults_javascript($settings); 
       } elsif ($action eq 'passwords') {
           $output = &passwords_javascript();
       } elsif ($action eq 'helpsettings') {
           my (%privs,%levelscurrent);
           my %full=();
           my %levels=(
                        course => {},
                        domain => {},
                        system => {},
                      );
           my $context = 'domain';
           my $crstype = 'Course';
           my $formname = 'display';
           &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);
           my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
           $output =
               &Apache::lonuserutils::custom_roledefs_js($context,$crstype,$formname,\%full, 
                                                         \@templateroles);
       } elsif ($action eq 'ltitools') {
           $output .= &ltitools_javascript($settings);
       } elsif ($action eq 'lti') {
           $output .= &lti_javascript($settings);
     }      }
     $output .=      $output .=
          '<table class="LC_nested_outer">           '<table class="LC_nested_outer">
           <tr>            <tr>
            <th align="left" valign="middle"><span class="LC_nobreak">'.             <th class="LC_left_item LC_middle"><span class="LC_nobreak">'.
            &mt($item->{text}).'&nbsp;'.             &mt($item->{text}).'&nbsp;'.
            &Apache::loncommon::help_open_topic($item->{'help'}).'</span></th>'."\n".             &Apache::loncommon::help_open_topic($item->{'help'}).'</span></th>'."\n".
           '</tr>';            '</tr>';
Line 674  sub print_config_box { Line 832  sub print_config_box {
         my $colspan = '';          my $colspan = '';
         my $rightcolspan = '';          my $rightcolspan = '';
         if (($action eq 'rolecolors') || ($action eq 'defaults') ||          if (($action eq 'rolecolors') || ($action eq 'defaults') ||
               ($action eq 'directorysrch') ||
             (($action eq 'login') && ($numheaders < 4))) {              (($action eq 'login') && ($numheaders < 4))) {
             $colspan = ' colspan="2"';              $colspan = ' colspan="2"';
         }          }
Line 691  sub print_config_box { Line 850  sub print_config_box {
         $rowtotal ++;          $rowtotal ++;
         if (($action eq 'autoupdate') || ($action eq 'usercreation') || ($action eq 'selfcreation') ||          if (($action eq 'autoupdate') || ($action eq 'usercreation') || ($action eq 'selfcreation') ||
             ($action eq 'usermodification') || ($action eq 'defaults') || ($action eq 'coursedefaults') ||              ($action eq 'usermodification') || ($action eq 'defaults') || ($action eq 'coursedefaults') ||
             ($action eq 'selfenrollment') || ($action eq 'usersessions')) {              ($action eq 'selfenrollment') || ($action eq 'usersessions') || ($action eq 'ssl') ||
               ($action eq 'directorysrch') || ($action eq 'trust') || ($action eq 'helpsettings') ||
               ($action eq 'contacts') || ($action eq 'privacy')) {
             $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);              $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);
           } elsif ($action eq 'passwords') {
               $output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);
         } elsif ($action eq 'coursecategories') {          } elsif ($action eq 'coursecategories') {
             $output .= $item->{'print'}->('top',$dom,$item,$settings,\$rowtotal);              $output .= $item->{'print'}->('top',$dom,$item,$settings,\$rowtotal);
           } elsif ($action eq 'scantron') {
               $output .= $item->{'print'}->($r,'top',$dom,$confname,$settings,\$rowtotal);
         } elsif ($action eq 'login') {          } elsif ($action eq 'login') {
             if ($numheaders == 4) {              if ($numheaders == 4) {
                 $colspan = ' colspan="2"';                  $colspan = ' colspan="2"';
Line 721  sub print_config_box { Line 886  sub print_config_box {
             $rowtotal ++;              $rowtotal ++;
         if (($action eq 'autoupdate') || ($action eq 'usercreation') ||          if (($action eq 'autoupdate') || ($action eq 'usercreation') ||
             ($action eq 'selfcreation') || ($action eq 'selfenrollment') ||              ($action eq 'selfcreation') || ($action eq 'selfenrollment') ||
             ($action eq 'usersessions') || ($action eq 'coursecategories')) {              ($action eq 'usersessions') || ($action eq 'coursecategories') || 
               ($action eq 'trust') || ($action eq 'contacts') ||
               ($action eq 'privacy') || ($action eq 'passwords')) {
             if ($action eq 'coursecategories') {              if ($action eq 'coursecategories') {
                 $output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);                  $output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);
                 $colspan = ' colspan="2"';                  $colspan = ' colspan="2"';
               } elsif ($action eq 'trust') {
                   $output .= $item->{'print'}->('shared',$dom,$settings,\$rowtotal);
               } elsif ($action eq 'passwords') {
                   $output .= $item->{'print'}->('middle',$dom,$confname,$settings,\$rowtotal);
             } else {              } else {
                 $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);                  $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);
             }              }
             $output .= '              if ($action eq 'trust') {
                   $output .= '
               </table>
             </td>
            </tr>';
                   my @trusthdrs = qw(2 3 4 5 6 7);
                   my @prefixes = qw(enroll othcoau coaurem domroles catalog reqcrs);
                   for (my $i=0; $i<@trusthdrs; $i++) {
                       $output .= '
            <tr>
              <td>
               <table class="LC_nested">
                <tr class="LC_info_row">
                 <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[$trusthdrs[$i]]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[$trusthdrs[$i]]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->($prefixes[$i],$dom,$settings,\$rowtotal).'
               </table>
             </td>
            </tr>';
                   }
                   $output .= '
            <tr>
              <td>
               <table class="LC_nested">
                <tr class="LC_info_row">
                 <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
               } else {
                   $output .= '
            </table>             </table>
           </td>            </td>
          </tr>           </tr>
Line 739  sub print_config_box { Line 939  sub print_config_box {
               <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
               <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td>                <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td>
              </tr>'."\n";               </tr>'."\n";
             if ($action eq 'coursecategories') {                  if ($action eq 'coursecategories') {
                 $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);                      $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);
             } else {                  } elsif (($action eq 'contacts') || ($action eq 'privacy') || ($action eq 'passwords')) {
                 $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);                      if ($action eq 'passwords') {
                           $output .= $item->{'print'}->('lower',$dom,$confname,$settings,\$rowtotal);
                       } else {
                           $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal);
                       }
                       $output .= '
                </tr>
               </table>
              </td>
             </tr>
             <tr>
              <td>
               <table class="LC_nested">
                <tr class="LC_info_row">
                 <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'."\n";
                       if ($action eq 'passwords') {
                           $output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal);
                       } else {
                           $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
                       }
                       $output .= '
               </table>
             </td>
            </tr>
            <tr>';
                   } else {
                       $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
                   }
             }              }
             $rowtotal ++;              $rowtotal ++;
         } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||          } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||
                   ($action eq 'defaults')) {                   ($action eq 'defaults') || ($action eq 'directorysrch') ||
                    ($action eq 'helpsettings')) {
             $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);              $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
           } elsif ($action eq 'scantron') {
               $output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal);
           } elsif ($action eq 'ssl') {
               $output .= $item->{'print'}->('connto',$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"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->('connfrom',$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'}->[3]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'login') {          } elsif ($action eq 'login') {
             if ($numheaders == 4) {              if ($numheaders == 4) {
                 $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).'                  $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).'
Line 818  sub print_config_box { Line 1071  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item"'.$colspan.' valign="top">'.&mt($item->{'header'}->[4]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.' style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col1'}).'</td>
               <td class="LC_right_item" valign="top">'.&mt($item->{'header'}->[4]->{'col2'}).'</td>                <td class="LC_right_item" style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col2'}).'</td>
              </tr>'.               </tr>'.
             &print_validation_rows('requestcourses',$dom,$settings,\$rowtotal);              &print_validation_rows('requestcourses',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'requestauthor') {          } elsif ($action eq 'requestauthor') {
Line 834  sub print_config_box { Line 1087  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item"'.$colspan.' valign="top">'.                <td class="LC_left_item"'.$colspan.' style="vertical-align: top">'.
                &mt($item->{'header'}->[2]->{'col1'}).'</td>                 &mt($item->{'header'}->[2]->{'col1'}).'</td>
               <td class="LC_right_item" valign="top">'.                <td class="LC_right_item" style="vertical-align: top">'.
                &mt($item->{'header'}->[2]->{'col2'}).'</td>                 &mt($item->{'header'}->[2]->{'col2'}).'</td>
              </tr>'.               </tr>'.
             &print_rolecolors($phase,'author',$dom,$confname,$settings,\$rowtotal).'              &print_rolecolors($phase,'author',$dom,$confname,$settings,\$rowtotal).'
Line 859  sub print_config_box { Line 1112  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">';               <tr class="LC_info_row">';
         if (($action eq 'login') || ($action eq 'directorysrch')) {          if ($action eq 'login') {
             $output .= '                $output .= '  
               <td class="LC_left_item" colspan="2">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';                <td class="LC_left_item" colspan="2">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';
         } elsif ($action eq 'serverstatuses') {          } elsif ($action eq 'serverstatuses') {
             $output .= '              $output .= '
               <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[0]->{'col1'}).                <td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}).
               '<br />('.&mt('Automatic access for Dom. Coords.').')</td>';                '<br />('.&mt('Automatic access for Dom. Coords.').')</td>';
   
         } else {          } else {
             $output .= '              $output .= '
               <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';                <td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';
         }          }
         if (defined($item->{'header'}->[0]->{'col3'})) {          if (defined($item->{'header'}->[0]->{'col3'})) {
             $output .= '<td class="LC_left_item" valign="top">'.              $output .= '<td class="LC_left_item" style="vertical-align: top">'.
                        &mt($item->{'header'}->[0]->{'col2'});                         &mt($item->{'header'}->[0]->{'col2'});
             if ($action eq 'serverstatuses') {              if ($action eq 'serverstatuses') {
                 $output .= '<br />(<tt>'.&mt('user1:domain1,user2:domain2 etc.').'</tt>)';                  $output .= '<br />(<tt>'.&mt('user1:domain1,user2:domain2 etc.').'</tt>)';
             }               } 
         } else {          } else {
             $output .= '<td class="LC_right_item" valign="top">'.              $output .= '<td class="LC_right_item" style="vertical-align: top">'.
                        &mt($item->{'header'}->[0]->{'col2'});                         &mt($item->{'header'}->[0]->{'col2'});
         }          }
         $output .= '</td>';          $output .= '</td>';
         if ($item->{'header'}->[0]->{'col3'}) {          if ($item->{'header'}->[0]->{'col3'}) {
             if (defined($item->{'header'}->[0]->{'col4'})) {              if (defined($item->{'header'}->[0]->{'col4'})) {
                 $output .= '<td class="LC_left_item" valign="top">'.                  $output .= '<td class="LC_left_item" style="vertical-align: top">'.
                             &mt($item->{'header'}->[0]->{'col3'});                              &mt($item->{'header'}->[0]->{'col3'});
             } else {              } else {
                 $output .= '<td class="LC_right_item" valign="top">'.                  $output .= '<td class="LC_right_item" style="vertical-align: top">'.
                            &mt($item->{'header'}->[0]->{'col3'});                             &mt($item->{'header'}->[0]->{'col3'});
             }              }
             if ($action eq 'serverstatuses') {              if ($action eq 'serverstatuses') {
Line 896  sub print_config_box { Line 1149  sub print_config_box {
             $output .= '</td>';              $output .= '</td>';
         }          }
         if ($item->{'header'}->[0]->{'col4'}) {          if ($item->{'header'}->[0]->{'col4'}) {
             $output .= '<td class="LC_right_item" valign="top">'.              $output .= '<td class="LC_right_item" style="vertical-align: top">'.
                        &mt($item->{'header'}->[0]->{'col4'});                         &mt($item->{'header'}->[0]->{'col4'});
         }          }
         $output .= '</tr>';          $output .= '</tr>';
         $rowtotal ++;          $rowtotal ++;
         if ($action eq 'quotas') {          if ($action eq 'quotas') {
             $output .= &print_quotas($dom,$settings,\$rowtotal,$action);              $output .= &print_quotas($dom,$settings,\$rowtotal,$action);
         } elsif (($action eq 'autoenroll') || ($action eq 'autocreate') || ($action eq 'directorysrch') ||          } elsif (($action eq 'autoenroll') || ($action eq 'autocreate') || 
                  ($action eq 'contacts') || ($action eq 'serverstatuses') || ($action eq 'loadbalancing')) {                   ($action eq 'serverstatuses') || ($action eq 'loadbalancing') || 
                    ($action eq 'ltitools') || ($action eq 'lti')) {
             $output .= $item->{'print'}->($dom,$settings,\$rowtotal);              $output .= $item->{'print'}->($dom,$settings,\$rowtotal);
         } elsif ($action eq 'scantron') {  
             $output .= &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal);  
         } elsif ($action eq 'helpsettings') {  
             $output .= &print_helpsettings($dom,$confname,$settings,\$rowtotal);  
         }          }
     }      }
     $output .= '      $output .= '
Line 930  sub print_login { Line 1180  sub print_login {
         my $choice = $choices{'disallowlogin'};          my $choice = $choices{'disallowlogin'};
         $css_class = ' class="LC_odd_row"';          $css_class = ' class="LC_odd_row"';
         $datatable .= '<tr'.$css_class.'><td>'.$choice.'</td>'.          $datatable .= '<tr'.$css_class.'><td>'.$choice.'</td>'.
                       '<td align="right"><table><tr><th>'.$choices{'hostid'}.'</th>'.                        '<td style="text-align: right"><table><tr><th>'.$choices{'hostid'}.'</th>'.
                       '<th>'.$choices{'server'}.'</th>'.                        '<th>'.$choices{'server'}.'</th>'.
                       '<th>'.$choices{'serverpath'}.'</th>'.                        '<th>'.$choices{'serverpath'}.'</th>'.
                       '<th>'.$choices{'custompath'}.'</th>'.                        '<th>'.$choices{'custompath'}.'</th>'.
Line 1211  sub print_login { Line 1461  sub print_login {
         my $choice = $choices{'headtag'};          my $choice = $choices{'headtag'};
         $css_class = ' class="LC_odd_row"';          $css_class = ' class="LC_odd_row"';
         $datatable .= '<tr'.$css_class.'><td colspan="2">'.$choice.'</td>'.          $datatable .= '<tr'.$css_class.'><td colspan="2">'.$choice.'</td>'.
                       '<td align="left"><table><tr><th>'.$choices{'hostid'}.'</th>'.                        '<td style="text-align: left"><table><tr><th>'.$choices{'hostid'}.'</th>'.
                       '<th>'.$choices{'current'}.'</th>'.                        '<th>'.$choices{'current'}.'</th>'.
                       '<th>'.$choices{'action'}.'</th>'.                        '<th>'.$choices{'action'}.'</th>'.
                       '<th>'.$choices{'exempt'}.'</th></tr>'."\n";                        '<th>'.$choices{'exempt'}.'</th></tr>'."\n";
Line 1254  sub print_login { Line 1504  sub print_login {
             } else {              } else {
                 $datatable .= '<input type="file" name="loginheadtag_'.$lonhost.'" />';                  $datatable .= '<input type="file" name="loginheadtag_'.$lonhost.'" />';
             }              }
             $datatable .= '</td><td><input type="textbox" name="loginheadtagexempt_'.$lonhost.'" value="'.$exempt.'" /></td></tr>';              $datatable .= '</td><td><input type="text" name="loginheadtagexempt_'.$lonhost.'" value="'.$exempt.'" /></td></tr>';
         }          }
         $datatable .= '</table></td></tr>';          $datatable .= '</table></td></tr>';
     }      }
Line 1414  sub display_color_options { Line 1664  sub display_color_options {
     my $datatable = '<tr'.$css_class.'>'.      my $datatable = '<tr'.$css_class.'>'.
         '<td>'.$choices->{'font'}.'</td>';          '<td>'.$choices->{'font'}.'</td>';
     if (!$is_custom->{'font'}) {      if (!$is_custom->{'font'}) {
         $datatable .=  '<td>'.&mt('Default in use:').'&nbsp;<span id="css_default_'.$role.'_font" style="color: '.$defaults->{'font'}.';">'.$defaults->{'font'}.'</span></td>';          $datatable .=  '<td>'.&mt('Default in use:').'&nbsp;<span class="css_default_'.$role.'_font" style="color: '.$defaults->{'font'}.';">'.$defaults->{'font'}.'</span></td>';
     } else {      } else {
         $datatable .= '<td>&nbsp;</td>';          $datatable .= '<td>&nbsp;</td>';
     }      }
Line 1423  sub display_color_options { Line 1673  sub display_color_options {
     $datatable .= '<td><span class="LC_nobreak">'.      $datatable .= '<td><span class="LC_nobreak">'.
                   '<input type="text" class="colorchooser" size="10" name="'.$role.'_font"'.                    '<input type="text" class="colorchooser" size="10" name="'.$role.'_font"'.
                   ' value="'.$current_color.'" />&nbsp;'.                    ' value="'.$current_color.'" />&nbsp;'.
                   '&nbsp;</td></tr>';                    '&nbsp;</span></td></tr>';
     unless ($role eq 'login') {       unless ($role eq 'login') { 
         $datatable .= '<tr'.$css_class.'>'.          $datatable .= '<tr'.$css_class.'>'.
                       '<td>'.$choices->{'fontmenu'}.'</td>';                        '<td>'.$choices->{'fontmenu'}.'</td>';
         if (!$is_custom->{'fontmenu'}) {          if (!$is_custom->{'fontmenu'}) {
             $datatable .=  '<td>'.&mt('Default in use:').'&nbsp;<span id="css_default_'.$role.'_font" style="color: '.$defaults->{'fontmenu'}.';">'.$defaults->{'fontmenu'}.'</span></td>';              $datatable .=  '<td>'.&mt('Default in use:').'&nbsp;<span class="css_default_'.$role.'_font" style="color: '.$defaults->{'fontmenu'}.';">'.$defaults->{'fontmenu'}.'</span></td>';
         } else {          } else {
             $datatable .= '<td>&nbsp;</td>';              $datatable .= '<td>&nbsp;</td>';
         }          }
Line 1438  sub display_color_options { Line 1688  sub display_color_options {
                       '<input class="colorchooser" type="text" size="10" name="'                        '<input class="colorchooser" type="text" size="10" name="'
       .$role.'_fontmenu"'.        .$role.'_fontmenu"'.
                       ' value="'.$current_color.'" />&nbsp;'.                        ' value="'.$current_color.'" />&nbsp;'.
                       '&nbsp;</td></tr>';                        '&nbsp;</span></td></tr>';
     }      }
     my $switchserver = &check_switchserver($dom,$confname);      my $switchserver = &check_switchserver($dom,$confname);
     foreach my $img (@{$images}) {      foreach my $img (@{$images}) {
Line 1497  sub display_color_options { Line 1747  sub display_color_options {
                         if ($fullwidth ne '' && $fullheight ne '') {                          if ($fullwidth ne '' && $fullheight ne '') {
                             if ($fullwidth > $width && $fullheight > $height) {                               if ($fullwidth > $width && $fullheight > $height) { 
                                 my $size = $width.'x'.$height;                                  my $size = $width.'x'.$height;
                                 system("convert -sample $size $input $output");                                  my @args = ('convert','-sample',$size,$input,$output);
                                   system({$args[0]} @args);
                                 $showfile = "/$imgdir/tn-".$filename;                                  $showfile = "/$imgdir/tn-".$filename;
                             }                              }
                         }                          }
Line 1555  sub display_color_options { Line 1806  sub display_color_options {
     my $bgs_def;      my $bgs_def;
     foreach my $item (@{$bgs}) {      foreach my $item (@{$bgs}) {
         if (!$is_custom->{$item}) {          if (!$is_custom->{$item}) {
             $bgs_def .= '<td><span class="LC_nobreak">'.$choices->{$item}.'</span>&nbsp;<span id="css_default_'.$role.'_'.$item.'" style="background-color: '.$defaults->{'bgs'}{$item}.';">&nbsp;&nbsp;&nbsp;</span><br />'.$defaults->{'bgs'}{$item}.'</td>';              $bgs_def .= '<td><span class="LC_nobreak">'.$choices->{$item}.'</span>&nbsp;<span class="css_default_'.$role.'_'.$item.'" style="background-color: '.$defaults->{'bgs'}{$item}.';">&nbsp;&nbsp;&nbsp;</span><br />'.$defaults->{'bgs'}{$item}.'</td>';
         }          }
     }      }
     if ($bgs_def) {      if ($bgs_def) {
Line 1567  sub display_color_options { Line 1818  sub display_color_options {
                   '<table border="0"><tr>';                    '<table border="0"><tr>';
   
     foreach my $item (@{$bgs}) {      foreach my $item (@{$bgs}) {
         $datatable .= '<td align="center">'.$choices->{$item};          $datatable .= '<td style="text-align: center">'.$choices->{$item};
  my $color = $designs->{'bgs'}{$item} ? $designs->{'bgs'}{$item} : $defaults->{'bgs'}{$item};   my $color = $designs->{'bgs'}{$item} ? $designs->{'bgs'}{$item} : $defaults->{'bgs'}{$item};
         if ($designs->{'bgs'}{$item}) {          if ($designs->{'bgs'}{$item}) {
             $datatable .= '&nbsp;';              $datatable .= '&nbsp;';
Line 1583  sub display_color_options { Line 1834  sub display_color_options {
     my $links_def;      my $links_def;
     foreach my $item (@{$links}) {      foreach my $item (@{$links}) {
         if (!$is_custom->{$item}) {          if (!$is_custom->{$item}) {
             $links_def .= '<td>'.$choices->{$item}.'<br /><span id="css_default_'.$role.'_'.$item.'" style="color: '.$defaults->{'links'}{$item}.';">'.$defaults->{'links'}{$item}.'</span></td>';              $links_def .= '<td>'.$choices->{$item}.'<br /><span class="css_default_'.$role.'_'.$item.'" style="color: '.$defaults->{'links'}{$item}.';">'.$defaults->{'links'}{$item}.'</span></td>';
         }          }
     }      }
     if ($links_def) {      if ($links_def) {
Line 1595  sub display_color_options { Line 1846  sub display_color_options {
                   '<table border="0"><tr>';                    '<table border="0"><tr>';
     foreach my $item (@{$links}) {      foreach my $item (@{$links}) {
  my $color = $designs->{'links'}{$item} ? $designs->{'links'}{$item} : $defaults->{'links'}{$item};   my $color = $designs->{'links'}{$item} ? $designs->{'links'}{$item} : $defaults->{'links'}{$item};
         $datatable .= '<td align="center">'.$choices->{$item}."\n";          $datatable .= '<td style="text-align: center">'.$choices->{$item}."\n";
         if ($designs->{'links'}{$item}) {          if ($designs->{'links'}{$item}) {
             $datatable.='&nbsp;';              $datatable.='&nbsp;';
         }          }
Line 1656  sub login_text_colors { Line 1907  sub login_text_colors {
     my ($img,$role,$logintext,$phase,$choices,$designs,$defaults) = @_;      my ($img,$role,$logintext,$phase,$choices,$designs,$defaults) = @_;
     my $color_menu = '<table border="0"><tr>';      my $color_menu = '<table border="0"><tr>';
     foreach my $item (@{$logintext}) {      foreach my $item (@{$logintext}) {
         $color_menu .= '<td align="center">'.$choices->{$item};          $color_menu .= '<td style="text-align: center">'.$choices->{$item};
         my $color = $designs->{'logintext'}{$item} ? $designs->{'logintext'}{$item} : $defaults->{'logintext'}{$item};          my $color = $designs->{'logintext'}{$item} ? $designs->{'logintext'}{$item} : $defaults->{'logintext'}{$item};
         $color_menu .= '<br /><input type="text" class="colorchooser" size="8" name="'.$role.'_'.$item.'" value="'.$color.          $color_menu .= '<br /><input type="text" class="colorchooser" size="8" name="'.$role.'_'.$item.'" value="'.$color.
                       '" onblur = "javascript:colchg_span('."'css_".$role.'_'.$item."'".',this);" /></td>';                        '" onblur = "javascript:colchg_span('."'css_".$role.'_'.$item."'".',this);" /></td>';
Line 1669  sub image_changes { Line 1920  sub image_changes {
     my ($is_custom,$alt_text,$img_import,$showfile,$fullsize,$role,$img,$imgfile,$logincolors) = @_;      my ($is_custom,$alt_text,$img_import,$showfile,$fullsize,$role,$img,$imgfile,$logincolors) = @_;
     my $output;      my $output;
     if ($img eq 'login') {      if ($img eq 'login') {
             # suppress image for Log-in header          $output = '</td><td>'.$logincolors; # suppress image for Log-in header
     } elsif (!$is_custom) {      } elsif (!$is_custom) {
         if ($img ne 'domlogo') {          if ($img ne 'domlogo') {
             $output .= &mt('Default image:').'<br />';              $output = &mt('Default image:').'<br />';
         } else {          } else {
             $output .= &mt('Default in use:').'<br />';              $output = &mt('Default in use:').'<br />';
         }          }
     }      }
     if ($img eq 'login') { # suppress image for Log-in header      if ($img ne 'login') {
         $output .= '<td>'.$logincolors;  
     } else {  
         if ($img_import) {          if ($img_import) {
             $output .= '<input type="hidden" name="'.$role.'_import_'.$img.'" value="'.$imgfile.'" />';              $output .= '<input type="hidden" name="'.$role.'_import_'.$img.'" value="'.$imgfile.'" />';
         }          }
Line 1691  sub image_changes { Line 1940  sub image_changes {
                        $role.'_del_'.$img.'" value="1" />'.&mt('Delete?').                         $role.'_del_'.$img.'" value="1" />'.&mt('Delete?').
                        '</label>&nbsp;'.&mt('Replace:').'</span><br />';                         '</label>&nbsp;'.&mt('Replace:').'</span><br />';
         } else {          } else {
             $output .= '<td valign="middle">'.$logincolors.&mt('Upload:').'<br />';              $output .= '<td class="LC_middle">'.$logincolors.&mt('Upload:').'<br />';
         }          }
     }      }
     return $output;      return $output;
Line 1710  sub print_quotas { Line 1959  sub print_quotas {
     my $typecount = 0;      my $typecount = 0;
     my ($css_class,%titles);      my ($css_class,%titles);
     if ($context eq 'requestcourses') {      if ($context eq 'requestcourses') {
         @usertools = ('official','unofficial','community','textbook');          @usertools = ('official','unofficial','community','textbook','placement','lti');
         @options =('norequest','approval','validate','autolimit');          @options =('norequest','approval','validate','autolimit');
         %validations = &Apache::lonnet::auto_courserequest_checks($dom);          %validations = &Apache::lonnet::auto_courserequest_checks($dom);
         %titles = &courserequest_titles();          %titles = &courserequest_titles();
Line 2123  sub print_quotas { Line 2372  sub print_quotas {
 }  }
   
 sub print_requestmail {  sub print_requestmail {
     my ($dom,$action,$settings,$rowtotal) = @_;      my ($dom,$action,$settings,$rowtotal,$customcss,$rowstyle) = @_;
     my ($now,$datatable,%currapp);      my ($now,$datatable,%currapp);
     $now = time;      $now = time;
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
Line 2135  sub print_requestmail { Line 2384  sub print_requestmail {
     }      }
     my $numinrow = 2;      my $numinrow = 2;
     my $css_class;      my $css_class;
     $css_class = ($$rowtotal%2? ' class="LC_odd_row"':'');      if ($$rowtotal%2) {
           $css_class = 'LC_odd_row';
       }
       if ($customcss) {
           $css_class .= " $customcss";
       }
       $css_class =~ s/^\s+//;
       if ($css_class) {
           $css_class = ' class="'.$css_class.'"';
       }
       if ($rowstyle) {
           $css_class .= ' style="'.$rowstyle.'"';
       }
     my $text;      my $text;
     if ($action eq 'requestcourses') {      if ($action eq 'requestcourses') {
         $text = &mt('Receive notification of course requests requiring approval');          $text = &mt('Receive notification of course requests requiring approval');
Line 2162  sub print_studentcode { Line 2423  sub print_studentcode {
     my ($settings,$rowtotal) = @_;      my ($settings,$rowtotal) = @_;
     my $rownum = 0;       my $rownum = 0; 
     my ($output,%current);      my ($output,%current);
     my @crstypes = ('official','unofficial','community','textbook');      my @crstypes = ('official','unofficial','community','textbook','placement','lti');
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if (ref($settings->{'uniquecode'}) eq 'HASH') {          if (ref($settings->{'uniquecode'}) eq 'HASH') {
             foreach my $type (@crstypes) {              foreach my $type (@crstypes) {
Line 2258  sub print_textbookcourses { Line 2519  sub print_textbookcourses {
                               ('&nbsp;'x2).                                ('&nbsp;'x2).
                               '<span class="LC_nobreak">'.&mt('Thumbnail:');                                '<span class="LC_nobreak">'.&mt('Thumbnail:');
                 if ($image) {                  if ($image) {
                     $datatable .= '<span class="LC_nobreak">'.                      $datatable .= $imgsrc.
                                   $imgsrc.  
                                   '<label><input type="checkbox" name="'.$type.'_image_del"'.                                    '<label><input type="checkbox" name="'.$type.'_image_del"'.
                                   ' value="'.$key.'" />'.&mt('Delete?').'</label></span> '.                                    ' value="'.$key.'" />'.&mt('Delete?').'</label></span> '.
                                   '<span class="LC_nobreak">&nbsp;'.&mt('Replace:').'&nbsp;';                                    '<span class="LC_nobreak">&nbsp;'.&mt('Replace:').'&nbsp;';
Line 2290  sub print_textbookcourses { Line 2550  sub print_textbookcourses {
         $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';          $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
     }      }
     $datatable .= '</select>&nbsp;'."\n".      $datatable .= '</select>&nbsp;'."\n".
                   '<input type="checkbox" name="'.$type.'_addbook" value="1" />'.&mt('Add').'</td>'."\n".                    '<input type="checkbox" name="'.$type.'_addbook" value="1" />'.&mt('Add').'</span></td>'."\n".
                   '<td colspan="2">'.                    '<td colspan="2">'.
                   '<span class="LC_nobreak">'.&mt('Subject:').'<input type="text" size="15" name="'.$type.'_addbook_subject" value="" /></span> '."\n".                    '<span class="LC_nobreak">'.&mt('Subject:').'<input type="text" size="15" name="'.$type.'_addbook_subject" value="" /></span> '."\n".
                   ('&nbsp;'x2).                    ('&nbsp;'x2).
Line 2307  sub print_textbookcourses { Line 2567  sub print_textbookcourses {
         } else {          } else {
             $datatable .= '<input type="file" name="'.$type.'_addbook_image" value="" />';              $datatable .= '<input type="file" name="'.$type.'_addbook_image" value="" />';
         }          }
           $datatable .= '</span>'."\n";
     }      }
     $datatable .= '</span>'."\n".      $datatable .= '<span class="LC_nobreak">'.&mt('LON-CAPA course:').'&nbsp;'.
                   '<span class="LC_nobreak">'.&mt('LON-CAPA course:').'&nbsp;'.  
                   &Apache::loncommon::select_dom_form($env{'request.role.domain'},$type.'_addbook_cdom').                    &Apache::loncommon::select_dom_form($env{'request.role.domain'},$type.'_addbook_cdom').
                   '<input type="text" size="25" name="'.$type.'_addbook_cnum" value="" />'.                    '<input type="text" size="25" name="'.$type.'_addbook_cnum" value="" />'.
                   &Apache::loncommon::selectcourse_link                    &Apache::loncommon::selectcourse_link
                       ('display',$type.'_addbook_cnum',$type.'_addbook_cdom',undef,undef,undef,'Course');                        ('display',$type.'_addbook_cnum',$type.'_addbook_cdom',undef,undef,undef,'Course').
                   '</span></td>'."\n".                    '</span></td>'."\n".
                   '</tr>'."\n";                    '</tr>'."\n";
     $itemcount ++;      $itemcount ++;
Line 2413  $jstext{'templates'}; Line 2673  $jstext{'templates'};
 ENDSCRIPT  ENDSCRIPT
 }  }
   
   sub ltitools_javascript {
       my ($settings) = @_;
       my $togglejs = &ltitools_toggle_js();
       unless (ref($settings) eq 'HASH') {
           return $togglejs;
       }
       my (%ordered,$total,%jstext);
       $total = 0;
       foreach my $item (keys(%{$settings})) {
           if (ref($settings->{$item}) eq 'HASH') {
               my $num = $settings->{$item}{'order'};
               $ordered{$num} = $item;
           }
       }
       $total = scalar(keys(%{$settings}));
       my @jsarray = ();
       foreach my $item (sort {$a <=> $b } (keys(%ordered))) {
           push(@jsarray,$ordered{$item});
       }
       my $jstext = '    var ltitools = Array('."'".join("','",@jsarray)."'".');'."\n";
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   function reorderLTITools(form,item) {
       var changedVal;
   $jstext
       var newpos = 'ltitools_add_pos';
       var maxh = 1 + $total;
       var current = new Array;
       var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;
       if (item == newpos) {
           changedVal = newitemVal;
       } else {
           changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;
           current[newitemVal] = newpos;
       }
       for (var i=0; i<ltitools.length; i++) {
           var elementName = 'ltitools_'+ltitools[i];
           if (elementName != item) {
               if (form.elements[elementName]) {
                   var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
                   current[currVal] = elementName;
               }
           }
       }
       var oldVal;
       for (var j=0; j<maxh; j++) {
           if (current[j] == undefined) {
               oldVal = j;
           }
       }
       if (oldVal < changedVal) {
           for (var k=oldVal+1; k<=changedVal ; k++) {
              var elementName = current[k];
              form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;
           }
       } else {
           for (var k=changedVal; k<oldVal; k++) {
               var elementName = current[k];
               form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;
           }
       }
       return;
   }
   
   // ]]>
   </script>
   
   $togglejs
   
   ENDSCRIPT
   }
   
   sub ltitools_toggle_js {
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   
   function toggleLTITools(form,setting,item) {
       var radioname = '';
       var divid = '';
       if ((setting == 'passback') || (setting == 'roster')) {
           radioname = 'ltitools_'+setting+'_'+item;
           divid = 'ltitools_'+setting+'time_'+item;
           var num = form.elements[radioname].length;
           if (num) {
               var setvis = '';
               for (var i=0; i<num; i++) {
                   if (form.elements[radioname][i].checked) {
                       if (form.elements[radioname][i].value == '1') {
                           if (document.getElementById(divid)) {
                               document.getElementById(divid).style.display = 'inline-block';
                           }
                           setvis = 1;
                       }
                       break;
                   }
               }
           }
           if (!setvis) {
               if (document.getElementById(divid)) {
                   document.getElementById(divid).style.display = 'none';
               }
           }
       }
       if (setting == 'user') {
           divid = 'ltitools_'+setting+'_div_'+item;
           var checkid = 'ltitools_'+setting+'_field_'+item;
           if (document.getElementById(divid)) {
               if (document.getElementById(checkid)) {
                   if (document.getElementById(checkid).checked) {
                       document.getElementById(divid).style.display = 'inline-block';
                   } else {
                       document.getElementById(divid).style.display = 'none';
                   }
               }
           }
       }
       return;
   }
   // ]]>
   </script>
   
   ENDSCRIPT
   }
   
   sub lti_javascript {
       my ($settings) = @_;
       my $togglejs = &lti_toggle_js();
       unless (ref($settings) eq 'HASH') {
           return $togglejs;
       }
       my (%ordered,$total,%jstext);
       $total = 0;
       foreach my $item (keys(%{$settings})) {
           if (ref($settings->{$item}) eq 'HASH') {
               my $num = $settings->{$item}{'order'};
               $ordered{$num} = $item;
           }
       }
       $total = scalar(keys(%{$settings}));
       my @jsarray = ();
       foreach my $item (sort {$a <=> $b } (keys(%ordered))) {
           push(@jsarray,$ordered{$item});
       }
       my $jstext = '    var lti = Array('."'".join("','",@jsarray)."'".');'."\n";
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   function reorderLTI(form,item) {
       var changedVal;
   $jstext
       var newpos = 'lti_pos_add';
       var maxh = 1 + $total;
       var current = new Array;
       var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;
       if (item == newpos) {
           changedVal = newitemVal;
       } else {
           changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;
           current[newitemVal] = newpos;
       }
       for (var i=0; i<lti.length; i++) {
           var elementName = 'lti_pos_'+lti[i];
           if (elementName != item) {
               if (form.elements[elementName]) {
                   var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
                   current[currVal] = elementName;
               }
           }
       }
       var oldVal;
       for (var j=0; j<maxh; j++) {
           if (current[j] == undefined) {
               oldVal = j;
           }
       }
       if (oldVal < changedVal) {
           for (var k=oldVal+1; k<=changedVal ; k++) {
              var elementName = current[k];
              form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;
           }
       } else {
           for (var k=changedVal; k<oldVal; k++) {
               var elementName = current[k];
               form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;
           }
       }
       return;
   }
   // ]]>
   </script>
   
   $togglejs
   
   ENDSCRIPT
   }
   
   sub lti_toggle_js {
       my %lcauthparmtext = &Apache::lonlocal::texthash (
                               localauth => 'Local auth argument',
                               krb       => 'Kerberos domain',
                            );
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   
   function toggleLTI(form,setting,item) {
       if (setting == 'requser') {
           var fieldsets = document.getElementsByClassName('ltioption_'+item);
           if (fieldsets.length) {
               var radioname = 'lti_'+setting+'_'+item;
               var num = form.elements[radioname].length;
               if (num) {
                   var setvis = '';
                   for (var i=0; i<num; i++) {
                       if (form.elements[radioname][i].checked) {
                           if (form.elements[radioname][i].value == '1') {
                              setvis = 1;
                              break;
                           }
                       }
                   }
                   for (var j=0; j<fieldsets.length; j++) {
                       if (setvis) {
                           fieldsets[j].style.display = 'block';
                       } else {
                           fieldsets[j].style.display = 'none';
                       }
                   }
               }
           }
       } else if ((setting == 'user') || (setting == 'crs') || (setting == 'passback') || (setting == 'callback')) {
           var radioname = '';
           var divid = '';
           if (setting == 'user') {
               radioname = 'lti_mapuser_'+item;
               divid = 'lti_userfield_'+item;
           } else if (setting == 'crs') {
               radioname = 'lti_mapcrs_'+item;
               divid = 'lti_crsfield_'+item;
           } else if (setting == 'callback') {
               radioname = 'lti_callback_'+item;
               divid = 'lti_callbackfield_'+item;
           } else {
               radioname = 'lti_passback_'+item;
               divid =  'lti_passback_'+item;
           }
           var num = form.elements[radioname].length;
           if (num) {
               var setvis = '';
               for (var i=0; i<num; i++) {
                  if (form.elements[radioname][i].checked) {
                      if ((setting == 'passback') || (setting == 'callback')) {
                          if (form.elements[radioname][i].value == '1') {
                              if (document.getElementById(divid)) {
                                  document.getElementById(divid).style.display = 'inline-block';
                              }
                              setvis = 1;
                              break;
                          }
                      } else {
                          if (form.elements[radioname][i].value == 'other') {
                              if (document.getElementById(divid)) {
                                  document.getElementById(divid).style.display = 'inline-block';
                              }
                              setvis = 1;
                              break;
                          }
                      }
                  } 
               }
               if (!setvis) {
                   if (document.getElementById(divid)) {
                       document.getElementById(divid).style.display = 'none';
                   }
               }
           }
       } else if ((setting == 'sec') || (setting == 'secsrc')) {
           var numsec = form.elements['lti_crssec_'+item].length;
           if (numsec) {
               var setvis = '';
               for (var i=0; i<numsec; i++) {
                   if (form.elements['lti_crssec_'+item][i].checked) {
                       if (form.elements['lti_crssec_'+item][i].value == '1') {
                           if (document.getElementById('lti_crssecfield_'+item)) {
                               document.getElementById('lti_crssecfield_'+item).style.display = 'inline-block';
                               setvis = 1;
                               var numsrcsec = form.elements['lti_crssecsrc_'+item].length;
                               if (numsrcsec) {
                                   var setsrcvis = '';
                                   for (var j=0; j<numsrcsec; j++) {
                                       if (form.elements['lti_crssecsrc_'+item][j].checked) {
                                           if (form.elements['lti_crssecsrc_'+item][j].value == 'other') {
                                               if (document.getElementById('lti_secsrcfield_'+item)) {
                                                   document.getElementById('lti_secsrcfield_'+item).style.display = 'inline-block';
                                                   setsrcvis = 1;
                                               }
                                           }
                                       }
                                   }
                                   if (!setsrcvis) {
                                       if (document.getElementById('lti_secsrcfield_'+item)) {
                                           document.getElementById('lti_secsrcfield_'+item).style.display = 'none';
                                       }
                                   }
                               }
                           }
                       }
                   }
               }
               if (!setvis) {
                   if (document.getElementById('lti_crssecfield_'+item)) {
                       document.getElementById('lti_crssecfield_'+item).style.display = 'none';
                   }
                   if (document.getElementById('lti_secsrcfield_'+item)) {
                       document.getElementById('lti_secsrcfield_'+item).style.display = 'none';
                   }
               }
           }
       } else if (setting == 'lcauth') {
           var numauth = form.elements['lti_lcauth_'+item].length;
           if (numauth) {
               for (var i=0; i<numauth; i++) {
                   if (form.elements['lti_lcauth_'+item][i].checked) {
                       if (document.getElementById('lti_'+setting+'_parmrow_'+item)) {
                           if ((form.elements['lti_'+setting+'_'+item][i].value == 'internal') || (form.elements['lti_'+setting+'_'+item][i].value == 'lti')) {
                               document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'none';
                           } else {
                               document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'table-row';
                               if (document.getElementById('lti_'+setting+'_parmtext_'+item)) {
                                   if (form.elements['lti_'+setting+'_'+item][i].value == 'localauth') {
                                       document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'localauth'}";
                                   } else {
                                       document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'krb'}";
                                   }
                               }
                           }
                       }
                   }
               }
           }
       } else if (setting == 'lcmenu') {
           var menus = new Array('lti_topmenu_'+item,'lti_inlinemenu_'+item);
           var divid = 'lti_menufield_'+item;
           var setvis = '';
           for (var i=0; i<menus.length; i++) {
               var radioname = menus[i];  
               var num = form.elements[radioname].length;
               if (num) {
                   for (var j=0; j<num; j++) {
                       if (form.elements[radioname][j].checked) {
                           if (form.elements[radioname][j].value == '1') {
                               if (document.getElementById(divid)) {
                                   document.getElementById(divid).style.display = 'inline-block';
                               }
                               setvis = 1;
                               break;
                           }
                       }
                   }
               }
               if (setvis == 1) {
                   break;
               }
           }
           if (!setvis) {
               if (document.getElementById(divid)) {
                   document.getElementById(divid).style.display = 'none';
               }
           }
       }
       return;
   }
   // ]]>
   </script>
   
   ENDSCRIPT
   }
   
 sub print_autoenroll {  sub print_autoenroll {
     my ($dom,$settings,$rowtotal) = @_;      my ($dom,$settings,$rowtotal) = @_;
     my $autorun = &Apache::lonnet::auto_run(undef,$dom),      my $autorun = &Apache::lonnet::auto_run(undef,$dom),
     my ($defdom,$runon,$runoff,$coownerson,$coownersoff);      my ($defdom,$runon,$runoff,$coownerson,$coownersoff,$failsafe);
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if (exists($settings->{'run'})) {          if (exists($settings->{'run'})) {
             if ($settings->{'run'} eq '0') {              if ($settings->{'run'} eq '0') {
Line 2450  sub print_autoenroll { Line 3090  sub print_autoenroll {
         if (exists($settings->{'sender_domain'})) {          if (exists($settings->{'sender_domain'})) {
             $defdom = $settings->{'sender_domain'};              $defdom = $settings->{'sender_domain'};
         }          }
           if (exists($settings->{'autofailsafe'})) {
               $failsafe = $settings->{'autofailsafe'};
           }
     } else {      } else {
         if ($autorun) {          if ($autorun) {
             $runon = ' checked="checked" ';              $runon = ' checked="checked" ';
Line 2485  sub print_autoenroll { Line 3128  sub print_autoenroll {
                   $coownerson.' value="1" />'.&mt('Yes').'</label>&nbsp;'.                    $coownerson.' value="1" />'.&mt('Yes').'</label>&nbsp;'.
                   '<label><input type="radio" name="autoassign_coowners"'.                    '<label><input type="radio" name="autoassign_coowners"'.
                   $coownersoff.' value="0" />'.&mt('No').'</label></span></td>'.                    $coownersoff.' value="0" />'.&mt('No').'</label></span></td>'.
                   '</tr>';                    '</tr><tr>'.
     $$rowtotal += 3;                    '<td>'.&mt('Failsafe for no drops when institutional data missing').'</td>'.
                     '<td class="LC_right_item"><span class="LC_nobreak">'.
                     '<input type="text" name="autoenroll_failsafe"'.
                     ' value="'.$failsafe.'" size="4" /></span></td></tr>';
       $$rowtotal += 4;
     return $datatable;      return $datatable;
 }  }
   
Line 2534  sub print_autoupdate { Line 3181  sub print_autoupdate {
         my $locknamesettings;          my $locknamesettings;
         $datatable .= &insttypes_row($settings,$types,$usertypes,          $datatable .= &insttypes_row($settings,$types,$usertypes,
                                      $dom,$numinrow,$othertitle,                                       $dom,$numinrow,$othertitle,
                                     'lockablenames');                                      'lockablenames',$rowtotal);
         $$rowtotal ++;          $$rowtotal ++;
     } else {      } else {
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);          my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
Line 2615  sub print_autocreate { Line 3262  sub print_autocreate {
 }  }
   
 sub print_directorysrch {  sub print_directorysrch {
     my ($dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my $srchon = ' ';      my $datatable;
     my $srchoff = ' checked="checked" ';      if ($position eq 'top') {
     my ($exacton,$containson,$beginson);          my $instsrchon = ' ';
     my $localon = ' ';          my $instsrchoff = ' checked="checked" ';
     my $localoff = ' checked="checked" ';          my ($exacton,$containson,$beginson);
     if (ref($settings) eq 'HASH') {          my $instlocalon = ' ';
         if ($settings->{'available'} eq '1') {          my $instlocaloff = ' checked="checked" ';
             $srchon = $srchoff;          if (ref($settings) eq 'HASH') {
             $srchoff = ' ';              if ($settings->{'available'} eq '1') {
         }                  $instsrchon = $instsrchoff;
         if ($settings->{'localonly'} eq '1') {                  $instsrchoff = ' ';
             $localon = $localoff;              }
             $localoff = ' ';              if ($settings->{'localonly'} eq '1') {
         }                  $instlocalon = $instlocaloff;
         if (ref($settings->{'searchtypes'}) eq 'ARRAY') {                  $instlocaloff = ' ';
             foreach my $type (@{$settings->{'searchtypes'}}) {              }
                 if ($type eq 'exact') {              if (ref($settings->{'searchtypes'}) eq 'ARRAY') {
                   foreach my $type (@{$settings->{'searchtypes'}}) {
                       if ($type eq 'exact') {
                           $exacton = ' checked="checked" ';
                       } elsif ($type eq 'contains') {
                           $containson = ' checked="checked" ';
                       } elsif ($type eq 'begins') {
                           $beginson = ' checked="checked" ';
                       }
                   }
               } else {
                   if ($settings->{'searchtypes'} eq 'exact') {
                       $exacton = ' checked="checked" ';
                   } elsif ($settings->{'searchtypes'} eq 'contains') {
                       $containson = ' checked="checked" ';
                   } elsif ($settings->{'searchtypes'} eq 'specify') {
                     $exacton = ' checked="checked" ';                      $exacton = ' checked="checked" ';
                 } elsif ($type eq 'contains') {  
                     $containson = ' checked="checked" ';                      $containson = ' checked="checked" ';
                 } elsif ($type eq 'begins') {  
                     $beginson = ' checked="checked" ';  
                 }                  }
             }              }
         } else {  
             if ($settings->{'searchtypes'} eq 'exact') {  
                 $exacton = ' checked="checked" ';  
             } elsif ($settings->{'searchtypes'} eq 'contains') {  
                 $containson = ' checked="checked" ';  
             } elsif ($settings->{'searchtypes'} eq 'specify') {  
                 $exacton = ' checked="checked" ';  
                 $containson = ' checked="checked" ';  
             }  
         }          }
     }          my ($searchtitles,$titleorder) = &sorted_searchtitles();
     my ($searchtitles,$titleorder) = &sorted_searchtitles();          my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
   
     my $numinrow = 4;          my $numinrow = 4;
     my $cansrchrow = 0;          my $cansrchrow = 0;
     my $datatable='<tr class="LC_odd_row">'.          $datatable='<tr class="LC_odd_row">'.
                   '<td colspan="2"><span class ="LC_nobreak">'.&mt('Directory search available?').'</span></td>'.                     '<td colspan="2"><span class ="LC_nobreak">'.&mt('Institutional directory search available?').'</span></td>'.
                   '<td class="LC_right_item"><span class="LC_nobreak"><label>'.                     '<td class="LC_right_item"><span class="LC_nobreak"><label>'.
                   '<input type="radio" name="dirsrch_available"'.                     '<input type="radio" name="dirsrch_available"'.
                   $srchon.' value="1" />'.&mt('Yes').'</label>&nbsp;'.                     $instsrchon.' value="1" />'.&mt('Yes').'</label>&nbsp;'.
                   '<label><input type="radio" name="dirsrch_available"'.                     '<label><input type="radio" name="dirsrch_available"'.
                   $srchoff.' value="0" />'.&mt('No').'</label></span></td>'.                     $instsrchoff.' value="0" />'.&mt('No').'</label></span></td>'.
                   '</tr><tr>'.                     '</tr><tr>'.
                   '<td colspan="2"><span class ="LC_nobreak">'.&mt('Other domains can search?').'</span></td>'.                     '<td colspan="2"><span class ="LC_nobreak">'.&mt('Other domains can search institution?').'</span></td>'.
                   '<td class="LC_right_item"><span class="LC_nobreak"><label>'.                     '<td class="LC_right_item"><span class="LC_nobreak"><label>'.
                   '<input type="radio" name="dirsrch_localonly"'.                     '<input type="radio" name="dirsrch_instlocalonly"'.
                   $localoff.' value="0" />'.&mt('Yes').'</label>&nbsp;'.                     $instlocaloff.' value="0" />'.&mt('Yes').'</label>&nbsp;'.
                   '<label><input type="radio" name="dirsrch_localonly"'.                     '<label><input type="radio" name="dirsrch_instlocalonly"'.
                   $localon.' value="1" />'.&mt('No').'</label></span></td>'.                     $instlocalon.' value="1" />'.&mt('No').'</label></span></td>'.
                   '</tr>';                     '</tr>';
     $$rowtotal += 2;          $$rowtotal += 2;
     if (ref($usertypes) eq 'HASH') {          if (ref($usertypes) eq 'HASH') {
         if (keys(%{$usertypes}) > 0) {              if (keys(%{$usertypes}) > 0) {
             $datatable .= &insttypes_row($settings,$types,$usertypes,$dom,                  $datatable .= &insttypes_row($settings,$types,$usertypes,$dom,
                                          $numinrow,$othertitle,'cansearch');                                               $numinrow,$othertitle,'cansearch',
             $cansrchrow = 1;                                               $rowtotal);
                   $cansrchrow = 1;
               }
         }          }
     }          if ($cansrchrow) {
     if ($cansrchrow) {              $$rowtotal ++;
         $$rowtotal ++;              $datatable .= '<tr>';
         $datatable .= '<tr>';          } else {
     } else {              $datatable .= '<tr class="LC_odd_row">';
         $datatable .= '<tr class="LC_odd_row">';          }
     }          $datatable .= '<td><span class ="LC_nobreak">'.&mt('Supported search methods').
     $datatable .= '<td><span class ="LC_nobreak">'.&mt('Supported search methods').                        '</span></td><td class="LC_left_item" colspan="2"><table><tr>';
                   '</span></td><td class="LC_left_item" colspan="2"><table><tr>';          foreach my $title (@{$titleorder}) {
     foreach my $title (@{$titleorder}) {              if (defined($searchtitles->{$title})) {
         if (defined($searchtitles->{$title})) {                  my $check = ' ';
             my $check = ' ';                  if (ref($settings) eq 'HASH') {
             if (ref($settings) eq 'HASH') {                      if (ref($settings->{'searchby'}) eq 'ARRAY') {
                 if (ref($settings->{'searchby'}) eq 'ARRAY') {                          if (grep(/^\Q$title\E$/,@{$settings->{'searchby'}})) {
                     if (grep(/^\Q$title\E$/,@{$settings->{'searchby'}})) {                              $check = ' checked="checked" ';
                         $check = ' checked="checked" ';                          }
                     }                      }
                 }                  }
                   $datatable .= '<td class="LC_left_item">'.
                                 '<span class="LC_nobreak"><label>'.
                                 '<input type="checkbox" name="searchby" '.
                                 'value="'.$title.'"'.$check.'/>'.
                                 $searchtitles->{$title}.'</label></span></td>';
             }              }
             $datatable .= '<td class="LC_left_item">'.  
                           '<span class="LC_nobreak"><label>'.  
                           '<input type="checkbox" name="searchby" '.  
                           'value="'.$title.'"'.$check.'/>'.  
                           $searchtitles->{$title}.'</label></span></td>';  
         }          }
     }          $datatable .= '</tr></table></td></tr>';
     $datatable .= '</tr></table></td></tr>';          $$rowtotal ++;
     $$rowtotal ++;          if ($cansrchrow) {
     if ($cansrchrow) {              $datatable .= '<tr class="LC_odd_row">';
         $datatable .= '<tr class="LC_odd_row">';          } else {
               $datatable .= '<tr>';
           }
           $datatable .= '<td><span class ="LC_nobreak">'.&mt('Search latitude').'</span></td>'.   
                         '<td class="LC_left_item" colspan="2">'.
                         '<span class="LC_nobreak"><label>'.
                         '<input type="checkbox" name="searchtypes" '.
                         $exacton.' value="exact" />'.&mt('Exact match').
                         '</label>&nbsp;'.
                         '<label><input type="checkbox" name="searchtypes" '.
                         $beginson.' value="begins" />'.&mt('Begins with').
                         '</label>&nbsp;'.
                         '<label><input type="checkbox" name="searchtypes" '.
                         $containson.' value="contains" />'.&mt('Contains').
                         '</label></span></td></tr>';
           $$rowtotal ++;
     } else {      } else {
         $datatable .= '<tr>';          my $domsrchon = ' checked="checked" ';
           my $domsrchoff = ' ';
           my $domlocalon = ' ';
           my $domlocaloff = ' checked="checked" ';
           if (ref($settings) eq 'HASH') {
               if ($settings->{'lclocalonly'} eq '1') {
                   $domlocalon = $domlocaloff;
                   $domlocaloff = ' ';
               }
               if ($settings->{'lcavailable'} eq '0') {
                   $domsrchoff = $domsrchon;
                   $domsrchon = ' ';
               }
           }
           $datatable='<tr class="LC_odd_row">'.
                         '<td colspan="2"><span class ="LC_nobreak">'.&mt('LON-CAPA directory search available?').'</span></td>'.
                         '<td class="LC_right_item"><span class="LC_nobreak"><label>'.
                         '<input type="radio" name="dirsrch_domavailable"'.
                         $domsrchon.' value="1" />'.&mt('Yes').'</label>&nbsp;'.
                         '<label><input type="radio" name="dirsrch_domavailable"'.
                         $domsrchoff.' value="0" />'.&mt('No').'</label></span></td>'.
                         '</tr><tr>'.
                         '<td colspan="2"><span class ="LC_nobreak">'.&mt('Other domains can search LON-CAPA domain?').'</span></td>'.
                         '<td class="LC_right_item"><span class="LC_nobreak"><label>'.
                         '<input type="radio" name="dirsrch_domlocalonly"'.
                         $domlocaloff.' value="0" />'.&mt('Yes').'</label>&nbsp;'.
                         '<label><input type="radio" name="dirsrch_domlocalonly"'.
                         $domlocalon.' value="1" />'.&mt('No').'</label></span></td>'.
                         '</tr>';
           $$rowtotal += 2;
     }      }
     $datatable .= '<td><span class ="LC_nobreak">'.&mt('Search latitude').'</span></td>'.     
                   '<td class="LC_left_item" colspan="2">'.  
                   '<span class="LC_nobreak"><label>'.  
                   '<input type="checkbox" name="searchtypes" '.  
                   $exacton.' value="exact" />'.&mt('Exact match').  
                   '</label>&nbsp;'.  
                   '<label><input type="checkbox" name="searchtypes" '.  
                   $beginson.' value="begins" />'.&mt('Begins with').  
                   '</label>&nbsp;'.  
                   '<label><input type="checkbox" name="searchtypes" '.  
                   $containson.' value="contains" />'.&mt('Contains').  
                   '</label></span></td></tr>';  
     $$rowtotal ++;  
     return $datatable;      return $datatable;
 }  }
   
 sub print_contacts {  sub print_contacts {
     my ($dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my $datatable;      my $datatable;
     my @contacts = ('adminemail','supportemail');      my @contacts = ('adminemail','supportemail');
     my (%checked,%to,%otheremails,%bccemails);      my (%checked,%to,%otheremails,%bccemails,%includestr,%includeloc,%currfield,
     my @mailings = ('errormail','packagesmail','lonstatusmail','helpdeskmail',          $maxsize,$fields,$fieldtitles,$fieldoptions,$possoptions,@mailings,%lonstatus);
                     'requestsmail','updatesmail','idconflictsmail');      if ($position eq 'top') {
     foreach my $type (@mailings) {          if (ref($settings) eq 'HASH') {
         $otheremails{$type} = '';              foreach my $item (@contacts) {
     }                  if (exists($settings->{$item})) {
     $bccemails{'helpdeskmail'} = '';                      $to{$item} = $settings->{$item};
     if (ref($settings) eq 'HASH') {                  }
         foreach my $item (@contacts) {  
             if (exists($settings->{$item})) {  
                 $to{$item} = $settings->{$item};  
             }              }
         }          }
       } elsif ($position eq 'middle') {
           @mailings = ('errormail','packagesmail','lonstatusmail','requestsmail',
                        'updatesmail','idconflictsmail','hostipmail');
         foreach my $type (@mailings) {          foreach my $type (@mailings) {
             if (exists($settings->{$type})) {              $otheremails{$type} = '';
                 if (ref($settings->{$type}) eq 'HASH') {          }
                     foreach my $item (@contacts) {      } elsif ($position eq 'lower') {
                         if ($settings->{$type}{$item}) {          if (ref($settings) eq 'HASH') {
                             $checked{$type}{$item} = ' checked="checked" ';              if (ref($settings->{'lonstatus'}) eq 'HASH') {
                   %lonstatus = %{$settings->{'lonstatus'}};
               }
           }
       } else {
           @mailings = ('helpdeskmail','otherdomsmail');
           foreach my $type (@mailings) {
               $otheremails{$type} = '';
           }
           $bccemails{'helpdeskmail'} = '';
           $bccemails{'otherdomsmail'} = '';
           $includestr{'helpdeskmail'} = '';
           $includestr{'otherdomsmail'} = '';
           ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields();
       }
       if (ref($settings) eq 'HASH') {
           unless (($position eq 'top') || ($position eq 'lower')) {
               foreach my $type (@mailings) {
                   if (exists($settings->{$type})) {
                       if (ref($settings->{$type}) eq 'HASH') {
                           foreach my $item (@contacts) {
                               if ($settings->{$type}{$item}) {
                                   $checked{$type}{$item} = ' checked="checked" ';
                               }
                           }
                           $otheremails{$type} = $settings->{$type}{'others'};
                           if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
                               $bccemails{$type} = $settings->{$type}{'bcc'};
                               if ($settings->{$type}{'include'} ne '') {
                                   ($includeloc{$type},$includestr{$type}) = split(/:/,$settings->{$type}{'include'},2);
                                   $includestr{$type} = &unescape($includestr{$type});
                               }
                         }                          }
                     }                      }
                     $otheremails{$type} = $settings->{$type}{'others'};                  } elsif ($type eq 'lonstatusmail') {
                     if ($type eq 'helpdeskmail') {                      $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" ';
                         $bccemails{$type} = $settings->{$type}{'bcc'};                  }
               }
           }
           if ($position eq 'bottom') {
               foreach my $type (@mailings) {
                   $bccemails{$type} = $settings->{$type}{'bcc'};
                   if ($settings->{$type}{'include'} ne '') {
                       ($includeloc{$type},$includestr{$type}) = split(/:/,$settings->{$type}{'include'},2);
                       $includestr{$type} = &unescape($includestr{$type});
                   }
               }
               if (ref($settings->{'helpform'}) eq 'HASH') {
                   if (ref($fields) eq 'ARRAY') {
                       foreach my $field (@{$fields}) {
                           $currfield{$field} = $settings->{'helpform'}{$field};
                       }
                   }
                   if (exists($settings->{'helpform'}{'maxsize'})) {
                       $maxsize = $settings->{'helpform'}{'maxsize'};
                   } else {
                       $maxsize = '1.0';
                   }
               } else {
                   if (ref($fields) eq 'ARRAY') {
                       foreach my $field (@{$fields}) {
                           $currfield{$field} = 'yes';
                     }                      }
                 }                  }
             } elsif ($type eq 'lonstatusmail') {                  $maxsize = '1.0';
                 $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" ';  
             }              }
         }          }
     } else {      } else {
         $to{'supportemail'} = $Apache::lonnet::perlvar{'lonSupportEMail'};          if ($position eq 'top') {
         $to{'adminemail'} = $Apache::lonnet::perlvar{'lonAdmEMail'};              $to{'supportemail'} = $Apache::lonnet::perlvar{'lonSupportEMail'};
         $checked{'errormail'}{'adminemail'} = ' checked="checked" ';              $to{'adminemail'} = $Apache::lonnet::perlvar{'lonAdmEMail'};
         $checked{'packagesmail'}{'adminemail'} = ' checked="checked" ';              $checked{'errormail'}{'adminemail'} = ' checked="checked" ';
         $checked{'helpdeskmail'}{'supportemail'} = ' checked="checked" ';              $checked{'packagesmail'}{'adminemail'} = ' checked="checked" ';
         $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" ';               $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" ';
         $checked{'requestsmail'}{'adminemail'} = ' checked="checked" ';              $checked{'requestsmail'}{'adminemail'} = ' checked="checked" ';
         $checked{'updatesmail'}{'adminemail'} = ' checked="checked" ';              $checked{'updatesmail'}{'adminemail'} = ' checked="checked" ';
         $checked{'idconflictsmail'}{'adminemail'} = ' checked="checked" ';              $checked{'idconflictsmail'}{'adminemail'} = ' checked="checked" ';
               $checked{'hostipmail'}{'adminemail'} = ' checked="checked" ';
           } elsif ($position eq 'bottom') {
               $checked{'helpdeskmail'}{'supportemail'} = ' checked="checked" ';
               $checked{'otherdomsmail'}{'supportemail'} = ' checked="checked" ';
               if (ref($fields) eq 'ARRAY') {
                   foreach my $field (@{$fields}) {
                       $currfield{$field} = 'yes';
                   }
               }
               $maxsize = '1.0';
           }
     }      }
     my ($titles,$short_titles) = &contact_titles();      my ($titles,$short_titles) = &contact_titles();
     my $rownum = 0;      my $rownum = 0;
     my $css_class;      my $css_class;
     foreach my $item (@contacts) {      if ($position eq 'top') {
           foreach my $item (@contacts) {
               $css_class = $rownum%2?' class="LC_odd_row"':'';
               $datatable .= '<tr'.$css_class.'>'. 
                             '<td><span class="LC_nobreak">'.$titles->{$item}.
                             '</span></td><td class="LC_right_item">'.
                             '<input type="text" name="'.$item.'" value="'.
                             $to{$item}.'" /></td></tr>';
               $rownum ++;
           }
       } elsif ($position eq 'bottom') {
         $css_class = $rownum%2?' class="LC_odd_row"':'';          $css_class = $rownum%2?' class="LC_odd_row"':'';
         $datatable .= '<tr'.$css_class.'>'.           $datatable .= '<tr'.$css_class.'>'.
                   '<td><span class="LC_nobreak">'.$titles->{$item}.                        '<td>'.&mt('Extra helpdesk form fields:').'<br />'.
                   '</span></td><td class="LC_right_item">'.                        &mt('(e-mail, subject, and description always shown)').
                   '<input type="text" name="'.$item.'" value="'.                        '</td><td class="LC_left_item">';
                   $to{$item}.'" /></td></tr>';          if ((ref($fields) eq 'ARRAY') && (ref($fieldtitles) eq 'HASH') &&
               (ref($fieldoptions) eq 'HASH') && (ref($possoptions) eq 'HASH')) {
               $datatable .= '<table><tr><th>'.&mt('Field').'</th><th>'.&mt('Status').'</th></tr>';
               foreach my $field (@{$fields}) {
                   $datatable .= '<tr><td>'.$fieldtitles->{$field};
                   if (($field eq 'screenshot') || ($field eq 'cc')) {
                       $datatable .= ' '.&mt('(logged-in users)');
                   }
                   $datatable .='</td><td>';
                   my $clickaction;
                   if ($field eq 'screenshot') {
                       $clickaction = ' onclick="screenshotSize(this);"';
                   }
                   if (ref($possoptions->{$field}) eq 'ARRAY') {
                       foreach my $option (@{$possoptions->{$field}}) {
                           my $checked;
                           if ($currfield{$field} eq $option) {
                               $checked = ' checked="checked"';
                           }
                           $datatable .= '<span class="LC_nobreak"><label>'.
                                         '<input type="radio" name="helpform_'.$field.'" '.
                                         'value="'.$option.'"'.$checked.$clickaction.' />'.$fieldoptions->{$option}.
                                         '</label></span>'.('&nbsp;'x2);
                       }
                   }
                   if ($field eq 'screenshot') {
                       my $display;
                       if ($currfield{$field} eq 'no') {
                           $display = ' style="display:none"';
                       }
                       $datatable .= '</td></tr><tr id="help_screenshotsize"'.$display.'>'.
                                     '<td>'.&mt('Maximum size for upload (MB)').'</td><td>'.
                                     '<input type="text" size="5" name="helpform_maxsize" value="'.$maxsize.'" />';
                   }
                   $datatable .= '</td></tr>';
               }
               $datatable .= '</table>';
           }
           $datatable .= '</td></tr>'."\n";
         $rownum ++;          $rownum ++;
     }      }
     foreach my $type (@mailings) {      unless (($position eq 'top') || ($position eq 'lower')) {
           foreach my $type (@mailings) {
               $css_class = $rownum%2?' class="LC_odd_row"':'';
               $datatable .= '<tr'.$css_class.'>'.
                             '<td><span class="LC_nobreak">'.
                             $titles->{$type}.': </span></td>'.
                             '<td class="LC_left_item">';
               if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
                   $datatable .= '<fieldset><legend>'.&mt('E-mail recipient(s)').'</legend>';
               }
               $datatable .= '<span class="LC_nobreak">';
               foreach my $item (@contacts) {
                   $datatable .= '<label>'.
                                 '<input type="checkbox" name="'.$type.'"'.
                                 $checked{$type}{$item}.
                                 ' value="'.$item.'" />'.$short_titles->{$item}.
                                 '</label>&nbsp;';
               }
               $datatable .= '</span><br />'.&mt('Others').':&nbsp;&nbsp;'.
                             '<input type="text" name="'.$type.'_others" '.
                             'value="'.$otheremails{$type}.'"  />';
               my %locchecked;
               if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
                   foreach my $loc ('s','b') {
                       if ($includeloc{$type} eq $loc) {
                           $locchecked{$loc} = ' checked="checked"';
                           last;
                       }
                   }
                   $datatable .= '<br />'.&mt('Bcc:').('&nbsp;'x6).
                                 '<input type="text" name="'.$type.'_bcc" '.
                                 'value="'.$bccemails{$type}.'"  /></fieldset>'.
                                 '<fieldset><legend>'.&mt('Optional added text').'</legend>'.
                                 &mt('Text automatically added to e-mail:').' '.
                                 '<input type="text" name="'.$type.'_includestr" value="'.$includestr{$type}.'" /><br />'.
                                 '<span class="LC_nobreak">'.&mt('Location:').'&nbsp;'.
                                 '<label><input type="radio" name="'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'.
                                 ('&nbsp;'x2).
                                 '<label><input type="radio" name="'.$type.'_includeloc" value="b"'.$locchecked{'b'}.' />'.&mt('in body').'</label>'.
                                 '</span></fieldset>';
               }
               $datatable .= '</td></tr>'."\n";
               $rownum ++;
           }
       }
       if ($position eq 'middle') {
           my %choices;
           my $corelink = &core_link_msu();
           $choices{'reporterrors'} = &mt('E-mail error reports to [_1]',$corelink);
           $choices{'reportupdates'} = &mt('E-mail record of completed LON-CAPA updates to [_1]',
                                           $corelink);
           $choices{'reportstatus'} = &mt('E-mail status if errors above threshold to [_1]',$corelink);
           my @toggles = ('reporterrors','reportupdates','reportstatus');
           my %defaultchecked = ('reporterrors'  => 'on',
                                 'reportupdates' => 'on',
                                 'reportstatus'  => 'on');
           (my $reports,$rownum) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
                                                      \%choices,$rownum);
           $datatable .= $reports;
       } elsif ($position eq 'lower') {
           $css_class = $rownum%2?' class="LC_odd_row"':'';
           my ($threshold,$sysmail,%excluded,%weights);
           my ($defaults,$names) = &Apache::loncommon::lon_status_items();
           if ($lonstatus{'threshold'} =~ /^\d+$/) {
               $threshold = $lonstatus{'threshold'};
           } else {
               $threshold = $defaults->{'threshold'};
           }
           if ($lonstatus{'sysmail'} =~ /^\d+$/) {
               $sysmail = $lonstatus{'sysmail'};
           } else {
               $sysmail = $defaults->{'sysmail'};
           }
           if (ref($lonstatus{'weights'}) eq 'HASH') {
               foreach my $type ('E','W','N','U') {
                   if ($lonstatus{'weights'}{$type} =~ /^\d+$/) {
                       $weights{$type} = $lonstatus{'weights'}{$type};
                   } else {
                       $weights{$type} = $defaults->{$type};
                   }
               }
           } else {
               foreach my $type ('E','W','N','U') {
                   $weights{$type} = $defaults->{$type};
               }
           }
           if (ref($lonstatus{'excluded'}) eq 'ARRAY') {
               if (@{$lonstatus{'excluded'}} > 0) {
                   map {$excluded{$_} = 1; } @{$lonstatus{'excluded'}};
               }
           }
           $datatable .= '<tr'.$css_class.'>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         $titles->{'errorthreshold'}.
                         '</span></td><td class="LC_left_item">'.
                         '<input type="text" name="errorthreshold" value="'.
                         $threshold.'" size="5" /></td></tr>';
           $rownum ++;
         $css_class = $rownum%2?' class="LC_odd_row"':'';          $css_class = $rownum%2?' class="LC_odd_row"':'';
         $datatable .= '<tr'.$css_class.'>'.          $datatable .= '<tr'.$css_class.'>'.
                       '<td><span class="LC_nobreak">'.  
                       $titles->{$type}.': </span></td>'.  
                       '<td class="LC_left_item">'.                        '<td class="LC_left_item">'.
                       '<span class="LC_nobreak">';                        '<span class="LC_nobreak">'.$titles->{'errorweights'}.
         foreach my $item (@contacts) {                        '</span></td><td class="LC_left_item"><table><tr>';
             $datatable .= '<label>'.          foreach my $type ('E','W','N','U') {
                           '<input type="checkbox" name="'.$type.'"'.              $datatable .= '<td>'.$names->{$type}.'<br />'.
                           $checked{$type}{$item}.                            '<input type="text" name="errorweights_'.$type.'" value="'.
                           ' value="'.$item.'" />'.$short_titles->{$item}.                            $weights{$type}.'" size="5" /></td>';
                           '</label>&nbsp;';  
         }  
         $datatable .= '</span><br />'.&mt('Others').':&nbsp;&nbsp;'.  
                       '<input type="text" name="'.$type.'_others" '.  
                       'value="'.$otheremails{$type}.'"  />';  
         if ($type eq 'helpdeskmail') {  
             $datatable .= '<br />'.&mt('Bcc:').('&nbsp;'x6).  
                           '<input type="text" name="'.$type.'_bcc" '.  
                           'value="'.$bccemails{$type}.'"  />';  
         }          }
         $datatable .= '</td></tr>'."\n";          $datatable .= '</tr></table></tr>';
         $rownum ++;          $rownum ++;
           $css_class = $rownum%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td class="LC_left_item">'.
                         $titles->{'errorexcluded'}.'</td>'.
                         '<td class="LC_left_item"><table>';
           my $numinrow = 4;
           my @ids = sort(values(%Apache::lonnet::serverhomeIDs));
           for (my $i=0; $i<@ids; $i++) {
               my $rem = $i%($numinrow);
               if ($rem == 0) {
                   if ($i > 0) {
                       $datatable .= '</tr>';
                   }
                   $datatable .= '<tr>';
               }
               my $check;
               if ($excluded{$ids[$i]}) {
                   $check = ' checked="checked" ';
               }
               $datatable .= '<td class="LC_left_item">'.
                             '<span class="LC_nobreak"><label>'.
                             '<input type="checkbox" name="errorexcluded" '.
                             'value="'.$ids[$i].'"'.$check.' />'.
                             $ids[$i].'</label></span></td>';
           }
           my $colsleft = $numinrow - @ids%($numinrow);
           if ($colsleft > 1 ) {
               $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
                             '&nbsp;</td>';
           } elsif ($colsleft == 1) {
               $datatable .= '<td class="LC_left_item">&nbsp;</td>';
           }
           $datatable .= '</tr></table></td></tr>';
           $rownum ++;
           $css_class = $rownum%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         $titles->{'errorsysmail'}.
                         '</span></td><td class="LC_left_item">'.
                         '<input type="text" name="errorsysmail" value="'.
                         $sysmail.'" size="5" /></td></tr>';
           $rownum ++;
       } elsif ($position eq 'bottom') {
           my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
           my (@posstypes,%usertypeshash);
           if (ref($types) eq 'ARRAY') {
               @posstypes = @{$types};
           }
           if (@posstypes) {
               if (ref($usertypes) eq 'HASH') {
                   %usertypeshash = %{$usertypes};
               }
               my @overridden;
               my $numinrow = 4;
               if (ref($settings) eq 'HASH') {
                   if (ref($settings->{'overrides'}) eq 'HASH') {
                       foreach my $key (sort(keys(%{$settings->{'overrides'}}))) {
                           if (ref($settings->{'overrides'}{$key}) eq 'HASH') {
                               push(@overridden,$key);
                               foreach my $item (@contacts) {
                                   if ($settings->{'overrides'}{$key}{$item}) {
                                       $checked{'override_'.$key}{$item} = ' checked="checked" ';
                                   }
                               }
                               $otheremails{'override_'.$key} = $settings->{'overrides'}{$key}{'others'};
                               $bccemails{'override_'.$key} = $settings->{'overrides'}{$key}{'bcc'};
                               $includeloc{'override_'.$key} = '';
                               $includestr{'override_'.$key} = '';
                               if ($settings->{'overrides'}{$key}{'include'} ne '') {
                                   ($includeloc{'override_'.$key},$includestr{'override_'.$key}) = 
                                       split(/:/,$settings->{'overrides'}{$key}{'include'},2);
                                   $includestr{'override_'.$key} = &unescape($includestr{'override_'.$key});
                               }
                           }
                       }
                   }
               }
               my $customclass = 'LC_helpdesk_override';
               my $optionsprefix = 'LC_options_helpdesk_';
   
               my $onclicktypes = "toggleHelpdeskRow(this.form,'overrides','$customclass','$optionsprefix');";
    
               $datatable .= &insttypes_row($settings,$types,$usertypes,$dom,
                                            $numinrow,$othertitle,'overrides',
                                            \$rownum,$onclicktypes,$customclass);
               $rownum ++;
               $usertypeshash{'default'} = $othertitle;
               foreach my $status (@posstypes) {
                   my $css_class;
                   if ($rownum%2) {
                       $css_class = 'LC_odd_row ';
                   }
                   $css_class .= $customclass;
                   my $rowid = $optionsprefix.$status;
                   my $hidden = 1;
                   my $currstyle = 'display:none';
                   if (grep(/^\Q$status\E$/,@overridden)) {
                       $currstyle = 'display:table-row';
                       $hidden = 0;
                   }
                   my $key = 'override_'.$status;
                   $datatable .= &overridden_helpdesk($checked{$key},$otheremails{$key},$bccemails{$key},
                                                     $includeloc{$key},$includestr{$key},$status,$rowid,
                                                     $usertypeshash{$status},$css_class,$currstyle,
                                                     \@contacts,$short_titles);
                   unless ($hidden) {
                       $rownum ++;
                   }
               }
           }
     }      }
     my %choices;  
     $choices{'reporterrors'} = &mt('E-mail error reports to [_1]',  
                                    &Apache::loncommon::modal_link('http://loncapa.org/core.html',  
                                    &mt('LON-CAPA core group - MSU'),600,500));  
     $choices{'reportupdates'} = &mt('E-mail record of completed LON-CAPA updates to [_1]',  
                                     &Apache::loncommon::modal_link('http://loncapa.org/core.html',  
                                     &mt('LON-CAPA core group - MSU'),600,500));  
     my @toggles = ('reporterrors','reportupdates');  
     my %defaultchecked = ('reporterrors'  => 'on',  
                           'reportupdates' => 'on');  
     (my $reports,$rownum) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,  
                                                \%choices,$rownum);  
     $datatable .= $reports;  
     $$rowtotal += $rownum;      $$rowtotal += $rownum;
     return $datatable;      return $datatable;
 }  }
   
   sub core_link_msu {
       return &Apache::loncommon::modal_link('http://loncapa.org/core.html',
                                             &mt('LON-CAPA core group - MSU'),600,500);
   }
   
   sub overridden_helpdesk {
       my ($checked,$otheremails,$bccemails,$includeloc,$includestr,$type,$rowid,
           $typetitle,$css_class,$rowstyle,$contacts,$short_titles) = @_;
       my $class = 'LC_left_item';
       if ($css_class) {
           $css_class = ' class="'.$css_class.'"';
       }
       if ($rowid) {
           $rowid = ' id="'.$rowid.'"';
       }
       if ($rowstyle) {
           $rowstyle = ' style="'.$rowstyle.'"';
       }
       my ($output,$description);
       $description = &mt('Helpdesk requests from: [_1] in this domain (overrides default)',"<b>$typetitle</b>");
       $output = '<tr'.$css_class.$rowid.$rowstyle.'>'.
                 "<td>$description</td>\n".
                 '<td class="'.$class.'" colspan="2">'.
                 '<fieldset><legend>'.&mt('E-mail recipient(s)').'</legend>'.
                 '<span class="LC_nobreak">';
       if (ref($contacts) eq 'ARRAY') {
           foreach my $item (@{$contacts}) {
               my $check;
               if (ref($checked) eq 'HASH') {
                  $check = $checked->{$item};
               }
               my $title;
               if (ref($short_titles) eq 'HASH') {
                   $title = $short_titles->{$item}; 
               }
               $output .= '<label>'.
                          '<input type="checkbox" name="override_'.$type.'"'.$check.
                          ' value="'.$item.'" />'.$title.'</label>&nbsp;';
           }
       }
       $output .= '</span><br />'.&mt('Others').':&nbsp;&nbsp;'.
                  '<input type="text" name="override_'.$type.'_others" '.
                  'value="'.$otheremails.'"  />';
       my %locchecked;
       foreach my $loc ('s','b') {
           if ($includeloc eq $loc) {
               $locchecked{$loc} = ' checked="checked"';
               last;
           }
       }
       $output .= '<br />'.&mt('Bcc:').('&nbsp;'x6).
                  '<input type="text" name="override_'.$type.'_bcc" '.
                  'value="'.$bccemails.'"  /></fieldset>'.
                  '<fieldset><legend>'.&mt('Optional added text').'</legend>'.
                  &mt('Text automatically added to e-mail:').' '.
                  '<input type="text" name="override_'.$type.'_includestr" value="'.$includestr.'" /><br />'.
                  '<span class="LC_nobreak">'.&mt('Location:').'&nbsp;'.
                  '<label><input type="radio" name="override_'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'.
                  ('&nbsp;'x2).
                  '<label><input type="radio" name="override_'.$type.'_includeloc" value="b"'.$locchecked{'b'}.' />'.&mt('in body').'</label>'.
                  '</span></fieldset>'.
                  '</td></tr>'."\n";
       return $output;
   }
   
   sub contacts_javascript {
       return <<"ENDSCRIPT";
   
   <script type="text/javascript">
   // <![CDATA[
   
   function screenshotSize(field) {
       if (document.getElementById('help_screenshotsize')) {
           if (field.value == 'no') {
               document.getElementById('help_screenshotsize').style.display="none";
           } else {
               document.getElementById('help_screenshotsize').style.display="";
           }
       }
       return;
   }
   
   function toggleHelpdeskRow(form,checkbox,target,prefix,docount) {
       if (form.elements[checkbox].length != undefined) {
           var count = 0;
           if (docount) {
               for (var i=0; i<form.elements[checkbox].length; i++) {
                   if (form.elements[checkbox][i].checked) {
                       count ++;
                   }
               }
           }
           for (var i=0; i<form.elements[checkbox].length; i++) {
               var type = form.elements[checkbox][i].value;
               if (document.getElementById(prefix+type)) {
                   if (form.elements[checkbox][i].checked) {
                       document.getElementById(prefix+type).style.display = 'table-row';
                       if (count % 2 == 1) {
                           document.getElementById(prefix+type).className = target+' LC_odd_row';
                       } else {
                           document.getElementById(prefix+type).className = target;
                       }
                       count ++;
                   } else {
                       document.getElementById(prefix+type).style.display = 'none';
                   }
               }
           }
       }
       return;
   }
   
   
   // ]]>
   </script>
   
   ENDSCRIPT
   }
   
 sub print_helpsettings {  sub print_helpsettings {
     my ($dom,$confname,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
       my $confname = $dom.'-domainconfig';
       my $formname = 'display';
     my ($datatable,$itemcount);      my ($datatable,$itemcount);
     $itemcount = 1;      if ($position eq 'top') {
     my (%choices,%defaultchecked,@toggles);          $itemcount = 1;
     $choices{'submitbugs'} = &mt('Display link to: [_1]?',          my (%choices,%defaultchecked,@toggles);
                                  &Apache::loncommon::modal_link('http://bugs.loncapa.org',          $choices{'submitbugs'} = &mt('Display link to: [_1]?',
                                  &mt('LON-CAPA bug tracker'),600,500));                                       &Apache::loncommon::modal_link('http://bugs.loncapa.org',
     %defaultchecked = ('submitbugs' => 'on');                                       &mt('LON-CAPA bug tracker'),600,500));
     @toggles = ('submitbugs',);          %defaultchecked = ('submitbugs' => 'on');
           @toggles = ('submitbugs');
     ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,          ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
                                                  \%choices,$itemcount);                                                       \%choices,$itemcount);
           $$rowtotal ++;
       } else {
           my $css_class;
           my %existing=&Apache::lonnet::dump('roles',$dom,$confname,'rolesdef_');
           my (%customroles,%ordered,%current);
           if (ref($settings) eq 'HASH') {
               if (ref($settings->{'adhoc'}) eq 'HASH') {
                   %current = %{$settings->{'adhoc'}};
               }
           }
           my $count = 0;
           foreach my $key (sort(keys(%existing))) {
               if ($key=~/^rolesdef\_(\w+)$/) {
                   my $rolename = $1;
                   my (%privs,$order);
                   ($privs{'system'},$privs{'domain'},$privs{'course'}) = split(/\_/,$existing{$key});
                   $customroles{$rolename} = \%privs;
                   if (ref($current{$rolename}) eq 'HASH') {
                       $order = $current{$rolename}{'order'};
                   }
                   if ($order eq '') {
                       $order = $count;
                   }
                   $ordered{$order} = $rolename;
                   $count++;
               }
           }
           my $maxnum = scalar(keys(%ordered));
           my @roles_by_num = ();
           foreach my $item (sort {$a <=> $b } (keys(%ordered))) {
               push(@roles_by_num,$item);
           }
           my $context = 'domprefs';
           my $crstype = 'Course';
           my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
           my @accesstypes = ('all','dh','da','none');
           my ($numstatustypes,@jsarray);
           if (ref($types) eq 'ARRAY') {
               if (@{$types} > 0) {
                   $numstatustypes = scalar(@{$types});
                   push(@accesstypes,'status');
                   @jsarray = ('bystatus');
               }
           }
           my %domhelpdesk = &Apache::lonnet::get_active_domroles($dom,['dh','da']);
           if (keys(%domhelpdesk)) {
               push(@accesstypes,('inc','exc'));
               push(@jsarray,('notinc','notexc'));
           }
           my $hiddenstr = join("','",@jsarray);
           my $context = 'domprefs';
           my $crstype = 'Course';
           my $prefix = 'helproles_';
           my $add_class = 'LC_hidden';
           foreach my $num (@roles_by_num) {
               my $role = $ordered{$num};
               my ($desc,$access,@statuses);
               if (ref($current{$role}) eq 'HASH') {
                   $desc = $current{$role}{'desc'};
                   $access = $current{$role}{'access'};
                   if (ref($current{$role}{'insttypes'}) eq 'ARRAY') {
                       @statuses = @{$current{$role}{'insttypes'}};
                   }
               }
               if ($desc eq '') {
                   $desc = $role;
               }
               my $identifier = 'custhelp'.$num;
               my %full=();
               my %levels= (
                            course => {},
                            domain => {},
                            system => {},
                           );
               my %levelscurrent=(
                                  course => {},
                                  domain => {},
                                  system => {},
                                 );
               &Apache::lonuserutils::custom_role_privs($customroles{$role},\%full,\%levels,\%levelscurrent);
               my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
               $css_class = $itemcount%2?' class="LC_odd_row"':'';
               my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$num."_pos'".');"';
               $datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><b>'.$role.'</b><br />'.
                             '<select name="helproles_'.$num.'_pos"'.$chgstr.'>';
               for (my $k=0; $k<=$maxnum; $k++) {
                   my $vpos = $k+1;
                   my $selstr;
                   if ($k == $num) {
                       $selstr = ' selected="selected" ';
                   }
                   $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
               }
               $datatable .= '</select>'.('&nbsp;'x2).
                             '<input type="hidden" name="helproles_'.$num.'" value="'.$role.'" />'.
                             '</td>'.
                             '<td><fieldset><legend>'.&mt('Role name').'</legend>'.
                             &mt('Name shown to users:').
                             '<input type="text" name="helproles_'.$num.'_desc" value="'.$desc.'" />'.
                             '</fieldset>'.
                             &helpdeskroles_access($dom,$prefix,$num,$add_class,$current{$role},\@accesstypes,
                                                   $othertitle,$usertypes,$types,\%domhelpdesk).
                             '<fieldset>'.
                             '<legend>'.&mt('Role privileges').&adhocbutton($prefix,$num,'privs','show').'</legend>'.
                             &Apache::lonuserutils::custom_role_table($crstype,\%full,\%levels,
                                                                      \%levelscurrent,$identifier,
                                                                      'LC_hidden',$prefix.$num.'_privs').
                             '</fieldset></td>';
               $itemcount ++;
           }
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           my $newcust = 'custhelp'.$count;
           my (%privs,%levelscurrent);
           my %full=();
           my %levels= (
                        course => {},
                        domain => {},
                        system => {},
                       );
           &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);
           my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
           my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$count."_pos'".');"';
           $datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><span class="LC_nobreak"><label>'.
                         '<input type="hidden" name="helproles_maxnum" value="'.$maxnum.'" />'."\n".
                         '<select name="helproles_'.$count.'_pos"'.$chgstr.'>';
           for (my $k=0; $k<$maxnum+1; $k++) {
               my $vpos = $k+1;
               my $selstr;
               if ($k == $maxnum) {
                   $selstr = ' selected="selected" ';
               }
               $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
           }
           $datatable .= '</select>&nbsp;'."\n".
                         '<input type="checkbox" name="newcusthelp" value="'.$count.'" />'. &mt('Add').
                         '</label></span></td>'.
                         '<td><fieldset><legend>'.&mt('Role name').'</legend>'.
                         '<span class="LC_nobreak">'.
                         &mt('Internal name:').
                         '<input type="text" size="10" name="custhelpname'.$count.'" value="" />'.
                         '</span>'.('&nbsp;'x4).
                         '<span class="LC_nobreak">'.
                         &mt('Name shown to users:').
                         '<input type="text" size="20" name="helproles_'.$count.'_desc" value="" />'.
                         '</span></fieldset>'.
                          &helpdeskroles_access($dom,$prefix,$count,'',undef,\@accesstypes,$othertitle,
                                                $usertypes,$types,\%domhelpdesk).
                         '<fieldset><legend>'.&mt('Role privileges').'</legend>'.
                         &Apache::lonuserutils::custom_role_header($context,$crstype,
                                                                   \@templateroles,$newcust).
                         &Apache::lonuserutils::custom_role_table('Course',\%full,\%levels,
                                                                  \%levelscurrent,$newcust).
                         '</fieldset>'.
                         &helpsettings_javascript(\@roles_by_num,$maxnum,$hiddenstr,$formname).
                         '</td></tr>';
           $count ++;
           $$rowtotal += $count;
       }
     return $datatable;      return $datatable;
 }  }
   
   sub adhocbutton {
       my ($prefix,$num,$field,$visibility) = @_;
       my %lt = &Apache::lonlocal::texthash(
                                             show => 'Show details',
                                             hide => 'Hide details',
                                           );
       return '<span style="text-decoration:line-through; font-weight: normal;">'.('&nbsp;'x10).
              '</span>'.('&nbsp;'x2).'<input type="button" id="'.$prefix.$num.'_'.$field.'_vis"'.
              ' value="'.$lt{$visibility}.'" style="height:20px;" '.
              'onclick="toggleHelpdeskItem('."'$num','$field'".');" />'.('&nbsp;'x2);
   }
   
   sub helpsettings_javascript {
       my ($roles_by_num,$total,$hiddenstr,$formname) = @_;
       return unless(ref($roles_by_num) eq 'ARRAY');
       my %html_js_lt = &Apache::lonlocal::texthash(
                                             show => 'Show details',
                                             hide => 'Hide details',
                                           );
       &html_escape(\%html_js_lt);
       my $jstext = '    var helproles = Array('."'".join("','",@{$roles_by_num})."'".');'."\n";
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   
   function reorderHelpRoles(form,item) {
       var changedVal;
   $jstext
       var newpos = 'helproles_${total}_pos';
       var maxh = 1 + $total;
       var current = new Array();
       var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;
       if (item == newpos) {
           changedVal = newitemVal;
       } else {
           changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;
           current[newitemVal] = newpos;
       }
       for (var i=0; i<helproles.length; i++) {
           var elementName = 'helproles_'+helproles[i]+'_pos';
           if (elementName != item) {
               if (form.elements[elementName]) {
                   var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
                   current[currVal] = elementName;
               }
           }
       }
       var oldVal;
       for (var j=0; j<maxh; j++) {
           if (current[j] == undefined) {
               oldVal = j;
           }
       }
       if (oldVal < changedVal) {
           for (var k=oldVal+1; k<=changedVal ; k++) {
              var elementName = current[k];
              form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;
           }
       } else {
           for (var k=changedVal; k<oldVal; k++) {
               var elementName = current[k];
               form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;
           }
       }
       return;
   }
   
   function helpdeskAccess(num) {
       var curraccess = null;
       if (document.$formname.elements['helproles_'+num+'_access'].length) {
           for (var i=0; i<document.$formname.elements['helproles_'+num+'_access'].length; i++) {
               if (document.$formname.elements['helproles_'+num+'_access'][i].checked) {
                   curraccess = document.$formname.elements['helproles_'+num+'_access'][i].value;
               }
           }
       }
       var shown = Array();
       var hidden = Array();
       if (curraccess == 'none') {
           hidden = Array('$hiddenstr');
       } else {
           if (curraccess == 'status') {
               shown = Array('bystatus');
               hidden = Array('notinc','notexc');
           } else {
               if (curraccess == 'exc') {
                   shown = Array('notexc');
                   hidden = Array('notinc','bystatus');
               }
               if (curraccess == 'inc') {
                   shown = Array('notinc');
                   hidden = Array('notexc','bystatus');
               }
               if ((curraccess == 'all') || (curraccess == 'dh') || (curraccess == 'da')) {
                   hidden = Array('notinc','notexc','bystatus');
               }
           }
       }
       if (hidden.length > 0) {
           for (var i=0; i<hidden.length; i++) {
               if (document.getElementById('helproles_'+num+'_'+hidden[i])) {
                   document.getElementById('helproles_'+num+'_'+hidden[i]).style.display = 'none';
               }
           }
       }
       if (shown.length > 0) {
           for (var i=0; i<shown.length; i++) {
               if (document.getElementById('helproles_'+num+'_'+shown[i])) {
                   if (shown[i] == 'privs') {
                       document.getElementById('helproles_'+num+'_'+shown[i]).style.display = 'block';
                   } else {
                       document.getElementById('helproles_'+num+'_'+shown[i]).style.display = 'inline-block';
                   }
               }
           }
       }
       return;
   }
   
   function toggleHelpdeskItem(num,field) {
       if (document.getElementById('helproles_'+num+'_'+field)) {
           if (document.getElementById('helproles_'+num+'_'+field).className.match(/(?:^|\\s)LC_hidden(?!\\S)/)) {
               document.getElementById('helproles_'+num+'_'+field).className =
                   document.getElementById('helproles_'+num+'_'+field).className.replace(/(?:^|\\s)LC_hidden(?!\\S)/g ,'');
               if (document.getElementById('helproles_'+num+'_'+field+'_vis')) {
                   document.getElementById('helproles_'+num+'_'+field+'_vis').value = '$html_js_lt{hide}';
               }
           } else {
               document.getElementById('helproles_'+num+'_'+field).className += ' LC_hidden';
               if (document.getElementById('helproles_'+num+'_'+field+'_vis')) {
                   document.getElementById('helproles_'+num+'_'+field+'_vis').value = '$html_js_lt{show}';
               }
           }
       }
       return;
   }
   
   // ]]>
   </script>
   
   ENDSCRIPT
   }
   
   sub helpdeskroles_access {
       my ($dom,$prefix,$num,$add_class,$current,$accesstypes,$othertitle,
           $usertypes,$types,$domhelpdesk) = @_;
       return unless ((ref($accesstypes) eq 'ARRAY') && (ref($domhelpdesk) eq 'HASH'));
       my %lt = &Apache::lonlocal::texthash(
                       'rou'    => 'Role usage',
                       'whi'    => 'Which helpdesk personnel may use this role?',
                       'all'    => 'All with domain helpdesk or helpdesk assistant role',
                       'dh'     => 'All with domain helpdesk role',
                       'da'     => 'All with domain helpdesk assistant role',
                       'none'   => 'None',
                       'status' => 'Determined based on institutional status',
                       'inc'    => 'Include all, but exclude specific personnel',
                       'exc'    => 'Exclude all, but include specific personnel',
                     );
       my %usecheck = (
                        all => ' checked="checked"',
                      );
       my %displaydiv = (
                         status => 'none',
                         inc    => 'none',
                         exc    => 'none',
                         priv   => 'block',
                        );
       my $output;
       if (ref($current) eq 'HASH') {
           if (($current->{'access'} ne '') && ($current->{'access'} ne 'all')) {
               if (grep(/^\Q$current->{access}\E$/,@{$accesstypes})) {
                   $usecheck{$current->{access}} = $usecheck{'all'};
                   delete($usecheck{'all'});
                   if ($current->{access} =~ /^(status|inc|exc)$/) {
                       my $access = $1;
                       $displaydiv{$access} = 'inline';
                   } elsif ($current->{access} eq 'none') {
                       $displaydiv{'priv'} = 'none';
                   }
               }
           }
       }
       $output = '<fieldset id="'.$prefix.$num.'_usage"><legend>'.$lt{'rou'}.'</legend>'.
                 '<p>'.$lt{'whi'}.'</p>';
       foreach my $access (@{$accesstypes}) {
           $output .= '<p><label><input type="radio" name="'.$prefix.$num.'_access" value="'.$access.'" '.$usecheck{$access}.
                      ' onclick="helpdeskAccess('."'$num'".');" />'.
                      $lt{$access}.'</label>';
           if ($access eq 'status') {
               $output .= '<div id="'.$prefix.$num.'_bystatus" style="display:'.$displaydiv{$access}.'">'.
                          &Apache::lonuserutils::adhoc_status_types($dom,$prefix,$num,$current->{$access},
                                                                    $othertitle,$usertypes,$types).
                          '</div>';
           } elsif (($access eq 'inc') && (keys(%{$domhelpdesk}) > 0)) {
               $output .= '<div id="'.$prefix.$num.'_notinc" style="display:'.$displaydiv{$access}.'">'.
                          &Apache::lonuserutils::adhoc_staff($access,$prefix,$num,$current->{$access},$domhelpdesk).
                          '</div>';
           } elsif (($access eq 'exc') && (keys(%{$domhelpdesk}) > 0)) {
               $output .= '<div id="'.$prefix.$num.'_notexc" style="display:'.$displaydiv{$access}.'">'.
                          &Apache::lonuserutils::adhoc_staff($access,$prefix,$num,$current->{$access},$domhelpdesk).
                          '</div>';
           }
           $output .= '</p>';
       }
       $output .= '</fieldset>';
       return $output;
   }
   
 sub radiobutton_prefs {  sub radiobutton_prefs {
     my ($settings,$toggles,$defaultchecked,$choices,$itemcount,$onclick,      my ($settings,$toggles,$defaultchecked,$choices,$itemcount,$onclick,
         $additional,$align) = @_;          $additional,$align) = @_;
Line 2876  sub radiobutton_prefs { Line 4341  sub radiobutton_prefs {
     foreach my $item (@{$toggles}) {      foreach my $item (@{$toggles}) {
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $datatable .=          $datatable .=
             '<tr'.$css_class.'><td valign="top">'.              '<tr'.$css_class.'><td style="vertical-align: top">'.
             '<span class="LC_nobreak">'.$choices->{$item}.              '<span class="LC_nobreak">'.$choices->{$item}.
             '</span></td>';              '</span></td>';
         if ($align eq 'left') {          if ($align eq 'left') {
Line 2884  sub radiobutton_prefs { Line 4349  sub radiobutton_prefs {
         } else {          } else {
             $datatable .= '<td class="LC_right_item">';              $datatable .= '<td class="LC_right_item">';
         }          }
         $datatable .=           $datatable .=
             '<span class="LC_nobreak">'.              '<span class="LC_nobreak">'.
             '<label><input type="radio" name="'.              '<label><input type="radio" name="'.
             $item.'" '.$checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').              $item.'" '.$checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').
Line 2898  sub radiobutton_prefs { Line 4363  sub radiobutton_prefs {
     return ($datatable,$itemcount);      return ($datatable,$itemcount);
 }  }
   
   sub print_ltitools {
       my ($dom,$settings,$rowtotal) = @_;
       my $rownum = 0;
       my $css_class;
       my $itemcount = 1;
       my $maxnum = 0;
       my %ordered;
       if (ref($settings) eq 'HASH') {
           foreach my $item (keys(%{$settings})) {
               if (ref($settings->{$item}) eq 'HASH') {
                   my $num = $settings->{$item}{'order'};
                   $ordered{$num} = $item;
               }
           }
       }
       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>';
               $datatable .= '<div style="'.$userfieldstyle.'" id="ltitools_user_div_'.$i.'">'.
                             '<span class="LC_nobreak"> : '.
                             '<select name="ltitools_userincdom_'.$i.'">'.
                             '<option value="">'.&mt('Select').'</option>'.
                             '<option value="0"'.$unseluserdom.'>'.&mt('username').'</option>'.
                             '<option value="1"'.$seluserdom.'>'.&mt('username:domain').'</option>'.
                             '</select></span></div>';
               $datatable .= '</fieldset>'.
                             '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>';
               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>';
               my %courseconfig;
               if (ref($settings->{$item}) eq 'HASH') {
                   if (ref($settings->{$item}->{'crsconf'}) eq 'HASH') {
                       %courseconfig = %{$settings->{$item}->{'crsconf'}};
                   }
               }
               $datatable .= '<fieldset><legend>'.&mt('Configurable in course').'</legend><span class="LC_nobreak">';
               foreach my $item ('label','title','target','linktext','explanation','append') {
                   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;' 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>';
               if (ref($settings->{$item}->{'custom'}) eq 'HASH') {
                   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 $chgstr = ' onchange="javascript:reorderLTITools(this.form,'."'ltitools_add_pos'".');"';
       $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
                     '<input type="hidden" name="ltitools_maxnum" value="'.$maxnum.'" />'."\n".
                     '<select name="ltitools_add_pos"'.$chgstr.'>';
       for (my $k=0; $k<$maxnum+1; $k++) {
           my $vpos = $k+1;
           my $selstr;
           if ($k == $maxnum) {
               $selstr = ' selected="selected" ';
           }
           $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
       }
       $datatable .= '</select>&nbsp;'."\n".
                     '<input type="checkbox" name="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;
   }
   
   sub ltitools_names {
       my %lt = &Apache::lonlocal::texthash(
                                             'title'          => 'Title',
                                             'version'        => 'Version',
                                             'msgtype'        => 'Message Type',
                                             'sigmethod'      => 'Signature Method',
                                             'url'            => 'URL',
                                             'key'            => 'Key',
                                             'lifetime'       => 'Nonce lifetime (s)',
                                             'secret'         => 'Secret',
                                             'icon'           => 'Icon',   
                                             'user'           => 'User',
                                             'fullname'       => 'Full Name',
                                             'firstname'      => 'First Name',
                                             'lastname'       => 'Last Name',
                                             'email'          => 'E-mail',
                                             'roles'          => 'Role',
                                             'window'         => 'Window',
                                             'tab'            => 'Tab',
                                             'iframe'         => 'iFrame',
                                             'height'         => 'Height',
                                             'width'          => 'Width',
                                             'linktext'       => 'Default Link Text',
                                             'explanation'    => 'Default Explanation',
                                             'passback'       => 'Tool can return grades:',
                                             'roster'         => 'Tool can retrieve roster:',
                                             'crstarget'      => 'Display target',
                                             'crslabel'       => 'Course label',
                                             'crstitle'       => 'Course title', 
                                             'crslinktext'    => 'Link Text',
                                             'crsexplanation' => 'Explanation',
                                             'crsappend'      => 'Provider URL',
                                           );
       return %lt;
   }
   
   sub print_lti {
       my ($dom,$settings,$rowtotal) = @_;
       my $itemcount = 1;
       my $maxnum = 0;
       my $css_class;
       my %ordered;
       if (ref($settings) eq 'HASH') {
           foreach my $item (keys(%{$settings})) {
               if (ref($settings->{$item}) eq 'HASH') {
                   my $num = $settings->{$item}{'order'};
                   $ordered{$num} = $item;
               }
           }
       }
       my $maxnum = scalar(keys(%ordered));
       my $datatable;
       my %lt = &lti_names();
       if (keys(%ordered)) {
           my @items = sort { $a <=> $b } keys(%ordered);
           for (my $i=0; $i<@items; $i++) {
               $css_class = $itemcount%2?' class="LC_odd_row"':'';
               my $item = $ordered{$items[$i]};
               my ($key,$secret,$lifetime,$consumer,$requser,$current);
               if (ref($settings->{$item}) eq 'HASH') {
                   $key = $settings->{$item}->{'key'};
                   $secret = $settings->{$item}->{'secret'};
                   $lifetime = $settings->{$item}->{'lifetime'};
                   $consumer = $settings->{$item}->{'consumer'};
                   $requser = $settings->{$item}->{'requser'};
                   $current = $settings->{$item};
               }
               my $onclickrequser = ' onclick="toggleLTI(this.form,'."'requser','$i'".');"';
               my %checkedrequser = (
                                      yes => ' checked="checked"',
                                      no  => '',
                                    );
               if (!$requser) {
                   $checkedrequser{'no'} = $checkedrequser{'yes'};
                   $checkedrequser{'yes'} = '';
               }
               my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_".$item."'".');"';
               $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
                            .'<select name="lti_pos_'.$item.'"'.$chgstr.'>';
               for (my $k=0; $k<=$maxnum; $k++) {
                   my $vpos = $k+1;
                   my $selstr;
                   if ($k == $i) {
                       $selstr = ' selected="selected" ';
                   }
                   $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
               }
               $datatable .= '</select>'.('&nbsp;'x2).
                   '<label><input type="checkbox" name="lti_del" value="'.$item.'" />'.
                   &mt('Delete?').'</label></span></td>'.
                   '<td colspan="2">'.
                   '<fieldset><legend>'.&mt('Required settings').'</legend>'.
                   '<span class="LC_nobreak">'.$lt{'consumer'}.
                   ':<input type="text" size="15" name="lti_consumer_'.$i.'" value="'.$consumer.'" /></span> '.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_'.$i.'">'.
                   '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" name="lti_lifetime_'.$i.'"'.
                   'value="'.$lifetime.'" size="3" /></span>'.
                   ('&nbsp;'x2).
                    '<span class="LC_nobreak">'.$lt{'requser'}.':'.
                    '<label><input type="radio" name="lti_requser_'.$i.'" value="1"'.$onclickrequser.$checkedrequser{yes}.' />'.&mt('Yes').'</label>&nbsp;'."\n".
                    '<label><input type="radio" name="lti_requser_'.$i.'" value="0"'.$onclickrequser.$checkedrequser{no}.' />'.&mt('No').'</label></span>'."\n".
                   '<br /><br />'.
                   '<span class="LC_nobreak">'.$lt{'key'}.
                   ':<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" /></span> '.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'secret'}.':'.
                   '<input type="password" size="20" name="lti_secret_'.$i.'" value="'.$secret.'" />'.
                   '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.
                   '<input type="hidden" name="lti_id_'.$i.'" value="'.$item.'" /></span>'.
                   '</fieldset>'.&lti_options($i,$current,$itemcount,%lt).'</td></tr>';
               $itemcount ++;
           }
       }
       $css_class = $itemcount%2?' class="LC_odd_row"':'';
       my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_add'".');"';
       $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
                     '<input type="hidden" name="lti_maxnum" value="'.$maxnum.'" />'."\n".
                     '<select name="lti_pos_add"'.$chgstr.'>';
       for (my $k=0; $k<$maxnum+1; $k++) {
           my $vpos = $k+1;
           my $selstr;
           if ($k == $maxnum) {
               $selstr = ' selected="selected" ';
           }
           $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
       }
       $datatable .= '</select>&nbsp;'."\n".
                     '<input type="checkbox" name="lti_add" value="1" />'.&mt('Add').'</span></td>'."\n".
                     '<td colspan="2">'.
                     '<fieldset><legend>'.&mt('Required settings').'</legend>'.
                     '<span class="LC_nobreak">'.$lt{'consumer'}.
                     ':<input type="text" size="15" name="lti_consumer_add" value="" /></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_add">'.
                     '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="3" name="lti_lifetime_add" value="300" /></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'requser'}.':'.
                     '<label><input type="radio" name="lti_requser_add" value="1" onclick="toggleLTI(this.form,'."'requser','add'".');" checked="checked" />'.&mt('Yes').'</label>&nbsp;'."\n".
                     '<label><input type="radio" name="lti_requser_add" value="0" onclick="toggleLTI(this.form,'."'requser','add'".');" />'.&mt('No').'</label></span>'."\n".
                     '<br /><br />'.
                     '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="lti_key_add" value="" /></span> '."\n".
                     ('&nbsp;'x2).
                     '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="lti_secret_add" value="" />'.
                     '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.lti_secret_add.type='."'text'".' } else { this.form.lti_secret_add.type='."'password'".' }" />'.&mt('Visible input').'</label></span> '."\n".
                     '</fieldset>'.&lti_options('add',undef,$itemcount,%lt).
                     '</td>'."\n".
                     '</tr>'."\n";
       $$rowtotal ++;
       return $datatable;;
   }
   
   sub lti_names {
       my %lt = &Apache::lonlocal::texthash(
                                             'version'   => 'LTI Version',
                                             'url'       => 'URL',
                                             'key'       => 'Key',
                                             'lifetime'  => 'Nonce lifetime (s)',
                                             'consumer'  => 'Consumer',
                                             'secret'    => 'Secret',
                                             'requser'   => "User's identity sent",
                                             'email'     => 'Email address',
                                             'sourcedid' => 'User ID',
                                             'other'     => 'Other',
                                             'passback'  => 'Can return grades to Consumer:',
                                             'roster'    => 'Can retrieve roster from Consumer:',
                                             'topmenu'   => 'Display LON-CAPA page header',
                                             'inlinemenu'=> 'Display LON-CAPA inline menu',
                                           );
       return %lt;
   }
   
   sub lti_options {
       my ($num,$current,$itemcount,%lt) = @_;
       my (%checked,%rolemaps,$crssecsrc,$userfield,$cidfield,$callback);
       $checked{'mapuser'}{'sourcedid'} = ' checked="checked"';
       $checked{'mapcrs'}{'course_offering_sourcedid'} = ' checked="checked"';
       $checked{'makecrs'}{'N'} = '  checked="checked"';
       $checked{'mapcrstype'} = {};
       $checked{'makeuser'} = {};
       $checked{'selfenroll'} = {};
       $checked{'crssec'} = {};
       $checked{'crssecsrc'} = {};
       $checked{'lcauth'} = {};
       $checked{'menuitem'} = {};
       if ($num eq 'add') {
           $checked{'lcauth'}{'lti'} = ' checked="checked"';
       }
       my $userfieldsty = 'none';
       my $crsfieldsty = 'none';
       my $crssecfieldsty = 'none';
       my $secsrcfieldsty = 'none';
       my $callbacksty = 'none';
       my $passbacksty = 'none';
       my $optionsty = 'block';
       my $lcauthparm;
       my $lcauthparmstyle = 'display:none';
       my $lcauthparmtext;
       my $menusty;
       my $numinrow = 4;
       my %menutitles = &ltimenu_titles();
   
       if (ref($current) eq 'HASH') {
           if (!$current->{'requser'}) {
               $optionsty = 'none';
           }
           if (($current->{'mapuser'} ne '') && ($current->{'mapuser'} ne 'lis_person_sourcedid')) {
               $checked{'mapuser'}{'sourcedid'} = '';
               if ($current->{'mapuser'} eq 'lis_person_contact_email_primary') {
                   $checked{'mapuser'}{'email'} = ' checked="checked"'; 
               } else {
                   $checked{'mapuser'}{'other'} = ' checked="checked"';
                   $userfield = $current->{'mapuser'};
                   $userfieldsty = 'inline-block';
               }
           }
           if (($current->{'mapcrs'} ne '') && ($current->{'mapcrs'} ne 'course_offering_sourcedid')) {
               $checked{'mapcrs'}{'course_offering_sourcedid'} = '';
               if ($current->{'mapcrs'} eq 'context_id') {
                   $checked{'mapcrs'}{'context_id'} = ' checked="checked"'; 
               } else {
                   $checked{'mapcrs'}{'other'} = ' checked="checked"';
                   $cidfield = $current->{'mapcrs'};
                   $crsfieldsty = 'inline-block';
               }
           }
           if (ref($current->{'mapcrstype'}) eq 'ARRAY') {
               foreach my $type (@{$current->{'mapcrstype'}}) {
                   $checked{'mapcrstype'}{$type} = ' checked="checked"';
               }
           }
           if ($current->{'makecrs'}) {
               $checked{'makecrs'}{'Y'} = '  checked="checked"';
           }
           if (ref($current->{'makeuser'}) eq 'ARRAY') {
               foreach my $role (@{$current->{'makeuser'}}) {
                   $checked{'makeuser'}{$role} = ' checked="checked"';
               }
           }
           if ($current->{'lcauth'} =~ /^(internal|localauth|krb4|krb5|lti)$/) {
               $checked{'lcauth'}{$1} = ' checked="checked"';
               unless (($current->{'lcauth'} eq 'lti') || ($current->{'lcauth'} eq 'internal')) {
                   $lcauthparm = $current->{'lcauthparm'};
                   $lcauthparmstyle = 'display:table-row'; 
                   if ($current->{'lcauth'} eq 'localauth') {
                       $lcauthparmtext = &mt('Local auth argument');
                   } else {
                       $lcauthparmtext = &mt('Kerberos domain');
                   }
               }
           }
           if (ref($current->{'selfenroll'}) eq 'ARRAY') {
               foreach my $role (@{$current->{'selfenroll'}}) {
                   $checked{'selfenroll'}{$role} = ' checked="checked"';
               }
           }
           if (ref($current->{'maproles'}) eq 'HASH') {
               %rolemaps = %{$current->{'maproles'}};
           }
           if ($current->{'section'} ne '') {
               $checked{'crssec'}{'Y'} = '  checked="checked"'; 
               $crssecfieldsty = 'inline-block';
               if ($current->{'section'} eq 'course_section_sourcedid') {
                   $checked{'crssecsrc'}{'sourcedid'} = ' checked="checked"';
               } else {
                   $checked{'crssecsrc'}{'other'} = ' checked="checked"';
                   $crssecsrc = $current->{'section'};
                   $secsrcfieldsty = 'inline-block';
               }
           } else {
               $checked{'crssec'}{'N'} = ' checked="checked"';
           }
           if ($current->{'callback'} ne '') {
               $callback = $current->{'callback'};
               $checked{'callback'}{'Y'} = ' checked="checked"';
               $callbacksty = 'inline-block';
           } else {
               $checked{'callback'}{'N'} = ' checked="checked"';
           }
           if ($current->{'topmenu'}) {
               $checked{'topmenu'}{'Y'} = ' checked="checked"';
           } else {
               $checked{'topmenu'}{'N'} = ' checked="checked"';
           }
           if ($current->{'inlinemenu'}) {
               $checked{'inlinemenu'}{'Y'} = ' checked="checked"';
           } else {
               $checked{'inlinemenu'}{'N'} = ' checked="checked"';
           }
           if (($current->{'topmenu'}) || ($current->{'inlinemenu'})) {
               $menusty = 'inline-block';
               if (ref($current->{'lcmenu'}) eq 'ARRAY') {
                   foreach my $item (@{$current->{'lcmenu'}}) {
                       if (exists($menutitles{$item})) {
                           $checked{'menuitem'}{$item} = ' checked="checked"';
                       }
                   }
               }
           } else {
               $menusty = 'none';
           }
       } else {
           $checked{'makecrs'}{'N'} = ' checked="checked"';
           $checked{'crssec'}{'N'} = ' checked="checked"';
           $checked{'callback'}{'N'} = ' checked="checked"';
           $checked{'topmenu'}{'N'} = ' checked="checked"';
           $checked{'inlinemenu'}{'Y'} = ' checked="checked"'; 
           $checked{'menuitem'}{'grades'} = ' checked="checked"';
           $menusty = 'inline-block'; 
       }
       my @coursetypes = ('official','unofficial','community','textbook','placement','lti');
       my %coursetypetitles = &Apache::lonlocal::texthash (
                                  official   => 'Official',
                                  unofficial => 'Unofficial',
                                  community  => 'Community',
                                  textbook   => 'Textbook',
                                  placement  => 'Placement Test',
                                  lti        => 'LTI Provider',
       );
       my @authtypes = ('internal','krb4','krb5','localauth');
       my %shortauth = (
                        internal => 'int',
                        krb4 => 'krb4',
                        krb5 => 'krb5',
                        localauth  => 'loc'
                       );
       my %authnames = &authtype_names();
       my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator);
       my @lticourseroles = qw(Learner Instructor TeachingAssistant Mentor);
       my @courseroles = ('cc','in','ta','ep','st');
       my $onclickuser = ' onclick="toggleLTI(this.form,'."'user','$num'".');"';
       my $onclickcrs = ' onclick="toggleLTI(this.form,'."'crs','$num'".');"';
       my $onclicksec = ' onclick="toggleLTI(this.form,'."'sec','$num'".');"';
       my $onclickcallback = ' onclick="toggleLTI(this.form,'."'callback','$num'".');"';
       my $onclicksecsrc = ' onclick="toggleLTI(this.form,'."'secsrc','$num'".')"';
       my $onclicklcauth = ' onclick="toggleLTI(this.form,'."'lcauth','$num'".')"';
       my $onclickmenu = ' onclick="toggleLTI(this.form,'."'lcmenu','$num'".');"';
       my $output = '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Mapping users').'</legend>'.
                    '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('LON-CAPA username').':&nbsp;';
       foreach my $option ('sourcedid','email','other') {
           $output .= '<label><input type="radio" name="lti_mapuser_'.$num.'" value="'.$option.'"'.
                      $checked{'mapuser'}{$option}.$onclickuser.' />'.$lt{$option}.'</label>'.
                      ($option eq 'other' ? '' : ('&nbsp;'x2) );
       }
       $output .= '</span></div>'.
                  '<div class="LC_floatleft" style="display:'.$userfieldsty.';" id="lti_userfield_'.$num.'">'.
                  '<input type="text" name="lti_customuser_'.$num.'" '.
                  'value="'.$userfield.'" /></div></fieldset>'. 
                  '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Mapping course roles').'</legend><table><tr>';
       foreach my $ltirole (@lticourseroles) {
           my ($selected,$selectnone);
           if ($rolemaps{$ltirole} eq '') {
               $selectnone = ' selected="selected"';
           }
           $output .= '<td style="text-align: center">'.$ltirole.'<br />'.
                      '<select name="lti_maprole_'.$ltirole.'_'.$num.'">'.
                      '<option value=""'.$selectnone.'>'.&mt('Select').'</option>';
           foreach my $role (@courseroles) {
               unless ($selectnone) {
                   if ($rolemaps{$ltirole} eq $role) {
                       $selected = ' selected="selected"';
                   } else {
                       $selected = '';
                   }
               }
               $output .= '<option value="'.$role.'"'.$selected.'>'.
                          &Apache::lonnet::plaintext($role,'Course').
                          '</option>';
           }
           $output .= '</select></td>';
       }
       $output .= '</tr></table></fieldset>'.
                  '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Roles which may create user accounts').'</legend>';
       foreach my $ltirole (@ltiroles) {
           $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_makeuser_'.$num.'" value="'.$ltirole.'"'.
                      $checked{'makeuser'}{$ltirole}.' />'.$ltirole.'</label>&nbsp;</span> ';     
       }
       $output .= '</fieldset>'.
                  '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('New user accounts created for LTI users').'</legend>'.
                  '<table>'.
                  &modifiable_userdata_row('lti','instdata_'.$num,$current,$numinrow,$itemcount).
                  '</table>'.
                  '<table class="LC_nested"><tr><td class="LC_left_item">LON-CAPA Authentication</td>'.
                  '<td class="LC_left_item">';
       foreach my $auth ('lti',@authtypes) {
           my $authtext;
           if ($auth eq 'lti') {
               $authtext = &mt('None');
           } else {
               $authtext = $authnames{$shortauth{$auth}};
           }
           $output .= '<span class="LC_nobreak"><label><input type="radio" name="lti_lcauth_'.$num.
                      '" value="'.$auth.'"'.$checked{'lcauth'}{$auth}.$onclicklcauth.' />'.
                      $authtext.'</label></span> &nbsp;';
       }
       $output .= '</td></tr>'.
                  '<tr id="lti_lcauth_parmrow_'.$num.'" style="'.$lcauthparmstyle.'">'.
                  '<td class="LC_right_item" colspan="2"><span class="LC_nobreak">'.
                  '<span id="lti_lcauth_parmtext_'.$num.'">'.$lcauthparmtext.'</span>'.
                  '<input type="text" name="lti_lcauthparm_'.$num.'" value="" /></span></td></tr>'.
                  '</table></fieldset>'.
                  '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Mapping courses').'</legend>'.
                  '<div class="LC_floatleft"><span class="LC_nobreak">'.
                  &mt('Unique course identifier').':&nbsp;';
       foreach my $option ('course_offering_sourcedid','context_id','other') {
           $output .= '<label><input type="radio" name="lti_mapcrs_'.$num.'" value="'.$option.'"'.
                      $checked{'mapcrs'}{$option}.$onclickcrs.' />'.$option.'</label>'.
                      ($option eq 'other' ? '' : ('&nbsp;'x2) );
       }
       $output .= '</span></div><div class="LC_floatleft" style="display:'.$crsfieldsty.';" id="lti_crsfield_'.$num.'">'.
                  '<input type="text" name="lti_mapcrsfield_'.$num.'" value="'.$cidfield.'" />'.
                  '</div><div style="padding:0;clear:both;margin:0;border:0"></div>'.
                  '<span class="LC_nobreak">'.&mt('LON-CAPA course type(s)').':&nbsp;';
       foreach my $type (@coursetypes) {
           $output .= '<label><input type="checkbox" name="lti_mapcrstype_'.$num.'" value="'.$type.'"'.
                      $checked{'mapcrstype'}{$type}.' />'.$coursetypetitles{$type}.'</label>'.
                      ('&nbsp;'x2);
       }
       $output .= '</span></fieldset>'.
                  '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Creating courses').'</legend>'.
                  '<span class="LC_nobreak">'.&mt('Course created (if absent) on Instructor access').':&nbsp;'.
                  '<label><input type="radio" name="lti_makecrs_'.$num.'" value="0"'.
                  $checked{'makecrs'}{'N'}.' />'.&mt('No').'</label>'.('&nbsp;'x2).
                  '<label><input type="radio" name="lti_makecrs_'.$num.'" value="1"'.
                  $checked{'makecrs'}{'Y'}.' />'.&mt('Yes').'</label></span>'.
                  '</fieldset>'.
                  '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Roles which may self-enroll').'</legend>';
       foreach my $lticrsrole (@lticourseroles) {
           $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_selfenroll_'.$num.'" value="'.$lticrsrole.'"'.
                      $checked{'selfenroll'}{$lticrsrole}.' />'.$lticrsrole.'</label>&nbsp;</span> ';
       }
       $output .= '</fieldset>'.
                  '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Course options').'</legend>'.
                  '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Assign users to sections').':&nbsp;'.
                  '<label><input type="radio" name="lti_crssec_'.$num.'" value="0"'.
                  $checked{'crssec'}{'N'}.$onclicksec.' />'.&mt('No').'</label>'.('&nbsp;'x2).
                  '<label><input type="radio" name="lti_crssec_'.$num.'" value="1"'.
                  $checked{'crssec'}{'Y'}.$onclicksec.' />'.&mt('Yes').'</label></span></div>'.
                  '<div class="LC_floatleft" style="display:'.$crssecfieldsty.';" id="lti_crssecfield_'.$num.'">'.
                  '<span class="LC_nobreak">'.&mt('From').':<label>'.
                  '<input type="radio" name="lti_crssecsrc_'.$num.'" value="course_section_sourcedid"'.
                  $checked{'crssecsrc'}{'sourcedid'}.$onclicksecsrc.' />'.
                  &mt('Standard field').'</label>'.('&nbsp;'x2).
                  '<label><input type="radio" name="lti_crssecsrc_'.$num.'" value="other"'.
                  $checked{'crssecsrc'}{'other'}.$onclicksecsrc.' />'.&mt('Other').
                  '</label></span></div><div class="LC_floatleft" style="display:'.$secsrcfieldsty.';" id="lti_secsrcfield_'.$num.'">'.
                  '<input type="text" name="lti_customsection_'.$num.'" value="'.$crssecsrc.'" />'.
                  '</div><div style="padding:0;clear:both;margin:0;border:0"></div>';
       my ($pb1p1chk,$pb1p0chk,$onclickpb);
       foreach my $extra ('roster','passback') {
           my $checkedon = '';
           my $checkedoff = ' checked="checked"';
           if ($extra eq 'passback') {
               $pb1p1chk = ' checked="checked"';
               $pb1p0chk = '';
               $onclickpb = ' onclick="toggleLTI(this.form,'."'passback','$num'".');"'; 
           } else {
               $onclickpb = ''; 
           }
           if (ref($current) eq 'HASH') {
               if (($current->{$extra})) {
                   $checkedon = $checkedoff;
                   $checkedoff = '';
                   if ($extra eq 'passback') {
                       $passbacksty = 'inline-block';
                   }
                   if ($current->{'passbackformat'} eq '1.0') {
                       $pb1p0chk =  ' checked="checked"';
                       $pb1p1chk = '';
                   }
               }
           }
           $output .= $lt{$extra}.'&nbsp;'.
                      '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="0"'.$checkedoff.$onclickpb.' />'.
                      &mt('No').'</label>'.('&nbsp;'x2).
                      '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="1"'.$checkedon.$onclickpb.' />'.
                      &mt('Yes').'</label><br />';
       }
       $output .= '<div class="LC_floatleft" style="display:'.$passbacksty.';" id="lti_passback_'.$num.'">'.
                  '<span class="LC_nobreak">'.&mt('Grade format').
                  '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.1"'.$pb1p1chk.' />'.
                  &mt('Outcomes Service (1.1)').'</label>'.('&nbsp;'x2).
                  '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.0"'.$pb1p0chk.'/>'.
                  &mt('Outcomes Extension (1.0)').'</label></span></div>'.
                  '<div style="padding:0;clear:both;margin:0;border:0"></div>'.
                  '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Callback on logout').':&nbsp;'.
                  '<label><input type="radio" name="lti_callback_'.$num.'" value="0"'.
                  $checked{'callback'}{'N'}.$onclickcallback.' />'.&mt('No').'</label>'.('&nbsp;'x2).
                  '<label><input type="radio" name="lti_callback_'.$num.'" value="1"'.
                  $checked{'callback'}{'Y'}.$onclickcallback.' />'.&mt('Yes').'</label></span></div>'.
                  '<div class="LC_floatleft" style="display:'.$callbacksty.';" id="lti_callbackfield_'.$num.'">'.
                  '<span class="LC_nobreak">'.&mt('Parameter').': '.
                  '<input type="text" name="lti_callbackparam_'.$num.'" value="'.$callback.'" /></span>'.
                  '</div><div style="padding:0;clear:both;margin:0;border:0"></div></fieldset>'.
                  '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Course defaults (Course Coordinator can override)').'</legend>'.
                  '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'topmenu'}.':&nbsp;'.
                  '<label><input type="radio" name="lti_topmenu_'.$num.'" value="0"'.
                  $checked{'topmenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.('&nbsp;'x2).
                  '<label><input type="radio" name="lti_topmenu_'.$num.'" value="1"'.
                  $checked{'topmenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>'.
                  '<div style="padding:0;clear:both;margin:0;border:0"></div>'.
                  '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'inlinemenu'}.':&nbsp;'.
                  '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="0"'.
                  $checked{'inlinemenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.('&nbsp;'x2).
                  '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="1"'.
                  $checked{'inlinemenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>';
        $output .='<div style="padding:0;clear:both;margin:0;border:0"></div>'. 
                  '<div class="LC_floatleft" style="display:'.$menusty.';" id="lti_menufield_'.$num.'">'.
                  '<span class="LC_nobreak">'.&mt('Menu items').':&nbsp;';
       foreach my $type ('fullname','coursetitle','role','logout','grades') {
           $output .= '<label><input type="checkbox" name="lti_menuitem_'.$num.'" value="'.$type.'"'.
                      $checked{'menuitem'}{$type}.' />'.$menutitles{$type}.'</label>'.
                      ('&nbsp;'x2);
       }
       $output .= '</span></div></fieldset>';
   #        '<fieldset><legend>'.&mt('Assigning author roles').'</legend>';
   #
   #    $output .= '</fieldset>'.
   #        '<fieldset><legend>'.&mt('Assigning domain roles').'</legend>';
       return $output;
   }
   
   sub ltimenu_titles {
       return &Apache::lonlocal::texthash(
                                           fullname    => 'Full name',
                                           coursetitle => 'Course title',
                                           role        => 'Role',
                                           logout      => 'Logout',
                                           grades      => 'Grades',
       );
   }
   
 sub print_coursedefaults {  sub print_coursedefaults {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles);      my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles);
Line 2909  sub print_coursedefaults { Line 5329  sub print_coursedefaults {
         coursecredits        => 'Credits can be specified for courses',          coursecredits        => 'Credits can be specified for courses',
         uselcmath            => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)',          uselcmath            => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)',
         usejsme              => 'Molecule editor uses JSME (HTML5) in place of JME (Java)',          usejsme              => 'Molecule editor uses JSME (HTML5) in place of JME (Java)',
           texengine            => 'Default method to display mathematics',
         postsubmit           => 'Disable submit button/keypress following student submission',          postsubmit           => 'Disable submit button/keypress following student submission',
           canclone             => "People who may clone a course (besides course's owner and coordinators)",
           mysqltables          => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver',
     );      );
     my %staticdefaults = (      my %staticdefaults = (
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
                            postsubmit           => 60,                             postsubmit           => 60,
                              mysqltables          => 172800,
                          );                           );
     if ($position eq 'top') {      if ($position eq 'top') {
         %defaultchecked = (          %defaultchecked = (
                             'canuse_pdfforms' => 'off',                              'canuse_pdfforms' => 'off',
                             'uselcmath'       => 'on',                              'uselcmath'       => 'on',
                             'usejsme'         => 'on',                              'usejsme'         => 'on',
                               'canclone'        => 'none',
                           );                            );
         @toggles = ('canuse_pdfforms','uselcmath','usejsme');          @toggles = ('canuse_pdfforms','uselcmath','usejsme');
           my $deftex = $Apache::lonnet::deftex;
           if (ref($settings) eq 'HASH') {
               if ($settings->{'texengine'}) {
                   if ($settings->{'texengine'} =~ /^(MathJax|mimetex|tth)$/) {
                       $deftex = $settings->{'texengine'};
                   }
               }
           }
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           my $mathdisp = '<tr'.$css_class.'><td style="vertical-align: top">'.
                          '<span class="LC_nobreak">'.$choices{'texengine'}.
                          '</span></td><td class="LC_right_item">'.
                          '<select name="texengine">'."\n";
           my %texoptions = (
                               MathJax  => 'MathJax',
                               mimetex  => &mt('Convert to Images'),
                               tth      => &mt('TeX to HTML'),
                            );
           foreach my $renderer ('MathJax','mimetex','tth') {
               my $selected = '';
               if ($renderer eq $deftex) {
                   $selected = ' selected="selected"';
               }
               $mathdisp .= '<option value="'.$renderer.'"'.$selected.'>'.$texoptions{$renderer}.'</option>'."\n";
           }
           $mathdisp .= '</select></td></tr>'."\n";
           $itemcount ++;
         ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,          ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
                                                      \%choices,$itemcount);                                                       \%choices,$itemcount);
           $datatable = $mathdisp.$datatable;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .=
               '<tr'.$css_class.'><td style="vertical-align: top">'.
               '<span class="LC_nobreak">'.$choices{'canclone'}.
               '</span></td><td class="LC_left_item">';
           my $currcanclone = 'none';
           my $onclick;
           my @cloneoptions = ('none','domain');
           my %clonetitles = (
                                none     => 'No additional course requesters',
                                domain   => "Any course requester in course's domain",
                                instcode => 'Course requests for official courses ...',
                             );
           my (%codedefaults,@code_order,@posscodes);
           if (&Apache::lonnet::auto_instcode_defaults($dom,\%codedefaults,
                                                       \@code_order) eq 'ok') {
               if (@code_order > 0) {
                   push(@cloneoptions,'instcode');
                   $onclick = ' onclick="toggleDisplay(this.form,'."'cloneinstcode'".');"';
               }
           }
           if (ref($settings) eq 'HASH') {
               if ($settings->{'canclone'}) {
                   if (ref($settings->{'canclone'}) eq 'HASH') {
                       if (ref($settings->{'canclone'}{'instcode'}) eq 'ARRAY') {
                           if (@code_order > 0) {
                               $currcanclone = 'instcode';
                               @posscodes = @{$settings->{'canclone'}{'instcode'}};
                           }
                       }
                   } elsif ($settings->{'canclone'} eq 'domain') {
                       $currcanclone = $settings->{'canclone'};
                   }
               }
           }
           foreach my $option (@cloneoptions) {
               my ($checked,$additional);
               if ($currcanclone eq $option) {
                   $checked = ' checked="checked"';
               }
               if ($option eq 'instcode') {
                   if (@code_order) {
                       my $show = 'none';
                       if ($checked) {
                           $show = 'block';
                       }
                       $additional = '<div id="cloneinstcode" style="display:'.$show.';" />'.
                                     &mt('Institutional codes for new and cloned course have identical:').
                                     '<br />';
                       foreach my $item (@code_order) {
                           my $codechk;
                           if ($checked) {
                               if (grep(/^\Q$item\E$/,@posscodes)) {
                                   $codechk = ' checked="checked"';
                               }
                           }
                           $additional .= '<label>'.
                                          '<input type="checkbox" name="clonecode" value="'.$item.'"'.$codechk.' />'.
                                          $item.'</label>';
                       }
                       $additional .= ('&nbsp;'x2).'('.&mt('check as many as needed').')</div>';
                   }
               }
               $datatable .=
                   '<span class="LC_nobreak"><label><input type="radio" name="canclone"'.$checked.
                   ' value="'.$option.'"'.$onclick.' />'.$clonetitles{$option}.
                   '</label>&nbsp;'.$additional.'</span><br />';
           }
           $datatable .= '</td>'.
                         '</tr>';
           $itemcount ++;
     } else {      } else {
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';          $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
         my ($currdefresponder,%defcredits,%curruploadquota,%deftimeout);          my ($currdefresponder,%defcredits,%curruploadquota,%deftimeout,%currmysql);
         my $currusecredits = 0;          my $currusecredits = 0;
         my $postsubmitclient = 1;          my $postsubmitclient = 1;
         my @types = ('official','unofficial','community','textbook');          my @types = ('official','unofficial','community','textbook','placement');
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             $currdefresponder = $settings->{'anonsurvey_threshold'};              $currdefresponder = $settings->{'anonsurvey_threshold'};
             if (ref($settings->{'uploadquota'}) eq 'HASH') {              if (ref($settings->{'uploadquota'}) eq 'HASH') {
Line 2957  sub print_coursedefaults { Line 5481  sub print_coursedefaults {
                     foreach my $type (@types) {                      foreach my $type (@types) {
                         if (ref($settings->{'postsubmit'}->{'timeout'}) eq 'HASH') {                          if (ref($settings->{'postsubmit'}->{'timeout'}) eq 'HASH') {
                             if ($settings->{'postsubmit'}->{'timeout'}->{$type} =~ /^\d+$/) {                              if ($settings->{'postsubmit'}->{'timeout'}->{$type} =~ /^\d+$/) {
                                 $deftimeout{$type} = $settings->{'postsubmit'}->{'timeout'}->{$type};                                   $deftimeout{$type} = $settings->{'postsubmit'}->{'timeout'}->{$type};
                             } else {                              } else {
                                 $deftimeout{$type} = $staticdefaults{'postsubmit'};                                  $deftimeout{$type} = $staticdefaults{'postsubmit'};
                             }                              }
Line 2971  sub print_coursedefaults { Line 5495  sub print_coursedefaults {
                     $deftimeout{$type} = $staticdefaults{'postsubmit'};                      $deftimeout{$type} = $staticdefaults{'postsubmit'};
                 }                  }
             }              }
               if (ref($settings->{'mysqltables'}) eq 'HASH') {
                   foreach my $type (keys(%{$settings->{'mysqltables'}})) {
                       $currmysql{$type} = $settings->{'mysqltables'}{$type};
                   }
               } else {
                   foreach my $type (@types) {
                       $currmysql{$type} = $staticdefaults{'mysqltables'};
                   }
               }
         } else {          } else {
             foreach my $type (@types) {              foreach my $type (@types) {
                 $deftimeout{$type} = $staticdefaults{'postsubmit'};                  $deftimeout{$type} = $staticdefaults{'postsubmit'};
Line 2999  sub print_coursedefaults { Line 5532  sub print_coursedefaults {
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.          $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
                       $choices{'uploadquota'}.                        $choices{'uploadquota'}.
                       '</span></td>'.                        '</span></td>'.
                       '<td align="right" class="LC_right_item">'.                        '<td style="text-align: right" class="LC_right_item">'.
                       '<table><tr>';                        '<table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             $datatable .= '<td align="center">'.&mt($type).'<br />'.              $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="uploadquota_'.$type.'"'.                             '<input type="text" name="uploadquota_'.$type.'"'.
                            ' value="'.$curruploadquota{$type}.'" size="5" /></td>';                             ' value="'.$curruploadquota{$type}.'" size="5" /></td>';
         }          }
Line 3017  sub print_coursedefaults { Line 5550  sub print_coursedefaults {
                          '<i>'.&mt('Default credits').'</i><br /><table><tr>';                           '<i>'.&mt('Default credits').'</i><br /><table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             next if ($type eq 'community');              next if ($type eq 'community');
             $additional .= '<td align="center">'.&mt($type).'<br />'.              $additional .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="'.$type.'_credits"'.                             '<input type="text" name="'.$type.'_credits"'.
                            ' value="'.$defcredits{$type}.'" size="3" /></td>';                             ' value="'.$defcredits{$type}.'" size="3" /></td>';
         }          }
Line 3037  sub print_coursedefaults { Line 5570  sub print_coursedefaults {
             $display = 'block';              $display = 'block';
         }          }
         $additional = '<div id="studentsubmission" style="display: '.$display.'">'.          $additional = '<div id="studentsubmission" style="display: '.$display.'">'.
                       '<i>'.&mt('Number of seconds submit is disabled').'</i><br /><table><tr>';                        &mt('Number of seconds submit is disabled').'<br />'.
                         '<i>'.&mt('Enter 0 to remain disabled until page reload.').'</i><br />'.
                         '<table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             $additional .= '<td align="center">'.&mt($type).'<br />'.              $additional .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="'.$type.'_timeout" value="'.                             '<input type="text" name="'.$type.'_timeout" value="'.
                            $deftimeout{$type}.'" size="5" /></td>';                             $deftimeout{$type}.'" size="5" /></td>';
         }          }
         $additional .= '</tr></table></div>'."\n";          $additional .= '</tr></table></div>'."\n";
         %defaultchecked = ('postsubmit' => 'on');          %defaultchecked = ('postsubmit' => 'on');
         @toggles = ('postsubmit');          @toggles = ('postsubmit');
         my $current = {          $current = {
                         'postsubmit' => $postsubmitclient,                         'postsubmit' => $postsubmitclient,
                       };                     };
         ($table,$itemcount) =          ($table,$itemcount) =
             &radiobutton_prefs($current,\@toggles,\%defaultchecked,              &radiobutton_prefs($current,\@toggles,\%defaultchecked,
                                \%choices,$itemcount,$onclick,$additional,'left');                                 \%choices,$itemcount,$onclick,$additional,'left');
         $datatable .= $table;          $datatable .= $table;
           $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
           $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
                         $choices{'mysqltables'}.
                         '</span></td>'.
                         '<td 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="mysqltables_'.$type.'"'.
                              ' value="'.$currmysql{$type}.'" size="8" /></td>';
           }
           $datatable .= '</tr></table></td></tr>'."\n";
           $itemcount ++;
   
     }      }
     $$rowtotal += $itemcount;      $$rowtotal += $itemcount;
     return $datatable;      return $datatable;
Line 3062  sub print_selfenrollment { Line 5611  sub print_selfenrollment {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable);      my ($css_class,$datatable);
     my $itemcount = 1;      my $itemcount = 1;
     my @types = ('official','unofficial','community','textbook');      my @types = ('official','unofficial','community','textbook','placement');
     if (($position eq 'top') || ($position eq 'middle')) {      if (($position eq 'top') || ($position eq 'middle')) {
         my ($rowsref,$titlesref) = &Apache::lonuserutils::get_selfenroll_titles();          my ($rowsref,$titlesref) = &Apache::lonuserutils::get_selfenroll_titles();
         my %descs = &Apache::lonuserutils::selfenroll_default_descs();          my %descs = &Apache::lonuserutils::selfenroll_default_descs();
Line 3246  sub print_validation_rows { Line 5795  sub print_validation_rows {
                               '</label></span> ';                                '</label></span> ';
             }              }
         } elsif ($item eq 'markup') {          } elsif ($item eq 'markup') {
             $datatable .= '<textarea name="'.$caller.'_validation_markup" cols="50" rows="5" wrap="soft">'.              $datatable .= '<textarea name="'.$caller.'_validation_markup" cols="50" rows="5">'.
                            $currvalidation{$item}.                             $currvalidation{$item}.
                               '</textarea>';                                '</textarea>';
         }          }
Line 3268  sub print_validation_rows { Line 5817  sub print_validation_rows {
         my ($numdc,$dctable,$rows) = &active_dc_picker($dom,$numinrow,'radio',          my ($numdc,$dctable,$rows) = &active_dc_picker($dom,$numinrow,'radio',
                                                        'validationdc',%currhash);                                                         'validationdc',%currhash);
         my $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';          my $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
         $datatable .= '</td></tr><tr'.$css_class.'><td>';          $datatable .= '<tr'.$css_class.'><td>';
         if ($numdc > 1) {          if ($numdc > 1) {
             $datatable .= &mt('Course creation processed as: (choose Dom. Coord.)');              $datatable .= &mt('Course creation processed as: (choose Dom. Coord.)');
         } else {          } else {
Line 3283  sub print_validation_rows { Line 5832  sub print_validation_rows {
     return $datatable;      return $datatable;
 }  }
   
   sub print_privacy {
       my ($position,$dom,$settings,$rowtotal) = @_;
       my ($datatable,$css_class,$numinrow,@items,%names,$othertitle,$usertypes,$types);
       my $itemcount = 0;
       unless ($position eq 'top') {
           @items = ('domain','author','course','community');
           %names = &Apache::lonlocal::texthash (
                        domain => 'Assigned domain role(s)',
                        author => 'Assigned co-author role(s)',
                        course => 'Assigned course role(s)',
                        community => 'Assigned community role',
                    );
           $numinrow = 4;
           ($othertitle,$usertypes,$types) =
               &Apache::loncommon::sorted_inst_types($dom);
       }
       if (($position eq 'top') || ($position eq 'middle')) {
           my (%by_ip,%by_location,@intdoms,@instdoms);
           &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
           if ($position eq 'top') {
               my %curr;
               my @options = ('none','user','domain','auto');
               my %titles = &Apache::lonlocal::texthash (
                   none   => 'Not allowed',
                   user   => 'User authorizes',
                   domain => 'DC authorizes',
                   auto   => 'Unrestricted',
                   instdom => 'Other domain shares institution/provider',
                   extdom => 'Other domain has different institution/provider',
               );
               my %names = &Apache::lonlocal::texthash (
                   domain => 'Domain role',
                   author => 'Co-author role',
                   course => 'Course role',
                   community => 'Community role',
               );
               my $primary_id = &Apache::lonnet::domain($dom,'primary');
               my $intdom = &Apache::lonnet::internet_dom($primary_id);
               foreach my $domtype ('instdom','extdom') {
                   my (%checked,$skip);
                   $css_class = $itemcount%2?' class="LC_odd_row"':'';
                   $datatable .= '<tr'.$css_class.'><td>'.$titles{$domtype}.'</td>'.
                                 '<td class="LC_left_item">';
                   if ($domtype eq 'instdom') {
                       unless (@instdoms > 1) {
                           $datatable .= &mt('Nothing to set, as no domains besides [_1] are hosted by [_2]',$dom,$intdom);
                           $skip = 1;
                       }
                   } elsif ($domtype eq 'extdom') {
                       if (keys(%by_location) == 0) {
                           $datatable .= &mt('Nothing to set, as no other hosts besides [_1]',$intdom);
                           $skip = 1;
                       }
                   }
                   unless ($skip) {
                       foreach my $roletype ('domain','author','course','community') {
                           $checked{'auto'} = ' checked="checked"';
                           if (ref($settings) eq 'HASH') {
                               if (ref($settings->{approval}) eq 'HASH') {
                                   if (ref($settings->{approval}->{$domtype}) eq 'HASH') {
                                       if ($settings->{approval}->{$domtype}->{$roletype}=~ /^(none|user|domain)$/) {
                                           $checked{$1} = ' checked="checked"';
                                           $checked{'auto'} = '';
                                       }
                                   }
                               }
                           }
                           $datatable .= '<fieldset><legend>'.$names{$roletype}.'</legend>';
                           foreach my $option (@options) {
                               $datatable .= '<span class="LC_nobreak"><label>'.
                                             '<input type="radio" name="privacy_approval_'.$domtype.'_'.$roletype.'" '.
                                             'value="'.$option.'"'.$checked{$option}.' />'.$titles{$option}.
                                             '</label></span>&nbsp; ';
                           }
                           $datatable .= '</fieldset>';
                       }
                   }
                   $datatable .= '</td></tr>';
                   $itemcount ++;
               }
           } elsif ($position eq 'middle') {
               if ((@instdoms > 1) || (keys(%by_location) > 0)) {
                   if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
                       foreach my $item (@{$types}) {
                           $datatable .= &modifiable_userdata_row('privacy','othdom_'.$item,$settings,
                                                                  $numinrow,$itemcount,'','','','','',
                                                                  '',$usertypes->{$item});
                           $itemcount ++;
                       }
                   }
                   $datatable .= &modifiable_userdata_row('privacy','othdom_default',$settings,
                                                          $numinrow,$itemcount,'','','','','',
                                                          '',$othertitle);
                   $itemcount ++;
               } else {
                   my (@insttypes,%insttitles);
                   if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
                       @insttypes = @{$types};
                       %insttitles = %{$usertypes};
                   }
                   foreach my $item (@insttypes,'default') {
                       my $title;
                       if ($item eq 'default') {
                           $title = $othertitle;
                       } else {
                           $title = $insttitles{$item};
                       }
                       $css_class = $itemcount%2?' class="LC_odd_row"':'';
                       $datatable .= '<tr'.$css_class.'>'.
                                     '<td class="LC_left_item">'.$title.'</td>'.
                                     '<td class="LC_left_item">'.
                                     &mt('Nothing to set here, as there are no other domains').
                                     '</td></tr>';
                       $itemcount ++;
                   }
               }
           }
       } else {
           my $prefix;
           if ($position eq 'lower') {
               $prefix = 'priv';
           } else {
               $prefix = 'unpriv';
           }
           foreach my $item (@items) {
               $datatable .= &modifiable_userdata_row('privacy',$prefix.'_'.$item,$settings,
                                                      $numinrow,$itemcount,'','','','','',
                                                      '',$names{$item});
               $itemcount ++;
           }
       }
       if (ref($rowtotal)) {
           $$rowtotal += $itemcount;
       }
       return $datatable;
   }
   
   sub print_passwords {
       my ($position,$dom,$confname,$settings,$rowtotal) = @_;
       my ($datatable,$css_class);
       my $itemcount = 0;
       my %titles = &Apache::lonlocal::texthash (
           captcha        => '"Forgot Password" CAPTCHA validation',
           link           => 'Reset link expiration (hours)',
           case           => 'Case-sensitive usernames/e-mail',
           prelink        => 'Information required (form 1)',
           postlink       => 'Information required (form 2)',
           emailsrc       => 'LON-CAPA e-mail address type(s)',
           customtext     => 'Domain specific text (HTML)',
           intauth_cost   => 'Encryption cost for bcrypt (positive integer)',
           intauth_check  => 'Check bcrypt cost if authenticated',
           intauth_switch => 'Existing crypt-based switched to bcrypt on authentication',
           permanent      => 'Permanent e-mail address',
           critical       => 'Critical notification address',
           notify         => 'Notification address',
           min            => 'Minimum password length',
           max            => 'Maximum password length',
           chars          => 'Required characters',
           expire         => 'Password expiration (days)',
           numsaved       => 'Number of previous passwords to save and disallow reuse',
       );
       if ($position eq 'top') {
           my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
           my $shownlinklife = 2;
           my $prelink = 'both';
           my (%casesens,%postlink,%emailsrc,$nostdtext,$customurl);
           if (ref($settings) eq 'HASH') {
               if ($settings->{resetlink} =~ /^\d+(|\.\d*)$/) {
                   $shownlinklife = $settings->{resetlink};
               }
               if (ref($settings->{resetcase}) eq 'ARRAY') {
                   map { $casesens{$_} = 1; } (@{$settings->{resetcase}});
               }
               if ($settings->{resetprelink} =~ /^(both|either)$/) {
                   $prelink = $settings->{resetprelink};
               }
               if (ref($settings->{resetpostlink}) eq 'HASH') {
                   %postlink = %{$settings->{resetpostlink}};
               }
               if (ref($settings->{resetemail}) eq 'ARRAY') {
                   map { $emailsrc{$_} = 1; } (@{$settings->{resetemail}});
               }
               if ($settings->{resetremove}) {
                   $nostdtext = 1;
               }
               if ($settings->{resetcustom}) {
                   $customurl = $settings->{resetcustom};
               }
           } else {
               if (ref($types) eq 'ARRAY') {
                   foreach my $item (@{$types}) {
                       $casesens{$item} = 1;
                       $postlink{$item} = ['username','email'];
                   }
               }
               $casesens{'default'} = 1;
               $postlink{'default'} = ['username','email'];
               $prelink = 'both';
               %emailsrc = (
                             permanent => 1,
                             critical  => 1,
                             notify    => 1,
               );
           }
           $datatable = &captcha_choice('passwords',$settings,$$rowtotal);
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'link'}.'</td>'.
                         '<td class="LC_left_item">'.
                         '<input type="textbox" value="'.$shownlinklife.'" '.
                         'name="passwords_link" size="3" /></td></tr>';
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'case'}.'</td>'.
                         '<td class="LC_left_item">';
           if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
               foreach my $item (@{$types}) {
                   my $checkedcase;
                   if ($casesens{$item}) {
                       $checkedcase = ' checked="checked"';
                   }
                   $datatable .= '<span class="LC_nobreak"><label>'.
                                 '<input type="checkbox" name="passwords_case_sensitive" value="'.
                                 $item.'"'.$checkedcase.' />'.$usertypes->{$item}.'</label>'.
                                 '<span>&nbsp;&nbsp; ';
               }
           }
           my $checkedcase;
           if ($casesens{'default'}) {
               $checkedcase = ' checked="checked"';
           }
           $datatable .= '<span class="LC_nobreak"><label><input type="checkbox" '.
                         'name="passwords_case_sensitive" value="default"'.$checkedcase.' />'.
                         $othertitle.'</label></span></td>';
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           my %checkedpre = (
                                both => ' checked="checked"',
                                either => '',
                            );
           if ($prelink eq 'either') {
               $checkedpre{either} = ' checked="checked"';
               $checkedpre{both} = '';
           }
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'prelink'}.'</td>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         '<label><input type="radio" name="passwords_prelink" value="both"'.$checkedpre{'both'}.' />'.
                         &mt('Both username and e-mail address').'</label></span>&nbsp;&nbsp; '.
                         '<span class="LC_nobreak"><label>'.
                         '<input type="radio" name="passwords_prelink" value="either"'.$checkedpre{'either'}.' />'.
                         &mt('Either username or e-mail address').'</label></span></td></tr>';
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'postlink'}.'</td>'.
                         '<td class="LC_left_item">';
           my %postlinked;
           if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
               foreach my $item (@{$types}) {
                   undef(%postlinked);
                   $datatable .= '<fieldset style="display: inline-block;">'.
                                 '<legend>'.$usertypes->{$item}.'</legend>';
                   if (ref($postlink{$item}) eq 'ARRAY') {
                       map { $postlinked{$_} = 1; } (@{$postlink{$item}});
                   }
                   foreach my $field ('email','username') {
                       my $checked;
                       if ($postlinked{$field}) {
                           $checked = ' checked="checked"';
                       }
                       $datatable .= '<span class="LC_nobreak"><label>'.
                                     '<input type="checkbox" name="passwords_postlink_'.$item.'" value="'.
                                     $field.'"'.$checked.' />'.$field.'</label>'.
                                     '<span>&nbsp;&nbsp; ';
                   }
                   $datatable .= '</fieldset>';
               }
           }
           if (ref($postlink{'default'}) eq 'ARRAY') {
               map { $postlinked{$_} = 1; } (@{$postlink{'default'}});
           }
           $datatable .= '<fieldset style="display: inline-block;">'.
                         '<legend>'.$othertitle.'</legend>';
           foreach my $field ('email','username') {
               my $checked;
               if ($postlinked{$field}) {
                   $checked = ' checked="checked"';
               }
               $datatable .= '<span class="LC_nobreak"><label>'.
                             '<input type="checkbox" name="passwords_postlink_default" value="'.
                             $field.'"'.$checked.' />'.$field.'</label>'.
                             '<span>&nbsp;&nbsp; ';
           }
           $datatable .= '</fieldset></td></tr>';
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'emailsrc'}.'</td>'.
                         '<td class="LC_left_item">';
           foreach my $type ('permanent','critical','notify') {
               my $checkedemail;
               if ($emailsrc{$type}) {
                   $checkedemail = ' checked="checked"';
               }
               $datatable .= '<span class="LC_nobreak"><label>'.
                             '<input type="checkbox" name="passwords_emailsrc" value="'.
                             $type.'"'.$checkedemail.' />'.$titles{$type}.'</label>'.
                             '<span>&nbsp;&nbsp; ';
           }
           $datatable .= '</td></tr>';
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           my $switchserver = &check_switchserver($dom,$confname);
           my ($showstd,$noshowstd);
           if ($nostdtext) {
               $noshowstd = ' checked="checked"';
           } else {
               $showstd = ' checked="checked"';
           }
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'customtext'}.'</td>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         &mt('Retain standard text:').
                         '<label><input type="radio" name="passwords_stdtext" value="1"'.$showstd.' />'.
                         &mt('Yes').'</label>'.'&nbsp;'.
                         '<label><input type="radio" name="passwords_stdtext" value="0"'.$noshowstd.' />'.
                         &mt('No').'</label></span><br />'.
                         '<span class="LC_fontsize_small">'.
                         &mt('(If you use the same account ...  reset a password from this page.)').'</span><br /><br />'.
                         &mt('Include custom text:');
           if ($customurl) {
               my $link =  &Apache::loncommon::modal_link($customurl,&mt('Custom text file'),600,500,
                                                          undef,undef,undef,undef,'background-color:#ffffff');
               $datatable .= '<span class="LC_nobreak">&nbsp;'.$link.
                             '<label><input type="checkbox" name="passwords_custom_del"'.
                             ' value="1" />'.&mt('Delete?').'</label></span>'.
                             ' <span class="LC_nobreak">&nbsp;'.&mt('Replace:').'</span>';
           }
           if ($switchserver) {
               $datatable .= '<span class="LC_nobreak">&nbsp;'.&mt('Upload to library server: [_1]',$switchserver).'</span>';
           } else {
               $datatable .='<span class="LC_nobreak">&nbsp;'.
                            '<input type="file" name="passwords_customfile" /></span>';
           }
           $datatable .= '</td></tr>';
       } elsif ($position eq 'middle') {
           my %domconf = &Apache::lonnet::get_dom('configuration',['defaults'],$dom);
           my @items = ('intauth_cost','intauth_check','intauth_switch');
           my %defaults;
           if (ref($domconf{'defaults'}) eq 'HASH') {
               %defaults = %{$domconf{'defaults'}};
               if ($defaults{'intauth_cost'} !~ /^\d+$/) {
                   $defaults{'intauth_cost'} = 10;
               }
               if ($defaults{'intauth_check'} !~ /^(0|1|2)$/) {
                   $defaults{'intauth_check'} = 0;
               }
               if ($defaults{'intauth_switch'} !~ /^(0|1|2)$/) {
                   $defaults{'intauth_switch'} = 0;
               }
           } else {
               %defaults = (
                             'intauth_cost'   => 10,
                             'intauth_check'  => 0,
                             'intauth_switch' => 0,
                           );
           }
           foreach my $item (@items) {
               if ($itemcount%2) {
                   $css_class = '';
               } else {
                   $css_class = ' class="LC_odd_row" ';
               }
               $datatable .= '<tr'.$css_class.'>'.
                             '<td><span class="LC_nobreak">'.$titles{$item}.
                             '</span></td><td class="LC_left_item" colspan="3">';
               if ($item eq 'intauth_switch') {
                   my @options = (0,1,2);
                   my %optiondesc = &Apache::lonlocal::texthash (
                                      0 => 'No',
                                      1 => 'Yes',
                                      2 => 'Yes, and copy existing passwd file to passwd.bak file',
                                    );
                   $datatable .= '<table width="100%">';
                   foreach my $option (@options) {
                       my $checked = ' ';
                       if ($defaults{$item} eq $option) {
                           $checked = ' checked="checked"';
                       }
                       $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.
                                     '<label><input type="radio" name="'.$item.
                                     '" value="'.$option.'"'.$checked.' />'.
                                     $optiondesc{$option}.'</label></span></td></tr>';
                   }
                   $datatable .= '</table>';
               } elsif ($item eq 'intauth_check') {
                   my @options = (0,1,2);
                   my %optiondesc = &Apache::lonlocal::texthash (
                                      0 => 'No',
                                      1 => 'Yes, allow login then update passwd file using default cost (if higher)',
                                      2 => 'Yes, disallow login if stored cost is less than domain default',
                                    );
                   $datatable .= '<table width="100%">';
                   foreach my $option (@options) {
                       my $checked = ' ';
                       my $onclick;
                       if ($defaults{$item} eq $option) {
                           $checked = ' checked="checked"';
                       }
                       if ($option == 2) {
                           $onclick = ' onclick="javascript:warnIntAuth(this);"';
                       }
                       $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.
                                     '<label><input type="radio" name="'.$item.
                                     '" value="'.$option.'"'.$checked.$onclick.' />'.
                                     $optiondesc{$option}.'</label></span></td></tr>';
                   }
                   $datatable .= '</table>';
               } else {
                   $datatable .= '<input type="text" name="'.$item.'" value="'.
                                 $defaults{$item}.'" size="3" onblur="javascript:warnIntAuth(this);" />';
               }
               $datatable .= '</td></tr>';
               $itemcount ++;
           }
       } elsif ($position eq 'lower') {
           my ($min,$max,%chars,$expire,$numsaved);
           $min = $Apache::lonnet::passwdmin;
           if (ref($settings) eq 'HASH') {
               if ($settings->{min}) {
                   $min = $settings->{min};
               }
               if ($settings->{max}) {
                   $max = $settings->{max};
               }
               if (ref($settings->{chars}) eq 'ARRAY') {
                   map { $chars{$_} = 1; } (@{$settings->{chars}});
               }
               if ($settings->{expire}) {
                   $expire = $settings->{expire};
               }
               if ($settings->{numsaved}) {
                   $numsaved = $settings->{numsaved};
               }
           }
           my %rulenames = &Apache::lonlocal::texthash(
                                                        uc => 'At least one upper case letter',
                                                        lc => 'At least one lower case letter',
                                                        num => 'At least one number',
                                                        spec => 'At least one non-alphanumeric',
                                                      );
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'min'}.'</td>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         '<input type="text" name="passwords_min" value="'.$min.'" size="3" '.
                         'onblur="javascript:warnIntPass(this);" />'.
                         '<span class="LC_fontsize_small"> '.&mt('(Enter an integer: 7 or larger)').'</span>'.
                         '</span></td></tr>';
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'max'}.'</td>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         '<input type="text" name="passwords_max" value="'.$max.'" size="3" '.
                         'onblur="javascript:warnIntPass(this);" />'.
                         '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no maximum)').'</span>'.
                         '</span></td></tr>';
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'chars'}.'<br />'.
                         '<span class="LC_nobreak LC_fontsize_small">'.&mt('(Leave unchecked if not required)').
                         '</span></td>';
           my $numinrow = 2;
           my @possrules = ('uc','lc','num','spec');
           $datatable .= '<td class="LC_left_item"><table>';
           for (my $i=0; $i<@possrules; $i++) {
               my ($rem,$checked);
               if ($chars{$possrules[$i]}) {
                   $checked = ' checked="checked"';
               }
               $rem = $i%($numinrow);
               if ($rem == 0) {
                   if ($i > 0) {
                       $datatable .= '</tr>';
                   }
                   $datatable .= '<tr>';
               }
               $datatable .= '<td><span class="LC_nobreak"><label>'.
                             '<input type="checkbox" name="passwords_chars" value="'.$possrules[$i].'"'.$checked.' />'.
                             $rulenames{$possrules[$i]}.'</label></span></td>';
           }
           my $rem = @possrules%($numinrow);
           my $colsleft = $numinrow - $rem;
           if ($colsleft > 1 ) {
               $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
                             '&nbsp;</td>';
           } elsif ($colsleft == 1) {
               $datatable .= '<td class="LC_left_item">&nbsp;</td>';
           }
           $datatable .='</table></td></tr>';
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'expire'}.'</td>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         '<input type="text" name="passwords_expire" value="'.$expire.'" size="4" '.
                         'onblur="javascript:warnIntPass(this);" />'.
                         '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no expiration)').'</span>'.
                         '</span></td></tr>';
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'numsaved'}.'</td>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         '<input type="text" name="passwords_numsaved" value="'.$numsaved.'" size="3" '.
                         'onblur="javascript:warnIntPass(this);" />'. 
                         '<span class="LC_fontsize_small"> '.&mt('(Leave blank to not save previous passwords)').'</span>'.
                         '</span></td></tr>';
       } else {
           my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
           my %ownerchg = (
                             by  => {},
                             for => {},
                          );
           my %ownertitles = &Apache::lonlocal::texthash (
                               by  => 'Course owner status(es) allowed',
                               for => 'Student status(es) allowed',
                             );
           if (ref($settings) eq 'HASH') {
               if (ref($settings->{crsownerchg}) eq 'HASH') {
                   if (ref($settings->{crsownerchg}{'by'}) eq 'ARRAY') {
                       map { $ownerchg{by}{$_} = 1; } (@{$settings->{crsownerchg}{'by'}});
                   }
                   if (ref($settings->{crsownerchg}{'for'}) eq 'ARRAY') {
                       map { $ownerchg{for}{$_} = 1; } (@{$settings->{crsownerchg}{'for'}});
                   }
               }
           }
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr '.$css_class.'>'.
                         '<td>'.
                         &mt('Requirements').'<ul>'.
                         '<li>'.&mt("Course 'type' is not a Community or Placement Test").'</li>'.
                         '<li>'.&mt('User is Course Coordinator and also course owner').'</li>'.
                         '<li>'.&mt("Student's only active roles are student role(s) in course(s) owned by this user").'</li>'.
                         '<li>'.&mt('User, course, and student share same domain').'</li>'.
                         '</ul>'.
                         '</td>'.
                         '<td class="LC_left_item">';
           foreach my $item ('by','for') {
               $datatable .= '<fieldset style="display: inline-block;">'.
                             '<legend>'.$ownertitles{$item}.'</legend>';
               if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
                   foreach my $type (@{$types}) {
                       my $checked;
                       if ($ownerchg{$item}{$type}) {
                           $checked = ' checked="checked"';
                       }
                       $datatable .= '<span class="LC_nobreak"><label>'.
                                     '<input type="checkbox" name="passwords_crsowner_'.$item.'" value="'.
                                     $type.'"'.$checked.' />'.$usertypes->{$type}.'</label>'.
                                     '<span>&nbsp;&nbsp; ';
                   }
               }
               my $checked;
               if ($ownerchg{$item}{'default'}) {
                   $checked = ' checked="checked"';
               }
               $datatable .= '<span class="LC_nobreak"><label><input type="checkbox" '.
                             'name="passwords_crsowner_'.$item.'" value="default"'.$checked.' />'.
                             $othertitle.'</label></span></fieldset>';
           }
           $datatable .= '</td></tr>';
       }
       return $datatable;
   }
   
 sub print_usersessions {  sub print_usersessions {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable,%checked,%choices);      my ($css_class,$datatable,$itemcount,%checked,%choices);
     my (%by_ip,%by_location,@intdoms);      my (%by_ip,%by_location,@intdoms,@instdoms);
     &build_location_hashes(\@intdoms,\%by_ip,\%by_location);      &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
   
     my @alldoms = &Apache::lonnet::all_domains();      my @alldoms = &Apache::lonnet::all_domains();
     my %serverhomes = %Apache::lonnet::serverhomeIDs;      my %serverhomes = %Apache::lonnet::serverhomeIDs;
     my %servers = &Apache::lonnet::internet_dom_servers($dom);      my %servers = &Apache::lonnet::internet_dom_servers($dom);
     my %altids = &id_for_thisdom(%servers);      my %altids = &id_for_thisdom(%servers);
     my $itemcount = 1;  
     if ($position eq 'top') {      if ($position eq 'top') {
         if (keys(%serverhomes) > 1) {          if (keys(%serverhomes) > 1) {
             my %spareid = &current_offloads_to($dom,$settings,\%servers);              my %spareid = &current_offloads_to($dom,$settings,\%servers);
             $datatable .= &spares_row($dom,\%servers,\%spareid,\%serverhomes,\%altids,$rowtotal);              my $curroffloadnow;
               if (ref($settings) eq 'HASH') {
                   if (ref($settings->{'offloadnow'}) eq 'HASH') {
                       $curroffloadnow = $settings->{'offloadnow'};
                   }
               }
               $datatable .= &spares_row($dom,\%servers,\%spareid,\%serverhomes,\%altids,$curroffloadnow,$rowtotal);
         } else {          } else {
             $datatable .= '<tr'.$css_class.'><td colspan="2">'.              $datatable .= '<tr'.$css_class.'><td colspan="2">'.
                           &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.');                            &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.').
                             '</td></tr>';
         }          }
     } else {      } else {
         if (keys(%by_location) == 0) {          my %titles = &usersession_titles();
             $datatable .= '<tr'.$css_class.'><td colspan="2">'.          my ($prefix,@types);
                           &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.');          if ($position eq 'bottom') {
               $prefix = 'remote';
               @types = ('version','excludedomain','includedomain');
         } else {          } else {
             my %lt = &usersession_titles();              $prefix = 'hosted';
             my $numinrow = 5;              @types = ('excludedomain','includedomain');
             my $prefix;          }
             my @types;          ($datatable,$itemcount) = &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
             if ($position eq 'bottom') {      }
                 $prefix = 'remote';      $$rowtotal += $itemcount;
                 @types = ('version','excludedomain','includedomain');      return $datatable;
             } else {  }
                 $prefix = 'hosted';  
                 @types = ('excludedomain','includedomain');  sub rules_by_location {
             }      my ($settings,$prefix,$by_location,$by_ip,$types,$titles) = @_; 
             my (%current,%checkedon,%checkedoff);      my ($datatable,$itemcount,$css_class);
             my @lcversions = &Apache::lonnet::all_loncaparevs();      if (keys(%{$by_location}) == 0) {
             my @locations = sort(keys(%by_location));          $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
             foreach my $type (@types) {          $datatable = '<tr'.$css_class.'><td colspan="2">'.
                 $checkedon{$type} = '';                       &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.').
                 $checkedoff{$type} = ' checked="checked"';                       '</td></tr>';
             }          $itemcount = 1;
             if (ref($settings) eq 'HASH') {      } else {
                 if (ref($settings->{$prefix}) eq 'HASH') {          $itemcount = 0;
                     foreach my $key (keys(%{$settings->{$prefix}})) {          my $numinrow = 5;
                         $current{$key} = $settings->{$prefix}{$key};          my (%current,%checkedon,%checkedoff);
                         if ($key eq 'version') {          my @locations = sort(keys(%{$by_location}));
                             if ($current{$key} ne '') {          foreach my $type (@{$types}) {
                                 $checkedon{$key} = ' checked="checked"';              $checkedon{$type} = '';
                                 $checkedoff{$key} = '';              $checkedoff{$type} = ' checked="checked"';
                             }          }
                         } elsif (ref($current{$key}) eq 'ARRAY') {          if (ref($settings) eq 'HASH') {
               if (ref($settings->{$prefix}) eq 'HASH') {
                   foreach my $key (keys(%{$settings->{$prefix}})) {
                       $current{$key} = $settings->{$prefix}{$key};
                       if ($key eq 'version') {
                           if ($current{$key} ne '') {
                             $checkedon{$key} = ' checked="checked"';                              $checkedon{$key} = ' checked="checked"';
                             $checkedoff{$key} = '';                              $checkedoff{$key} = '';
                         }                          }
                       } elsif (ref($current{$key}) eq 'ARRAY') {
                           $checkedon{$key} = ' checked="checked"';
                           $checkedoff{$key} = '';
                     }                      }
                 }                  }
             }              }
             foreach my $type (@types) {          }
                 next if ($type ne 'version' && !@locations);          foreach my $type (@{$types}) {
                 $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';              next if ($type ne 'version' && !@locations);
                 $datatable .= '<tr'.$css_class.'>              $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
                                <td><span class="LC_nobreak">'.$lt{$type}.'</span><br />              $datatable .= '<tr'.$css_class.'>
                                <span class="LC_nobreak">&nbsp;                             <td><span class="LC_nobreak">'.$titles->{$type}.'</span><br />
                                <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedoff{$type}.' value="0" />'.&mt('Not in use').'</label>&nbsp;                             <span class="LC_nobreak">&nbsp;
                                <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedon{$type}.' value="1" />'.&mt('In use').'</label></span></td><td>';                             <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedoff{$type}.' value="0" />'.&mt('Not in use').'</label>&nbsp;
                 if ($type eq 'version') {                             <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedon{$type}.' value="1" />'.&mt('In use').'</label></span></td><td>';
                     my $selector = '<select name="'.$prefix.'_version">';              if ($type eq 'version') {
                     foreach my $version (@lcversions) {                  my @lcversions = &Apache::lonnet::all_loncaparevs();
                         my $selected = '';                  my $selector = '<select name="'.$prefix.'_version">';
                         if ($current{'version'} eq $version) {                  foreach my $version (@lcversions) {
                             $selected = ' selected="selected"';                      my $selected = '';
                         }                      if ($current{'version'} eq $version) {
                         $selector .= ' <option value="'.$version.'"'.                          $selected = ' selected="selected"';
                                      $selected.'>'.$version.'</option>';  
                     }                      }
                     $selector .= '</select> ';                      $selector .= ' <option value="'.$version.'"'.
                     $datatable .= &mt('remote server must be version: [_1] or later',$selector);                                   $selected.'>'.$version.'</option>';
                 } else {                  }
                     $datatable.= '<div><input type="button" value="'.&mt('check all').'" '.                  $selector .= '</select> ';
                                  'onclick="javascript:checkAll(document.display.'.$prefix.'_'.$type.')"'.                  $datatable .= &mt('remote server must be version: [_1] or later',$selector);
                                  ' />'.('&nbsp;'x2).              } else {
                                  '<input type="button" value="'.&mt('uncheck all').'" '.                  $datatable.= '<div><input type="button" value="'.&mt('check all').'" '.
                                  'onclick="javascript:uncheckAll(document.display.'.$prefix.'_'.$type.')" />'.                               'onclick="javascript:checkAll(document.display.'.$prefix.'_'.$type.')"'.
                                  "\n".                               ' />'.('&nbsp;'x2).
                                  '</div><div><table>';                               '<input type="button" value="'.&mt('uncheck all').'" '.
                     my $rem;                               'onclick="javascript:uncheckAll(document.display.'.$prefix.'_'.$type.')" />'.
                     for (my $i=0; $i<@locations; $i++) {                               "\n".
                         my ($showloc,$value,$checkedtype);                               '</div><div><table>';
                         if (ref($by_location{$locations[$i]}) eq 'ARRAY') {                  my $rem;
                             my $ip = $by_location{$locations[$i]}->[0];                  for (my $i=0; $i<@locations; $i++) {
                             if (ref($by_ip{$ip}) eq 'ARRAY') {                      my ($showloc,$value,$checkedtype);
                                  $value = join(':',@{$by_ip{$ip}});                      if (ref($by_location->{$locations[$i]}) eq 'ARRAY') {
                                 $showloc = join(', ',@{$by_ip{$ip}});                          my $ip = $by_location->{$locations[$i]}->[0];
                                 if (ref($current{$type}) eq 'ARRAY') {                          if (ref($by_ip->{$ip}) eq 'ARRAY') {
                                     foreach my $loc (@{$by_ip{$ip}}) {                                $value = join(':',@{$by_ip->{$ip}});
                                         if (grep(/^\Q$loc\E$/,@{$current{$type}})) {                              $showloc = join(', ',@{$by_ip->{$ip}});
                                             $checkedtype = ' checked="checked"';                              if (ref($current{$type}) eq 'ARRAY') {
                                             last;                                  foreach my $loc (@{$by_ip->{$ip}}) {
                                         }                                      if (grep(/^\Q$loc\E$/,@{$current{$type}})) {
                                           $checkedtype = ' checked="checked"';
                                           last;
                                     }                                      }
                                 }                                  }
                             }                              }
                         }                          }
                         $rem = $i%($numinrow);  
                         if ($rem == 0) {  
                             if ($i > 0) {  
                                 $datatable .= '</tr>';  
                             }  
                             $datatable .= '<tr>';  
                         }  
                         $datatable .= '<td class="LC_left_item">'.  
                                       '<span class="LC_nobreak"><label>'.  
                                       '<input type="checkbox" name="'.$prefix.'_'.$type.  
                                       '" value="'.$value.'"'.$checkedtype.' />'.$showloc.  
                                       '</label></span></td>';  
                     }                      }
                     $rem = @locations%($numinrow);                      $rem = $i%($numinrow);
                     my $colsleft = $numinrow - $rem;                      if ($rem == 0) {
                     if ($colsleft > 1 ) {                          if ($i > 0) {
                         $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.                              $datatable .= '</tr>';
                                       '&nbsp;</td>';                          }
                     } elsif ($colsleft == 1) {                          $datatable .= '<tr>';
                         $datatable .= '<td class="LC_left_item">&nbsp;</td>';                      }
                       $datatable .= '<td class="LC_left_item">'.
                                     '<span class="LC_nobreak"><label>'.
                                     '<input type="checkbox" name="'.$prefix.'_'.$type.
                                     '" value="'.$value.'"'.$checkedtype.' />'.$showloc.
                                     '</label></span></td>';
                   }
                   $rem = @locations%($numinrow);
                   my $colsleft = $numinrow - $rem;
                   if ($colsleft > 1 ) {
                       $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
                                     '&nbsp;</td>';
                   } elsif ($colsleft == 1) {
                       $datatable .= '<td class="LC_left_item">&nbsp;</td>';
                   }
                   $datatable .= '</tr></table>';
               }
               $datatable .= '</td></tr>';
               $itemcount ++;
           }
       }
       return ($datatable,$itemcount);
   }
   
   sub print_ssl {
       my ($position,$dom,$settings,$rowtotal) = @_;
       my ($css_class,$datatable);
       my $itemcount = 1;
       if ($position eq 'top') {
           my $primary_id = &Apache::lonnet::domain($dom,'primary');
           my $intdom = &Apache::lonnet::internet_dom($primary_id);
           my $same_institution;
           if ($intdom ne '') {
               my $internet_names = &Apache::lonnet::get_internet_names($Apache::lonnet::perlvar{'lonHostID'});
               if (ref($internet_names) eq 'ARRAY') {
                   if (grep(/^\Q$intdom\E$/,@{$internet_names})) {
                       $same_institution = 1;
                   }
               }
           }
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable = '<tr'.$css_class.'><td colspan="2">';
           if ($same_institution) {
               my %domservers = &Apache::lonnet::get_servers($dom);
               $datatable .= &LONCAPA::SSL::print_certstatus(\%domservers,'web','domprefs');
           } else {
               $datatable .= &mt("You need to be logged into one of your own domain's servers to display information about the status of LON-CAPA SSL certificates.");
           }
           $datatable .= '</td></tr>';
           $itemcount ++;
       } else {
           my %titles = &ssl_titles();
           my (%by_ip,%by_location,@intdoms,@instdoms);
           &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
           my @alldoms = &Apache::lonnet::all_domains();
           my %serverhomes = %Apache::lonnet::serverhomeIDs;
           my @domservers = &Apache::lonnet::get_servers($dom);
           my %servers = &Apache::lonnet::internet_dom_servers($dom);
           my %altids = &id_for_thisdom(%servers);
           if (($position eq 'connto') || ($position eq 'connfrom')) {
               my $legacy;
               unless (ref($settings) eq 'HASH') {
                   my $name;
                   if ($position eq 'connto') {
                       $name = 'loncAllowInsecure';
                   } else {
                       $name = 'londAllowInsecure';
                   }
                   my $primarylibserv = &Apache::lonnet::domain($dom,'primary');
                   my @ids=&Apache::lonnet::current_machine_ids();
                   if (($primarylibserv ne '') && (!grep(/^\Q$primarylibserv\E$/,@ids))) {
                       my %what = (
                                      $name => 1,
                                  );
                       my ($result,$returnhash) =
                           &Apache::lonnet::get_remote_globals($primarylibserv,\%what);
                       if ($result eq 'ok') {
                           if (ref($returnhash) eq 'HASH') {
                               $legacy = $returnhash->{$name};
                           }
                       }
                   } else {
                       $legacy = $Apache::lonnet::perlvar{$name};
                   }
               }
               foreach my $type ('dom','intdom','other') {
                   my %checked;
                   $css_class = $itemcount%2?' class="LC_odd_row"':'';
                   $datatable .= '<tr'.$css_class.'><td>'.$titles{$type}.'</td>'.
                                 '<td class="LC_right_item">';
                   my $skip; 
                   if ($type eq 'dom') {
                       unless (keys(%servers) > 1) {
                           $datatable .= &mt('Nothing to set here, as there are no other servers/VMs');    
                           $skip = 1;
                       }
                   }
                   if ($type eq 'intdom') {
                       unless (@instdoms > 1) {
                           $datatable .= &mt('Nothing to set here, as there are no other domains for this institution');
                           $skip = 1;
                       } 
                   } elsif ($type eq 'other') {
                       if (keys(%by_location) == 0) {
                           $datatable .= &mt('Nothing to set here, as there are no other institutions');
                           $skip = 1;
                       }
                   }
                   unless ($skip) {
                       $checked{'yes'} = ' checked="checked"'; 
                       if (ref($settings) eq 'HASH') {
                           if (ref($settings->{$position}) eq 'HASH') {
                               if ($settings->{$position}->{$type} =~ /^(no|req)$/) {
                                   $checked{$1} = $checked{'yes'};
                                   delete($checked{'yes'}); 
                               }
                           }
                       } else {
                           if ($legacy == 0) {
                               $checked{'req'} = $checked{'yes'};
                               delete($checked{'yes'});    
                           }
                       }
                       foreach my $option ('no','yes','req') {
                           $datatable .= '<span class="LC_nobreak"><label>'.
                                         '<input type="radio" name="'.$position.'_'.$type.'" '.
                                         'value="'.$option.'"'.$checked{$option}.' />'.$titles{$option}.
                                         '</label></span>'.('&nbsp;'x2);
                     }                      }
                     $datatable .= '</tr></table>';  
                 }                  }
                 $datatable .= '</td></tr>';                  $datatable .= '</td></tr>';
                   $itemcount ++; 
               }
           } else {
               my $prefix = 'replication';
               my @types = ('certreq','nocertreq');
               if (keys(%by_location) == 0) {
                   $datatable .= '<tr'.$css_class.'><td>'.
                                 &mt('Nothing to set here, as there are no other institutions').
                                 '</td></tr>';
                 $itemcount ++;                  $itemcount ++;
               } else {
                   ($datatable,$itemcount) = 
                       &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
             }              }
         }          }
     }      }
Line 3419  sub print_usersessions { Line 6682  sub print_usersessions {
     return $datatable;      return $datatable;
 }  }
   
   sub ssl_titles {
       return &Apache::lonlocal::texthash (
                  dom           => 'LON-CAPA servers/VMs from same domain',
                  intdom        => 'LON-CAPA servers/VMs from same "internet" domain',
                  other         => 'External LON-CAPA servers/VMs',
                  connto        => 'Connections to other servers',
                  connfrom      => 'Connections from other servers',
                  replication   => 'Replicating content to other institutions',
                  certreq       => 'Client certificate required, but specific domains exempt',
                  nocertreq     => 'No client certificate required, except for specific domains',
                  no            => 'SSL not used',
                  yes           => 'SSL Optional (used if available)',
                  req           => 'SSL Required',
       );
   }
   
   sub print_trust {
       my ($prefix,$dom,$settings,$rowtotal) = @_;
       my ($css_class,$datatable,%checked,%choices);
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
       my $itemcount = 1;
       my %titles = &trust_titles();
       my @types = ('exc','inc');
       if ($prefix eq 'top') {
           $prefix = 'content';
       } elsif ($prefix eq 'bottom') {
           $prefix = 'msg';
       }
       ($datatable,$itemcount) = &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
       $$rowtotal += $itemcount;
       return $datatable;
   }
   
   sub trust_titles {
       return &Apache::lonlocal::texthash(
                  content  => "Access to this domain's content by others",
                  shared   => "Access to other domain's content by this domain",
                  enroll   => "Enrollment in this domain's courses by others", 
                  othcoau  => "Co-author roles in this domain for others",
                  coaurem  => "Co-author roles for this domain's users elsewhere", 
                  domroles => "Domain roles in this domain assignable to others",
                  catalog  => "Course Catalog for this domain displayed elsewhere",
                  reqcrs   => "Requests for creation of courses in this domain by others",
                  msg      => "Users in other domains can send messages to this domain",
                  exc      => "Allow all, but exclude specific domains",
                  inc      => "Deny all, but include specific domains",
              );
   } 
   
 sub build_location_hashes {  sub build_location_hashes {
     my ($intdoms,$by_ip,$by_location) = @_;      my ($intdoms,$by_ip,$by_location,$instdoms) = @_;
     return unless((ref($intdoms) eq 'ARRAY') && (ref($by_ip) eq 'HASH') &&      return unless((ref($intdoms) eq 'ARRAY') && (ref($by_ip) eq 'HASH') &&
                   (ref($by_location) eq 'HASH'));                     (ref($by_location) eq 'HASH') && (ref($instdoms) eq 'ARRAY'));
     my %iphost = &Apache::lonnet::get_iphost();      my %iphost = &Apache::lonnet::get_iphost();
     my $primary_id = &Apache::lonnet::domain($env{'request.role.domain'},'primary');      my $primary_id = &Apache::lonnet::domain($env{'request.role.domain'},'primary');
     my $primary_ip = &Apache::lonnet::get_host_ip($primary_id);      my $primary_ip = &Apache::lonnet::get_host_ip($primary_id);
Line 3439  sub build_location_hashes { Line 6752  sub build_location_hashes {
             foreach my $id (@{$iphost{$ip}}) {              foreach my $id (@{$iphost{$ip}}) {
                 my $location = &Apache::lonnet::internet_dom($id);                  my $location = &Apache::lonnet::internet_dom($id);
                 if ($location) {                  if ($location) {
                     next if (grep(/^\Q$location\E$/,@{$intdoms}));                      if (grep(/^\Q$location\E$/,@{$intdoms})) {
                           my $dom = &Apache::lonnet::host_domain($id);
                           unless (grep(/^\Q$dom\E/,@{$instdoms})) {
                               push(@{$instdoms},$dom);
                           }
                           next;
                       }
                     if (ref($by_ip->{$ip}) eq 'ARRAY') {                      if (ref($by_ip->{$ip}) eq 'ARRAY') {
                         unless(grep(/^\Q$location\E$/,@{$by_ip->{$ip}})) {                          unless(grep(/^\Q$location\E$/,@{$by_ip->{$ip}})) {
                             push(@{$by_ip->{$ip}},$location);                              push(@{$by_ip->{$ip}},$location);
Line 3547  sub current_offloads_to { Line 6866  sub current_offloads_to {
 }  }
   
 sub spares_row {  sub spares_row {
     my ($dom,$servers,$spareid,$serverhomes,$altids,$rowtotal) = @_;      my ($dom,$servers,$spareid,$serverhomes,$altids,$curroffloadnow,$rowtotal) = @_;
     my $css_class;      my $css_class;
     my $numinrow = 4;      my $numinrow = 4;
     my $itemcount = 1;      my $itemcount = 1;
Line 3567  sub spares_row { Line 6886  sub spares_row {
                 }                  }
             }              }
             next unless (ref($spareid->{$server}) eq 'HASH');              next unless (ref($spareid->{$server}) eq 'HASH');
               my $checkednow;
               if (ref($curroffloadnow) eq 'HASH') {
                   if ($curroffloadnow->{$server}) {
                       $checkednow = ' checked="checked"';
                   }
               }
             $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';              $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
             $datatable .= '<tr'.$css_class.'>              $datatable .= '<tr'.$css_class.'>
                            <td rowspan="2">                             <td rowspan="2">
                             <span class="LC_nobreak">'.                              <span class="LC_nobreak">'.
                           &mt('[_1] when busy, offloads to:'                            &mt('[_1] when busy, offloads to:'
                               ,'<b>'.$server.'</b>').                                ,'<b>'.$server.'</b>').'</span><br />'.
                             '<span class="LC_nobreak">'."\n".
                             '<label><input type="checkbox" name="offloadnow" value="'.$server.'"'.$checkednow.' />'.
                             '&nbsp;'.&mt('Switch active users on next access').'</label></span>'.
                           "\n";                            "\n";
             my (%current,%canselect);              my (%current,%canselect);
             my @choices =               my @choices = 
Line 3697  sub print_loadbalancing { Line 7025  sub print_loadbalancing {
     my $numinrow = 1;      my $numinrow = 1;
     my $datatable;      my $datatable;
     my %servers = &Apache::lonnet::internet_dom_servers($dom);      my %servers = &Apache::lonnet::internet_dom_servers($dom);
     my (%currbalancer,%currtargets,%currrules,%existing);      my (%currbalancer,%currtargets,%currrules,%existing,%currcookies);
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         %existing = %{$settings};          %existing = %{$settings};
     }      }
     if ((keys(%servers) > 1) || (keys(%existing) > 0)) {      if ((keys(%servers) > 1) || (keys(%existing) > 0)) {
         &get_loadbalancers_config(\%servers,\%existing,\%currbalancer,          &get_loadbalancers_config(\%servers,\%existing,\%currbalancer,
                                   \%currtargets,\%currrules);                                    \%currtargets,\%currrules,\%currcookies);
     } else {      } else {
         return;          return;
     }      }
Line 3737  sub print_loadbalancing { Line 7065  sub print_loadbalancing {
         my $disabled_div_style = 'display: block';          my $disabled_div_style = 'display: block';
         my $homedom_div_style = 'display: none';          my $homedom_div_style = 'display: none';
         $datatable .= '<tr class="'.$css_class[$cssidx].'">'.          $datatable .= '<tr class="'.$css_class[$cssidx].'">'.
                       '<td rowspan="'.$rownum.'" valign="top">'.                        '<td rowspan="'.$rownum.'" style="vertical-align: top">'.
                       '<p>';                        '<p>';
         if ($lonhost eq '') {          if ($lonhost eq '') {
             $datatable .= '<span class="LC_nobreak">';              $datatable .= '<span class="LC_nobreak">';
Line 3770  sub print_loadbalancing { Line 7098  sub print_loadbalancing {
                 $homedom_div_style = 'display: block';                  $homedom_div_style = 'display: block';
             }              }
         }          }
         $datatable .= '</p></td><td rowspan="'.$rownum.'" valign="top">'.          $datatable .= '</p></td><td rowspan="'.$rownum.'" style="vertical-align: top">'.
                   '<div id="loadbalancing_disabled_'.$balnum.'" style="'.                    '<div id="loadbalancing_disabled_'.$balnum.'" style="'.
                   $disabled_div_style.'">'.$disabledtext.'</div>'."\n".                    $disabled_div_style.'">'.$disabledtext.'</div>'."\n".
                   '<div id="loadbalancing_targets_'.$balnum.'" style="'.$targets_div_style.'">'.&mt('Offloads to:').'<br />';                    '<div id="loadbalancing_targets_'.$balnum.'" style="'.$targets_div_style.'">'.&mt('Offloads to:').'<br />';
         my ($numspares,@spares) = &count_servers($lonhost,%servers);          my ($numspares,@spares) = &count_servers($lonhost,%servers);
         my @sparestypes = ('primary','default');          my @sparestypes = ('primary','default');
         my %typetitles = &sparestype_titles();          my %typetitles = &sparestype_titles();
           my %hostherechecked = (
                                     no => ' checked="checked"',
                                 );
           my %balcookiechecked = (
                                     no => ' checked="checked"', 
                                  );
         foreach my $sparetype (@sparestypes) {          foreach my $sparetype (@sparestypes) {
             my $targettable;              my $targettable;
             for (my $i=0; $i<$numspares; $i++) {              for (my $i=0; $i<$numspares; $i++) {
Line 3822  sub print_loadbalancing { Line 7156  sub print_loadbalancing {
                 $datatable .=  '<i>'.$typetitles{$sparetype}.'</i><br />'.                  $datatable .=  '<i>'.$typetitles{$sparetype}.'</i><br />'.
                                '<table><tr>'.$targettable.'</tr></table><br />';                                 '<table><tr>'.$targettable.'</tr></table><br />';
             }              }
               $hostherechecked{$sparetype} = '';
               if (ref($currtargets{$lonhost}) eq 'HASH') {
                   if (ref($currtargets{$lonhost}{$sparetype}) eq 'ARRAY') {
                       if (grep(/^\Q$lonhost\E$/,@{$currtargets{$lonhost}{$sparetype}})) {
                           $hostherechecked{$sparetype} = ' checked="checked"';
                           $hostherechecked{'no'} = '';
                       }
                   }
               }
         }          }
         $datatable .= '</div></td></tr>'.          if ($currcookies{$lonhost}) {
               %balcookiechecked = (
                                       yes => ' checked="checked"',
                                   );
           }
           $datatable .= &mt('Hosting on balancer itself').'<br />'.
                         '<label><input type="radio" name="loadbalancing_target_'.$balnum.'_hosthere" value="no"'.
                         $hostherechecked{'no'}.' />'.&mt('No').'</label><br />';
           foreach my $sparetype (@sparestypes) {
               $datatable .= '<label><input type="radio" name="loadbalancing_target_'.$balnum.'_hosthere" '.
                             'value="'.$sparetype.'"'.$hostherechecked{$sparetype}.' /><i>'.$typetitles{$sparetype}.
                             '</i></label><br />';
           }
           $datatable .= &mt('Use balancer cookie').'<br />'.
                         '<label><input type="radio" name="loadbalancing_cookie_'.$balnum.'" value="1"'.
                         $balcookiechecked{'yes'}.' />'.&mt('Yes').'</label><br />'.
                         '<label><input type="radio" name="loadbalancing_cookie_'.$balnum.'" value="0"'.
                         $balcookiechecked{'no'}.' />'.&mt('No').'</label><br />'.
                         '</div></td></tr>'.
                       &loadbalancing_rules($dom,$intdom,$currrules{$lonhost},                        &loadbalancing_rules($dom,$intdom,$currrules{$lonhost},
                                            $othertitle,$usertypes,$types,\%servers,                                             $othertitle,$usertypes,$types,\%servers,
                                            \%currbalancer,$lonhost,                                             \%currbalancer,$lonhost,
Line 3837  sub print_loadbalancing { Line 7198  sub print_loadbalancing {
 }  }
   
 sub get_loadbalancers_config {  sub get_loadbalancers_config {
     my ($servers,$existing,$currbalancer,$currtargets,$currrules) = @_;      my ($servers,$existing,$currbalancer,$currtargets,$currrules,$currcookies) = @_;
     return unless ((ref($servers) eq 'HASH') &&      return unless ((ref($servers) eq 'HASH') &&
                    (ref($existing) eq 'HASH') && (ref($currbalancer) eq 'HASH') &&                     (ref($existing) eq 'HASH') && (ref($currbalancer) eq 'HASH') &&
                    (ref($currtargets) eq 'HASH') && (ref($currrules) eq 'HASH'));                     (ref($currtargets) eq 'HASH') && (ref($currrules) eq 'HASH') &&
                      (ref($currcookies) eq 'HASH'));
     if (keys(%{$existing}) > 0) {      if (keys(%{$existing}) > 0) {
         my $oldlonhost;          my $oldlonhost;
         foreach my $key (sort(keys(%{$existing}))) {          foreach my $key (sort(keys(%{$existing}))) {
Line 3859  sub get_loadbalancers_config { Line 7221  sub get_loadbalancers_config {
                 $currbalancer->{$key} = 1;                  $currbalancer->{$key} = 1;
                 $currtargets->{$key} = $existing->{$key}{'targets'};                  $currtargets->{$key} = $existing->{$key}{'targets'};
                 $currrules->{$key} = $existing->{$key}{'rules'};                  $currrules->{$key} = $existing->{$key}{'rules'};
                   if ($existing->{$key}{'cookie'}) {
                       $currcookies->{$key} = 1;
                   }
             }              }
         }          }
     } else {      } else {
Line 3914  sub loadbalancing_titles { Line 7279  sub loadbalancing_titles {
            '_LC_ipchange'    => &mt('Non-SSO users with IP mismatch'),             '_LC_ipchange'    => &mt('Non-SSO users with IP mismatch'),
                      );                       );
     my @alltypes = ('_LC_adv','_LC_author','_LC_internetdom','_LC_external','_LC_ipchangesso','_LC_ipchange');      my @alltypes = ('_LC_adv','_LC_author','_LC_internetdom','_LC_external','_LC_ipchangesso','_LC_ipchange');
       my @available;
     if (ref($types) eq 'ARRAY') {      if (ref($types) eq 'ARRAY') {
         unshift(@alltypes,@{$types},'default');          @available = @{$types};
       }
       unless (grep(/^default$/,@available)) {
           push(@available,'default');
     }      }
       unshift(@alltypes,@available);
     my %titles;      my %titles;
     foreach my $type (@alltypes) {      foreach my $type (@alltypes) {
         if ($type =~ /^_LC_/) {          if ($type =~ /^_LC_/) {
Line 3957  sub loadbalance_rule_row { Line 7327  sub loadbalance_rule_row {
     }      }
     my $space;      my $space;
     if ($islast && $num == 1) {      if ($islast && $num == 1) {
         $space = '<div display="inline-block">&nbsp;</div>';          $space = '<div style="display:inline-block;">&nbsp;</div>';
     }      }
     my $output =      my $output =
         '<tr class="'.$css_class.'" id="balanceruletr_'.$balnum.'_'.$num.'"><td valign="top">'.$space.          '<tr class="'.$css_class.'" id="balanceruletr_'.$balnum.'_'.$num.'"><td style="vertical-align: top">'.$space.
         '<div id="balanceruletitle_'.$balnum.'_'.$type.'" style="'.$style.'">'.$title.'</div></td>'."\n".          '<div id="balanceruletitle_'.$balnum.'_'.$type.'" style="'.$style.'">'.$title.'</div></td>'."\n".
         '<td valaign="top">'.$space.          '<td valaign="top">'.$space.
         '<div id="balancerule_'.$balnum.'_'.$type.'" style="'.$style.'">'."\n";          '<div id="balancerule_'.$balnum.'_'.$type.'" style="'.$style.'">'."\n";
Line 4039  sub sparestype_titles { Line 7409  sub sparestype_titles {
   
 sub contact_titles {  sub contact_titles {
     my %titles = &Apache::lonlocal::texthash (      my %titles = &Apache::lonlocal::texthash (
                    'supportemail' => 'Support E-mail address',                     'supportemail'    => 'Support E-mail address',
                    'adminemail'   => 'Default Server Admin E-mail address',                     'adminemail'      => 'Default Server Admin E-mail address',
                    'errormail'    => 'Error reports to be e-mailed to',                     'errormail'       => 'Error reports to be e-mailed to',
                    'packagesmail' => 'Package update alerts to be e-mailed to',                     'packagesmail'    => 'Package update alerts to be e-mailed to',
                    'helpdeskmail' => 'Helpdesk requests to be e-mailed to',                     'helpdeskmail'    => "Helpdesk requests from all users in this domain",
                    'lonstatusmail' => 'E-mail from nightly status check (warnings/errors)',                     'otherdomsmail'   => 'Helpdesk requests from users in other (unconfigured) domains',
                    'requestsmail' => 'E-mail from course requests requiring approval',                     'lonstatusmail'   => 'E-mail from nightly status check (warnings/errors)',
                    'updatesmail'  => 'E-mail from nightly check of LON-CAPA module integrity/updates',                     'requestsmail'    => 'E-mail from course requests requiring approval',
                      'updatesmail'     => 'E-mail from nightly check of LON-CAPA module integrity/updates',
                    'idconflictsmail' => 'E-mail from bi-nightly check for multiple users sharing same student/employee ID',                     'idconflictsmail' => 'E-mail from bi-nightly check for multiple users sharing same student/employee ID',
                      'hostipmail'      => 'E-mail from nightly check of hostname/IP network changes',
                      'errorthreshold'  => 'Error/warning threshold for status e-mail',
                      'errorsysmail'    => 'Error threshold for e-mail to core group',
                      'errorweights'    => 'Weights used to compute error count',
                      'errorexcluded'   => 'Servers with unsent updates excluded from count',
                  );                   );
     my %short_titles = &Apache::lonlocal::texthash (      my %short_titles = &Apache::lonlocal::texthash (
                            adminemail   => 'Admin E-mail address',                             adminemail   => 'Admin E-mail address',
Line 4056  sub contact_titles { Line 7432  sub contact_titles {
     return (\%titles,\%short_titles);      return (\%titles,\%short_titles);
 }  }
   
   sub helpform_fields {
       my %titles =  &Apache::lonlocal::texthash (
                          'username'   => 'Name',
                          'user'       => 'Username/domain',
                          'phone'      => 'Phone',
                          'cc'         => 'Cc e-mail',
                          'course'     => 'Course Details',
                          'section'    => 'Sections',
                          'screenshot' => 'File upload',
       );
       my @fields = ('username','phone','user','course','section','cc','screenshot');
       my %possoptions = (
                           username     => ['yes','no','req'],
                           phone        => ['yes','no','req'],
                           user         => ['yes','no'],
                           cc           => ['yes','no'],
                           course       => ['yes','no'],
                           section      => ['yes','no'],
                           screenshot   => ['yes','no'],
                         );
       my %fieldoptions = &Apache::lonlocal::texthash (
                            'yes'  => 'Optional',
                            'req'  => 'Required',
                            'no'   => "Not shown",
       );
       return (\@fields,\%titles,\%fieldoptions,\%possoptions);
   }
   
 sub tool_titles {  sub tool_titles {
     my %titles = &Apache::lonlocal::texthash (      my %titles = &Apache::lonlocal::texthash (
                      aboutme    => 'Personal web page',                       aboutme    => 'Personal web page',
Line 4066  sub tool_titles { Line 7470  sub tool_titles {
                      unofficial => 'Unofficial courses',                       unofficial => 'Unofficial courses',
                      community  => 'Communities',                       community  => 'Communities',
                      textbook   => 'Textbook courses',                       textbook   => 'Textbook courses',
                        placement  => 'Placement tests',
                  );                   );
     return %titles;      return %titles;
 }  }
Line 4076  sub courserequest_titles { Line 7481  sub courserequest_titles {
                                    unofficial => 'Unofficial',                                     unofficial => 'Unofficial',
                                    community  => 'Communities',                                     community  => 'Communities',
                                    textbook   => 'Textbook',                                     textbook   => 'Textbook',
                                      placement  => 'Placement tests',
                                      lti        => 'LTI Provider',
                                    norequest  => 'Not allowed',                                     norequest  => 'Not allowed',
                                    approval   => 'Approval by Dom. Coord.',                                     approval   => 'Approval by DC',
                                    validate   => 'With validation',                                     validate   => 'With validation',
                                    autolimit  => 'Numerical limit',                                     autolimit  => 'Numerical limit',
                                    unlimited  => '(blank for unlimited)',                                     unlimited  => '(blank for unlimited)',
Line 4166  sub print_usercreation { Line 7573  sub print_usercreation {
             }              }
             $datatable .= '<tr'.$css_class.'>'.              $datatable .= '<tr'.$css_class.'>'.
                          '<td><span class="LC_nobreak">'.$lt{$item}.                           '<td><span class="LC_nobreak">'.$lt{$item}.
                          '</span></td><td align="right">';                           '</span></td><td style="text-align: right">';
             my @options = ('any');              my @options = ('any');
             if (ref($rules) eq 'HASH') {              if (ref($rules) eq 'HASH') {
                 if (keys(%{$rules}) > 0) {                  if (keys(%{$rules}) > 0) {
Line 4189  sub print_usercreation { Line 7596  sub print_usercreation {
         }          }
     } else {      } else {
         my @contexts = ('author','course','domain');          my @contexts = ('author','course','domain');
         my @authtypes = ('int','krb4','krb5','loc');          my @authtypes = ('int','krb4','krb5','loc','lti');
         my %checked;          my %checked;
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if (ref($settings->{'authtypes'}) eq 'HASH') {              if (ref($settings->{'authtypes'}) eq 'HASH') {
Line 4240  sub print_usercreation { Line 7647  sub print_usercreation {
   
 sub print_selfcreation {  sub print_selfcreation {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my (@selfcreate,$createsettings,$processing,$datatable);      my (@selfcreate,$createsettings,$processing,$emailoptions,$emailverified,
           $emaildomain,$datatable);
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if (ref($settings->{'cancreate'}) eq 'HASH') {          if (ref($settings->{'cancreate'}) eq 'HASH') {
             $createsettings = $settings->{'cancreate'};              $createsettings = $settings->{'cancreate'};
Line 4257  sub print_selfcreation { Line 7665  sub print_selfcreation {
                 if (ref($createsettings->{'selfcreateprocessing'}) eq 'HASH') {                  if (ref($createsettings->{'selfcreateprocessing'}) eq 'HASH') {
                     $processing = $createsettings->{'selfcreateprocessing'};                      $processing = $createsettings->{'selfcreateprocessing'};
                 }                  }
                   if (ref($createsettings->{'emailoptions'}) eq 'HASH') {
                       $emailoptions = $createsettings->{'emailoptions'};
                   }
                   if (ref($createsettings->{'emailverified'}) eq 'HASH') {
                       $emailverified = $createsettings->{'emailverified'};
                   }
                   if (ref($createsettings->{'emaildomain'}) eq 'HASH') {
                       $emaildomain = $createsettings->{'emaildomain'};
                   }
             }              }
         }          }
     }      }
     my %radiohash;      my %radiohash;
     my $numinrow = 4;      my $numinrow = 4;
     map { $radiohash{'cancreate_'.$_} = 1; } @selfcreate;      map { $radiohash{'cancreate_'.$_} = 1; } @selfcreate;
       my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
     if ($position eq 'top') {      if ($position eq 'top') {
         my %choices = &Apache::lonlocal::texthash (          my %choices = &Apache::lonlocal::texthash (
                                                       cancreate_login      => 'Institutional Login',                                                        cancreate_login      => 'Institutional Login',
Line 4278  sub print_selfcreation { Line 7696  sub print_selfcreation {
                                                      \%choices,$itemcount,$onclick);                                                       \%choices,$itemcount,$onclick);
         $$rowtotal += $itemcount;          $$rowtotal += $itemcount;
                   
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
   
         if (ref($usertypes) eq 'HASH') {          if (ref($usertypes) eq 'HASH') {
             if (keys(%{$usertypes}) > 0) {              if (keys(%{$usertypes}) > 0) {
                 $datatable .= &insttypes_row($createsettings,$types,$usertypes,                  $datatable .= &insttypes_row($createsettings,$types,$usertypes,
                                              $dom,$numinrow,$othertitle,                                               $dom,$numinrow,$othertitle,
                                              'statustocreate',$$rowtotal);                                               'statustocreate',$rowtotal);
                 $$rowtotal ++;                  $$rowtotal ++;
             }              }
         }          }
Line 4297  sub print_selfcreation { Line 7713  sub print_selfcreation {
         $datatable .= '<tr'.$css_class.'>'.          $datatable .= '<tr'.$css_class.'>'.
                      '<td class="LC_left_item">'.&mt('Mapping of Shibboleth environment variable names to user data fields (SSO auth)').'</td>'.                       '<td class="LC_left_item">'.&mt('Mapping of Shibboleth environment variable names to user data fields (SSO auth)').'</td>'.
                      '<td class="LC_left_item">'."\n".                       '<td class="LC_left_item">'."\n".
                      '<table><tr><td>'."\n";                       '<table>'."\n";
         for (my $i=0; $i<@fields; $i++) {          for (my $i=0; $i<@fields; $i++) {
             $rem = $i%($numperrow);              $rem = $i%($numperrow);
             if ($rem == 0) {              if ($rem == 0) {
Line 4329  sub print_selfcreation { Line 7745  sub print_selfcreation {
         $$rowtotal ++;          $$rowtotal ++;
     } elsif ($position eq 'middle') {      } elsif ($position eq 'middle') {
         my %domconf = &Apache::lonnet::get_dom('configuration',['usermodification'],$dom);          my %domconf = &Apache::lonnet::get_dom('configuration',['usermodification'],$dom);
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);          my @posstypes;
         $usertypes->{'default'} = $othertitle;  
         if (ref($types) eq 'ARRAY') {          if (ref($types) eq 'ARRAY') {
             push(@{$types},'default');              @posstypes = @{$types};
             $usertypes->{'default'} = $othertitle;          }
             foreach my $status (@{$types}) {          unless (grep(/^default$/,@posstypes)) {
                 $datatable .= &modifiable_userdata_row('selfcreate',$status,$domconf{'usermodification'},              push(@posstypes,'default');
                                                        $numinrow,$$rowtotal,$usertypes);          }
                 $$rowtotal ++;          my %usertypeshash;
             }          if (ref($usertypes) eq 'HASH') {
               %usertypeshash = %{$usertypes};
           }
           $usertypeshash{'default'} = $othertitle;
           foreach my $status (@posstypes) {
               $datatable .= &modifiable_userdata_row('selfcreate',$status,$domconf{'usermodification'},
                                                      $numinrow,$$rowtotal,\%usertypeshash);
               $$rowtotal ++;
         }          }
     } else {      } else {
         my %choices = &Apache::lonlocal::texthash (          my %choices = &Apache::lonlocal::texthash (
                                                       cancreate_email => 'E-mail address as username',                            'cancreate_email' => 'Non-institutional username (via e-mail verification)',
                                                   );                                                    );
         my @toggles = sort(keys(%choices));          my @toggles = sort(keys(%choices));
         my %defaultchecked = (          my %defaultchecked = (
                                'cancreate_email' => 'off',                                 'cancreate_email' => 'off',
                              );                               );
         my $itemcount = 0;          my $customclass = 'LC_selfcreate_email';
           my $classprefix = 'LC_canmodify_emailusername_';
           my $optionsprefix = 'LC_options_emailusername_';
         my $display = 'none';          my $display = 'none';
           my $rowstyle = 'display:none';
         if (grep(/^\Qemail\E$/,@selfcreate)) {          if (grep(/^\Qemail\E$/,@selfcreate)) {
             $display = 'block';              $display = 'block';
               $rowstyle = 'display:table-row';
         }          }
         my $onclick = "toggleDisplay(this.form,'emailoptions');";          my $onclick = "toggleRows(this.form,'cancreate_email','selfassign','$customclass','$classprefix','$optionsprefix');";
         my $additional = '<div id="emailoptions" style="display: '.$display.'">';          ($datatable,$$rowtotal) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked,
                                                        \%choices,$$rowtotal,$onclick);
           $datatable .= &print_requestmail($dom,'selfcreation',$createsettings,$rowtotal,$customclass,
                                            $rowstyle);
           $$rowtotal ++;
           $datatable .= &captcha_choice('cancreate',$createsettings,$$rowtotal,$customclass,
                                         $rowstyle);
           $$rowtotal ++;
           my (@ordered,@posstypes,%usertypeshash);
         my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);          my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
         my $usertypes = {};          my ($emailrules,$emailruleorder) =
         my $order = [];              &Apache::lonnet::inst_userrules($dom,'email');
         if ((ref($domdefaults{'inststatustypes'}) eq 'HASH') && (ref($domdefaults{'inststatusguest'}) eq 'ARRAY')) {          my $primary_id = &Apache::lonnet::domain($dom,'primary');
             $usertypes = $domdefaults{'inststatustypes'};          my $intdom = &Apache::lonnet::internet_dom($primary_id);
             $order = $domdefaults{'inststatusguest'};          if (ref($types) eq 'ARRAY') {
         }              @posstypes = @{$types};
         if (ref($order) eq 'ARRAY') {          }
             push(@{$order},'default');          if (@posstypes) {
             if (@{$order} > 1) {              unless (grep(/^default$/,@posstypes)) {
                 $usertypes->{'default'} = &mt('Other users');                  push(@posstypes,'default');
                 $additional .= '<table><tr>';              }
                 foreach my $status (@{$order}) {              if (ref($usertypes) eq 'HASH') {
                     $additional .= '<th>'.$usertypes->{$status}.'</th>';                  %usertypeshash = %{$usertypes};
                 }              }
                 $additional .= '</tr><tr>';              my $currassign;
                 foreach my $status (@{$order}) {              if (ref($domdefaults{'inststatusguest'}) eq 'ARRAY') {
                     $additional .= '<td>'.&email_as_username($rowtotal,$processing,$status).'</td>';                  $currassign = {
                 }                                    selfassign => $domdefaults{'inststatusguest'},
                 $additional .= '</tr></table>';                                };
                   @ordered = @{$domdefaults{'inststatusguest'}};
             } else {              } else {
                 $usertypes->{'default'} = &mt('All users');                  $currassign = { selfassign => [] };
                 $additional .= &email_as_username($rowtotal,$processing);              }
               my $onclicktypes = "toggleDataRow(this.form,'selfassign','$customclass','$optionsprefix',);".
                                  "toggleDataRow(this.form,'selfassign','$customclass','$classprefix',1);";
               $datatable .= &insttypes_row($currassign,$types,$usertypes,$dom,
                                            $numinrow,$othertitle,'selfassign',
                                            $rowtotal,$onclicktypes,$customclass,
                                            $rowstyle);
               $$rowtotal ++;
               $usertypeshash{'default'} = $othertitle;
               foreach my $status (@posstypes) {
                   my $css_class;
                   if ($$rowtotal%2) {
                       $css_class = 'LC_odd_row ';
                   }
                   $css_class .= $customclass;
                   my $rowid = $optionsprefix.$status;
                   my $hidden = 1;
                   my $currstyle = 'display:none';
                   if (grep(/^\Q$status\E$/,@ordered)) {
                       $currstyle = $rowstyle;
                       $hidden = 0; 
                   }
                   $datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain,
                                                $emailrules,$emailruleorder,$settings,$status,$rowid,
                                                $usertypeshash{$status},$css_class,$currstyle,$intdom);
                   unless ($hidden) {
                       $$rowtotal ++;
                   }
             }              }
           } else {
               my $css_class;
               if ($$rowtotal%2) {
                   $css_class = 'LC_odd_row ';
               }
               $css_class .= $customclass;
               $usertypeshash{'default'} = $othertitle;
               $datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain,
                                            $emailrules,$emailruleorder,$settings,'default','',
                                            $othertitle,$css_class,$rowstyle,$intdom);
               $$rowtotal ++;
         }          }
         $additional .= '</div>'."\n";  
   
         ($datatable,$itemcount) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked,  
                                                      \%choices,$$rowtotal,$onclick,$additional);  
         $$rowtotal ++;  
         $datatable .= &print_requestmail($dom,'selfcreation',$createsettings,$rowtotal);  
         $$rowtotal ++;  
         my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info();          my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info();
         $numinrow = 1;          $numinrow = 1;
         if (ref($order) eq 'ARRAY') {          if (@posstypes) {
             foreach my $status (@{$order}) {              foreach my $status (@posstypes) {
                   my $rowid = $classprefix.$status;
                   my $datarowstyle = 'display:none';
                   if (grep(/^\Q$status\E$/,@ordered)) { 
                       $datarowstyle = $rowstyle; 
                   }
                 $datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings,                  $datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings,
                                                        $numinrow,$$rowtotal,$usertypes,$infofields,$infotitles);                                                         $numinrow,$$rowtotal,\%usertypeshash,$infofields,
                 $$rowtotal ++;                                                         $infotitles,$rowid,$customclass,$datarowstyle);
                   unless ($datarowstyle eq 'display:none') {
                       $$rowtotal ++;
                   }
             }              }
           } else {
               $datatable .= &modifiable_userdata_row('cancreate','emailusername_default',$settings,
                                                      $numinrow,$$rowtotal,\%usertypeshash,$infofields,
                                                      $infotitles,'',$customclass,$rowstyle);
         }          }
         my ($emailrules,$emailruleorder) =      }
             &Apache::lonnet::inst_userrules($dom,'email');      return $datatable;
         if (ref($emailrules) eq 'HASH') {  }
             if (keys(%{$emailrules}) > 0) {  
                 $datatable .= &user_formats_row('email',$settings,$emailrules,  sub selfcreate_javascript {
                                                 $emailruleorder,$numinrow,$$rowtotal);      return <<"ENDSCRIPT";
                 $$rowtotal ++;  
   <script type="text/javascript">
   // <![CDATA[
   
   function toggleRows(form,radio,checkbox,target,prefix,altprefix) {
       var x = document.getElementsByClassName(target);
       var insttypes = 0;
       var insttypeRegExp = new RegExp(prefix);
       if ((x.length != undefined) && (x.length > 0)) {
           if (form.elements[radio].length != undefined) {
               for (var i=0; i<form.elements[radio].length; i++) {
                   if (form.elements[radio][i].checked) {
                       if (form.elements[radio][i].value == 1) {
                           for (var j=0; j<x.length; j++) {
                               if (x[j].id == 'undefined') {
                                   x[j].style.display = 'table-row';
                               } else if (insttypeRegExp.test(x[j].id)) {
                                   insttypes ++;
                               } else {
                                   x[j].style.display = 'table-row';
                               }
                           }
                       } else {
                           for (var j=0; j<x.length; j++) {
                               x[j].style.display = 'none';
                           }
                       }
                       break;
                   }
               }
               if (insttypes > 0) {
                   toggleDataRow(form,checkbox,target,altprefix);
                   toggleDataRow(form,checkbox,target,prefix,1);
             }              }
         }          }
         $datatable .= &captcha_choice('cancreate',$createsettings,$$rowtotal);  
     }      }
     return $datatable;      return;
 }  }
   
 sub email_as_username {  function toggleDataRow(form,checkbox,target,prefix,docount) {
     my ($rowtotal,$processing,$type) = @_;      if (form.elements[checkbox].length != undefined) {
     my %choices =          var count = 0;
         &Apache::lonlocal::texthash (          if (docount) {
                                       automatic => 'Automatic approval',              for (var i=0; i<form.elements[checkbox].length; i++) {
                                       approval  => 'Queued for approval',                  if (form.elements[checkbox][i].checked) {
                                     );                      count ++;
     my $output;                  }
     foreach my $option ('automatic','approval') {              }
         my $checked;          }
         if (ref($processing) eq 'HASH') {          for (var i=0; i<form.elements[checkbox].length; i++) {
             if ($type eq '') {                 var type = form.elements[checkbox][i].value;
                 if (!exists($processing->{'default'})) {              if (document.getElementById(prefix+type)) {
                     if ($option eq 'automatic') {                  if (form.elements[checkbox][i].checked) {
                         $checked = ' checked="checked"';                      document.getElementById(prefix+type).style.display = 'table-row';
                       if (count % 2 == 1) {
                           document.getElementById(prefix+type).className = target+' LC_odd_row';
                       } else {
                           document.getElementById(prefix+type).className = target;
                     }                      }
                       count ++;
                 } else {                  } else {
                     if ($processing->{'default'} eq $option) {                      document.getElementById(prefix+type).style.display = 'none';
                         $checked = ' checked="checked"';                  }
               }
           }
       }
       return;
   }
   
   function toggleEmailOptions(form,radio,prefix,altprefix,status) {
       var caller = radio+'_'+status;
       if (form.elements[caller].length != undefined) {
           for (var i=0; i<form.elements[caller].length; i++) {
               if (form.elements[caller][i].checked) {
                   if (document.getElementById(altprefix+'_inst_'+status)) {
                       var curr = form.elements[caller][i].value;
                       if (prefix) {
                           document.getElementById(prefix+'_'+status).style.display = 'none';
                       }
                       document.getElementById(altprefix+'_inst_'+status).style.display = 'none';
                       document.getElementById(altprefix+'_noninst_'+status).style.display = 'none';
                       if (curr == 'custom') {
                           if (prefix) { 
                               document.getElementById(prefix+'_'+status).style.display = 'inline';
                           }
                       } else if (curr == 'inst') {
                           document.getElementById(altprefix+'_inst_'+status).style.display = 'inline';
                       } else if (curr == 'noninst') {
                           document.getElementById(altprefix+'_noninst_'+status).style.display = 'inline';
                     }                      }
                       break;
                 }                  }
             } else {              }
                 if (!exists($processing->{$type})) {          }
                     if ($option eq 'automatic') {      }
                         $checked = ' checked="checked"';  }
   
   // ]]>
   </script>
   
   ENDSCRIPT
   }
   
   sub noninst_users {
       my ($processing,$emailverified,$emailoptions,$emaildomain,$emailrules,
           $emailruleorder,$settings,$type,$rowid,$typetitle,$css_class,$rowstyle,$intdom) = @_; 
       my $class = 'LC_left_item';
       if ($css_class) {
           $css_class = ' class="'.$css_class.'"'; 
       }
       if ($rowid) {
           $rowid = ' id="'.$rowid.'"';
       }
       if ($rowstyle) {
           $rowstyle = ' style="'.$rowstyle.'"';
       }
       my ($output,$description);
       if ($type eq 'default') {
           $description = &mt('Requests for: [_1]',$typetitle);
       } else {
           $description = &mt('Requests for: [_1] (status self-reported)',$typetitle);
       }
       $output = '<tr'.$css_class.$rowid.$rowstyle.'>'.
                 "<td>$description</td>\n".           
                 '<td class="'.$class.'" colspan="2">'.
                 '<table><tr>';
       my %headers = &Apache::lonlocal::texthash( 
                 approve  => 'Processing',
                 email    => 'E-mail',
                 username => 'Username',
       );
       foreach my $item ('approve','email','username') {
           $output .= '<th>'.$headers{$item}.'</th>';
       }
       $output .= '</tr><tr>';
       foreach my $item ('approve','email','username') {
           $output .= '<td style="vertical-align: top">';
           my (%choices,@options,$hashref,$defoption,$name,$onclick,$hascustom);
           if ($item eq 'approve') {
               %choices = &Apache::lonlocal::texthash (
                                                        automatic => 'Automatically approved',
                                                        approval  => 'Queued for approval',
                                                      );
               @options = ('automatic','approval');
               $hashref = $processing;
               $defoption = 'automatic';
               $name = 'cancreate_emailprocess_'.$type;
           } elsif ($item eq 'email') {
               %choices = &Apache::lonlocal::texthash (
                                                        any     => 'Any e-mail',
                                                        inst    => 'Institutional only',
                                                        noninst => 'Non-institutional only',
                                                        custom  => 'Custom restrictions',
                                                      );
               @options = ('any','inst','noninst');
               my $showcustom;
               if (ref($emailrules) eq 'HASH') {
                   if (keys(%{$emailrules}) > 0) {
                       push(@options,'custom');
                       $showcustom = 'cancreate_emailrule';
                       if (ref($settings) eq 'HASH') {
                           if (ref($settings->{'email_rule'}) eq 'ARRAY') {
                               foreach my $rule (@{$settings->{'email_rule'}}) {
                                   if (exists($emailrules->{$rule})) {
                                       $hascustom ++;
                                   }
                               }
                           } elsif (ref($settings->{'email_rule'}) eq 'HASH') {
                               if (ref($settings->{'email_rule'}{$type}) eq 'ARRAY') {
                                   foreach my $rule (@{$settings->{'email_rule'}{$type}}) {
                                       if (exists($emailrules->{$rule})) {
                                           $hascustom ++;
                                       }
                                   }
                               }
                           }
                       }
                   }
               }
               $onclick = ' onclick="toggleEmailOptions(this.form,'."'cancreate_emailoptions','$showcustom',".
                                                        "'cancreate_emaildomain','$type'".');"';
               $hashref = $emailoptions;
               $defoption = 'any';
               $name = 'cancreate_emailoptions_'.$type;
           } elsif ($item eq 'username') {
               %choices = &Apache::lonlocal::texthash (
                                                        all    => 'Same as e-mail',
                                                        first  => 'Omit @domain',
                                                        free   => 'Free to choose',
                                                      );
               @options = ('all','first','free');
               $hashref = $emailverified;
               $defoption = 'all';
               $name = 'cancreate_usernameoptions_'.$type;
           }
           foreach my $option (@options) {
               my $checked;
               if (ref($hashref) eq 'HASH') {
                   if ($type eq '') {
                       if (!exists($hashref->{'default'})) {
                           if ($option eq $defoption) {
                               $checked = ' checked="checked"';
                           }
                       } else {
                           if ($hashref->{'default'} eq $option) {
                               $checked = ' checked="checked"';
                           }
                     }                      }
                 } else {                  } else {
                     if ($processing->{$type} eq $option) {                      if (!exists($hashref->{$type})) {
                         $checked = ' checked="checked"';                          if ($option eq $defoption) {
                               $checked = ' checked="checked"';
                           }
                       } else {
                           if ($hashref->{$type} eq $option) {
                               $checked = ' checked="checked"';
                           }
                     }                      }
                 }                  }
               } elsif (($item eq 'email') && ($hascustom)) {
                   if ($option eq 'custom') {
                       $checked = ' checked="checked"';
                   }
               } elsif ($option eq $defoption) {
                   $checked = ' checked="checked"';
               }
               $output .= '<span class="LC_nobreak"><label>'.
                          '<input type="radio" name="'.$name.'"'.
                          $checked.' value="'.$option.'"'.$onclick.' />'.
                          $choices{$option}.'</label></span><br />';
               if ($item eq 'email') {
                   if ($option eq 'custom') {
                       my $id = 'cancreate_emailrule_'.$type;
                       my $display = 'none';
                       if ($checked) {
                           $display = 'inline';
                       }
                       my $numinrow = 2;
                       $output .= '<fieldset id="'.$id.'" style="display:'.$display.';">'.
                                  '<legend>'.&mt('Disallow').'</legend><table>'.
                                  &user_formats_row('email',$settings,$emailrules,
                                                    $emailruleorder,$numinrow,'',$type);
                                 '</table></fieldset>';
                   } elsif (($option eq 'inst') || ($option eq 'noninst')) {
                       my %text = &Apache::lonlocal::texthash (
                                                                inst    => 'must end:',
                                                                noninst => 'cannot end:',
                                                              );
                       my $value;
                       if (ref($emaildomain) eq 'HASH') {
                           if (ref($emaildomain->{$type}) eq 'HASH') {
                               $value = $emaildomain->{$type}->{$option}; 
                           }
                       }
                       if ($value eq '') {
                           $value = '@'.$intdom;
                       }
                       my $condition = 'cancreate_emaildomain_'.$option.'_'.$type;
                       my $display = 'none';
                       if ($checked) {
                           $display = 'inline';
                       }
                       $output .= '<div id="'.$condition.'" style="display:'.$display.';">'.
                                  '<span class="LC_domprefs_email">'.$text{$option}.'</span> '.
                                  '<input type="text" name="'.$condition.'" value="'.$value.'" size="10" />'.
                                  '</div>';
                   }
             }              }
         } elsif ($option eq 'automatic') {  
             $checked = ' checked="checked"';   
         }  
         my $name = 'cancreate_emailprocess';  
         if (($type ne '') && ($type ne 'default')) {  
             $name .= '_'.$type;  
         }  
         $output .= '<span class="LC_nobreak"><label>'.  
                    '<input type="radio" name="'.$name.'"'.  
                    $checked.' value="'.$option.'" />'.  
                    $choices{$option}.'</label></span>';  
         if ($type eq '') {  
             $output .= '&nbsp;';  
         } else {  
             $output .= '<br />';  
         }          }
           $output .= '</td>'."\n";
     }      }
     $$rowtotal ++;      $output .= "</tr></table></td></tr>\n";
     return $output;      return $output;
 }  }
   
 sub captcha_choice {  sub captcha_choice {
     my ($context,$settings,$itemcount) = @_;      my ($context,$settings,$itemcount,$customcss,$rowstyle) = @_;
     my ($keyentry,$currpub,$currpriv,%checked,$rowname,$pubtext,$privtext);      my ($keyentry,$currpub,$currpriv,%checked,$rowname,$pubtext,$privtext,
           $vertext,$currver);
     my %lt = &captcha_phrases();      my %lt = &captcha_phrases();
     $keyentry = 'hidden';      $keyentry = 'hidden';
       my $colspan=2;
     if ($context eq 'cancreate') {      if ($context eq 'cancreate') {
         $rowname = &mt('CAPTCHA validation');          $rowname = &mt('CAPTCHA validation');
     } elsif ($context eq 'login') {      } elsif ($context eq 'login') {
         $rowname =  &mt('"Contact helpdesk" CAPTCHA validation');          $rowname =  &mt('"Contact helpdesk" CAPTCHA validation');
       } elsif ($context eq 'passwords') {
           $rowname = &mt('"Forgot Password" CAPTCHA validation');
           $colspan=1;
     }      }
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if ($settings->{'captcha'}) {          if ($settings->{'captcha'}) {
Line 4483  sub captcha_choice { Line 8180  sub captcha_choice {
             $pubtext = $lt{'pub'};              $pubtext = $lt{'pub'};
             $privtext = $lt{'priv'};              $privtext = $lt{'priv'};
             $keyentry = 'text';              $keyentry = 'text';
               $vertext = $lt{'ver'};
               $currver = $settings->{'recaptchaversion'};
               if ($currver ne '2') {
                   $currver = 1;
               }
         }          }
         if (ref($settings->{'recaptchakeys'}) eq 'HASH') {          if (ref($settings->{'recaptchakeys'}) eq 'HASH') {
             $currpub = $settings->{'recaptchakeys'}{'public'};              $currpub = $settings->{'recaptchakeys'}{'public'};
Line 4491  sub captcha_choice { Line 8193  sub captcha_choice {
     } else {      } else {
         $checked{'original'} = ' checked="checked"';          $checked{'original'} = ' checked="checked"';
     }      }
     my $css_class = $itemcount%2?' class="LC_odd_row"':'';      my $css_class;
       if ($itemcount%2) {
           $css_class = 'LC_odd_row';
       }
       if ($customcss) {
           $css_class .= " $customcss";
       }
       $css_class =~ s/^\s+//;
       if ($css_class) {
           $css_class = ' class="'.$css_class.'"';
       }
       if ($rowstyle) {
           $css_class .= ' style="'.$rowstyle.'"';
       }
     my $output = '<tr'.$css_class.'>'.      my $output = '<tr'.$css_class.'>'.
                  '<td class="LC_left_item">'.$rowname.'</td><td class="LC_left_item" colspan="2">'."\n".                   '<td class="LC_left_item">'.$rowname.'</td><td class="LC_left_item" colspan="'.$colspan.'">'."\n".
                  '<table><tr><td>'."\n";                   '<table><tr><td>'."\n";
     foreach my $option ('original','recaptcha','notused') {      foreach my $option ('original','recaptcha','notused') {
         $output .= '<span class="LC_nobreak"><label><input type="radio" name="'.$context.'_captcha" value="'.          $output .= '<span class="LC_nobreak"><label><input type="radio" name="'.$context.'_captcha" value="'.
Line 4510  sub captcha_choice { Line 8225  sub captcha_choice {
 # specified for use with the key should be broad enough to accommodate all servers in the LON-CAPA domain.  # specified for use with the key should be broad enough to accommodate all servers in the LON-CAPA domain.
 #  #
     $output .= '</td></tr>'."\n".      $output .= '</td></tr>'."\n".
                '<tr><td>'."\n".                 '<tr><td class="LC_zero_height">'."\n".
                '<span class="LC_nobreak"><span id="'.$context.'_recaptchapubtxt">'.$pubtext.'</span>&nbsp;'."\n".                 '<span class="LC_nobreak"><span id="'.$context.'_recaptchapubtxt">'.$pubtext.'</span>&nbsp;'."\n".
                '<input type="'.$keyentry.'" id="'.$context.'_recaptchapub" name="'.$context.'_recaptchapub" value="'.                 '<input type="'.$keyentry.'" id="'.$context.'_recaptchapub" name="'.$context.'_recaptchapub" value="'.
                $currpub.'" size="40" /></span><br />'."\n".                 $currpub.'" size="40" /></span><br />'."\n".
                '<span class="LC_nobreak"><span id="'.$context.'_recaptchaprivtxt">'.$privtext.'</span>&nbsp;'."\n".                 '<span class="LC_nobreak"><span id="'.$context.'_recaptchaprivtxt">'.$privtext.'</span>&nbsp;'."\n".
                '<input type="'.$keyentry.'" id="'.$context.'_recaptchapriv" name="'.$context.'_recaptchapriv" value="'.                 '<input type="'.$keyentry.'" id="'.$context.'_recaptchapriv" name="'.$context.'_recaptchapriv" value="'.
                $currpriv.'" size="40" /></span></td></tr></table>'."\n".                 $currpriv.'" size="40" /></span><br />'.
                  '<span class="LC_nobreak"><span id="'.$context.'_recaptchavertxt">'.$vertext.'</span>&nbsp;'."\n".
                  '<input type="'.$keyentry.'" id="'.$context.'_recaptchaversion" name="'.$context.'_recaptchaversion" value="'.
                  $currver.'" size="3" /></span><br />'.
                  '</td></tr></table>'."\n".
                '</td></tr>';                 '</td></tr>';
     return $output;      return $output;
 }  }
   
 sub user_formats_row {  sub user_formats_row {
     my ($type,$settings,$rules,$ruleorder,$numinrow,$rowcount) = @_;      my ($type,$settings,$rules,$ruleorder,$numinrow,$rowcount,$status) = @_;
     my $output;      my $output;
     my %text = (      my %text = (
                    'username' => 'new usernames',                     'username' => 'new usernames',
                    'id'       => 'IDs',                     'id'       => 'IDs',
                    'email'    => 'self-created accounts (e-mail)',  
                );                 );
     my $css_class = $rowcount%2?' class="LC_odd_row"':'';      unless ($type eq 'email') {
     $output = '<tr '.$css_class.'>'.          my $css_class = $rowcount%2?' class="LC_odd_row"':'';
               '<td><span class="LC_nobreak">';          $output = '<tr '.$css_class.'>'.
     if ($type eq 'email') {                    '<td><span class="LC_nobreak">'.
         $output .= &mt("Formats disallowed for $text{$type}: ");                    &mt("Format rules to check for $text{$type}: ").
     } else {                    '</td><td class="LC_left_item" colspan="2"><table>';
         $output .= &mt("Format rules to check for $text{$type}: ");  
     }      }
     $output .= '</span></td>'.  
                '<td class="LC_left_item" colspan="2"><table>';  
     my $rem;      my $rem;
     if (ref($ruleorder) eq 'ARRAY') {      if (ref($ruleorder) eq 'ARRAY') {
         for (my $i=0; $i<@{$ruleorder}; $i++) {          for (my $i=0; $i<@{$ruleorder}; $i++) {
Line 4556  sub user_formats_row { Line 8271  sub user_formats_row {
                         if (grep(/^\Q$ruleorder->[$i]\E$/,@{$settings->{$type.'_rule'}})) {                          if (grep(/^\Q$ruleorder->[$i]\E$/,@{$settings->{$type.'_rule'}})) {
                             $check = ' checked="checked" ';                              $check = ' checked="checked" ';
                         }                          }
                       } elsif ((ref($settings->{$type.'_rule'}) eq 'HASH') && ($status ne '')) {
                           if (ref($settings->{$type.'_rule'}->{$status}) eq 'ARRAY') {
                               if (grep(/^\Q$ruleorder->[$i]\E$/,@{$settings->{$type.'_rule'}->{$status}})) {
                                   $check = ' checked="checked" ';
                               }
                           }
                     }                      }
                 }                  }
                   my $name = $type.'_rule';
                   if ($type eq 'email') {
                       $name .= '_'.$status;
                   }
                 $output .= '<td class="LC_left_item">'.                  $output .= '<td class="LC_left_item">'.
                            '<span class="LC_nobreak"><label>'.                             '<span class="LC_nobreak"><label>'.
                            '<input type="checkbox" name="'.$type.'_rule" '.                             '<input type="checkbox" name="'.$name.'" '.
                            'value="'.$ruleorder->[$i].'"'.$check.'/>'.                             'value="'.$ruleorder->[$i].'"'.$check.'/>'.
                            $rules->{$ruleorder->[$i]}{'name'}.'</label></span></td>';                             $rules->{$ruleorder->[$i]}{'name'}.'</label></span></td>';
             }              }
         }          }
         $rem = @{$ruleorder}%($numinrow);          $rem = @{$ruleorder}%($numinrow);
     }      }
     my $colsleft = $numinrow - $rem;      my $colsleft;
       if ($rem) {
           $colsleft = $numinrow - $rem;
       }
     if ($colsleft > 1 ) {      if ($colsleft > 1 ) {
         $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.          $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
                    '&nbsp;</td>';                     '&nbsp;</td>';
     } elsif ($colsleft == 1) {      } elsif ($colsleft == 1) {
         $output .= '<td class="LC_left_item">&nbsp;</td>';          $output .= '<td class="LC_left_item">&nbsp;</td>';
     }      }
     $output .= '</tr></table></td></tr>';      $output .= '</tr></table>';
       unless ($type eq 'email') {
           $output .= '</td></tr>';
       }
     return $output;      return $output;
 }  }
   
Line 4609  sub authtype_names { Line 8340  sub authtype_names {
                       krb4   => 'Kerberos 4',                        krb4   => 'Kerberos 4',
                       krb5   => 'Kerberos 5',                        krb5   => 'Kerberos 5',
                       loc    => 'Local',                        loc    => 'Local',
                         lti    => 'LTI',
                   );                    );
     return %lt;      return %lt;
 }  }
Line 4651  sub print_usermodification { Line 8383  sub print_usermodification {
 sub print_defaults {  sub print_defaults {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my $rownum = 0;      my $rownum = 0;
     my ($datatable,$css_class);      my ($datatable,$css_class,$titles);
       unless ($position eq 'bottom') {
           $titles = &defaults_titles($dom);
       }
     if ($position eq 'top') {      if ($position eq 'top') {
         my @items = ('auth_def','auth_arg_def','lang_def','timezone_def',          my @items = ('auth_def','auth_arg_def','lang_def','timezone_def',
                      'datelocale_def','portal_def');                       'datelocale_def','portal_def');
Line 4664  sub print_defaults { Line 8399  sub print_defaults {
                 $defaults{$item} = $domdefaults{$item};                  $defaults{$item} = $domdefaults{$item};
             }              }
         }          }
         my $titles = &defaults_titles($dom);  
         foreach my $item (@items) {          foreach my $item (@items) {
             if ($rownum%2) {              if ($rownum%2) {
                 $css_class = '';                  $css_class = '';
Line 4675  sub print_defaults { Line 8409  sub print_defaults {
                           '<td><span class="LC_nobreak">'.$titles->{$item}.                            '<td><span class="LC_nobreak">'.$titles->{$item}.
                           '</span></td><td class="LC_right_item" colspan="3">';                            '</span></td><td class="LC_right_item" colspan="3">';
             if ($item eq 'auth_def') {              if ($item eq 'auth_def') {
                 my @authtypes = ('internal','krb4','krb5','localauth');                  my @authtypes = ('internal','krb4','krb5','localauth','lti');
                 my %shortauth = (                  my %shortauth = (
                                  internal => 'int',                                   internal => 'int',
                                  krb4 => 'krb4',                                   krb4 => 'krb4',
                                  krb5 => 'krb5',                                   krb5 => 'krb5',
                                  localauth  => 'loc'                                   localauth  => 'loc',
                                    lti => 'lti',
                                 );                                  );
                 my %authnames = &authtype_names();                  my %authnames = &authtype_names();
                 foreach my $auth (@authtypes) {                  foreach my $auth (@authtypes) {
Line 4699  sub print_defaults { Line 8434  sub print_defaults {
                 my $includeempty = 1;                  my $includeempty = 1;
                 $datatable .= &Apache::loncommon::select_datelocale($item,$defaults{$item},undef,$includeempty);                  $datatable .= &Apache::loncommon::select_datelocale($item,$defaults{$item},undef,$includeempty);
             } elsif ($item eq 'lang_def') {              } elsif ($item eq 'lang_def') {
                 my %langchoices = &get_languages_hash();                  my $includeempty = 1;
                 $langchoices{''} = 'No language preference';                  $datatable .= &Apache::loncommon::select_language($item,$defaults{$item},$includeempty);
                 %langchoices = &Apache::lonlocal::texthash(%langchoices);  
                 $datatable .= &Apache::loncommon::select_form($defaults{$item},$item,  
                                                               \%langchoices);  
             } else {              } else {
                 my $size;                  my $size;
                 if ($item eq 'portal_def') {                  if ($item eq 'portal_def') {
Line 4716  sub print_defaults { Line 8448  sub print_defaults {
             $rownum ++;              $rownum ++;
         }          }
     } else {      } else {
         my (%defaults);          my %defaults;
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH') &&              if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {
                 (ref($settings->{'inststatusguest'}) eq 'ARRAY')) {  
                 my $maxnum = @{$settings->{'inststatusorder'}};                  my $maxnum = @{$settings->{'inststatusorder'}};
                 for (my $i=0; $i<$maxnum; $i++) {                  for (my $i=0; $i<$maxnum; $i++) {
                     $css_class = $rownum%2?' class="LC_odd_row"':'';                      $css_class = $rownum%2?' class="LC_odd_row"':'';
                     my $item = $settings->{'inststatusorder'}->[$i];                      my $item = $settings->{'inststatusorder'}->[$i];
                     my $title = $settings->{'inststatustypes'}->{$item};                      my $title = $settings->{'inststatustypes'}->{$item};
                     my $guestok;  
                     if (grep(/^\Q$item\E$/,@{$settings->{'inststatusguest'}})) {  
                         $guestok = 1;  
                     }  
                     my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'$item'".');"';                      my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'$item'".');"';
                     $datatable .= '<tr'.$css_class.'>'.                      $datatable .= '<tr'.$css_class.'>'.
                                   '<td><span class="LC_nobreak">'.                                    '<td><span class="LC_nobreak">'.
Line 4741  sub print_defaults { Line 8468  sub print_defaults {
                         }                          }
                         $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';                          $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
                     }                      }
                     my ($checkedon,$checkedoff);  
                     $checkedoff = ' checked="checked"';  
                     if ($guestok) {  
                         $checkedon = $checkedoff;  
                         $checkedoff = '';   
                     }  
                     $datatable .= '</select>&nbsp;'.&mt('Internal ID:').'&nbsp;<b>'.$item.'</b>&nbsp;'.                      $datatable .= '</select>&nbsp;'.&mt('Internal ID:').'&nbsp;<b>'.$item.'</b>&nbsp;'.
                                   '<input type="checkbox" name="inststatus_delete" value="'.$item.'" />'.                                    '<input type="checkbox" name="inststatus_delete" value="'.$item.'" />'.
                                   &mt('delete').'</span></td>'.                                    &mt('delete').'</span></td>'.
                                   '<td class="LC_left_item"><span class="LC_nobreak">'.&mt('Name displayed:').                                    '<td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.&mt('Name displayed:').
                                   '<input type="text" size="20" name="inststatus_title_'.$item.'" value="'.$title.'" />'.                                    '<input type="text" size="20" name="inststatus_title_'.$item.'" value="'.$title.'" />'.
                                   '</span></td>'.                                    '</span></td></tr>';
                                   '<td class="LC_right_item"><span class="LC_nobreak">'.  
                                   '<label><input type="radio" value="1" name="inststatus_guest_'.$item.'"'.$checkedon.' />'.  
                                   &mt('Yes').'</label>'.('&nbsp;'x2).  
                                   '<label><input type="radio" value="0" name="inststatus_guest_'.$item.'"'.$checkedoff.' />'.  
                                   &mt('No').'</label></span></td></tr>';  
                 }                  }
                 $css_class = $rownum%2?' class="LC_odd_row"':'';                  $css_class = $rownum%2?' class="LC_odd_row"':'';
                 my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'addinststatus_pos'".');"';                  my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'addinststatus_pos'".');"';
Line 4772  sub print_defaults { Line 8488  sub print_defaults {
                     $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';                      $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
                 }                  }
                 $datatable .= '</select>&nbsp;'.&mt('Internal ID:').                  $datatable .= '</select>&nbsp;'.&mt('Internal ID:').
                               '<input type="text" size="10" name="addinststatus" value="" /></span>'.                                '<input type="text" size="10" name="addinststatus" value="" />'.
                               '&nbsp;'.&mt('(new)').                                '&nbsp;'.&mt('(new)').
                               '</span></td><td class="LC_left_item"><span class="LC_nobreak">'.                                '</span></td><td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.
                               &mt('Name displayed:').                                &mt('Name displayed:').
                               '<input type="text" size="20" name="addinststatus_title" value="" /></span></td>'.                                '<input type="text" size="20" name="addinststatus_title" value="" /></span></td>'.
                               '<td class="LC_right_item"><span class="LC_nobreak">'.  
                               '<label><input type="radio" value="1" name="addinststatus_guest" />'.  
                               &mt('Yes').'</label>'.('&nbsp;'x2).  
                               '<label><input type="radio" value="0" name="addinststatus_guest" />'.  
                               &mt('No').'</label></span></td></tr>';  
                               '</tr>'."\n";                                '</tr>'."\n";
                 $rownum ++;                  $rownum ++;
             }              }
Line 4811  sub defaults_titles { Line 8522  sub defaults_titles {
                    'timezone_def'  => 'Default timezone',                     'timezone_def'  => 'Default timezone',
                    'datelocale_def' => 'Default locale for dates',                     'datelocale_def' => 'Default locale for dates',
                    'portal_def'     => 'Portal/Default URL',                     'portal_def'     => 'Portal/Default URL',
                      'intauth_cost'   => 'Encryption cost for bcrypt (positive integer)',
                      'intauth_check'  => 'Check bcrypt cost if authenticated',
                      'intauth_switch' => 'Existing crypt-based switched to bcrypt on authentication',
                  );                   );
     if ($dom) {      if ($dom) {
         my $uprimary_id = &Apache::lonnet::domain($dom,'primary');          my $uprimary_id = &Apache::lonnet::domain($dom,'primary');
Line 4825  sub defaults_titles { Line 8539  sub defaults_titles {
     return (\%titles);      return (\%titles);
 }  }
   
   sub print_scantron {
       my ($r,$position,$dom,$confname,$settings,$rowtotal) = @_;
       if ($position eq 'top') {
           return &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal);
       } else {
           return &print_scantronconfig($dom,$settings,\$rowtotal);
       }
   }
   
   sub scantron_javascript {
       return <<"ENDSCRIPT";
   
   <script type="text/javascript">
   // <![CDATA[
   
   function toggleScantron(form) {
       var csvfieldset = new Array();
       if (document.getElementById('scantroncsv_cols')) {
           csvfieldset.push(document.getElementById('scantroncsv_cols'));
       }
       if (document.getElementById('scantroncsv_options')) {
           csvfieldset.push(document.getElementById('scantroncsv_options'));
       }
       if (csvfieldset.length) {
           if (document.getElementById('scantronconfcsv')) {
               var scantroncsv = document.getElementById('scantronconfcsv');
               if (scantroncsv.checked) {
                   for (var i=0; i<csvfieldset.length; i++) {
                       csvfieldset[i].style.display = 'block';
                   }
               } else {
                   for (var i=0; i<csvfieldset.length; i++) {
                       csvfieldset[i].style.display = 'none';
                   }
                   var csvselects = document.getElementsByClassName('scantronconfig_csv');
                   if (csvselects.length) {
                       for (var j=0; j<csvselects.length; j++) {
                           csvselects[j].selectedIndex = 0;
                       }
                   }
               }
           }
       }
       return;
   }
   // ]]>
   </script>
   
   ENDSCRIPT
   
   }
   
 sub print_scantronformat {  sub print_scantronformat {
     my ($r,$dom,$confname,$settings,$rowtotal) = @_;      my ($r,$dom,$confname,$settings,$rowtotal) = @_;
     my $itemcount = 1;      my $itemcount = 1;
Line 4851  sub print_scantronformat { Line 8617  sub print_scantronformat {
             if ($configuserok eq 'ok') {              if ($configuserok eq 'ok') {
                 if ($author_ok eq 'ok') {                  if ($author_ok eq 'ok') {
                     my %legacyfile = (                      my %legacyfile = (
  default => $Apache::lonnet::perlvar{'lonTabDir'}.'/default_scantronformat.tab',    default => $Apache::lonnet::perlvar{'lonTabDir'}.'/default_scantronformat.tab',
  custom  => $Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab',    custom  => $Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab',
                     );                      );
                     my %md5chk;                      my %md5chk;
                     foreach my $type (keys(%legacyfile)) {                      foreach my $type (keys(%legacyfile)) {
Line 4861  sub print_scantronformat { Line 8627  sub print_scantronformat {
                     }                      }
                     if ($md5chk{'default'} ne $md5chk{'custom'}) {                      if ($md5chk{'default'} ne $md5chk{'custom'}) {
                         foreach my $type (keys(%legacyfile)) {                          foreach my $type (keys(%legacyfile)) {
                             ($scantronurls{$type},my $error) =                               ($scantronurls{$type},my $error) =
                                 &legacy_scantronformat($r,$dom,$confname,                                  &legacy_scantronformat($r,$dom,$confname,
                                                  $type,$legacyfile{$type},                                                   $type,$legacyfile{$type},
                                                  $scantronurls{$type},                                                   $scantronurls{$type},
Line 4872  sub print_scantronformat { Line 8638  sub print_scantronformat {
                         }                          }
                         if (keys(%error) == 0) {                          if (keys(%error) == 0) {
                             $is_custom = 1;                              $is_custom = 1;
                             $confhash{'scantron'}{'scantronformat'} =                               $confhash{'scantron'}{'scantronformat'} =
                                 $scantronurls{'custom'};                                  $scantronurls{'custom'};
                             my $putresult =                               my $putresult =
                                 &Apache::lonnet::put_dom('configuration',                                  &Apache::lonnet::put_dom('configuration',
                                                          \%confhash,$dom);                                                           \%confhash,$dom);
                             if ($putresult ne 'ok') {                              if ($putresult ne 'ok') {
                                 $error{'custom'} =                                   $error{'custom'} =
                                     '<span class="LC_error">'.                                      '<span class="LC_error">'.
                                     &mt('An error occurred updating the domain configuration: [_1]',$putresult).'</span>';                                      &mt('An error occurred updating the domain configuration: [_1]',$putresult).'</span>';
                             }                              }
Line 4941  sub print_scantronformat { Line 8707  sub print_scantronformat {
         }          }
         $datatable .= '</span></td>';          $datatable .= '</span></td>';
         if (keys(%error) == 0) {           if (keys(%error) == 0) { 
             $datatable .= '<td valign="bottom">';              $datatable .= '<td style="vertical-align: bottom">';
             if (!$switchserver) {              if (!$switchserver) {
                 $datatable .= &mt('Upload:').'<br />';                  $datatable .= &mt('Upload:').'<br />';
             }              }
Line 4998  sub legacy_scantronformat { Line 8764  sub legacy_scantronformat {
     return ($url,$error);      return ($url,$error);
 }  }
   
   sub print_scantronconfig {
       my ($dom,$settings,$rowtotal) = @_;
       my $itemcount = 2;
       my $is_checked = ' checked="checked"';
       my %optionson = (
                        hdr => ' checked="checked"',
                        pad => ' checked="checked"',
                        rem => ' checked="checked"',
                       );
       my %optionsoff = (
                         hdr => '',
                         pad => '',
                         rem => '',
                        );
       my $currcsvsty = 'none';
       my ($datatable,%csvfields,%checked,%onclick,%csvoptions);
       my @fields = &scantroncsv_fields();
       my %titles = &scantronconfig_titles();
       if (ref($settings) eq 'HASH') {
           if (ref($settings->{config}) eq 'HASH') {
               if ($settings->{config}->{dat}) {
                   $checked{'dat'} = $is_checked;
               }
               if (ref($settings->{config}->{csv}) eq 'HASH') {
                   if (ref($settings->{config}->{csv}->{fields}) eq 'HASH') {
                       %csvfields = %{$settings->{config}->{csv}->{fields}};
                       if (keys(%csvfields) > 0) {
                           $checked{'csv'} = $is_checked;
                           $currcsvsty = 'block';
                       }
                   }
                   if (ref($settings->{config}->{csv}->{options}) eq 'HASH') {
                       %csvoptions = %{$settings->{config}->{csv}->{options}};
                       foreach my $option (keys(%optionson)) {
                           unless ($csvoptions{$option}) {
                               $optionsoff{$option} = $optionson{$option};
                               $optionson{$option} = '';
                           }
                       }
                   }
               }
           } else {
               $checked{'dat'} = $is_checked;
           }
       } else {
           $checked{'dat'} = $is_checked;
       }
       $onclick{'csv'} = ' onclick="toggleScantron(this.form);"';
       my $css_class = $itemcount%2? ' class="LC_odd_row"':'';
       $datatable = '<tr '.$css_class.'><td>'.&mt('Supported formats').'</td>'.
                    '<td class="LC_left_item" valign="top"><span class="LC_nobreak">';
       foreach my $item ('dat','csv') {
           my $id;
           if ($item eq 'csv') {
               $id = 'id="scantronconfcsv" ';
           }
           $datatable .= '<label><input type="checkbox" name="scantronconfig" '.$id.'value="'.$item.'"'.$checked{$item}.$onclick{$item}.' />'.
                         $titles{$item}.'</label>'.('&nbsp;'x3);
           if ($item eq 'csv') {
               $datatable .= '<fieldset style="display:'.$currcsvsty.'" id="scantroncsv_cols">'.
                             '<legend>'.&mt('CSV Column Mapping').'</legend>'.
                             '<table><tr><th>'.&mt('Field').'</th><th>'.&mt('Location').'</th></tr>'."\n";
               foreach my $col (@fields) {
                   my $selnone;
                   if ($csvfields{$col} eq '') {
                       $selnone = ' selected="selected"';
                   }
                   $datatable .= '<tr><td>'.$titles{$col}.'</td>'.
                                 '<td><select name="scantronconfig_csv_'.$col.'" class="scantronconfig_csv">'.
                                 '<option value=""'.$selnone.'></option>';
                   for (my $i=0; $i<20; $i++) {
                       my $shown = $i+1;
                       my $sel;
                       unless ($selnone) {
                           if (exists($csvfields{$col})) {
                               if ($csvfields{$col} == $i) {
                                   $sel = ' selected="selected"';
                               }
                           }
                       }
                       $datatable .= '<option value="'.$i.'"'.$sel.'>'.$shown.'</option>';
                   }
                   $datatable .= '</select></td></tr>';
              }
              $datatable .= '</table></fieldset>'.
                            '<fieldset style="display:'.$currcsvsty.'" id="scantroncsv_options">'.
                            '<legend>'.&mt('CSV Options').'</legend>';
              foreach my $option ('hdr','pad','rem') {
                  $datatable .= '<span class="LC_nobreak">'.$titles{$option}.':'.
                            '<label><input type="radio" name="scantroncsv_'.$option.'" value="1"'.$optionson{$option}.' />'.
                            &mt('Yes').'</label>'.('&nbsp;'x2)."\n".
                            '<label><input type="radio" name="scantroncsv_'.$option.'" value="0"'.$optionsoff{$option}.' />'.&mt('No').'</label></span><br />';
              }
              $datatable .= '</fieldset>';
              $itemcount ++;
           }
       }
       $datatable .= '</td></tr>';
       $$rowtotal ++;
       return $datatable;
   }
   
   sub scantronconfig_titles {
       return &Apache::lonlocal::texthash(
                                             dat => 'Standard format (.dat)',
                                             csv => 'Comma separated values (.csv)',
                                             hdr => 'Remove first line in file (contains column titles)',
                                             pad => 'Prepend 0s to PaperID',
                                             rem => 'Remove leading spaces (except Question Response columns)',
                                             CODE => 'CODE',
                                             ID   => 'Student ID',
                                             PaperID => 'Paper ID',
                                             FirstName => 'First Name',
                                             LastName => 'Last Name',
                                             FirstQuestion => 'First Question Response',
                                             Section => 'Section',
       );
   }
   
   sub scantroncsv_fields {
       return ('PaperID','LastName','FirstName','ID','Section','CODE','FirstQuestion');
   }
   
 sub print_coursecategories {  sub print_coursecategories {
     my ($position,$dom,$hdritem,$settings,$rowtotal) = @_;      my ($position,$dom,$hdritem,$settings,$rowtotal) = @_;
     my $datatable;      my $datatable;
Line 5040  sub print_coursecategories { Line 8929  sub print_coursecategories {
                              '<input type="radio" name="coursecat_'.$item.'" value="'.$type.'"'.$ischecked.                               '<input type="radio" name="coursecat_'.$item.'" value="'.$type.'"'.$ischecked.
                              ' />'.$lt{$type}.'</label>&nbsp;';                               ' />'.$lt{$type}.'</label>&nbsp;';
            }             }
            $datatable .= '</td></tr>';             $datatable .= '</span></td></tr>';
            $itemcount ++;             $itemcount ++;
         }          }
         $$rowtotal += $itemcount;          $$rowtotal += $itemcount;
Line 5053  sub print_coursecategories { Line 8942  sub print_coursecategories {
         my $toggle_catscomm_dom = ' checked="checked" ';          my $toggle_catscomm_dom = ' checked="checked" ';
         my $can_catcomm_comm = ' ';          my $can_catcomm_comm = ' ';
         my $can_catcomm_dom = ' checked="checked" ';          my $can_catcomm_dom = ' checked="checked" ';
           my $toggle_catsplace_place = ' ';
           my $toggle_catsplace_dom = ' checked="checked" ';
           my $can_catplace_place = ' ';
           my $can_catplace_dom = ' checked="checked" ';
   
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ($settings->{'togglecats'} eq 'crs') {              if ($settings->{'togglecats'} eq 'crs') {
Line 5071  sub print_coursecategories { Line 8964  sub print_coursecategories {
                 $can_catcomm_comm = $can_catcomm_dom;                  $can_catcomm_comm = $can_catcomm_dom;
                 $can_catcomm_dom = ' ';                  $can_catcomm_dom = ' ';
             }              }
               if ($settings->{'togglecatsplace'} eq 'place') {
                   $toggle_catsplace_place = $toggle_catsplace_dom;
                   $toggle_catsplace_dom = ' ';
               }
               if ($settings->{'categorizeplace'} eq 'place') {
                   $can_catplace_place = $can_catplace_dom;
                   $can_catplace_dom = ' ';
               }
         }          }
         my %title = &Apache::lonlocal::texthash (          my %title = &Apache::lonlocal::texthash (
                      togglecats     => 'Show/Hide a course in catalog',                       togglecats      => 'Show/Hide a course in catalog',
                      togglecatscomm => 'Show/Hide a community in catalog',                       togglecatscomm  => 'Show/Hide a community in catalog',
                      categorize     => 'Assign a category to a course',                       togglecatsplace => 'Show/Hide a placement test in catalog',
                      categorizecomm => 'Assign a category to a community',                       categorize      => 'Assign a category to a course',
                        categorizecomm  => 'Assign a category to a community',
                        categorizeplace => 'Assign a category to a placement test',
                     );                      );
         my %level = &Apache::lonlocal::texthash (          my %level = &Apache::lonlocal::texthash (
                      dom  => 'Set in Domain',                       dom   => 'Set in Domain',
                      crs  => 'Set in Course',                       crs   => 'Set in Course',
                      comm => 'Set in Community',                       comm  => 'Set in Community',
                        place => 'Set in Placement Test',
                     );                      );
         $datatable = '<tr class="LC_odd_row">'.          $datatable = '<tr class="LC_odd_row">'.
                   '<td>'.$title{'togglecats'}.'</td>'.                    '<td>'.$title{'togglecats'}.'</td>'.
Line 5111  sub print_coursecategories { Line 9015  sub print_coursecategories {
                   $can_catcomm_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.                    $can_catcomm_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.
                   '<label><input type="radio" name="categorizecomm"'.                    '<label><input type="radio" name="categorizecomm"'.
                   $can_catcomm_comm.'value="comm" />'.$level{'comm'}.'</label></span></td>'.                    $can_catcomm_comm.'value="comm" />'.$level{'comm'}.'</label></span></td>'.
                     '</tr><tr class="LC_odd_row">'.
                     '<td>'.$title{'togglecatsplace'}.'</td>'.
                     '<td class="LC_right_item"><span class="LC_nobreak"><label>'.
                     '<input type="radio" name="togglecatsplace"'.
                     $toggle_catsplace_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.
                     '<label><input type="radio" name="togglecatscomm"'.
                     $toggle_catsplace_place.' value="comm" />'.$level{'place'}.'</label></span></td>'.
                     '</tr><tr>'.
                     '<td>'.$title{'categorizeplace'}.'</td>'.
                     '<td class="LC_right_item"><span class="LC_nobreak">'.
                     '<label><input type="radio" name="categorizeplace"'.
                     $can_catplace_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.
                     '<label><input type="radio" name="categorizeplace"'.
                     $can_catplace_place.'value="place" />'.$level{'place'}.'</label></span></td>'.
                   '</tr>';                    '</tr>';
         $$rowtotal += 4;          $$rowtotal += 6;
     } else {      } else {
         my $css_class;          my $css_class;
         my $itemcount = 1;          my $itemcount = 1;
Line 5137  sub print_coursecategories { Line 9055  sub print_coursecategories {
                     my %default_names = (                      my %default_names = (
                           instcode    => &mt('Official courses'),                            instcode    => &mt('Official courses'),
                           communities => &mt('Communities'),                            communities => &mt('Communities'),
                             placement   => &mt('Placement Tests'),
                     );                      );
   
                     if ((!grep(/^instcode$/,@{$cats[0]})) ||                       if ((!grep(/^instcode$/,@{$cats[0]})) || 
                         ($cathash->{'instcode::0'} eq '') ||                          ($cathash->{'instcode::0'} eq '') ||
                         (!grep(/^communities$/,@{$cats[0]})) ||                           (!grep(/^communities$/,@{$cats[0]})) || 
                         ($cathash->{'communities::0'} eq '')) {                          ($cathash->{'communities::0'} eq '') ||
                           (!grep(/^placement$/,@{$cats[0]})) ||
                           ($cathash->{'placement::0'} eq '')) {
                         $maxnum ++;                          $maxnum ++;
                     }                      }
                     my $lastidx;                      my $lastidx;
Line 5163  sub print_coursecategories { Line 9084  sub print_coursecategories {
                             $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';                              $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
                         }                          }
                         $datatable .= '</select></span></td><td>';                          $datatable .= '</select></span></td><td>';
                         if ($parent eq 'instcode' || $parent eq 'communities') {                          if ($parent eq 'instcode' || $parent eq 'communities' || $parent eq 'placement') {
                             $datatable .=  '<span class="LC_nobreak">'                              $datatable .=  '<span class="LC_nobreak">'
                                            .$default_names{$parent}.'</span>';                                             .$default_names{$parent}.'</span>';
                             if ($parent eq 'instcode') {                              if ($parent eq 'instcode') {
Line 5186  sub print_coursecategories { Line 9107  sub print_coursecategories {
                             $datatable .= '<label><input type="radio" name="'                              $datatable .= '<label><input type="radio" name="'
                                           .$parent.'" value="0" />'                                            .$parent.'" value="0" />'
                                           .&mt('Do not display').'</label></span>';                                            .&mt('Do not display').'</label></span>';
                             if ($parent eq 'communities') {                              if (($parent eq 'communities') || ($parent eq 'placement')) {
                                 $datatable .= '</td></tr></table>';                                  $datatable .= '</td></tr></table>';
                             }                              }
                             $datatable .= '</td>';                              $datatable .= '</td>';
Line 5218  sub print_coursecategories { Line 9139  sub print_coursecategories {
                                   .'<input type="text" size="20" name="addcategory_name" value="" /></td>'                                    .'<input type="text" size="20" name="addcategory_name" value="" /></td>'
                                   .'</tr>'."\n";                                    .'</tr>'."\n";
                     $itemcount ++;                      $itemcount ++;
                     foreach my $default ('instcode','communities') {                      foreach my $default ('instcode','communities','placement') {
                         if ((!grep(/^\Q$default\E$/,@{$cats[0]})) || ($cathash->{$default.'::0'} eq '')) {                          if ((!grep(/^\Q$default\E$/,@{$cats[0]})) || ($cathash->{$default.'::0'} eq '')) {
                             $css_class = $itemcount%2?' class="LC_odd_row"':'';                              $css_class = $itemcount%2?' class="LC_odd_row"':'';
                             my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','$lastidx'".');"';                              my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','$lastidx'".');"';
Line 5251  sub print_coursecategories { Line 9172  sub print_coursecategories {
                 $datatable .= &initialize_categories($itemcount);                  $datatable .= &initialize_categories($itemcount);
             }              }
         } else {          } else {
             $datatable .= '<td class="LC_right_item">'.$hdritem->{'header'}->[1]->{'col2'}.'</td>'              $datatable .= '<tr><td class="LC_right_item">'.$hdritem->{'header'}->[1]->{'col2'}.'</td></tr>'
                           .&initialize_categories($itemcount);                            .&initialize_categories($itemcount);
         }          }
         $$rowtotal += $itemcount;          $$rowtotal += $itemcount;
Line 5299  sub print_serverstatuses { Line 9220  sub print_serverstatuses {
                       '<span class="LC_nobreak">'.                        '<span class="LC_nobreak">'.
                       '<input type="text" name="'.$type.'_machines" '.                        '<input type="text" name="'.$type.'_machines" '.
                       'value="'.$machineaccess{$type}.'" size="10" />'.                        'value="'.$machineaccess{$type}.'" size="10" />'.
                       '</td></tr>'."\n";                        '</span></td></tr>'."\n";
     }      }
     $$rowtotal += $rownum;      $$rowtotal += $rownum;
     return $datatable;      return $datatable;
Line 5307  sub print_serverstatuses { Line 9228  sub print_serverstatuses {
   
 sub serverstatus_pages {  sub serverstatus_pages {
     return ('userstatus','lonstatus','loncron','server-status','codeversions',      return ('userstatus','lonstatus','loncron','server-status','codeversions',
             'checksums','clusterstatus','metadata_keywords','metadata_harvest',              'checksums','clusterstatus','certstatus','metadata_keywords',
             'takeoffline','takeonline','showenv','toggledebug','ping','domconf',              'metadata_harvest','takeoffline','takeonline','showenv','toggledebug',
             'uniquecodes','diskusage');              'ping','domconf','uniquecodes','diskusage','coursecatalog');
 }  }
   
 sub defaults_javascript {  sub defaults_javascript {
     my ($settings) = @_;      my ($settings) = @_;
     return unless (ref($settings) eq 'HASH');       return unless (ref($settings) eq 'HASH');
     if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {      if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {
         my $maxnum = scalar(@{$settings->{'inststatusorder'}});          my $maxnum = scalar(@{$settings->{'inststatusorder'}});
         if ($maxnum eq '') {          if ($maxnum eq '') {
Line 5373  $jstext Line 9294  $jstext
   
 ENDSCRIPT  ENDSCRIPT
     }      }
       return;
   }
   
   sub passwords_javascript {
       my %intalert = &Apache::lonlocal::texthash (
           authcheck => 'Warning: disallowing login for an authenticated user if the stored cost is less than the default will require a password reset by/for the user.',
           authcost => 'Warning: bcrypt encryption cost for internal authentication must be an integer.',
           passmin => 'Warning: minimum password length must be a positive integer greater than 6.',
           passmax => 'Warning: maximum password length must be a positive integer (or blank).',
           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).',
       );
       &js_escape(\%intalert);
       my $defmin = $Apache::lonnet::passwdmin;
       my $intauthjs = <<"ENDSCRIPT";
   
   function warnIntAuth(field) {
       if (field.name == 'intauth_check') {
           if (field.value == '2') {
               alert('$intalert{authcheck}');
           }
       }
       if (field.name == 'intauth_cost') {
           field.value.replace(/\s/g,'');
           if (field.value != '') {
               var regexdigit=/^\\d+\$/;
               if (!regexdigit.test(field.value)) {
                   alert('$intalert{authcost}');
               }
           }
       }
       return;
   }
   
   function warnIntPass(field) {
       field.value.replace(/^\s+/,'');
       field.value.replace(/\s+\$/,'');
       var regexdigit=/^\\d+\$/;
       if (field.name == 'passwords_min') {
           if (field.value == '') {
               alert('$intalert{passmin}');
               field.value = '$defmin';
           } else {
               if (!regexdigit.test(field.value)) {
                   alert('$intalert{passmin}');
                   field.value = '$defmin';
               }
               var minval = parseInt(field.value,10);
               if (minval < $defmin) {
                   alert('$intalert{passmin}');
                   field.value = '$defmin';
               }
           }
       } else {
           if (field.value == '0') {
               field.value = '';
           }
           if (field.value != '') {
               if (field.name == 'passwords_expire') {
                   var regexpposnum=/^\\d+(|\\.\\d*)\$/; 
                   if (!regexpposnum.test(field.value)) {
                       alert('$intalert{passexp}');
                       field.value = '';
                   } else {
                       var expval = parseFloat(field.value);
                       if (expval == 0) {
                           alert('$intalert{passexp}');
                           field.value = '';
                       }
                   }
               } else {
                   if (!regexdigit.test(field.value)) {
                       if (field.name == 'passwords_max') {
                           alert('$intalert{passmax}');
                       } else {
                           if (field.name == 'passwords_numsaved') {
                               alert('$intalert{passnum}');
                           }
                       }
                   }
                   field.value = '';
               }
           }
       }
       return;
   }
   
   ENDSCRIPT
       return &Apache::lonhtmlcommon::scripttag($intauthjs);
 }  }
   
 sub coursecategories_javascript {  sub coursecategories_javascript {
Line 5399  sub coursecategories_javascript { Line 9409  sub coursecategories_javascript {
     }      }
     my $instcode_reserved = &mt('The name: [_1] is a reserved category.','"instcode"');      my $instcode_reserved = &mt('The name: [_1] is a reserved category.','"instcode"');
     my $communities_reserved = &mt('The name: [_1] is a reserved category.','"communities"');      my $communities_reserved = &mt('The name: [_1] is a reserved category.','"communities"');
     my $choose_again = '\\n'.&mt('Please use a different name for the new top level category.');       my $placement_reserved = &mt('The name: [_1] is a reserved category.','"placement"');
       my $choose_again = "\n".&mt('Please use a different name for the new top level category.'); 
       &js_escape(\$instcode_reserved);
       &js_escape(\$communities_reserved);
       &js_escape(\$placement_reserved);
       &js_escape(\$choose_again);
     $output = <<"ENDSCRIPT";      $output = <<"ENDSCRIPT";
 <script type="text/javascript">  <script type="text/javascript">
 // <![CDATA[  // <![CDATA[
Line 5468  function categoryCheck(form) { Line 9483  function categoryCheck(form) {
         alert('$communities_reserved\\n$choose_again');          alert('$communities_reserved\\n$choose_again');
         return false;          return false;
     }      }
       if (form.elements['addcategory_name'].value == 'placement') {
           alert('$placement_reserved\\n$choose_again');
           return false;
       }
     return true;      return true;
 }  }
   
Line 5484  sub initialize_categories { Line 9503  sub initialize_categories {
     my %default_names = (      my %default_names = (
                       instcode    => 'Official courses (with institutional codes)',                        instcode    => 'Official courses (with institutional codes)',
                       communities => 'Communities',                        communities => 'Communities',
                         placement   => 'Placement Tests',
                         );                          );
     my $select0 = ' selected="selected"';      my %selnum = (
     my $select1 = '';                     instcode    => '0',
     foreach my $default ('instcode','communities') {                     communities => '1',
                      placement   => '2',
                    );
       my %selected;
       foreach my $default ('instcode','communities','placement') {
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $chgstr = ' onchange="javascript:reorderCats(this.form,'."'',$default"."_pos','0'".');"';          $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','0'".');"';
         if ($default eq 'communities') {          map { $selected{$selnum{$_}} = '' } keys(%selnum);
             $select1 = $select0;          $selected{$selnum{$default}} = ' selected="selected"';
             $select0 = '';  
         }  
         $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'          $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
                      .'<select name="'.$default.'_pos">'                       .'<select name="'.$default.'_pos"'.$chgstr.'>'
                      .'<option value="0"'.$select0.'>1</option>'                       .'<option value="0"'.$selected{'0'}.'>1</option>'
                      .'<option value="1"'.$select1.'>2</option>'                       .'<option value="1"'.$selected{'1'}.'>2</option>'
                      .'<option value="2">3</option></select>&nbsp;'                       .'<option value="2"'.$selected{'2'}.'>3</option>'
                        .'<option value="3">4</option></select>&nbsp;'
                      .$default_names{$default}                       .$default_names{$default}
                      .'</span></td><td><span class="LC_nobreak">'                       .'</span></td><td><span class="LC_nobreak">'
                      .'<label><input type="radio" name="'.$default.'" value="1" checked="checked" />'                       .'<label><input type="radio" name="'.$default.'" value="1" checked="checked" />'
Line 5513  sub initialize_categories { Line 9536  sub initialize_categories {
                   .'<select name="addcategory_pos"'.$chgstr.'>'                    .'<select name="addcategory_pos"'.$chgstr.'>'
                   .'<option value="0">1</option>'                    .'<option value="0">1</option>'
                   .'<option value="1">2</option>'                    .'<option value="1">2</option>'
                   .'<option value="2" selected="selected">3</option></select>&nbsp;'                    .'<option value="2">3</option>'
                   .&mt('Add category').'</td><td>'.&mt('Name:')                    .'<option value="3" selected="selected">4</option></select>&nbsp;'
                   .'&nbsp;<input type="text" size="20" name="addcategory_name" value="" /></td></tr>';                    .&mt('Add category').'</span></td><td><span class="LC_nobreak">'.&mt('Name:')
                     .'&nbsp;<input type="text" size="20" name="addcategory_name" value="" /></span>'
                     .'</td></tr>';
     return $datatable;      return $datatable;
 }  }
   
Line 5570  sub build_category_rows { Line 9595  sub build_category_rows {
                             pop(@{$path});                              pop(@{$path});
                         }                          }
                     } else {                      } else {
                         $text .= &mt('Add subcategory:').'&nbsp;</span><input type="textbox" size="20" name="addcategory_name_';                          $text .= &mt('Add subcategory:').'&nbsp;</span><input type="text" size="20" name="addcategory_name_';
                         if ($j == $numchildren) {                          if ($j == $numchildren) {
                             $text .= $name;                              $text .= $name;
                         } else {                          } else {
Line 5593  sub build_category_rows { Line 9618  sub build_category_rows {
                 my $colspan;                  my $colspan;
                 if ($parent ne 'instcode') {                  if ($parent ne 'instcode') {
                     $colspan = $maxdepth - $depth - 1;                      $colspan = $maxdepth - $depth - 1;
                     $text .= '<td colspan="'.$colspan.'">'.&mt('Add subcategory:').'<input type="textbox" size="20" name="subcat_'.$name.'" value="" /></td>';                      $text .= '<td colspan="'.$colspan.'">'.&mt('Add subcategory:').'<input type="text" size="20" name="subcat_'.$name.'" value="" /></td>';
                 }                  }
             }              }
         }          }
Line 5602  sub build_category_rows { Line 9627  sub build_category_rows {
 }  }
   
 sub modifiable_userdata_row {  sub modifiable_userdata_row {
     my ($context,$item,$settings,$numinrow,$rowcount,$usertypes,$fieldsref,$titlesref) = @_;      my ($context,$item,$settings,$numinrow,$rowcount,$usertypes,$fieldsref,$titlesref,
           $rowid,$customcss,$rowstyle,$itemdesc) = @_;
     my ($role,$rolename,$statustype);      my ($role,$rolename,$statustype);
     $role = $item;      $role = $item;
     if ($context eq 'cancreate') {      if ($context eq 'cancreate') {
         if ($item =~ /^emailusername_(.+)$/) {          if ($item =~ /^(emailusername)_(.+)$/) {
             $statustype = $1;              $role = $1;
             $role = 'emailusername';              $statustype = $2;
             if (ref($usertypes) eq 'HASH') {              if (ref($usertypes) eq 'HASH') {
                 if ($usertypes->{$statustype}) {                  if ($usertypes->{$statustype}) {
                     $rolename = &mt('Data provided by [_1]',$usertypes->{$statustype});                      $rolename = &mt('Data provided by [_1]',$usertypes->{$statustype});
Line 5623  sub modifiable_userdata_row { Line 9649  sub modifiable_userdata_row {
         } else {          } else {
             $rolename = $role;              $rolename = $role;
         }          }
       } elsif ($context eq 'lti') {
           $rolename = &mt('Institutional data used (if available)');
       } elsif ($context eq 'privacy') {
           $rolename = $itemdesc;
     } else {      } else {
         if ($role eq 'cr') {          if ($role eq 'cr') {
             $rolename = &mt('Custom role');              $rolename = &mt('Custom role');
Line 5643  sub modifiable_userdata_row { Line 9673  sub modifiable_userdata_row {
         %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();          %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
     }      }
     my $output;      my $output;
     my $css_class = $rowcount%2?' class="LC_odd_row"':'';      my $css_class;
     $output = '<tr '.$css_class.'>'.      if ($rowcount%2) {
           $css_class = 'LC_odd_row';
       }
       if ($customcss) {
           $css_class .= " $customcss";
       }
       $css_class =~ s/^\s+//;
       if ($css_class) {
           $css_class = ' class="'.$css_class.'"';
       }
       if ($rowstyle) {
           $css_class .= ' style="'.$rowstyle.'"';
       }
       if ($rowid) {
           $rowid = ' id="'.$rowid.'"';
       }
       $output = '<tr '.$css_class.$rowid.'>'.
               '<td><span class="LC_nobreak">'.$rolename.'</span></td>'.                '<td><span class="LC_nobreak">'.$rolename.'</span></td>'.
               '<td class="LC_left_item" colspan="2"><table>';                '<td class="LC_left_item" colspan="2"><table>';
     my $rem;      my $rem;
     my %checks;      my %checks;
       my %current;
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if (ref($settings->{$context}) eq 'HASH') {          my $hashref;
           if ($context eq 'lti') {
               if (ref($settings) eq 'HASH') {
                   $hashref = $settings->{'instdata'};
               }
           } elsif ($context eq 'privacy') {
               my ($key,$inner) = split(/_/,$role);
               if (ref($settings) eq 'HASH') {
                   if (ref($settings->{$key}) eq 'HASH') {
                       $hashref = $settings->{$key}->{$inner};
                   }
               }
           } elsif (ref($settings->{$context}) eq 'HASH') {
             if (ref($settings->{$context}->{$role}) eq 'HASH') {              if (ref($settings->{$context}->{$role}) eq 'HASH') {
                 my $hashref = $settings->{$context}->{$role};                  $hashref = $settings->{'lti_instdata'};
                 if ($role eq 'emailusername') {              }
                     if ($statustype) {              if ($role eq 'emailusername') {
                         if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') {                  if ($statustype) {
                             $hashref = $settings->{$context}->{$role}->{$statustype};                      if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') {
                             if (ref($hashref) eq 'HASH') {                           $hashref = $settings->{$context}->{$role}->{$statustype};
                                 foreach my $field (@fields) {  
                                     if ($hashref->{$field}) {  
                                         $checks{$field} = $hashref->{$field};  
                                     }  
                                 }  
                             }  
                         }  
                     }                      }
                 } else {                  }
                     if (ref($hashref) eq 'HASH') {              }
                         foreach my $field (@fields) {          }
                             if ($hashref->{$field}) {          if (ref($hashref) eq 'HASH') { 
                                 $checks{$field} = ' checked="checked" ';              foreach my $field (@fields) {
                             }                  if ($hashref->{$field}) {
                         }                      if ($role eq 'emailusername') {
                           $checks{$field} = $hashref->{$field};
                       } else {
                           $checks{$field} = ' checked="checked" ';
                     }                      }
                 }                  }
             }              }
         }          }
     }      }
         
     for (my $i=0; $i<@fields; $i++) {      my $total = scalar(@fields);
         my $rem = $i%($numinrow);      for (my $i=0; $i<$total; $i++) {
           $rem = $i%($numinrow);
         if ($rem == 0) {          if ($rem == 0) {
             if ($i > 0) {              if ($i > 0) {
                 $output .= '</tr>';                  $output .= '</tr>';
Line 5690  sub modifiable_userdata_row { Line 9746  sub modifiable_userdata_row {
         my $check = ' ';          my $check = ' ';
         unless ($role eq 'emailusername') {          unless ($role eq 'emailusername') {
             if (exists($checks{$fields[$i]})) {              if (exists($checks{$fields[$i]})) {
                 $check = $checks{$fields[$i]}                  $check = $checks{$fields[$i]};
             } else {              } elsif ($context eq 'privacy') {
                   if ($role =~ /^priv_(domain|course)$/) {
                       if (ref($settings) ne 'HASH') {
                           $check = ' checked="checked" ';
                       }
                   } elsif ($role =~ /^priv_(author|community)$/) {
                       if (ref($settings) ne 'HASH') {
                           unless ($fields[$i] eq 'id') {
                               $check = ' checked="checked" ';
                           }
                       }
                   } elsif ($role =~ /^(unpriv|othdom)_/) {
                       if (ref($settings) ne 'HASH') {
                           if (($fields[$i] eq 'lastname') || ($fields[$i] eq 'firstname')) {
                               $check = ' checked="checked" ';
                           }
                       }
                   }
               } elsif ($context ne 'lti') {
                 if ($role eq 'st') {                  if ($role eq 'st') {
                     if (ref($settings) ne 'HASH') {                      if (ref($settings) ne 'HASH') {
                         $check = ' checked="checked" ';                           $check = ' checked="checked" '; 
Line 5701  sub modifiable_userdata_row { Line 9775  sub modifiable_userdata_row {
         }          }
         $output .= '<td class="LC_left_item">'.          $output .= '<td class="LC_left_item">'.
                    '<span class="LC_nobreak">';                     '<span class="LC_nobreak">';
           my $prefix = 'canmodify';
         if ($role eq 'emailusername') {          if ($role eq 'emailusername') {
             unless ($checks{$fields[$i]} =~ /^(required|optional)$/) {              unless ($checks{$fields[$i]} =~ /^(required|optional)$/) {
                 $checks{$fields[$i]} = 'omit';                  $checks{$fields[$i]} = 'omit';
Line 5711  sub modifiable_userdata_row { Line 9786  sub modifiable_userdata_row {
                     $checked='checked="checked" ';                      $checked='checked="checked" ';
                 }                  }
                 $output .= '<label>'.                  $output .= '<label>'.
                            '<input type="radio" name="canmodify_'.$item.'_'.$fields[$i].'" value="'.$option.'" '.$checked.'/>'.                             '<input type="radio" name="'.$prefix.'_'.$item.'_'.$fields[$i].'" value="'.$option.'" '.$checked.'/>'.
                            &mt($option).'</label>'.('&nbsp;' x2);                             &mt($option).'</label>'.('&nbsp;' x2);
             }              }
             $output .= '<i>'.$fieldtitles{$fields[$i]}.'</i>';              $output .= '<i>'.$fieldtitles{$fields[$i]}.'</i>';
         } else {          } else {
               if ($context eq 'lti') {
                   $prefix = 'lti';
               } elsif ($context eq 'privacy') {
                   $prefix = 'privacy';
               }
             $output .= '<label>'.              $output .= '<label>'.
                        '<input type="checkbox" name="canmodify_'.$role.'" '.                         '<input type="checkbox" name="'.$prefix.'_'.$role.'" '.
                        'value="'.$fields[$i].'"'.$check.'/>'.$fieldtitles{$fields[$i]}.                         'value="'.$fields[$i].'"'.$check.'/>'.$fieldtitles{$fields[$i]}.
                        '</label>';                         '</label>';
         }          }
         $output .= '</span></td>';          $output .= '</span></td>';
         $rem = @fields%($numinrow);  
     }      }
     my $colsleft = $numinrow - $rem;      $rem = $total%$numinrow;
     if ($colsleft > 1 ) {      my $colsleft;
       if ($rem) {
           $colsleft = $numinrow - $rem;
       }
       if ($colsleft > 1) {
         $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.          $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
                    '&nbsp;</td>';                     '&nbsp;</td>';
     } elsif ($colsleft == 1) {      } elsif ($colsleft == 1) {
Line 5736  sub modifiable_userdata_row { Line 9819  sub modifiable_userdata_row {
 }  }
   
 sub insttypes_row {  sub insttypes_row {
     my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rownum) = @_;      my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rowtotal,$onclick,
           $customcss,$rowstyle) = @_;
     my %lt = &Apache::lonlocal::texthash (      my %lt = &Apache::lonlocal::texthash (
                       cansearch => 'Users allowed to search',                        cansearch => 'Users allowed to search',
                       statustocreate => 'Institutional affiliation(s) able to create own account (login/SSO)',                        statustocreate => 'Institutional affiliation(s) able to create own account (login/SSO)',
                       lockablenames => 'User preference to lock name',                        lockablenames => 'User preference to lock name',
                         selfassign    => 'Self-reportable affiliations',
                         overrides     => "Override domain's helpdesk settings based on requester's affiliation",
              );               );
     my $showdom;      my $showdom;
     if ($context eq 'cansearch') {      if ($context eq 'cansearch') {
Line 5750  sub insttypes_row { Line 9836  sub insttypes_row {
     if ($context eq 'statustocreate') {      if ($context eq 'statustocreate') {
         $class = 'LC_right_item';          $class = 'LC_right_item';
     }      }
     my $css_class = ' class="LC_odd_row"';      my $css_class;
     if ($rownum ne '') {       if ($$rowtotal%2) {
         $css_class = ($rownum%2? ' class="LC_odd_row"':'');          $css_class = 'LC_odd_row';
       }
       if ($customcss) {
           $css_class .= ' '.$customcss;
       }
       $css_class =~ s/^\s+//;
       if ($css_class) {
           $css_class = ' class="'.$css_class.'"';
       }
       if ($rowstyle) {
           $css_class .= ' style="'.$rowstyle.'"';
       }
       if ($onclick) {
           $onclick = 'onclick="'.$onclick.'" ';
     }      }
     my $output = '<tr'.$css_class.'>'.      my $output = '<tr'.$css_class.'>'.
                  '<td>'.$lt{$context}.$showdom.                   '<td>'.$lt{$context}.$showdom.
Line 5774  sub insttypes_row { Line 9873  sub insttypes_row {
                         if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) {                          if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) {
                             $check = ' checked="checked" ';                              $check = ' checked="checked" ';
                         }                          }
                       } elsif (ref($settings->{$context}) eq 'HASH') {
                           if (ref($settings->{$context}->{$types->[$i]}) eq 'HASH') {
                               $check = ' checked="checked" ';
                           }
                     } elsif ($context eq 'statustocreate') {                      } elsif ($context eq 'statustocreate') {
                         $check = ' checked="checked" ';                          $check = ' checked="checked" ';
                     }                      }
Line 5781  sub insttypes_row { Line 9884  sub insttypes_row {
                 $output .= '<td class="LC_left_item">'.                  $output .= '<td class="LC_left_item">'.
                            '<span class="LC_nobreak"><label>'.                             '<span class="LC_nobreak"><label>'.
                            '<input type="checkbox" name="'.$context.'" '.                             '<input type="checkbox" name="'.$context.'" '.
                            'value="'.$types->[$i].'"'.$check.'/>'.                             'value="'.$types->[$i].'"'.$check.$onclick.' />'.
                            $usertypes->{$types->[$i]}.'</label></span></td>';                             $usertypes->{$types->[$i]}.'</label></span></td>';
             }              }
         }          }
         $rem = @{$types}%($numinrow);          $rem = @{$types}%($numinrow);
     }      }
     my $colsleft = $numinrow - $rem;      my $colsleft = $numinrow - $rem;
     if (($rem == 0) && (@{$types} > 0)) {      if ($context eq 'overrides') {
         $output .= '<tr>';          if ($colsleft > 1) {
     }              $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">';
     if ($colsleft > 1) {          } else {
         $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">';              $output .= '<td class="LC_left_item">';
           }
           $output .= '&nbsp;';  
     } else {      } else {
         $output .= '<td class="LC_left_item">';          if ($rem == 0) {
     }              $output .= '<tr>';
     my $defcheck = ' ';          }
     if (ref($settings) eq 'HASH') {            if ($colsleft > 1) {
         if (ref($settings->{$context}) eq 'ARRAY') {              $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">';
             if (grep(/^default$/,@{$settings->{$context}})) {          } else {
               $output .= '<td class="LC_left_item">';
           }
           my $defcheck = ' ';
           if (ref($settings) eq 'HASH') {  
               if (ref($settings->{$context}) eq 'ARRAY') {
                   if (grep(/^default$/,@{$settings->{$context}})) {
                       $defcheck = ' checked="checked" ';
                   }
               } elsif ($context eq 'statustocreate') {
                 $defcheck = ' checked="checked" ';                  $defcheck = ' checked="checked" ';
             }              }
         } elsif ($context eq 'statustocreate') {  
             $defcheck = ' checked="checked" ';  
         }          }
           $output .= '<span class="LC_nobreak"><label>'.
                      '<input type="checkbox" name="'.$context.'" '.
                      'value="default"'.$defcheck.$onclick.' />'.
                      $othertitle.'</label></span>';
     }      }
     $output .= '<span class="LC_nobreak"><label>'.      $output .= '</td></tr></table></td></tr>';
                '<input type="checkbox" name="'.$context.'" '.  
                'value="default"'.$defcheck.'/>'.  
                $othertitle.'</label></span></td>'.  
                '</tr></table></td></tr>';  
     return $output;      return $output;
 }  }
   
Line 6076  sub modify_login { Line 10188  sub modify_login {
                 if ($domservers{$lonhost}) {                  if ($domservers{$lonhost}) {
                     if (ref($domconfig{'login'}{'headtag'}{$lonhost}) eq 'HASH') {                      if (ref($domconfig{'login'}{'headtag'}{$lonhost}) eq 'HASH') {
                         $currheadtagurls{$lonhost} = $domconfig{'login'}{'headtag'}{$lonhost}{'url'};                          $currheadtagurls{$lonhost} = $domconfig{'login'}{'headtag'}{$lonhost}{'url'};
                         $currexempt{$lonhost} = $domconfig{'login'}{'headtagexempt'}{$lonhost}{'exempt'}                          $currexempt{$lonhost} = $domconfig{'login'}{'headtag'}{$lonhost}{'exempt'};
                     }                      }
                 }                  }
             }              }
Line 6095  sub modify_login { Line 10207  sub modify_login {
             } elsif ($currheadtagurls{$lonhost}) {              } elsif ($currheadtagurls{$lonhost}) {
                 $loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $currheadtagurls{$lonhost};                  $loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $currheadtagurls{$lonhost};
                 if ($currexempt{$lonhost}) {                  if ($currexempt{$lonhost}) {
                     if ((!exists($possexempt{$lonhost})) || ($possexempt{$lonhost} ne $currexempt{$lonhost})) {                       if ((!exists($possexempt{$lonhost})) || ($possexempt{$lonhost} ne $currexempt{$lonhost})) {
                         $changes{'headtag'}{$lonhost} = 1;                          $changes{'headtag'}{$lonhost} = 1;
                     }                      }
                 } elsif ($possexempt{$lonhost}) {                  } elsif ($possexempt{$lonhost}) {
Line 6301  sub modify_login { Line 10413  sub modify_login {
                         $chgtxt .= '</ul>';                          $chgtxt .= '</ul>';
                         $resulttext .= '<li>'.$chgtxt.'</li>';                          $resulttext .= '<li>'.$chgtxt.'</li>';
                     }                      }
                   } elsif ($item eq 'recaptchaversion') {
                       if (ref($loginhash{'login'}) eq 'HASH') {
                           if ($loginhash{'login'}{'captcha'} eq 'recaptcha') {
                               $resulttext .= '<li>'.&mt('ReCAPTCHA for helpdesk form set to version [_1]',$loginhash{'login'}{'recaptchaversion'}).
                                              '</li>';
                           }
                       }
                 } else {                  } else {
                     $resulttext .= '<li>'.&mt("$title{$item} set to $offon[$env{'form.'.$item}]").'</li>';                      $resulttext .= '<li>'.&mt("$title{$item} set to $offon[$env{'form.'.$item}]").'</li>';
                 }                  }
Line 6320  sub modify_login { Line 10439  sub modify_login {
     return $resulttext;      return $resulttext;
 }  }
   
   
 sub check_exempt_addresses {  sub check_exempt_addresses {
     my ($iplist) = @_;      my ($iplist) = @_;
     $iplist =~ s/^\s+//;      $iplist =~ s/^\s+//;
Line 6711  sub display_colorchgs { Line 10829  sub display_colorchgs {
                         } else {                          } else {
                             my $newitem = $confhash->{$role}{$item};                              my $newitem = $confhash->{$role}{$item};
                             if ($key eq 'images') {                              if ($key eq 'images') {
                                 $newitem = '<img src="'.$confhash->{$role}{$item}.'" alt="'.$choices{$item}.'" valign="bottom" />';                                  $newitem = '<img src="'.$confhash->{$role}{$item}.'" alt="'.$choices{$item}.'" style="vertical-align: bottom" />';
                             }                              }
                             $resulttext .= '<li>'.&mt("$choices{$item} set to [_1]",$newitem).'</li>';                              $resulttext .= '<li>'.&mt("$choices{$item} set to [_1]",$newitem).'</li>';
                         }                          }
Line 6764  sub check_configuser { Line 10882  sub check_configuser {
     my ($configuserok,%currroles);      my ($configuserok,%currroles);
     if ($uhome eq 'no_host') {      if ($uhome eq 'no_host') {
         srand( time() ^ ($$ + ($$ << 15))  ); # Seed rand.          srand( time() ^ ($$ + ($$ << 15))  ); # Seed rand.
         my $configpass = &LONCAPA::Enrollment::create_password();          my $configpass = &LONCAPA::Enrollment::create_password($dom);
         $configuserok =           $configuserok = 
             &Apache::lonnet::modifyuser($dom,$confname,'','internal',              &Apache::lonnet::modifyuser($dom,$confname,'','internal',
                              $configpass,'','','','','',undef,$servadm);                               $configpass,'','','','','',undef,$servadm);
Line 6793  sub check_authorstatus { Line 10911  sub check_authorstatus {
   
 sub publishlogo {  sub publishlogo {
     my ($r,$action,$formname,$dom,$confname,$subdir,$thumbwidth,$thumbheight,$savefileas) = @_;      my ($r,$action,$formname,$dom,$confname,$subdir,$thumbwidth,$thumbheight,$savefileas) = @_;
     my ($output,$fname,$logourl);      my ($output,$fname,$logourl,$madethumb);
     if ($action eq 'upload') {      if ($action eq 'upload') {
         $fname=$env{'form.'.$formname.'.filename'};          $fname=$env{'form.'.$formname.'.filename'};
         chop($env{'form.'.$formname});          chop($env{'form.'.$formname});
Line 6838  sub publishlogo { Line 10956  sub publishlogo {
     } else {      } else {
         my $source = $filepath.'/'.$file;          my $source = $filepath.'/'.$file;
         my $logfile;          my $logfile;
         if (!open($logfile,">>$source".'.log')) {          if (!open($logfile,">>",$source.'.log')) {
             return (&mt('No write permission to Authoring Space'));              return (&mt('No write permission to Authoring Space'));
         }          }
         print $logfile          print $logfile
 "\n================= Publish ".localtime()." ================\n".  "\n================= Publish ".localtime()." ================\n".
 $env{'user.name'}.':'.$env{'user.domain'}."\n";  $env{'user.name'}.':'.$env{'user.domain'}."\n";
 # Save the file  # Save the file
         if (!open(FH,'>'.$source)) {          if (!open(FH,">",$source)) {
             &Apache::lonnet::logthis('Failed to create '.$source);              &Apache::lonnet::logthis('Failed to create '.$source);
             return (&mt('Failed to create file'));              return (&mt('Failed to create file'));
         }          }
Line 6906  $env{'user.name'}.':'.$env{'user.domain' Line 11024  $env{'user.name'}.':'.$env{'user.domain'
                 if ($fullwidth ne '' && $fullheight ne '') {                   if ($fullwidth ne '' && $fullheight ne '') { 
                     if ($fullwidth > $thumbwidth && $fullheight > $thumbheight) {                      if ($fullwidth > $thumbwidth && $fullheight > $thumbheight) {
                         my $thumbsize = $thumbwidth.'x'.$thumbheight;                          my $thumbsize = $thumbwidth.'x'.$thumbheight;
                         system("convert -sample $thumbsize $inputfile $outfile");                          my @args = ('convert','-sample',$thumbsize,$inputfile,$outfile);
                           system({$args[0]} @args);
                         chmod(0660, $filepath.'/tn-'.$file);                          chmod(0660, $filepath.'/tn-'.$file);
                         if (-e $outfile) {                          if (-e $outfile) {
                             my $copyfile=$targetdir.'/tn-'.$file;                              my $copyfile=$targetdir.'/tn-'.$file;
Line 6921  $env{'user.name'}.':'.$env{'user.domain' Line 11040  $env{'user.name'}.':'.$env{'user.domain'
                                     $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);                                      $r->set_handlers('PerlCleanupHandler' => [\&notifysubscribed,@{$handlers}]);
                                     $registered_cleanup=1;                                      $registered_cleanup=1;
                                 }                                  }
                                   $madethumb = 1;
                             } else {                              } else {
                                 print $logfile "\nUnable to write ".$copyfile.                                  print $logfile "\nUnable to write ".$copyfile.
                                                ':'.$!."\n";                                                 ':'.$!."\n";
Line 6933  $env{'user.name'}.':'.$env{'user.domain' Line 11053  $env{'user.name'}.':'.$env{'user.domain'
             $output = $versionresult;              $output = $versionresult;
         }          }
     }      }
     return ($output,$logourl);      return ($output,$logourl,$madethumb);
 }  }
   
 sub logo_versioning {  sub logo_versioning {
Line 6985  sub write_metadata { Line 11105  sub write_metadata {
     {      {
         print $logfile "\nWrite metadata file for ".$targetdir.'/'.$file;          print $logfile "\nWrite metadata file for ".$targetdir.'/'.$file;
         my $mfh;          my $mfh;
         if (open($mfh,'>'.$targetdir.'/'.$file.'.meta')) {          if (open($mfh,">",$targetdir.'/'.$file.'.meta')) {
             foreach (sort(keys(%metadatafields))) {              foreach (sort(keys(%metadatafields))) {
                 unless ($_=~/\./) {                  unless ($_=~/\./) {
                     my $unikey=$_;                      my $unikey=$_;
Line 7019  sub notifysubscribed { Line 11139  sub notifysubscribed {
         next unless (ref($targetsource) eq 'ARRAY');          next unless (ref($targetsource) eq 'ARRAY');
         my ($target,$source)=@{$targetsource};          my ($target,$source)=@{$targetsource};
         if ($source ne '') {          if ($source ne '') {
             if (open(my $logfh,'>>'.$source.'.log')) {              if (open(my $logfh,">>",$source.'.log')) {
                 print $logfh "\nCleanup phase: Notifications\n";                  print $logfh "\nCleanup phase: Notifications\n";
                 my @subscribed=&subscribed_hosts($target);                  my @subscribed=&subscribed_hosts($target);
                 foreach my $subhost (@subscribed) {                  foreach my $subhost (@subscribed) {
Line 7045  sub notifysubscribed { Line 11165  sub notifysubscribed {
 sub subscribed_hosts {  sub subscribed_hosts {
     my ($target) = @_;      my ($target) = @_;
     my @subscribed;      my @subscribed;
     if (open(my $fh,"<$target.subscription")) {      if (open(my $fh,"<","$target.subscription")) {
         while (my $subline=<$fh>) {          while (my $subline=<$fh>) {
             if ($subline =~ /^($match_lonid):/) {              if ($subline =~ /^($match_lonid):/) {
                 my $host = $1;                  my $host = $1;
Line 7087  sub modify_quotas { Line 11207  sub modify_quotas {
         $context = $action;          $context = $action;
     }      }
     if ($context eq 'requestcourses') {      if ($context eq 'requestcourses') {
         @usertools = ('official','unofficial','community','textbook');          @usertools = ('official','unofficial','community','textbook','placement','lti');
         @options =('norequest','approval','validate','autolimit');          @options =('norequest','approval','validate','autolimit');
         %validations = &Apache::lonnet::auto_courserequest_checks($dom);          %validations = &Apache::lonnet::auto_courserequest_checks($dom);
         %titles = &courserequest_titles();          %titles = &courserequest_titles();
Line 7136  sub modify_quotas { Line 11256  sub modify_quotas {
         my @approvalnotify = &Apache::loncommon::get_env_multiple('form.'.$context.'notifyapproval');          my @approvalnotify = &Apache::loncommon::get_env_multiple('form.'.$context.'notifyapproval');
         @approvalnotify = sort(@approvalnotify);          @approvalnotify = sort(@approvalnotify);
         $confhash{'notify'}{'approval'} = join(',',@approvalnotify);          $confhash{'notify'}{'approval'} = join(',',@approvalnotify);
         my @crstypes = ('official','unofficial','community','textbook');          my @crstypes = ('official','unofficial','community','textbook','placement','lti');
         my @hasuniquecode = &Apache::loncommon::get_env_multiple('form.uniquecode');          my @hasuniquecode = &Apache::loncommon::get_env_multiple('form.uniquecode');
         foreach my $type (@hasuniquecode) {          foreach my $type (@hasuniquecode) {
             if (grep(/^\Q$type\E$/,@crstypes)) {              if (grep(/^\Q$type\E$/,@crstypes)) {
Line 7230  sub modify_quotas { Line 11350  sub modify_quotas {
                                     my $newpos = $env{'form.'.$itemid};                                      my $newpos = $env{'form.'.$itemid};
                                     $newpos =~ s/\D+//g;                                      $newpos =~ s/\D+//g;
                                     foreach my $item ('subject','title','publisher','author') {                                      foreach my $item ('subject','title','publisher','author') {
                                         next if ((($item eq 'author') || ($item eq 'publisher')) &&                                           next if ((($item eq 'author') || ($item eq 'publisher')) &&
                                                  ($type eq 'templates'));                                                   ($type eq 'templates'));
                                         $confhash{$type}{$key}{$item} = $env{'form.'.$type.'_'.$item.'_'.$i};                                          $confhash{$type}{$key}{$item} = $env{'form.'.$type.'_'.$item.'_'.$i};
                                         if ($domconfig{$action}{$type}{$key}{$item} ne $confhash{$type}{$key}{$item}) {                                          if ($domconfig{$action}{$type}{$key}{$item} ne $confhash{$type}{$key}{$item}) {
Line 7244  sub modify_quotas { Line 11364  sub modify_quotas {
                                     #FIXME need to obsolete item in RES space                                      #FIXME need to obsolete item in RES space
                                 } elsif ($env{'form.'.$type.'_image_'.$i.'.filename'}) {                                  } elsif ($env{'form.'.$type.'_image_'.$i.'.filename'}) {
                                     my ($cdom,$cnum) = split(/_/,$key);                                      my ($cdom,$cnum) = split(/_/,$key);
                                     my ($imgurl,$error) = &process_textbook_image($r,$dom,$confname,$type.'_image_'.$i,                                      if (&Apache::lonnet::homeserver($cnum,$cdom) eq 'no_host') {
                                                                                   $cdom,$cnum,$type,$configuserok,                                          $errors .= '<li><span class="LC_error">'.&mt('Image not saved: could not find textbook course').'</li>';
                                                                                   $switchserver,$author_ok);                                      } else {
                                     if ($imgurl) {                                          my ($imgurl,$error) = &process_textbook_image($r,$dom,$confname,$type.'_image_'.$i,
                                         $confhash{$type}{$key}{'image'} = $imgurl;                                                                                        $cdom,$cnum,$type,$configuserok,
                                         $changes{$type}{$key} = 1;                                                                                         $switchserver,$author_ok);
                                     }                                          if ($imgurl) {
                                     if ($error) {                                              $confhash{$type}{$key}{'image'} = $imgurl;
                                         &Apache::lonnet::logthis($error);                                              $changes{$type}{$key} = 1; 
                                         $errors .= '<li><span class="LC_error">'.$error.'</span></li>';                                          }
                                     }                                           if ($error) {
                                               &Apache::lonnet::logthis($error);
                                               $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
                                           }
                                       }
                                 } elsif ($domconfig{$action}{$type}{$key}{'image'}) {                                  } elsif ($domconfig{$action}{$type}{$key}{'image'}) {
                                     $confhash{$type}{$key}{'image'} =                                       $confhash{$type}{$key}{'image'} = 
                                         $domconfig{$action}{$type}{$key}{'image'};                                          $domconfig{$action}{$type}{$key}{'image'};
Line 7287  sub modify_quotas { Line 11411  sub modify_quotas {
                     if ($type eq 'textbooks') {                      if ($type eq 'textbooks') {
                         if ($env{'form.'.$type.'_addbook_image.filename'} ne '') {                          if ($env{'form.'.$type.'_addbook_image.filename'} ne '') {
                             my ($cdom,$cnum) = split(/_/,$newbook{$type});                              my ($cdom,$cnum) = split(/_/,$newbook{$type});
                             my ($imageurl,$error) =                              if (&Apache::lonnet::homeserver($cnum,$cdom) eq 'no_host') {
                                 &process_textbook_image($r,$dom,$confname,$type.'_addbook_image',$cdom,$cnum,$type,                                  $errors .= '<li><span class="LC_error">'.&mt('Image not saved: could not find textbook course').'</li>';
                                                         $configuserok,$switchserver,$author_ok);                              } else {
                             if ($imageurl) {                                  my ($imageurl,$error) =
                                 $confhash{$type}{$newbook{$type}}{'image'} = $imageurl;                                      &process_textbook_image($r,$dom,$confname,$type.'_addbook_image',$cdom,$cnum,$type,
                             }                                                              $configuserok,$switchserver,$author_ok);
                             if ($error) {                                  if ($imageurl) {
                                 &Apache::lonnet::logthis($error);                                      $confhash{$type}{$newbook{$type}}{'image'} = $imageurl;
                                 $errors .= '<li><span class="LC_error">'.$error.'</span></li>';                                  }
                                   if ($error) {
                                       &Apache::lonnet::logthis($error);
                                       $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
                                   }
                             }                              }
                         }                          }
                     }                      }
Line 7327  sub modify_quotas { Line 11455  sub modify_quotas {
                         if (@{$confhash{'validation'}{$item}} > 0) {                          if (@{$confhash{'validation'}{$item}} > 0) {
                             @{$confhash{'validation'}{$item}} = sort(@{$confhash{'validation'}{$item}});                              @{$confhash{'validation'}{$item}} = sort(@{$confhash{'validation'}{$item}});
                         }                          }
                         if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {                          if (ref($domconfig{'requestcourses'}) eq 'HASH') {
                             if (ref($domconfig{'requestcourses'}{'validation'}{$item}) eq 'ARRAY') {                              if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {
                                 @changed = &Apache::loncommon::compare_arrays($confhash{'validation'}{$item},                                  if (ref($domconfig{'requestcourses'}{'validation'}{$item}) eq 'ARRAY') {
                                                                               $domconfig{'requestcourses'}{'validation'}{$item});                                      @changed = &Apache::loncommon::compare_arrays($confhash{'validation'}{$item},
                                                                                     $domconfig{'requestcourses'}{'validation'}{$item});
                                   } else {
                                       @changed = @{$confhash{'validation'}{$item}};
                                   }
                             } else {                              } else {
                                 @changed = @{$confhash{'validation'}{$item}};                                  @changed = @{$confhash{'validation'}{$item}};
                             }                              }
Line 7351  sub modify_quotas { Line 11483  sub modify_quotas {
                                 $env{'form.requestcourses_validation_'.$item} =~ s/[\n\r\f]+/\s/gs;                                  $env{'form.requestcourses_validation_'.$item} =~ s/[\n\r\f]+/\s/gs;
                             }                              }
                         }                          }
                         if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {                          if (ref($domconfig{'requestcourses'}) eq 'HASH') {
                             if ($domconfig{'requestcourses'}{'validation'}{$item} ne $confhash{'validation'}{$item}) {                              if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {
                                 $changes{'validation'}{$item} = $confhash{'validation'}{$item};                                  if ($domconfig{'requestcourses'}{'validation'}{$item} ne $confhash{'validation'}{$item}) {
                                       $changes{'validation'}{$item} = $confhash{'validation'}{$item};
                                   }
                               } else {
                                   if ($confhash{'validation'}{$item} ne '') {
                                       $changes{'validation'}{$item} = $confhash{'validation'}{$item};
                                   }
                             }                              }
                         } else {                          } else {
                             if ($confhash{'validation'}{$item} ne '') {                              if ($confhash{'validation'}{$item} ne '') {
Line 7365  sub modify_quotas { Line 11503  sub modify_quotas {
             }              }
             if ($env{'form.validationdc'}) {              if ($env{'form.validationdc'}) {
                 my $newval = $env{'form.validationdc'};                  my $newval = $env{'form.validationdc'};
                 my %domcoords = &get_active_dcs($dom);                  my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']);
                 if (exists($domcoords{$newval})) {                  if (exists($domcoords{$newval})) {
                     $confhash{'validation'}{'dc'} = $newval;                      $confhash{'validation'}{'dc'} = $newval;
                 }                  }
             }              }
             if (ref($confhash{'validation'}) eq 'HASH') {              if (ref($confhash{'validation'}) eq 'HASH') {
                 if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {                  if (ref($domconfig{'requestcourses'}) eq 'HASH') {
                     if ($domconfig{'requestcourses'}{'validation'}{'dc'}) {                      if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {
                         unless ($confhash{'validation'}{'dc'} eq $domconfig{'requestcourses'}{'validation'}{'dc'}) {                          if ($domconfig{'requestcourses'}{'validation'}{'dc'}) {
                             if ($confhash{'validation'}{'dc'} eq '') {                              unless ($confhash{'validation'}{'dc'} eq $domconfig{'requestcourses'}{'validation'}{'dc'}) {
                                 $changes{'validation'}{'dc'} = &mt('None');                                  if ($confhash{'validation'}{'dc'} eq '') {
                             } else {                                      $changes{'validation'}{'dc'} = &mt('None');
                                 $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};                                  } else {
                                       $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};
                                   }
                             }                              }
                           } elsif ($confhash{'validation'}{'dc'} ne '') {
                               $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};
                         }                          }
                     } elsif ($confhash{'validation'}{'dc'} ne '') {                      } elsif ($confhash{'validation'}{'dc'} ne '') {
                         $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};                          $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};
Line 7386  sub modify_quotas { Line 11528  sub modify_quotas {
                 } elsif ($confhash{'validation'}{'dc'} ne '') {                  } elsif ($confhash{'validation'}{'dc'} ne '') {
                     $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};                      $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};
                 }                  }
             } elsif (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {              } else {
                 if ($domconfig{'requestcourses'}{'validation'}{'dc'}) {                  if (ref($domconfig{'requestcourses'}) eq 'HASH') {
                     $changes{'validation'}{'dc'} = &mt('None');                      if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {
                           if ($domconfig{'requestcourses'}{'validation'}{'dc'}) {
                               $changes{'validation'}{'dc'} = &mt('None');
                           }
                       }
                 }                  }
             }              }
         }          }
Line 7769  sub process_textbook_image { Line 11915  sub process_textbook_image {
         } elsif ($author_ok eq 'ok') {          } elsif ($author_ok eq 'ok') {
             my ($result,$imageurl) =              my ($result,$imageurl) =
                 &publishlogo($r,'upload',$caller,$dom,$confname,                  &publishlogo($r,'upload',$caller,$dom,$confname,
                              "$type/$dom/$cnum/cover",$width,$height);                               "$type/$cdom/$cnum/cover",$width,$height);
             if ($result eq 'ok') {              if ($result eq 'ok') {
                 $url = $imageurl;                  $url = $imageurl;
             } else {              } else {
Line 7784  sub process_textbook_image { Line 11930  sub process_textbook_image {
     return ($url,$error);      return ($url,$error);
 }  }
   
   sub modify_ltitools {
       my ($r,$dom,$action,$lastactref,%domconfig) = @_;
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my ($newid,@allpos,%changes,%confhash,%encconfig,$errors,$resulttext);
       my $confname = $dom.'-domainconfig';
       my $servadm = $r->dir_config('lonAdmEMail');
       my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);
       my (%posslti,%possfield);
       my @courseroles = ('cc','in','ta','ep','st');
       my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner);
       map { $posslti{$_} = 1; } @ltiroles;
       my @allfields = ('fullname','firstname','lastname','email','user','roles');
       map { $possfield{$_} = 1; } @allfields;
       my %lt = &ltitools_names(); 
       if ($env{'form.ltitools_add'}) {
           my $title = $env{'form.ltitools_add_title'};
           $title =~ s/(`)/'/g;
           ($newid,my $error) = &get_ltitools_id($dom,$title);
           if ($newid) {
               my $position = $env{'form.ltitools_add_pos'};
               $position =~ s/\D+//g;
               if ($position ne '') {
                   $allpos[$position] = $newid;
               }
               $changes{$newid} = 1;
               foreach my $item ('title','url','key','secret','lifetime') {
                   $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;
           my @newcustom = &Apache::loncommon::get_env_multiple('form.ltitools_customadd');
           if (@newcustom) {
               map { $customadds{$_} = 1; } @newcustom;
           } 
           my %imgdeletions;
           my @todeleteimages = &Apache::loncommon::get_env_multiple('form.ltitools_image_del');
           if (@todeleteimages) {
               map { $imgdeletions{$_} = 1; } @todeleteimages;
           }
           my $maxnum = $env{'form.ltitools_maxnum'};
           for (my $i=0; $i<=$maxnum; $i++) {
               my $itemid = $env{'form.ltitools_id_'.$i};
               $itemid =~ s/\D+//g;
               if (ref($domconfig{$action}{$itemid}) eq 'HASH') {
                   if ($deletions{$itemid}) {
                       if ($domconfig{$action}{$itemid}{'image'}) {
                           #FIXME need to obsolete item in RES space
                       }
                       $changes{$itemid} = $domconfig{$action}{$itemid}{'title'};
                       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;
                               }
                           }
                           last if ($changes{$itemid});
                       }
                   }
               }
           }
       }
       if (@allpos > 0) {
           my $idx = 0;
           foreach my $itemid (@allpos) {
               if ($itemid ne '') {
                   $confhash{$itemid}{'order'} = $idx;
                   if (ref($domconfig{$action}) eq 'HASH') {
                       if (ref($domconfig{$action}{$itemid}) eq 'HASH') {
                           if ($domconfig{$action}{$itemid}{'order'} ne $idx) {
                               $changes{$itemid} = 1;
                           }
                       }
                   }
                   $idx ++;
               }
           }
       }
       my %ltitoolshash = (
                             $action => { %confhash }
                          );
       my $putresult = &Apache::lonnet::put_dom('configuration',\%ltitoolshash,
                                                $dom);
       if ($putresult eq 'ok') {
           my %ltienchash = (
                                $action => { %encconfig }
                            );
           &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom);
           if (keys(%changes) > 0) {
               my $cachetime = 24*60*60;
               my %ltiall = %confhash;
               foreach my $id (keys(%ltiall)) {
                   if (ref($encconfig{$id}) eq 'HASH') {
                       foreach my $item ('key','secret') {
                           $ltiall{$id}{$item} = $encconfig{$id}{$item};
                       }
                   }
               }
               &Apache::lonnet::do_cache_new('ltitools',$dom,\%ltiall,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'ltitools'} = 1;
               }
               $resulttext = &mt('Changes made:').'<ul>';
               my %bynum;
               foreach my $itemid (sort(keys(%changes))) {
                   my $position = $confhash{$itemid}{'order'};
                   $bynum{$position} = $itemid;
               }
               foreach my $pos (sort { $a <=> $b } keys(%bynum)) {
                   my $itemid = $bynum{$pos}; 
                   if (ref($confhash{$itemid}) ne 'HASH') {
                       $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';
                   } else {
                       $resulttext .= '<li><b>'.$confhash{$itemid}{'title'}.'</b>';
                       if ($confhash{$itemid}{'image'}) {
                           $resulttext .= '&nbsp;'.
                                          '<img src="'.$confhash{$itemid}{'image'}.'"'.
                                          ' alt="'.&mt('Tool Provider icon').'" />';
                       }
                       $resulttext .= '</li><ul>';
                       my $position = $pos + 1;
                       $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';
                       foreach my $item ('version','msgtype','sigmethod','url','lifetime') {
                           if ($confhash{$itemid}{$item} ne '') {
                               $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{$item}.'</li>';
                           }
                       }
                       if ($encconfig{$itemid}{'key'} ne '') {
                           $resulttext .= '<li>'.$lt{'key'}.':&nbsp;'.$encconfig{$itemid}{'key'}.'</li>';
                       }
                       if ($encconfig{$itemid}{'secret'} ne '') {
                           $resulttext .= '<li>'.$lt{'secret'}.':&nbsp;';
                           my $num = length($encconfig{$itemid}{'secret'});
                           $resulttext .= ('*'x$num).'</li>';
                       }
                       $resulttext .= '<li>'.&mt('Configurable in course:');
                       my @possconfig = ('label','title','target','linktext','explanation','append');
                       my $numconfig = 0; 
                       if (ref($confhash{$itemid}{'crsconf'}) eq 'HASH') { 
                           foreach my $item (@possconfig) {
                               if ($confhash{$itemid}{'crsconf'}{$item}) {
                                   $numconfig ++;
                                   $resulttext .= ' "'.$lt{'crs'.$item}.'"';
                               }
                           }
                       }
                       if (!$numconfig) {
                           $resulttext .= &mt('None');
                       }
                       $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') {
                           my $rolemaps;
                           foreach my $role (@courseroles) {
                               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') {
                           my $customlist;
                           if (keys(%{$confhash{$itemid}{'custom'}})) {
                               foreach my $key (sort(keys(%{$confhash{$itemid}{'custom'}}))) {
                                   $customlist .= $key.':'.$confhash{$itemid}{'custom'}{$key}.('&nbsp;'x2);
                               } 
                           }
                           if ($customlist) {
                               $resulttext .= '<li>'.&mt('Custom items').': '.$customlist.'</li>';
                           }
                       } 
                       $resulttext .= '</ul></li>';
                   }
               }
               $resulttext .= '</ul>';
           } 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 {
       my ($r,$dom,$confname,$caller,$itemid,$configuserok,$switchserver,$author_ok) = @_;
       my $filename = $env{'form.'.$caller.'.filename'};
       my ($error,$url);
       my ($width,$height) = (21,21);
       if ($configuserok eq 'ok') {
           if ($switchserver) {
               $error = &mt('Upload of Tool Provider (LTI) icon is not permitted to this server: [_1]',
                            $switchserver);
           } elsif ($author_ok eq 'ok') {
               my ($result,$imageurl,$madethumb) =
                   &publishlogo($r,'upload',$caller,$dom,$confname,
                                "ltitools/$itemid/icon",$width,$height);
               if ($result eq 'ok') {
                   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 {
       my ($cdom,$title) = @_;
       # get lock on ltitools db
       my $lockhash = {
                         lock => $env{'user.name'}.
                                 ':'.$env{'user.domain'},
                      };
       my $tries = 0;
       my $gotlock = &Apache::lonnet::newput_dom('ltitools',$lockhash,$cdom);
       my ($id,$error);
    
       while (($gotlock ne 'ok') && ($tries<10)) {
           $tries ++;
           sleep (0.1);
           $gotlock = &Apache::lonnet::newput_dom('ltitools',$lockhash,$cdom);
       }
       if ($gotlock eq 'ok') {
           my %currids = &Apache::lonnet::dump_dom('ltitools',$cdom);
           if ($currids{'lock'}) {
               delete($currids{'lock'});
               if (keys(%currids)) {
                   my @curr = sort { $a <=> $b } keys(%currids);
                   if ($curr[-1] =~ /^\d+$/) {
                       $id = 1 + $curr[-1];
                   }
               } else {
                   $id = 1;
               }
               if ($id) {
                   unless (&Apache::lonnet::newput_dom('ltitools',{ $id => $title },$cdom) eq 'ok') {
                       $error = 'nostore';
                   }
               } else {
                   $error = 'nonumber';
               }
           }
           my $dellockoutcome = &Apache::lonnet::del_dom('ltitools',['lock'],$cdom);
       } else {
           $error = 'nolock';
       }
       return ($id,$error);
   }
   
   sub modify_lti {
       my ($r,$dom,$action,$lastactref,%domconfig) = @_;
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my ($newid,@allpos,%changes,%confhash,%encconfig,$errors,$resulttext);
       my (%posslti,%posslticrs,%posscrstype);
       my @courseroles = ('cc','in','ta','ep','st');
       my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator);
       my @lticourseroles = qw(Instructor TeachingAssistant Mentor Learner);
       my @coursetypes = ('official','unofficial','community','textbook','placement');
       my %coursetypetitles = &Apache::lonlocal::texthash (
                                  official   => 'Official',
                                  unofficial => 'Unofficial',
                                  community  => 'Community',
                                  textbook   => 'Textbook',
                                  placement  => 'Placement Test',
       );
       my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
       my %lt = &lti_names();
       map { $posslti{$_} = 1; } @ltiroles;
       map { $posslticrs{$_} = 1; } @lticourseroles;
       map { $posscrstype{$_} = 1; } @coursetypes;
   
       my %menutitles = &ltimenu_titles();
   
       my (@items,%deletions,%itemids);
       if ($env{'form.lti_add'}) {
           my $consumer = $env{'form.lti_consumer_add'};
           $consumer =~ s/(`)/'/g;
           ($newid,my $error) = &get_lti_id($dom,$consumer);
           if ($newid) {
               $itemids{'add'} = $newid;
               push(@items,'add');
               $changes{$newid} = 1;
           } else {
               my $error = &mt('Failed to acquire unique ID for new LTI configuration');
               $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
           }
       }
       if (ref($domconfig{$action}) eq 'HASH') {
           my @todelete = &Apache::loncommon::get_env_multiple('form.lti_del');
           if (@todelete) {
               map { $deletions{$_} = 1; } @todelete;
           }
           my $maxnum = $env{'form.lti_maxnum'};
           for (my $i=0; $i<=$maxnum; $i++) {
               my $itemid = $env{'form.lti_id_'.$i};
               $itemid =~ s/\D+//g;
               if (ref($domconfig{$action}{$itemid}) eq 'HASH') {
                   if ($deletions{$itemid}) {
                       $changes{$itemid} = $domconfig{$action}{$itemid}{'consumer'};
                   } else {
                      push(@items,$i);
                      $itemids{$i} = $itemid;
                   }
               }
           }
       }
       foreach my $idx (@items) {
           my $itemid = $itemids{$idx};
           next unless ($itemid);
           my $position = $env{'form.lti_pos_'.$idx};
           $position =~ s/\D+//g;
           if ($position ne '') {
               $allpos[$position] = $itemid;
           }
           foreach my $item ('consumer','key','secret','lifetime','requser') {
               my $formitem = 'form.lti_'.$item.'_'.$idx;
               $env{$formitem} =~ s/(`)/'/g;
               if ($item eq 'lifetime') {
                   $env{$formitem} =~ s/[^\d.]//g;
               }
               if ($env{$formitem} ne '') {
                   if (($item eq 'key') || ($item eq 'secret')) {
                       $encconfig{$itemid}{$item} = $env{$formitem};
                   } else {
                       $confhash{$itemid}{$item} = $env{$formitem};
                       unless (($idx eq 'add') || ($changes{$itemid})) {
                           if ($domconfig{$action}{$itemid}{$item} ne $confhash{$itemid}{$item}) {
                               $changes{$itemid} = 1;
                           }
                       }
                   }
               }
           }
           if ($env{'form.lti_version_'.$idx} eq 'LTI-1p0') {
               $confhash{$itemid}{'version'} = $env{'form.lti_version_'.$idx};
           }
           if ($confhash{$itemid}{'requser'}) {
               if ($env{'form.lti_mapuser_'.$idx} eq 'sourcedid') {
                   $confhash{$itemid}{'mapuser'} = 'lis_person_sourcedid'; 
               } elsif ($env{'form.lti_mapuser_'.$idx} eq 'email') {
                   $confhash{$itemid}{'mapuser'} = 'lis_person_contact_email_primary';
               } elsif ($env{'form.lti_mapuser_'.$idx} eq 'other') {
                   my $mapuser = $env{'form.lti_customuser_'.$idx};
                   $mapuser =~ s/(`)/'/g;
                   $mapuser =~ s/^\s+|\s+$//g; 
                   $confhash{$itemid}{'mapuser'} = $mapuser; 
               }
               foreach my $ltirole (@lticourseroles) {
                   my $possrole = $env{'form.lti_maprole_'.$ltirole.'_'.$idx};
                   if (grep(/^\Q$possrole\E$/,@courseroles)) {
                       $confhash{$itemid}{'maproles'}{$ltirole} = $possrole;
                   }
               }
               my @possmakeuser = &Apache::loncommon::get_env_multiple('form.lti_makeuser_'.$idx);
               my @makeuser;
               foreach my $ltirole (sort(@possmakeuser)) {
                   if ($posslti{$ltirole}) {
                       push(@makeuser,$ltirole);
                   }
               }
               $confhash{$itemid}{'makeuser'} = \@makeuser;
               if (@makeuser) {
                   my $lcauth = $env{'form.lti_lcauth_'.$idx};
                   if ($lcauth =~ /^(internal|krb4|krb5|localauth)$/) {
                       $confhash{$itemid}{'lcauth'} = $lcauth;
                       if ($lcauth ne 'internal') {
                           my $lcauthparm = $env{'form.lti_lcauthparm_'.$idx};
                           $lcauthparm =~ s/^(\s+|\s+)$//g;
                           $lcauthparm =~ s/`//g;
                           if ($lcauthparm ne '') {
                               $confhash{$itemid}{'lcauthparm'} = $lcauthparm;
                           }
                       }
                   } else {
                       $confhash{$itemid}{'lcauth'} = 'lti';
                   }
               }
               my @possinstdata =  &Apache::loncommon::get_env_multiple('form.lti_instdata_'.$idx);
               if (@possinstdata) {
                   foreach my $field (@possinstdata) {
                       if (exists($fieldtitles{$field})) {
                           push(@{$confhash{$itemid}{'instdata'}});
                       }
                   }
               }
               if (($env{'form.lti_mapcrs_'.$idx} eq 'course_offering_sourcedid') ||
                   ($env{'form.lti_mapcrs_'.$idx} eq 'context_id'))  {
                   $confhash{$itemid}{'mapcrs'} = $env{'form.lti_mapcrs_'.$idx};
               } elsif ($env{'form.lti_mapcrs_'.$idx} eq 'other') {
                   my $mapcrs = $env{'form.lti_mapcrsfield_'.$idx}; 
                   $mapcrs =~ s/(`)/'/g;
                   $mapcrs =~ s/^\s+|\s+$//g;
                   $confhash{$itemid}{'mapcrs'} = $mapcrs;
               }
               my @posstypes = &Apache::loncommon::get_env_multiple('form.lti_mapcrstype_'.$idx);
               my @crstypes;
               foreach my $type (sort(@posstypes)) {
                   if ($posscrstype{$type}) {
                       push(@crstypes,$type);
                   }
               }
               $confhash{$itemid}{'mapcrstype'} = \@crstypes;
               if ($env{'form.lti_makecrs_'.$idx}) {
                   $confhash{$itemid}{'makecrs'} = 1;
               }
               my @possenroll = &Apache::loncommon::get_env_multiple('form.lti_selfenroll_'.$idx);
               my @selfenroll;
               foreach my $type (sort(@possenroll)) {
                   if ($posslticrs{$type}) {
                       push(@selfenroll,$type);
                   }
               }
               $confhash{$itemid}{'selfenroll'} = \@selfenroll;
               if ($env{'form.lti_crssec_'.$idx}) {
                   if ($env{'form.lti_crssecsrc_'.$idx} eq 'course_section_sourcedid') {
                       $confhash{$itemid}{'section'} = $env{'form.lti_crssecsrc_'.$idx};
                   } elsif ($env{'form.lti_crssecsrc_'.$idx} eq 'other') {
                       my $section = $env{'form.lti_customsection_'.$idx};
                       $section =~ s/(`)/'/g;
                       $section =~ s/^\s+|\s+$//g;
                       if ($section ne '') {
                           $confhash{$itemid}{'section'} = $section;
                       }
                   }
               }
               if ($env{'form.lti_callback_'.$idx}) {
                   if ($env{'form.lti_callbackparam_'.$idx}) {
                       my $callback = $env{'form.lti_callbackparam_'.$idx};
                       $callback =~ s/^\s+|\s+$//g;
                       $confhash{$itemid}{'callback'} = $callback;
                   }
               }
               foreach my $field ('passback','roster','topmenu','inlinemenu') {
                   if ($env{'form.lti_'.$field.'_'.$idx}) {
                       $confhash{$itemid}{$field} = 1;
                   }
               }
               if ($env{'form.lti_passback_'.$idx}) {
                   if ($env{'form.lti_passbackformat_'.$idx} eq '1.0') {
                       $confhash{$itemid}{'passbackformat'} = '1.0';
                   } else {
                       $confhash{$itemid}{'passbackformat'} = '1.1';
                   }
               }
               if ($env{'form.lti_topmenu_'.$idx} || $env{'form.lti_inlinemenu_'.$idx}) {
                   $confhash{$itemid}{lcmenu} = [];
                   my @possmenu = &Apache::loncommon::get_env_multiple('form.lti_menuitem_'.$idx);
                   foreach my $field (@possmenu) {
                       if (exists($menutitles{$field})) {
                           if ($field eq 'grades') {
                               next unless ($env{'form.lti_inlinemenu_'.$idx});
                           }
                           push(@{$confhash{$itemid}{lcmenu}},$field);
                       }
                   }
               }
               unless (($idx eq 'add') || ($changes{$itemid})) {
                   foreach my $field ('mapuser','mapcrs','makecrs','section','passback','roster','lcauth','lcauthparm','topmenu','inlinemenu','callback') {
                       if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) {
                           $changes{$itemid} = 1;
                       }
                   }
                   unless ($changes{$itemid}) {
                       if ($domconfig{$action}{$itemid}{'passback'} eq $confhash{$itemid}{'passback'}) {
                           if ($domconfig{$action}{$itemid}{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) {
                               $changes{$itemid} = 1;
                           }
                       }
                   }
                   foreach my $field ('makeuser','mapcrstype','selfenroll','instdata','lcmenu') {
                       unless ($changes{$itemid}) {
                           if (ref($domconfig{$action}{$itemid}{$field}) eq 'ARRAY') {
                               if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
                                   my @diffs = &Apache::loncommon::compare_arrays($domconfig{$action}{$itemid}{$field},
                                                                                  $confhash{$itemid}{$field});
                                   if (@diffs) {
                                       $changes{$itemid} = 1;
                                   }
                               } elsif (@{$domconfig{$action}{$itemid}{$field}} > 0) {
                                   $changes{$itemid} = 1;
                               }
                           } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
                               if (@{$confhash{$itemid}{$field}} > 0) {
                                   $changes{$itemid} = 1;
                               }
                           }
                       }
                   }
                   unless ($changes{$itemid}) {
                       if (ref($domconfig{$action}{$itemid}{'maproles'}) eq 'HASH') {
                           if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
                               foreach my $ltirole (keys(%{$domconfig{$action}{$itemid}{'maproles'}})) {
                                   if ($domconfig{$action}{$itemid}{'maproles'}{$ltirole} ne 
                                       $confhash{$itemid}{'maproles'}{$ltirole}) {
                                       $changes{$itemid} = 1;
                                       last;
                                   }
                               }
                               unless ($changes{$itemid}) {
                                   foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) {
                                       if ($confhash{$itemid}{'maproles'}{$ltirole} ne 
                                           $domconfig{$action}{$itemid}{'maproles'}{$ltirole}) {
                                           $changes{$itemid} = 1;
                                           last;
                                       }
                                   }
                               }
                           } elsif (keys(%{$domconfig{$action}{$itemid}{'maproles'}}) > 0) {
                               $changes{$itemid} = 1;
                           }
                       } elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
                           unless ($changes{$itemid}) {
                               if (keys(%{$confhash{$itemid}{'maproles'}}) > 0) {
                                   $changes{$itemid} = 1;
                               }
                           }
                       }
                   }
               }
           }
       }
       if (@allpos > 0) {
           my $idx = 0;
           foreach my $itemid (@allpos) {
               if ($itemid ne '') {
                   $confhash{$itemid}{'order'} = $idx;
                   if (ref($domconfig{$action}) eq 'HASH') {
                       if (ref($domconfig{$action}{$itemid}) eq 'HASH') {
                           if ($domconfig{$action}{$itemid}{'order'} ne $idx) {
                               $changes{$itemid} = 1;
                           }
                       }
                   }
                   $idx ++;
               }
           }
       }
       my %ltihash = (
                             $action => { %confhash }
                          );
       my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,
                                                $dom);
       if ($putresult eq 'ok') {
           my %ltienchash = (
                                $action => { %encconfig }
                            );
           &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom);
           if (keys(%changes) > 0) {
               my $cachetime = 24*60*60;
               my %ltiall = %confhash;
               foreach my $id (keys(%ltiall)) {
                   if (ref($encconfig{$id}) eq 'HASH') {
                       foreach my $item ('key','secret') {
                           $ltiall{$id}{$item} = $encconfig{$id}{$item};
                       }
                   }
               }
               &Apache::lonnet::do_cache_new('lti',$dom,\%ltiall,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'lti'} = 1;
               }
               $resulttext = &mt('Changes made:').'<ul>';
               my %bynum;
               foreach my $itemid (sort(keys(%changes))) {
                   my $position = $confhash{$itemid}{'order'};
                   $bynum{$position} = $itemid;
               }
               foreach my $pos (sort { $a <=> $b } keys(%bynum)) {
                   my $itemid = $bynum{$pos};
                   if (ref($confhash{$itemid}) ne 'HASH') {
                       $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';
                   } else {
                       $resulttext .= '<li><b>'.$confhash{$itemid}{'consumer'}.'</b></li><ul>';
                       my $position = $pos + 1;
                       $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';
                       foreach my $item ('version','lifetime') {
                           if ($confhash{$itemid}{$item} ne '') {
                               $resulttext .= '<li>'.$lt{$item}.':&nbsp;'.$confhash{$itemid}{$item}.'</li>';
                           }
                       }
                       if ($encconfig{$itemid}{'key'} ne '') {
                           $resulttext .= '<li>'.$lt{'key'}.':&nbsp;'.$encconfig{$itemid}{'key'}.'</li>';
                       }
                       if ($encconfig{$itemid}{'secret'} ne '') {
                           $resulttext .= '<li>'.$lt{'secret'}.':&nbsp;';
                           my $num = length($encconfig{$itemid}{'secret'});
                           $resulttext .= ('*'x$num).'</li>';
                       }
                       if ($confhash{$itemid}{'requser'}) {
                           if ($confhash{$itemid}{'mapuser'}) {
                               my $shownmapuser;
                               if ($confhash{$itemid}{'mapuser'} eq 'lis_person_sourcedid') {
                                   $shownmapuser = $lt{'sourcedid'}.' (lis_person_sourcedid)';
                               } elsif ($confhash{$itemid}{'mapuser'} eq 'lis_person_contact_email_primary') {
                                   $shownmapuser = $lt{'email'}.' (lis_person_contact_email_primary)';
                               } else {
                                   $shownmapuser = &mt('Other').' ('.$confhash{$itemid}{'mapuser'}.')';
                               }
                               $resulttext .= '<li>'.&mt('LON-CAPA username').': '.$shownmapuser.'</li>';
                           }
                           if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
                               my $rolemaps;
                               foreach my $role (@ltiroles) {
                                   if ($confhash{$itemid}{'maproles'}{$role}) {
                                       $rolemaps .= ('&nbsp;'x2).$role.'='.
                                                    &Apache::lonnet::plaintext($confhash{$itemid}{'maproles'}{$role},
                                                                               'Course').',';
                                   }
                               }
                               if ($rolemaps) {
                                   $rolemaps =~ s/,$//;
                                   $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>';
                               }
                           }
                           if (ref($confhash{$itemid}{'makeuser'}) eq 'ARRAY') {
                               if (@{$confhash{$itemid}{'makeuser'}} > 0) { 
                                   $resulttext .= '<li>'.&mt('Following roles may create user accounts: [_1]',
                                                             join(', ',@{$confhash{$itemid}{'makeuser'}})).'<br />';
                                   if ($confhash{$itemid}{'lcauth'} eq 'lti') {
                                       $resulttext .= &mt('New users will only be able to authenticate via LTI').'</li>';
                                   } else {
                                       $resulttext .= &mt('New users will be assigned LON-CAPA authentication: [_1]',
                                                          $confhash{$itemid}{'lcauth'});
                                       if ($confhash{$itemid}{'lcauth'} eq 'internal') {
                                           $resulttext .= '; '.&mt('a randomly generated password will be created');
                                       } elsif ($confhash{$itemid}{'lcauth'} eq 'localauth') {
                                           if ($confhash{$itemid}{'lcauthparm'} ne '') {
                                               $resulttext .= ' '.&mt('with argument: [_1]',$confhash{$itemid}{'lcauthparm'});
                                           }
                                       } else {
                                           $resulttext .= '; '.&mt('Kerberos domain: [_1]',$confhash{$itemid}{'lcauthparm'});
                                       }
                                   }
                                   $resulttext .= '</li>';
                               } else {
                                   $resulttext .= '<li>'.&mt('User account creation not permitted.').'</li>';
                               }
                           }
                           if (ref($confhash{$itemid}{'instdata'}) eq 'ARRAY') {
                               if (@{$confhash{$itemid}{'instdata'}} > 0) {
                                   $resulttext .= '<li>'.&mt('Institutional data will be used when creating a new user for: [_1]',
                                                             join(', ',map { $fieldtitles{$_}; } @{$confhash{$itemid}{'instdata'}})).'</li>';
                               } else {
                                   $resulttext .= '<li>'.&mt('No institutional data used when creating a new user.').'</li>';
                               }
                           }
                           if ($confhash{$itemid}{'mapcrs'}) {
                               $resulttext .= '<li>'.&mt('Unique course identifier').': '.$confhash{$itemid}{'mapcrs'}.'</li>';
                           }
                           if (ref($confhash{$itemid}{'mapcrstype'}) eq 'ARRAY') {
                               if (@{$confhash{$itemid}{'mapcrstype'}} > 0) {
                                   $resulttext .= '<li>'.&mt('Mapping for the following LON-CAPA course types: [_1]',
                                                  join(', ',map { $coursetypetitles{$_}; } @coursetypes)).
                                                  '</li>';
                               } else {
                                   $resulttext .= '<li>'.&mt('No mapping to LON-CAPA courses').'</li>';
                               }
                           }
                           if ($confhash{$itemid}{'makecrs'}) {
                               $resulttext .= '<li>'.&mt('Instructor may create course (if absent).').'</li>';
                           } else {
                               $resulttext .= '<li>'.&mt('Instructor may not create course (if absent).').'</li>';
                           }
                           if (ref($confhash{$itemid}{'selfenroll'}) eq 'ARRAY') {
                               if (@{$confhash{$itemid}{'selfenroll'}} > 0) {
                                   $resulttext .= '<li>'.&mt('Self-enrollment for following roles: [_1]',
                                                             join(', ',@{$confhash{$itemid}{'selfenroll'}})).
                                                  '</li>';
                               } else {
                                   $resulttext .= '<li>'.&mt('Self-enrollment not permitted').'</li>';
                               }
                           }
                           if ($confhash{$itemid}{'section'}) {
                               if ($confhash{$itemid}{'section'} eq 'course_section_sourcedid') {
                                   $resulttext .= '<li>'.&mt('User section from standard field:').
                                                        ' (course_section_sourcedid)'.'</li>';  
                               } else {
                                   $resulttext .= '<li>'.&mt('User section from:').' '.
                                                         $confhash{$itemid}{'section'}.'</li>';
                               }
                           } else {
                               $resulttext .= '<li>'.&mt('No section assignment').'</li>';
                           }
                           if ($confhash{$itemid}{'callback'}) {
                               $resulttext .= '<li>'.&mt('Callback setting').': '.$confhash{$itemid}{'callback'}.'</li>';
                           } else {
                               $resulttext .= '<li>'.&mt('No callback to logout LON-CAPA session when user logs out of Comsumer');
                           }
                           foreach my $item ('passback','roster','topmenu','inlinemenu') {
                               $resulttext .= '<li>'.$lt{$item}.':&nbsp;';
                               if ($confhash{$itemid}{$item}) {
                                   $resulttext .= &mt('Yes');
                                   if ($item eq 'passback') {
                                       if ($confhash{$itemid}{'passbackformat'} eq '1.0') {
                                           $resulttext .= '&nbsp;('.&mt('Outcomes Extension (1.0)').')';
                                       } elsif ($confhash{$itemid}{'passbackformat'} eq '1.1') {
                                           $resulttext .= '&nbsp;('.&mt('Outcomes Service (1.1)').')';
                                       }
                                   }
                               } else {
                                   $resulttext .= &mt('No');
                               }
                               $resulttext .= '</li>';
                           }
                           if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') {
                               if (@{$confhash{$itemid}{'lcmenu'}} > 0) {
                                   $resulttext .= '<li>'.&mt('Menu items:').' '.
                                                  join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>'; 
                               } else {
                                   $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>'; 
                               }
                           }
                       }
                       $resulttext .= '</ul></li>';
                   }
               }
               $resulttext .= '</ul>';
           } 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 get_lti_id {
       my ($domain,$consumer) = @_;
       # get lock on lti db
       my $lockhash = {
                         lock => $env{'user.name'}.
                                 ':'.$env{'user.domain'},
                      };
       my $tries = 0;
       my $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);
       my ($id,$error);
   
       while (($gotlock ne 'ok') && ($tries<10)) {
           $tries ++;
           sleep (0.1);
           $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);
       }
       if ($gotlock eq 'ok') {
           my %currids = &Apache::lonnet::dump_dom('lti',$domain);
           if ($currids{'lock'}) {
               delete($currids{'lock'});
               if (keys(%currids)) {
                   my @curr = sort { $a <=> $b } keys(%currids);
                   if ($curr[-1] =~ /^\d+$/) {
                       $id = 1 + $curr[-1];
                   }
               } else {
                   $id = 1;
               }
               if ($id) {
                   unless (&Apache::lonnet::newput_dom('lti',{ $id => $consumer },$domain) eq 'ok') {
                       $error = 'nostore';
                   }
               } else {
                   $error = 'nonumber';
               }
           }
           my $dellockoutcome = &Apache::lonnet::del_dom('lti',['lock'],$domain);
       } else {
           $error = 'nolock';
       }
       return ($id,$error);
   }
   
 sub modify_autoenroll {  sub modify_autoenroll {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,%changes);      my ($resulttext,%changes);
Line 7796  sub modify_autoenroll { Line 13120  sub modify_autoenroll {
     my $autorun = &Apache::lonnet::auto_run(undef,$dom),      my $autorun = &Apache::lonnet::auto_run(undef,$dom),
     my %title = ( run => 'Auto-enrollment active',      my %title = ( run => 'Auto-enrollment active',
                   sender => 'Sender for notification messages',                    sender => 'Sender for notification messages',
                   coowners => 'Automatic assignment of co-ownership to instructors of record (institutional data)');                    coowners => 'Automatic assignment of co-ownership to instructors of record (institutional data)',
                     failsafe => 'Failsafe for no drops if institutional data missing for a section');
     my @offon = ('off','on');      my @offon = ('off','on');
     my $sender_uname = $env{'form.sender_uname'};      my $sender_uname = $env{'form.sender_uname'};
     my $sender_domain = $env{'form.sender_domain'};      my $sender_domain = $env{'form.sender_domain'};
Line 7806  sub modify_autoenroll { Line 13131  sub modify_autoenroll {
         $sender_domain = '';          $sender_domain = '';
     }      }
     my $coowners = $env{'form.autoassign_coowners'};      my $coowners = $env{'form.autoassign_coowners'};
       my $failsafe = $env{'form.autoenroll_failsafe'};
       $failsafe =~ s{^\s+|\s+$}{}g;
       if ($failsafe =~ /\D/) {
           undef($failsafe);
       }
     my %autoenrollhash =  (      my %autoenrollhash =  (
                        autoenroll => { 'run' => $env{'form.autoenroll_run'},                         autoenroll => { 'run' => $env{'form.autoenroll_run'},
                                        'sender_uname' => $sender_uname,                                         'sender_uname' => $sender_uname,
                                        'sender_domain' => $sender_domain,                                         'sender_domain' => $sender_domain,
                                        'co-owners' => $coowners,                                         'co-owners' => $coowners,
                                          'autofailsafe' => $failsafe,
                                 }                                  }
                      );                       );
     my $putresult = &Apache::lonnet::put_dom('configuration',\%autoenrollhash,      my $putresult = &Apache::lonnet::put_dom('configuration',\%autoenrollhash,
Line 7837  sub modify_autoenroll { Line 13168  sub modify_autoenroll {
             }              }
         } elsif ($coowners) {          } elsif ($coowners) {
             $changes{'coowners'} = 1;              $changes{'coowners'} = 1;
         }                }
           if ($currautoenroll{'autofailsafe'} ne $failsafe) {
               $changes{'autofailsafe'} = 1;
           }
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
             $resulttext = &mt('Changes made:').'<ul>';              $resulttext = &mt('Changes made:').'<ul>';
             if ($changes{'run'}) {              if ($changes{'run'}) {
Line 7857  sub modify_autoenroll { Line 13191  sub modify_autoenroll {
                     $lastactref->{'domainconfig'} = 1;                      $lastactref->{'domainconfig'} = 1;
                 }                  }
             }              }
               if ($changes{'autofailsafe'}) {
                   if ($failsafe ne '') {
                       $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section set to: [_1]',$failsafe).'</li>';
                   } else {
                       $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section: deleted');
                   }
                   &Apache::lonnet::get_domain_defaults($dom,1);
                   if (ref($lastactref) eq 'HASH') {
                       $lastactref->{'domdefaults'} = 1;
                   }
               }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
         } else {          } else {
             $resulttext = &mt('No changes made to auto-enrollment settings');              $resulttext = &mt('No changes made to auto-enrollment settings');
Line 8072  sub modify_autocreate { Line 13417  sub modify_autocreate {
         $newvals{$item} = 0 if ($newvals{$item} eq '');          $newvals{$item} = 0 if ($newvals{$item} eq '');
     }      }
     $newvals{'xmldc'} = $env{'form.autocreate_xmldc'};      $newvals{'xmldc'} = $env{'form.autocreate_xmldc'};
     my %domcoords = &get_active_dcs($dom);      my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']);
     unless (exists($domcoords{$newvals{'xmldc'}})) {      unless (exists($domcoords{$newvals{'xmldc'}})) {
         $newvals{'xmldc'} = '';          $newvals{'xmldc'} = '';
     }       } 
Line 8129  sub modify_autocreate { Line 13474  sub modify_autocreate {
 }  }
   
 sub modify_directorysrch {  sub modify_directorysrch {
     my ($dom,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,%changes);      my ($resulttext,%changes);
     my %currdirsrch;      my %currdirsrch;
     if (ref($domconfig{'directorysrch'}) eq 'HASH') {      if (ref($domconfig{'directorysrch'}) eq 'HASH') {
Line 8137  sub modify_directorysrch { Line 13482  sub modify_directorysrch {
             $currdirsrch{$key} = $domconfig{'directorysrch'}{$key};              $currdirsrch{$key} = $domconfig{'directorysrch'}{$key};
         }          }
     }      }
     my %title = ( available => 'Directory search available',      my %title = ( available => 'Institutional directory search available',
                   localonly => 'Other domains can search',                    localonly => 'Other domains can search institution',
                     lcavailable => 'LON-CAPA directory search available',
                     lclocalonly => 'Other domains can search LON-CAPA domain',
                   searchby => 'Search types',                    searchby => 'Search types',
                   searchtypes => 'Search latitude');                    searchtypes => 'Search latitude');
     my @offon = ('off','on');      my @offon = ('off','on');
Line 8212  sub modify_directorysrch { Line 13559  sub modify_directorysrch {
     my %dirsrch_hash =  (      my %dirsrch_hash =  (
             directorysrch => { available => $env{'form.dirsrch_available'},              directorysrch => { available => $env{'form.dirsrch_available'},
                                cansearch => \@cansearch,                                 cansearch => \@cansearch,
                                localonly => $env{'form.dirsrch_localonly'},                                 localonly => $env{'form.dirsrch_instlocalonly'},
                                  lclocalonly => $env{'form.dirsrch_domlocalonly'},
                                  lcavailable => $env{'form.dirsrch_domavailable'},
                                searchby => \@searchby,                                 searchby => \@searchby,
                                searchtypes => \@searchtypes,                                 searchtypes => \@searchtypes,
                              }                               }
Line 8229  sub modify_directorysrch { Line 13578  sub modify_directorysrch {
                 $changes{'available'} = 1;                  $changes{'available'} = 1;
             }              }
         }          }
           if (exists($currdirsrch{'lcavailable'})) {
               if ($currdirsrch{'lcavailable'} ne $env{'form.dirsrch_domavailable'}) {
                   $changes{'lcavailable'} = 1;
               }
           } else {
               if ($env{'form.dirsrch_lcavailable'} eq '1') {
                   $changes{'lcavailable'} = 1;
               }
           }
         if (exists($currdirsrch{'localonly'})) {          if (exists($currdirsrch{'localonly'})) {
              if ($currdirsrch{'localonly'} ne $env{'form.dirsrch_localonly'}) {              if ($currdirsrch{'localonly'} ne $env{'form.dirsrch_instlocalonly'}) {
                  $changes{'localonly'} = 1;                  $changes{'localonly'} = 1;
              }              }
         } else {          } else {
             if ($env{'form.dirsrch_localonly'} eq '1') {              if ($env{'form.dirsrch_instlocalonly'} eq '1') {
                 $changes{'localonly'} = 1;                  $changes{'localonly'} = 1;
             }              }
         }          }
           if (exists($currdirsrch{'lclocalonly'})) {
               if ($currdirsrch{'lclocalonly'} ne $env{'form.dirsrch_domlocalonly'}) {
                   $changes{'lclocalonly'} = 1;
               }
           } else {
               if ($env{'form.dirsrch_domlocalonly'} eq '1') {
                   $changes{'lclocalonly'} = 1;
               }
           }
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
             $resulttext = &mt('Changes made:').'<ul>';              $resulttext = &mt('Changes made:').'<ul>';
             if ($changes{'available'}) {              if ($changes{'available'}) {
                 $resulttext .= '<li>'.&mt("$title{'available'} set to: $offon[$env{'form.dirsrch_available'}]").'</li>';                  $resulttext .= '<li>'.&mt("$title{'available'} set to: $offon[$env{'form.dirsrch_available'}]").'</li>';
             }              }
               if ($changes{'lcavailable'}) {
                   $resulttext .= '<li>'.&mt("$title{'lcavailable'} set to: $offon[$env{'form.dirsrch_domavailable'}]").'</li>';
               }
             if ($changes{'localonly'}) {              if ($changes{'localonly'}) {
                 $resulttext .= '<li>'.&mt("$title{'localonly'} set to: $otherdoms[$env{'form.dirsrch_localonly'}]").'</li>';                  $resulttext .= '<li>'.&mt("$title{'localonly'} set to: $otherdoms[$env{'form.dirsrch_instlocalonly'}]").'</li>';
               }
               if ($changes{'lclocalonly'}) {
                   $resulttext .= '<li>'.&mt("$title{'lclocalonly'} set to: $otherdoms[$env{'form.dirsrch_domlocalonly'}]").'</li>';
             }              }
   
             if (ref($changes{'cansearch'}) eq 'ARRAY') {              if (ref($changes{'cansearch'}) eq 'ARRAY') {
                 my $chgtext;                  my $chgtext;
                 if (ref($usertypes) eq 'HASH') {                  if (ref($usertypes) eq 'HASH') {
Line 8296  sub modify_directorysrch { Line 13668  sub modify_directorysrch {
                 $resulttext .= '<li>'.&mt($title{'searchtypes'}.' set to: "[_1]"',$chgtext).'</li>';                  $resulttext .= '<li>'.&mt($title{'searchtypes'}.' set to: "[_1]"',$chgtext).'</li>';
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
               &Apache::lonnet::do_cache_new('directorysrch',$dom,$dirsrch_hash{'directorysrch'},3600);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'directorysrch'} = 1;
               }
         } else {          } else {
             $resulttext = &mt('No changes made to institution directory search settings');              $resulttext = &mt('No changes made to directory search settings');
         }          }
     } else {      } else {
         $resulttext = '<span class="LC_error">'.          $resulttext = '<span class="LC_error">'.
Line 8314  sub modify_contacts { Line 13690  sub modify_contacts {
             $currsetting{$key} = $domconfig{'contacts'}{$key};              $currsetting{$key} = $domconfig{'contacts'}{$key};
         }          }
     }      }
     my (%others,%to,%bcc);      my (%others,%to,%bcc,%includestr,%includeloc);
     my @contacts = ('supportemail','adminemail');      my @contacts = ('supportemail','adminemail');
     my @mailings = ('errormail','packagesmail','helpdeskmail','lonstatusmail',      my @mailings = ('errormail','packagesmail','helpdeskmail','otherdomsmail',
                     'requestsmail','updatesmail','idconflictsmail');                      'lonstatusmail','requestsmail','updatesmail','idconflictsmail','hostipmail');
     my @toggles = ('reporterrors','reportupdates');      my @toggles = ('reporterrors','reportupdates','reportstatus');
       my @lonstatus = ('threshold','sysmail','weights','excluded');
       my ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields();
     foreach my $type (@mailings) {      foreach my $type (@mailings) {
         @{$newsetting{$type}} =           @{$newsetting{$type}} = 
             &Apache::loncommon::get_env_multiple('form.'.$type);              &Apache::loncommon::get_env_multiple('form.'.$type);
Line 8328  sub modify_contacts { Line 13706  sub modify_contacts {
             } else {              } else {
                 $contacts_hash{contacts}{$type}{$item} = 0;                  $contacts_hash{contacts}{$type}{$item} = 0;
             }              }
         }            }
         $others{$type} = $env{'form.'.$type.'_others'};          $others{$type} = $env{'form.'.$type.'_others'};
         $contacts_hash{contacts}{$type}{'others'} = $others{$type};          $contacts_hash{contacts}{$type}{'others'} = $others{$type};
         if ($type eq 'helpdeskmail') {          if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
             $bcc{$type} = $env{'form.'.$type.'_bcc'};              $bcc{$type} = $env{'form.'.$type.'_bcc'};
             $contacts_hash{contacts}{$type}{'bcc'} = $bcc{$type};              $contacts_hash{contacts}{$type}{'bcc'} = $bcc{$type};
               if (($env{'form.'.$type.'_includestr'} ne '') && ($env{'form.'.$type.'_includeloc'} =~ /^s|b$/)) {
                   $includestr{$type} = $env{'form.'.$type.'_includestr'};
                   $includeloc{$type} = $env{'form.'.$type.'_includeloc'};
                   $contacts_hash{contacts}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type});
               }
         }          }
     }      }
     foreach my $item (@contacts) {      foreach my $item (@contacts) {
Line 8345  sub modify_contacts { Line 13728  sub modify_contacts {
             $contacts_hash{'contacts'}{$item} = $env{'form.'.$item};              $contacts_hash{'contacts'}{$item} = $env{'form.'.$item};
         }          }
     }      }
       my ($lonstatus_defs,$lonstatus_names) = &Apache::loncommon::lon_status_items();
       foreach my $item (@lonstatus) {
           if ($item eq 'excluded') {
               my (%serverhomes,@excluded);
               map { $serverhomes{$_} = 1; } values(%Apache::lonnet::serverhomeIDs);
               my @possexcluded = &Apache::loncommon::get_env_multiple('form.errorexcluded');
               if (@possexcluded) {
                   foreach my $id (sort(@possexcluded)) {
                       if ($serverhomes{$id}) {
                           push(@excluded,$id);
                       }
                   }
               }
               if (@excluded) {
                   $contacts_hash{'contacts'}{'lonstatus'}{$item} = \@excluded;
               }
           } elsif ($item eq 'weights') {
               foreach my $type ('E','W','N') {
                   $env{'form.error'.$item.'_'.$type} =~ s/^\s+|\s+$//g;
                   if ($env{'form.error'.$item.'_'.$type} =~ /^\d+$/) {
                       unless ($env{'form.error'.$item.'_'.$type} == $lonstatus_defs->{$type}) {
                           $contacts_hash{'contacts'}{'lonstatus'}{$item}{$type} =
                               $env{'form.error'.$item.'_'.$type};
                       }
                   }
               }
           } elsif (($item eq 'threshold') || ($item eq 'sysmail')) {
               $env{'form.error'.$item} =~ s/^\s+|\s+$//g;
               if ($env{'form.error'.$item} =~ /^\d+$/) {
                   unless ($env{'form.error'.$item} == $lonstatus_defs->{$item}) {
                       $contacts_hash{'contacts'}{'lonstatus'}{$item} = $env{'form.error'.$item};
                   }
               }
           }
       }
       if ((ref($fields) eq 'ARRAY') && (ref($possoptions) eq 'HASH')) {
           foreach my $field (@{$fields}) {
               if (ref($possoptions->{$field}) eq 'ARRAY') {
                   my $value = $env{'form.helpform_'.$field};
                   $value =~ s/^\s+|\s+$//g;
                   if (grep(/^\Q$value\E$/,@{$possoptions->{$field}})) {
                       $contacts_hash{'contacts'}{'helpform'}{$field} = $value;
                       if ($field eq 'screenshot') {
                           $env{'form.helpform_maxsize'} =~ s/^\s+|\s+$//g;
                           if ($env{'form.helpform_maxsize'} =~ /^\d+\.?\d*$/) {
                               $contacts_hash{'contacts'}{'helpform'}{'maxsize'} = $env{'form.helpform_maxsize'};
                           }
                       }
                   }
               }
           }
       }
       my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
       my (@statuses,%usertypeshash,@overrides);
       if ((ref($types) eq 'ARRAY') && (@{$types} > 0)) {
           @statuses = @{$types};
           if (ref($usertypes) eq 'HASH') {
               %usertypeshash = %{$usertypes};
           }
       }
       if (@statuses) {
           my @possoverrides = &Apache::loncommon::get_env_multiple('form.overrides');
           foreach my $type (@possoverrides) {
               if (($type ne '') && (grep(/^\Q$type\E$/,@statuses))) {
                   push(@overrides,$type);
               }
           }
           if (@overrides) {
               foreach my $type (@overrides) {
                   my @standard = &Apache::loncommon::get_env_multiple('form.override_'.$type);
                   foreach my $item (@contacts) {
                       if (grep(/^\Q$item\E$/,@standard)) {
                           $contacts_hash{'contacts'}{'overrides'}{$type}{$item} = 1;
                           $newsetting{'override_'.$type}{$item} = 1;
                       } else {
                           $contacts_hash{'contacts'}{'overrides'}{$type}{$item} = 0;
                           $newsetting{'override_'.$type}{$item} = 0;
                       }
                   }
                   $contacts_hash{'contacts'}{'overrides'}{$type}{'others'} = $env{'form.override_'.$type.'_others'};
                   $contacts_hash{'contacts'}{'overrides'}{$type}{'bcc'} = $env{'form.override_'.$type.'_bcc'};
                   $newsetting{'override_'.$type}{'others'} = $env{'form.override_'.$type.'_others'};
                   $newsetting{'override_'.$type}{'bcc'} = $env{'form.override_'.$type.'_bcc'};
                   if (($env{'form.override_'.$type.'_includestr'} ne '') && ($env{'form.override_'.$type.'_includeloc'} =~ /^s|b$/)) {
                       $includestr{$type} = $env{'form.override_'.$type.'_includestr'};
                       $includeloc{$type} = $env{'form.override_'.$type.'_includeloc'};
                       $contacts_hash{'contacts'}{'overrides'}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type});
                       $newsetting{'override_'.$type}{'include'} = $contacts_hash{'contacts'}{'overrides'}{$type}{'include'};
                   }
               }     
           }
       }
     if (keys(%currsetting) > 0) {      if (keys(%currsetting) > 0) {
         foreach my $item (@contacts) {          foreach my $item (@contacts) {
             if ($to{$item} ne $currsetting{$item}) {              if ($to{$item} ne $currsetting{$item}) {
Line 8364  sub modify_contacts { Line 13839  sub modify_contacts {
             if ($others{$type} ne $currsetting{$type}{'others'}) {              if ($others{$type} ne $currsetting{$type}{'others'}) {
                 push(@{$changes{$type}},'others');                  push(@{$changes{$type}},'others');
             }              }
             if ($type eq 'helpdeskmail') {                 if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
                 if ($bcc{$type} ne $currsetting{$type}{'bcc'}) {                  if ($bcc{$type} ne $currsetting{$type}{'bcc'}) {
                     push(@{$changes{$type}},'bcc');                       push(@{$changes{$type}},'bcc'); 
                 }                  }
                   my ($currloc,$currstr) = split(/:/,$currsetting{$type}{'include'},2);
                   if (($includeloc{$type} ne $currloc) || (&escape($includestr{$type}) ne $currstr)) {
                       push(@{$changes{$type}},'include');
                   }
               }
           }
           if (ref($fields) eq 'ARRAY') {
               if (ref($currsetting{'helpform'}) eq 'HASH') {
                   foreach my $field (@{$fields}) {
                       if ($currsetting{'helpform'}{$field} ne $contacts_hash{'contacts'}{'helpform'}{$field}) {
                           push(@{$changes{'helpform'}},$field);
                       }
                       if (($field eq 'screenshot') && ($contacts_hash{'contacts'}{'helpform'}{'screenshot'} ne 'no')) {
                           if ($currsetting{'helpform'}{'maxsize'} ne $contacts_hash{'contacts'}{'helpform'}{'maxsize'}) {
                               push(@{$changes{'helpform'}},'maxsize');
                           }
                       }
                   }
               } else {
                   foreach my $field (@{$fields}) {
                       if ($contacts_hash{'contacts'}{'helpform'}{$field} ne 'yes') {
                           push(@{$changes{'helpform'}},$field);
                       }
                       if (($field eq 'screenshot') && ($contacts_hash{'contacts'}{'helpform'}{'screenshot'} ne 'no')) {
                           if ($contacts_hash{'contacts'}{'helpform'}{'maxsize'} != 1) {
                               push(@{$changes{'helpform'}},'maxsize');
                           }
                       }
                   }
               }
           }
           if (@statuses) {
               if (ref($currsetting{'overrides'}) eq 'HASH') { 
                   foreach my $key (keys(%{$currsetting{'overrides'}})) {
                       if (ref($currsetting{'overrides'}{$key}) eq 'HASH') {
                           if (ref($newsetting{'override_'.$key}) eq 'HASH') {
                               foreach my $item (@contacts,'bcc','others','include') {
                                   if ($currsetting{'overrides'}{$key}{$item} ne $newsetting{'override_'.$key}{$item}) { 
                                       push(@{$changes{'overrides'}},$key);
                                       last;
                                   }
                               }
                           } else {
                               push(@{$changes{'overrides'}},$key);
                           }
                       }
                   }
                   foreach my $key (@overrides) {
                       unless (exists($currsetting{'overrides'}{$key})) {
                           push(@{$changes{'overrides'}},$key);
                       }
                   }
               } else {
                   foreach my $key (@overrides) {
                       push(@{$changes{'overrides'}},$key); 
                   }
               }
           }
           if (ref($currsetting{'lonstatus'}) eq 'HASH') {
               foreach my $key ('excluded','weights','threshold','sysmail') {
                   if ($key eq 'excluded') {
                       if ((ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') &&
                           (ref($contacts_hash{contacts}{lonstatus}{excluded}) eq 'ARRAY')) {
                           if ((ref($currsetting{'lonstatus'}{$key}) eq 'ARRAY') &&
                               (@{$currsetting{'lonstatus'}{$key}})) {
                               my @diffs =
                                   &Apache::loncommon::compare_arrays($contacts_hash{contacts}{lonstatus}{excluded},
                                                                      $currsetting{'lonstatus'}{$key});
                               if (@diffs) {
                                   push(@{$changes{'lonstatus'}},$key);
                               }
                           } elsif (@{$contacts_hash{contacts}{lonstatus}{excluded}}) {
                               push(@{$changes{'lonstatus'}},$key);
                           }
                       } elsif ((ref($currsetting{'lonstatus'}{$key}) eq 'ARRAY') &&
                                (@{$currsetting{'lonstatus'}{$key}})) {
                           push(@{$changes{'lonstatus'}},$key);
                       }
                   } elsif ($key eq 'weights') {
                       if ((ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') &&
                           (ref($contacts_hash{contacts}{lonstatus}{$key}) eq 'HASH')) {
                           if (ref($currsetting{'lonstatus'}{$key}) eq 'HASH') {
                               foreach my $type ('E','W','N','U') {
                                   unless ($contacts_hash{contacts}{lonstatus}{$key}{$type} eq
                                           $currsetting{'lonstatus'}{$key}{$type}) {
                                       push(@{$changes{'lonstatus'}},$key);
                                       last;
                                   }
                               }
                           } else {
                               foreach my $type ('E','W','N','U') {
                                   if ($contacts_hash{contacts}{lonstatus}{$key}{$type} ne '') {
                                       push(@{$changes{'lonstatus'}},$key);
                                       last;
                                   }
                               }
                           }
                       } elsif (ref($currsetting{'lonstatus'}{$key}) eq 'HASH') {
                           foreach my $type ('E','W','N','U') {
                               if ($currsetting{'lonstatus'}{$key}{$type} ne '') {
                                   push(@{$changes{'lonstatus'}},$key);
                                   last;
                               }
                           }
                       }
                   } elsif (($key eq 'threshold') || ($key eq 'sysmail')) {
                       if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') {
                           if ($currsetting{'lonstatus'}{$key} =~ /^\d+$/) {
                               if ($currsetting{'lonstatus'}{$key} != $contacts_hash{contacts}{lonstatus}{$key}) {
                                   push(@{$changes{'lonstatus'}},$key);
                               }
                           } elsif ($contacts_hash{contacts}{lonstatus}{$key} =~ /^\d+$/) {
                               push(@{$changes{'lonstatus'}},$key);
                           }
                       } elsif ($currsetting{'lonstatus'}{$key} =~ /^\d+$/) {
                           push(@{$changes{'lonstatus'}},$key);
                       }
                   }
               }
           } else {
               if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') {
                   foreach my $key ('excluded','weights','threshold','sysmail') {
                       if (exists($contacts_hash{contacts}{lonstatus}{$key})) {
                           push(@{$changes{'lonstatus'}},$key);
                       }
                   }
             }              }
         }          }
     } else {      } else {
Line 8377  sub modify_contacts { Line 13978  sub modify_contacts {
         $default{'errormail'} = 'adminemail';          $default{'errormail'} = 'adminemail';
         $default{'packagesmail'} = 'adminemail';          $default{'packagesmail'} = 'adminemail';
         $default{'helpdeskmail'} = 'supportemail';          $default{'helpdeskmail'} = 'supportemail';
           $default{'otherdomsmail'} = 'supportemail';
         $default{'lonstatusmail'} = 'adminemail';          $default{'lonstatusmail'} = 'adminemail';
         $default{'requestsmail'} = 'adminemail';          $default{'requestsmail'} = 'adminemail';
         $default{'updatesmail'} = 'adminemail';          $default{'updatesmail'} = 'adminemail';
           $default{'hostipmail'} = 'adminemail';
         foreach my $item (@contacts) {          foreach my $item (@contacts) {
            if ($to{$item} ne $default{$item}) {             if ($to{$item} ne $default{$item}) {
               $changes{$item} = 1;                 $changes{$item} = 1;
            }             }
         }          }
         foreach my $type (@mailings) {          foreach my $type (@mailings) {
             if ((@{$newsetting{$type}} != 1) || ($newsetting{$type}[0] ne $default{$type})) {              if ((@{$newsetting{$type}} != 1) || ($newsetting{$type}[0] ne $default{$type})) {
                  
                 push(@{$changes{$type}},@{$newsetting{$type}});                  push(@{$changes{$type}},@{$newsetting{$type}});
             }              }
             if ($others{$type} ne '') {              if ($others{$type} ne '') {
                 push(@{$changes{$type}},'others');                  push(@{$changes{$type}},'others');
             }              }
             if ($type eq 'helpdeskmail') {              if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
                 if ($bcc{$type} ne '') {                  if ($bcc{$type} ne '') {
                     push(@{$changes{$type}},'bcc');                      push(@{$changes{$type}},'bcc');
                 }                  }
                   if (($includeloc{$type} =~ /^b|s$/) && ($includestr{$type} ne '')) {
                       push(@{$changes{$type}},'include');
                   }
               }
           }
           if (ref($fields) eq 'ARRAY') {
               foreach my $field (@{$fields}) {
                   if ($contacts_hash{'contacts'}{'helpform'}{$field} ne 'yes') {
                       push(@{$changes{'helpform'}},$field);
                   }
                   if (($field eq 'screenshot') && ($contacts_hash{'contacts'}{'helpform'}{'screenshot'} ne 'no')) {
                       if ($contacts_hash{'contacts'}{'helpform'}{'maxsize'} != 1) {
                           push(@{$changes{'helpform'}},'maxsize');
                       }
                   }
               }
           }
           if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') {
               foreach my $key ('excluded','weights','threshold','sysmail') {
                   if (exists($contacts_hash{contacts}{lonstatus}{$key})) {
                       push(@{$changes{'lonstatus'}},$key);
                   }
             }              }
         }          }
     }      }
Line 8428  sub modify_contacts { Line 14052  sub modify_contacts {
             }              }
             foreach my $type (@mailings) {              foreach my $type (@mailings) {
                 if (ref($changes{$type}) eq 'ARRAY') {                  if (ref($changes{$type}) eq 'ARRAY') {
                     $resulttext .= '<li>'.$titles->{$type}.': ';                      if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
                           $resulttext .= '<li>'.$titles->{$type}.' -- '.&mt('sent to').': ';
                       } else {
                           $resulttext .= '<li>'.$titles->{$type}.': ';
                       }
                     my @text;                      my @text;
                     foreach my $item (@{$newsetting{$type}}) {                      foreach my $item (@{$newsetting{$type}}) {
                         push(@text,$short_titles->{$item});                          push(@text,$short_titles->{$item});
Line 8436  sub modify_contacts { Line 14064  sub modify_contacts {
                     if ($others{$type} ne '') {                      if ($others{$type} ne '') {
                         push(@text,$others{$type});                          push(@text,$others{$type});
                     }                      }
                     $resulttext .= '<span class="LC_cusr_emph">'.                      if (@text) {
                                    join(', ',@text).'</span>';                          $resulttext .= '<span class="LC_cusr_emph">'.
                     if ($type eq 'helpdeskmail') {                                         join(', ',@text).'</span>';
                       }
                       if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
                         if ($bcc{$type} ne '') {                          if ($bcc{$type} ne '') {
                             $resulttext .= '&nbsp;'.&mt('with Bcc to').': <span class="LC_cusr_emph">'.$bcc{$type}.'</span>';                              my $bcctext;
                               if (@text) {
                                   $bcctext = '&nbsp;'.&mt('with Bcc to');
                               } else {
                                   $bcctext = '(Bcc)';
                               }
                               $resulttext .= $bcctext.': <span class="LC_cusr_emph">'.$bcc{$type}.'</span>';
                           } elsif (!@text) {
                               $resulttext .= &mt('No one');
                           }   
                           if ($includestr{$type} ne '') {
                               if ($includeloc{$type} eq 'b') {
                                   $resulttext .= '<br />'.&mt('Text automatically added to e-mail body:').' '.$includestr{$type};
                               } elsif ($includeloc{$type} eq 's') {
                                   $resulttext .= '<br />'.&mt('Text automatically added to e-mail subject:').' '.$includestr{$type};
                               }
                         }                          }
                       } elsif (!@text) {
                           $resulttext .= &mt('No recipients');
                     }                      }
                     $resulttext .= '</li>';                      $resulttext .= '</li>';
                 }                  }
             }              }
               if (ref($changes{'overrides'}) eq 'ARRAY') {
                   my @deletions;
                   foreach my $type (@{$changes{'overrides'}}) {
                       if ($usertypeshash{$type}) {
                           if (grep(/^\Q$type\E/,@overrides)) {
                               $resulttext .= '<li>'.&mt("Overrides based on requester's affiliation set for [_1]",
                                                         $usertypeshash{$type}).'<ul><li>';
                               if (ref($newsetting{'override_'.$type}) eq 'HASH') {
                                   my @text;
                                   foreach my $item (@contacts) {
                                       if ($newsetting{'override_'.$type}{$item}) { 
                                           push(@text,$short_titles->{$item});
                                       }
                                   }
                                   if ($newsetting{'override_'.$type}{'others'} ne '') {
                                       push(@text,$newsetting{'override_'.$type}{'others'});
                                   }
     
                                   if (@text) {
                                       $resulttext .= &mt('Helpdesk e-mail sent to: [_1]',
                                                          '<span class="LC_cusr_emph">'.join(', ',@text).'</span>');
                                   }
                                   if ($newsetting{'override_'.$type}{'bcc'} ne '') {
                                       my $bcctext;
                                       if (@text) {
                                           $bcctext = '&nbsp;'.&mt('with Bcc to');
                                       } else {
                                           $bcctext = '(Bcc)';
                                       }
                                       $resulttext .= $bcctext.': <span class="LC_cusr_emph">'.$newsetting{'override_'.$type}{'bcc'}.'</span>';
                                   } elsif (!@text) {
                                        $resulttext .= &mt('Helpdesk e-mail sent to no one');
                                   }
                                   $resulttext .= '</li>';
                                   if ($newsetting{'override_'.$type}{'include'} ne '') {
                                       my ($loc,$str) = split(/:/,$newsetting{'override_'.$type}{'include'});
                                       if ($loc eq 'b') {
                                           $resulttext .= '<li>'.&mt('Text automatically added to e-mail body:').' '.&unescape($str).'</li>';
                                       } elsif ($loc eq 's') {
                                           $resulttext .= '<li>'.&mt('Text automatically added to e-mail subject:').' '.&unescape($str).'</li>';
                                       }
                                   }
                               }
                               $resulttext .= '</li></ul></li>';
                           } else {
                               push(@deletions,$usertypeshash{$type});
                           }
                       }
                   }
                   if (@deletions) {
                       $resulttext .= '<li>'.&mt("Overrides based on requester's affiliation discontinued for: [_1]",
                                                 join(', ',@deletions)).'</li>';
                   }
               }
             my @offon = ('off','on');              my @offon = ('off','on');
               my $corelink = &core_link_msu();
             if ($changes{'reporterrors'}) {              if ($changes{'reporterrors'}) {
                 $resulttext .= '<li>'.                  $resulttext .= '<li>'.
                                &mt('E-mail error reports to [_1] set to "'.                                 &mt('E-mail error reports to [_1] set to "'.
                                    $offon[$env{'form.reporterrors'}].'".',                                     $offon[$env{'form.reporterrors'}].'".',
                                    &Apache::loncommon::modal_link('http://loncapa.org/core.html',                                     $corelink).
                                        &mt('LON-CAPA core group - MSU'),600,500)).  
                                '</li>';                                 '</li>';
             }              }
             if ($changes{'reportupdates'}) {              if ($changes{'reportupdates'}) {
                 $resulttext .= '<li>'.                  $resulttext .= '<li>'.
                                 &mt('E-mail record of completed LON-CAPA updates to [_1] set to "'.                                  &mt('E-mail record of completed LON-CAPA updates to [_1] set to "'.
                                     $offon[$env{'form.reportupdates'}].'".',                                      $offon[$env{'form.reportupdates'}].'".',
                                     &Apache::loncommon::modal_link('http://loncapa.org/core.html',                                      $corelink).
                                         &mt('LON-CAPA core group - MSU'),600,500)).                                  '</li>';
               }
               if ($changes{'reportstatus'}) {
                   $resulttext .= '<li>'.
                                   &mt('E-mail status if errors above threshold to [_1] set to "'.
                                       $offon[$env{'form.reportstatus'}].'".',
                                       $corelink).
                                 '</li>';                                  '</li>';
             }              }
               if (ref($changes{'lonstatus'}) eq 'ARRAY') {
                   $resulttext .= '<li>'.
                                  &mt('Nightly status check e-mail settings').':<ul>';
                   my (%defval,%use_def,%shown);
                   $defval{'threshold'} = $lonstatus_defs->{'threshold'};
                   $defval{'sysmail'} = $lonstatus_defs->{'sysmail'};
                   $defval{'weights'} =
                       join(', ',map { $lonstatus_names->{$_}.'='.$lonstatus_defs->{$_}; } ('E','W','N','U'));
                   $defval{'excluded'} = &mt('None');
                   if (ref($contacts_hash{'contacts'}{'lonstatus'}) eq 'HASH') {
                       foreach my $item ('threshold','sysmail','weights','excluded') {
                           if (exists($contacts_hash{'contacts'}{'lonstatus'}{$item})) {
                               if (($item eq 'threshold') || ($item eq 'sysmail')) {
                                   $shown{$item} = $contacts_hash{'contacts'}{'lonstatus'}{$item};
                               } elsif ($item eq 'weights') {
                                   if (ref($contacts_hash{'contacts'}{'lonstatus'}{$item}) eq 'HASH') {
                                       foreach my $type ('E','W','N','U') {
                                           $shown{$item} .= $lonstatus_names->{$type}.'=';
                                           if (exists($contacts_hash{'contacts'}{'lonstatus'}{$item}{$type})) {
                                               $shown{$item} .= $contacts_hash{'contacts'}{'lonstatus'}{$item}{$type};
                                           } else {
                                               $shown{$item} .= $lonstatus_defs->{$type};
                                           }
                                           $shown{$item} .= ', ';
                                       }
                                       $shown{$item} =~ s/, $//;
                                   } else {
                                       $shown{$item} = $defval{$item};
                                   }
                               } elsif ($item eq 'excluded') {
                                   if (ref($contacts_hash{'contacts'}{'lonstatus'}{$item}) eq 'ARRAY') {
                                       $shown{$item} = join(', ',@{$contacts_hash{'contacts'}{'lonstatus'}{$item}});
                                   } else {
                                       $shown{$item} = $defval{$item};
                                   }
                               }
                           } else {
                               $shown{$item} = $defval{$item};
                           }
                       }
                   } else {
                       foreach my $item ('threshold','weights','excluded','sysmail') {
                           $shown{$item} = $defval{$item};
                       }
                   }
                   foreach my $item ('threshold','weights','excluded','sysmail') {
                       $resulttext .= '<li>'.&mt($titles->{'error'.$item}.' -- [_1]',
                                             $shown{$item}).'</li>';
                   }
                   $resulttext .= '</ul></li>';
               }
               if ((ref($changes{'helpform'}) eq 'ARRAY') && (ref($fields) eq 'ARRAY')) {
                   my (@optional,@required,@unused,$maxsizechg);
                   foreach my $field (@{$changes{'helpform'}}) {
                       if ($field eq 'maxsize') {
                           $maxsizechg = 1;
                           next;
                       }
                       if ($contacts_hash{'contacts'}{'helpform'}{$field} eq 'yes') {
                           push(@optional,$field);
                       } elsif ($contacts_hash{'contacts'}{'helpform'}{$field} eq 'no') {
                           push(@unused,$field);
                       } elsif ($contacts_hash{'contacts'}{'helpform'}{$field} eq 'req') {
                           push(@required,$field);
                       }
                   }
                   if (@optional) {
                       $resulttext .= '<li>'.
                                      &mt('Help form fields changed to "Optional": [_1].',
                                          '<span class="LC_cusr_emph">'.join(', ',map { $fieldtitles->{$_}; } @optional)).'</span>'.
                                      '</li>';
                   }
                   if (@required) {
                       $resulttext .= '<li>'.
                                      &mt('Help form fields changed to "Required": [_1].',
                                          '<span class="LC_cusr_emph">'.join(', ',map { $fieldtitles->{$_}; } @required)).'</span>'.
                                      '</li>';
                   }
                   if (@unused) {
                       $resulttext .= '<li>'.
                                      &mt('Help form fields changed to "Not shown": [_1].',
                                          '<span class="LC_cusr_emph">'.join(', ',map { $fieldtitles->{$_}; } @unused)).'</span>'.
                                      '</li>';
                   }
                   if ($maxsizechg) {
                       $resulttext .= '<li>'.
                                      &mt('Max size for file uploaded to help form by logged-in user set to [_1] MB.',
                                          $contacts_hash{'contacts'}{'helpform'}{'maxsize'}).
                                      '</li>';
                   }
               }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
         } else {          } else {
             $resulttext = &mt('No changes made to contact information');              $resulttext = &mt('No changes made to contacts and form settings');
         }          }
     } else {      } else {
         $resulttext = '<span class="LC_error">'.          $resulttext = '<span class="LC_error">'.
Line 8474  sub modify_contacts { Line 14272  sub modify_contacts {
     return $resulttext;      return $resulttext;
 }  }
   
   sub modify_privacy {
       my ($dom,%domconfig) = @_;
       my ($resulttext,%current,%changes);
       if (ref($domconfig{'privacy'}) eq 'HASH') {
           %current = %{$domconfig{'privacy'}};
       }
       my @fields = ('lastname','firstname','middlename','generation','permanentemail','id');
       my @items = ('domain','author','course','community');
       my %names = &Apache::lonlocal::texthash (
                      domain => 'Assigned domain role(s)',
                      author => 'Assigned co-author role(s)',
                      course => 'Assigned course role(s)',
                      community => 'Assigned community role',
                   );
       my %roles = &Apache::lonlocal::texthash (
                      domain => 'Domain role',
                      author => 'Co-author role',
                      course => 'Course role',
                      community => 'Community role',
                   );
       my %titles = &Apache::lonlocal::texthash (
                     approval => 'Approval for role in different domain',
                     othdom   => 'User information available in other domain',
                     priv     => 'Information viewable by privileged user in same domain',
                     unpriv   => 'Information viewable by unprivileged user in same domain',
                     instdom  => 'Other domain shares institution/provider',
                     extdom   => 'Other domain has different institution/provider',
                     none     => 'Not allowed',
                     user     => 'User authorizes',
                     domain   => 'Domain Coordinator authorizes',
                     auto     => 'Unrestricted',
       );
       my %fieldnames = &Apache::lonlocal::texthash (
                           id => 'Student/Employee ID',
                           permanentemail => 'E-mail address',
                           lastname => 'Last Name',
                           firstname => 'First Name',
                           middlename => 'Middle Name',
                           generation => 'Generation',
       );
       my ($othertitle,$usertypes,$types) =
           &Apache::loncommon::sorted_inst_types($dom);
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
   
       my %privacyhash = (
                          'approval' => {
                                          instdom => {},
                                          extdom  => {},
                                        },
                          'othdom'   => {},
                          'priv'     => {},
                          'unpriv'   => {},
                         );
       foreach my $item (@items) {
           if (@instdoms > 1) {
               if ($env{'form.privacy_approval_instdom'.$item} =~ /^(none|user|domain|auto)$/) {
                   $privacyhash{'approval'}{'instdom'}{$item} = $env{'form.privacy_approval_instdom_'.$item};
               }
               if (ref($current{'approval'}) eq 'HASH') {
                   if (ref($current{'approval'}{'instdom'}) eq 'HASH') {
                       unless ($privacyhash{'approval'}{'instdom'}{$item} eq $current{'approval'}{'instdom'}{$item}) {
                           $changes{'approval'} = 1;
                       }
                   }
               } elsif ($privacyhash{'approval'}{'instdom'}{$item} ne 'auto') {
                   $changes{'approval'} = 1;
               }
           }
           if (keys(%by_location) > 0) {
               if ($env{'form.privacy_approval_extdom_'.$item} =~ /^(none|user|domain|auto)$/) {
                   $privacyhash{'approval'}{'extdom'}{$item} = $env{'form.privacy_approval_extdom_'.$item};
               }
               if (ref($current{'approval'}) eq 'HASH') {
                   if (ref($current{'approval'}{'extdom'}) eq 'HASH') {
                       unless ($privacyhash{'approval'}{'extdom'}{$item} eq $current{'approval'}{'extdom'}{$item}) {
                           $changes{'approval'} = 1;
                       }
                   }
               } elsif ($privacyhash{'approval'}{'extdom'}{$item} ne 'auto') {
                   $changes{'approval'} = 1;
               }
           }
           foreach my $status ('priv','unpriv') {
               my @possibles = sort(&Apache::loncommon::get_env_multiple('form.privacy_'.$status.'_'.$item));
               my @newvalues;
               foreach my $field (@possibles) {
                   if (grep(/^\Q$field\E$/,@fields)) {
                       $privacyhash{$status}{$item}{$field} = 1;
                       push(@newvalues,$field);
                   }
               }
               @newvalues = sort(@newvalues);
               if (ref($current{$status}) eq 'HASH') {
                   if (ref($current{$status}{$item}) eq 'HASH') {
                       my @currvalues = sort(keys(%{$current{$status}{$item}}));
                       my @diffs = &Apache::loncommon::compare_arrays(\@currvalues,\@newvalues);
                       if (@diffs > 0) {
                           $changes{$status} = 1;
                       }
                   }
               } else {
                   my @stdfields;
                   foreach my $field (@fields) {
                       if ($field eq 'id') {
                           next if ($status eq 'unpriv');
                           next if (($status eq 'priv') && ($item eq 'community'));
                       }
                       push(@stdfields,$field);
                   }
                   my @diffs = &Apache::loncommon::compare_arrays(\@stdfields,\@newvalues);
                   if (@diffs > 0) {
                       $changes{$status} = 1;
                   }
               }
           }
       }
       if ((@instdoms > 1) || (keys(%by_location) > 0)) {
           my @statuses;
           if (ref($types) eq 'ARRAY') {
               @statuses = @{$types};
           }
           foreach my $type (@statuses,'default') {
               my @possfields = &Apache::loncommon::get_env_multiple('form.privacy_othdom_'.$type);
               my @newvalues;
               foreach my $field (sort(@possfields)) {
                   if (grep(/^\Q$field\E$/,@fields)) {
                       $privacyhash{'othdom'}{$type}{$field} = 1;
                       push(@newvalues,$field);
                   }
               }
               @newvalues = sort(@newvalues);
               if (ref($current{'othdom'}) eq 'HASH') {
                   if (ref($current{'othdom'}{$type}) eq 'HASH') {
                       my @currvalues = sort(keys(%{$current{'othdom'}{$type}}));
                       my @diffs = &Apache::loncommon::compare_arrays(\@currvalues,\@newvalues);
                       if (@diffs > 0) {
                           $changes{'othdom'} = 1;
                       }
                   }
               } else {
                   my @stdfields = ('lastname','firstname','middlename','generation','permanentemail');
                   my @diffs = &Apache::loncommon::compare_arrays(\@stdfields,\@newvalues);
                   if (@diffs > 0) {
                       $changes{'othdom'} = 1;
                   }
               }
           }
       }
       my %confighash = (
                           privacy => \%privacyhash,
                        );
       my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,$dom);
       if ($putresult eq 'ok') {
           if (keys(%changes) > 0) {
               $resulttext = &mt('Changes made: ').'<ul>';
               foreach my $key ('approval','othdom','priv','unpriv') {
                   if ($changes{$key}) {
                       $resulttext .= '<li>'.$titles{$key}.':<ul>';
                       if ($key eq 'approval') {
                           if (keys(%{$privacyhash{$key}{instdom}})) {
                               $resulttext .= '<li>'.$titles{'instdom'}.'<ul>';
                               foreach my $item (@items) {
                                   $resulttext .=  '<li>'.$roles{$item}.': '.$titles{$privacyhash{$key}{instdom}{$item}}.'</li>';
                               }
                               $resulttext .= '</ul></li>';
                           }
                           if (keys(%{$privacyhash{$key}{extdom}})) {
                               $resulttext .= '<li>'.$titles{'extdom'}.'<ul>';
                               foreach my $item (@items) {
                                   $resulttext .=  '<li>'.$roles{$item}.': '.$titles{$privacyhash{$key}{extdom}{$item}}.'</li>';
                               }
                               $resulttext .= '</ul></li>';
                           }
                       } elsif ($key eq 'othdom') {
                           my @statuses;
                           if (ref($types) eq 'ARRAY') {
                               @statuses = @{$types};
                           }
                           if (ref($privacyhash{$key}) eq 'HASH') {
                               foreach my $status (@statuses,'default') {
                                   if ($status eq 'default') {
                                       $resulttext .= '<li>'.$othertitle.': ';
                                   } elsif (ref($usertypes) eq 'HASH') {
                                       $resulttext .= '<li>'.$usertypes->{$status}.': ';
                                   } else {
                                       next;
                                   }
                                   if (ref($privacyhash{$key}{$status}) eq 'HASH') {
                                       if (keys(%{$privacyhash{$key}{$status}})) {
                                           $resulttext .= join(', ', map { $fieldnames{$_}; } (sort(keys(%{$privacyhash{$key}{$status}}))));
                                       } else {
                                           $resulttext .= &mt('none');
                                       }
                                   }
                                   $resulttext .= '</li>';
                               }
                           }
                       } else {
                           foreach my $item (@items) {
                               if (ref($privacyhash{$key}{$item}) eq 'HASH') {
                                   $resulttext .= '<li>'.$names{$item}.': ';
                                   if (keys(%{$privacyhash{$key}{$item}})) {
                                       $resulttext .= join(', ', map { $fieldnames{$_}; } (sort(keys(%{$privacyhash{$key}{$item}}))));
                                   } else {
                                       $resulttext .= &mt('none');
                                   }
                                   $resulttext .= '</li>';
                               }
                           }
                       }
                       $resulttext .= '</ul></li>';
                   }
               }
           } else {
               $resulttext = &mt('No changes made to user information settings');
           }
       } else {
           $resulttext = '<span class="LC_error">'.
               &mt('An error occurred: [_1]',$putresult).'</span>';
       }
       return $resulttext;
   }
   
   sub modify_passwords {
       my ($r,$dom,$confname,$lastactref,%domconfig) = @_;
       my ($resulttext,%current,%changes,%newvalues,@oktypes,$errors,
           $updatedefaults,$updateconf);
       my $customfn = 'resetpw.html';
       if (ref($domconfig{'passwords'}) eq 'HASH') {
           %current = %{$domconfig{'passwords'}};
       }
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
       if (ref($types) eq 'ARRAY') {
           @oktypes = @{$types};
       }
       push(@oktypes,'default');
   
       my %titles = &Apache::lonlocal::texthash (
           intauth_cost   => 'Encryption cost for bcrypt (positive integer)',
           intauth_check  => 'Check bcrypt cost if authenticated',
           intauth_switch => 'Existing crypt-based switched to bcrypt on authentication',
           permanent      => 'Permanent e-mail address',
           critical       => 'Critical notification address',
           notify         => 'Notification address',
           min            => 'Minimum password length',
           max            => 'Maximum password length',
           chars          => 'Required characters',
           expire         => 'Password expiration (days)',
           numsaved       => 'Number of previous passwords to save',
           reset          => 'Resetting Forgotten Password',
           intauth        => 'Encryption of Stored Passwords (Internal Auth)',
           rules          => 'Rules for LON-CAPA Passwords',
           crsownerchg    => 'Course Owner Changing Student Passwords',
           username       => 'Username',
           email          => 'E-mail address',
       );
   
   #
   # Retrieve current domain configuration for internal authentication from $domconfig{'defaults'}.
   #
       my (%curr_defaults,%save_defaults);
       if (ref($domconfig{'defaults'}) eq 'HASH') {
           foreach my $key (keys(%{$domconfig{'defaults'}})) {
               if ($key =~ /^intauth_(cost|check|switch)$/) {
                   $curr_defaults{$key} = $domconfig{'defaults'}{$key};
               } else {
                   $save_defaults{$key} = $domconfig{'defaults'}{$key};
               }
           }
       }
       my %staticdefaults = (
           'resetlink'      => 2,
           'resetcase'      => \@oktypes,
           'resetprelink'   => 'both',
           'resetemail'     => ['critical','notify','permanent'],
           'intauth_cost'   => 10,
           'intauth_check'  => 0,
           'intauth_switch' => 0,
       );
       $staticdefaults{'min'} = $Apache::lonnet::passwdmin;
       foreach my $type (@oktypes) {
           $staticdefaults{'resetpostlink'}{$type} = ['email','username'];
       }
       my $linklife = $env{'form.passwords_link'};
       $linklife =~ s/^\s+|\s+$//g;
       if (($linklife =~ /^\d+(|\.\d*)$/) && ($linklife > 0)) {
           $newvalues{'resetlink'} = $linklife;
           if ($current{'resetlink'}) {
               if ($current{'resetlink'} ne $linklife) {
                   $changes{'reset'} = 1;
               }
           } elsif (!exists($domconfig{passwords})) {
               if ($staticdefaults{'resetlink'} ne $linklife) {
                   $changes{'reset'} = 1;
               }
           }
       } elsif ($current{'resetlink'}) {
           $changes{'reset'} = 1;
       }
       my @casesens;
       my @posscase = &Apache::loncommon::get_env_multiple('form.passwords_case_sensitive');
       foreach my $case (sort(@posscase)) {
           if (grep(/^\Q$case\E$/,@oktypes)) {
               push(@casesens,$case);
           }
       }
       $newvalues{'resetcase'} = \@casesens;
       if (ref($current{'resetcase'}) eq 'ARRAY') {
           my @diffs = &Apache::loncommon::compare_arrays($current{'resetcase'},\@casesens);
           if (@diffs > 0) {
               $changes{'reset'} = 1;
           }
       } elsif (!exists($domconfig{passwords})) {
           my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetcase'},\@casesens);
           if (@diffs > 0) {
               $changes{'reset'} = 1;
           }
       }
       if ($env{'form.passwords_prelink'} =~ /^(both|either)$/) {
           $newvalues{'resetprelink'} = $env{'form.passwords_prelink'};
           if (exists($current{'resetprelink'})) {
               if ($current{'resetprelink'} ne $newvalues{'resetprelink'}) {
                   $changes{'reset'} = 1;
               }
           } elsif (!exists($domconfig{passwords})) {
               if ($staticdefaults{'resetprelink'} ne $newvalues{'resetprelink'}) {
                   $changes{'reset'} = 1;
               }
           }
       } elsif ($current{'resetprelink'}) {
           $changes{'reset'} = 1;
       }
       foreach my $type (@oktypes) {
           my @possplink = &Apache::loncommon::get_env_multiple('form.passwords_postlink_'.$type);
           my @postlink;
           foreach my $item (sort(@possplink)) {
               if ($item =~ /^(email|username)$/) {
                   push(@postlink,$item);
               }
           }
           $newvalues{'resetpostlink'}{$type} = \@postlink;
           unless ($changes{'reset'}) {
               if (ref($current{'resetpostlink'}) eq 'HASH') {
                   if (ref($current{'resetpostlink'}{$type}) eq 'ARRAY') {
                       my @diffs = &Apache::loncommon::compare_arrays($current{'resetpostlink'}{$type},\@postlink);
                       if (@diffs > 0) {
                           $changes{'reset'} = 1;
                       }
                   } else {
                       $changes{'reset'} = 1;
                   }
               } elsif (!exists($domconfig{passwords})) {
                   my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetpostlink'}{$type},\@postlink);
                   if (@diffs > 0) {
                       $changes{'reset'} = 1;
                   }
               }
           }
       }
       my @possemailsrc = &Apache::loncommon::get_env_multiple('form.passwords_emailsrc');
       my @resetemail;
       foreach my $item (sort(@possemailsrc)) {
           if ($item =~ /^(permanent|critical|notify)$/) {
               push(@resetemail,$item);
           }
       }
       $newvalues{'resetemail'} = \@resetemail;
       unless ($changes{'reset'}) {
           if (ref($current{'resetemail'}) eq 'ARRAY') {
               my @diffs = &Apache::loncommon::compare_arrays($current{'resetemail'},\@resetemail);
               if (@diffs > 0) {
                   $changes{'reset'} = 1;
               }
           } elsif (!exists($domconfig{passwords})) {
               my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetemail'},\@resetemail);
               if (@diffs > 0) {
                   $changes{'reset'} = 1;
               }
           }
       }
       if ($env{'form.passwords_stdtext'} == 0) {
           $newvalues{'resetremove'} = 1;
           unless ($current{'resetremove'}) {
               $changes{'reset'} = 1;
           }
       } elsif ($current{'resetremove'}) {
           $changes{'reset'} = 1;
       }
       if ($env{'form.passwords_customfile.filename'} ne '') {
           my $servadm = $r->dir_config('lonAdmEMail');
           my ($configuserok,$author_ok,$switchserver) =
               &config_check($dom,$confname,$servadm);
           my $error;
           if ($configuserok eq 'ok') {
               if ($switchserver) {
                   $error = &mt("Upload of file containing domain-specific text is not permitted to this server: [_1]",$switchserver);
               } else {
                   if ($author_ok eq 'ok') {
                       my ($result,$customurl) =
                           &publishlogo($r,'upload','passwords_customfile',$dom,
                                        $confname,'customtext/resetpw','','',$customfn);
                       if ($result eq 'ok') {
                           $newvalues{'resetcustom'} = $customurl;
                           $changes{'reset'} = 1;
                       } else {
                           $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$customfn,$result);
                       }
                   } else {
                       $error = &mt("Upload of [_1] failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3].  Error was: [_4].",$customfn,$confname,$dom,$author_ok);
                   }
               }
           } else {
               $error = &mt("Upload of [_1] failed because a Domain Configuration user ([_2]) could not be created in domain: [_3].  Error was: [_4].",$customfn,$confname,$dom,$configuserok);
           }
           if ($error) {
               &Apache::lonnet::logthis($error);
               $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
           }
       } elsif ($current{'resetcustom'}) {
           if ($env{'form.passwords_custom_del'}) {
               $changes{'reset'} = 1;
           } else {
               $newvalues{'resetcustom'} = $current{'resetcustom'};
           }
       }
       $env{'form.intauth_cost'} =~ s/^\s+|\s+$//g;
       if (($env{'form.intauth_cost'} ne '') && ($env{'form.intauth_cost'} =~ /^\d+$/)) {
           $save_defaults{'intauth_cost'} = $env{'form.intauth_cost'};
           if ($save_defaults{'intauth_cost'} ne $curr_defaults{'intauth_cost'}) {
               $changes{'intauth'} = 1;
           }
       } else {
           $save_defaults{'intauth_cost'} = $curr_defaults{'intauth_cost'};
       }
       if ($env{'form.intauth_check'} =~ /^(0|1|2)$/) {
           $save_defaults{'intauth_check'} = $env{'form.intauth_check'};
           if ($save_defaults{'intauth_check'} ne $curr_defaults{'intauth_check'}) {
               $changes{'intauth'} = 1;
           }
       } else {
           $save_defaults{'intauth_check'} = $curr_defaults{'intauth_check'};
       }
       if ($env{'form.intauth_switch'} =~ /^(0|1|2)$/) {
           $save_defaults{'intauth_switch'} = $env{'form.intauth_switch'};
           if ($save_defaults{'intauth_switch'} ne $curr_defaults{'intauth_switch'}) {
               $changes{'intauth'} = 1;
           }
       } else {
           $save_defaults{'intauth_check'} = $curr_defaults{'intauth_check'};
       }
       foreach my $item ('cost','check','switch') {
           if ($save_defaults{'intauth_'.$item} ne $domdefaults{'intauth_'.$item}) {
               $domdefaults{'intauth_'.$item} = $save_defaults{'intauth_'.$item};
               $updatedefaults = 1;
           }
       }
       foreach my $rule ('min','max','expire','numsaved') {
           $env{'form.passwords_'.$rule} =~ s/^\s+|\s+$//g;
           my $ruleok;
           if ($rule eq 'expire') {
               if (($env{'form.passwords_'.$rule} =~ /^\d+(|\.\d*)$/) &&
                   ($env{'form.passwords_'.$rule} ne '0')) {
                   $ruleok = 1;
               }
           } elsif ($rule eq 'min') {
               if ($env{'form.passwords_'.$rule} =~ /^\d+$/) {
                   if ($env{'form.passwords_'.$rule} >= $Apache::lonnet::passwdmin) {
                       $ruleok = 1;
                   }
               }
           } elsif (($env{'form.passwords_'.$rule} =~ /^\d+$/) &&
                    ($env{'form.passwords_'.$rule} ne '0')) {
               $ruleok = 1;
           }
           if ($ruleok) {
               $newvalues{$rule} = $env{'form.passwords_'.$rule};
               if (exists($current{$rule})) {
                   if ($newvalues{$rule} ne $current{$rule}) {
                       $changes{'rules'} = 1;
                   }
               } elsif ($rule eq 'min') {
                   if ($staticdefaults{$rule} ne $newvalues{$rule}) {
                       $changes{'rules'} = 1;
                   }
               }
           } elsif (exists($current{$rule})) {
               $changes{'rules'} = 1;
           }
       }
       my @posschars = &Apache::loncommon::get_env_multiple('form.passwords_chars');
       my @chars;
       foreach my $item (sort(@posschars)) {
           if ($item =~ /^(uc|lc|num|spec)$/) {
               push(@chars,$item);
           }
       }
       $newvalues{'chars'} = \@chars;
       unless ($changes{'rules'}) {
           if (ref($current{'chars'}) eq 'ARRAY') {
               my @diffs = &Apache::loncommon::compare_arrays($current{'chars'},\@chars);
               if (@diffs > 0) {
                   $changes{'rules'} = 1;
               }
           } else {
               if (@chars > 0) {
                   $changes{'rules'} = 1;
               }
           }
       }
       my %crsownerchg = (
                           by => [],
                           for => [],
                         );
       foreach my $item ('by','for') {
           my @posstypes = &Apache::loncommon::get_env_multiple('form.passwords_crsowner_'.$item);
           foreach my $type (sort(@posstypes)) {
               if (grep(/^\Q$type\E$/,@oktypes)) {
                   push(@{$crsownerchg{$item}},$type);
               }
           }
       }
       $newvalues{'crsownerchg'} = \%crsownerchg;
       if (ref($current{'crsownerchg'}) eq 'HASH') {
           foreach my $item ('by','for') {
               if (ref($current{'crsownerchg'}{$item}) eq 'ARRAY') {
                   my @diffs = &Apache::loncommon::compare_arrays($current{'crsownerchg'}{$item},$crsownerchg{$item});
                   if (@diffs > 0) {
                       $changes{'crsownerchg'} = 1;
                       last;
                   }
               }
           }
       } elsif (!exists($domconfig{passwords})) {
           foreach my $item ('by','for') {
               if (@{$crsownerchg{$item}} > 0) {
                   $changes{'crsownerchg'} = 1;
                   last;
               }
           }
       }
   
       my %confighash = (
                           defaults  => \%save_defaults,
                           passwords => \%newvalues,
                        );
       &process_captcha('passwords',\%changes,$confighash{'passwords'},$domconfig{'passwords'});
   
       my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,$dom);
       if ($putresult eq 'ok') {
           if (keys(%changes) > 0) {
               $resulttext = &mt('Changes made: ').'<ul>';
               foreach my $key ('reset','intauth','rules','crsownerchg') {
                   if ($changes{$key}) {
                       unless ($key eq 'intauth') {
                           $updateconf = 1;
                       }
                       $resulttext .= '<li>'.$titles{$key}.':<ul>';
                       if ($key eq 'reset') {
                           if ($confighash{'passwords'}{'captcha'} eq 'original') {
                               $resulttext .= '<li>'.&mt('CAPTCHA validation set to use: original CAPTCHA').'</li>';
                           } elsif ($confighash{'passwords'}{'captcha'} eq 'recaptcha') {
                               $resulttext .= '<li>'.&mt('CAPTCHA validation set to use: reCAPTCHA').' '.
                                              &mt('version: [_1]',$confighash{'passwords'}{'recaptchaversion'}).'<br />'.
                                              &mt('Public key: [_1]',$confighash{'passwords'}{'recaptchapub'}).'</br>'.
                                              &mt('Private key: [_1]',$confighash{'passwords'}{'recaptchapriv'}).'</li>';
                           } else {
                               $resulttext .= '<li>'.&mt('No CAPTCHA validation').'</li>';
                           }
                           if ($confighash{'passwords'}{'resetlink'}) {
                               $resulttext .= '<li>'.&mt('Reset link expiration set to [quant,_1,hour]',$confighash{'passwords'}{'resetlink'}).'</li>';
                           } else {
                               $resulttext .= '<li>'.&mt('No reset link expiration set.').' '.
                                                     &mt('Will default to 2 hours').'</li>';
                           }
                           if (ref($confighash{'passwords'}{'resetcase'}) eq 'ARRAY') {
                               if (@{$confighash{'passwords'}{'resetcase'}} == 0) {
                                   $resulttext .= '<li>'.&mt('User input for username and/or e-mail address not case sensitive for "Forgot Password" web form').'</li>';
                               } else {
                                   my $casesens;
                                   foreach my $type (@{$confighash{'passwords'}{'resetcase'}}) {
                                       if ($type eq 'default') {
                                           $casesens .= $othertitle.', ';
                                       } elsif ($usertypes->{$type} ne '') {
                                           $casesens .= $usertypes->{$type}.', ';
                                       }
                                   }
                                   $casesens =~ s/\Q, \E$//;
                                   $resulttext .= '<li>'.&mt('"Forgot Password" web form input for username and/or e-mail address is case-sensitive for: [_1]',$casesens).'</li>';
                               }
                           } else {
                               $resulttext .= '<li>'.&mt('Case-sensitivity not set for "Forgot Password" web form').' '.&mt('Will default to case-sensitive for username and/or e-mail address for all').'</li>';
                           }
                           if ($confighash{'passwords'}{'resetprelink'} eq 'either') {
                               $resulttext .= '<li>'.&mt('Users can enter either a username or an e-mail address in "Forgot Password" web form').'</li>';
                           } else {
                               $resulttext .= '<li>'.&mt('Users can enter both a username and an e-mail address in "Forgot Password" web form').'</li>';
                           }
                           if (ref($confighash{'passwords'}{'resetpostlink'}) eq 'HASH') {
                               my $output;
                               if (ref($types) eq 'ARRAY') {
                                   foreach my $type (@{$types}) {
                                       if (ref($confighash{'passwords'}{'resetpostlink'}{$type}) eq 'ARRAY') {
                                           if (@{$confighash{'passwords'}{'resetpostlink'}{$type}} == 0) {
                                               $output .= $usertypes->{$type}.' -- '.&mt('none');
                                           } else {
                                               $output .= $usertypes->{$type}.' -- '.
                                                          join(', ',map { $titles{$_}; } (@{$confighash{'passwords'}{'resetpostlink'}{$type}})).'; ';
                                           }
                                       }
                                   }
                               }
                               if (ref($confighash{'passwords'}{'resetpostlink'}{'default'}) eq 'ARRAY') {
                                   if (@{$confighash{'passwords'}{'resetpostlink'}{'default'}} == 0) {
                                       $output .= $othertitle.' -- '.&mt('none');
                                   } else {
                                       $output .= $othertitle.' -- '.
                                                  join(', ',map { $titles{$_}; } (@{$confighash{'passwords'}{'resetpostlink'}{'default'}}));
                                   }
                               }
                               if ($output) {
                                   $resulttext .= '<li>'.&mt('Information required for new password form (by user type) set to: [_1]',$output).'</li>';
                               } else {
                                   $resulttext .= '<li>'.&mt('Information required for new password form not set.').' '.&mt('Will default to requiring both the username and an e-mail address').'</li>';
                               }
                           } else {
                               $resulttext .= '<li>'.&mt('Information required for new password form not set.').' '.&mt('Will default to requiring both the username and an e-mail address').'</li>';
                           }
                           if (ref($confighash{'passwords'}{'resetemail'}) eq 'ARRAY') {
                               if (@{$confighash{'passwords'}{'resetemail'}} > 0) {
                                   $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$confighash{'passwords'}{'resetemail'}})).'</li>';
                               } else {
                                   $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>';
                               }
                           } else {
                               $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA usedfor verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>';
                           }
                           if ($confighash{'passwords'}{'resetremove'}) {
                               $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form not shown').'</li>';
                           } else {
                               $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form is shown').'</li>';
                           }
                           if ($confighash{'passwords'}{'resetcustom'}) {
                               my $customlink = &Apache::loncommon::modal_link($confighash{'passwords'}{'resetcustom'},
                                                                               $titles{custom},600,500);
                               $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" form includes [_1]',$customlink).'</li>';
                           } else {
                               $resulttext .= '<li>'.&mt('No custom text included in preamble to "Forgot Password" form').'</li>';
                           }
                       } elsif ($key eq 'intauth') {
                           foreach my $item ('cost','switch','check') {
                               my $value = $save_defaults{$key.'_'.$item};
                               if ($item eq 'switch') {
                                   my %optiondesc = &Apache::lonlocal::texthash (
                                                        0 => 'No',
                                                        1 => 'Yes',
                                                        2 => 'Yes, and copy existing passwd file to passwd.bak file',
                                                    );
                                   if ($value =~ /^(0|1|2)$/) {
                                       $value = $optiondesc{$value};
                                   } else {
                                       $value = &mt('none -- defaults to No');
                                   }
                               } elsif ($item eq 'check') {
                                   my %optiondesc = &Apache::lonlocal::texthash (
                                                        0 => 'No',
                                                        1 => 'Yes, allow login then update passwd file using default cost (if higher)',
                                                        2 => 'Yes, disallow login if stored cost is less than domain default',
                                                    );
                                   if ($value =~ /^(0|1|2)$/) {
                                       $value = $optiondesc{$value};
                                   } else {
                                       $value = &mt('none -- defaults to No');
                                   }
                               }
                               $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$titles{$key.'_'.$item},$value).'</li>';
                           }
                       } elsif ($key eq 'rules') {
                           foreach my $rule ('min','max','expire','numsaved') {
                               if ($confighash{'passwords'}{$rule} eq '') {
                                   if ($rule eq 'min') {
                                       $resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule});
                                                      ' '.&mt('Default of [_1] will be used',
                                                              $Apache::lonnet::passwdmin).'</li>';
                                   } else {
                                       $resulttext .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>';
                                   }
                               } else {
                                   $resulttext .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$confighash{'passwords'}{$rule}).'</li>';
                               }
                           }
                       } elsif ($key eq 'crsownerchg') {
                           if (ref($confighash{'passwords'}{'crsownerchg'}) eq 'HASH') {
                               if ((@{$confighash{'passwords'}{'crsownerchg'}{'by'}} == 0) ||
                                   (@{$confighash{'passwords'}{'crsownerchg'}{'for'}} == 0)) {
                                   $resulttext .= '<li>'.&mt('Course owner may not change student passwords.').'</li>';
                               } else {
                                   my %crsownerstr;
                                   foreach my $item ('by','for') {
                                       if (ref($confighash{'passwords'}{'crsownerchg'}{$item}) eq 'ARRAY') {
                                           foreach my $type (@{$confighash{'passwords'}{'crsownerchg'}{$item}}) {
                                               if ($type eq 'default') {
                                                   $crsownerstr{$item} .= $othertitle.', ';
                                               } elsif ($usertypes->{$type} ne '') {
                                                   $crsownerstr{$item} .= $usertypes->{$type}.', ';
                                               }
                                           }
                                           $crsownerstr{$item} =~ s/\Q, \E$//;
                                       }
                                   }
                                   $resulttext .= '<li>'.&mt('Course owner (with status: [_1]) may change passwords for students (with status: [_2]).',
                                              $crsownerstr{'by'},$crsownerstr{'for'}).'</li>';
                               }
                           } else {
                               $resulttext .= '<li>'.&mt('Course owner may not change student passwords.').'</li>';
                           }
                       }
                       $resulttext .= '</ul></li>';
                   }
               }
               $resulttext .= '</ul>';
           } else {
               $resulttext = &mt('No changes made to password settings');
           }
           my $cachetime = 24*60*60;
           if ($updatedefaults) {
               &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'domdefaults'} = 1;
               }
           }
           if ($updateconf) {
               &Apache::lonnet::do_cache_new('passwdconf',$dom,$confighash{'passwords'},$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'passwdconf'} = 1;
               }
           }
       } else {
           $resulttext = '<span class="LC_error">'.
               &mt('An error occurred: [_1]',$putresult).'</span>';
       }
       if ($errors) {
           $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.
                          $errors.'</ul></p>';
       }
       return $resulttext;
   }
   
 sub modify_usercreation {  sub modify_usercreation {
     my ($dom,%domconfig) = @_;      my ($dom,%domconfig) = @_;
     my ($resulttext,%curr_usercreation,%changes,%authallowed,%cancreate,%save_usercreate);      my ($resulttext,%curr_usercreation,%changes,%authallowed,%cancreate,%save_usercreate);
Line 8483  sub modify_usercreation { Line 15030  sub modify_usercreation {
             if ($key eq 'cancreate') {              if ($key eq 'cancreate') {
                 if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') {                  if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') {
                     foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) {                      foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) {
                         if (($item eq 'selfcreate') || ($item eq 'statustocreate') ||                          if (($item eq 'requestcrs') || ($item eq 'course') || ($item eq 'author')) {
                             ($item eq 'captcha') || ($item eq 'recaptchakeys')) {  
                             $save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};  
                         } else {  
                             $curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};                              $curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};
                           } else {
                               $save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};
                         }                          }
                     }                      }
                 }                  }
Line 8559  sub modify_usercreation { Line 15105  sub modify_usercreation {
     }      }
   
     my @authen_contexts = ('author','course','domain');      my @authen_contexts = ('author','course','domain');
     my @authtypes = ('int','krb4','krb5','loc');      my @authtypes = ('int','krb4','krb5','loc','lti');
     my %authhash;      my %authhash;
     foreach my $item (@authen_contexts) {      foreach my $item (@authen_contexts) {
         my @authallowed =  &Apache::loncommon::get_env_multiple('form.'.$item.'_auth');          my @authallowed =  &Apache::loncommon::get_env_multiple('form.'.$item.'_auth');
Line 8690  sub modify_usercreation { Line 15236  sub modify_usercreation {
 }  }
   
 sub modify_selfcreation {  sub modify_selfcreation {
     my ($dom,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,$warningmsg,%curr_usercreation,%curr_usermodify,%changes,%cancreate);      my ($resulttext,$warningmsg,%curr_usercreation,%curr_usermodify,%curr_inststatus,%changes,%cancreate);
     my (%save_usercreate,%save_usermodify);      my (%save_usercreate,%save_usermodify,%save_inststatus,@types,%usertypes);
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);      my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
     if (ref($types) eq 'ARRAY') {      my ($othertitle,$usertypesref,$typesref) = &Apache::loncommon::sorted_inst_types($dom);
         $usertypes->{'default'} = $othertitle;      if (ref($typesref) eq 'ARRAY') {
         push(@{$types},'default');          @types = @{$typesref};
     }      }
       if (ref($usertypesref) eq 'HASH') {
           %usertypes = %{$usertypesref};
       }
       $usertypes{'default'} = $othertitle;
 #  #
 # Retrieve current domain configuration for self-creation of usernames from $domconfig{'usercreation'}.  # Retrieve current domain configuration for self-creation of usernames from $domconfig{'usercreation'}.
 #  #
Line 8707  sub modify_selfcreation { Line 15257  sub modify_selfcreation {
                 if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') {                  if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') {
                     foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) {                      foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) {
                         if (($item eq 'selfcreate') || ($item eq 'statustocreate') ||                          if (($item eq 'selfcreate') || ($item eq 'statustocreate') ||
                             ($item eq 'captcha') || ($item eq 'recaptchakeys') ||                               ($item eq 'captcha') || ($item eq 'recaptchakeys') ||
                             ($item eq 'emailusername') || ($item eq 'notify') ||                              ($item eq 'recaptchaversion') || ($item eq 'notify') ||
                             ($item eq 'selfcreateprocessing') || ($item eq 'shibenv')) {                              ($item eq 'emailusername') || ($item eq 'shibenv') ||
                               ($item eq 'selfcreateprocessing') || ($item eq 'emailverified') ||
                               ($item eq 'emailoptions') || ($item eq 'emaildomain')) {
                             $curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};                              $curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};
                         } else {                          } else {
                             $save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};                              $save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};
Line 8735  sub modify_selfcreation { Line 15287  sub modify_selfcreation {
             }              }
         }          }
     }      }
   #
   # Retrieve current domain configuration for institutional status types from $domconfig{'inststatus'}.
   #
       if (ref($domconfig{'inststatus'}) eq 'HASH') {
           foreach my $key (keys(%{$domconfig{'inststatus'}})) {
               if ($key eq 'inststatusguest') {
                   $curr_inststatus{$key} = $domconfig{'inststatus'}{$key};
               } else {
                   $save_inststatus{$key} = $domconfig{'inststatus'}{$key};
               }
           }
       }
   
     my @contexts = ('selfcreate');      my @contexts = ('selfcreate');
     @{$cancreate{'selfcreate'}} = ();      @{$cancreate{'selfcreate'}} = ();
     %{$cancreate{'emailusername'}} = ();      %{$cancreate{'emailusername'}} = ();
     @{$cancreate{'statustocreate'}} = ();      if (@types) {
           @{$cancreate{'statustocreate'}} = ();
       }
     %{$cancreate{'selfcreateprocessing'}} = ();      %{$cancreate{'selfcreateprocessing'}} = ();
     %{$cancreate{'shibenv'}} = ();      %{$cancreate{'shibenv'}} = ();
       %{$cancreate{'emailverified'}} = ();
       %{$cancreate{'emailoptions'}} = ();
       %{$cancreate{'emaildomain'}} = ();
     my %selfcreatetypes = (      my %selfcreatetypes = (
                              sso   => 'users authenticated by institutional single sign on',                               sso   => 'users authenticated by institutional single sign on',
                              login => 'users authenticated by institutional log-in',                               login => 'users authenticated by institutional log-in',
                              email => 'users who provide a valid e-mail address for use as username',                               email => 'users verified by e-mail',
                           );                            );
 #  #
 # Populate $cancreate{'selfcreate'} array reference with types of user, for which self-creation of user accounts  # Populate $cancreate{'selfcreate'} array reference with types of user, for which self-creation of user accounts
 # is permitted.  # is permitted.
 #  #
       my ($emailrules,$emailruleorder) = &Apache::lonnet::inst_userrules($dom,'email');
   
     my @statuses;      my (@statuses,%email_rule);
     if (ref($domconfig{'inststatus'}) eq 'HASH') {  
         if (ref($domconfig{'inststatus'}{'inststatusguest'}) eq 'ARRAY') {  
             @statuses = @{$domconfig{'inststatus'}{'inststatusguest'}};  
         }  
     }  
     push(@statuses,'default');  
   
     foreach my $item ('login','sso','email') {      foreach my $item ('login','sso','email') {
         if ($item eq 'email') {          if ($item eq 'email') {
             if ($env{'form.cancreate_email'}) {              if ($env{'form.cancreate_email'}) {
                 push(@{$cancreate{'selfcreate'}},'email');                  if (@types) {
                 push(@contexts,'selfcreateprocessing');                      my @poss_statuses = &Apache::loncommon::get_env_multiple('form.selfassign');
                 foreach my $type (@statuses) {                      foreach my $status (@poss_statuses) {
                     if ($type eq 'default') {                          if (grep(/^\Q$status\E$/,(@types,'default'))) {
                         $cancreate{'selfcreateprocessing'}{$type} = $env{'form.cancreate_emailprocess'};                              push(@statuses,$status);
                     } else {                           }
                         $cancreate{'selfcreateprocessing'}{$type} = $env{'form.cancreate_emailprocess_'.$type};                      }
                       $save_inststatus{'inststatusguest'} = \@statuses;
                   } else {
                       push(@statuses,'default');
                   }
                   if (@statuses) {
                       my %curr_rule;
                       if (ref($curr_usercreation{'email_rule'}) eq 'ARRAY') {
                           foreach my $type (@statuses) {
                               $curr_rule{$type} = $curr_usercreation{'email_rule'};
                           }
                       } elsif (ref($curr_usercreation{'email_rule'}) eq 'HASH') {
                           foreach my $type (@statuses) {
                               $curr_rule{$type} = $curr_usercreation{'email_rule'}{$type};
                           }
                       }
                       push(@{$cancreate{'selfcreate'}},'email');
                       push(@contexts,('selfcreateprocessing','emailverified','emailoptions'));
                       my %curremaildom;
                       if (ref($curr_usercreation{'cancreate'}{'emaildomain'}) eq 'HASH') {
                           %curremaildom = %{$curr_usercreation{'cancreate'}{'emaildomain'}};
                       }
                       foreach my $type (@statuses) {
                           if ($env{'form.cancreate_emailprocess_'.$type} =~ /^(?:approval|automatic)$/) {
                               $cancreate{'selfcreateprocessing'}{$type} = $env{'form.cancreate_emailprocess_'.$type};
                           }
                           if ($env{'form.cancreate_usernameoptions_'.$type} =~ /^(?:all|first|free)$/) {
                               $cancreate{'emailverified'}{$type} = $env{'form.cancreate_usernameoptions_'.$type};
                           }
                           if ($env{'form.cancreate_emailoptions_'.$type} =~ /^(any|inst|noninst|custom)$/) {
   #
   # Retrieve rules (if any) governing types of e-mail address which may be used to verify a username.
   #
                               my $chosen = $1;
                               if (($chosen eq 'inst') || ($chosen eq 'noninst')) {
                                   my $emaildom;
                                   if ($env{'form.cancreate_emaildomain_'.$chosen.'_'.$type} =~ /^\@[^\@]+$/) {
                                       $emaildom = $env{'form.cancreate_emaildomain_'.$chosen.'_'.$type}; 
                                       $cancreate{'emaildomain'}{$type}{$chosen} = $emaildom;
                                       if (ref($curremaildom{$type}) eq 'HASH') {
                                           if (exists($curremaildom{$type}{$chosen})) {
                                               if ($curremaildom{$type}{$chosen} ne $emaildom) {
                                                   push(@{$changes{'cancreate'}},'emaildomain');
                                               }
                                           } elsif ($emaildom ne '') {
                                               push(@{$changes{'cancreate'}},'emaildomain');
                                           }
                                       } elsif ($emaildom ne '') {
                                           push(@{$changes{'cancreate'}},'emaildomain');
                                       } 
                                   }
                                   $cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type};
                               } elsif ($chosen eq 'custom') {
                                   my @possemail_rules = &Apache::loncommon::get_env_multiple('form.email_rule_'.$type);
                                   $email_rule{$type} = [];
                                   if (ref($emailrules) eq 'HASH') {
                                       foreach my $rule (@possemail_rules) {
                                           if (exists($emailrules->{$rule})) {
                                               push(@{$email_rule{$type}},$rule);
                                           }
                                       }
                                   }
                                   if (@{$email_rule{$type}}) {
                                       $cancreate{'emailoptions'}{$type} = 'custom';
                                       if (ref($curr_rule{$type}) eq 'ARRAY') {
                                           if (@{$curr_rule{$type}} > 0) {
                                               foreach my $rule (@{$curr_rule{$type}}) {
                                                   if (!grep(/^\Q$rule\E$/,@{$email_rule{$type}})) {
                                                       push(@{$changes{'email_rule'}},$type);
                                                   }
                                               }
                                           }
                                           foreach my $type (@{$email_rule{$type}}) {
                                               if (!grep(/^\Q$type\E$/,@{$curr_rule{$type}})) {
                                                   push(@{$changes{'email_rule'}},$type);
                                               }
                                           }
                                       } else {
                                           push(@{$changes{'email_rule'}},$type);
                                       }
                                   }
                               } else {
                                   $cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type};
                               }
                           }
                       }
                       if (@types) {
                           if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') {
                               my @changed = &Apache::loncommon::compare_arrays(\@statuses,$curr_inststatus{'inststatusguest'});
                               if (@changed) {
                                   push(@{$changes{'inststatus'}},'inststatusguest');
                               }
                           } else {
                               push(@{$changes{'inststatus'}},'inststatusguest');
                           }
                       }
                   } else {
                       delete($env{'form.cancreate_email'});
                       if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') {
                           if (@{$curr_inststatus{'inststatusguest'}} > 0) {
                               push(@{$changes{'inststatus'}},'inststatusguest');
                           }
                       }
                   }
               } else {
                   $save_inststatus{'inststatusguest'} = [];
                   if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') {
                       if (@{$curr_inststatus{'inststatusguest'}} > 0) {
                           push(@{$changes{'inststatus'}},'inststatusguest');
                     }                      }
                 }                  }
             }              }
Line 8779  sub modify_selfcreation { Line 15450  sub modify_selfcreation {
             }              }
         }          }
     }      }
     my (@email_rule,%userinfo,%savecaptcha);      my (%userinfo,%savecaptcha);
     my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info();      my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info();
 #  #
 # Populate $cancreate{'emailusername'}{$type} hash ref with information fields (if new user will provide data  # Populate $cancreate{'emailusername'}{$type} hash ref with information fields (if new user will provide data
Line 8788  sub modify_selfcreation { Line 15459  sub modify_selfcreation {
   
     if ($env{'form.cancreate_email'}) {      if ($env{'form.cancreate_email'}) {
         push(@contexts,'emailusername');          push(@contexts,'emailusername');
         if (ref($types) eq 'ARRAY') {          if (@statuses) {
             foreach my $type (@{$types}) {              foreach my $type (@statuses) {
                 if (ref($infofields) eq 'ARRAY') {                  if (ref($infofields) eq 'ARRAY') {
                     foreach my $field (@{$infofields}) {                      foreach my $field (@{$infofields}) {
                         if ($env{'form.canmodify_emailusername_'.$type.'_'.$field} =~ /^(required|optional)$/) {                          if ($env{'form.canmodify_emailusername_'.$type.'_'.$field} =~ /^(required|optional)$/) {
Line 8801  sub modify_selfcreation { Line 15472  sub modify_selfcreation {
         }          }
 #  #
 # Populate $cancreate{'notify'} hash ref with names of Domain Coordinators who are to be notified of  # Populate $cancreate{'notify'} hash ref with names of Domain Coordinators who are to be notified of
 # queued requests for self-creation of account using e-mail address as username  # queued requests for self-creation of account verified by e-mail.
 #  #
   
         my @approvalnotify = &Apache::loncommon::get_env_multiple('form.selfcreationnotifyapproval');          my @approvalnotify = &Apache::loncommon::get_env_multiple('form.selfcreationnotifyapproval');
Line 8821  sub modify_selfcreation { Line 15492  sub modify_selfcreation {
             push(@{$changes{'cancreate'}},'notify');              push(@{$changes{'cancreate'}},'notify');
         }          }
   
 #  
 # Retrieve rules (if any) governing types of e-mail address which may be used as a username  
 #  
         @email_rule = &Apache::loncommon::get_env_multiple('form.email_rule');  
         &process_captcha('cancreate',\%changes,\%savecaptcha,$curr_usercreation{'cancreate'});          &process_captcha('cancreate',\%changes,\%savecaptcha,$curr_usercreation{'cancreate'});
         if (ref($curr_usercreation{'email_rule'}) eq 'ARRAY') {  
             if (@{$curr_usercreation{'email_rule'}} > 0) {  
                 foreach my $type (@{$curr_usercreation{'email_rule'}}) {  
                     if (!grep(/^\Q$type\E$/,@email_rule)) {  
                         push(@{$changes{'email_rule'}},$type);  
                     }  
                 }  
             }  
             if (@email_rule > 0) {  
                 foreach my $type (@email_rule) {  
                     if (!grep(/^\Q$type\E$/,@{$curr_usercreation{'email_rule'}})) {  
                         push(@{$changes{'email_rule'}},$type);  
                     }  
                 }  
             }  
         } elsif (@email_rule > 0) {  
             push(@{$changes{'email_rule'}},@email_rule);  
         }  
     }      }
 #    #  
 # Check if domain default is set appropriately, if self-creation of accounts is to be available for  # Check if domain default is set appropriately, if self-creation of accounts is to be available for
 # institutional log-in.  # institutional log-in.
 #  #
     if (grep(/^login$/,@{$cancreate{'selfcreate'}})) {      if (grep(/^login$/,@{$cancreate{'selfcreate'}})) {
         my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);  
         if (!((($domdefaults{'auth_def'} =~/^krb/) && ($domdefaults{'auth_arg_def'} ne '')) ||           if (!((($domdefaults{'auth_def'} =~/^krb/) && ($domdefaults{'auth_arg_def'} ne '')) || 
                ($domdefaults{'auth_def'} eq 'localauth'))) {                 ($domdefaults{'auth_def'} eq 'localauth'))) {
             $warningmsg = &mt('Although account creation has been set to be available for institutional logins, currently default authentication in this domain has not been set to support this.').' '.              $warningmsg = &mt('Although account creation has been set to be available for institutional logins, currently default authentication in this domain has not been set to support this.').' '.
Line 8869  sub modify_selfcreation { Line 15517  sub modify_selfcreation {
 # which the user may supply, if institutional data is unavailable.  # which the user may supply, if institutional data is unavailable.
 #  #
     if (($env{'form.cancreate_login'}) || ($env{'form.cancreate_sso'})) {      if (($env{'form.cancreate_login'}) || ($env{'form.cancreate_sso'})) {
         if (ref($types) eq 'ARRAY') {          if (@types) {
             if (@{$types} > 1) {              @{$cancreate{'statustocreate'}} = &Apache::loncommon::get_env_multiple('form.statustocreate');
                 @{$cancreate{'statustocreate'}} = &Apache::loncommon::get_env_multiple('form.statustocreate');              push(@contexts,'statustocreate');
                 push(@contexts,'statustocreate');              foreach my $type (@types) {
             } else {  
                 undef($cancreate{'statustocreate'});  
             }   
             foreach my $type (@{$types}) {  
                 my @modifiable =  &Apache::loncommon::get_env_multiple('form.canmodify_'.$type);                  my @modifiable =  &Apache::loncommon::get_env_multiple('form.canmodify_'.$type);
                 foreach my $field (@fields) {                  foreach my $field (@fields) {
                     if (grep(/^\Q$field\E$/,@modifiable)) {                      if (grep(/^\Q$field\E$/,@modifiable)) {
Line 8887  sub modify_selfcreation { Line 15531  sub modify_selfcreation {
                 }                  }
             }              }
             if (ref($curr_usermodify{'selfcreate'}) eq 'HASH') {              if (ref($curr_usermodify{'selfcreate'}) eq 'HASH') {
                 foreach my $type (@{$types}) {                  foreach my $type (@types) {
                     if (ref($curr_usermodify{'selfcreate'}{$type}) eq 'HASH') {                      if (ref($curr_usermodify{'selfcreate'}{$type}) eq 'HASH') {
                         foreach my $field (@fields) {                          foreach my $field (@fields) {
                             if ($save_usermodify{'selfcreate'}{$type}{$field} ne                              if ($save_usermodify{'selfcreate'}{$type}{$field} ne
Line 8899  sub modify_selfcreation { Line 15543  sub modify_selfcreation {
                     }                      }
                 }                  }
             } else {              } else {
                 foreach my $type (@{$types}) {                  foreach my $type (@types) {
                     push(@{$changes{'selfcreate'}},$type);                      push(@{$changes{'selfcreate'}},$type);
                 }                  }
             }              }
Line 8948  sub modify_selfcreation { Line 15592  sub modify_selfcreation {
             }              }
         } elsif (ref($curr_usercreation{'cancreate'}{$item}) eq 'HASH') {          } elsif (ref($curr_usercreation{'cancreate'}{$item}) eq 'HASH') {
             if (ref($cancreate{$item}) eq 'HASH') {              if (ref($cancreate{$item}) eq 'HASH') {
                 foreach my $curr (keys(%{$curr_usercreation{'cancreate'}{$item}})) {                  foreach my $type (keys(%{$curr_usercreation{'cancreate'}{$item}})) {
                     if (ref($curr_usercreation{'cancreate'}{$item}{$curr}) eq 'HASH') {                      if (ref($curr_usercreation{'cancreate'}{$item}{$type}) eq 'HASH') {
                         foreach my $field (keys(%{$curr_usercreation{'cancreate'}{$item}{$curr}})) {                          foreach my $field (keys(%{$curr_usercreation{'cancreate'}{$item}{$type}})) {
                             unless ($curr_usercreation{'cancreate'}{$item}{$curr}{$field} eq $cancreate{$item}{$curr}{$field}) {                              unless ($curr_usercreation{'cancreate'}{$item}{$type}{$field} eq $cancreate{$item}{$type}{$field}) {
                                 if (!grep(/^$item$/,@{$changes{'cancreate'}})) {                                  if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
                                     push(@{$changes{'cancreate'}},$item);                                      push(@{$changes{'cancreate'}},$item);
                                 }                                  }
                             }                              }
                         }                          }
                     } elsif ($item eq 'selfcreateprocessing') {                      } elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) {
                         if ($cancreate{$item}{$curr} ne $curr_usercreation{'cancreate'}{$item}{$curr}) {                          if ($cancreate{$item}{$type} ne $curr_usercreation{'cancreate'}{$item}{$type}) {
                             if (!grep(/^$item$/,@{$changes{'cancreate'}})) {  
                                 push(@{$changes{'cancreate'}},$item);  
                             }  
                         }  
                     } else {  
                         if (!$cancreate{$item}{$curr}) {  
                             if (!grep(/^$item$/,@{$changes{'cancreate'}})) {                              if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
                                 push(@{$changes{'cancreate'}},$item);                                  push(@{$changes{'cancreate'}},$item);
                             }                              }
                         }                          }
                     }                      }
                 }                  }
                 foreach my $field (keys(%{$cancreate{$item}})) {                  foreach my $type (keys(%{$cancreate{$item}})) {
                     if (ref($cancreate{$item}{$field}) eq 'HASH') {                      if (ref($cancreate{$item}{$type}) eq 'HASH') {
                         foreach my $inner (keys(%{$cancreate{$item}{$field}})) {                          foreach my $field (keys(%{$cancreate{$item}{$type}})) {
                             if (ref($curr_usercreation{'cancreate'}{$item}{$field}) eq 'HASH') {                              if (ref($curr_usercreation{'cancreate'}{$item}{$type}) eq 'HASH') {
                                 unless ($curr_usercreation{'cancreate'}{$item}{$field}{$inner} eq $cancreate{$item}{$field}{$inner}) {                                  unless ($curr_usercreation{'cancreate'}{$item}{$type}{$field} eq $cancreate{$item}{$type}{$field}) {
                                     if (!grep(/^$item$/,@{$changes{'cancreate'}})) {                                      if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
                                         push(@{$changes{'cancreate'}},$item);                                          push(@{$changes{'cancreate'}},$item);
                                     }                                      }
Line 8986  sub modify_selfcreation { Line 15624  sub modify_selfcreation {
                                 }                                  }
                             }                              }
                         }                          }
                     } elsif ($item eq 'selfcreateprocessing') {                      } elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) {
                         if ($cancreate{$item}{$field} ne $curr_usercreation{'cancreate'}{$item}{$field}) {                          if ($cancreate{$item}{$type} ne $curr_usercreation{'cancreate'}{$item}{$type}) {
                             if (!grep(/^$item$/,@{$changes{'cancreate'}})) {  
                                 push(@{$changes{'cancreate'}},$item);  
                             }  
                         }  
                     } else {  
                         if (!$curr_usercreation{'cancreate'}{$item}{$field}) {  
                             if (!grep(/^$item$/,@{$changes{'cancreate'}})) {                              if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
                                 push(@{$changes{'cancreate'}},$item);                                  push(@{$changes{'cancreate'}},$item);
                             }                              }
Line 9008  sub modify_selfcreation { Line 15640  sub modify_selfcreation {
                         push(@{$changes{'cancreate'}},$item);                          push(@{$changes{'cancreate'}},$item);
                     }                      }
                 }                  }
             } elsif (ref($cancreate{$item}) eq 'HASH') {              }
                 if (!$cancreate{$item}{$curr_usercreation{'cancreate'}{$item}}) {          } elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) {
                     if (!grep(/^$item$/,@{$changes{'cancreate'}})) {              if (ref($cancreate{$item}) eq 'HASH') {
                         push(@{$changes{'cancreate'}},$item);                  if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
                     }                      push(@{$changes{'cancreate'}},$item);
                 }                  }
             }              }
         } elsif ($item eq 'emailusername') {          } elsif ($item eq 'emailusername') {
Line 9037  sub modify_selfcreation { Line 15669  sub modify_selfcreation {
 #  #
     $save_usercreate{'cancreate'}{'captcha'} = $savecaptcha{'captcha'};      $save_usercreate{'cancreate'}{'captcha'} = $savecaptcha{'captcha'};
     $save_usercreate{'cancreate'}{'recaptchakeys'} = $savecaptcha{'recaptchakeys'};      $save_usercreate{'cancreate'}{'recaptchakeys'} = $savecaptcha{'recaptchakeys'};
       $save_usercreate{'cancreate'}{'recaptchaversion'} = $savecaptcha{'recaptchaversion'};
     $save_usercreate{'cancreate'}{'selfcreate'} = $cancreate{'selfcreate'};      $save_usercreate{'cancreate'}{'selfcreate'} = $cancreate{'selfcreate'};
     if (ref($cancreate{'notify'}) eq 'HASH') {      if (ref($cancreate{'notify'}) eq 'HASH') {
         $save_usercreate{'cancreate'}{'notify'} = $cancreate{'notify'};          $save_usercreate{'cancreate'}{'notify'} = $cancreate{'notify'};
Line 9044  sub modify_selfcreation { Line 15677  sub modify_selfcreation {
     if (ref($cancreate{'selfcreateprocessing'}) eq 'HASH') {      if (ref($cancreate{'selfcreateprocessing'}) eq 'HASH') {
         $save_usercreate{'cancreate'}{'selfcreateprocessing'} = $cancreate{'selfcreateprocessing'};          $save_usercreate{'cancreate'}{'selfcreateprocessing'} = $cancreate{'selfcreateprocessing'};
     }      }
       if (ref($cancreate{'emailverified'}) eq 'HASH') {
           $save_usercreate{'cancreate'}{'emailverified'} = $cancreate{'emailverified'};
       }
       if (ref($cancreate{'emailoptions'}) eq 'HASH') {
           $save_usercreate{'cancreate'}{'emailoptions'} = $cancreate{'emailoptions'};
       }
       if (ref($cancreate{'emaildomain'}) eq 'HASH') {
           $save_usercreate{'cancreate'}{'emaildomain'} = $cancreate{'emaildomain'};
       }
     if (ref($cancreate{'statustocreate'}) eq 'ARRAY') {      if (ref($cancreate{'statustocreate'}) eq 'ARRAY') {
         $save_usercreate{'cancreate'}{'statustocreate'} = $cancreate{'statustocreate'};          $save_usercreate{'cancreate'}{'statustocreate'} = $cancreate{'statustocreate'};
     }      }
Line 9051  sub modify_selfcreation { Line 15693  sub modify_selfcreation {
         $save_usercreate{'cancreate'}{'shibenv'} = $cancreate{'shibenv'};          $save_usercreate{'cancreate'}{'shibenv'} = $cancreate{'shibenv'};
     }      }
     $save_usercreate{'cancreate'}{'emailusername'} = $cancreate{'emailusername'};      $save_usercreate{'cancreate'}{'emailusername'} = $cancreate{'emailusername'};
     $save_usercreate{'emailrule'} = \@email_rule;      $save_usercreate{'email_rule'} = \%email_rule;
   
     my %userconfig_hash = (      my %userconfig_hash = (
             usercreation     => \%save_usercreate,              usercreation     => \%save_usercreate,
             usermodification => \%save_usermodify,              usermodification => \%save_usermodify,
               inststatus       => \%save_inststatus,
     );      );
   
     my $putresult = &Apache::lonnet::put_dom('configuration',\%userconfig_hash,      my $putresult = &Apache::lonnet::put_dom('configuration',\%userconfig_hash,
                                              $dom);                                               $dom);
 #  #
 # Accumulate details of changes to domain cofiguration for self-creation of usernames in $resulttext  # Accumulate details of changes to domain configuration for self-creation of usernames in $resulttext
 #  #
     if ($putresult eq 'ok') {      if ($putresult eq 'ok') {
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
Line 9068  sub modify_selfcreation { Line 15712  sub modify_selfcreation {
             if (ref($changes{'cancreate'}) eq 'ARRAY') {              if (ref($changes{'cancreate'}) eq 'ARRAY') {
                 my %lt = &selfcreation_types();                  my %lt = &selfcreation_types();
                 foreach my $type (@{$changes{'cancreate'}}) {                  foreach my $type (@{$changes{'cancreate'}}) {
                     my $chgtext;                      my $chgtext = '';
                     if ($type eq 'selfcreate') {                      if ($type eq 'selfcreate') {
                         if (@{$cancreate{$type}} == 0) {                          if (@{$cancreate{$type}} == 0) {
                             $chgtext .= &mt('Self creation of a new user account is not permitted.');                              $chgtext .= &mt('Self creation of a new user account is not permitted.');
Line 9083  sub modify_selfcreation { Line 15727  sub modify_selfcreation {
                                 if (grep(/^(login|sso)$/,@{$cancreate{$type}})) {                                  if (grep(/^(login|sso)$/,@{$cancreate{$type}})) {
                                     if (ref($cancreate{'statustocreate'}) eq 'ARRAY') {                                      if (ref($cancreate{'statustocreate'}) eq 'ARRAY') {
                                         if (@{$cancreate{'statustocreate'}} == 0) {                                          if (@{$cancreate{'statustocreate'}} == 0) {
                                             $chgtext .= '<br />'.                                              $chgtext .= '<span class="LC_warning">'.
                                                         '<span class="LC_warning">'.                                                          &mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts via log-in or single sign-on.").
                                                         &mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts.").                                                          '</span><br />';
                                                         '</span>';  
                                         }                                          }
                                     }                                      }
                                 }                                  }
                                   if (grep(/^email$/,@{$cancreate{$type}})) {
                                       if (!@statuses) {
                                           $chgtext .= '<span class="LC_warning">'.
                                                       &mt("However, e-mail verification is currently set to 'unavailable' for all user types (including 'other'), so self-creation of accounts is not possible for non-institutional log-in.").
                                                       '</span><br />';
   
                                       }
                                   }
                             }                              }
                         }                          }
                     } elsif ($type eq 'shibenv') {                      } elsif ($type eq 'shibenv') {
                         if (keys(%{$cancreate{$type}}) == 0) {                          if (keys(%{$cancreate{$type}}) == 0) {
                             $chgtext .= &mt('Shibboleth-autheticated user does not use environment variables to set user information');                               $chgtext .= &mt('Shibboleth-autheticated user does not use environment variables to set user information').'<br />'; 
                         } else {                          } else {
                             $chgtext .= &mt('Shibboleth-autheticated user information set from environment variables, as follows:').                              $chgtext .= &mt('Shibboleth-autheticated user information set from environment variables, as follows:').
                                         '<ul>';                                          '<ul>';
Line 9107  sub modify_selfcreation { Line 15758  sub modify_selfcreation {
                                 }                                  }
                             }                              }
                             $chgtext .= '</ul>';                              $chgtext .= '</ul>';
                         }                            }
                     } elsif ($type eq 'statustocreate') {                      } elsif ($type eq 'statustocreate') {
                         if ((ref($cancreate{'selfcreate'}) eq 'ARRAY') &&                          if ((ref($cancreate{'selfcreate'}) eq 'ARRAY') &&
                             (ref($cancreate{'statustocreate'}) eq 'ARRAY')) {                              (ref($cancreate{'statustocreate'}) eq 'ARRAY')) {
Line 9120  sub modify_selfcreation { Line 15771  sub modify_selfcreation {
                                                     &mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts.").                                                      &mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts.").
                                                     '</span>';                                                      '</span>';
                                     }                                      }
                                 } elsif (ref($usertypes) eq 'HASH') {                                  } elsif (keys(%usertypes) > 0) {
                                     if (grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) {                                      if (grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) {
                                         $chgtext .= &mt('Creation of a new account for an institutional user is restricted to the following institutional affiliation(s):');                                          $chgtext .= &mt('Creation of a new account for an institutional user is restricted to the following institutional affiliation(s):');
                                     } else {                                      } else {
Line 9131  sub modify_selfcreation { Line 15782  sub modify_selfcreation {
                                         if ($case eq 'default') {                                          if ($case eq 'default') {
                                             $chgtext .= '<li>'.$othertitle.'</li>';                                              $chgtext .= '<li>'.$othertitle.'</li>';
                                         } else {                                          } else {
                                             $chgtext .= '<li>'.$usertypes->{$case}.'</li>';                                              $chgtext .= '<li>'.$usertypes{$case}.'</li>';
                                         }                                          }
                                     }                                      }
                                     $chgtext .= '</ul>';                                      $chgtext .= '</ul>';
                                     if (!grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) {                                      if (!grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) {
                                         $chgtext .= '<br /><span class="LC_warning">'.                                          $chgtext .= '<span class="LC_warning">'.
                                                     &mt('However, users authenticated by institutional login/single sign on are not currently permitted to create accounts.').                                                      &mt('However, users authenticated by institutional login/single sign on are not currently permitted to create accounts.').
                                                     '</span>';                                                      '</span>';
                                     }                                      }
Line 9148  sub modify_selfcreation { Line 15799  sub modify_selfcreation {
                                     $chgtext .= &mt('Although institutional affiliations permitted to create accounts were changed, self creation of accounts is not currently permitted for any authentication types.');                                      $chgtext .= &mt('Although institutional affiliations permitted to create accounts were changed, self creation of accounts is not currently permitted for any authentication types.');
                                 }                                  }
                             }                              }
                               $chgtext .= '<br />';
                         }                          }
                     } elsif ($type eq 'selfcreateprocessing') {                      } elsif ($type eq 'selfcreateprocessing') {
                         my %choices = &Apache::lonlocal::texthash (                          my %choices = &Apache::lonlocal::texthash (
                                                                     automatic => 'Automatic approval',                                                                      automatic => 'Automatic approval',
                                                                     approval  => 'Queued for approval',                                                                      approval  => 'Queued for approval',
                                                                   );                                                                    );
                         if (@statuses > 1) {                          if (@types) {
                             $chgtext .= &mt('Processing of requests to create account with e-mail address as username set as follows:').                               if (@statuses) {
                                         '<ul>';                                  $chgtext .= &mt('Processing of requests to create account with e-mail verification set as follows:'). 
                            foreach my $type (@statuses) {                                              '<ul>';
                                if ($type eq 'default') {                                  foreach my $status (@statuses) {
                                    $chgtext .= '<li>'.$othertitle.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$type}}.'</li>';                                      if ($status eq 'default') {
                                } else {                                          $chgtext .= '<li>'.$othertitle.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$status}}.'</li>';
                                    $chgtext .= '<li>'.$usertypes->{$type}.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$type}}.'</li>';                                      } else {
                                }                                          $chgtext .= '<li>'.$usertypes{$status}.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$status}}.'</li>';
                            }                                      }
                            $chgtext .= '</ul>';                                  }
                                   $chgtext .= '</ul>';
                               }
                           } else {
                               $chgtext .= &mt('Processing of requests to create account with e-mail verification set to: "[_1]"',
                                               $choices{$cancreate{'selfcreateprocessing'}{'default'}});
                           }
                       } elsif ($type eq 'emailverified') {
                           my %options = &Apache::lonlocal::texthash (
                                                                       all   => 'Same as e-mail',
                                                                       first => 'Omit @domain',
                                                                       free  => 'Free to choose',
                                                                     );
                           if (@types) {
                               if (@statuses) {
                                   $chgtext .= &mt('For self-created accounts verified by e-mail address, username is set as follows:').
                                               '<ul>';
                                   foreach my $status (@statuses) {
                                       if ($status eq 'default') {
                                           $chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';
                                       } else {
                                           $chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';
                                       }
                                   }
                                   $chgtext .= '</ul>';
                               }
                           } else {
                               $chgtext .= &mt("For self-created accounts verified by e-mail address, user's username is: '[_1]'",
                                               $options{$cancreate{'emailverified'}{'default'}});
                           }
                       } elsif ($type eq 'emailoptions') {
                           my %options = &Apache::lonlocal::texthash (
                                                                       any     => 'Any e-mail',
                                                                       inst    => 'Institutional only',
                                                                       noninst => 'Non-institutional only',
                                                                       custom  => 'Custom restrictions',
                                                                     );
                           if (@types) {
                               if (@statuses) {
                                   $chgtext .= &mt('For self-created accounts verified by e-mail address, requirements for e-mail address are as follows:').
                                               '<ul>';
                                   foreach my $status (@statuses) {
                                       if ($type eq 'default') {
                                           $chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailoptions'}{$status}}.'</li>';
                                       } else {
                                           $chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailoptions'}{$status}}.'</li>';
                                       }
                                   }
                                   $chgtext .= '</ul>';
                               }
                         } else {                          } else {
                            $chgtext .= &mt('Processing of requests to create account with e-mail address as username set to: "[_1]"',                              if ($cancreate{'emailoptions'}{'default'} eq 'any') {
                                          $choices{$cancreate{'selfcreateprocessing'}{'default'}});                                  $chgtext .= &mt('For self-created accounts verified by e-mail address, any e-mail may be used');
                               } else {
                                   $chgtext .= &mt('For self-created accounts verified by e-mail address, e-mail restricted to: "[_1]"',
                                                   $options{$cancreate{'emailoptions'}{'default'}});
                               }
                           }
                       } elsif ($type eq 'emaildomain') {
                           my $output;
                           if (@statuses) {
                               foreach my $type (@statuses) {
                                   if (ref($cancreate{'emaildomain'}{$type}) eq 'HASH') {
                                       if ($cancreate{'emailoptions'}{$type} eq 'inst') {
                                           if ($type eq 'default') {
                                               if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') ||
                                                   ($cancreate{'emaildomain'}{$type}{'inst'} eq '')) {
                                                   $output = '<li>'.$othertitle.' -- '.&mt('No restriction on e-mail domain').'</li>';
                                               } else {
                                                   $output = '<li>'.$othertitle.' -- '.&mt("User's e-mail address needs to end: [_1]",
                                                                                           $cancreate{'emaildomain'}{$type}{'inst'}).'</li>';
                                               }
                                           } else {
                                               if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') ||
                                                   ($cancreate{'emaildomain'}{$type}{'inst'} eq '')) {
                                                   $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';
                                               } else {
                                                   $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address needs to end: [_1]",
                                                                                                 $cancreate{'emaildomain'}{$type}{'inst'}).'</li>'; 
                                               }
                                           }
                                       } elsif ($cancreate{'emailoptions'}{$type} eq 'noninst') {
                                           if ($type eq 'default') {
                                               if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') ||
                                                   ($cancreate{'emaildomain'}{$type}{'noninst'} eq '')) {
                                                   $output = '<li>'.$othertitle.' -- '.&mt('No restriction on e-mail domain').'</li>';
                                               } else {
                                                   $output = '<li>'.$othertitle.' -- '.&mt("User's e-mail address must not end: [_1]",
                                                                                           $cancreate{'emaildomain'}{$type}{'noninst'}).'</li>';
                                               }
                                           } else {
                                               if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') ||
                                                   ($cancreate{'emaildomain'}{$type}{'noninst'} eq '')) {
                                                   $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';
                                               } else {
                                                   $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address must not end: [_1]",
                                                                                                   $cancreate{'emaildomain'}{$type}{'noninst'}).'</li>';   
                                               }
                                           }
                                       }
                                   }
                               }
                           }
                           if ($output ne '') {
                               $chgtext .= &mt('For self-created accounts verified by e-mail address:').
                                           '<ul>'.$output.'</ul>';
                         }                          }
                     } elsif ($type eq 'captcha') {                      } elsif ($type eq 'captcha') {
                         if ($savecaptcha{$type} eq 'notused') {                          if ($savecaptcha{$type} eq 'notused') {
Line 9198  sub modify_selfcreation { Line 15952  sub modify_selfcreation {
                             $chgtext .= '<li>'.&mt('Private key set to [_1]',$pubkey).'</li>';                              $chgtext .= '<li>'.&mt('Private key set to [_1]',$pubkey).'</li>';
                         }                          }
                         $chgtext .= '</ul>';                          $chgtext .= '</ul>';
                       } elsif ($type eq 'recaptchaversion') {
                           if ($savecaptcha{'captcha'} eq 'recaptcha') {
                               $chgtext .= &mt('ReCAPTCHA set to version [_1]',$savecaptcha{$type});
                           }
                     } elsif ($type eq 'emailusername') {                      } elsif ($type eq 'emailusername') {
                         if (ref($cancreate{'emailusername'}) eq 'HASH') {                          if (ref($cancreate{'emailusername'}) eq 'HASH') {
                             if (ref($types) eq 'ARRAY') {                              if (@statuses) {
                                 foreach my $type (@{$types}) {                                  foreach my $type (@statuses) {
                                     if (ref($cancreate{'emailusername'}{$type}) eq 'HASH') {                                      if (ref($cancreate{'emailusername'}{$type}) eq 'HASH') {
                                         if (keys(%{$cancreate{'emailusername'}{$type}}) > 0) {                                          if (keys(%{$cancreate{'emailusername'}{$type}}) > 0) {
                                             $chgtext .= &mt('When self-creating account with e-mail as username, the following information will be provided by [_1]:',"'$usertypes->{$type}'").                                              $chgtext .= &mt('When self-creating account with e-mail verification, the following information will be provided by [_1]:',"'$usertypes{$type}'").
                                                     '<ul>';                                                      '<ul>';
                                             foreach my $field (@{$infofields}) {                                              foreach my $field (@{$infofields}) {
                                                 if ($cancreate{'emailusername'}{$type}{$field}) {                                                  if ($cancreate{'emailusername'}{$type}{$field}) {
Line 9213  sub modify_selfcreation { Line 15971  sub modify_selfcreation {
                                             }                                              }
                                             $chgtext .= '</ul>';                                              $chgtext .= '</ul>';
                                         } else {                                          } else {
                                             $chgtext .= &mt('When self creating account with e-mail as username, no information besides e-mail address will be provided by [_1].',"'$usertypes->{$type}'").'<br />';                                              $chgtext .= &mt('When self creating account with e-mail verification, no information besides e-mail address will be provided by [_1].',"'$usertypes{$type}'").'<br />';
                                         }                                          }
                                     } else {                                      } else {
                                         $chgtext .= &mt('When self creating account with e-mail as username, no information besides e-mail address will be provided by [_1].',"'$usertypes->{$type}'").'<br />';                                          $chgtext .= &mt('When self creating account with e-mail verification, no information besides e-mail address will be provided by [_1].',"'$usertypes{$type}'").'<br />';
                                     }                                      }
                                 }                                  }
                             }                              }
                         }                          }
                     } elsif ($type eq 'notify') {                      } elsif ($type eq 'notify') {
                         $chgtext = &mt('No Domain Coordinators will receive notification of username requests requiring approval.');                          my $numapprove = 0;
                         if (ref($changes{'cancreate'}) eq 'ARRAY') {                          if (ref($changes{'cancreate'}) eq 'ARRAY') {
                             if ((grep(/^notify$/,@{$changes{'cancreate'}})) && (ref($cancreate{'notify'}) eq 'HASH')) {                              if ((grep(/^notify$/,@{$changes{'cancreate'}})) && (ref($cancreate{'notify'}) eq 'HASH')) {
                                 if ($cancreate{'notify'}{'approval'}) {                                  if ($cancreate{'notify'}{'approval'}) {
                                     $chgtext = &mt('Notification of username requests requiring approval will be sent to: ').$cancreate{'notify'}{'approval'};                                      $chgtext .= &mt('Notification of username requests requiring approval will be sent to: ').$cancreate{'notify'}{'approval'};
                                       $numapprove ++;
                                 }                                  }
                             }                              }
                         }                          }
                           unless ($numapprove) {
                               $chgtext .= &mt('No Domain Coordinators will receive notification of username requests requiring approval.');
                           }
                     }                      }
                     if ($chgtext) {                      if ($chgtext) {
                         $resulttext .= '<li>'.$chgtext.'</li>';                          $resulttext .= '<li>'.$chgtext.'</li>';
                     }                      }
                 }                  }
             }              }
             if (ref($changes{'email_rule'}) eq 'ARRAY') {              if ((ref($changes{'email_rule'}) eq 'ARRAY') && (@{$changes{'email_rule'}} > 0)) {
                 my ($emailrules,$emailruleorder) =                  my ($emailrules,$emailruleorder) =
                     &Apache::lonnet::inst_userrules($dom,'email');                      &Apache::lonnet::inst_userrules($dom,'email');
                 my $chgtext = '<ul>';                  foreach my $type (@{$changes{'email_rule'}}) {
                 foreach my $type (@email_rule) {                      if (ref($email_rule{$type}) eq 'ARRAY') {
                     if (ref($emailrules->{$type}) eq 'HASH') {                          my $chgtext = '<ul>';
                         $chgtext .= '<li>'.$emailrules->{$type}{'name'}.'</li>';                          foreach my $rule (@{$email_rule{$type}}) {
                               if (ref($emailrules->{$rule}) eq 'HASH') {
                                   $chgtext .= '<li>'.$emailrules->{$rule}{'name'}.'</li>';
                               }
                           }
                           $chgtext .= '</ul>';
                           my $typename;
                           if (@types) {
                               if ($type eq 'default') {
                                   $typename = $othertitle;
                               } else {
                                   $typename = $usertypes{$type};
                               } 
                               $chgtext .= &mt('(Affiliation: [_1])',$typename);
                           }
                           if (@{$email_rule{$type}} > 0) {
                               $resulttext .= '<li>'.
                                              &mt('Accounts may not be created by users verified by e-mail, for e-mail addresses of the following types: ',
                                                  $usertypes{$type}).
                                              $chgtext.
                                              '</li>';
                           } else {
                               $resulttext .= '<li>'.
                                              &mt('There are now no restrictions on e-mail addresses which may be used for verification when a user requests an account.').
                                              '</li>'.
                                              &mt('(Affiliation: [_1])',$typename);
                           }
                     }                      }
                 }                  }
                 $chgtext .= '</ul>';              }
                 if (@email_rule > 0) {              if (ref($changes{'inststatus'}) eq 'ARRAY') {
                     $resulttext .= '<li>'.                  if (ref($save_inststatus{'inststatusguest'}) eq 'ARRAY') {
                                    &mt('Accounts may not be created by users self-enrolling with e-mail addresses of the following types: ').                      if (@{$save_inststatus{'inststatusguest'}} > 0) {
                                        $chgtext.                          my $chgtext = '<ul>';
                                    '</li>';                          foreach my $type (@{$save_inststatus{'inststatusguest'}}) {
                 } else {                              $chgtext .= '<li>'.$usertypes{$type}.'</li>';
                     $resulttext .= '<li>'.                          }
                                    &mt('There are now no restrictions on e-mail addresses which may be used as a username when self-enrolling.').                          $chgtext .= '</ul>';
                                    '</li>';                          $resulttext .= '<li>'.
                                          &mt('A user will self-report one of the following affiliations when requesting an account verified by e-mail: ').
                                             $chgtext.
                                          '</li>';
                       } else {
                           $resulttext .= '<li>'.
                                          &mt('No affiliations available for self-reporting when requesting an account verified by e-mail.').
                                          '</li>';
                       }
                 }                  }
             }              }
             if (ref($changes{'selfcreate'}) eq 'ARRAY') {              if (ref($changes{'selfcreate'}) eq 'ARRAY') {
Line 9262  sub modify_selfcreation { Line 16058  sub modify_selfcreation {
                 my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();                  my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
                 foreach my $type (@{$changes{'selfcreate'}}) {                  foreach my $type (@{$changes{'selfcreate'}}) {
                     my $typename = $type;                      my $typename = $type;
                     if (ref($usertypes) eq 'HASH') {                      if (keys(%usertypes) > 0) {
                         if ($usertypes->{$type} ne '') {                          if ($usertypes{$type} ne '') {
                             $typename = $usertypes->{$type};                              $typename = $usertypes{$type};
                         }                          }
                     }                      }
                     my @modifiable;                      my @modifiable;
Line 9287  sub modify_selfcreation { Line 16083  sub modify_selfcreation {
                 $resulttext .= '</ul></li>';                  $resulttext .= '</ul></li>';
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
               my $cachetime = 24*60*60;
               $domdefaults{'inststatusguest'} = $save_inststatus{'inststatusguest'};
               &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'domdefaults'} = 1;
               }
         } else {          } else {
             $resulttext = &mt('No changes made to self-creation settings');              $resulttext = &mt('No changes made to self-creation settings');
         }          }
Line 9318  sub process_captcha { Line 16120  sub process_captcha {
             $changes->{'captcha'} = 1;              $changes->{'captcha'} = 1;
         }          }
     }      }
     my ($newpub,$newpriv,$currpub,$currpriv);      my ($newpub,$newpriv,$currpub,$currpriv,$newversion,$currversion);
     if ($newsettings->{'captcha'} eq 'recaptcha') {      if ($newsettings->{'captcha'} eq 'recaptcha') {
         $newpub = $env{'form.'.$container.'_recaptchapub'};          $newpub = $env{'form.'.$container.'_recaptchapub'};
         $newpriv = $env{'form.'.$container.'_recaptchapriv'};          $newpriv = $env{'form.'.$container.'_recaptchapriv'};
Line 9328  sub process_captcha { Line 16130  sub process_captcha {
                                              public  => $newpub,                                               public  => $newpub,
                                              private => $newpriv,                                               private => $newpriv,
                                           };                                            };
           $newversion = $env{'form.'.$container.'_recaptchaversion'};
           $newversion =~ s/\D//g;
           if ($newversion ne '2') {
               $newversion = 1;
           }
           $newsettings->{'recaptchaversion'} = $newversion;
     }      }
     if (ref($current->{'recaptchakeys'}) eq 'HASH') {      if (ref($current->{'recaptchakeys'}) eq 'HASH') {
         $currpub = $current->{'recaptchakeys'}{'public'};          $currpub = $current->{'recaptchakeys'}{'public'};
Line 9339  sub process_captcha { Line 16147  sub process_captcha {
                                               }                                                }
         }          }
     }      }
       if ($current->{'captcha'} eq 'recaptcha') {
           $currversion = $current->{'recaptchaversion'};
           if ($currversion ne '2') {
               $currversion = 1;
           }
       }
       if ($currversion ne $newversion) {
           if ($container eq 'cancreate') {
               if (ref($changes->{'cancreate'}) eq 'ARRAY') {
                   push(@{$changes->{'cancreate'}},'recaptchaversion');
               } elsif (!defined($changes->{'cancreate'})) {
                   $changes->{'cancreate'} = ['recaptchaversion'];
               }
           } else {
               $changes->{'recaptchaversion'} = 1;
           }
       }
     if (($newpub ne $currpub) || ($newpriv ne $currpriv)) {      if (($newpub ne $currpub) || ($newpriv ne $currpriv)) {
         if ($container eq 'cancreate') {          if ($container eq 'cancreate') {
             if (ref($changes->{'cancreate'}) eq 'ARRAY') {              if (ref($changes->{'cancreate'}) eq 'ARRAY') {
Line 9460  sub modify_defaults { Line 16285  sub modify_defaults {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,$mailmsgtxt,%newvalues,%changes,@errors);      my ($resulttext,$mailmsgtxt,%newvalues,%changes,@errors);
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);      my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
     my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def','portal_def');      my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def',
     my @authtypes = ('internal','krb4','krb5','localauth');                   'portal_def');
       my @authtypes = ('internal','krb4','krb5','localauth','lti');
     foreach my $item (@items) {      foreach my $item (@items) {
         $newvalues{$item} = $env{'form.'.$item};          $newvalues{$item} = $env{'form.'.$item};
         if ($item eq 'auth_def') {          if ($item eq 'auth_def') {
Line 9510  sub modify_defaults { Line 16336  sub modify_defaults {
         }          }
         $domdefaults{$item} = $newvalues{$item};          $domdefaults{$item} = $newvalues{$item};
     }      }
       my %staticdefaults = (
                              'intauth_cost'   => 10,
                              'intauth_check'  => 0,
                              'intauth_switch' => 0,
                            );
       foreach my $item ('intauth_cost','intauth_check','intauth_switch') {
           if (exists($domdefaults{$item})) {
               $newvalues{$item} = $domdefaults{$item};
           } else {
               $newvalues{$item} = $staticdefaults{$item};
           }
       }
     my %defaults_hash = (      my %defaults_hash = (
                          defaults => \%newvalues,                           defaults => \%newvalues,
                         );                          );
Line 9528  sub modify_defaults { Line 16366  sub modify_defaults {
     }      }
     my @todelete = &Apache::loncommon::get_env_multiple('form.inststatus_delete');      my @todelete = &Apache::loncommon::get_env_multiple('form.inststatus_delete');
     my @allpos;      my @allpos;
     my %guests;  
     my %alltypes;      my %alltypes;
     my ($currtitles,$currguests,$currorder);      my @inststatusguest;
       if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') {
           foreach my $type (@{$currinststatus->{'inststatusguest'}}) {
               unless (grep(/^\Q$type\E$/,@todelete)) {
                   push(@inststatusguest,$type);
               }
           }
       }
       my ($currtitles,$currorder);
     if (ref($currinststatus) eq 'HASH') {      if (ref($currinststatus) eq 'HASH') {
         if (ref($currinststatus->{'inststatusorder'}) eq 'ARRAY') {          if (ref($currinststatus->{'inststatusorder'}) eq 'ARRAY') {
             foreach my $type (@{$currinststatus->{'inststatusorder'}}) {              foreach my $type (@{$currinststatus->{'inststatusorder'}}) {
Line 9545  sub modify_defaults { Line 16390  sub modify_defaults {
                     $allpos[$position] = $type;                      $allpos[$position] = $type;
                     $alltypes{$type} = $env{'form.inststatus_title_'.$type};                      $alltypes{$type} = $env{'form.inststatus_title_'.$type};
                     $alltypes{$type} =~ s/`//g;                      $alltypes{$type} =~ s/`//g;
                     if ($env{'form.inststatus_guest_'.$type}) {  
                         $guests{$type} = 1;  
                     }  
                 }                  }
             }              }
             if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') {  
                 $currguests = join(',',@{$currinststatus->{'inststatusguest'}});  
             }  
             $currorder = join(',',@{$currinststatus->{'inststatusorder'}});              $currorder = join(',',@{$currinststatus->{'inststatusorder'}});
             $currtitles =~ s/,$//;              $currtitles =~ s/,$//;
         }          }
Line 9561  sub modify_defaults { Line 16400  sub modify_defaults {
         my $newtype = $env{'form.addinststatus'};          my $newtype = $env{'form.addinststatus'};
         $newtype =~ s/\W//g;          $newtype =~ s/\W//g;
         unless (exists($alltypes{$newtype})) {          unless (exists($alltypes{$newtype})) {
             if ($env{'form.addinststatus_guest'}) {  
                 $guests{$newtype} = 1;  
             }  
             $alltypes{$newtype} = $env{'form.addinststatus_title'};              $alltypes{$newtype} = $env{'form.addinststatus_title'};
             $alltypes{$newtype} =~ s/`//g;               $alltypes{$newtype} =~ s/`//g; 
             my $position = $env{'form.addinststatus_pos'};              my $position = $env{'form.addinststatus_pos'};
Line 9573  sub modify_defaults { Line 16409  sub modify_defaults {
             }              }
         }          }
     }      }
     my (@orderedstatus,@orderedguests);      my @orderedstatus;
     foreach my $type (@allpos) {      foreach my $type (@allpos) {
         unless (($type eq '') || (grep(/^\Q$type\E$/,@orderedstatus))) {          unless (($type eq '') || (grep(/^\Q$type\E$/,@orderedstatus))) {
             push(@orderedstatus,$type);              push(@orderedstatus,$type);
             if ($guests{$type}) {  
                 push(@orderedguests,$type);  
             }  
         }          }
     }      }
     foreach my $type (keys(%alltypes)) {      foreach my $type (keys(%alltypes)) {
Line 9590  sub modify_defaults { Line 16423  sub modify_defaults {
     $defaults_hash{'inststatus'} = {      $defaults_hash{'inststatus'} = {
                                      inststatustypes => \%alltypes,                                       inststatustypes => \%alltypes,
                                      inststatusorder => \@orderedstatus,                                       inststatusorder => \@orderedstatus,
                                      inststatusguest => \@orderedguests,                                       inststatusguest => \@inststatusguest,
                                    };                                     };
     if (ref($defaults_hash{'inststatus'}) eq 'HASH') {      if (ref($defaults_hash{'inststatus'}) eq 'HASH') {
         foreach my $item ('inststatustypes','inststatusorder','inststatusguest') {          foreach my $item ('inststatustypes','inststatusorder','inststatusguest') {
Line 9600  sub modify_defaults { Line 16433  sub modify_defaults {
     if ($currorder ne join(',',@orderedstatus)) {      if ($currorder ne join(',',@orderedstatus)) {
         $changes{'inststatus'}{'inststatusorder'} = 1;          $changes{'inststatus'}{'inststatusorder'} = 1;
     }      }
     if ($currguests ne join(',',@orderedguests)) {  
         $changes{'inststatus'}{'inststatusguest'} = 1;  
     }  
     my $newtitles;      my $newtitles;
     foreach my $item (@orderedstatus) {      foreach my $item (@orderedstatus) {
         $newtitles .= $alltypes{$item}.',';          $newtitles .= $alltypes{$item}.',';
Line 9621  sub modify_defaults { Line 16451  sub modify_defaults {
             foreach my $item (sort(keys(%changes))) {              foreach my $item (sort(keys(%changes))) {
                 if ($item eq 'inststatus') {                  if ($item eq 'inststatus') {
                     if (ref($changes{'inststatus'}) eq 'HASH') {                      if (ref($changes{'inststatus'}) eq 'HASH') {
                         if (($changes{'inststatus'}{'inststatustypes'}) || $changes{'inststatus'}{'inststatusorder'}) {                          if (@orderedstatus) {
                             $resulttext .= '<li>'.&mt('Institutional user status types set to:').' ';                              $resulttext .= '<li>'.&mt('Institutional user status types set to:').' ';
                             foreach my $type (@orderedstatus) {                               foreach my $type (@orderedstatus) { 
                                 $resulttext .= $alltypes{$type}.', ';                                  $resulttext .= $alltypes{$type}.', ';
                             }                              }
                             $resulttext =~ s/, $//;                              $resulttext =~ s/, $//;
                             $resulttext .= '</li>';                              $resulttext .= '</li>';
                         }                          } else {
                         if ($changes{'inststatus'}{'inststatusguest'}) {                              $resulttext .= '<li>'.&mt('Institutional user status types deleted').'</li>'; 
                             $resulttext .= '<li>';   
                             if (@orderedguests) {  
                                 $resulttext .= &mt('Types assignable to "non-institutional" usernames set to:').' ';  
                                 foreach my $type (@orderedguests) {  
                                     $resulttext .= $alltypes{$type}.', ';  
                                 }  
                                 $resulttext =~ s/, $//;  
                             } else {  
                                 $resulttext .= &mt('Types assignable to "non-institutional" usernames set to none.');  
                             }  
                             $resulttext .= '</li>';  
                         }                          }
                     }                      }
                 } else {                  } else {
Line 9654  sub modify_defaults { Line 16473  sub modify_defaults {
                                           krb4       => 'krb4',                                            krb4       => 'krb4',
                                           krb5       => 'krb5',                                            krb5       => 'krb5',
                                           localauth  => 'loc',                                            localauth  => 'loc',
                                             lti        => 'lti',
                         );                          );
                         $value = $authnames{$shortauth{$value}};                          $value = $authnames{$shortauth{$value}};
                     }                      }
Line 9704  sub modify_scantron { Line 16524  sub modify_scantron {
     my $custom = 'custom.tab';      my $custom = 'custom.tab';
     my $default = 'default.tab';      my $default = 'default.tab';
     my $servadm = $r->dir_config('lonAdmEMail');      my $servadm = $r->dir_config('lonAdmEMail');
     my ($configuserok,$author_ok,$switchserver) =       my ($configuserok,$author_ok,$switchserver) =
         &config_check($dom,$confname,$servadm);          &config_check($dom,$confname,$servadm);
     if ($env{'form.scantronformat.filename'} ne '') {      if ($env{'form.scantronformat.filename'} ne '') {
         my $error;          my $error;
Line 9739  sub modify_scantron { Line 16559  sub modify_scantron {
             if ($env{'form.scantronformat_del'}) {              if ($env{'form.scantronformat_del'}) {
                 $confhash{'scantron'}{'scantronformat'} = '';                  $confhash{'scantron'}{'scantronformat'} = '';
                 $changes{'scantronformat'} = 1;                  $changes{'scantronformat'} = 1;
               } else {
                   $confhash{'scantron'}{'scantronformat'} = $domconfig{'scantron'}{'scantronformat'};
               }
           }
       }
       my @options = ('hdr','pad','rem');
       my @fields = &scantroncsv_fields();
       my %titles = &scantronconfig_titles();
       my @formats = &Apache::loncommon::get_env_multiple('form.scantronconfig');
       my ($newdat,$currdat,%newcol,%currcol);
       if (grep(/^dat$/,@formats)) {
           $confhash{'scantron'}{config}{dat} = 1;
           $newdat = 1;
       } else {
           $newdat = 0;
       }
       if (grep(/^csv$/,@formats)) {
           my %bynum;
           foreach my $field (@fields) {
               if ($env{'form.scantronconfig_csv_'.$field} =~ /^(\d+)$/) {
                   my $posscol = $1;
                   if (($posscol < 20) && (!$bynum{$posscol})) {
                       $confhash{'scantron'}{config}{csv}{fields}{$field} = $posscol;
                       $bynum{$posscol} = $field;
                       $newcol{$field} = $posscol;
                   }
               }
           }
           if (keys(%newcol)) {
               foreach my $option (@options) {
                   if ($env{'form.scantroncsv_'.$option}) {
                       $confhash{'scantron'}{config}{csv}{options}{$option} = 1;
                   }
               }
           }
       }
       $currdat = 1;
       if (ref($domconfig{'scantron'}) eq 'HASH') {
           if (ref($domconfig{'scantron'}{'config'}) eq 'HASH') {
               unless (exists($domconfig{'scantron'}{'config'}{'dat'})) {
                   $currdat = 0;
               }
               if (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH') {
                   if (ref($domconfig{'scantron'}{'config'}{'csv'}{'fields'}) eq 'HASH') {
                       %currcol = %{$domconfig{'scantron'}{'config'}{'csv'}{'fields'}};
                   }
               }
           }
       }
       if ($currdat != $newdat) {
           $changes{'config'} = 1;
       } else {
           foreach my $field (@fields) {
               if ($currcol{$field} ne '') {
                   if ($currcol{$field} ne $newcol{$field}) {
                       $changes{'config'} = 1;
                       last;
                   }
               } elsif ($newcol{$field} ne '') {
                   $changes{'config'} = 1;
                   last;
             }              }
         }          }
     }      }
Line 9749  sub modify_scantron { Line 16630  sub modify_scantron {
             if (keys(%changes) > 0) {              if (keys(%changes) > 0) {
                 if (ref($confhash{'scantron'}) eq 'HASH') {                  if (ref($confhash{'scantron'}) eq 'HASH') {
                     $resulttext = &mt('Changes made:').'<ul>';                      $resulttext = &mt('Changes made:').'<ul>';
                     if ($confhash{'scantron'}{'scantronformat'} eq '') {                      if ($changes{'scantronformat'}) {
                         $resulttext .= '<li>'.&mt('[_1] bubblesheet format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'</li>';                          if ($confhash{'scantron'}{'scantronformat'} eq '') {
                     } else {                              $resulttext .= '<li>'.&mt('[_1] bubblesheet format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'</li>';
                         $resulttext .= '<li>'.&mt('Custom bubblesheet format file ([_1]) uploaded for use with courses in this domain.',$custom).'</li>';                          } else {
                               $resulttext .= '<li>'.&mt('Custom bubblesheet format file ([_1]) uploaded for use with courses in this domain.',$custom).'</li>';
                           }
                       }
                       if ($changes{'config'}) {
                           if (ref($confhash{'scantron'}{'config'}) eq 'HASH') {
                               if ($confhash{'scantron'}{'config'}{'dat'}) {
                                   $resulttext .= '<li>'.&mt('Bubblesheet data upload formats includes .dat format').'</li>';
                               }
                               if (ref($confhash{'scantron'}{'config'}{'csv'}) eq 'HASH') {
                                   if (ref($confhash{'scantron'}{'config'}{'csv'}{'fields'}) eq 'HASH') {
                                       if (keys(%{$confhash{'scantron'}{'config'}{'csv'}{'fields'}})) {
                                           $resulttext .= '<li>'.&mt('Bubblesheet data upload formats includes .csv format, with following fields/column numbers supported:').'<ul>';
                                           foreach my $field (@fields) {
                                               if ($confhash{'scantron'}{'config'}{'csv'}{'fields'}{$field} ne '') {
                                                   my $showcol = $confhash{'scantron'}{'config'}{'csv'}{'fields'}{$field} + 1;
                                                   $resulttext .= '<li>'.$titles{$field}.': '.$showcol.'</li>';
                                               }
                                           }
                                           $resulttext .= '</ul></li>';
                                           if (ref($confhash{'scantron'}{'config'}{'csv'}{'options'}) eq 'HASH') {
                                               if (keys(%{$confhash{'scantron'}{'config'}{'csv'}{'options'}})) {
                                                   $resulttext .= '<li>'.&mt('Bubblesheet data upload formats includes .csv format, with following options:').'<ul>';
                                                   foreach my $option (@options) {
                                                       if ($confhash{'scantron'}{'config'}{'csv'}{'options'}{$option} ne '') {
                                                           $resulttext .= '<li>'.$titles{$option}.'</li>';
                                                       }
                                                   }
                                                   $resulttext .= '</ul></li>';
                                               }
                                           }
                                       }
                                   }
                               }
                           } else {
                               $resulttext .= '<li>'.&mt('No bubblesheet data upload formats set -- will default to assuming .dat format').'</li>';
                           }
                     }                      }
                     $resulttext .= '</ul>';                      $resulttext .= '</ul>';
                 } else {                  } else {
                     $resulttext = &mt('Changes made to bubblesheet format file.');                      $resulttext = &mt('Changes made to bubblesheet format file.');
                 }                  }
                 $resulttext .= '</ul>';  
                 &Apache::loncommon::devalidate_domconfig_cache($dom);                  &Apache::loncommon::devalidate_domconfig_cache($dom);
                 if (ref($lastactref) eq 'HASH') {                  if (ref($lastactref) eq 'HASH') {
                     $lastactref->{'domainconfig'} = 1;                      $lastactref->{'domainconfig'} = 1;
                 }                  }
             } else {              } else {
                 $resulttext = &mt('No changes made to bubblesheet format file');                  $resulttext = &mt('No changes made to bubblesheet format settings');
             }              }
         } else {          } else {
             $resulttext = '<span class="LC_error">'.              $resulttext = '<span class="LC_error">'.
Line 9774  sub modify_scantron { Line 16690  sub modify_scantron {
         $resulttext = &mt('No changes made to bubblesheet format file');           $resulttext = &mt('No changes made to bubblesheet format file'); 
     }      }
     if ($errors) {      if ($errors) {
         $resulttext .= &mt('The following errors occurred: ').'<ul>'.          $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.
                        $errors.'</ul>';                         $errors.'</ul></p>';
     }      }
     return $resulttext;      return $resulttext;
 }  }
Line 9804  sub modify_coursecategories { Line 16720  sub modify_coursecategories {
         if ($domconfig{'coursecategories'}{'categorizecomm'} ne $env{'form.categorizecomm'}) {          if ($domconfig{'coursecategories'}{'categorizecomm'} ne $env{'form.categorizecomm'}) {
             $changes{'categorizecomm'} = 1;              $changes{'categorizecomm'} = 1;
             $domconfig{'coursecategories'}{'categorizecomm'} = $env{'form.categorizecomm'};              $domconfig{'coursecategories'}{'categorizecomm'} = $env{'form.categorizecomm'};
   
           }
           if ($domconfig{'coursecategories'}{'togglecatsplace'} ne $env{'form.togglecatsplace'}) {
               $changes{'togglecatsplace'} = 1;
               $domconfig{'coursecategories'}{'togglecatsplace'} = $env{'form.togglecatsplace'};
           }
           if ($domconfig{'coursecategories'}{'categorizeplace'} ne $env{'form.categorizeplace'}) {
               $changes{'categorizeplace'} = 1;
               $domconfig{'coursecategories'}{'categorizeplace'} = $env{'form.categorizeplace'};
         }          }
         foreach my $item (@catitems) {          foreach my $item (@catitems) {
             if (grep(/^\Q$env{'form.coursecat_'.$item}\E$/,@cattypes)) {              if (grep(/^\Q$env{'form.coursecat_'.$item}\E$/,@cattypes)) {
Line 9818  sub modify_coursecategories { Line 16743  sub modify_coursecategories {
         $changes{'categorize'} = 1;          $changes{'categorize'} = 1;
         $changes{'togglecatscomm'} = 1;          $changes{'togglecatscomm'} = 1;
         $changes{'categorizecomm'} = 1;          $changes{'categorizecomm'} = 1;
           $changes{'togglecatsplace'} = 1;
           $changes{'categorizeplace'} = 1;
         $domconfig{'coursecategories'} = {          $domconfig{'coursecategories'} = {
                                              togglecats => $env{'form.togglecats'},                                               togglecats => $env{'form.togglecats'},
                                              categorize => $env{'form.categorize'},                                               categorize => $env{'form.categorize'},
                                              togglecatscomm => $env{'form.togglecatscomm'},                                               togglecatscomm => $env{'form.togglecatscomm'},
                                              categorizecomm => $env{'form.categorizecomm'},                                               categorizecomm => $env{'form.categorizecomm'},
                                                togglecatsplace => $env{'form.togglecatsplace'},
                                                categorizeplace => $env{'form.categorizeplace'},
                                          };                                           };
         foreach my $item (@catitems) {          foreach my $item (@catitems) {
             if ($env{'form.coursecat_'.$item} ne 'std') {              if ($env{'form.coursecat_'.$item} ne 'std') {
Line 9840  sub modify_coursecategories { Line 16769  sub modify_coursecategories {
         if (($domconfig{'coursecategories'}{'cats'}{'communities::0'} ne '')  && ($env{'form.communities'} == 0)) {          if (($domconfig{'coursecategories'}{'cats'}{'communities::0'} ne '')  && ($env{'form.communities'} == 0)) {
             push(@deletecategory,'communities::0');              push(@deletecategory,'communities::0');
         }          }
           if (($domconfig{'coursecategories'}{'cats'}{'placement::0'} ne '')  && ($env{'form.placement'} == 0)) {
               push(@deletecategory,'placement::0');
           }
     }      }
     my (@predelcats,@predeltrails,%predelallitems,%sort_by_deltrail);      my (@predelcats,@predeltrails,%predelallitems,%sort_by_deltrail);
     if (ref($cathash) eq 'HASH') {      if (ref($cathash) eq 'HASH') {
Line 9902  sub modify_coursecategories { Line 16834  sub modify_coursecategories {
             $adds{$newitem} = 1;              $adds{$newitem} = 1;
         }          }
     }      }
       if ($env{'form.placement'} eq '1') {
           if (ref($cathash) eq 'HASH') {
               my $newitem = 'placement::0';
               if ($cathash->{$newitem} eq '') {
                   $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.placement_pos'};
                   $adds{$newitem} = 1;
               }
           } else {
               my $newitem = 'placement::0';
               $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.placement_pos'};
               $adds{$newitem} = 1;
           }
       }
     if ($env{'form.addcategory_name'} ne '') {      if ($env{'form.addcategory_name'} ne '') {
         if (($env{'form.addcategory_name'} ne 'instcode') &&          if (($env{'form.addcategory_name'} ne 'instcode') &&
             ($env{'form.addcategory_name'} ne 'communities')) {              ($env{'form.addcategory_name'} ne 'communities') &&
               ($env{'form.addcategory_name'} ne 'placement')) {
             my $newitem = &escape($env{'form.addcategory_name'}).'::0';              my $newitem = &escape($env{'form.addcategory_name'}).'::0';
             $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos'};              $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos'};
             $adds{$newitem} = 1;              $adds{$newitem} = 1;
Line 10020  sub modify_coursecategories { Line 16966  sub modify_coursecategories {
                     }                      }
                     $resulttext .= '</ul></li>';                      $resulttext .= '</ul></li>';
                 }                  }
                   &Apache::lonnet::do_cache_new('cats',$dom,$cathash,3600);
                   if (ref($lastactref) eq 'HASH') {
                       $lastactref->{'cats'} = 1;
                   }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
             if ($changes{'unauth'} || $changes{'auth'}) {              if ($changes{'unauth'} || $changes{'auth'}) {
Line 10171  sub modify_serverstatuses { Line 17121  sub modify_serverstatuses {
 }  }
   
 sub modify_helpsettings {  sub modify_helpsettings {
     my ($r,$dom,$confname,%domconfig) = @_;      my ($r,$dom,$confname,$lastactref,%domconfig) = @_;
     my ($resulttext,$errors,%changes,%helphash);      my ($resulttext,$errors,%changes,%helphash);
     my %defaultchecked = ('submitbugs' => 'on');      my %defaultchecked = ('submitbugs' => 'on');
     my @offon = ('off','on');      my @offon = ('off','on');
     my @toggles = ('submitbugs');      my @toggles = ('submitbugs');
       my %current = ('submitbugs' => '',
                      'adhoc'      => {},
                     );
     if (ref($domconfig{'helpsettings'}) eq 'HASH') {      if (ref($domconfig{'helpsettings'}) eq 'HASH') {
         foreach my $item (@toggles) {          %current = %{$domconfig{'helpsettings'}};
             if ($defaultchecked{$item} eq 'on') {       }
                 if ($domconfig{'helpsettings'}{$item} eq '') {      my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
                     if ($env{'form.'.$item} eq '0') {      foreach my $item (@toggles) {
                         $changes{$item} = 1;          if ($defaultchecked{$item} eq 'on') { 
                     }              if ($current{$item} eq '') {
                 } elsif ($domconfig{'helpsettings'}{$item} ne $env{'form.'.$item}) {                  if ($env{'form.'.$item} eq '0') {
                     $changes{$item} = 1;                      $changes{$item} = 1;
                 }                  }
             } elsif ($defaultchecked{$item} eq 'off') {              } elsif ($current{$item} ne $env{'form.'.$item}) {
                 if ($domconfig{'helpsettings'}{$item} eq '') {                  $changes{$item} = 1;
                     if ($env{'form.'.$item} eq '1') {              }
                         $changes{$item} = 1;          } elsif ($defaultchecked{$item} eq 'off') {
                     }              if ($current{$item} eq '') {
                 } elsif ($domconfig{'helpsettings'}{$item} ne $env{'form.'.$item}) {                  if ($env{'form.'.$item} eq '1') {
                     $changes{$item} = 1;                      $changes{$item} = 1;
                 }                  }
               } elsif ($current{$item} ne $env{'form.'.$item}) {
                   $changes{$item} = 1;
               }
           }
           if (($env{'form.'.$item} eq '0') || ($env{'form.'.$item} eq '1')) {
               $helphash{'helpsettings'}{$item} = $env{'form.'.$item};
           }
       }
       my $maxnum = $env{'form.helproles_maxnum'};
       my $confname = $dom.'-domainconfig';
       my %existing=&Apache::lonnet::dump('roles',$dom,$confname,'rolesdef_');
       my (@allpos,%newsettings,%changedprivs,$newrole);
       my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
       my @accesstypes = ('all','dh','da','none','status','inc','exc');
       my %domhelpdesk = &Apache::lonnet::get_active_domroles($dom,['dh','da']);
       my %lt = &Apache::lonlocal::texthash(
                       s      => 'system',
                       d      => 'domain',
                       order  => 'Display order',
                       access => 'Role usage',
                       all    => 'All with domain helpdesk or helpdesk assistant role',
                       dh     => 'All with domain helpdesk role',
                       da     => 'All with domain helpdesk assistant role',
                       none   => 'None',
                       status => 'Determined based on institutional status',
                       inc    => 'Include all, but exclude specific personnel',
                       exc    => 'Exclude all, but include specific personnel',
       );
       for (my $num=0; $num<=$maxnum; $num++) {
           my ($prefix,$identifier,$rolename,%curr);
           if ($num == $maxnum) {
               next unless ($env{'form.newcusthelp'} == $maxnum);
               $identifier = 'custhelp'.$num;
               $prefix = 'helproles_'.$num;
               $rolename = $env{'form.custhelpname'.$num};
               $rolename=~s/[^A-Za-z0-9]//gs;
               next if ($rolename eq '');
               next if (exists($existing{'rolesdef_'.$rolename}));
               my %newprivs = &Apache::lonuserutils::custom_role_update($rolename,$identifier);
               my $result = &Apache::lonnet::definerole($rolename,$newprivs{'s'},$newprivs{'d'},
                                                        $newprivs{'c'},$confname,$dom);
               if ($result ne 'ok') {
                   $errors .= '<li><span class="LC_error">'.
                              &mt('An error occurred storing the new custom role: [_1]',
                              $result).'</span></li>';
                   next;
               } else {
                   $changedprivs{$rolename} = \%newprivs;
                   $newrole = $rolename;
               }
           } else {
               $prefix = 'helproles_'.$num;
               $rolename = $env{'form.'.$prefix};
               next if ($rolename eq '');
               next unless (exists($existing{'rolesdef_'.$rolename}));
               $identifier = 'custhelp'.$num;
               my %newprivs = &Apache::lonuserutils::custom_role_update($rolename,$identifier);
               my %currprivs;
               ($currprivs{'s'},$currprivs{'d'},$currprivs{'c'}) =
                   split(/\_/,$existing{'rolesdef_'.$rolename});
               foreach my $level ('c','d','s') {
                   if ($newprivs{$level} ne $currprivs{$level}) {
                       my $result = &Apache::lonnet::definerole($rolename,$newprivs{'s'},$newprivs{'d'},
                                                                $newprivs{'c'},$confname,$dom);
                       if ($result ne 'ok') {
                           $errors .= '<li><span class="LC_error">'.
                                      &mt('An error occurred storing privileges for existing role [_1]: [_2]',
                                          $rolename,$result).'</span></li>';
                       } else {
                           $changedprivs{$rolename} = \%newprivs;
                       }
                       last;
                   }
               }
               if (ref($current{'adhoc'}) eq 'HASH') {
                   if (ref($current{'adhoc'}{$rolename}) eq 'HASH') {
                       %curr = %{$current{'adhoc'}{$rolename}};
                   }
               }
           }
           my $newpos = $env{'form.'.$prefix.'_pos'};
           $newpos =~ s/\D+//g;
           $allpos[$newpos] = $rolename;
           my $newdesc = $env{'form.'.$prefix.'_desc'};
           $helphash{'helpsettings'}{'adhoc'}{$rolename}{'desc'} = $newdesc;
           if ($curr{'desc'}) {
               if ($curr{'desc'} ne $newdesc) {
                   $changes{'customrole'}{$rolename}{'desc'} = 1;
                   $newsettings{$rolename}{'desc'} = $newdesc;
               }
           } elsif ($newdesc ne '') {
               $changes{'customrole'}{$rolename}{'desc'} = 1;
               $newsettings{$rolename}{'desc'} = $newdesc;
           }
           my $access = $env{'form.'.$prefix.'_access'};
           if (grep(/^\Q$access\E$/,@accesstypes)) {
               $helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'} = $access;
               if ($access eq 'status') {
                   my @statuses = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_status');
                   if (scalar(@statuses) == 0) {
                       $helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'} = 'none';
                   } else {
                       my (@shownstatus,$numtypes);
                       $helphash{'helpsettings'}{'adhoc'}{$rolename}{$access} = [];
                       if (ref($types) eq 'ARRAY') {
                           $numtypes = scalar(@{$types});
                           foreach my $type (sort(@statuses)) {
                               if ($type eq 'default') {
                                   push(@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}},$type);
                               } elsif (grep(/^\Q$type\E$/,@{$types})) {
                                   push(@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}},$type);
                                   push(@shownstatus,$usertypes->{$type});
                               }
                           }
                       }
                       if (grep(/^default$/,@statuses)) {
                           push(@shownstatus,$othertitle);
                       }
                       if (scalar(@shownstatus) == 1+$numtypes) {
                           $helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'} = 'all';
                           delete($helphash{'helpsettings'}{'adhoc'}{$rolename}{'status'});
                       } else {
                           $newsettings{$rolename}{'status'} = join(' '.&mt('or').' ',@shownstatus);
                           if (ref($curr{'status'}) eq 'ARRAY') {
                               my @diffs = &Apache::loncommon::compare_arrays($helphash{'helpsettings'}{'adhoc'}{$rolename}{$access},$curr{$access});
                               if (@diffs) {
                                   $changes{'customrole'}{$rolename}{$access} = 1;
                               }
                           } elsif (@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}}) {
                               $changes{'customrole'}{$rolename}{$access} = 1;
                           }
                       }
                   }
               } elsif (($access eq 'inc') || ($access eq 'exc')) {
                   my @personnel = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_staff_'.$access);
                   my @newspecstaff;
                   $helphash{'helpsettings'}{'adhoc'}{$rolename}{$access} = [];
                   foreach my $person (sort(@personnel)) {
                       if ($domhelpdesk{$person}) {
                           push(@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}},$person);
                       }
                   }
                   if (ref($curr{$access}) eq 'ARRAY') {
                       my @diffs = &Apache::loncommon::compare_arrays($helphash{'helpsettings'}{'adhoc'}{$rolename}{$access},$curr{$access});
                       if (@diffs) {
                           $changes{'customrole'}{$rolename}{$access} = 1;
                       }
                   } elsif (@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}}) {
                       $changes{'customrole'}{$rolename}{$access} = 1;
                   }
                   foreach my $person (@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}}) {
                       my ($uname,$udom) = split(/:/,$person);
                           push(@newspecstaff,&Apache::loncommon::aboutmewrapper(&Apache::loncommon::plainname($uname,$udom,'lastname'),$uname,$udom));
                   }
                   $newsettings{$rolename}{$access} = join(', ',sort(@newspecstaff));
             }              }
             if (($env{'form.'.$item} eq '0') || ($env{'form.'.$item} eq '1')) {          } else {
                 $helphash{'helpsettings'}{$item} = $env{'form.'.$item};              $helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'}= 'all';
           }
           unless ($curr{'access'} eq $access) {
               $changes{'customrole'}{$rolename}{'access'} = 1;
               $newsettings{$rolename}{'access'} = $lt{$helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'}};
           }
       }
       if (@allpos > 0) {
           my $idx = 0;
           foreach my $rolename (@allpos) {
               if ($rolename ne '') {
                   $helphash{'helpsettings'}{'adhoc'}{$rolename}{'order'} = $idx;
                   if (ref($current{'adhoc'}) eq 'HASH') {
                       if (ref($current{'adhoc'}{$rolename}) eq 'HASH') {
                           if ($current{'adhoc'}{$rolename}{'order'} ne $idx) {
                               $changes{'customrole'}{$rolename}{'order'} = 1;
                               $newsettings{$rolename}{'order'} = $idx+1;
                           }
                       }
                   }
                   $idx ++;
             }              }
         }          }
     }      }
Line 10204  sub modify_helpsettings { Line 17332  sub modify_helpsettings {
     if (keys(%changes) > 0) {      if (keys(%changes) > 0) {
         $putresult = &Apache::lonnet::put_dom('configuration',\%helphash,$dom);          $putresult = &Apache::lonnet::put_dom('configuration',\%helphash,$dom);
         if ($putresult eq 'ok') {          if ($putresult eq 'ok') {
             $resulttext = &mt('Changes made:').'<ul>';              if (ref($helphash{'helpsettings'}) eq 'HASH') {
                   $domdefaults{'submitbugs'} = $helphash{'helpsettings'}{'submitbugs'};
                   if (ref($helphash{'helpsettings'}{'adhoc'}) eq 'HASH') {
                       $domdefaults{'adhocroles'} = $helphash{'helpsettings'}{'adhoc'};
                   }
               }
               my $cachetime = 24*60*60;
               &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'domdefaults'} = 1;
               }
           } else {
               $errors .= '<li><span class="LC_error">'.
                          &mt('An error occurred storing the settings: [_1]',
                              $putresult).'</span></li>';
           }
       }
       if ((keys(%changes) && ($putresult eq 'ok')) || (keys(%changedprivs))) {
           $resulttext = &mt('Changes made:').'<ul>';
           my (%shownprivs,@levelorder);
           @levelorder = ('c','d','s');
           if ((keys(%changes)) && ($putresult eq 'ok')) {
             foreach my $item (sort(keys(%changes))) {              foreach my $item (sort(keys(%changes))) {
                 if ($item eq 'submitbugs') {                  if ($item eq 'submitbugs') {
                     $resulttext .= '<li>'.&mt('Display link to: [_1] set to "'.$offon[$env{'form.'.$item}].'".',                      $resulttext .= '<li>'.&mt('Display link to: [_1] set to "'.$offon[$env{'form.'.$item}].'".',
                                               &Apache::loncommon::modal_link('http://bugs.loncapa.org',                                                &Apache::loncommon::modal_link('http://bugs.loncapa.org',
                                               &mt('LON-CAPA bug tracker'),600,500)).'</li>';                                                &mt('LON-CAPA bug tracker'),600,500)).'</li>';
                   } elsif ($item eq 'customrole') {
                       if (ref($changes{'customrole'}) eq 'HASH') {
                           my @keyorder = ('order','desc','access','status','exc','inc');
                           my %keytext = &Apache::lonlocal::texthash(
                                                                      order  => 'Order',
                                                                      desc   => 'Role description',
                                                                      access => 'Role usage',
                                                                      status => 'Allowed institutional types',
                                                                      exc    => 'Allowed personnel',
                                                                      inc    => 'Disallowed personnel',
                           );
                           foreach my $role (sort(keys(%{$changes{'customrole'}}))) {
                               if (ref($changes{'customrole'}{$role}) eq 'HASH') {
                                   if ($role eq $newrole) {
                                       $resulttext .= '<li>'.&mt('New custom role added: [_1]',
                                                                 $role).'<ul>';
                                   } else {
                                       $resulttext .= '<li>'.&mt('Existing custom role modified: [_1]',
                                                                 $role).'<ul>';
                                   }
                                   foreach my $key (@keyorder) {
                                       if ($changes{'customrole'}{$role}{$key}) {
                                           $resulttext .= '<li>'.&mt("[_1] set to: [_2]",
                                                                     $keytext{$key},$newsettings{$role}{$key}).
                                                          '</li>';
                                       }
                                   }
                                   if (ref($changedprivs{$role}) eq 'HASH') {
                                       $shownprivs{$role} = 1;
                                       $resulttext .= '<li>'.&mt('Privileges set to :').'<ul>';
                                       foreach my $level (@levelorder) {
                                           foreach my $item (split(/\:/,$changedprivs{$role}{$level})) {
                                               next if ($item eq '');
                                               my ($priv) = split(/\&/,$item,2);
                                               if (&Apache::lonnet::plaintext($priv)) {
                                                   $resulttext .= '<li>'.&Apache::lonnet::plaintext($priv);
                                                   unless ($level eq 'c') {
                                                       $resulttext .= ' ('.$lt{$level}.')';
                                                   }
                                                   $resulttext .= '</li>';
                                               }
                                           }
                                       }
                                       $resulttext .= '</ul>';
                                   }
                                   $resulttext .= '</ul></li>';
                               }
                           }
                       }
                   }
               }
           }
           if (keys(%changedprivs)) {
               foreach my $role (sort(keys(%changedprivs))) {
                   unless ($shownprivs{$role}) {
                       $resulttext .= '<li>'.&mt('Existing custom role modified: [_1]',
                                                 $role).'<ul>'.
                                      '<li>'.&mt('Privileges set to :').'<ul>';
                       foreach my $level (@levelorder) {
                           foreach my $item (split(/\:/,$changedprivs{$role}{$level})) {
                               next if ($item eq '');
                               my ($priv) = split(/\&/,$item,2);
                               if (&Apache::lonnet::plaintext($priv)) {
                                   $resulttext .= '<li>'.&Apache::lonnet::plaintext($priv);
                                   unless ($level eq 'c') {
                                       $resulttext .= ' ('.$lt{$level}.')';
                                   }
                                   $resulttext .= '</li>';
                               }
                           }
                       }
                       $resulttext .= '</ul></li></ul></li>';
                 }                  }
             }              }
             $resulttext .= '</ul>';  
         } else {  
             $resulttext = &mt('No changes made to help settings');  
             $errors .= '<li><span class="LC_error">'.  
                        &mt('An error occurred storing the settings: [_1]',  
                            $putresult).'</span></li>';  
         }          }
           $resulttext .= '</ul>';
       } else {
           $resulttext = &mt('No changes made to help settings');
     }      }
     if ($errors) {      if ($errors) {
         $resulttext .= '<br />'.&mt('The following errors occurred: ').'<ul>'.          $resulttext .= '<br />'.&mt('The following errors occurred: ').'<ul>'.
                        $errors.'</ul>';                                      $errors.'</ul>';
     }      }
     return $resulttext;      return $resulttext;
 }  }
Line 10237  sub modify_coursedefaults { Line 17455  sub modify_coursedefaults {
                          );                           );
     my @toggles = ('canuse_pdfforms','uselcmath','usejsme');      my @toggles = ('canuse_pdfforms','uselcmath','usejsme');
     my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial',      my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial',
                    'uploadquota_community','uploadquota_textbook');                     'uploadquota_community','uploadquota_textbook','uploadquota_placement',
     my @types = ('official','unofficial','community','textbook');                     'mysqltables_official','mysqltables_unofficial','mysqltables_community',
                      'mysqltables_textbook','mysqltables_placement');
       my @types = ('official','unofficial','community','textbook','placement');
     my %staticdefaults = (      my %staticdefaults = (
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
                            postsubmit           => 60,                             postsubmit           => 60,
                              mysqltables          => 172800,
                          );                           );
       my %texoptions = (
                           MathJax  => 'MathJax',
                           mimetex  => &mt('Convert to Images'),
                           tth      => &mt('TeX to HTML'),
                        );
     $defaultshash{'coursedefaults'} = {};      $defaultshash{'coursedefaults'} = {};
   
     if (ref($domconfig{'coursedefaults'}) ne 'HASH') {      if (ref($domconfig{'coursedefaults'}) ne 'HASH') {
Line 10283  sub modify_coursedefaults { Line 17508  sub modify_coursedefaults {
                 }                  }
                 $defaultshash{'coursedefaults'}{$item} = $newdef;                  $defaultshash{'coursedefaults'}{$item} = $newdef;
             } else {              } else {
                 my ($type) = ($item =~ /^\Quploadquota_\E(\w+)$/);                  my ($setting,$type) = ($item =~ /^(uploadquota|mysqltables)_(\w+)$/);
                 if (ref($domconfig{'coursedefaults'}{'uploadquota'}) eq 'HASH') {                  if (ref($domconfig{'coursedefaults'}{$setting}) eq 'HASH') {
                     $currdef = $domconfig{'coursedefaults'}{'uploadquota'}{$type};                      $currdef = $domconfig{'coursedefaults'}{$setting}{$type};
                 }                  }
                 $newdef =~ s/[^\w.\-]//g;                  $newdef =~ s/[^\w.\-]//g;
                 $defaultshash{'coursedefaults'}{'uploadquota'}{$type} = $newdef;                  $defaultshash{'coursedefaults'}{$setting}{$type} = $newdef;
             }              }
             if ($currdef ne $newdef) {              if ($currdef ne $newdef) {
                 my $staticdef;  
                 if ($item eq 'anonsurvey_threshold') {                  if ($item eq 'anonsurvey_threshold') {
                     unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) {                      unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) {
                         $changes{$item} = 1;                          $changes{$item} = 1;
                     }                      }
                 } else {                  } elsif ($item =~ /^(uploadquota|mysqltables)_/) {
                     unless (($currdef eq '') && ($newdef == $staticdefaults{'uploadquota'})) {                      my $setting = $1;
                         $changes{'uploadquota'} = 1;                      unless (($currdef eq '') && ($newdef == $staticdefaults{$setting})) {
                           $changes{$setting} = 1;
                     }                      }
                 }                  }
             }              }
         }          }
           my $texengine;
           if ($env{'form.texengine'} =~ /^(MathJax|mimetex|tth)$/) {
               $texengine = $env{'form.texengine'};
               my $currdef = $domconfig{'coursedefaults'}{'texengine'};
               if ($currdef eq '') {
                   unless ($texengine eq $Apache::lonnet::deftex) {
                       $changes{'texengine'} = 1;
                   }
               } elsif ($currdef ne $texengine) {
                   $changes{'texengine'} = 1;
               }
           }
           if ($texengine ne '') {
               $defaultshash{'coursedefaults'}{'texengine'} = $texengine;
           }
           my $currclone = $domconfig{'coursedefaults'}{'canclone'};
           my @currclonecode;
           if (ref($currclone) eq 'HASH') {
               if (ref($currclone->{'instcode'}) eq 'ARRAY') {
                   @currclonecode = @{$currclone->{'instcode'}};
               }
           }
           my $newclone;
           if ($env{'form.canclone'} =~ /^(none|domain|instcode)$/) {
               $newclone = $env{'form.canclone'};
           }
           if ($newclone eq 'instcode') {
               my @newcodes = &Apache::loncommon::get_env_multiple('form.clonecode');
               my (%codedefaults,@code_order,@clonecode);
               &Apache::lonnet::auto_instcode_defaults($dom,\%codedefaults,
                                                       \@code_order);
               foreach my $item (@code_order) {
                   if (grep(/^\Q$item\E$/,@newcodes)) {
                       push(@clonecode,$item);
                   }
               }
               if (@clonecode) {
                   $defaultshash{'coursedefaults'}{'canclone'} = { $newclone => \@clonecode };
                   my @diffs = &Apache::loncommon::compare_arrays(\@currclonecode,\@clonecode);
                   if (@diffs) {
                       $changes{'canclone'} = 1;
                   }
               } else {
                   $newclone eq '';
               }
           } elsif ($newclone ne '') {
               $defaultshash{'coursedefaults'}{'canclone'} = $newclone;
           }
           if ($newclone ne $currclone) {
               $changes{'canclone'} = 1;
           }
         my %credits;          my %credits;
         foreach my $type (@types) {          foreach my $type (@types) {
             unless ($type eq 'community') {              unless ($type eq 'community') {
Line 10318  sub modify_coursedefaults { Line 17593  sub modify_coursedefaults {
                 $defaultshash{'coursedefaults'}{'coursecredits'}{$type} = $credits{$type};                  $defaultshash{'coursedefaults'}{'coursecredits'}{$type} = $credits{$type};
             }              }
         } else {          } else {
             if ($env{'form.coursecredits'} eq '1') {               if ($env{'form.coursecredits'} eq '1') {
                 foreach my $type (@types) {                  foreach my $type (@types) {
                     unless ($type eq 'community') {                      unless ($type eq 'community') {
                         if ($domconfig{'coursedefaults'}{'coursecredits'}{$type} ne $credits{$type}) {                                  if ($domconfig{'coursedefaults'}{'coursecredits'}{$type} ne $credits{$type}) {
                             $changes{'coursecredits'} = 1;                              $changes{'coursecredits'} = 1;
                         }                          }
                         $defaultshash{'coursedefaults'}{'coursecredits'}{$type} = $credits{$type};                          $defaultshash{'coursedefaults'}{'coursecredits'}{$type} = $credits{$type};
Line 10364  sub modify_coursedefaults { Line 17639  sub modify_coursedefaults {
                 }                  }
                 if (exists($currtimeout{$type})) {                  if (exists($currtimeout{$type})) {
                     if ($timeout ne $currtimeout{$type}) {                      if ($timeout ne $currtimeout{$type}) {
                         $changes{'postsubmit'} = 1;                           $changes{'postsubmit'} = 1;
                     }                      }
                 } elsif ($timeout ne '') {                  } elsif ($timeout ne '') {
                     $changes{'postsubmit'} = 1;                      $changes{'postsubmit'} = 1;
Line 10387  sub modify_coursedefaults { Line 17662  sub modify_coursedefaults {
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
             my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);              my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
             if (($changes{'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'}) ||
                 foreach my $item ('canuse_pdfforms','uselcmath','usejsme') {                   ($changes{'canclone'}) || ($changes{'mysqltables'}) || ($changes{'texengine'})) {
                   foreach my $item ('canuse_pdfforms','uselcmath','usejsme','texengine') {
                     if ($changes{$item}) {                      if ($changes{$item}) {
                         $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};                          $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};
                     }                      }
                 }                   }
                 if ($changes{'coursecredits'}) {                  if ($changes{'coursecredits'}) {
                     if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') {                      if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') {
                         foreach my $type (keys(%{$defaultshash{'coursedefaults'}{'coursecredits'}})) {                          foreach my $type (keys(%{$defaultshash{'coursedefaults'}{'coursecredits'}})) {
Line 10419  sub modify_coursedefaults { Line 17695  sub modify_coursedefaults {
                         }                          }
                     }                      }
                 }                  }
                   if ($changes{'canclone'}) {
                       if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') {
                           if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {
                               my @clonecodes = @{$defaultshash{'coursedefaults'}{'canclone'}{'instcode'}};
                               if (@clonecodes) {
                                   $domdefaults{'canclone'} = join('+',@clonecodes);
                               }
                           }
                       } else {
                           $domdefaults{'canclone'}=$defaultshash{'coursedefaults'}{'canclone'};
                       }
                   }
                 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 10443  sub modify_coursedefaults { Line 17731  sub modify_coursedefaults {
                     if ($env{'form.'.$item} eq '1') {                      if ($env{'form.'.$item} eq '1') {
                         $resulttext .= '<li>'.&mt('Molecule editor uses JSME (HTML5), if supported by browser.').'</li>';                          $resulttext .= '<li>'.&mt('Molecule editor uses JSME (HTML5), if supported by browser.').'</li>';
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('Molecule editor uses JME (Java), if supported by client OS.').'</li>';                           $resulttext .= '<li>'.&mt('Molecule editor uses JME (Java), if supported by client OS.').'</li>';
                       }
                   } elsif ($item eq 'texengine') {
                       if ($defaultshash{'coursedefaults'}{'texengine'} ne '') {
                           $resulttext .= '<li>'.&mt('Default method to display mathematics set to: "[_1]"',
                                                     $texoptions{$defaultshash{'coursedefaults'}{'texengine'}}).'</li>';
                     }                      }
                 } elsif ($item eq 'anonsurvey_threshold') {                  } elsif ($item eq 'anonsurvey_threshold') {
                     $resulttext .= '<li>'.&mt('Responder count required for display of anonymous survey submissions set to [_1].',$defaultshash{'coursedefaults'}{'anonsurvey_threshold'}).'</li>';                      $resulttext .= '<li>'.&mt('Responder count required for display of anonymous survey submissions set to [_1].',$defaultshash{'coursedefaults'}{'anonsurvey_threshold'}).'</li>';
Line 10453  sub modify_coursedefaults { Line 17746  sub modify_coursedefaults {
                                        '<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'official'}.'</b>').'</li>'.                                         '<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'official'}.'</b>').'</li>'.
                                        '<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'unofficial'}.'</b>').'</li>'.                                         '<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'unofficial'}.'</b>').'</li>'.
                                        '<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'textbook'}.'</b>').'</li>'.                                         '<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'textbook'}.'</b>').'</li>'.
                                          '<li>'.&mt('Placement tests: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'placement'}.'</b>').'</li>'. 
                                        '<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'community'}.'</b>').'</li>'.                                         '<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'community'}.'</b>').'</li>'.
                                        '</ul>'.                                         '</ul>'.
                                        '</li>';                                         '</li>';
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('Default quota for content uploaded via Course Editor remains default: [_1] MB',$staticdefaults{'uploadquota'}).'</li>';                          $resulttext .= '<li>'.&mt('Default quota for content uploaded via Course Editor remains default: [_1] MB',$staticdefaults{'uploadquota'}).'</li>';
                     }                      }
                   } elsif ($item eq 'mysqltables') {
                       if (ref($defaultshash{'coursedefaults'}{'mysqltables'}) eq 'HASH') {
                           $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver').'<ul>'.
                                          '<li>'.&mt('Official courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'official'}.'</b>').'</li>'.
                                          '<li>'.&mt('Unofficial courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'unofficial'}.'</b>').'</li>'.
                                          '<li>'.&mt('Textbook courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'textbook'}.'</b>').'</li>'.
                                          '<li>'.&mt('Placement tests: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'placement'}.'</b>').'</li>'.
                                          '<li>'.&mt('Communities: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'community'}.'</b>').'</li>'.
                                          '</ul>'.
                                          '</li>';
                       } else {
                           $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver remains default: [_1] s',$staticdefaults{'uploadquota'}).'</li>';
                       }
                 } elsif ($item eq 'postsubmit') {                  } elsif ($item eq 'postsubmit') {
                     if ($domdefaults{'postsubmit'} eq 'off') {                      if ($domdefaults{'postsubmit'} eq 'off') {
                         $resulttext .= '<li>'.&mt('Submit button(s) remain enabled on page after student makes submission.');                          $resulttext .= '<li>'.&mt('Submit button(s) remain enabled on page after student makes submission.');
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('Submit button(s) disabled on page after student makes submission').'; ';                          $resulttext .= '<li>'.&mt('Submit button(s) disabled on page after student makes submission').'; ';
                         if (ref($defaultshash{'coursedefaults'}{'postsubmit'}) eq 'HASH') {                           if (ref($defaultshash{'coursedefaults'}{'postsubmit'}) eq 'HASH') {
                             $resulttext .= &mt('durations:').'<ul>';                              $resulttext .= &mt('durations:').'<ul>';
                             foreach my $type (@types) {                              foreach my $type (@types) {
                                 $resulttext .= '<li>';                                  $resulttext .= '<li>';
Line 10489  sub modify_coursedefaults { Line 17795  sub modify_coursedefaults {
                                     $resulttext .= &mt('Unofficial courses');                                      $resulttext .= &mt('Unofficial courses');
                                 } elsif ($type eq 'textbook') {                                  } elsif ($type eq 'textbook') {
                                     $resulttext .= &mt('Textbook courses');                                      $resulttext .= &mt('Textbook courses');
                                   } elsif ($type eq 'placement') {
                                       $resulttext .= &mt('Placement tests');
                                 }                                  }
                                 $resulttext .= ' -- '.$display.'</li>';                                  $resulttext .= ' -- '.$display.'</li>';
                             }                              }
                             $resulttext .= '</ul>';                              $resulttext .= '</ul>';
                         }                          }
                         $resulttext .= '</li>';                              $resulttext .= '</li>';
                     }                      }
                 } elsif ($item eq 'coursecredits') {                  } elsif ($item eq 'coursecredits') {
                     if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') {                      if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') {
Line 10513  sub modify_coursedefaults { Line 17821  sub modify_coursedefaults {
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('Student credits not in use for courses in this domain').'</li>';                          $resulttext .= '<li>'.&mt('Student credits not in use for courses in this domain').'</li>';
                     }                      }
                   } elsif ($item eq 'canclone') {
                       if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') {
                           if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {
                               my $clonecodes = join(' '.&mt('and').' ',@{$defaultshash{'coursedefaults'}{'canclone'}{'instcode'}});
                               $resulttext .= '<li>'.&mt('By default, official courses can be cloned from existing courses with the same: [_1]','<b>'.$clonecodes.'</b>').'</li>';
                           }
                       } elsif ($defaultshash{'coursedefaults'}{'canclone'} eq 'domain') {
                           $resulttext .= '<li>'.&mt('By default, a course requester can clone any course from his/her domain.').'</li>';
                       } else {
                           $resulttext .= '<li>'.&mt('By default, only course owner and coordinators may clone a course.').'</li>';
                       }
                 }                  }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
Line 10529  sub modify_coursedefaults { Line 17848  sub modify_coursedefaults {
 sub modify_selfenrollment {  sub modify_selfenrollment {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,$errors,%changes,%selfenrollhash,%ordered);      my ($resulttext,$errors,%changes,%selfenrollhash,%ordered);
     my @types = ('official','unofficial','community','textbook');      my @types = ('official','unofficial','community','textbook','placement');
     my %titles = &tool_titles();      my %titles = &tool_titles();
     my %descs = &Apache::lonuserutils::selfenroll_default_descs();      my %descs = &Apache::lonuserutils::selfenroll_default_descs();
     ($ordered{'admin'},my $titlesref) = &Apache::lonuserutils::get_selfenroll_titles();      ($ordered{'admin'},my $titlesref) = &Apache::lonuserutils::get_selfenroll_titles();
Line 10746  sub modify_selfenrollment { Line 18065  sub modify_selfenrollment {
                         $resulttext .= '</ul></li>';                           $resulttext .= '</ul></li>'; 
                     }                      }
                 }                  }
                 if ((exists($changes{'admin'})) || (exists($changes{'default'}))) {              }
                     my $cachetime = 24*60*60;              if ((exists($changes{'admin'})) || (exists($changes{'default'}))) {
                     &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);                  my $cachetime = 24*60*60;
                     if (ref($lastactref) eq 'HASH') {                  &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
                         $lastactref->{'domdefaults'} = 1;                  if (ref($lastactref) eq 'HASH') {
                     }                      $lastactref->{'domdefaults'} = 1;
                 }                  }
             }              }
             $resulttext .= '</ul>';              $resulttext .= '</ul>';
Line 10776  sub modify_usersessions { Line 18095  sub modify_usersessions {
                 );                  );
     my @prefixes = ('remote','hosted','spares');      my @prefixes = ('remote','hosted','spares');
     my @lcversions = &Apache::lonnet::all_loncaparevs();      my @lcversions = &Apache::lonnet::all_loncaparevs();
     my (%by_ip,%by_location,@intdoms);      my (%by_ip,%by_location,@intdoms,@instdoms);
     &build_location_hashes(\@intdoms,\%by_ip,\%by_location);      &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
     my @locations = sort(keys(%by_location));      my @locations = sort(keys(%by_location));
     my (%defaultshash,%changes);      my (%defaultshash,%changes);
     foreach my $prefix (@prefixes) {      foreach my $prefix (@prefixes) {
Line 10931  sub modify_usersessions { Line 18250  sub modify_usersessions {
             $changes{'spares'}{$lonhost} = \%spareschg;              $changes{'spares'}{$lonhost} = \%spareschg;
         }          }
     }      }
       $defaultshash{'usersessions'}{'offloadnow'} = {};
       my @offloadnow = &Apache::loncommon::get_env_multiple('form.offloadnow');
       my @okoffload;
       if (@offloadnow) {
           foreach my $server (@offloadnow) {
               if (&Apache::lonnet::hostname($server) ne '') {
                   unless (grep(/^\Q$server\E$/,@okoffload)) {
                       push(@okoffload,$server);
                   }
               }
           }
           if (@okoffload) {
               foreach my $lonhost (@okoffload) {
                   $defaultshash{'usersessions'}{'offloadnow'}{$lonhost} = 1;
               }
           }
       }
     if (ref($domconfig{'usersessions'}) eq 'HASH') {      if (ref($domconfig{'usersessions'}) eq 'HASH') {
         if (ref($domconfig{'usersessions'}{'spares'}) eq 'HASH') {          if (ref($domconfig{'usersessions'}{'spares'}) eq 'HASH') {
             if (ref($changes{'spares'}) eq 'HASH') {              if (ref($changes{'spares'}) eq 'HASH') {
Line 10942  sub modify_usersessions { Line 18277  sub modify_usersessions {
         } else {          } else {
             $savespares = 1;              $savespares = 1;
         }          }
           if (ref($domconfig{'usersessions'}{'offloadnow'}) eq 'HASH') {
               foreach my $lonhost (keys(%{$domconfig{'usersessions'}{'offloadnow'}})) {
                   unless ($defaultshash{'usersessions'}{'offloadnow'}{$lonhost}) {
                       $changes{'offloadnow'} = 1;
                       last;
                   }
               }
               unless ($changes{'offloadnow'}) {
                   foreach my $lonhost (keys(%{$defaultshash{'usersessions'}{'offloadnow'}})) {
                       unless ($domconfig{'usersessions'}{'offloadnow'}{$lonhost}) {
                           $changes{'offloadnow'} = 1;
                           last;
                       }
                   }
               }
           } elsif (@okoffload) {
               $changes{'offloadnow'} = 1;
           }
       } elsif (@okoffload) {
           $changes{'offloadnow'} = 1;
     }      }
   
     my $nochgmsg = &mt('No changes made to settings for user session hosting/offloading.');      my $nochgmsg = &mt('No changes made to settings for user session hosting/offloading.');
     if ((keys(%changes) > 0) || ($savespares)) {      if ((keys(%changes) > 0) || ($savespares)) {
         my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,          my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
Line 10956  sub modify_usersessions { Line 18310  sub modify_usersessions {
                 if (ref($defaultshash{'usersessions'}{'hosted'}) eq 'HASH') {                  if (ref($defaultshash{'usersessions'}{'hosted'}) eq 'HASH') {
                     $domdefaults{'hostedsessions'} = $defaultshash{'usersessions'}{'hosted'};                      $domdefaults{'hostedsessions'} = $defaultshash{'usersessions'}{'hosted'};
                 }                  }
                   if (ref($defaultshash{'usersessions'}{'offloadnow'}) eq 'HASH') {
                       $domdefaults{'offloadnow'} = $defaultshash{'usersessions'}{'offloadnow'};
                   }
             }              }
             my $cachetime = 24*60*60;              my $cachetime = 24*60*60;
             &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);              &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               &Apache::lonnet::do_cache_new('usersessions',$dom,$defaultshash{'usersessions'},3600);
             if (ref($lastactref) eq 'HASH') {              if (ref($lastactref) eq 'HASH') {
                 $lastactref->{'domdefaults'} = 1;                  $lastactref->{'domdefaults'} = 1;
                   $lastactref->{'usersessions'} = 1;
             }              }
             if (keys(%changes) > 0) {              if (keys(%changes) > 0) {
                 my %lt = &usersession_titles();                  my %lt = &usersession_titles();
Line 10994  sub modify_usersessions { Line 18353  sub modify_usersessions {
                         } else {                          } else {
                             foreach my $type (@{$types{$prefix}}) {                              foreach my $type (@{$types{$prefix}}) {
                                 if (defined($changes{$prefix}{$type})) {                                  if (defined($changes{$prefix}{$type})) {
                                     my $newvalue;                                      my ($newvalue,$notinuse);
                                     if (ref($defaultshash{'usersessions'}) eq 'HASH') {                                      if (ref($defaultshash{'usersessions'}) eq 'HASH') {
                                         if (ref($defaultshash{'usersessions'}{$prefix})) {                                          if (ref($defaultshash{'usersessions'}{$prefix})) {
                                             if ($type eq 'version') {                                              if ($type eq 'version') {
                                                 $newvalue = $defaultshash{'usersessions'}{$prefix}{$type};                                                  $newvalue = $defaultshash{'usersessions'}{$prefix}{$type};
                                             } elsif (ref($defaultshash{'usersessions'}{$prefix}{$type}) eq 'ARRAY') {                                              } else {
                                                 if (@{$defaultshash{'usersessions'}{$prefix}{$type}} > 0) {                                                  if (ref($defaultshash{'usersessions'}{$prefix}{$type}) eq 'ARRAY') {
                                                     $newvalue = join(', ',@{$defaultshash{'usersessions'}{$prefix}{$type}});                                                      if (@{$defaultshash{'usersessions'}{$prefix}{$type}} > 0) {
                                                           $newvalue = join(', ',@{$defaultshash{'usersessions'}{$prefix}{$type}});
                                                       }
                                                   } else {
                                                       $notinuse = 1;
                                                 }                                                  }
                                             }                                              }
                                         }                                          }
Line 11009  sub modify_usersessions { Line 18372  sub modify_usersessions {
                                     if ($newvalue eq '') {                                      if ($newvalue eq '') {
                                         if ($type eq 'version') {                                          if ($type eq 'version') {
                                             $resulttext .= '<li>'.&mt('[_1] set to: off',$lt{$type}).'</li>';                                              $resulttext .= '<li>'.&mt('[_1] set to: off',$lt{$type}).'</li>';
                                           } elsif ($notinuse) {
                                               $resulttext .= '<li>'.&mt('[_1] set to: not in use',$lt{$type}).'</li>';
                                         } else {                                          } else {
                                             $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';                                              $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';
                                         }                                          }
                                     } else {                                      } else {
                                         if ($type eq 'version') {                                          if ($type eq 'version') {
                                             $newvalue .= ' '.&mt('(or later)');                                               $newvalue .= ' '.&mt('(or later)');
                                         }                                          }
                                         $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>';                                          $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>';
                                     }                                      }
Line 11024  sub modify_usersessions { Line 18389  sub modify_usersessions {
                         $resulttext .= '</ul>';                          $resulttext .= '</ul>';
                     }                      }
                 }                  }
                   if ($changes{'offloadnow'}) {
                       if (ref($defaultshash{'usersessions'}{'offloadnow'}) eq 'HASH') {
                           if (keys(%{$defaultshash{'usersessions'}{'offloadnow'}}) > 0) {
                               $resulttext .= '<li>'.&mt('Switch active users on next access, for server(s):').'<ul>';
                               foreach my $lonhost (sort(keys(%{$defaultshash{'usersessions'}{'offloadnow'}}))) {
                                   $resulttext .= '<li>'.$lonhost.'</li>';
                               }
                               $resulttext .= '</ul>';
                           } else {
                               $resulttext .= '<li>'.&mt('No servers now set to switch active users on next access.');
                           }
                       } else {
                           $resulttext .= '<li>'.&mt('No servers now set to switch active users on next access.').'</li>';
                       }
                   }
                   $resulttext .= '</ul>';
               } else {
                   $resulttext = $nochgmsg;
               }
           } else {
               $resulttext = '<span class="LC_error">'.
                             &mt('An error occurred: [_1]',$putresult).'</span>';
           }
       } else {
           $resulttext = $nochgmsg;
       }
       return $resulttext;
   }
   
   sub modify_ssl {
       my ($dom,$lastactref,%domconfig) = @_;
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
       my @locations = sort(keys(%by_location));
       my %servers = &Apache::lonnet::internet_dom_servers($dom);
       my (%defaultshash,%changes);
       my $action = 'ssl';
       my @prefixes = ('connto','connfrom','replication');
       foreach my $prefix (@prefixes) {
           $defaultshash{$action}{$prefix} = {};
       }
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my $resulttext;
       my %iphost = &Apache::lonnet::get_iphost();
       my @reptypes = ('certreq','nocertreq');
       my @connecttypes = ('dom','intdom','other');
       my %types = (
                     connto      => \@connecttypes,
                     connfrom    => \@connecttypes,
                     replication => \@reptypes,
                   );
       foreach my $prefix (sort(keys(%types))) {
           foreach my $type (@{$types{$prefix}}) {
               if (($prefix eq 'connto') || ($prefix eq 'connfrom')) {
                   my $value = 'yes';
                   if ($env{'form.'.$prefix.'_'.$type} =~ /^(no|req)$/) {
                       $value = $env{'form.'.$prefix.'_'.$type};
                   }
                   if (ref($domconfig{$action}) eq 'HASH') {
                       if (ref($domconfig{$action}{$prefix}) eq 'HASH') {
                           if ($domconfig{$action}{$prefix}{$type} ne '') {
                               if ($value ne $domconfig{$action}{$prefix}{$type}) {
                                   $changes{$prefix}{$type} = 1;
                               }
                               $defaultshash{$action}{$prefix}{$type} = $value;
                           } else {
                               $defaultshash{$action}{$prefix}{$type} = $value;
                               $changes{$prefix}{$type} = 1;
                           }
                       } else {
                           $defaultshash{$action}{$prefix}{$type} = $value;
                           $changes{$prefix}{$type} = 1;
                       }
                   } else {
                       $defaultshash{$action}{$prefix}{$type} = $value;
                       $changes{$prefix}{$type} = 1;
                   }
                   if (($type eq 'dom') && (keys(%servers) == 1)) {
                       delete($changes{$prefix}{$type});
                   } elsif (($type eq 'intdom') && (@instdoms == 1)) {
                       delete($changes{$prefix}{$type});
                   } elsif (($type eq 'other') && (keys(%by_location) == 0)) { 
                       delete($changes{$prefix}{$type});
                   }
               } elsif ($prefix eq 'replication') {
                   if (@locations > 0) {
                       my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'};
                       my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type);
                       my @okvals;
                       foreach my $val (@vals) {
                           if ($val =~ /:/) {
                               my @items = split(/:/,$val);
                               foreach my $item (@items) {
                                   if (ref($by_location{$item}) eq 'ARRAY') {
                                       push(@okvals,$item);
                                   }
                               }
                           } else {
                               if (ref($by_location{$val}) eq 'ARRAY') {
                                   push(@okvals,$val);
                               }
                           }
                       }
                       @okvals = sort(@okvals);
                       if (ref($domconfig{$action}) eq 'HASH') {
                           if (ref($domconfig{$action}{$prefix}) eq 'HASH') {
                               if (ref($domconfig{$action}{$prefix}{$type}) eq 'ARRAY') {
                                   if ($inuse == 0) {
                                       $changes{$prefix}{$type} = 1;
                                   } else {
                                       $defaultshash{$action}{$prefix}{$type} = \@okvals;
                                       my @changed = &Apache::loncommon::compare_arrays($domconfig{$action}{$prefix}{$type},$defaultshash{$action}{$prefix}{$type});
                                       if (@changed > 0) {
                                           $changes{$prefix}{$type} = 1;
                                       }
                                   }
                               } else {
                                   if ($inuse == 1) {
                                       $defaultshash{$action}{$prefix}{$type} = \@okvals;
                                       $changes{$prefix}{$type} = 1;
                                   }
                               }
                           } else {
                               if ($inuse == 1) {
                                   $defaultshash{$action}{$prefix}{$type} = \@okvals;
                                   $changes{$prefix}{$type} = 1;
                               }
                           }
                       } else {
                           if ($inuse == 1) {
                               $defaultshash{$action}{$prefix}{$type} = \@okvals;
                               $changes{$prefix}{$type} = 1;
                           }
                       }
                   }
               }
           }
       }
       if (keys(%changes)) {
           foreach my $prefix (keys(%changes)) {
               if (ref($changes{$prefix}) eq 'HASH') {
                   if (scalar(keys(%{$changes{$prefix}})) == 0) {
                       delete($changes{$prefix});
                   }
               } else {
                   delete($changes{$prefix});
               }
           }
       }
       my $nochgmsg = &mt('No changes made to LON-CAPA SSL settings');
       if (keys(%changes) > 0) {
           my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                                    $dom);
           if ($putresult eq 'ok') {
               if (ref($defaultshash{$action}) eq 'HASH') {
                   if (ref($defaultshash{$action}{'replication'}) eq 'HASH') {
                       $domdefaults{'replication'} = $defaultshash{$action}{'replication'};
                   }
                   if (ref($defaultshash{$action}{'connto'}) eq 'HASH') {
                       $domdefaults{'connto'} = $defaultshash{$action}{'connto'};
                   }
                   if (ref($defaultshash{$action}{'connfrom'}) eq 'HASH') {
                       $domdefaults{'connfrom'} = $defaultshash{$action}{'connfrom'};
                   }
               }
               my $cachetime = 24*60*60;
               &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'domdefaults'} = 1;
               }
               if (keys(%changes) > 0) {
                   my %titles = &ssl_titles();
                   $resulttext = &mt('Changes made:').'<ul>';
                   foreach my $prefix (@prefixes) {
                       if (ref($changes{$prefix}) eq 'HASH') {
                           $resulttext .= '<li>'.$titles{$prefix}.'<ul>';
                           foreach my $type (@{$types{$prefix}}) {
                               if (defined($changes{$prefix}{$type})) {
                                   my ($newvalue,$notinuse);
                                   if (ref($defaultshash{$action}) eq 'HASH') {
                                       if (ref($defaultshash{$action}{$prefix})) {
                                           if (($prefix eq 'connto') || ($prefix eq 'connfrom')) {
                                               $newvalue = $titles{$defaultshash{$action}{$prefix}{$type}};
                                           } else {
                                               if (ref($defaultshash{$action}{$prefix}{$type}) eq 'ARRAY') {
                                                   if (@{$defaultshash{$action}{$prefix}{$type}} > 0) {
                                                       $newvalue = join(', ',@{$defaultshash{$action}{$prefix}{$type}});
                                                   }
                                               } else {
                                                   $notinuse = 1;
                                               }
                                           }
                                       }
                                       if ($notinuse) {
                                           $resulttext .= '<li>'.&mt('[_1] set to: not in use',$titles{$type}).'</li>';
                                       } elsif ($newvalue eq '') {
                                           $resulttext .= '<li>'.&mt('[_1] set to: none',$titles{$type}).'</li>';
                                       } else {
                                           $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$titles{$type},$newvalue).'</li>';
                                       }
                                   }
                               }
                           }
                           $resulttext .= '</ul>';
                       }
                   }
               } else {
                   $resulttext = $nochgmsg;
               }
           } else {
               $resulttext = '<span class="LC_error">'.
                             &mt('An error occurred: [_1]',$putresult).'</span>';
           }
       } else {
           $resulttext = $nochgmsg;
       }
       return $resulttext;
   }
   
   sub modify_trust {
       my ($dom,$lastactref,%domconfig) = @_;
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
       my @locations = sort(keys(%by_location));
       my @prefixes = qw(content shared enroll othcoau coaurem domroles catalog reqcrs msg);
       my @types = ('exc','inc');
       my (%defaultshash,%changes);
       foreach my $prefix (@prefixes) {
           $defaultshash{'trust'}{$prefix} = {};
       }
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my $resulttext;
       foreach my $prefix (@prefixes) {
           foreach my $type (@types) {
               my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'};
               my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type);
               my @okvals;
               foreach my $val (@vals) {
                   if ($val =~ /:/) {
                       my @items = split(/:/,$val);
                       foreach my $item (@items) {
                           if (ref($by_location{$item}) eq 'ARRAY') {
                               push(@okvals,$item);
                           }
                       }
                   } else {
                       if (ref($by_location{$val}) eq 'ARRAY') {
                           push(@okvals,$val);
                       }
                   }
               }
               @okvals = sort(@okvals);
               if (ref($domconfig{'trust'}) eq 'HASH') {
                   if (ref($domconfig{'trust'}{$prefix}) eq 'HASH') {
                       if (ref($domconfig{'trust'}{$prefix}{$type}) eq 'ARRAY') {
                           if ($inuse == 0) {
                               $changes{$prefix}{$type} = 1;
                           } else {
                               $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                               my @changed = &Apache::loncommon::compare_arrays($domconfig{'trust'}{$prefix}{$type},$defaultshash{'trust'}{$prefix}{$type});
                               if (@changed > 0) {
                                   $changes{$prefix}{$type} = 1;
                               }
                           }
                       } else {
                           if ($inuse == 1) {
                               $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                               $changes{$prefix}{$type} = 1;
                           }
                       }
                   } else {
                       if ($inuse == 1) {
                           $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                           $changes{$prefix}{$type} = 1;
                       }
                   }
               } else {
                   if ($inuse == 1) {
                       $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                       $changes{$prefix}{$type} = 1;
                   }
               }
           }
       }
       my $nochgmsg = &mt('No changes made to trust settings.');
       if (keys(%changes) > 0) {
           my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                                    $dom);
           if ($putresult eq 'ok') {
               if (ref($defaultshash{'trust'}) eq 'HASH') {
                   foreach my $prefix (@prefixes) {
                       if (ref($defaultshash{'trust'}{$prefix}) eq 'HASH') {
                           $domdefaults{'trust'.$prefix} = $defaultshash{'trust'}{$prefix};
                       }
                   }
               }
               my $cachetime = 24*60*60;
               &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'domdefaults'} = 1;
               }
               if (keys(%changes) > 0) {
                   my %lt = &trust_titles();
                   $resulttext = &mt('Changes made:').'<ul>';
                   foreach my $prefix (@prefixes) {
                       if (ref($changes{$prefix}) eq 'HASH') {
                           $resulttext .= '<li>'.$lt{$prefix}.'<ul>';
                           foreach my $type (@types) {
                               if (defined($changes{$prefix}{$type})) {
                                   my ($newvalue,$notinuse);
                                   if (ref($defaultshash{'trust'}) eq 'HASH') {
                                       if (ref($defaultshash{'trust'}{$prefix})) {
                                           if (ref($defaultshash{'trust'}{$prefix}{$type}) eq 'ARRAY') {
                                               if (@{$defaultshash{'trust'}{$prefix}{$type}} > 0) {
                                                   $newvalue = join(', ',@{$defaultshash{'trust'}{$prefix}{$type}});
                                               }
                                           } else {
                                               $notinuse = 1;
                                           }
                                       }
                                   }
                                   if ($notinuse) {
                                       $resulttext .= '<li>'.&mt('[_1] set to: not in use',$lt{$type}).'</li>';
                                   } elsif ($newvalue eq '') {
                                       $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';
                                   } else {
                                       $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>';
                                   }
                               }
                           }
                           $resulttext .= '</ul>';
                       }
                   }
                 $resulttext .= '</ul>';                  $resulttext .= '</ul>';
             } else {              } else {
                 $resulttext = $nochgmsg;                  $resulttext = $nochgmsg;
Line 11049  sub modify_loadbalancing { Line 18747  sub modify_loadbalancing {
     my @sparestypes = ('primary','default');      my @sparestypes = ('primary','default');
     my %typetitles = &sparestype_titles();      my %typetitles = &sparestype_titles();
     my $resulttext;      my $resulttext;
     my (%currbalancer,%currtargets,%currrules,%existing);      my (%currbalancer,%currtargets,%currrules,%existing,%currcookies);
     if (ref($domconfig{'loadbalancing'}) eq 'HASH') {      if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
         %existing = %{$domconfig{'loadbalancing'}};          %existing = %{$domconfig{'loadbalancing'}};
     }      }
     &get_loadbalancers_config(\%servers,\%existing,\%currbalancer,      &get_loadbalancers_config(\%servers,\%existing,\%currbalancer,
                               \%currtargets,\%currrules);                                \%currtargets,\%currrules,\%currcookies);
     my ($saveloadbalancing,%defaultshash,%changes);      my ($saveloadbalancing,%defaultshash,%changes);
     my ($alltypes,$othertypes,$titles) =      my ($alltypes,$othertypes,$titles) =
         &loadbalancing_titles($dom,$intdom,$usertypes,$types);          &loadbalancing_titles($dom,$intdom,$usertypes,$types);
Line 11098  sub modify_loadbalancing { Line 18796  sub modify_loadbalancing {
                         push(@offloadto,$target);                          push(@offloadto,$target);
                     }                      }
                 }                  }
                 $defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype} = \@offloadto;              }
               if ($env{'form.loadbalancing_target_'.$i.'_hosthere'} eq $sparetype) {
                   unless(grep(/^\Q$balancer\E$/,@offloadto)) {
                       push(@offloadto,$balancer);
                   }
               }
               $defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype} = \@offloadto;
           }
           if ($env{'form.loadbalancing_cookie_'.$i}) {
               $defaultshash{'loadbalancing'}{$balancer}{'cookie'} = 1;
               if (exists($currbalancer{$balancer})) { 
                   unless ($currcookies{$balancer}) {
                       $changes{'curr'}{$balancer}{'cookie'} = 1;
                   }
               }
           } elsif (exists($currbalancer{$balancer})) {
               if ($currcookies{$balancer}) {
                   $changes{'curr'}{$balancer}{'cookie'} = 1;
             }              }
         }          }
         if (ref($currtargets{$balancer}) eq 'HASH') {          if (ref($currtargets{$balancer}) eq 'HASH') {
Line 11138  sub modify_loadbalancing { Line 18853  sub modify_loadbalancing {
                 }                  }
                 if ($rule eq 'specific') {                  if ($rule eq 'specific') {
                     my $specifiedhost = $env{'form.loadbalancing_singleserver_'.$i.'_'.$type};                      my $specifiedhost = $env{'form.loadbalancing_singleserver_'.$i.'_'.$type};
                     if (exists($servers{$specifiedhost})) {                       if (exists($servers{$specifiedhost})) {
                         $rule = $specifiedhost;                          $rule = $specifiedhost;
                     }                      }
                 }                  }
Line 11214  sub modify_loadbalancing { Line 18929  sub modify_loadbalancing {
                                         if ($rule eq '') {                                          if ($rule eq '') {
                                             $balancetext =  $ruletitles{'default'};                                              $balancetext =  $ruletitles{'default'};
                                         } elsif (($rule eq 'homeserver') || ($rule eq 'externalbalancer') ||                                          } elsif (($rule eq 'homeserver') || ($rule eq 'externalbalancer') ||
                                                  ($type eq '_LC_ipchange') || ($type eq '_LC_ipchangesso')) {                                                    ($type eq '_LC_ipchange') || ($type eq '_LC_ipchangesso')) {
                                             if (($type eq '_LC_ipchange') || ($type eq '_LC_ipchangesso')) {                                              if (($type eq '_LC_ipchange') || ($type eq '_LC_ipchangesso')) {
                                                 foreach my $sparetype (@sparestypes) {                                                  foreach my $sparetype (@sparestypes) {
                                                     if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') {                                                      if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') {
Line 11254  sub modify_loadbalancing { Line 18969  sub modify_loadbalancing {
                                 }                                  }
                             }                              }
                         }                          }
                           if ($changes{'curr'}{$balancer}{'cookie'}) {
                               $resulttext .= '<li>'.&mt('Load Balancer: [_1] -- cookie use enabled',
                                                         $balancer).'</li>'; 
                           }
                         if (keys(%toupdate)) {                          if (keys(%toupdate)) {
                             my %thismachine;                              my %thismachine;
                             my $updatedhere;                              my $updatedhere;
Line 11333  sub recurse_cat_deletes { Line 19052  sub recurse_cat_deletes {
     return;      return;
 }  }
   
 sub get_active_dcs {  
     my ($dom) = @_;  
     my $now = time;  
     my %dompersonnel = &Apache::lonnet::get_domain_roles($dom,['dc'],$now,$now);  
     my %domcoords;  
     my $numdcs = 0;  
     foreach my $server (keys(%dompersonnel)) {  
         foreach my $user (sort(keys(%{$dompersonnel{$server}}))) {  
             my ($trole,$uname,$udom,$runame,$rudom,$rsec) = split(/:/,$user);  
             $domcoords{$uname.':'.$udom} = $dompersonnel{$server}{$user};  
         }  
     }  
     return %domcoords;  
 }  
   
 sub active_dc_picker {  sub active_dc_picker {
     my ($dom,$numinrow,$inputtype,$name,%currhash) = @_;      my ($dom,$numinrow,$inputtype,$name,%currhash) = @_;
     my %domcoords = &get_active_dcs($dom);      my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']);
     my @domcoord = keys(%domcoords);      my @domcoord = keys(%domcoords);
     if (keys(%currhash)) {      if (keys(%currhash)) {
         foreach my $dc (keys(%currhash)) {          foreach my $dc (keys(%currhash)) {
Line 11498  sub lonbalance_targets_js { Line 19202  sub lonbalance_targets_js {
     }      }
     push(@alltypes,'default','_LC_adv','_LC_author','_LC_internetdom','_LC_external');      push(@alltypes,'default','_LC_adv','_LC_author','_LC_internetdom','_LC_external');
     $allinsttypes = join("','",@alltypes);      $allinsttypes = join("','",@alltypes);
     my (%currbalancer,%currtargets,%currrules,%existing);      my (%currbalancer,%currtargets,%currrules,%existing,%currcookies);
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         %existing = %{$settings};          %existing = %{$settings};
     }      }
     &get_loadbalancers_config($servers,\%existing,\%currbalancer,      &get_loadbalancers_config($servers,\%existing,\%currbalancer,
                               \%currtargets,\%currrules);                                \%currtargets,\%currrules,\%currcookies);
     my $balancers = join("','",sort(keys(%currbalancer)));      my $balancers = join("','",sort(keys(%currbalancer)));
     return <<"END";      return <<"END";
   
Line 11914  function updateCaptcha(caller,context) { Line 19618  function updateCaptcha(caller,context) {
     var pubitem;      var pubitem;
     var privtext;      var privtext;
     var pubtext;      var pubtext;
       var versionitem;
       var versiontext;
     if (document.getElementById(context+'_recaptchapub')) {      if (document.getElementById(context+'_recaptchapub')) {
         pubitem = document.getElementById(context+'_recaptchapub');          pubitem = document.getElementById(context+'_recaptchapub');
     } else {      } else {
Line 11934  function updateCaptcha(caller,context) { Line 19640  function updateCaptcha(caller,context) {
     } else {      } else {
         return;          return;
     }      }
       if (document.getElementById(context+'_recaptchaversion')) {
           versionitem = document.getElementById(context+'_recaptchaversion');
       } else {
           return;
       }
       if (document.getElementById(context+'_recaptchavertxt')) {
           versiontext = document.getElementById(context+'_recaptchavertxt');
       } else {
           return;
       }
     if (caller.checked) {      if (caller.checked) {
         if (caller.value == 'recaptcha') {          if (caller.value == 'recaptcha') {
             pubitem.type = 'text';              pubitem.type = 'text';
Line 11942  function updateCaptcha(caller,context) { Line 19658  function updateCaptcha(caller,context) {
             privitem.size = '40';              privitem.size = '40';
             pubtext.innerHTML = "$lt{'pub'}";              pubtext.innerHTML = "$lt{'pub'}";
             privtext.innerHTML = "$lt{'priv'}";              privtext.innerHTML = "$lt{'priv'}";
               versionitem.type = 'text';
               versionitem.size = '3';
               versiontext.innerHTML = "$lt{'ver'}";
         } else {          } else {
             pubitem.type = 'hidden';              pubitem.type = 'hidden';
             privitem.type = 'hidden';              privitem.type = 'hidden';
               versionitem.type = 'hidden';
             pubtext.innerHTML = '';              pubtext.innerHTML = '';
             privtext.innerHTML = '';              privtext.innerHTML = '';
               versiontext.innerHTML = '';
         }          }
     }      }
     return;      return;
Line 11969  function toggleDisplay(domForm,caller) { Line 19690  function toggleDisplay(domForm,caller) {
     if (document.getElementById(caller)) {      if (document.getElementById(caller)) {
         var divitem = document.getElementById(caller);          var divitem = document.getElementById(caller);
         var optionsElement = domForm.coursecredits;          var optionsElement = domForm.coursecredits;
           var checkval = 1;
           var dispval = 'block';
           var selfcreateRegExp = /^cancreate_emailverified/;
         if (caller == 'emailoptions') {          if (caller == 'emailoptions') {
             optionsElement = domForm.cancreate_email;               optionsElement = domForm.cancreate_email; 
         }          }
         if (caller == 'studentsubmission') {          if (caller == 'studentsubmission') {
             optionsElement = domForm.postsubmit;              optionsElement = domForm.postsubmit;
         }          }
           if (caller == 'cloneinstcode') {
               optionsElement = domForm.canclone;
               checkval = 'instcode';
           }
           if (selfcreateRegExp.test(caller)) {
               optionsElement = domForm.elements[caller];
               checkval = 'other';
               dispval = 'inline'
           }
         if (optionsElement.length) {          if (optionsElement.length) {
             var currval;              var currval;
             for (var i=0; i<optionsElement.length; i++) {              for (var i=0; i<optionsElement.length; i++) {
Line 11982  function toggleDisplay(domForm,caller) { Line 19715  function toggleDisplay(domForm,caller) {
                    currval = optionsElement[i].value;                     currval = optionsElement[i].value;
                 }                  }
             }              }
             if (currval == 1) {              if (currval == checkval) {
                 divitem.style.display = 'block';                  divitem.style.display = dispval;
             } else {              } else {
                 divitem.style.display = 'none';                  divitem.style.display = 'none';
             }              }
Line 12006  sub captcha_phrases { Line 19739  sub captcha_phrases {
                  original  => 'original (CAPTCHA)',                   original  => 'original (CAPTCHA)',
                  recaptcha => 'successor (ReCAPTCHA)',                   recaptcha => 'successor (ReCAPTCHA)',
                  notused   => 'unused',                   notused   => 'unused',
                    ver => 'ReCAPTCHA version (1 or 2)',
     );      );
 }  }
   
Line 12015  sub devalidate_remote_domconfs { Line 19749  sub devalidate_remote_domconfs {
     my %servers = &Apache::lonnet::internet_dom_servers($dom);      my %servers = &Apache::lonnet::internet_dom_servers($dom);
     my %thismachine;      my %thismachine;
     map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();      map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();
     my @posscached = ('domainconfig','domdefaults');      my @posscached = ('domainconfig','domdefaults','ltitools','usersessions',
     if (keys(%servers) > 1) {                        'directorysrch','passwdconf','cats');
       if (keys(%servers)) {
         foreach my $server (keys(%servers)) {          foreach my $server (keys(%servers)) {
             next if ($thismachine{$server});              next if ($thismachine{$server});
             my @cached;              my @cached;

Removed from v.1.258  
changed lines
  Added in v.1.367


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