File:  [LON-CAPA] / loncom / interface / lonuserutils.pm
Revision 1.171: download - view: text, annotated - select for diffs
Wed Aug 5 18:47:21 2015 UTC (8 years, 8 months ago) by raeburn
Branches: MAIN
CVS tags: HEAD
- Bug 5596.
  Add a routine to lonnet.pm -- get_multiple_instusers() which makes one call
  to lond > lonsql > localenroll.pm to retrieve institutional data
  for multiple users when adding users via file upload, to minimize number
  of sleep() commands needed. Supports up to 1s per query, on localenroll.pm
  side if adding more than 100 new users.

- Add new routine to localenroll.pm -- &get_multusersinfo() -- to retrieve
    institutional data for users being added via user file upload.

  Note: if this routine does not exist in localenroll.pm, will fall-back
  to retrieving institutional data using a separate call to &get_userinfo()
  for each user.

# The LearningOnline Network with CAPA
# Utility functions for managing LON-CAPA user accounts
#
# $Id: lonuserutils.pm,v 1.171 2015/08/05 18:47:21 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
#
###############################################################
###############################################################

package Apache::lonuserutils;

use strict;
use Apache::lonnet;
use Apache::loncommon();
use Apache::lonhtmlcommon;
use Apache::lonlocal;
use Apache::longroup;
use LONCAPA qw(:DEFAULT :match);

###############################################################
###############################################################
# Drop student from all sections of a course, except optional $csec
sub modifystudent {
    my ($udom,$unam,$courseid,$csec,$desiredhost,$context)=@_;
    # if $csec is undefined, drop the student from all the courses matching
    # this one.  If $csec is defined, drop them from all other sections of
    # this course and add them to section $csec
    my ($cnum,$cdom) = &get_course_identity($courseid);
    my %roles = &Apache::lonnet::dump('roles',$udom,$unam);
    my ($tmp) = keys(%roles);
    # Bail out if we were unable to get the students roles
    return "$1" if ($tmp =~ /^(con_lost|error|no_such_host)/i);
    # Go through the roles looking for enrollment in this course
    my $result = '';
    foreach my $course (keys(%roles)) {
        if ($course=~m{^/\Q$cdom\E/\Q$cnum\E(?:\/)*(?:\s+)*(\w+)*\_st$}) {
            # We are in this course
            my $section=$1;
            $section='' if ($course eq "/$cdom/$cnum".'_st');
            if (defined($csec) && $section eq $csec) {
                $result .= 'ok:';
            } elsif ( ((!$section) && (!$csec)) || ($section ne $csec) ) {
                my (undef,$end,$start)=split(/\_/,$roles{$course});
                my $now=time;
                # if this is an active role
                if (!($start && ($now<$start)) || !($end && ($now>$end))) {
                    my $reply=&Apache::lonnet::modifystudent
                        # dom  name  id mode pass     f     m     l     g
                        ($udom,$unam,'',  '',  '',undef,undef,undef,undef,
                         $section,time,undef,undef,$desiredhost,'','manual',
                         '',$courseid,'',$context);
                    $result .= $reply.':';
                }
            }
        }
    }
    if ($result eq '') {
        $result = &mt('Unable to find section for this student');
    } else {
        $result =~ s/(ok:)+/ok/g;
    }
    return $result;
}

sub modifyuserrole {
    my ($context,$setting,$changeauth,$cid,$udom,$uname,$uid,$umode,$upass,
        $first,$middle,$last,$gene,$sec,$forceid,$desiredhome,$email,$role,
        $end,$start,$checkid,$inststatus) = @_;
    my ($scope,$userresult,$authresult,$roleresult,$idresult);
    if ($setting eq 'course' || $context eq 'course') {
        $scope = '/'.$cid;
        $scope =~ s/\_/\//g;
        if (($role ne 'cc') && ($role ne 'co') && ($sec ne '')) {
            $scope .='/'.$sec;
        }
    } elsif ($context eq 'domain') {
        $scope = '/'.$env{'request.role.domain'}.'/';
    } elsif ($context eq 'author') {
        $scope =  '/'.$env{'user.domain'}.'/'.$env{'user.name'};
    }
    if ($context eq 'domain') {
        my $uhome = &Apache::lonnet::homeserver($uname,$udom);
        if ($uhome ne 'no_host') {
            if (($changeauth eq 'Yes') && (&Apache::lonnet::allowed('mau',$udom))) {
                if ((($umode =~ /^krb4|krb5|internal$/) && $upass ne '') ||
                    ($umode eq 'localauth')) {
                    $authresult = &Apache::lonnet::modifyuserauth($udom,$uname,$umode,$upass);
                }
            }
            if (($forceid) && (&Apache::lonnet::allowed('mau',$udom)) &&
                ($env{'form.recurseid'}) && ($checkid)) {
                my %userupdate = (
                                  lastname   => $last,
                                  middlename => $middle,
                                  firstname  => $first,
                                  generation => $gene,
                                  id         => $uid,
                                 );
                $idresult = &propagate_id_change($uname,$udom,\%userupdate);
            }
        }
    }
    $userresult =
        &Apache::lonnet::modifyuser($udom,$uname,$uid,$umode,$upass,$first,
                                    $middle,$last,$gene,$forceid,$desiredhome,
                                    $email,$inststatus);
    if ($userresult eq 'ok') {
        if ($role ne '') {
            $role =~ s/_/\//g;
            $roleresult = &Apache::lonnet::assignrole($udom,$uname,$scope,
                                                      $role,$end,$start,'',
                                                      '',$context);
        }
    }
    return ($userresult,$authresult,$roleresult,$idresult);
}

sub propagate_id_change {
    my ($uname,$udom,$user) = @_;
    my (@types,@roles);
    @types = ('active','future');
    @roles = ('st');
    my $idresult;
    my %roleshash = &Apache::lonnet::get_my_roles($uname,
                        $udom,'userroles',\@types,\@roles);
    my %args = (
                one_time => 1,
               );
    foreach my $item (keys(%roleshash)) {
        my ($cnum,$cdom,$role) = split(/:/,$item,-1);
        my ($start,$end) = split(/:/,$roleshash{$item});
        if (&Apache::lonnet::is_course($cdom,$cnum)) {
            my $result = &update_classlist($cdom,$cnum,$udom,$uname,$user);
            my %coursehash = 
                &Apache::lonnet::coursedescription($cdom.'_'.$cnum,\%args);
            my $cdesc = $coursehash{'description'};
            if ($cdesc eq '') { 
                $cdesc = $cdom.'_'.$cnum;
            }
            if ($result eq 'ok') {
                $idresult .= &mt('Classlist update for "[_1]" in "[_2]".',$uname.':'.$udom,$cdesc).'<br />'."\n";
            } else {
                $idresult .= &mt('Error: "[_1]" during classlist update for "[_2]" in "[_3]".',$result,$uname.':'.$udom,$cdesc).'<br />'."\n";
            }
        }
    }
    return $idresult;
}

sub update_classlist {
    my ($cdom,$cnum,$udom,$uname,$user,$newend) = @_;
    my ($uid,$classlistentry);
    my $fullname =
        &Apache::lonnet::format_name($user->{'firstname'},$user->{'middlename'},
                                     $user->{'lastname'},$user->{'generation'},
                                     'lastname');
    my %classhash = &Apache::lonnet::get('classlist',[$uname.':'.$udom],
                                         $cdom,$cnum);
    my @classinfo = split(/:/,$classhash{$uname.':'.$udom});
    my $ididx=&Apache::loncoursedata::CL_ID() - 2;
    my $nameidx=&Apache::loncoursedata::CL_FULLNAME() - 2;
    my $endidx = &Apache::loncoursedata::CL_END() - 2;
    my $startidx = &Apache::loncoursedata::CL_START() - 2;
    for (my $i=0; $i<@classinfo; $i++) {
        if ($i == $endidx) {
            if ($newend ne '') {
                $classlistentry .= $newend.':';
            } else {
                $classlistentry .= $classinfo[$i].':';
            }
        } elsif ($i == $startidx) {
            if ($newend ne '') {
                if ($classinfo[$i] > $newend) {
                    $classlistentry .= $newend.':';
                } else {
                    $classlistentry .= $classinfo[$i].':';
                }
            } else {
                $classlistentry .= $classinfo[$i].':';
            }
        } elsif ($i == $ididx) {
            if (defined($user->{'id'})) {
                $classlistentry .= $user->{'id'}.':';
            } else {
                $classlistentry .= $classinfo[$i].':';
            }
        } elsif ($i == $nameidx) {
            if (defined($user->{'lastname'})) {
                $classlistentry .= $fullname.':';
            } else {
                $classlistentry .= $classinfo[$i].':';
            }
        } else {
            $classlistentry .= $classinfo[$i].':';
        }
    }
    $classlistentry =~ s/:$//;
    my $reply=&Apache::lonnet::cput('classlist',
                                    {"$uname:$udom" => $classlistentry},
                                    $cdom,$cnum);
    if (($reply eq 'ok') || ($reply eq 'delayed')) {
        return 'ok';
    } else {
        return 'error: '.$reply;
    }
}


###############################################################
###############################################################
# build a role type and role selection form
sub domain_roles_select {
    # Set up the role type and role selection boxes when in 
    # domain context   
    #
    # Role types
    my @roletypes = ('domain','author','course','community');
    my %lt = &role_type_names();
    my $onchangefirst = "updateCols('showrole')";
    my $onchangesecond = "updateCols('showrole')";
    #
    # build up the menu information to be passed to
    # &Apache::loncommon::linked_select_forms
    my %select_menus;
    if ($env{'form.roletype'} eq '') {
        $env{'form.roletype'} = 'domain';
    }
    foreach my $roletype (@roletypes) {
        # set up the text for this domain
        $select_menus{$roletype}->{'text'}= $lt{$roletype};
        my $crstype;
        if ($roletype eq 'community') {
            $crstype = 'Community';
        }
        # we want a choice of 'default' as the default in the second menu
        if ($env{'form.roletype'} ne '') {
            $select_menus{$roletype}->{'default'} = $env{'form.showrole'};
        } else { 
            $select_menus{$roletype}->{'default'} = 'Any';
        }
        # Now build up the other items in the second menu
        my @roles;
        if ($roletype eq 'domain') {
            @roles = &domain_roles();
        } elsif ($roletype eq 'author') {
            @roles = &construction_space_roles();
        } else {
            my $custom = 1;
            @roles = &course_roles('domain',undef,$custom,$roletype);
        }
        my $order = ['Any',@roles];
        $select_menus{$roletype}->{'order'} = $order; 
        foreach my $role (@roles) {
            if ($role eq 'cr') {
                $select_menus{$roletype}->{'select2'}->{$role} =
                              &mt('Custom role');
            } else {
                $select_menus{$roletype}->{'select2'}->{$role} = 
                              &Apache::lonnet::plaintext($role,$crstype);
            }
        }
        $select_menus{$roletype}->{'select2'}->{'Any'} = &mt('Any');
    }
    my $result = &Apache::loncommon::linked_select_forms
        ('studentform',('&nbsp;'x3).&mt('Role: '),$env{'form.roletype'},
         'roletype','showrole',\%select_menus,
         ['domain','author','course','community'],$onchangefirst,
         $onchangesecond);
    return $result;
}

###############################################################
###############################################################
sub hidden_input {
    my ($name,$value) = @_;
    return '<input type="hidden" name="'.$name.'" value="'.$value.'" />'."\n";
}

sub print_upload_manager_header {
    my ($r,$datatoken,$distotal,$krbdefdom,$context,$permission,$crstype,
        $can_assign)=@_;
    my $javascript;
    #
    if (! exists($env{'form.upfile_associate'})) {
        $env{'form.upfile_associate'} = 'forward';
    }
    if ($env{'form.associate'} eq 'Reverse Association') {
        if ( $env{'form.upfile_associate'} ne 'reverse' ) {
            $env{'form.upfile_associate'} = 'reverse';
        } else {
            $env{'form.upfile_associate'} = 'forward';
        }
    }
    if ($env{'form.upfile_associate'} eq 'reverse') {
        $javascript=&upload_manager_javascript_reverse_associate($can_assign);
    } else {
        $javascript=&upload_manager_javascript_forward_associate($can_assign);
    }
    #
    # Deal with restored settings
    my $password_choice = '';
    if (exists($env{'form.ipwd_choice'}) &&
        $env{'form.ipwd_choice'} ne '') {
        # If a column was specified for password, assume it is for an
        # internal password.  This is a bug waiting to be filed (could be
        # local or krb auth instead of internal) but I do not have the
        # time to mess around with this now.
        $password_choice = 'int';
    }
    #
    my $groupslist;
    if ($context eq 'course') {
        $groupslist = &get_groupslist();
    }
    my $javascript_validations =
        &javascript_validations('upload',$krbdefdom,$password_choice,undef,
                                $env{'request.role.domain'},$context,
                                $groupslist,$crstype);
    my $checked=(($env{'form.noFirstLine'})?' checked="checked"':'');
    $r->print(
        '<h3>'.&mt('Identify fields in uploaded list')."</h3>\n".
        '<p class="LC_info">'.
        &mt('Total number of records found in file: [_1]'
           ,'<b>'.$distotal.'</b>').
        "</p>\n"
    );
    if ($distotal == 0) {
        $r->print('<p class="LC_warning">'.&mt('None found').'</p>');
    }
    $r->print(
        '<p>'.
        &mt('Enter as many fields as you can.').'<br />'.
        &mt('The system will inform you and bring you back to this page,[_1]if the data selected are insufficient to add users.','<br />').
        "</p>\n"
    );
    $r->print(&hidden_input('action','upload').
              &hidden_input('state','got_file').
              &hidden_input('associate','').
              &hidden_input('datatoken',$datatoken).
              &hidden_input('fileupload',$env{'form.fileupload'}).
              &hidden_input('upfiletype',$env{'form.upfiletype'}).
              &hidden_input('upfile_associate',$env{'form.upfile_associate'}));
    $r->print(
        '<div class="LC_left_float">'.
        '<fieldset><legend>'.&mt('Functions').'</legend>'.
        '<label><input type="checkbox" name="noFirstLine"'.$checked.' />'.
              &mt('Ignore First Line').'</label>'.
        ' <input type="button" value="'.&mt('Reverse Association').'" '.
              'name="Reverse Association" '.
              'onclick="javascript:this.form.associate.value=\'Reverse Association\';submit(this.form);" />'.
        '</fieldset></div><br clear="all" />'
    );
    $r->print(
        '<script type="text/javascript" language="Javascript">'."\n".
        '// <![CDATA['."\n".
        $javascript."\n".$javascript_validations."\n".
        '// ]]>'."\n".
        '</script>'
    );
}

###############################################################
###############################################################
sub javascript_validations {
    my ($mode,$krbdefdom,$curr_authtype,$curr_authfield,$domain,
        $context,$groupslist,$crstype)=@_;
    my %param = (
                  kerb_def_dom => $krbdefdom,
                  curr_authtype => $curr_authtype,
                );
    if ($mode eq 'upload') {
        $param{'formname'} = 'studentform';
    } elsif ($mode eq 'createcourse') {
        $param{'formname'} = 'ccrs';
    } elsif ($mode eq 'modifycourse') {
        $param{'formname'} = 'cmod';
        $param{'mode'} = 'modifycourse',
        $param{'curr_autharg'} = $curr_authfield;
    }

    my $showcredits;
    my %domdefaults = &Apache::lonnet::get_domain_defaults($domain);
    if ($domdefaults{'officialcredits'} || $domdefaults{'unofficialcredits'} || $domdefaults{'textbookcredits'}) {
        $showcredits = 1;
    }

    my ($setsection_call,$setsections_js);
    my $finish = "  vf.submit();\n";
    if ($mode eq 'upload') {
        if (($context eq 'course') || ($context eq 'domain')) {
            if ($context eq 'course') {
                if ($env{'request.course.sec'} eq '') {
                    $setsection_call = 'setSections(document.'.$param{'formname'}.",'$crstype'".');';
                    $setsections_js =
                        &setsections_javascript($param{'formname'},$groupslist,
                                                $mode,'',$crstype,$showcredits);
                } else {
                    $setsection_call = "'ok'";
                }
            } elsif ($context eq 'domain') {
                $setsection_call = 'setCourse()';
                $setsections_js = &dc_setcourse_js($param{'formname'},$mode,
                                                   $context,$showcredits);
            }
            $finish = "  var checkSec = $setsection_call\n".
                      "  if (checkSec == 'ok') {\n".
                      "      vf.submit();\n".
                      "   }\n";
        }
    }
    my $authheader = &Apache::loncommon::authform_header(%param);

    my %alert = &Apache::lonlocal::texthash
        (username => 'You need to specify the username field.',
         authen   => 'You must choose an authentication type.',
         krb      => 'You need to specify the Kerberos domain.',
         ipass    => 'You need to specify the initial password.',
         name     => 'The optional name field was not specified.',
         snum     => 'The optional student/employee ID field was not specified.',
         section  => 'The optional section field was not specified.',
         email    => 'The optional e-mail address field was not specified.',
         role     => 'The optional role field was not specified.',
         domain   => 'The optional domain field was not specified.',
         continue => 'Continue adding users?',
         );
    if ($showcredits) {
        $alert{'credits'} = &mt('The optional credits field was not specified');
    }
    if (($mode eq 'upload') && ($context eq 'domain')) {
        $alert{'inststatus'} = &mt('The optional affiliation field was not specified'); 
    }
    &js_escape(\%alert);
    my $function_name = <<"END";
$setsections_js

function verify_message (vf,founduname,foundpwd,foundname,foundid,foundsec,foundemail,foundrole,founddomain,foundinststatus,foundcredits) {
END
    my ($authnum,%can_assign) =  &Apache::loncommon::get_assignable_auth($domain);
    my $auth_checks;
    if ($mode eq 'createcourse') {
        $auth_checks .= (<<END);
    if (vf.autoadds[0].checked == true) {
        if (current.radiovalue == null || current.radiovalue == 'nochange') {
            alert('$alert{'authen'}');
            return;
        }
    }
END
    } else {
        $auth_checks .= (<<END);
    var foundatype=0;
    if (founduname==0) {
        alert('$alert{'username'}');
        return;
    }

END
        if ($authnum > 1) {
            $auth_checks .= (<<END);
    if (current.radiovalue == null || current.radiovalue == '' || current.radiovalue == 'nochange') {
        // They did not check any of the login radiobuttons.
        alert('$alert{'authen'}');
        return;
    }
END
        }
    }
    if ($mode eq 'createcourse') {
        $auth_checks .= "
    if ( (vf.autoadds[0].checked == true) &&
         (vf.elements[current.argfield].value == null || vf.elements[current.argfield].value == '') ) {
";
    } elsif ($mode eq 'modifycourse') {
        $auth_checks .= "
    if (vf.elements[current.argfield].value == null || vf.elements[current.argfield].value == '') {
";
    }
    if ( ($mode eq 'createcourse') || ($mode eq 'modifycourse') ) {
        $auth_checks .= (<<END);
        var alertmsg = '';
        switch (current.radiovalue) {
            case 'krb':
                alertmsg = '$alert{'krb'}';
                break;
            default:
                alertmsg = '';
        }
        if (alertmsg != '') {
            alert(alertmsg);
            return;
        }
    }
/* regexp here to check for non \d \. in credits */
END
    } else {
        $auth_checks .= (<<END);
    foundatype=1;
    if (current.argfield == null || current.argfield == '') {
        var alertmsg = '';
        switch (current.radiovalue) {
            case 'krb':
                alertmsg = '$alert{'krb'}';
                break;
            case 'loc':
            case 'fsys':
                alertmsg = '$alert{'ipass'}';
                break;
            case 'fsys':
                alertmsg = '';
                break;
            default:
                alertmsg = '';
        }
        if (alertmsg != '') {
            alert(alertmsg);
            return;
        }
    }
END
    }
    my $section_checks;
    my $optional_checks = '';
    if ( ($mode eq 'createcourse') || ($mode eq 'modifycourse') ) {
        $optional_checks = (<<END);
    vf.submit();
}
END
    } else {
        $section_checks = &section_check_js();
        $optional_checks = (<<END);
    var message='';
    if (foundname==0) {
        message='$alert{'name'}';
    }
    if (foundid==0) {
        if (message!='') {
            message+='\\n';
        }
        message+='$alert{'snum'}';
    }
    if (foundsec==0) {
        if (message!='') {
            message+='\\n';
        }
        message+='$alert{'section'}';
    }
    if (foundemail==0) {
        if (message!='') {
            message+='\\n';
        }
        message+='$alert{'email'}';
    }
    if (foundrole==0) {
        if (message!='') {
            message+='\\n';
        }
        message+='$alert{'role'}';
    }
    if (founddomain==0) {
        if (message!='') {
            message+='\\n';
        }
        message+='$alert{'domain'}';
    }
END
        if ($showcredits) {
            $optional_checks .= <<END;
    if (foundcredits==0) {
        if (message!='') {
            message+='\\n';
        }
        message+='$alert{'credits'}';
    }
END
        }
        if (($mode eq 'upload') && ($context eq 'domain')) {
            $optional_checks .= (<<END);

    if (foundinststatus==0) {
        if (message!='') {
            message+='\\n';
        }
        message+='$alert{'inststatus'}';
    }
END
        }
        $optional_checks .= (<<END);

    if (message!='') {
        message+= '\\n$alert{'continue'}';
        if (confirm(message)) {
            vf.state.value='enrolling';
            $finish
        }
    } else {
        vf.state.value='enrolling';
        $finish
    }
}
END
    }
    my $result = $function_name.$auth_checks.$optional_checks."\n".
                 $section_checks.$authheader;
    return $result;
}
###############################################################
###############################################################
sub upload_manager_javascript_forward_associate {
    my ($can_assign) = @_;
    my ($auth_update,$numbuttons,$argreset);
    if (ref($can_assign) eq 'HASH') {
        if ($can_assign->{'krb4'} || $can_assign->{'krb5'}) {
            $argreset .= "      vf.krbarg.value='';\n";
            $numbuttons ++ ;
        }
        if ($can_assign->{'int'}) {
            $argreset .= "      vf.intarg.value='';\n";
            $numbuttons ++;
        }
        if ($can_assign->{'loc'}) {
            $argreset .= "      vf.locarg.value='';\n";
            $numbuttons ++;
        }
        if (!$can_assign->{'int'}) {
            my $warning = &mt('You may not specify an initial password for each user, as this is only available when new users use LON-CAPA internal authentication.')."\n".
                          &mt('Your current role does not have rights to create users with that authentication type.');
            &js_escape(\$warning);
            $auth_update = <<"END";
   // Currently the initial password field is only supported for internal auth
   // (see bug 6368).
   if (nw==9) {
       eval('vf.f'+tf+'.selectedIndex=0;')
       alert('$warning');
   }
END
        } elsif ($numbuttons > 1) {
            $auth_update = <<"END";
   // If we set the password, make the password form below correspond to
   // the new value.
   if (nw==9) {
      changed_radio('int',document.studentform);
      set_auth_radio_buttons('int',document.studentform);
$argreset
   }

END
        }
    }

    return(<<ENDPICK);
function verify(vf,sec_caller) {
    var founduname=0;
    var foundpwd=0;
    var foundname=0;
    var foundid=0;
    var foundsec=0;
    var foundemail=0;
    var foundrole=0;
    var founddomain=0;
    var foundinststatus=0;
    var foundcredits=0;
    var tw;
    for (i=0;i<=vf.nfields.value;i++) {
        tw=eval('vf.f'+i+'.selectedIndex');
        if (tw==1) { founduname=1; }
        if ((tw>=2) && (tw<=6)) { foundname=1; }
        if (tw==7) { foundid=1; }
        if (tw==8) { foundsec=1; }
        if (tw==9) { foundpwd=1; }
        if (tw==10) { foundemail=1; }
        if (tw==11) { foundrole=1; }
        if (tw==12) { founddomain=1; }
        if (tw==13) { foundinststatus=1; }
        if (tw==14) { foundcredits=1; }
    }
    verify_message(vf,founduname,foundpwd,foundname,foundid,foundsec,foundemail,foundrole,founddomain,foundinststatus,foundcredits);
}

//
// vf = this.form
// tf = column number
//
// values of nw
//
// 0 = none
// 1 = username
// 2 = names (lastname, firstnames)
// 3 = fname (firstname)
// 4 = mname (middlename)
// 5 = lname (lastname)
// 6 = gen   (generation)
// 7 = id
// 8 = section
// 9 = ipwd  (password)
// 10 = email address
// 11 = role
// 12 = domain
// 13 = inststatus
// 14 = foundcredits 

function flip(vf,tf) {
   var nw=eval('vf.f'+tf+'.selectedIndex');
   var i;
   // make sure no other columns are labeled the same as this one
   for (i=0;i<=vf.nfields.value;i++) {
      if ((i!=tf) && (eval('vf.f'+i+'.selectedIndex')==nw)) {
          eval('vf.f'+i+'.selectedIndex=0;')
      }
   }
   // If we set this to 'lastname, firstnames', clear out all the ones
   // set to 'fname','mname','lname','gen' (3,4,5,6) currently.
   if (nw==2) {
      for (i=0;i<=vf.nfields.value;i++) {
         if ((eval('vf.f'+i+'.selectedIndex')>=3) &&
             (eval('vf.f'+i+'.selectedIndex')<=6)) {
             eval('vf.f'+i+'.selectedIndex=0;')
         }
      }
   }
   // If we set this to one of 'fname','mname','lname','gen' (3,4,5,6),
   // clear out any that are set to 'lastname, firstnames' (2)
   if ((nw>=3) && (nw<=6)) {
      for (i=0;i<=vf.nfields.value;i++) {
         if (eval('vf.f'+i+'.selectedIndex')==2) {
             eval('vf.f'+i+'.selectedIndex=0;')
         }
      }
   }
   $auth_update
}

function clearpwd(vf) {
    var i;
    for (i=0;i<=vf.nfields.value;i++) {
        if (eval('vf.f'+i+'.selectedIndex')==9) {
            eval('vf.f'+i+'.selectedIndex=0;')
        }
    }
}

ENDPICK
}

###############################################################
###############################################################
sub upload_manager_javascript_reverse_associate {
    my ($can_assign) = @_;
    my ($auth_update,$numbuttons,$argreset);
    if (ref($can_assign) eq 'HASH') {
        if ($can_assign->{'krb4'} || $can_assign->{'krb5'}) {
            $argreset .= "      vf.krbarg.value='';\n";
            $numbuttons ++ ;
        }
        if ($can_assign->{'int'}) {
            $argreset .= "      vf.intarg.value='';\n";
            $numbuttons ++;
        }
        if ($can_assign->{'loc'}) {
            $argreset .= "      vf.locarg.value='';\n";
            $numbuttons ++;
        }
        if (!$can_assign->{'int'}) {
            my $warning = &mt('You may not specify an initial password, as this is only available when new users use LON-CAPA internal authentication.\n').
                          &mt('Your current role does not have rights to create users with that authentication type.');
            &js_escape(\$warning);
            $auth_update = <<"END";
   // Currently the initial password field is only supported for internal auth
   // (see bug 6368).
   if (tf==8 && nw!=0) {
       eval('vf.f'+tf+'.selectedIndex=0;')
       alert('$warning');
   }
END
        } elsif ($numbuttons > 1) {
            $auth_update = <<"END";
   // initial password specified, pick internal authentication
   if (tf==8 && nw!=0) {
      changed_radio('int',document.studentform);
      set_auth_radio_buttons('int',document.studentform);
$argreset
   }

END
        }
    }

    return(<<ENDPICK);
function verify(vf,sec_caller) {
    var founduname=0;
    var foundpwd=0;
    var foundname=0;
    var foundid=0;
    var foundsec=0;
    var foundemail=0;
    var foundrole=0;
    var founddomain=0;
    var foundinststatus=0;
    var foundcredits=0;
    var tw;
    for (i=0;i<=vf.nfields.value;i++) {
        tw=eval('vf.f'+i+'.selectedIndex');
        if (i==0 && tw!=0) { founduname=1; }
        if (((i>=1) && (i<=5)) && tw!=0 ) { foundname=1; }
        if (i==6 && tw!=0) { foundid=1; }
        if (i==7 && tw!=0) { foundsec=1; }
        if (i==8 && tw!=0) { foundpwd=1; }
        if (i==9 && tw!=0) { foundemail=1; }
        if (i==10 && tw!=0) { foundrole=1; }
        if (i==11 && tw!=0) { founddomain=1; }
        if (i==12 && tw!=0) { foundinstatus=1; }
        if (i==13 && tw!=0) { foundcredits=1; }
    }
    verify_message(vf,founduname,foundpwd,foundname,foundid,foundsec,foundemail,foundrole,founddomain,foundinststatus,foundcredits);
}

function flip(vf,tf) {
   var nw=eval('vf.f'+tf+'.selectedIndex');
   var i;
   // picked the all one name field, reset the other name ones to blank
   if (tf==1 && nw!=0) {
      for (i=2;i<=5;i++) {
         eval('vf.f'+i+'.selectedIndex=0;')
      }
   }
   //picked one of the piecewise name fields, reset the all in
   //one field to blank
   if ((tf>=2) && (tf<=5) && (nw!=0)) {
      eval('vf.f1.selectedIndex=0;')
   }
   $auth_update
}

function clearpwd(vf) {
    var i;
    if (eval('vf.f8.selectedIndex')!=0) {
        eval('vf.f8.selectedIndex=0;')
    }
}
ENDPICK
}

###############################################################
###############################################################
sub print_upload_manager_footer {
    my ($r,$i,$keyfields,$defdom,$today,$halfyear,$context,$permission,$crstype,
        $showcredits) = @_;
    my $form = 'document.studentform';
    my $formname = 'studentform';
    my ($krbdef,$krbdefdom) =
        &Apache::loncommon::get_kerberos_defaults($defdom);
    my %param = ( formname => $form,
                  kerb_def_dom => $krbdefdom,
                  kerb_def_auth => $krbdef
                  );
    if (exists($env{'form.ipwd_choice'}) &&
        defined($env{'form.ipwd_choice'}) &&
        $env{'form.ipwd_choice'} ne '') {
        $param{'curr_authtype'} = 'int';
    }
    my $krbform = &Apache::loncommon::authform_kerberos(%param);
    my $intform = &Apache::loncommon::authform_internal(%param);
    my $locform = &Apache::loncommon::authform_local(%param);
    my $date_table = &date_setting_table(undef,undef,$context,undef,
                                         $formname,$permission,$crstype);

    my $Str = "\n".'<div class="LC_left_float">';
    $Str .= &hidden_input('nfields',$i);
    $Str .= &hidden_input('keyfields',$keyfields);

    $Str .= '<h3>'.&mt('Options').'</h3>'
           .&Apache::lonhtmlcommon::start_pick_box();

    $Str .= &Apache::lonhtmlcommon::row_title(&mt('Login Type'));
    if ($context eq 'domain') {
        $Str .= '<p>'
               .&mt('Change authentication for existing users in domain "[_1]" to these settings?'
                   ,$defdom)
               .'&nbsp;<span class="LC_nobreak"><label>'
               .'<input type="radio" name="changeauth" value="No" checked="checked" />'
               .&mt('No').'</label>'
               .'&nbsp;&nbsp;<label>'
               .'<input type="radio" name="changeauth" value="Yes" />'
               .&mt('Yes').'</label>'
               .'</span></p>'; 
    } else {
        $Str .= '<p class="LC_info">'."\n".
            &mt('This will not take effect if the user already exists.').
            &Apache::loncommon::help_open_topic('Auth_Options').
            "</p>\n";
    }
    $Str .= &set_login($defdom,$krbform,$intform,$locform);

    my ($home_server_pick,$numlib) =
        &Apache::loncommon::home_server_form_item($defdom,'lcserver',
                                                  'default','hide');
    if ($numlib > 1) {
        $Str .= &Apache::lonhtmlcommon::row_closure()
               .&Apache::lonhtmlcommon::row_title(
                    &mt('LON-CAPA Home Server for New Users'))
               .&mt('LON-CAPA domain: [_1] with home server:','"'.$defdom.'"')
               .$home_server_pick
               .&Apache::lonhtmlcommon::row_closure();
    } else {
        $Str .= $home_server_pick.
                &Apache::lonhtmlcommon::row_closure();
    }

    $Str .= &Apache::lonhtmlcommon::row_title(&mt('Default domain'))
           .&Apache::loncommon::select_dom_form($defdom,'defaultdomain',undef,1)
           .&Apache::lonhtmlcommon::row_closure();

    $Str .= &Apache::lonhtmlcommon::row_title(&mt('Starting and Ending Dates'))
           ."<p>\n".$date_table."</p>\n"
           .&Apache::lonhtmlcommon::row_closure();

    if ($context eq 'domain') {
        $Str .= &Apache::lonhtmlcommon::row_title(
                    &mt('Settings for assigning roles'))
               .&mt('Pick the action to take on roles for these users:').'<br />'
               .'<span class="LC_nobreak"><label>'
               .'<input type="radio" name="roleaction" value="norole" checked="checked" />'
               .'&nbsp;'.&mt('No role changes').'</label>'
               .'&nbsp;&nbsp;&nbsp;<label>'
               .'<input type="radio" name="roleaction" value="domain" />'
               .'&nbsp;'.&mt('Add a domain role').'</label>'
               .'&nbsp;&nbsp;&nbsp;<label>'
               .'<input type="radio" name="roleaction" value="course" />'
               .'&nbsp;'.&mt('Add a course/community role').'</label>'
               .'</span>';
    } elsif ($context eq 'author') {
        $Str .= &Apache::lonhtmlcommon::row_title(
                    &mt('Default role'))
               .&mt('Choose the role to assign to users without a value specified in the uploaded file.')
    } elsif ($context eq 'course') {
        if ($showcredits) {
            $Str .= &Apache::lonhtmlcommon::row_title(
                    &mt('Default role, section and credits'))
                   .&mt('Choose the role and/or section(s) and/or credits to assign to users without values specified in the uploaded file.');
        } else { 
            $Str .= &Apache::lonhtmlcommon::row_title(
                    &mt('Default role and section'))
                   .&mt('Choose the role and/or section(s) to assign to users without values specified in the uploaded file.');
        }
    } else {
        $Str .= &Apache::lonhtmlcommon::row_title(
                    &mt('Default role and/or section(s)'))
               .&mt('Role and/or section(s) for users without values specified in the uploaded file.');
    }
    if (($context eq 'domain') || ($context eq 'author')) {
        $Str .= '<br />';
        my ($options,$cb_script,$coursepick) = 
            &default_role_selector($context,1,'',$showcredits);
        if ($context eq 'domain') {
            $Str .= '<p>'
                   .'<b>'.&mt('Domain Level').'</b><br />'
                   .$options
                   .'</p><p>'
                   .'<b>'.&mt('Course Level').'</b>'
                   .'</p>'
                   .$cb_script.$coursepick
                   .&Apache::lonhtmlcommon::row_closure();
        } elsif ($context eq 'author') {
            $Str .= $options
                   .&Apache::lonhtmlcommon::row_closure(1); # last row in pick_box
        }
    } else {
        my ($cnum,$cdom) = &get_course_identity();
        my $rowtitle = &mt('section');
        my $defaultcredits;
        if ($showcredits) {
            $defaultcredits = &get_defaultcredits();
        }
        my $secbox = &section_picker($cdom,$cnum,'Any',$rowtitle,$permission,
                                     $context,'upload',$crstype,$showcredits,
                                     $defaultcredits);
        $Str .= $secbox
               .&Apache::lonhtmlcommon::row_closure();
        my %lt;
        if ($crstype eq 'Community') {
            %lt = &Apache::lonlocal::texthash (
                    disp => 'Display members with current/future access who are not in the uploaded file',
                    stus => 'Members selected from this list can be dropped.'
            );
        } else {
            %lt = &Apache::lonlocal::texthash (
                    disp => 'Display students with current/future access who are not in the uploaded file',
                    stus => 'Students selected from this list can be dropped.'
            );
        }
        $Str .= &Apache::lonhtmlcommon::row_title(&mt('Full Update'))
               .'<label><input type="checkbox" name="fullup" value="yes" />'
               .' '.$lt{'disp'}
               .'</label><br />'
               .$lt{'stus'}
               .&Apache::lonhtmlcommon::row_closure();
    }
    if ($context eq 'course' || $context eq 'domain') {
        $Str .= &Apache::lonhtmlcommon::row_title(&mt('Student/Employee ID'))
               .&forceid_change($context)
               .&Apache::lonhtmlcommon::row_closure(1); # last row in pick_box
    }

    $Str .= &Apache::lonhtmlcommon::end_pick_box();
    $Str .= '</div>';

    # Footer
    $Str .= '<div class="LC_clear_float_footer">'
           .'<hr />';
    if ($context eq 'course') {
        $Str .= '<p class="LC_info">'
               .&mt('Note: This operation may be time consuming when adding several users.')
               .'</p>';
    }
    $Str .= '<p><input type="button"'
           .' onclick="javascript:verify(this.form,this.form.csec)"'
           .' value="'.&mt('Update Users').'" />'
           .'</p>'."\n"
           .'</div>';
    $r->print($Str);
    return;
}

sub get_defaultcredits {
    my ($cdom,$cnum) = @_;
     
    if ($cdom eq '' || $cnum eq '') {
        return unless ($env{'request.course.id'});
        $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
        $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
    }
    return unless(($cdom =~ /^$match_domain$/) && ($cnum =~ /^$match_courseid$/)); 
    my ($defaultcredits,$domdefcredits);
    my %domdefaults = &Apache::lonnet::get_domain_defaults($cdom);
    if ($domdefaults{'officialcredits'} || $domdefaults{'unofficialcredits'} || $domdefaults{'textbookcredits'}) {
        my $instcode = $env{'course.'.$cdom.'_'.$cnum.'.internal.coursecode'};
        if ($instcode) {
            $domdefcredits = $domdefaults{'officialcredits'};
        } elsif ($env{'course.'.$cdom.'_'.$cnum.'.internal.textbook'}) {
            $domdefcredits = $domdefaults{'textbookcredits'};
        } else {
            $domdefcredits = $domdefaults{'unofficialcredits'};
        }
    } else {
        return;
    }

    if ($env{'request.course.id'} eq $cdom.'_'.$cnum) {
        $defaultcredits = $env{'course.'.$cdom.'_'.$cnum.'.internal.defaultcredits'};
    } elsif (exists($env{'course.'.$cdom.'_'.$cnum.'.internal.defaultcredits'})) {
        $defaultcredits = $env{'course.'.$cdom.'_'.$cnum.'.internal.defaultcredits'};
    } else {
        my %crsinfo =
            &Apache::lonnet::coursedescription("$cdom/$cnum",{'one_time' => 1});
        $defaultcredits = $crsinfo{'internal.defaultcredits'};
    }
    if ($defaultcredits eq '') {
        $defaultcredits = $domdefcredits;
    }
    return $defaultcredits;
}

sub forceid_change {
    my ($context) = @_;
    my $output = 
        '<label><input type="checkbox" name="forceid" value="yes" />'
       .&mt('Force change of existing ID')
       .'</label>'.&Apache::loncommon::help_open_topic('ForceIDChange')."\n";
    if ($context eq 'domain') {
        $output .= 
            '<br />'
           .'<label><input type="checkbox" name="recurseid" value="yes" />'
           .&mt("Update ID in user's course(s).").'</label>'."\n";
    }
    return $output;
}

###############################################################
###############################################################
sub print_upload_manager_form {
    my ($r,$context,$permission,$crstype,$showcredits) = @_;
    my $firstLine;
    my $datatoken;
    if (!$env{'form.datatoken'}) {
        $datatoken=&Apache::loncommon::upfile_store($r);
    } else {
        $datatoken=$env{'form.datatoken'};
        &Apache::loncommon::load_tmp_file($r);
    }
    my @records=&Apache::loncommon::upfile_record_sep();
    if($env{'form.noFirstLine'}){
        $firstLine=shift(@records);
    }
    my $total=$#records;
    my $distotal=$total+1;
    my $today=time;
    my $halfyear=$today+15552000;
    #
    # Restore memorized settings
    my $col_setting_names =  { 'username_choice' => 'scalar', # column settings
                               'names_choice' => 'scalar',
                               'fname_choice' => 'scalar',
                               'mname_choice' => 'scalar',
                               'lname_choice' => 'scalar',
                               'gen_choice' => 'scalar',
                               'id_choice' => 'scalar',
                               'sec_choice' => 'scalar',
                               'ipwd_choice' => 'scalar',
                               'email_choice' => 'scalar',
                               'role_choice' => 'scalar',
                               'domain_choice' => 'scalar',
                               'inststatus_choice' => 'scalar',
                             };
    if ($showcredits) {
        $col_setting_names->{'credits_choice'} = 'scalar';
    }
    if ($context eq 'course') {
        &Apache::loncommon::restore_course_settings('enrollment_upload',
                                                    $col_setting_names);
    } else {
        &Apache::loncommon::restore_settings($context,'user_upload',
                                             $col_setting_names);
    }
    my $defdom = $env{'request.role.domain'};
    #
    # Determine kerberos parameters as appropriate
    my ($krbdef,$krbdefdom) =
        &Apache::loncommon::get_kerberos_defaults($defdom);
    #
    my ($authnum,%can_assign) =  &Apache::loncommon::get_assignable_auth($defdom);
    &print_upload_manager_header($r,$datatoken,$distotal,$krbdefdom,$context,
                                 $permission,$crstype,\%can_assign);
    my $i;
    my $keyfields;
    if ($total>=0) {
        my @field=
            (['username',&mt('Username'),     $env{'form.username_choice'}],
             ['names',&mt('Last Name, First Names'),$env{'form.names_choice'}],
             ['fname',&mt('First Name'),      $env{'form.fname_choice'}],
             ['mname',&mt('Middle Names/Initials'),$env{'form.mname_choice'}],
             ['lname',&mt('Last Name'),       $env{'form.lname_choice'}],
             ['gen',  &mt('Generation'),      $env{'form.gen_choice'}],
             ['id',   &mt('Student/Employee ID'),$env{'form.id_choice'}],
             ['sec',  &mt('Section'),          $env{'form.sec_choice'}],
             ['ipwd', &mt('Initial Password'),$env{'form.ipwd_choice'}],
             ['email',&mt('E-mail Address'),   $env{'form.email_choice'}],
             ['role',&mt('Role'),             $env{'form.role_choice'}],
             ['domain',&mt('Domain'),         $env{'form.domain_choice'}],
             ['inststatus',&mt('Affiliation'), $env{'form.inststatus_choice'}]);
        if ($showcredits) {     
            push(@field,
                 ['credits',&mt('Student Credits'), $env{'form.credits_choice'}]);
        }
        if ($env{'form.upfile_associate'} eq 'reverse') {
            &Apache::loncommon::csv_print_samples($r,\@records);
            $i=&Apache::loncommon::csv_print_select_table($r,\@records,
                                                          \@field);
            foreach (@field) {
                $keyfields.=$_->[0].',';
            }
            chop($keyfields);
        } else {
            unshift(@field,['none','']);
            $i=&Apache::loncommon::csv_samples_select_table($r,\@records,
                                                            \@field);
            my %sone=&Apache::loncommon::record_sep($records[0]);
            $keyfields=join(',',sort(keys(%sone)));
        }
    }
    &print_upload_manager_footer($r,$i,$keyfields,$defdom,$today,$halfyear,
                                 $context,$permission,$crstype,$showcredits);
}

sub setup_date_selectors {
    my ($starttime,$endtime,$mode,$nolink,$formname) = @_;
    if ($formname eq '') {
        $formname = 'studentform';
    }
    if (! defined($starttime)) {
        $starttime = time;
        unless ($mode eq 'create_enrolldates' || $mode eq 'create_defaultdates') {
            if (exists($env{'course.'.$env{'request.course.id'}.
                            '.default_enrollment_start_date'})) {
                $starttime = $env{'course.'.$env{'request.course.id'}.
                                  '.default_enrollment_start_date'};
            }
        }
    }
    if (! defined($endtime)) {
        $endtime = time+(6*30*24*60*60); # 6 months from now, approx
        unless ($mode eq 'createcourse') {
            if (exists($env{'course.'.$env{'request.course.id'}.
                            '.default_enrollment_end_date'})) {
                $endtime = $env{'course.'.$env{'request.course.id'}.
                                '.default_enrollment_end_date'};
            }
        }
    }

    my $startdateform = 
        &Apache::lonhtmlcommon::date_setter($formname,'startdate',$starttime,
            undef,undef,undef,undef,undef,undef,undef,$nolink);

    my $enddateform = 
        &Apache::lonhtmlcommon::date_setter($formname,'enddate',$endtime,
            undef,undef,undef,undef,undef,undef,undef,$nolink);

    if ($mode eq 'create_enrolldates') {
        $startdateform = &Apache::lonhtmlcommon::date_setter('ccrs',
                                                            'startenroll',
                                                            $starttime);
        $enddateform = &Apache::lonhtmlcommon::date_setter('ccrs',
                                                          'endenroll',
                                                          $endtime);
    }
    if ($mode eq 'create_defaultdates') {
        $startdateform = &Apache::lonhtmlcommon::date_setter('ccrs',
                                                            'startaccess',
                                                            $starttime);
        $enddateform = &Apache::lonhtmlcommon::date_setter('ccrs',
                                                          'endaccess',
                                                          $endtime);
    }
    return ($startdateform,$enddateform);
}


sub get_dates_from_form {
    my ($startname,$endname) = @_;
    if ($startname eq '') {
        $startname = 'startdate';
    }
    if ($endname eq '') {
        $endname = 'enddate';
    }
    my $startdate = &Apache::lonhtmlcommon::get_date_from_form($startname);
    my $enddate   = &Apache::lonhtmlcommon::get_date_from_form($endname);
    if ($env{'form.no_end_date'}) {
        $enddate = 0;
    }
    return ($startdate,$enddate);
}

sub date_setting_table {
    my ($starttime,$endtime,$mode,$bulkaction,$formname,$permission,$crstype) = @_;
    my $nolink;
    if ($bulkaction) {
        $nolink = 1;
    }
    my ($startform,$endform) = 
        &setup_date_selectors($starttime,$endtime,$mode,$nolink,$formname);
    my $dateDefault;
    if ($mode eq 'create_enrolldates' || $mode eq 'create_defaultdates') {
        $dateDefault = '&nbsp;';
    } elsif ($mode ne 'author' && $mode ne 'domain') {
        if (($bulkaction eq 'reenable') || 
            ($bulkaction eq 'activate') || 
            ($bulkaction eq 'chgdates') ||
            ($env{'form.action'} eq 'upload')) {
            if ($env{'request.course.sec'} eq '') {
                $dateDefault = '<span class="LC_nobreak">'.
                    '<label><input type="checkbox" name="makedatesdefault" value="1" /> ';
                if ($crstype eq 'Community') {
                    $dateDefault .= &mt("make these dates the default access dates for future community enrollment");
                } else {
                    $dateDefault .= &mt("make these dates the default access dates for future course enrollment");
                }
                $dateDefault .= '</label></span>';
            }
        }
    }
    my $perpetual = '<span class="LC_nobreak"><label><input type="checkbox" name="no_end_date"';
    if (defined($endtime) && $endtime == 0) {
        $perpetual .= ' checked="checked"';
    }
    $perpetual.= ' /> '.&mt('no ending date').'</label></span>';
    if ($mode eq 'create_enrolldates') {
        $perpetual = '&nbsp;';
    }
    my $result = &Apache::lonhtmlcommon::start_pick_box()."\n";
    $result .= &Apache::lonhtmlcommon::row_title(&mt('Starting Date'),
                                                     'LC_oddrow_value')."\n".
               $startform."\n".
               &Apache::lonhtmlcommon::row_closure(1).
               &Apache::lonhtmlcommon::row_title(&mt('Ending Date'), 
                                                     'LC_oddrow_value')."\n".
               $endform.'&nbsp;'.$perpetual.
               &Apache::lonhtmlcommon::row_closure(1).
               &Apache::lonhtmlcommon::end_pick_box();
    if ($dateDefault) {
        $result .=  $dateDefault.'<br />'."\n";
    }
    return $result;
}

sub make_dates_default {
    my ($startdate,$enddate,$context,$crstype) = @_;
    my $result = '';
    if ($context eq 'course') {
        my ($cnum,$cdom) = &get_course_identity();
        my $put_result = &Apache::lonnet::put('environment',
                {'default_enrollment_start_date'=>$startdate,
                 'default_enrollment_end_date'  =>$enddate},$cdom,$cnum);
        if ($put_result eq 'ok') {
            if ($crstype eq 'Community') {
                $result .= &mt('Set default start and end access dates for community.');
            } else {
                $result .= &mt('Set default start and end access dates for course.');
            }
            $result .= '<br />'."\n";
            #
            # Refresh the course environment
            &Apache::lonnet::coursedescription($env{'request.course.id'},
                                               {'freshen_cache' => 1});
        } else {
            if ($crstype eq 'Community') {
                $result .= &mt('Unable to set default access dates for community');
            } else {
                $result .= &mt('Unable to set default access dates for course');
            }
            $result .= ':'.$put_result.'<br />';
        }
    }
    return $result;
}

sub default_role_selector {
    my ($context,$checkpriv,$crstype,$showcredits) = @_;
    my %customroles;
    my ($options,$coursepick,$cb_jscript);
    if ($context ne 'author') {
        %customroles = &my_custom_roles($crstype);
    }

    my %lt=&Apache::lonlocal::texthash(
                    'rol'  => "Role",
                    'grs'  => "Section",
                    'exs'  => "Existing sections",
                    'new'  => "New section",
                    'crd'  => "Credits",
                  );
    $options = '<select name="defaultrole">'."\n".
               ' <option value="">'.&mt('Please select').'</option>'."\n"; 
    if ($context eq 'course') {
        $options .= &default_course_roles($context,$checkpriv,$crstype,%customroles);
    } elsif ($context eq 'author') {
        my @roles = &construction_space_roles($checkpriv);
        foreach my $role (@roles) {
           my $plrole=&Apache::lonnet::plaintext($role);
           $options .= '  <option value="'.$role.'">'.$plrole.'</option>'."\n";
        }
    } elsif ($context eq 'domain') {
        my @roles = &domain_roles($checkpriv);
        foreach my $role (@roles) {
           my $plrole=&Apache::lonnet::plaintext($role);
           $options .= '  <option value="'.$role.'">'.$plrole.'</option>';
        }
        my $courseform = &Apache::loncommon::selectcourse_link
            ('studentform','dccourse','dcdomain','coursedesc',"$env{'request.role.domain'}",undef,'Course/Community');
        my ($credit_elem,$creditsinput);
        if ($showcredits) {
            $credit_elem = 'credits';
            $creditsinput = '<td><input type="text" name="credits" value="" /></td>';
        }
        $cb_jscript = 
            &Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'},'currsec','studentform','courserole','Course/Community',$credit_elem);
        $coursepick = &Apache::loncommon::start_data_table().
                      &Apache::loncommon::start_data_table_header_row().
                      '<th>'.$courseform.'</th><th>'.$lt{'rol'}.'</th>'.
                      '<th>'.$lt{'grs'}.'</th>'.
                      '<th>'.$lt{'crd'}.'</th>'.
                      &Apache::loncommon::end_data_table_header_row().
                      &Apache::loncommon::start_data_table_row()."\n".
                      '<td><input type="text" name="coursedesc" value="" onfocus="this.blur();opencrsbrowser('."'studentform','dccourse','dcdomain','coursedesc','','','','crstype'".')" /></td>'."\n".
                      '<td><select name="courserole">'."\n".
                      &default_course_roles($context,$checkpriv,'Course',%customroles)."\n".
                      '</select></td><td>'.
                      '<table class="LC_createuser">'.
                      '<tr class="LC_section_row"><td valign="top">'.
                      $lt{'exs'}.'<br /><select name="currsec">'.
                      ' <option value="">&lt;--'.&mt('Pick course first').
                      '</select></td>'.
                      '<td>&nbsp;&nbsp;</td>'.
                      '<td valign="top">'.$lt{'new'}.'<br />'.
                      '<input type="text" name="newsec" value="" size="5" />'.
                      '<input type="hidden" name="groups" value="" />'.
                      '<input type="hidden" name="sections" value="" />'.
                      '<input type="hidden" name="origdom" value="'.
                      $env{'request.role.domain'}.'" />'.
                      '<input type="hidden" name="dccourse" value="" />'.
                      '<input type="hidden" name="dcdomain" value="" />'.
                      '<input type="hidden" name="crstype" value="" />'.
                      '</td></tr></table></td>'.$creditsinput.
                      &Apache::loncommon::end_data_table_row().
                      &Apache::loncommon::end_data_table()."\n";
    }
    $options .= '</select>';
    return ($options,$cb_jscript,$coursepick);
}

sub default_course_roles {
    my ($context,$checkpriv,$crstype,%customroles) = @_;
    my $output;
    my $custom = 1;
    my @roles = &course_roles($context,$checkpriv,$custom,lc($crstype));
    foreach my $role (@roles) {
        if ($role ne 'cr') {
            my $plrole=&Apache::lonnet::plaintext($role,$crstype);
            $output .= '  <option value="'.$role.'">'.$plrole.'</option>';
        }
    }
    if (keys(%customroles) > 0) {
        if (grep(/^cr$/,@roles)) {
            foreach my $cust (sort(keys(%customroles))) {
                my $custrole='cr_'.$env{'user.domain'}.
                             '_'.$env{'user.name'}.'_'.$cust;
                $output .= '  <option value="'.$custrole.'">'.$cust.'</option>';
            }
        }
    }
    return $output;
}

sub construction_space_roles {
    my ($checkpriv) = @_;
    my @allroles = &roles_by_context('author');
    my @roles;
    if ($checkpriv) {
        foreach my $role (@allroles) {
            if (&Apache::lonnet::allowed('c'.$role,$env{'user.domain'}.'/'.$env{'user.name'})) { 
                push(@roles,$role); 
            }
        }
        return @roles;
    } else {
        return @allroles;
    }
}

sub domain_roles {
    my ($checkpriv) = @_;
    my @allroles = &roles_by_context('domain');
    my @roles;
    if ($checkpriv) {
        foreach my $role (@allroles) {
            if (&Apache::lonnet::allowed('c'.$role,$env{'request.role.domain'})) {
                push(@roles,$role);
            }
        }
        return @roles;
    } else {
        return @allroles;
    }
}

sub course_roles {
    my ($context,$checkpriv,$custom,$roletype) = @_;
    my $crstype;
    if ($roletype eq 'community') {
        $crstype = 'Community' ;
    } else {
        $crstype = 'Course';
    }
    my @allroles = &roles_by_context('course',$custom,$crstype);
    my @roles;
    if ($context eq 'domain') {
        @roles = @allroles;
    } elsif ($context eq 'course') {
        if ($env{'request.course.id'}) {
            if ($checkpriv) { 
                foreach my $role (@allroles) {
                    if (&Apache::lonnet::allowed('c'.$role,$env{'request.course.id'})) {
                        push(@roles,$role);
                    } else {
                        if ((($role ne 'cc') && ($role ne 'co')) && ($env{'request.course.sec'} ne '')) {
                            if (&Apache::lonnet::allowed('c'.$role,
                                             $env{'request.course.id'}.'/'.
                                             $env{'request.course.sec'})) {
                                push(@roles,$role);
                            }
                        }
                    }
                }
            } else {
                @roles = @allroles;
            }
        }
    }
    return @roles;
}

sub curr_role_permissions {
    my ($context,$setting,$checkpriv,$type) = @_; 
    my $custom = 1;
    my @roles;
    if ($context eq 'author') {
        @roles = &construction_space_roles($checkpriv);
    } elsif ($context eq 'domain') {
        if ($setting eq 'course') {
            @roles = &course_roles($context,$checkpriv,$custom,$type); 
        } else {
            @roles = &domain_roles($checkpriv);
        }
    } elsif ($context eq 'course') {
        @roles = &course_roles($context,$checkpriv,$custom,$type);
    }
    return @roles;
}

# ======================================================= Existing Custom Roles

sub my_custom_roles {
    my ($crstype) = @_;
    my %returnhash=();
    my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1});
    my %rolehash=&Apache::lonnet::dump('roles');
    foreach my $key (keys(%rolehash)) {
        if ($key=~/^rolesdef\_(\w+)$/) {
            if ($crstype eq 'Community') {
                next if ($rolehash{$key} =~ /bre\&S/); 
            }
            $returnhash{$1}=$1;
        }
    }
    return %returnhash;
}

sub print_userlist {
    my ($r,$mode,$permission,$context,$formname,$totcodes,$codetitles,
        $idlist,$idlist_titles,$showcredits) = @_;
    my $format = $env{'form.output'};
    if (! exists($env{'form.sortby'})) {
        $env{'form.sortby'} = 'username';
    }
    if ($env{'form.Status'} !~ /^(Any|Expired|Active|Future)$/) {
        $env{'form.Status'} = 'Active';
    }
    my $onchange = "javascript:updateCols('Status');";
    my $status_select = &Apache::lonhtmlcommon::StatusOptions
        ($env{'form.Status'},undef,undef,$onchange);

    if ($env{'form.showrole'} eq '') {
        if ($context eq 'course') {
            $env{'form.showrole'} = 'st';
        } else {
            $env{'form.showrole'} = 'Any';            
        }
    }
    if (! defined($env{'form.output'}) ||
        $env{'form.output'} !~ /^(csv|excel|html)$/ ) {
        $env{'form.output'} = 'html';
    }

    my @statuses;
    if ($env{'form.Status'} eq 'Any') {
        @statuses = ('previous','active','future');
    } elsif ($env{'form.Status'} eq 'Expired') {
        @statuses = ('previous');
    } elsif ($env{'form.Status'} eq 'Active') {
        @statuses = ('active');
    } elsif ($env{'form.Status'} eq 'Future') {
        @statuses = ('future');
    }

    # Interface output
    $r->print('<form name="studentform" method="post" action="/adm/createuser">'."\n".
              '<input type="hidden" name="action" value="'.
              $env{'form.action'}.'" />');
    $r->print('<div>'."\n");
    if ($env{'form.action'} ne 'modifystudent') {
        my %lt=&Apache::lonlocal::texthash('csv' => "CSV",
                                           'excel' => "Excel",
                                           'html'  => 'HTML');
        my $output_selector = '<select size="1" name="output" onchange="javascript:updateCols('."'output'".');" >';
        foreach my $outputformat ('html','csv','excel') {
            my $option = '<option value="'.$outputformat.'"';
            if ($outputformat eq $env{'form.output'}) {
                $option .= ' selected="selected"';
            }
            $option .='>'.$lt{$outputformat}.'</option>';
            $output_selector .= "\n".$option;
        }
        $output_selector .= '</select>';
        $r->print('<span class="LC_nobreak">'
                 .&mt('Output Format: [_1]',$output_selector)
                 .'</span>'.('&nbsp;'x3));
    }
    $r->print('<span class="LC_nobreak">'
             .&mt('User Status: [_1]',$status_select)
             .'</span>'.('&nbsp;'x3)."\n");
    my $roleselected = '';
    if ($env{'form.showrole'} eq 'Any') {
       $roleselected = ' selected="selected"'; 
    }
    my ($cnum,$cdom);
    $r->print(&role_filter($context));
    if ($context eq 'course') {
        ($cnum,$cdom) = &get_course_identity();
        $r->print(&section_group_filter($cnum,$cdom));
    }
    $r->print('</div><div class="LC_left_float">'.
              &column_checkboxes($context,$mode,$formname,$showcredits).
              '</div>');
    if ($env{'form.phase'} eq '') {
        $r->print('<br clear="all" />'.
                  &list_submit_button(&mt('Display List of Users'))."\n".
                  '<input type="hidden" name="phase" value="" /></form>');
        return;
    }
    if (!(($context eq 'domain') && 
          (($env{'form.roletype'} eq 'course') || ($env{'form.roletype'} eq 'community')))) {
        $r->print('<br clear="all" />'.
                  &list_submit_button(&mt('Update Display'))."\n");
    }

    my @cols = &infocolumns($context,$mode,$showcredits);  
    if (!@cols) {
         $r->print('<hr style="clear:both;" /><span class="LC_warning">'.
                   &mt('No user information selected for display.').'</span>'.
                   '<input type="hidden" name="phase" value="display" /></form>'."\n");
         return;
    }
    my ($indexhash,$keylist) = &make_keylist_array();
    my (%userlist,%userinfo,$clearcoursepick,$needauthorquota,$needauthorusage);
    if (($context eq 'domain') && 
        ($env{'form.roletype'} eq 'course') || 
        ($env{'form.roletype'} eq 'community')) {
        my ($crstype,$numcodes,$title,$warning);
        if ($env{'form.roletype'} eq 'course') {
            $crstype = 'Course';
            $numcodes = $totcodes;
            $title = &mt('Select Courses');
            $warning = &mt('Warning: data retrieval for multiple courses can take considerable time, as this operation is not currently optimized.');
        } elsif ($env{'form.roletype'} eq 'community') {
            $crstype = 'Community';
            $numcodes = 0;
            $title = &mt('Select Communities');
            $warning = &mt('Warning: data retrieval for multiple communities can take considerable time, as this operation is not currently optimized.');
        }
        my @standardnames = &Apache::loncommon::get_standard_codeitems();
        my $courseform =
            &Apache::lonhtmlcommon::course_selection($formname,$numcodes,
                            $codetitles,$idlist,$idlist_titles,$crstype,
                            \@standardnames);
        $r->print('<div class="LC_left_float">'.
                  '<fieldset><legend>'.$title.'</legend>'."\n".
                  $courseform."\n".
                  '</fieldset></div><br clear="all" />'.
                  '<p><input type="hidden" name="origroletype" value="'.$env{'form.roletype'}.'" />'.
                  &list_submit_button(&mt('Update Display')).
                  "\n".'</p><span class="LC_warning">'.$warning.'</span>'."\n");
        $clearcoursepick = 0;
        if (($env{'form.origroletype'} ne '') &&
            ($env{'form.origroletype'} ne $env{'form.roletype'})) {
            $clearcoursepick = 1;
        }
        if (($env{'form.coursepick'}) && (!$clearcoursepick)) {
            $r->print('<hr />'.&mt('Searching ...').'<br />&nbsp;<br />');
        }
    } else {
        $r->print('<hr style="clear:both;" /><div id="searching">'.&mt('Searching ...').'</div>');
    }
    $r->rflush();
    if ($context eq 'course') {
        if (($env{'form.showrole'} eq 'st') || ($env{'form.showrole'} eq 'Any')) { 
            my $classlist = &Apache::loncoursedata::get_classlist();
            if (ref($classlist) eq 'HASH') {
                %userlist = %{$classlist};
            }
        }
        if ($env{'form.showrole'} ne 'st') {
            my $showroles;
            if ($env{'form.showrole'} ne 'Any') {
                $showroles = [$env{'form.showrole'}];
            } else {
                $showroles = undef;
            }
            my $withsec = 1;
            my $hidepriv = 1;
            my %advrolehash = &Apache::lonnet::get_my_roles($cnum,$cdom,undef,
                              \@statuses,$showroles,undef,$withsec,$hidepriv);
            &gather_userinfo($context,$format,\%userlist,$indexhash,\%userinfo,
                             \%advrolehash,$permission);
        }
    } else {
        my (%cstr_roles,%dom_roles);
        if ($context eq 'author') {
            # List co-authors and assistant co-authors
            my @possroles = &roles_by_context($context);
            %cstr_roles = &Apache::lonnet::get_my_roles(undef,undef,undef,
                                              \@statuses,\@possroles);
            &gather_userinfo($context,$format,\%userlist,$indexhash,\%userinfo,
                             \%cstr_roles,$permission);
        } elsif ($context eq 'domain') {
            if ($env{'form.roletype'} eq 'domain') {
                if (grep(/^authorusage$/,@cols)) {
                    $needauthorusage = 1;
                }
                if (grep(/^authorquota$/,@cols)) {
                    $needauthorquota = 1;
                }
                %dom_roles = &Apache::lonnet::get_domain_roles($env{'request.role.domain'});
                foreach my $key (keys(%dom_roles)) {
                    if (ref($dom_roles{$key}) eq 'HASH') {
                        &gather_userinfo($context,$format,\%userlist,$indexhash,
                                         \%userinfo,$dom_roles{$key},$permission);
                    }
                }
            } elsif ($env{'form.roletype'} eq 'author') {
                my %dom_roles = &Apache::lonnet::get_domain_roles($env{'request.role.domain'},['au']);
                my %coauthors;
                foreach my $key (keys(%dom_roles)) {
                    if (ref($dom_roles{$key}) eq 'HASH') {
                        if ($env{'form.showrole'} eq 'au') {
                            &gather_userinfo($context,$format,\%userlist,$indexhash,
                                             \%userinfo,$dom_roles{$key},$permission);
                        } else {
                            my @possroles;
                            if ($env{'form.showrole'} eq 'Any') {
                                @possroles = &roles_by_context('author');
                            } else {
                                @possroles = ($env{'form.showrole'}); 
                            }
                            foreach my $author (sort(keys(%{$dom_roles{$key}}))) {
                                my ($role,$authorname,$authordom) = split(/:/,$author,-1);
                                my $extent = '/'.$authordom.'/'.$authorname;
                                %{$coauthors{$extent}} =
                                    &Apache::lonnet::get_my_roles($authorname,
                                       $authordom,undef,\@statuses,\@possroles);
                            }
                            &gather_userinfo($context,$format,\%userlist,
                                     $indexhash,\%userinfo,\%coauthors,$permission);
                        }
                    }
                }
            } elsif (($env{'form.roletype'} eq 'course') ||
                     ($env{'form.roletype'} eq 'community')) {
                if (($env{'form.coursepick'}) && (!$clearcoursepick)) {
                    my %courses = &process_coursepick();
                    my %allusers;
                    my $hidepriv = 1;
                    foreach my $cid (keys(%courses)) {
                        my ($cnum,$cdom,$cdesc) = &get_course_identity($cid);
                        next if ($cnum eq '' || $cdom eq '');
                        my $custom = 1;
                        my (@roles,@sections,%access,%users,%userdata,
                            %statushash);
                        if ($env{'form.showrole'} eq 'Any') {
                            @roles = &course_roles($context,undef,$custom,
                                                   $env{'form.roletype'});
                        } else {
                            @roles = ($env{'form.showrole'});
                        }
                        foreach my $role (@roles) {
                            %{$users{$role}} = ();
                        }
                        foreach my $type (@statuses) {
                            $access{$type} = $type;
                        }
                        &Apache::loncommon::get_course_users($cdom,$cnum,\%access,\@roles,\@sections,\%users,\%userdata,\%statushash,$hidepriv);
                        foreach my $user (keys(%userdata)) {
                            next if (ref($userinfo{$user}) eq 'HASH');
                            foreach my $item ('fullname','id') {
                                $userinfo{$user}{$item} = $userdata{$user}[$indexhash->{$item}];
                            }
                        }
                        foreach my $role (keys(%users)) {
                            foreach my $user (keys(%{$users{$role}})) {
                                my $uniqid = $user.':'.$role;
                                $allusers{$uniqid}{$cid} = { desc => $cdesc,
                                                             secs  => $statushash{$user}{$role},
                                                           };
                            }
                        }
                    }
                    &gather_userinfo($context,$format,\%userlist,$indexhash,
                                     \%userinfo,\%allusers,$permission);
                } else {
                    $r->print('<input type="hidden" name="phase" value="'.
                              $env{'form.phase'}.'" /></form>');
                    return;
                }
            }
        }
    }
    if (keys(%userlist) == 0) {
        my $msg = '';
        if ($context eq 'author') {
            $msg = &mt('There are no co-authors to display.');
        } elsif ($context eq 'domain') {
            if ($env{'form.roletype'} eq 'domain') {
                $msg = &mt('There are no users with domain roles to display.');
            } elsif ($env{'form.roletype'} eq 'author') {
                $msg = &mt('There are no authors or co-authors to display.');
            } elsif ($env{'form.roletype'} eq 'course') {
                $msg = &mt('There are no course users to display');
            } elsif ($env{'form.roletype'} eq 'community') {
                $msg = &mt('There are no community users to display');
            }
        } elsif ($context eq 'course') {
            $r->print(&mt('There are no course users to display.')."\n");
        }
        $r->print('<p class="LC_info">'.$msg.'</p>'."\n") if $msg;
    } else {
        # Print out the available choices
        my $usercount;
        if ($env{'form.action'} eq 'modifystudent') {
            ($usercount) = &show_users_list($r,$context,'view',$permission,
                                 $env{'form.Status'},\%userlist,$keylist,'',
                                 $showcredits);
        } else {
            ($usercount) = &show_users_list($r,$context,$env{'form.output'},
                               $permission,$env{'form.Status'},\%userlist,
                               $keylist,'',$showcredits,$needauthorquota,$needauthorusage);
        }
        if (!$usercount) {
            $r->print('<br /><span class="LC_info">'
                     .&mt('There are no users matching the search criteria.')
                     .'</span>'
            ); 
        }
    }
    $r->print('<input type="hidden" name="phase" value="'.
              $env{'form.phase'}.'" /></form>');
    return;
}

sub role_filter {
    my ($context) = @_;
    my $output;
    my $roleselected = '';
    if ($env{'form.showrole'} eq 'Any') {
       $roleselected = ' selected="selected"';
    }
    my ($role_select);
    if ($context eq 'domain') {
        $role_select = &domain_roles_select();
        $output = '<span class="LC_nobreak">'
                 .&mt('Role Type: [_1]',$role_select)
                 .'</span>';
    } else {
        $role_select = '<select name="showrole" onchange="javascript:updateCols('."'showrole'".');">'."\n".
                       '<option value="Any" '.$roleselected.'>'.
                       &mt('Any role').'</option>';
        my ($roletype,$crstype);
        if ($context eq 'course') {
            $crstype = &Apache::loncommon::course_type();
            if ($crstype eq 'Community') {
                $roletype = 'community';
            } else {
                $roletype = 'course';
            } 
        }
        my @poss_roles = &curr_role_permissions($context,'','',$roletype);
        foreach my $role (@poss_roles) {
            $roleselected = '';
            if ($role eq $env{'form.showrole'}) {
                $roleselected = ' selected="selected"';
            }
            my $plrole;
            if ($role eq 'cr') {
                $plrole = &mt('Custom role');
            } else {
                $plrole=&Apache::lonnet::plaintext($role,$crstype);
            }
            $role_select .= '<option value="'.$role.'"'.$roleselected.'>'.$plrole.'</option>';
        }
        $role_select .= '</select>';
        $output = '<span class="LC_nobreak">'
                 .&mt('Role: [_1]',$role_select)
                 .'</span>';
    }
    return $output;
}

sub section_group_filter {
    my ($cnum,$cdom) = @_;
    my @filters;
    if ($env{'request.course.sec'} eq '') {
        @filters = ('sec');
    }
    push(@filters,'grp');
    my %name = (
                 sec => 'secfilter',
                 grp => 'grpfilter',
               );
    my %title = &Apache::lonlocal::texthash (
                                              sec  => 'Section(s)',
                                              grp  => 'Group(s)',
                                              all  => 'all',
                                              none => 'none',
                                            );
    my $output;
    foreach my $item (@filters) {
        my ($markup,@options); 
        if ($env{'form.'.$name{$item}} eq '') {
            $env{'form.'.$name{$item}} = 'all';
        }
        if ($item eq 'sec') {
            if (($env{'form.showrole'} eq 'cc') || ($env{'form.showrole'} eq 'co')) {
                $env{'form.'.$name{$item}} = 'none';
            }
            my %sections_count = &Apache::loncommon::get_sections($cdom,$cnum);
            @options = sort(keys(%sections_count));
        } elsif ($item eq 'grp') {
            my %curr_groups = &Apache::longroup::coursegroups();
            @options = sort(keys(%curr_groups));
        }
        if (@options > 0) {
            my $currsel;
            $markup = '<select name="'.$name{$item}.'">'."\n";
            foreach my $option ('all','none',@options) { 
                $currsel = '';
                if ($env{'form.'.$name{$item}} eq $option) {
                    $currsel = ' selected="selected"';
                }
                $markup .= ' <option value="'.$option.'"'.$currsel.'>';
                if (($option eq 'all') || ($option eq 'none')) {
                    $markup .= $title{$option};
                } else {
                    $markup .= $option;
                }   
                $markup .= '</option>'."\n";
            }
            $markup .= '</select>'."\n";
            $output .= ('&nbsp;'x3).'<span class="LC_nobreak">'
                      .'<label>'.$title{$item}.': '.$markup.'</label>'
                      .'</span> ';
        }
    }
    return $output;
}

sub infocolumns {
    my ($context,$mode,$showcredits) = @_;
    my @cols;
    if (($mode eq 'pickauthor') || ($mode eq 'autoenroll')) {
        @cols = &get_cols_array($context,$mode,$showcredits);
    } else {
        my @posscols = &get_cols_array($context,$mode,$showcredits);
        if ($env{'form.phase'} ne '') {
            my @checkedcols = &Apache::loncommon::get_env_multiple('form.showcol');
            foreach my $col (@checkedcols) {
                if (grep(/^$col$/,@posscols)) {
                    push(@cols,$col);
                }
            }
        } else {
            @cols = @posscols;
        }
    }
    return @cols;
}

sub get_cols_array {
    my ($context,$mode,$showcredits) = @_;
    my @cols;
    if ($mode eq 'pickauthor') {
        @cols = ('username','fullname','status','email');
    } else {
        @cols = ('username','domain','id','fullname');
        if ($context eq 'course') {
            push(@cols,'section');
        }
        push(@cols,('start','end','role'));
        unless (($mode eq 'autoenroll') && ($env{'form.Status'} ne 'Any')) {
            push(@cols,'status');
        }
        if ($context eq 'course') {
            push(@cols,'groups');
        }
        push(@cols,'email');
        if (($context eq 'course') && ($mode ne 'autoenroll')) {
            if ($showcredits) {
                push(@cols,'credits');
            }
            push(@cols,'lastlogin','clicker');
        }
        if (($context eq 'course') && ($mode ne 'autoenroll') &&
            ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'})) {
            push(@cols,'photo');
        }
        if ($context eq 'domain') {
            push (@cols,('authorusage','authorquota','extent'));
        }
    }
    return @cols;
}

sub column_checkboxes {
    my ($context,$mode,$formname,$showcredits) = @_;
    my @cols = &get_cols_array($context,$mode,$showcredits);
    my @showncols = &Apache::loncommon::get_env_multiple('form.showcol');
    my (%disabledchk,%unchecked);
    if ($env{'form.phase'} eq '') {
        $disabledchk{'status'} = 1;
        if ($context eq 'course') {
            $disabledchk{'role'} = 1;
            $unchecked{'photo'} = 1;
            $unchecked{'clicker'} = 1;
            if ($showcredits) {
                $unchecked{'credits'} = 1;
            }
        } elsif ($context eq 'domain') { 
            $unchecked{'extent'} = 1; 
        }
        $unchecked{'start'} = 1;
        $unchecked{'end'} = 1;
    } else {
        if ($env{'form.Status'} ne 'Any') {
            $disabledchk{'status'} = 1;
        }
        if (($env{'form.showrole'} ne 'Any') && ($env{'form.showrole'} ne 'cr')) {
            $disabledchk{'role'} = 1;
        }
        if ($context eq 'domain') {
            if (($env{'form.roletype'} eq 'course') || 
                ($env{'form.roletype'} eq 'community')) {
                $disabledchk{'status'} = 1;
                $disabledchk{'authorusage'} = 1;
                $disabledchk{'authorquota'} = 1;
            } elsif ($env{'form.roletype'} eq 'domain') {
                $disabledchk{'extent'} = 1; 
            }
        }
    }
    my $numposs = scalar(@cols);
    my $numinrow = 7;
    my %lt = &get_column_names($context);
    my $output = '<fieldset><legend>'.&mt('Information to show').'</legend>'."\n".'<span class="LC_nobreak">'.
                 '<input type="button" onclick="javascript:checkAll(document.'.$formname.'.showcol);" value="'.&mt('check all').'" />'.
                 ('&nbsp;'x3).
                 '<input type="button" onclick="javascript:uncheckAll(document.'.$formname.'.showcol);" value="'.&mt('uncheck all').'" />'.
                 '</span><table>';
    
    for (my $i=0; $i<$numposs; $i++) {
        my $rem = $i%($numinrow);
        if ($rem == 0) {
            if ($i > 0) {
                $output .= '</tr>';
            }
            $output .= '<tr>';
        }
        my $checked;
        if ($env{'form.phase'} eq '') {
            $checked = ' checked="checked"';
            if ($unchecked{$cols[$i]}) { 
               $checked = '';
            }
            if ($disabledchk{$cols[$i]}) {
                $checked = ' disabled="disabled"';
            }
        } elsif (grep(/^\Q$cols[$i]\E$/,@showncols)) {
            $checked = ' checked="checked"';
        } elsif ($disabledchk{$cols[$i]}) {
            $checked = ' disabled="disabled"';
        }
        if ($i == $numposs-1) {
            my $colsleft = $numinrow-$rem;
            if ($colsleft > 1) {
                $output .= '<td colspan="'.$colsleft.'">';
            } else {
                $output .= '<td>';
            }
        } else {
            $output .= '<td>';
        }
        my $style;
        if ($cols[$i] eq 'extent') {
            if (($env{'form.roletype'} eq 'domain') || ($env{'form.roletype'} eq '')) {
                $style = ' style="display: none;"';
            } 
        } elsif (($cols[$i] eq 'authorusage') || ($cols[$i] eq 'authorquota')) {
            if ($env{'form.roletype'} ne 'domain') {
                $style = ' style="display: none;"';
            }
        }
        $output .= '<span id="show'.$cols[$i].'"'.$style.'><label>'.
                   '<input id="showcol'.$cols[$i].'" type="checkbox" name="showcol" value="'.$cols[$i].'"'.$checked.' /><span id="showcoltext'.$cols[$i].'">'.
                   $lt{$cols[$i]}.'</span>'.
                   '</label></span></td>';
    }
    $output .= '</tr></table></fieldset>';
    return $output;
}

sub list_submit_button {
    my ($text) = @_;
    return '<input type="button" name="updatedisplay" value="'.$text.'" onclick="javascript:display_update()" />';
}

sub get_column_names {
    my ($context) = @_;
    my %lt = &Apache::lonlocal::texthash(
        'username'   => "username",
        'domain'     => "domain",
        'id'         => 'ID',
        'fullname'   => "name",
        'section'    => "section",
        'groups'     => "active groups",
        'start'      => "start date",
        'end'        => "end date",
        'status'     => "status",
        'role'       => "role",
        'credits'    => "credits",
        'type'       => "enroll type/action",
        'email'      => "e-mail address",
        'photo'      => "photo",
        'lastlogin'  => "last login",
        'extent'     => "extent",
        'authorusage' => "disk usage (%)",
        'authorquota' => "disk quota (MB)",
        'ca'         => "check all",
        'ua'         => "uncheck all",
        'clicker'    => "clicker-ID",
    );
    if ($context eq 'domain' && $env{'form.roletype'} eq 'course') {
        $lt{'extent'} = &mt('course(s): description, section(s), status');
    } elsif ($context eq 'domain' && $env{'form.roletype'} eq 'community') {
        $lt{'extent'} = &mt('community(s): description, section(s), status');
    } elsif (($context eq 'author') || 
             ($context eq 'domain' && $env{'form.roletype'} eq 'author')) {
        $lt{'extent'} = &mt('author');
    }
    return %lt;
}

sub gather_userinfo {
    my ($context,$format,$userlist,$indexhash,$userinfo,$rolehash,$permission) = @_;
    my $viewablesec;
    if ($context eq 'course') {
        $viewablesec = &viewable_section($permission);
    }
    foreach my $item (keys(%{$rolehash})) {
        my %userdata;
        if ($context eq 'author') { 
            ($userdata{'username'},$userdata{'domain'},$userdata{'role'}) =
                split(/:/,$item);
            ($userdata{'start'},$userdata{'end'})=split(/:/,$rolehash->{$item});
            &build_user_record($context,\%userdata,$userinfo,$indexhash,
                               $item,$userlist);
        } elsif ($context eq 'course') {
            ($userdata{'username'},$userdata{'domain'},$userdata{'role'},
             $userdata{'section'}) = split(/:/,$item,-1);
            ($userdata{'start'},$userdata{'end'})=split(/:/,$rolehash->{$item});
            if (($viewablesec ne '') && ($userdata{'section'} ne '')) {
                next if ($viewablesec ne $userdata{'section'});
            }
            &build_user_record($context,\%userdata,$userinfo,$indexhash,
                               $item,$userlist);
        } elsif ($context eq 'domain') {
            if ($env{'form.roletype'} eq 'domain') {
                ($userdata{'role'},$userdata{'username'},$userdata{'domain'}) =
                    split(/:/,$item);
                ($userdata{'end'},$userdata{'start'})=split(/:/,$rolehash->{$item});
                &build_user_record($context,\%userdata,$userinfo,$indexhash,
                                   $item,$userlist);
            } elsif ($env{'form.roletype'} eq 'author') {
                if (ref($rolehash->{$item}) eq 'HASH') {
                    $userdata{'extent'} = $item;
                    foreach my $key (keys(%{$rolehash->{$item}})) {
                        ($userdata{'username'},$userdata{'domain'},$userdata{'role'}) =  split(/:/,$key);
                        ($userdata{'start'},$userdata{'end'}) = 
                            split(/:/,$rolehash->{$item}{$key});
                        my $uniqid = $key.':'.$item;
                        &build_user_record($context,\%userdata,$userinfo,
                                           $indexhash,$uniqid,$userlist);
                    }
                }
            } elsif (($env{'form.roletype'} eq 'course') || 
                     ($env{'form.roletype'} eq 'community')) {
                ($userdata{'username'},$userdata{'domain'},$userdata{'role'}) =
                    split(/:/,$item);
                if (ref($rolehash->{$item}) eq 'HASH') {
                    my $numcids = keys(%{$rolehash->{$item}});
                    foreach my $cid (sort(keys(%{$rolehash->{$item}}))) {
                        if (ref($rolehash->{$item}{$cid}) eq 'HASH') {
                            my $spanstart = '';
                            my $spanend = '; ';
                            my $space = ', ';
                            if ($format eq 'html' || $format eq 'view') {
                                $spanstart = '<span class="LC_nobreak">';
                                # FIXME: actions on courses disabled for now
#                                if ($permission->{'cusr'}) {
#                                    if ($numcids > 1) {
#                                        $spanstart .= '<input type="radio" name="'.$item.'" value="'.$cid.'" />&nbsp;';
#                                    } else {
#                                        $spanstart .= '<input type="hidden" name="'.$item.'" value="'.$cid.'" />&nbsp;';
#                                    }
#                                }
                                $spanend = '</span><br />';
                                $space = ',&nbsp;';
                            }
                            $userdata{'extent'} .= $spanstart.
                                    $rolehash->{$item}{$cid}{'desc'}.$space;
                            if (ref($rolehash->{$item}{$cid}{'secs'}) eq 'HASH') { 
                                foreach my $sec (sort(keys(%{$rolehash->{$item}{$cid}{'secs'}}))) {
                                    if (($env{'form.Status'} eq 'Any') ||
                                        ($env{'form.Status'} eq $rolehash->{$item}{$cid}{'secs'}{$sec})) {
                                        $userdata{'extent'} .= $sec.$space.$rolehash->{$item}{$cid}{'secs'}{$sec}.$spanend;
                                        $userdata{'status'} = $rolehash->{$item}{$cid}{'secs'}{$sec};
                                    }
                                }
                            }
                        }
                    }
                }
                if ($userdata{'status'} ne '') {
                    &build_user_record($context,\%userdata,$userinfo,
                                       $indexhash,$item,$userlist);
                }
            }
        }
    }
    return;
}

sub build_user_record {
    my ($context,$userdata,$userinfo,$indexhash,$record_key,$userlist) = @_;
    next if ($userdata->{'start'} eq '-1' && $userdata->{'end'} eq '-1');
    if (!(($context eq 'domain') && (($env{'form.roletype'} eq 'course')
                             && ($env{'form.roletype'} eq 'community')))) {
        &process_date_info($userdata);
    }
    my $username = $userdata->{'username'};
    my $domain = $userdata->{'domain'};
    if (ref($userinfo->{$username.':'.$domain}) eq 'HASH') {
        $userdata->{'fullname'} = $userinfo->{$username.':'.$domain}{'fullname'};
        $userdata->{'id'} = $userinfo->{$username.':'.$domain}{'id'};
    } else {
        &aggregate_user_info($domain,$username,$userinfo);
        $userdata->{'fullname'} = $userinfo->{$username.':'.$domain}{'fullname'};
        $userdata->{'id'} = $userinfo->{$username.':'.$domain}{'id'};
    }
    foreach my $key (keys(%{$indexhash})) {
        if (defined($userdata->{$key})) {
            $userlist->{$record_key}[$indexhash->{$key}] = $userdata->{$key};
        }
    }
    return;
}

sub courses_selector {
    my ($cdom,$formname) = @_;
    my %coursecodes = ();
    my %codes = ();
    my @codetitles = ();
    my %cat_titles = ();
    my %cat_order = ();
    my %idlist = ();
    my %idnums = ();
    my %idlist_titles = ();
    my $caller = 'global';
    my $format_reply;
    my $jscript = '';

    my $totcodes = 0;
    $totcodes =
        &Apache::courseclassifier::retrieve_instcodes(\%coursecodes,
                                                      $cdom,$totcodes);
    if ($totcodes > 0) {
        $format_reply =
             &Apache::lonnet::auto_instcode_format($caller,$cdom,\%coursecodes,
                                \%codes,\@codetitles,\%cat_titles,\%cat_order);
        if ($format_reply eq 'ok') {
            my $numtypes = @codetitles;
            &Apache::courseclassifier::build_code_selections(\%codes,\@codetitles,\%cat_titles,\%cat_order,\%idlist,\%idnums,\%idlist_titles);
            my ($scripttext,$longtitles) = &Apache::courseclassifier::javascript_definitions(\@codetitles,\%idlist,\%idlist_titles,\%idnums,\%cat_titles);
            my $longtitles_str = join('","',@{$longtitles});
            my $allidlist = $idlist{$codetitles[0]};
            $jscript .= &Apache::courseclassifier::courseset_js_start($formname,$longtitles_str,$allidlist);
            $jscript .= $scripttext;
            $jscript .= &Apache::courseclassifier::javascript_code_selections($formname,@codetitles);
        }
    }
    my $cb_jscript = &Apache::loncommon::coursebrowser_javascript($cdom);

    my %elements = (
                     Year => 'selectbox',
                     coursepick => 'radio',
                     coursetotal => 'text',
                     courselist => 'text',
                   );
    $jscript .= &Apache::lonhtmlcommon::set_form_elements(\%elements);
    if ($env{'form.coursepick'} eq 'category') {
        $jscript .= qq|
function setCourseCat(formname) {
    if (formname.Year.options[formname.Year.selectedIndex].value == -1) {
        return;
    }
    courseSet('$codetitles[0]');
    for (var j=0; j<formname.Semester.length; j++) {
        if (formname.Semester.options[j].value == "$env{'form.Semester'}") {
            formname.Semester.options[j].selected = true;
        }
    }
    if (formname.Semester.options[formname.Semester.selectedIndex].value == -1) {
        return;
    }
    courseSet('$codetitles[1]');
    for (var j=0; j<formname.Department.length; j++) {
        if (formname.Department.options[j].value == "$env{'form.Department'}") {            formname.Department.options[j].selected = true;
        }
    }
    if (formname.Department.options[formname.Department.selectedIndex].value == -1) {
        return;
    }
    courseSet('$codetitles[2]');
    for (var j=0; j<formname.Number.length; j++) {
        if (formname.Number.options[j].value == "$env{'form.Number'}") {
            formname.Number.options[j].selected = true;
        }
    }
}
|;
    }
    return ($cb_jscript,$jscript,$totcodes,\@codetitles,\%idlist,
            \%idlist_titles);
}

sub course_selector_loadcode {
    my ($formname) = @_;
    my $loadcode;
    if ($env{'form.coursepick'} ne '') {
        $loadcode = 'javascript:setFormElements(document.'.$formname.')';
        if ($env{'form.coursepick'} eq 'category') {
            $loadcode .= ';javascript:setCourseCat(document.'.$formname.')';
        }
    }
    return $loadcode;
}

sub process_coursepick {
    my $coursefilter = $env{'form.coursepick'};
    my $cdom = $env{'request.role.domain'};
    my %courses;
    my $crssrch = 'Course';
    if ($env{'form.roletype'} eq 'community') {
        $crssrch = 'Community';
    }
    if ($coursefilter eq 'all') {
        %courses = &Apache::lonnet::courseiddump($cdom,'.','.','.','.','.',
                                                 undef,undef,$crssrch);
    } elsif ($coursefilter eq 'category') {
        my $instcode = &instcode_from_coursefilter();
        %courses = &Apache::lonnet::courseiddump($cdom,'.','.',$instcode,'.','.',
                                                 undef,undef,$crssrch);
    } elsif ($coursefilter eq 'specific') {
        if ($env{'form.coursetotal'} > 1) {
            my @course_ids = split(/&&/,$env{'form.courselist'});
            foreach my $cid (@course_ids) {
                $courses{$cid} = '';
            }
        } else {
            $courses{$env{'form.courselist'}} = '';
        }
    }
    return %courses;
}

sub instcode_from_coursefilter {
    my $instcode = '';
    my @cats = ('Semester','Year','Department','Number');
    foreach my $category (@cats) {
        if (defined($env{'form.'.$category})) {
            unless ($env{'form.'.$category} eq '-1') {
                $instcode .= $env{'form.'.$category};
           }
        }
    }
    if ($instcode eq '') {
        $instcode = '.';
    }
    return $instcode;
}

sub make_keylist_array {
    my ($index,$keylist);
    $index->{'domain'} = &Apache::loncoursedata::CL_SDOM();
    $index->{'username'} = &Apache::loncoursedata::CL_SNAME();
    $index->{'end'} = &Apache::loncoursedata::CL_END();
    $index->{'start'} = &Apache::loncoursedata::CL_START();
    $index->{'id'} = &Apache::loncoursedata::CL_ID();
    $index->{'section'} = &Apache::loncoursedata::CL_SECTION();
    $index->{'fullname'} = &Apache::loncoursedata::CL_FULLNAME();
    $index->{'status'} = &Apache::loncoursedata::CL_STATUS();
    $index->{'type'} = &Apache::loncoursedata::CL_TYPE();
    $index->{'lockedtype'} = &Apache::loncoursedata::CL_LOCKEDTYPE();
    $index->{'groups'} = &Apache::loncoursedata::CL_GROUP();
    $index->{'email'} = &Apache::loncoursedata::CL_PERMANENTEMAIL();
    $index->{'role'} = &Apache::loncoursedata::CL_ROLE();
    $index->{'extent'} = &Apache::loncoursedata::CL_EXTENT();
    $index->{'photo'} = &Apache::loncoursedata::CL_PHOTO();
    $index->{'thumbnail'} = &Apache::loncoursedata::CL_THUMBNAIL();
    $index->{'credits'} = &Apache::loncoursedata::CL_CREDITS();
    $index->{'authorquota'} = &Apache::loncoursedata::CL_AUTHORQUOTA();
    $index->{'authorusage'} = &Apache::loncoursedata::CL_AUTHORUSAGE();
    foreach my $key (keys(%{$index})) {
        $keylist->[$index->{$key}] = $key;
    }
    return ($index,$keylist);
}

sub aggregate_user_info {
    my ($udom,$uname,$userinfo) = @_;
    my %info=&Apache::lonnet::get('environment',
                                  ['firstname','middlename',
                                   'lastname','generation','id'],
                                   $udom,$uname);
    my ($tmp) = keys(%info);
    my ($fullname,$id);
    if ($tmp =~/^(con_lost|error|no_such_host)/i) {
        $fullname = 'not available';
        $id = 'not available';
        &Apache::lonnet::logthis('unable to retrieve environment '.
                                 'for '.$uname.':'.$udom);
    } else {
        $fullname = &Apache::lonnet::format_name(@info{qw/firstname middlename lastname generation/},'lastname');
        $id = $info{'id'};
    }
    $userinfo->{$uname.':'.$udom} = { 
                                      fullname => $fullname,
                                      id       => $id,
                                    };
    return;
}

sub process_date_info {
    my ($userdata) = @_;
    my $now = time;
    $userdata->{'status'} = 'Active';
    if ($userdata->{'start'} > 0) {
        if ($now < $userdata->{'start'}) {
            $userdata->{'status'} = 'Future';
        }
    }
    if ($userdata->{'end'} > 0) {
        if ($now > $userdata->{'end'}) {
            $userdata->{'status'} = 'Expired';
        }
    }
    return;
}

sub show_users_list {
    my ($r,$context,$mode,$permission,$statusmode,$userlist,$keylist,$formname,
        $showcredits,$needauthorquota,$needauthorusage)=@_;
    if ($formname eq '') {
        $formname = 'studentform';
    }
    my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
    #
    # Variables for excel output
    my ($excel_workbook, $excel_sheet, $excel_filename,$row,$format);
    #
    # Variables for csv output
    my ($CSVfile,$CSVfilename);
    #
    my $sortby = $env{'form.sortby'};
    my @sortable = ('username','domain','id','fullname','start','end','email','role');
    if ($context eq 'course') {
        push(@sortable,('section','groups','type'));
        if ($showcredits) {
            push(@sortable,'credits');
        }
    } else {
        push(@sortable,'extent');
        if (($context eq 'domain') && ($env{'form.roletype'} eq 'domain') &&
            (($env{'form.showrole'} eq 'Any') || ($env{'form.showrole'} eq 'au'))) {
            push(@sortable,('authorusage','authorquota'));
        }
    }
    if ($mode eq 'pickauthor') {
        @sortable = ('username','fullname','email','status');
    }
    my %is_sortable;
    map { $is_sortable{$_} = 1; } @sortable;
    unless ($is_sortable{$sortby}) {
        $sortby = 'username';
    }
    my $setting = $env{'form.roletype'};
    my ($cid,$cdom,$cnum,$classgroups,$crstype,$defaultcredits);
    if ($context eq 'course') {
        $cid = $env{'request.course.id'};
        $crstype = &Apache::loncommon::course_type();
        ($cnum,$cdom) = &get_course_identity($cid);
        $defaultcredits = $env{'course.'.$cid.'.internal.defaultcredits'};
        ($classgroups) = &Apache::loncoursedata::get_group_memberships(
                                     $userlist,$keylist,$cdom,$cnum);
        if ($mode eq 'autoenroll') {
            $env{'form.showrole'} = 'st';
        } else {
            if ($env{'course.'.$cid.'.internal.showphoto'}) {
                $r->print('
<script type="text/javascript">
// <![CDATA[
function photowindow(photolink) {
    var title = "Photo_Viewer";
    var options = "scrollbars=1,resizable=1,menubar=0";
    options += ",width=240,height=240";
    stdeditbrowser = open(photolink,title,options,"1");
    stdeditbrowser.focus();
}
// ]]>
</script>
               ');
            }
        }
    } elsif ($context eq 'domain') {
        if ($setting eq 'community') {
            $crstype = 'Community';
        } elsif ($setting eq 'course') {
            $crstype = 'Course';
        }
    }
    if ($mode ne 'autoenroll' && $mode ne 'pickauthor') {
        my $date_sec_selector = &date_section_javascript($context,$setting,$statusmode);
        my $verify_action_js = &bulkaction_javascript($formname);
        $r->print(<<END);

<script type="text/javascript" language="Javascript">
// <![CDATA[

$verify_action_js

function username_display_launch(username,domain) {
    var target;
    for (var i=0; i<document.$formname.usernamelink.length; i++) {
        if (document.$formname.usernamelink[i].checked) {
            target = document.$formname.usernamelink[i].value;
        }
    }
    if (target == 'modify') {
        if (document.$formname.userwin.checked == true) {
            var url = '/adm/createuser?srchterm='+username+'&srchdomain='+domain+'&phase=get_user_info&action=singleuser&srchin=dom&srchby=uname&srchtype=exact&popup=1';
            var options = 'height=600,width=800,resizable=yes,scrollbars=yes,location=no,menubar=no,toolbar=no';
            modifywin = window.open(url,'',options,1);
            modifywin.focus();
            return;
        } else {
            document.$formname.srchterm.value=username;
            document.$formname.srchdomain.value=domain;
            document.$formname.phase.value='get_user_info';
            document.$formname.action.value = 'singleuser';
            document.$formname.submit();
        }
    }
    if (target == 'aboutme') {
        if (document.$formname.userwin.checked == true) {
            var url = '/adm/'+domain+'/'+username+'/aboutme?popup=1';
            var options = 'height=600,width=800,resizable=yes,scrollbars=yes,location=no,menubar=no,toolbar=no';
            aboutmewin = window.open(url,'',options,1);
            aboutmewin.focus();
            return;
        } else {
            document.location.href = '/adm/'+domain+'/'+username+'/aboutme';
        }
    }
    if (target == 'track') {
        if (document.$formname.userwin.checked == true) {
            var url = '/adm/trackstudent?selected_student='+username+':'+domain+'&only_body=1';
            var options = 'height=600,width=800,resizable=yes,scrollbars=yes,location=no,menubar=no,toolbar=no';
            var trackwin = window.open(url,'',options,1);
            trackwin.focus();
            return;
        } else {
            document.location.href = '/adm/trackstudent?selected_student='+username+':'+domain;
        }
    }
}
// ]]>
</script>
$date_sec_selector
<input type="hidden" name="state" value="$env{'form.state'}" />
END
    }
    $r->print(<<END);
<input type="hidden" name="sortby" value="$sortby" />
END
    my @cols = &infocolumns($context,$mode,$showcredits);
    my %coltxt = &get_column_names($context);
    my %acttxt = &Apache::lonlocal::texthash(
                       'pr'         => "Proceed",
                       'ac'         => "Action to take for selected users",
                       'link'       => "Behavior of clickable username link for each user",
                       'aboutme'    => "Display a user's personal information page",
                       'owin'       => "Open in a new window",
                       'modify'     => "Modify a user's information",
                       'track'      => "View a user's recent activity",
                      );
    my %lt = (%coltxt,%acttxt);
    my $rolefilter = $env{'form.showrole'};
    if ($env{'form.showrole'} eq 'cr') {
        $rolefilter = &mt('custom');  
    } elsif ($env{'form.showrole'} ne 'Any') {
        $rolefilter = &Apache::lonnet::plaintext($env{'form.showrole'},$crstype);
    }
    my $results_description;
    if ($mode ne 'autoenroll') {
        $results_description = &results_header_row($rolefilter,$statusmode,
                                                   $context,$permission,$mode,$crstype);
        $r->print('<b>'.$results_description.'</b><br clear="all" />');
    }
    my ($output,$actionselect,%canchange,%canchangesec);
    if ($mode eq 'html' || $mode eq 'view' || $mode eq 'autoenroll' || $mode eq 'pickauthor') {
        if ($mode ne 'autoenroll' && $mode ne 'pickauthor') {
            if ($permission->{'cusr'}) {
                unless (($context eq 'domain') && 
                        (($setting eq 'course') || ($setting eq 'community'))) {
                    $actionselect = 
                        &select_actions($context,$setting,$statusmode,$formname);
                }
            }
            $r->print(<<END);
<input type="hidden" name="srchby"  value="uname" />
<input type="hidden" name="srchin"   value="dom" />
<input type="hidden" name="srchtype" value="exact" />
<input type="hidden" name="srchterm" value="" />
<input type="hidden" name="srchdomain" value="" /> 
END
            if ($actionselect) {
                $output .= <<"END";
<div class="LC_left_float"><fieldset><legend>$lt{'ac'}</legend>
$actionselect
<br/><br /><input type="button" value="$lt{'ca'}" onclick="javascript:checkAll(document.$formname.actionlist)" /> &nbsp;
<input type="button" value="$lt{'ua'}" onclick="javascript:uncheckAll(document.$formname.actionlist)" /><br /><input type="button" value="$lt{'pr'}" onclick="javascript:verify_action('actionlist')" /></fieldset></div>
END
                my @allroles;
                if ($env{'form.showrole'} eq 'Any') {
                    my $custom = 1;
                    if ($context eq 'domain') {
                        @allroles = &roles_by_context($setting,$custom,$crstype);
                    } else {
                        @allroles = &roles_by_context($context,$custom,$crstype);
                    }
                } else {
                    @allroles = ($env{'form.showrole'});
                }
                foreach my $role (@allroles) {
                    if ($context eq 'domain') {
                        if ($setting eq 'domain') {
                            if (&Apache::lonnet::allowed('c'.$role,
                                    $env{'request.role.domain'})) {
                                $canchange{$role} = 1;
                            }
                        } elsif ($setting eq 'author') {
                            if (&Apache::lonnet::allowed('c'.$role,
                                    $env{'request.role.domain'})) {
                                $canchange{$role} = 1;
                            }
                        }
                    } elsif ($context eq 'author') {
                        if (&Apache::lonnet::allowed('c'.$role,
                            $env{'user.domain'}.'/'.$env{'user.name'})) {
                            $canchange{$role} = 1;
                        }
                    } elsif ($context eq 'course') {
                        if (&Apache::lonnet::allowed('c'.$role,$env{'request.course.id'})) {
                            $canchange{$role} = 1;
                        } elsif ($env{'request.course.sec'} ne '') {
                            if (&Apache::lonnet::allowed('c'.$role,$env{'request.course.id'}.'/'.$env{'request.course.sec'})) {
                                $canchangesec{$role} = $env{'request.course.sec'};
                            }
                        } elsif ((($role eq 'co') && ($crstype eq 'Community')) ||
                                 (($role eq 'cc') && ($crstype eq 'Course'))) {
                            if (&is_courseowner($env{'request.course.id'},
                                                $env{'course.'.$env{'request.course.id'}.'.internal.courseowner'})) {
                                $canchange{$role} = 1;
                            }
                        }
                    }
                }
            }
            $output .= '<div class="LC_left_float"><fieldset><legend>'.$lt{'link'}.'</legend>'.
                       '<table><tr>';
            my @linkdests = ('aboutme');
            if ($permission->{'cusr'}) {
                unshift (@linkdests,'modify');
            }
            if (&Apache::lonnet::allowed('vsa', $env{'request.course.id'}) ||
                &Apache::lonnet::allowed('vsa', $env{'request.course.id'}.'/'.
                                         $env{'request.course.sec'})) {
                push(@linkdests,'track');
            }

            $output .= '<td>';
            my $usernamelink = $env{'form.usernamelink'};
            if ($usernamelink eq '') {
                $usernamelink = 'aboutme';
            }
            foreach my $item (@linkdests) {
                my $checkedstr = '';
                if ($item eq $usernamelink) {
                    $checkedstr = ' checked="checked"';
                }
                $output .= '<span class="LC_nobreak"><label><input type="radio" name="usernamelink" value="'.$item.'"'.$checkedstr.' />&nbsp;'.$lt{$item}.'</label></span><br />';
            }
            my $checkwin;
            if ($env{'form.userwin'}) {
                $checkwin = ' checked="checked"';
            }
            $output .=
                '</td><td valign="top"  style="border-left: 1px solid;">'
               .'<span class="LC_nobreak"><label>'
               .'<input type="checkbox" name="userwin" value="1"'.$checkwin.' />'.$lt{'owin'}
               .'</label></span></td></tr></table></fieldset></div>';
        }
        $output .= "\n".'<br clear="all" />'."\n".
                  &Apache::loncommon::start_data_table().
                  &Apache::loncommon::start_data_table_header_row();
        if ($mode eq 'autoenroll') {
            $output .= "
 <th><a href=\"javascript:document.$formname.sortby.value='type';document.$formname.submit();\">$lt{'type'}</a></th>
            ";
        } else {
            $output .= "\n".'<th>&nbsp;</th>'."\n";
            if ($actionselect) {
                $output .= '<th class="LC_nobreak" valign="top">'.&mt('Select').'</th>'."\n";
            }
        }
        foreach my $item (@cols) {
            $output .= '<th class="LC_nobreak" valign="top">';
            if ($is_sortable{$item}) {
                $output .= "<a href=\"javascript:document.$formname.sortby.value='$item';document.$formname.submit();\" style=\"text-decoration:none;\">$lt{$item}<span class=\"LC_fontsize_small\"> &#9660;</span></a>";
            } else {
                $output .= $lt{$item};
            }
            $output .= "</th>\n";
        }
        my %role_types = &role_type_names();
        $output .= &Apache::loncommon::end_data_table_header_row();
# Done with the HTML header line
    } elsif ($mode eq 'csv') {
        #
        # Open a file
        $CSVfilename = '/prtspool/'.
                       $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
                       time.'_'.rand(1000000000).'.csv';
        unless ($CSVfile = Apache::File->new('>/home/httpd'.$CSVfilename)) {
            $r->log_error("Couldn't open $CSVfilename for output $!");
            $r->print(
                '<p class="LC_error">'
               .&mt('Problems occurred in writing the CSV file.')
               .' '.&mt('This error has been logged.')
               .' '.&mt('Please alert your LON-CAPA administrator.')
               .'</p>'
            );
            $CSVfile = undef;
        }
        #
        # Write headers and data to file
        print $CSVfile '"'.$results_description.'"'."\n"; 
        print $CSVfile '"'.join('","',map {
            &Apache::loncommon::csv_translate($lt{$_})
            } (@cols))."\"\n";
    } elsif ($mode eq 'excel') {
        # Create the excel spreadsheet
        ($excel_workbook,$excel_filename,$format) =
            &Apache::loncommon::create_workbook($r);
        return if (! defined($excel_workbook));
        $excel_sheet = $excel_workbook->addworksheet('userlist');
        $excel_sheet->write($row++,0,$results_description,$format->{'h2'});
        #
        my @colnames = map {$lt{$_}} (@cols);

        $excel_sheet->write($row++,0,\@colnames,$format->{'bold'});
    }

# Done with header lines in all formats
    my %index;
    my $i;
    foreach my $idx (@$keylist) {
        $index{$idx} = $i++;
    }
    my $usercount = 0;
    my ($secfilter,$grpfilter);
    if ($context eq 'course') {
        $secfilter = $env{'form.secfilter'};
        $grpfilter = $env{'form.grpfilter'};
        if ($secfilter eq '') {
            $secfilter = 'all';
        }
        if ($grpfilter eq '') {
            $grpfilter = 'all';
        }
    }
    my %ltstatus = &Apache::lonlocal::texthash(
                                                Active  => 'Active',
                                                Future  => 'Future',
                                                Expired => 'Expired',
                                               );
    # If this is for a single course get last course "log-in".
    my %crslogins;
    if ($context eq 'course') {
        %crslogins=&Apache::lonnet::dump('nohist_crslastlogin',$cdom,$cnum);
    }
    # Get groups, role, permanent e-mail so we can sort on them if
    # necessary.
    foreach my $user (keys(%{$userlist})) {
        if ($user eq '' ) {
            delete($userlist->{$user});
            next;
        }
        if ($context eq 'domain' &&  $user eq $env{'request.role.domain'}.'-domainconfig:'.$env{'request.role.domain'}) {
            delete($userlist->{$user});
            next;
        }
        my ($uname,$udom,$role,$groups,$email);
        if (($statusmode ne 'Any') && 
                 ($userlist->{$user}->[$index{'status'}] ne $statusmode)) {
            delete($userlist->{$user});
            next;
        }
        if ($context eq 'domain') {
            if ($env{'form.roletype'} eq 'domain') {
                ($role,$uname,$udom) = split(/:/,$user);
                if (($uname eq $env{'request.role.domain'}.'-domainconfig') &&
                    ($udom eq $env{'request.role.domain'})) {
                    delete($userlist->{$user});
                    next;
                }
            } elsif ($env{'form.roletype'} eq 'author') {
                ($uname,$udom,$role) = split(/:/,$user,-1);
            } elsif (($env{'form.roletype'} eq 'course') || 
                     ($env{'form.roletype'} eq 'community')) {
                ($uname,$udom,$role) = split(/:/,$user);
            }
        } else {
            ($uname,$udom,$role) = split(/:/,$user,-1);
            if (($context eq 'course') && $role eq '') {
                $role = 'st';
            }
        }
        $userlist->{$user}->[$index{'role'}] = $role;
        if (($env{'form.showrole'} ne 'Any') && (!($env{'form.showrole'}  eq 'cr' && $role =~ /^cr\//)) && ($role ne $env{'form.showrole'})) {
            delete($userlist->{$user});
            next;
        }
        if ($context eq 'course') {
            my @ac_groups;
            if (ref($classgroups) eq 'HASH') {
                $groups = $classgroups->{$user};
            }
            if (ref($groups->{'active'}) eq 'HASH') {
                @ac_groups = keys(%{$groups->{'active'}});
                $userlist->{$user}->[$index{'groups'}] = join(', ',@ac_groups);
            }
            if ($mode ne 'autoenroll') {
                my $section = $userlist->{$user}->[$index{'section'}];
                if (($env{'request.course.sec'} ne '') && 
                    ($section ne $env{'request.course.sec'})) {
                    if ($role eq 'st') {
                        delete($userlist->{$user});
                        next;
                    }
                }
                if ($secfilter eq 'none') {
                    if ($section ne '') {
                        delete($userlist->{$user});
                        next;
                    }
                } elsif ($secfilter ne 'all') {
                    if ($section ne $secfilter) {
                        delete($userlist->{$user});
                        next;
                    }
                }
                if ($grpfilter eq 'none') {
                    if (@ac_groups > 0) {
                        delete($userlist->{$user});
                        next;
                    }
                } elsif ($grpfilter ne 'all') {
                    if (!grep(/^\Q$grpfilter\E$/,@ac_groups)) {
                        delete($userlist->{$user});
                        next;
                    }
                }
                if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) {
                    if ((grep/^photo$/,@cols) && ($role eq 'st')) {
                        $userlist->{$user}->[$index{'photo'}] =
                            &Apache::lonnet::retrievestudentphoto($udom,$uname,'jpg');
                        $userlist->{$user}->[$index{'thumbnail'}] =
                            &Apache::lonnet::retrievestudentphoto($udom,$uname,
                                                                'gif','thumbnail');
                    }
                }
                if (($role eq 'st') && ($defaultcredits)) {
                    if ($userlist->{$user}->[$index{'credits'}] eq '') {
                        $userlist->{$user}->[$index{'credits'}] = $defaultcredits;
                    }
                }
            }
        }
        my %emails   = &Apache::loncommon::getemails($uname,$udom);
        if ($emails{'permanentemail'} =~ /\S/) {
            $userlist->{$user}->[$index{'email'}] = $emails{'permanentemail'};
        }
        if (($context eq 'domain') && ($env{'form.roletype'} eq 'domain') && 
            ($role eq 'au')) {
            my ($disk_quota,$current_disk_usage,$percent); 
            if (($needauthorusage) || ($needauthorquota)) {
                $disk_quota = &Apache::loncommon::get_user_quota($uname,$udom,'author');
            }
            if ($needauthorusage) {
                $current_disk_usage =
                    &Apache::lonnet::diskusage($udom,$uname,"$londocroot/priv/$udom/$uname");
                if ($disk_quota == 0) {
                    $percent = 100.0;
                } else {
                    $percent = $current_disk_usage/(10 * $disk_quota);
                }
                $userlist->{$user}->[$index{'authorusage'}] = sprintf("%.0f",$percent);
            }
            if ($needauthorquota) {
                $userlist->{$user}->[$index{'authorquota'}] = sprintf("%.2f",$disk_quota);
            }
        }
        $usercount ++;
    }
    my $autocount = 0;
    my $manualcount = 0;
    my $lockcount = 0;
    my $unlockcount = 0;
    if ($usercount) {
        $r->print($output);
    } else {
        if ($mode eq 'autoenroll') {
            return ($usercount,$autocount,$manualcount,$lockcount,$unlockcount);
        } else {
            return;
        }
    }
    #
    # Sort the users
    my $index  = $index{$sortby};
    my $second = $index{'username'};
    my $third  = $index{'domain'};
    my @sorted_users;
    if (($sortby eq 'authorquota') || ($sortby eq 'authorusage')) {  
        @sorted_users = sort {
            $userlist->{$b}->[$index] <=> $userlist->{$a}->[$index]           ||
            lc($userlist->{$a}->[$second]) cmp lc($userlist->{$b}->[$second]) ||
            lc($userlist->{$a}->[$third]) cmp lc($userlist->{$b}->[$third])
            } (keys(%$userlist));
    } else {
        @sorted_users = sort {
            lc($userlist->{$a}->[$index]) cmp lc($userlist->{$b}->[$index])   ||
            lc($userlist->{$a}->[$second]) cmp lc($userlist->{$b}->[$second]) ||
            lc($userlist->{$a}->[$third]) cmp lc($userlist->{$b}->[$third])
            } (keys(%$userlist));
    }
    my $rowcount = 0;
    foreach my $user (@sorted_users) {
        my %in;
        my $sdata = $userlist->{$user};
        $rowcount ++; 
        foreach my $item (@{$keylist}) {
            $in{$item} = $sdata->[$index{$item}];
        }
        my $clickers = (&Apache::lonnet::userenvironment($in{'domain'},$in{'username'},'clickers'))[1];
        if ($clickers!~/\w/) { $clickers='-'; }
        $in{'clicker'} = $clickers;
	my $role = $in{'role'};
        $in{'role'}=&Apache::lonnet::plaintext($sdata->[$index{'role'}],$crstype);
        unless ($mode eq 'excel') {
            if (! defined($in{'start'}) || $in{'start'} == 0) {
                $in{'start'} = &mt('none');
            } else {
                $in{'start'} = &Apache::lonlocal::locallocaltime($in{'start'});
            }
            if (! defined($in{'end'}) || $in{'end'} == 0) {
                $in{'end'} = &mt('none');
            } else {
                $in{'end'} = &Apache::lonlocal::locallocaltime($in{'end'});
            }
        }
        if ($context eq 'course') {
            my $lastlogin = $crslogins{$in{'username'}.':'.$in{'domain'}.':'.$in{'section'}.':'.$role};
            if ($lastlogin ne '') {
                $in{'lastlogin'} = &Apache::lonlocal::locallocaltime($lastlogin);
            }
        }
        if ($mode eq 'view' || $mode eq 'html' || $mode eq 'autoenroll' || $mode eq 'pickauthor') {
            $r->print(&Apache::loncommon::start_data_table_row());
            my $checkval;
            if ($mode eq 'autoenroll') {
                my $cellentry;
                if ($in{'type'} eq 'auto') {
                    $cellentry = '<b>'.&mt('auto').'</b>&nbsp;<label><input type="checkbox" name="chgauto" value="'.$in{'username'}.':'.$in{'domain'}.'" />&nbsp;'.&mt('Change').'</label>';
                    $autocount ++;
                } else {
                    $cellentry = '<table border="0" cellspacing="0"><tr><td rowspan="2"><b>'.&mt('manual').'</b></td><td><span class="LC_nobreak"><label><input type="checkbox" name="chgmanual" value="'.$in{'username'}.':'.$in{'domain'}.'" />&nbsp;'.&mt('Change').'</label></span></td></tr><tr><td><span class="LC_nobreak">';
                    $manualcount ++;
                    if ($in{'lockedtype'}) {
                        $cellentry .= '<label><input type="checkbox" name="unlockchg" value="'.$in{'username'}.':'.$in{'domain'}.'" />&nbsp;'.&mt('Unlock').'</label>';
                        $unlockcount ++;
                    } else {
                        $cellentry .= '<label><input type="checkbox" name="lockchg" value="'.$in{'username'}.':'.$in{'domain'}.'" />&nbsp;'.&mt('Lock').'</label>';
                        $lockcount ++;
                    }
                    $cellentry .= '</span></td></tr></table>';
                }
                $r->print("<td>$cellentry</td>\n");
            } else {
                if ($mode ne 'pickauthor') {  
                    $r->print("<td>$rowcount</td>\n");
                }
                if ($actionselect) {
                    my $showcheckbox;
                    if ($role =~ /^cr\//) {
                        $showcheckbox = $canchange{'cr'};
                    } else {
                        $showcheckbox = $canchange{$role};
                    }
                    if (!$showcheckbox) {
                        if ($context eq 'course') {
                            if ($canchangesec{$role} ne '') {
                                if ($canchangesec{$role} eq $in{'section'}) {
                                    $showcheckbox = 1;
                                }
                            }
                        }
                    }
                    if ($showcheckbox) {
                        $checkval = $user; 
                        if ($context eq 'course') {
                            if (($role eq 'co' || $role eq 'cc') &&
                                ($user =~ /^\Q$env{'user.name'}:$env{'user.domain'}:$role\E/)) {
                                $showcheckbox = 0;
                            } else {
                                if ($role eq 'st') {
                                    $checkval .= ':st';
                                }
                                $checkval .= ':'.$in{'section'};
                                if ($role eq 'st') {
                                    $checkval .= ':'.$in{'type'}.':'.
                                                 $in{'lockedtype'}.':'.
                                                 $in{'credits'};
                                }
                             }
                        }
                        if ($showcheckbox) {
                            $r->print('<td><input type="checkbox" name="'.
                                      'actionlist" value="'.$checkval.'" /></td>');
                        } else {
                            $r->print('<td>&nbsp;</td>');
                        }
                    } else {
                        $r->print('<td>&nbsp;</td>');
                    }
                } elsif ($mode eq 'pickauthor') {
                        $r->print('<td><input type="button" name="chooseauthor" onclick="javascript:gochoose('."'$in{'username'}'".');" value="'.&mt('Select').'" /></td>');
                }
            }
            foreach my $item (@cols) {
                if ($item eq 'username') {
                    $r->print('<td>'.&print_username_link($mode,\%in).'</td>');
                } elsif (($item eq 'start' || $item eq 'end') && ($actionselect)) {
                    $r->print('<td>'.$in{$item}.'<input type="hidden" name="'.$checkval.'_'.$item.'" value="'.$sdata->[$index{$item}].'" /></td>'."\n");
                } elsif ($item eq 'status') {
                    my $showitem = $in{$item};
                    if (defined($ltstatus{$in{$item}})) {
                        $showitem = $ltstatus{$in{$item}};
                    }
                    $r->print('<td>'.$showitem.'</td>'."\n");
                } elsif ($item eq 'photo') {
                     if (($context eq 'course') && ($mode ne 'autoenroll') && 
                         ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'})) { 
                         if ($role eq 'st') {
                             $r->print('<td align="right"><a href="javascript:photowindow('."'".$in{'photo'}."'".')"><img src="'.$in{'thumbnail'}.'" border="1" alt="" /></a></td>');
                         } else {
                             $r->print('<td>&nbsp;</td>');
                         }
                     }
                } elsif ($item eq 'clicker') {
                    if (($context eq 'course') && ($mode ne 'autoenroll')) {
                        if ($env{'form.showrole'} eq 'st' || $env{'form.showrole'} eq 'Any') {
                            my $clickers =
                   (&Apache::lonnet::userenvironment($in{'domain'},$in{'username'},'clickers'))[1];
                            if ($clickers!~/\w/) { $clickers='-'; }
                            $r->print('<td>'.$clickers.'</td>');
                        } else {
                             $r->print('<td>&nbsp;</td>'."\n");
                        } 
                    }
                } elsif (($item eq 'authorquota') || ($item eq 'authorusage')) {
                    $r->print('<td align="right">'.$in{$item}.'</td>'."\n");
                } else {
                    $r->print('<td>'.$in{$item}.'</td>'."\n");
                }
            }
            $r->print(&Apache::loncommon::end_data_table_row());
        } elsif ($mode eq 'csv') {
            next if (! defined($CSVfile));
            # no need to bother with $linkto
            my @line = ();
            foreach my $item (@cols) {
                push @line,&Apache::loncommon::csv_translate($in{$item});
            }
            print $CSVfile '"'.join('","',@line)."\"\n";
        } elsif ($mode eq 'excel') {
            my $col = 0;
            foreach my $item (@cols) {
                if ($item eq 'start' || $item eq 'end') {
                    if ((defined($in{$item})) && ($in{$item} != 0)) {
                        $excel_sheet->write($row,$col++,
                            &Apache::lonstathelpers::calc_serial($in{$item}),
                                    $format->{'date'});
                    } else {
                        $excel_sheet->write($row,$col++,'none');
                    }
                } else {
                    $excel_sheet->write($row,$col++,$in{$item});
                }
            }
            $row++;
        }
    }
    if ($mode eq 'view' || $mode eq 'html' || $mode eq 'autoenroll' || $mode eq 'pickauthor') {
            $r->print(&Apache::loncommon::end_data_table().'<br />');
    } elsif ($mode eq 'excel') {
        $excel_workbook->close();
	$r->print('<p>'.&mt('[_1]Your Excel spreadsheet[_2] is ready for download.', '<a href="'.$excel_filename.'">','</a>')."</p>\n");
    } elsif ($mode eq 'csv') {
        close($CSVfile);
	$r->print('<p>'.&mt('[_1]Your CSV file[_2] is ready for download.', '<a href="'.$CSVfilename.'">','</a>')."</p>\n");
        $r->rflush();
    }
    if ($mode eq 'autoenroll') {
        return ($usercount,$autocount,$manualcount,$lockcount,$unlockcount);
    } else {
        return ($usercount);
    }
}

sub bulkaction_javascript {
    my ($formname,$caller) = @_;
    my $docstart = 'document';
    if ($caller eq 'popup') {
        $docstart = 'opener.document';
    }
    my %lt = &Apache::lonlocal::texthash(
              acwi => 'Access will be set to start immediately',
              asyo => 'as you did not select an end date in the pop-up window',
              accw => 'Access will be set to continue indefinitely',
              asyd => 'as you did not select an end date in the pop-up window',
              sewi => "Sections will be switched to 'No section'",
              ayes => "as you either selected the 'No section' option",
              oryo => 'or you did not select a section in the pop-up window',
              arol => 'A role with no section will be added',
              swbs => 'Sections will be switched to:',
              rwba => 'Roles will be added for section(s):',
            );
    my $alert = &mt("You must select at least one user by checking a user's 'Select' checkbox");
    my $noaction = &mt("You need to select an action to take for the user(s) you have selected"); 
    my $singconfirm = &mt(' for a single user?');
    my $multconfirm = &mt(' for multiple users?');
    &js_escape(\$alert);
    &js_escape(\$noaction);
    &js_escape(\$singconfirm);
    &js_escape(\$multconfirm);
    my $output = <<"ENDJS";
function verify_action (field) {
    var numchecked = 0;
    var singconf = '$singconfirm';
    var multconf = '$multconfirm';
    if ($docstart.$formname.elements[field].length > 0) {
        for (i=0; i<$docstart.$formname.elements[field].length; i++) {
            if ($docstart.$formname.elements[field][i].checked == true) {
               numchecked ++;
            }
        }
    } else {
        if ($docstart.$formname.elements[field].checked == true) {
            numchecked ++;
        }
    }
    if (numchecked == 0) {
        alert("$alert");
        return;
    } else {
        var message = $docstart.$formname.bulkaction[$docstart.$formname.bulkaction.selectedIndex].text;
        var choice = $docstart.$formname.bulkaction[$docstart.$formname.bulkaction.selectedIndex].value;
        if (choice == '') {
            alert("$noaction");
            return;
        } else {
            if (numchecked == 1) {
                message += singconf;
            } else {
                message += multconf;
            }
ENDJS
    if ($caller ne 'popup') {
        $output .= <<"NEWWIN";
            if (choice == 'chgdates' || choice == 'reenable' || choice == 'activate' || choice == 'chgsec') {
                opendatebrowser(document.$formname,'$formname','go');
                return;

            } else {
                if (confirm(message)) {
                    document.$formname.phase.value = 'bulkchange';
                    document.$formname.submit();
                    return;
                }
            }
NEWWIN
    } else {
        $output .= <<"POPUP";
            if (choice == 'chgdates' || choice == 'reenable' || choice == 'activate') {
                var datemsg = '';
                if (($docstart.$formname.startdate_month.value == '') &&
                    ($docstart.$formname.startdate_day.value  == '') &&
                    ($docstart.$formname.startdate_year.value == '')) {
                    datemsg = "\\n$lt{'acwi'},\\n$lt{'asyo'}.\\n";
                }
                if (($docstart.$formname.enddate_month.value == '') &&
                    ($docstart.$formname.enddate_day.value  == '') &&
                    ($docstart.$formname.enddate_year.value == '')) {
                    datemsg += "\\n$lt{'accw'},\\n$lt{'asyd'}.\\n";
                }
                if (datemsg != '') {
                    message += "\\n"+datemsg;
                }
            }
            if (choice == 'chgsec') {
                var rolefilter = $docstart.$formname.showrole.options[$docstart.$formname.showrole.selectedIndex].value;
                var retained =  $docstart.$formname.retainsec.value;
                var secshow = $docstart.$formname.newsecs.value;
                if (secshow == '') {
                    if (rolefilter == 'st' || retained == 0 || retained == "") {
                        message += "\\n\\n$lt{'sewi'},\\n$lt{'ayes'},\\n$lt{'oryo'}.\\n";
                    } else {
                        message += "\\n\\n$lt{'arol'}\\n$lt{'ayes'},\\n$lt{'oryo'}.\\n";
                    }
                } else {
                    if (rolefilter == 'st' || retained == 0 || retained == "") {
                        message += "\\n\\n$lt{'swbs'} "+secshow+".\\n";
                    } else {
                        message += "\\n\\n$lt{'rwba'} "+secshow+".\\n";
                    }
                }
            }
            if (confirm(message)) {
                $docstart.$formname.phase.value = 'bulkchange';
                $docstart.$formname.submit();
                window.close();
            }
POPUP
    }
    $output .= '
        }
    }
}
';
    return $output;
}

sub print_username_link {
    my ($mode,$in) = @_;
    my $output;
    if ($mode eq 'autoenroll') {
        $output = $in->{'username'};
    } else {
        $output = '<a href="javascript:username_display_launch('.
                  "'$in->{'username'}','$in->{'domain'}'".')">'.
                  $in->{'username'}.'</a>';
    }
    return $output;
}

sub role_type_names {
    my %lt = &Apache::lonlocal::texthash (
                         'domain' => 'Domain Roles',
                         'author' => 'Co-Author Roles',
                         'course' => 'Course Roles',
                         'community' => 'Community Roles',
             );
    return %lt;
}

sub select_actions {
    my ($context,$setting,$statusmode,$formname) = @_;
    my %lt = &Apache::lonlocal::texthash(
                revoke   => "Revoke user roles",
                delete   => "Delete user roles",
                reenable => "Re-enable expired user roles",
                activate => "Make future user roles active now",
                chgdates  => "Change starting/ending dates",
                chgsec   => "Change section associated with user roles",
    );
    # FIXME Add an option to change credits for student roles.
    my ($output,$options,%choices);
    # FIXME Disable actions for now for roletype=course in domain context
    if ($context eq 'domain' && $setting eq 'course') {
        return;
    }
    if ($context eq 'course') {
        if ($env{'form.showrole'} ne 'Any') {
            my $showactions;
            if (&Apache::lonnet::allowed('c'.$env{'form.showrole'},
                                          $env{'request.course.id'})) {
                $showactions = 1;  
            } elsif ($env{'request.course.sec'} ne '') {
                if (&Apache::lonnet::allowed('c'.$env{'form.showrole'},$env{'request.course.id'}.'/'.$env{'request.course.sec'})) {
                    $showactions = 1;
                }
            }
            unless ($showactions) {
                unless (&is_courseowner($env{'request.course.id'},
                                       $env{'course.'.$env{'request.course.id'}.'.internal.courseowner'})) {
                    return; 
                }
            }
        }
    }
    if ($statusmode eq 'Any') {
        $options .= '
<option value="chgdates">'.$lt{'chgdates'}.'</option>';
        $choices{'dates'} = 1;
    } else {
        if ($statusmode eq 'Future') {
            $options .= '
<option value="activate">'.$lt{'activate'}.'</option>';
            $choices{'dates'} = 1;
        } elsif ($statusmode eq 'Expired') {
            $options .= '
<option value="reenable">'.$lt{'reenable'}.'</option>';
            $choices{'dates'} = 1;
        }
        if ($statusmode eq 'Active' || $statusmode eq 'Future') {
            $options .= '
<option value="chgdates">'.$lt{'chgdates'}.'</option>
<option value="revoke">'.$lt{'revoke'}.'</option>';
            $choices{'dates'} = 1;
        }
    }
    if ($context eq 'domain') {
        $options .= '
<option value="delete">'.$lt{'delete'}.'</option>';
    }
    if (($context eq 'course') || ($context eq 'domain' && $setting eq 'course')) {
        if (($statusmode ne 'Expired') && ($env{'request.course.sec'} eq '')) {
            $options .= '
<option value="chgsec">'.$lt{'chgsec'}.'</option>';
            $choices{'sections'} = 1;
        }
    }
    if ($options) {
        $output = '<select name="bulkaction">'."\n".
                  '<option value="" selected="selected">'.
                  &mt('Please select').'</option>'."\n".$options."\n".'</select>';
        if ($choices{'dates'}) {
            $output .= 
                '<input type="hidden" name="startdate_month" value="" />'."\n".
                '<input type="hidden" name="startdate_day" value="" />'."\n".
                '<input type="hidden" name="startdate_year" value="" />'."\n".
                '<input type="hidden" name="startdate_hour" value="" />'."\n".
                '<input type="hidden" name="startdate_minute" value="" />'."\n".
                '<input type="hidden" name="startdate_second" value="" />'."\n".
                '<input type="hidden" name="enddate_month" value="" />'."\n".
                '<input type="hidden" name="enddate_day" value="" />'."\n".
                '<input type="hidden" name="enddate_year" value="" />'."\n".
                '<input type="hidden" name="enddate_hour" value="" />'."\n".
                '<input type="hidden" name="enddate_minute" value="" />'."\n".
                '<input type="hidden" name="enddate_second" value="" />'."\n".
                '<input type="hidden" name="no_end_date" value="" />'."\n";
            if ($context eq 'course') {
                $output .= '<input type="hidden" name="makedatesdefault" value="" />'."\n";
            }
        }
        if ($choices{'sections'}) {
            $output .= '<input type="hidden" name="retainsec" value="" />'."\n".
                       '<input type="hidden" name="newsecs" value="" />'."\n";
        }
    }
    return $output;
}

sub date_section_javascript {
    my ($context,$setting) = @_;
    my $title = 'Date_And_Section_Selector';
    my %nopopup = &Apache::lonlocal::texthash (
        revoke => "Check the boxes for any users for whom roles are to be revoked, and click 'Proceed'",
        delete => "Check the boxes for any users for whom roles are to be deleted, and click 'Proceed'",
        none   => "Choose an action to take for selected users",
    );  
    my $output = <<"ENDONE";
<script type="text/javascript">
// <![CDATA[
    function opendatebrowser(callingform,formname,calledby) {
        var bulkaction = callingform.bulkaction.options[callingform.bulkaction.selectedIndex].value;
        var url = '/adm/createuser?';
        var type = '';
        var showrole = callingform.showrole.options[callingform.showrole.selectedIndex].value;
ENDONE
    if ($context eq 'domain') {
        $output .= '
        type = callingform.roletype.options[callingform.roletype.selectedIndex].value;
';
    }
    my $width= '700';
    my $height = '400';
    $output .= <<"ENDTWO";
        url += 'action=dateselect&callingform=' + formname + 
               '&roletype='+type+'&showrole='+showrole +'&bulkaction='+bulkaction;
        var title = '$title';
        var options = 'scrollbars=1,resizable=1,menubar=0';
        options += ',width=$width,height=$height';
        stdeditbrowser = open(url,title,options,'1');
        stdeditbrowser.focus();
    }
// ]]>
</script>
ENDTWO
    return $output;
}

sub date_section_selector {
    my ($context,$permission,$crstype,$showcredits) = @_;
    my $callingform = $env{'form.callingform'};
    my $formname = 'dateselect';  
    my $groupslist = &get_groupslist();
    my $sec_js =
        &setsections_javascript($formname,$groupslist,undef,undef,$crstype,
                                $showcredits);
    my $output = <<"END";
<script type="text/javascript">
// <![CDATA[

$sec_js

function saveselections(formname) {

END
    if ($env{'form.bulkaction'} eq 'chgsec') {
        $output .= <<"END";
        if (formname.retainsec.length > 1) {  
            for (var i=0; i<formname.retainsec.length; i++) {
                if (formname.retainsec[i].checked == true) {
                    opener.document.$callingform.retainsec.value = formname.retainsec[i].value;
                }
            }
        } else {
            opener.document.$callingform.retainsec.value = formname.retainsec.value;
        }
        setSections(formname,'$crstype');
        if (seccheck == 'ok') {
            opener.document.$callingform.newsecs.value = formname.sections.value;
        }
END
    } else {
        if ($context eq 'course') {
            if (($env{'form.bulkaction'} eq 'reenable') || 
                ($env{'form.bulkaction'} eq 'activate') || 
                ($env{'form.bulkaction'} eq 'chgdates')) {
                if ($env{'request.course.sec'} eq '') {
                    $output .= <<"END";
 
        if (formname.makedatesdefault.checked == true) {
            opener.document.$callingform.makedatesdefault.value = 1;
        }
        else {
            opener.document.$callingform.makedatesdefault.value = 0;
        }

END
                }
            }
        }
        $output .= <<"END";
    opener.document.$callingform.startdate_month.value =  formname.startdate_month.options[formname.startdate_month.selectedIndex].value;
    opener.document.$callingform.startdate_day.value =  formname.startdate_day.value;
    opener.document.$callingform.startdate_year.value = formname.startdate_year.value;
    opener.document.$callingform.startdate_hour.value =  formname.startdate_hour.options[formname.startdate_hour.selectedIndex].value;
    opener.document.$callingform.startdate_minute.value =  formname.startdate_minute.value;
    opener.document.$callingform.startdate_second.value = formname.startdate_second.value;
    opener.document.$callingform.enddate_month.value =  formname.enddate_month.options[formname.enddate_month.selectedIndex].value;
    opener.document.$callingform.enddate_day.value =  formname.enddate_day.value;
    opener.document.$callingform.enddate_year.value = formname.enddate_year.value;
    opener.document.$callingform.enddate_hour.value =  formname.enddate_hour.options[formname.enddate_hour.selectedIndex].value;
    opener.document.$callingform.enddate_minute.value =  formname.enddate_minute.value;
    opener.document.$callingform.enddate_second.value = formname.enddate_second.value;
    if (formname.no_end_date.checked) {
        opener.document.$callingform.no_end_date.value = '1';
    } else {
        opener.document.$callingform.no_end_date.value = '0';
    }
END
    }
    my $verify_action_js = &bulkaction_javascript($callingform,'popup');
    $output .= <<"ENDJS";
    verify_action('actionlist');
}

$verify_action_js

// ]]>
</script>
ENDJS
    my %lt = &Apache::lonlocal::texthash (
                 chac => 'Access dates to apply for selected users',
                 chse => 'Changes in section affiliation to apply to selected users',
                 fors => 'For student roles, changing the section will result in a section switch as students may only be in one section of a course at a time.',
                 forn => 'For a course role that is not "student", users may have roles in more than one section at a time.',
                 reta => "Retain each user's current section affiliations?",
                 dnap => '(Does not apply to student roles).',
            );
    my ($date_items,$headertext);
    if ($env{'form.bulkaction'} eq 'chgsec') {
        $headertext = $lt{'chse'};
    } else {
        $headertext = $lt{'chac'};
        my $starttime;
        if (($env{'form.bulkaction'} eq 'activate') || 
            ($env{'form.bulkaction'} eq 'reenable')) {
            $starttime = time;
        }
        $date_items = &date_setting_table($starttime,undef,$context,
                                          $env{'form.bulkaction'},$formname,
                                          $permission,$crstype);
    }
    $output .= '<h3>'.$headertext.'</h3>'.
               '<form name="'.$formname.'" method="post" action="">'."\n".
                $date_items;
    if ($context eq 'course' && $env{'form.bulkaction'} eq 'chgsec') {
        my ($cnum,$cdom) = &get_course_identity();
        if ($crstype eq 'Community') {
            $lt{'fors'} = &mt('For member roles, changing the section will result in a section switch, as members may only be in one section of a community at a time.');
            $lt{'forn'} = &mt('For a community role that is not "member", users may have roles in more than one section at a time.');
            $lt{'dnap'} = &mt('(Does not apply to member roles).'); 
        }
        my $info;
        if ($env{'form.showrole'} eq 'st') {
            $output .= '<p>'.$lt{'fors'}.'</p>'; 
        } elsif ($env{'form.showrole'} eq 'Any') {
            $output .= '<p>'.$lt{'fors'}.'</p>'.
                       '<p>'.$lt{'forn'}.'&nbsp;';
            $info = $lt{'reta'};
        } else {
            $output .= '<p>'.$lt{'forn'}.'&nbsp;';
            $info = $lt{'reta'};
        }
        if ($info) {
            $info .= '<span class="LC_nobreak">'.
                     '<label><input type="radio" name="retainsec" value="1" '.
                     'checked="checked" />'.&mt('Yes').'</label>&nbsp;&nbsp;'.
                     '<label><input type="radio" name="retainsec" value="0" />'.
                     &mt('No').'</label></span>';
            if ($env{'form.showrole'} eq 'Any') {
                $info .= '<br />'.$lt{'dnap'};
            }
            $info .= '</p>';
        } else {
            $info = '<input type="hidden" name="retainsec" value="0" />'; 
        }
        my $rowtitle = &mt('New section to assign');
        my $secbox = &section_picker($cdom,$cnum,$env{'form.showrole'},$rowtitle,
                                     $permission,$context,'chgsec',$crstype);
        $output .= $info.$secbox;
    }
    $output .= '<p>'.
'<input type="button" name="dateselection" value="'.&mt('Save').'" onclick="javascript:saveselections(this.form)" /></p>'."\n".
'</form>';
    return $output;
}

sub section_picker {
    my ($cdom,$cnum,$role,$rowtitle,$permission,$context,$mode,$crstype,
        $showcredits,$credits) = @_;
    my %sections_count = &Apache::loncommon::get_sections($cdom,$cnum);
    my $sections_select .= &course_sections(\%sections_count,$role);
    my $secbox = '<div>'.&Apache::lonhtmlcommon::start_pick_box()."\n";
    if ($mode eq 'upload') {
        my ($options,$cb_script,$coursepick) =
            &default_role_selector($context,1,$crstype,$showcredits);
        $secbox .= &Apache::lonhtmlcommon::row_title(&mt('role'),'LC_oddrow_value').
                   $options. &Apache::lonhtmlcommon::row_closure(1)."\n";
    }
    $secbox .= &Apache::lonhtmlcommon::row_title($rowtitle,'LC_oddrow_value')."\n";
    if ($env{'request.course.sec'} eq '') {
        $secbox .= '<table class="LC_createuser"><tr class="LC_section_row">'."\n".
                   '<td align="center">'.&mt('Existing sections')."\n".
                   '<br />'.$sections_select.'</td><td align="center">'.
                   &mt('New section').'<br />'."\n".
                   '<input type="text" name="newsec" size="15" value="" />'."\n".
                   '<input type="hidden" name="sections" value="" />'."\n".
                   '</td></tr></table>'."\n";
    } else {
        $secbox .= '<input type="hidden" name="sections" value="'.
                   $env{'request.course.sec'}.'" />'.
                   $env{'request.course.sec'};
    }
    $secbox .= &Apache::lonhtmlcommon::row_closure(1)."\n";
    unless ($mode eq 'chgsec') {
        if ($showcredits) {
            $secbox .= 
                &Apache::lonhtmlcommon::row_title(&mt('credits (students)'),
                                                  'LC_evenrow_value')."\n".
                '<input type="text" name="credits" size="3" value="'.$credits.'" />'."\n".
                &Apache::lonhtmlcommon::row_closure(1)."\n";
        }
    }
    $secbox .= &Apache::lonhtmlcommon::end_pick_box().'</div>';
    return $secbox;
}

sub results_header_row {
    my ($rolefilter,$statusmode,$context,$permission,$mode,$crstype) = @_;
    my ($description,$showfilter);
    if ($rolefilter ne 'Any') {
        $showfilter = $rolefilter;
    }
    if ($context eq 'course') {
        if ($mode eq 'csv' || $mode eq 'excel') {
            if ($crstype eq 'Community') {
                $description = &mt('Community - [_1]:',$env{'course.'.$env{'request.course.id'}.'.description'}).' ';
            } else {
                $description = &mt('Course - [_1]:',$env{'course.'.$env{'request.course.id'}.'.description'}).' ';
            }
        }
        if ($statusmode eq 'Expired') {
            if ($crstype eq 'Community') {
                $description .= &mt('Users in community with expired [_1] roles',$showfilter);
            } else {
                $description .= &mt('Users in course with expired [_1] roles',$showfilter);
            }
        } elsif ($statusmode eq 'Future') {
            if ($crstype eq 'Community') {
                $description .= &mt('Users in community with future [_1] roles',$showfilter);
            } else {
                $description .= &mt('Users in course with future [_1] roles',$showfilter);
            }
        } elsif ($statusmode eq 'Active') {
            if ($crstype eq 'Community') {
                $description .= &mt('Users in community with active [_1] roles',$showfilter);
            } else {
                $description .= &mt('Users in course with active [_1] roles',$showfilter);
            }
        } else {
            if ($rolefilter eq 'Any') {
                if ($crstype eq 'Community') {
                    $description .= &mt('All users in community');
                } else {
                    $description .= &mt('All users in course');
                }
            } else {
                if ($crstype eq 'Community') {
                    $description .= &mt('All users in community with [_1] roles',$rolefilter);
                } else {
                    $description .= &mt('All users in course with [_1] roles',$rolefilter);
                }
            }
        }
        my $constraint;
        my $viewablesec = &viewable_section($permission);
        if ($viewablesec ne '') {
            if ($env{'form.showrole'} eq 'st') {
                $constraint = &mt('only users in section "[_1]"',$viewablesec);
            } elsif (($env{'form.showrole'} ne 'cc') && ($env{'form.showrole'} ne 'co')) {
                $constraint = &mt('only users affiliated with no section or section "[_1]"',$viewablesec);
            }
            if (($env{'form.grpfilter'} ne 'all') && ($env{'form.grpfilter'} ne '')) {
                if ($env{'form.grpfilter'} eq 'none') {
                    $constraint .= &mt(' and not in any group');
                } else {
                    $constraint .= &mt(' and members of group: "[_1]"',$env{'form.grpfilter'});
                }
            }
        } else {
            if (($env{'form.secfilter'} ne 'all') && ($env{'form.secfilter'} ne '')) {
                if ($env{'form.secfilter'} eq 'none') {
                    $constraint = &mt('only users affiliated with no section');
                } else {
                    $constraint = &mt('only users affiliated with section "[_1]"',$env{'form.secfilter'});
                }
            }
            if (($env{'form.grpfilter'} ne 'all') && ($env{'form.grpfilter'} ne '')) {
                if ($env{'form.grpfilter'} eq 'none') {
                    if ($constraint eq '') {
                        $constraint = &mt('only users not in any group');
                    } else {
                        $constraint .= &mt(' and also not in any group'); 
                    }
                } else {
                    if ($constraint eq '') {
                        $constraint = &mt('only members of group: "[_1]"',$env{'form.grpfilter'});
                    } else {
                        $constraint .= &mt(' and also members of group: "[_1]"'.$env{'form.grpfilter'});
                    }
                }
            }
        }
        if ($constraint ne '') {
            $description .= ' ('.$constraint.')';
        } 
    } elsif ($context eq 'author') {
        $description = 
            &mt('Author space for [_1]'
                ,'<span class="LC_cusr_emph">'
                .&Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'})
                .'</span>')
            .':&nbsp;&nbsp;';
        if ($statusmode eq 'Expired') {
            $description .= &mt('Co-authors with expired [_1] roles',$showfilter);
        } elsif ($statusmode eq 'Future') {
            $description .= &mt('Co-authors with future [_1] roles',$showfilter);
        } elsif ($statusmode eq 'Active') {
            $description .= &mt('Co-authors with active [_1] roles',$showfilter);
        } else {
            if ($rolefilter eq 'Any') {
                $description .= &mt('All co-authors');
            } else {
                $description .= &mt('All co-authors with [_1] roles',$rolefilter);
            }
        }
    } elsif ($context eq 'domain') {
        my $domdesc = &Apache::lonnet::domain($env{'request.role.domain'},'description');
        $description = &mt('Domain - [_1]:',$domdesc).' ';
        if ($env{'form.roletype'} eq 'domain') {
            if ($statusmode eq 'Expired') {
                $description .= &mt('Users in domain with expired [_1] roles',$showfilter);
            } elsif ($statusmode eq 'Future') {
                $description .= &mt('Users in domain with future [_1] roles',$showfilter);
            } elsif ($statusmode eq 'Active') {
                $description .= &mt('Users in domain with active [_1] roles',$showfilter);
            } else {
                if ($rolefilter eq 'Any') {
                    $description .= &mt('All users in domain');
                } else {
                    $description .= &mt('All users in domain with [_1] roles',$rolefilter);
                }
            }
        } elsif ($env{'form.roletype'} eq 'author') {
            if ($statusmode eq 'Expired') {
                $description .= &mt('Co-authors in domain with expired [_1] roles',$showfilter);
            } elsif ($statusmode eq 'Future') {
                $description .= &mt('Co-authors in domain with future [_1] roles',$showfilter);
            } elsif ($statusmode eq 'Active') {
               $description .= &mt('Co-authors in domain with active [_1] roles',$showfilter);
            } else {
                if ($rolefilter eq 'Any') {
                    $description .= &mt('All users with co-author roles in domain',$showfilter);
                } else {
                    $description .= &mt('All co-authors in domain with [_1] roles',$rolefilter);
                }
            }
        } elsif (($env{'form.roletype'} eq 'course') || 
                 ($env{'form.roletype'} eq 'community')) {
            my $coursefilter = $env{'form.coursepick'};
            if ($env{'form.roletype'} eq 'course') {
                if ($coursefilter eq 'category') {
                    my $instcode = &instcode_from_coursefilter();
                    if ($instcode eq '.') {
                        $description .= &mt('All courses in domain').' - ';
                    } else {
                        $description .= &mt('Courses in domain with institutional code: [_1]',$instcode).' - ';
                    }
                } elsif ($coursefilter eq 'selected') {
                    $description .= &mt('Selected courses in domain').' - ';
                } elsif ($coursefilter eq 'all') {
                    $description .= &mt('All courses in domain').' - ';
                }
            } elsif ($env{'form.roletype'} eq 'community') {
                if ($coursefilter eq 'selected') {
                    $description .= &mt('Selected communities in domain').' - ';
                } elsif ($coursefilter eq 'all') {
                    $description .= &mt('All communities in domain').' - ';
                }
            }
            if ($statusmode eq 'Expired') {
                $description .= &mt('users with expired [_1] roles',$showfilter);
            } elsif ($statusmode eq 'Future') {
                $description .= &mt('users with future [_1] roles',$showfilter);
            } elsif ($statusmode eq 'Active') {
                $description .= &mt('users with active [_1] roles',$showfilter);
            } else {
                if ($rolefilter eq 'Any') {
                    $description .= &mt('all users');
                } else {
                    $description .= &mt('users with [_1] roles',$rolefilter);
                }
            }
        }
    }
    return $description;
}

sub viewable_section {
    my ($permission) = @_;
    my $viewablesec;
    if (ref($permission) eq 'HASH') {
        if (exists($permission->{'view_section'})) {
            $viewablesec = $permission->{'view_section'};
        } elsif (exists($permission->{'cusr_section'})) {
            $viewablesec = $permission->{'cusr_section'};
        }
    }
    return $viewablesec;
}

    
#################################################
#################################################
sub show_drop_list {
    my ($r,$classlist,$nosort,$permission,$crstype) = @_;
    my $cid = $env{'request.course.id'};
    my ($cnum,$cdom) = &get_course_identity($cid);
    if (! exists($env{'form.sortby'})) {
        &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
                                                ['sortby']);
    }
    my $sortby = $env{'form.sortby'};
    if ($sortby !~ /^(username|domain|section|groups|fullname|id|start|end)$/) {
        $sortby = 'username';
    }
    my $action = "drop";
    my $check_uncheck_js = &Apache::loncommon::check_uncheck_jscript();
    $r->print(<<END);
<input type="hidden" name="sortby" value="$sortby" />
<input type="hidden" name="action" value="$action" />
<input type="hidden" name="state"  value="done" />
<script type="text/javascript" language="Javascript">
// <![CDATA[
$check_uncheck_js
// ]]>
</script>
<input type="hidden" name="phase" value="four" />
END
    my ($indexhash,$keylist) = &make_keylist_array();
    my $studentcount = 0;
    if (ref($classlist) eq 'HASH') {
        foreach my $student (keys(%{$classlist})) {
            my $sdata = $classlist->{$student}; 
            my $status = $sdata->[$indexhash->{'status'}];
            my $section = $sdata->[$indexhash->{'section'}];
            if ($status ne 'Active') {
                delete($classlist->{$student});
                next;
            }
            if ($env{'request.course.sec'} ne '') {
                if ($section ne $env{'request.course.sec'}) {
                    delete($classlist->{$student});
                    next;
                }
            }
            $studentcount ++;
        }
    }
    if (!$studentcount) {
       my $msg = '';
        if ($crstype eq 'Community') {
            $msg = &mt('There are no members to drop.');
        } else {
            $msg = &mt('There are no students to drop.');
        }
        $r->print('<p class="LC_info">'.$msg.'</p>');
        return;
    }
    my ($classgroups) = &Apache::loncoursedata::get_group_memberships(
                                              $classlist,$keylist,$cdom,$cnum);
    my %lt=&Apache::lonlocal::texthash('usrn'   => "username",
                                       'dom'    => "domain",
                                       'id'     => "ID",
                                       'sn'     => "student name",
                                       'mn'     => "member name",
                                       'sec'    => "section",
                                       'start'  => "start date",
                                       'end'    => "end date",
                                       'groups' => "active groups",
                                      );
    my $nametitle = $lt{'sn'};
    if ($crstype eq 'Community') {
        $nametitle = $lt{'mn'};
    }
    if ($nosort) {
        $r->print(&Apache::loncommon::start_data_table().
                  &Apache::loncommon::start_data_table_header_row());
        $r->print(<<END);
    <th>&nbsp;</th>
    <th>$lt{'usrn'}</th>
    <th>$lt{'dom'}</th>
    <th>$lt{'id'}</th>
    <th>$nametitle</th>
    <th>$lt{'sec'}</th>
    <th>$lt{'start'}</th>
    <th>$lt{'end'}</th>
    <th>$lt{'groups'}</th>
END
        $r->print(&Apache::loncommon::end_data_table_header_row());
    } else  {
        $r->print(&Apache::loncommon::start_data_table().
                  &Apache::loncommon::start_data_table_header_row());
        $r->print(<<END);
    <th>&nbsp;</th>
    <th>
       <a href="/adm/createuser?action=$action&amp;sortby=username">$lt{'usrn'}</a>
    </th><th>
       <a href="/adm/createuser?action=$action&amp;sortby=domain">$lt{'dom'}</a>
    </th><th>
       <a href="/adm/createuser?action=$action&amp;sortby=id">$lt{'id'}</a>
    </th><th>
       <a href="/adm/createuser?action=$action&amp;sortby=fullname">$nametitle</a>
    </th><th>
       <a href="/adm/createuser?action=$action&amp;sortby=section">$lt{'sec'}</a>
    </th><th>
       <a href="/adm/createuser?action=$action&amp;sortby=start">$lt{'start'}</a>
    </th><th>
       <a href="/adm/createuser?action=$action&amp;sortby=end">$lt{'end'}</a>
    </th><th>
       <a href="/adm/createuser?action=$action&amp;sortby=groups">$lt{'groups'}</a>
    </th>
END
        $r->print(&Apache::loncommon::end_data_table_header_row());
    }
    #
    # Sort the students
    my $index  = $indexhash->{$sortby};
    my $second = $indexhash->{'username'};
    my $third  = $indexhash->{'domain'};
    my @Sorted_Students = sort {
        lc($classlist->{$a}->[$index])  cmp lc($classlist->{$b}->[$index])
            ||
        lc($classlist->{$a}->[$second]) cmp lc($classlist->{$b}->[$second])
            ||
        lc($classlist->{$a}->[$third]) cmp lc($classlist->{$b}->[$third])
        } (keys(%{$classlist}));
    foreach my $student (@Sorted_Students) {
        my $error;
        my $sdata = $classlist->{$student};
        my $username = $sdata->[$indexhash->{'username'}];
        my $domain   = $sdata->[$indexhash->{'domain'}];
        my $section  = $sdata->[$indexhash->{'section'}];
        my $name     = $sdata->[$indexhash->{'fullname'}];
        my $id       = $sdata->[$indexhash->{'id'}];
        my $start    = $sdata->[$indexhash->{'start'}];
        my $end      = $sdata->[$indexhash->{'end'}];
        my $groups = $classgroups->{$student};
        my $active_groups;
        if (ref($groups->{active}) eq 'HASH') {
            $active_groups = join(', ',keys(%{$groups->{'active'}}));
        }
        if (! defined($start) || $start == 0) {
            $start = &mt('none');
        } else {
            $start = &Apache::lonlocal::locallocaltime($start);
        }
        if (! defined($end) || $end == 0) {
            $end = &mt('none');
        } else {
            $end = &Apache::lonlocal::locallocaltime($end);
        }
        my $studentkey = $student.':'.$section;
        my $startitem = '<input type="hidden" name="'.$studentkey.'_start" value="'.$sdata->[$indexhash->{'start'}].'" />';
        #
        $r->print(&Apache::loncommon::start_data_table_row());
        $r->print(<<"END");
    <td><input type="checkbox" name="droplist" value="$studentkey" /></td>
    <td>$username</td>
    <td>$domain</td>
    <td>$id</td>
    <td>$name</td>
    <td>$section</td>
    <td>$start $startitem</td>
    <td>$end</td>
    <td>$active_groups</td>
END
        $r->print(&Apache::loncommon::end_data_table_row());
    }
    $r->print(&Apache::loncommon::end_data_table().'<br />');
    %lt=&Apache::lonlocal::texthash(
                       'dp'   => "Drop Students",
                       'dm'   => "Drop Members",
                       'ca'   => "check all",
                       'ua'   => "uncheck all",
                                       );
    my $btn = $lt{'dp'};
    if ($crstype eq 'Community') {
        $btn = $lt{'dm'}; 
    }
    $r->print(<<"END");
<p>
<input type="button" value="$lt{'ca'}" onclick="javascript:checkAll(document.studentform.droplist)" /> &nbsp;
<input type="button" value="$lt{'ua'}" onclick="javascript:uncheckAll(document.studentform.droplist)" />
</p>
<p>
<input type="submit" value="$btn" />
</p>
END
    return;
}

#
# Print out the initial form to get the file containing a list of users
#
sub print_first_users_upload_form {
    my ($r,$context) = @_;
    my $str;
    $str  = '<input type="hidden" name="phase" value="two" />';
    $str .= '<input type="hidden" name="action" value="upload" />';
    $str .= '<input type="hidden" name="state"  value="got_file" />';

    $str .= &Apache::grades::checkforfile_js();

    $str .= '<h2>'.&mt('Upload a file containing information about users').'</h2>'."\n";

    # Excel and CSV Help
    $str .= '<div class="LC_columnSection">'
           .&Apache::loncommon::help_open_topic("Course_Create_Class_List",
                &mt("How do I create a users list from a spreadsheet"))
           .' '.&Apache::loncommon::help_open_topic("Course_Convert_To_CSV",
                &mt("How do I create a CSV file from a spreadsheet"))
           ."</div>\n";
    $str .= &Apache::lonhtmlcommon::start_pick_box()
           .&Apache::lonhtmlcommon::row_title(&mt('File'));
    if (&Apache::lonlocal::current_language() ne 'en') {
        if ($context eq 'course') { 
            $str .= '<p class="LC_info">'."\n"
                   .&mt('Please upload an UTF8 encoded file to ensure a correct character encoding in your classlist.')."\n"
                   .'</p>'."\n";
        }
    }
    $str .= &Apache::loncommon::upfile_select_html()
           .&Apache::lonhtmlcommon::row_closure()
           .&Apache::lonhtmlcommon::row_title(
                '<label for="noFirstLine">'
               .&mt('Ignore First Line')
               .'</label>')
           .'<input type="checkbox" name="noFirstLine" id="noFirstLine" />'
           .&Apache::lonhtmlcommon::row_closure(1)
           .&Apache::lonhtmlcommon::end_pick_box();

    $str .= '<p>'
           .'<input type="submit" name="fileupload" value="'.&mt('Next').'"'
           .' onclick="javascript:checkUpload(this.form);" />'
           .'</p>';

    $r->print($str);
    return;
}

# ================================================= Drop/Add from uploaded file
sub upfile_drop_add {
    my ($r,$context,$permission,$showcredits) = @_;
    &Apache::loncommon::load_tmp_file($r);
    my @userdata=&Apache::loncommon::upfile_record_sep();
    if($env{'form.noFirstLine'}){shift(@userdata);}
    my @keyfields = split(/\,/,$env{'form.keyfields'});
    my %fields=();
    for (my $i=0; $i<=$env{'form.nfields'}; $i++) {
        if ($env{'form.upfile_associate'} eq 'reverse') {
            if ($env{'form.f'.$i} ne 'none') {
                $fields{$keyfields[$i]}=$env{'form.f'.$i};
            }
        } else {
            $fields{$env{'form.f'.$i}}=$keyfields[$i];
        }
    }
    if ($env{'form.fullup'} ne 'yes') {
        $r->print('<form name="studentform" method="post" action="/adm/createuser">'."\n".
                  '<input type="hidden" name="action" value="'.$env{'form.action'}.'" />');
    }
    #
    # Store the field choices away
    my @storefields = qw/username names fname mname lname gen id 
                         sec ipwd email role domain inststatus/;
    if ($showcredits) {
        push (@storefields,'credits');
    }
    my %fieldstype; 
    foreach my $field (@storefields) {
        $env{'form.'.$field.'_choice'}=$fields{$field};
        $fieldstype{$field.'_choice'} = 'scalar';
    }
    &Apache::loncommon::store_course_settings('enrollment_upload',\%fieldstype);
    my ($cid,$crstype,$setting);
    if ($context eq 'domain') {
        $setting = $env{'form.roleaction'};
    }
    if ($env{'request.course.id'} ne '') {
        $cid = $env{'request.course.id'};
        $crstype = &Apache::loncommon::course_type();
    } elsif ($setting eq 'course') {
        if (&Apache::lonnet::is_course($env{'form.dcdomain'},$env{'form.dccourse'})) {
            $cid = $env{'form.dcdomain'}.'_'.$env{'form.dccourse'};
            $crstype = &Apache::loncommon::course_type($cid);
        }
    }
    my ($startdate,$enddate) = &get_dates_from_form();
    if ($env{'form.makedatesdefault'}) {
        $r->print(&make_dates_default($startdate,$enddate,$context,$crstype));
    }
    # Determine domain and desired host (home server)
    my $defdom=$env{'request.role.domain'};
    my $domain;
    if ($env{'form.defaultdomain'} ne '') {
        $domain = $env{'form.defaultdomain'};
    } else {
        $domain = $defdom;
    }
    my $desiredhost = $env{'form.lcserver'};
    if (lc($desiredhost) eq 'default') {
        $desiredhost = undef;
    } else {
        my %home_servers = &Apache::lonnet::get_servers($defdom,'library');
        if (! exists($home_servers{$desiredhost})) {
            $r->print('<span class="LC_error">'.&mt('Error').
                      &mt('Invalid home server specified').'</span>');
            $r->print(&Apache::loncommon::end_page());
            return;
        }
    }
    # Determine authentication mechanism
    my $changeauth;
    if ($context eq 'domain') {
        $changeauth = $env{'form.changeauth'};
    }
    my $amode  = '';
    my $genpwd = '';
    if ($env{'form.login'} eq 'krb') {
        $amode='krb';
        $amode.=$env{'form.krbver'};
        $genpwd=$env{'form.krbarg'};
    } elsif ($env{'form.login'} eq 'int') {
        $amode='internal';
        if ((defined($env{'form.intarg'})) && ($env{'form.intarg'})) {
            $genpwd=$env{'form.intarg'};
        }
    } elsif ($env{'form.login'} eq 'loc') {
        $amode='localauth';
        if ((defined($env{'form.locarg'})) && ($env{'form.locarg'})) {
            $genpwd=$env{'form.locarg'};
        }
    }
    if ($amode =~ /^krb/) {
        if (! defined($genpwd) || $genpwd eq '') {
            $r->print('<span class="Error">'.
                      &mt('Unable to enroll users').' '.
                      &mt('No Kerberos domain was specified.').'</span></p>');
            $amode = ''; # This causes the loop below to be skipped
        }
    }
    my ($defaultsec,$defaultrole,$defaultcredits,$commoncredits);
    if ($context eq 'domain') {
        if ($setting eq 'domain') {
            $defaultrole = $env{'form.defaultrole'};
        } elsif ($setting eq 'course') {
            $defaultrole = $env{'form.courserole'};
            $defaultsec = $env{'form.sections'};
            if ($showcredits) {
                $commoncredits = $env{'form.credits'};
                if ($crstype ne 'Community') {
                    my %coursehash=&Apache::lonnet::coursedescription($cid);
                    $defaultcredits = $coursehash{'internal.defaultcredits'};
                }
            }
        }
    } elsif ($context eq 'author') {
        $defaultrole = $env{'form.defaultrole'};
    } elsif ($context eq 'course') {
        $defaultrole = $env{'form.defaultrole'};
        $defaultsec = $env{'form.sections'};
        if ($showcredits) {
            $commoncredits = $env{'form.credits'};
            $defaultcredits = $env{'course.'.$cid.'.internal.defaultcredits'};
        }
    }
    # Check to see if user information can be changed
    my @userinfo = ('firstname','middlename','lastname','generation',
                    'permanentemail','id');
    my %canmodify;
    if (&Apache::lonnet::allowed('mau',$domain)) {
        push(@userinfo,'inststatus');
        foreach my $field (@userinfo) {
            $canmodify{$field} = 1;
        }
    }
    my (%userlist,%modifiable_fields,@poss_roles);
    my $secidx = &Apache::loncoursedata::CL_SECTION();
    my @courseroles = &roles_by_context('course',1,$crstype);
    if (!&Apache::lonnet::allowed('mau',$domain)) {
        if ($context eq 'course' || $context eq 'author') {
            @poss_roles =  &curr_role_permissions($context,'','',$crstype);
            my @statuses = ('active','future');
            my ($indexhash,$keylist) = &make_keylist_array();
            my %info;
            foreach my $role (@poss_roles) {
                %{$modifiable_fields{$role}} = &can_modify_userinfo($context,$domain,
                                                        \@userinfo,[$role]);
            }
            if ($context eq 'course') {
                my ($cnum,$cdom) = &get_course_identity();
                my $roster = &Apache::loncoursedata::get_classlist();
                if (ref($roster) eq 'HASH') {
                    %userlist = %{$roster};
                }
                my %advrolehash = &Apache::lonnet::get_my_roles($cnum,$cdom,undef,
                                                         \@statuses,\@poss_roles);
                &gather_userinfo($context,'view',\%userlist,$indexhash,\%info,
                                \%advrolehash,$permission);
            } elsif ($context eq 'author') {
                my %cstr_roles = &Apache::lonnet::get_my_roles(undef,undef,undef,
                                                  \@statuses,\@poss_roles);
                &gather_userinfo($context,'view',\%userlist,$indexhash,\%info,
                             \%cstr_roles,$permission);

            }
        }
    }
    if ( $domain eq &LONCAPA::clean_domain($domain)
        && ($amode ne '')) {
        #######################################
        ##         Add/Modify Users          ##
        #######################################
        if ($context eq 'course') {
            $r->print('<h3>'.&mt('Enrolling Users')."</h3>\n<p>\n");
        } elsif ($context eq 'author') {
            $r->print('<h3>'.&mt('Updating Co-authors')."</h3>\n<p>\n");
        } else {
            $r->print('<h3>'.&mt('Adding/Modifying Users')."</h3>\n<p>\n");
        }
        $r->rflush;

        my %counts = (
                       user => 0,
                       auth => 0,
                       role => 0,
                     );
        my $flushc=0;
        my %student=();
        my (%curr_groups,@sections,@cleansec,$defaultwarn,$groupwarn);
        my %userchg;
        if ($context eq 'course' || $setting eq 'course') {
            if ($context eq 'course') {
                # Get information about course groups
                %curr_groups = &Apache::longroup::coursegroups();
            } elsif ($setting eq 'course') {
                if ($cid) {
                    %curr_groups =
                        &Apache::longroup::coursegroups($env{'form.dcdomain'},
                                                        $env{'form.dccourse'});
                }
            }
            # determine section number
            if ($defaultsec =~ /,/) {
                push(@sections,split(/,/,$defaultsec));
            } else {
                push(@sections,$defaultsec);
            }
            # remove non alphanumeric values from section
            foreach my $item (@sections) {
                $item =~ s/\W//g;
                if ($item eq "none" || $item eq 'all') {
                    $defaultwarn = &mt('Default section name [_1] could not be used as it is a reserved word.',$item);
                } elsif ($item ne ''  && exists($curr_groups{$item})) {
                    $groupwarn = &mt('Default section name "[_1]" is the name of a course group. Section names and group names must be distinct.',$item);
                } elsif ($item ne '') {
                    push(@cleansec,$item);
                }
            }
            if ($defaultwarn) {
                $r->print($defaultwarn.'<br />');
            }
            if ($groupwarn) {
                $r->print($groupwarn.'<br />');
            }
        }
        my (%curr_rules,%got_rules,%alerts,%cancreate);
        my %customroles = &my_custom_roles($crstype);
        my @permitted_roles = 
            &roles_on_upload($context,$setting,$crstype,%customroles);
        my %longtypes = &Apache::lonlocal::texthash(
                            official   => 'Institutional',
                            unofficial => 'Non-institutional',
                        );
        my $newuserdom = $env{'request.role.domain'};
        map { $cancreate{$_} = &can_create_user($newuserdom,$context,$_); } keys(%longtypes);
        # Get new users list
        my (%existinguser,%userinfo,%disallow,%rulematch,%inst_results,%idinst_results,%alerts,%checkuname);
        my $counter = -1;
        foreach my $line (@userdata) {
            $counter ++;
            my @secs;
            my %entries=&Apache::loncommon::record_sep($line);
            # Determine user name
            $entries{$fields{'username'}} =~ s/^\s+|\s+$//g;
            unless (($entries{$fields{'username'}} eq '') ||
                    (!defined($entries{$fields{'username'}}))) {
                my ($fname, $mname, $lname,$gen) = ('','','','');
                if (defined($fields{'names'})) {
                    ($lname,$fname,$mname)=($entries{$fields{'names'}}=~
                                            /([^\,]+)\,\s*(\w+)\s*(.*)$/);
                } else {
                    if (defined($fields{'fname'})) {
                        $fname=$entries{$fields{'fname'}};
                    }
                    if (defined($fields{'mname'})) {
                        $mname=$entries{$fields{'mname'}};
                    }
                    if (defined($fields{'lname'})) {
                        $lname=$entries{$fields{'lname'}};
                    }
                    if (defined($fields{'gen'})) {
                        $gen=$entries{$fields{'gen'}};
                    }
                }

                if ($entries{$fields{'username'}}
                    ne &LONCAPA::clean_username($entries{$fields{'username'}})) {
                    my $nowhitespace;
                    if ($entries{$fields{'username'}} =~ /\s/) {
                        $nowhitespace = ' - '.&mt('usernames may not contain spaces.');
                    }
                    $disallow{$counter} =
                        &mt('Unacceptable username [_1] for user [_2] [_3] [_4] [_5]',
                            '"<b>'.$entries{$fields{'username'}}.'</b>"',
                            $fname,$mname,$lname,$gen).$nowhitespace;
                    next;
                } else {
                    $entries{$fields{'domain'}} =~ s/^\s+|\s+$//g;
                    if ($entries{$fields{'domain'}} 
                        ne &LONCAPA::clean_domain($entries{$fields{'domain'}})) {
                        $disallow{$counter} =
                            &mt('Unacceptable domain [_1] for user [_2] [_3] [_4] [_5]',
                                '"<b>'.$entries{$fields{'domain'}}.'</b>"',
                                $fname,$mname,$lname,$gen);
                        next;
                    }
                    my $username = $entries{$fields{'username'}};
                    my $userdomain = $entries{$fields{'domain'}};
                    if ($userdomain eq '') {
                        $userdomain = $domain;
                    }
                    if (defined($fields{'sec'})) {
                        if (defined($entries{$fields{'sec'}})) {
                            $entries{$fields{'sec'}} =~ s/\W//g;
                            my $item = $entries{$fields{'sec'}};
                            if ($item eq "none" || $item eq 'all') {
                                $disallow{$counter} =
                                    &mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a reserved word.',
                                        '<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$item);
                                next;
                            } elsif (exists($curr_groups{$item})) {
                                $disallow{$counter} =
                                    &mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]" - this is a course group.',
                                        '<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$item).' '.
                                    &mt('Section names and group names must be distinct.');
                                next;
                            } else {
                                push(@secs,$item);
                            }
                        }
                    }
                    if ($env{'request.course.sec'} ne '') {
                        @secs = ($env{'request.course.sec'});
                        if (ref($userlist{$username.':'.$userdomain}) eq 'ARRAY') {
                            my $currsec = $userlist{$username.':'.$userdomain}[$secidx];
                            if ($currsec ne $env{'request.course.sec'}) {
                                $disallow{$counter} =
                                    &mt('[_1]: Unable to enroll user [_2] [_3] [_4] [_5] in a section named "[_6]".',
                                        '<b>'.$username.'</b>',$fname,$mname,$lname,$gen,$secs[0]);
                                if ($currsec eq '') {
                                    $disallow{$counter} .=
                                        &mt('This user already has an active/future student role in the course, unaffiliated to any section.');

                                } else {
                                    $disallow{$counter} .=
                                        &mt('This user already has an active/future role in section "[_1]" of the course.',$currsec);
                                }
                                $disallow{$counter} .=
                                    '<br />'.
                                    &mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments in other sections.',
                                        $secs[0]);
                                next;
                            }
                        }
                    } elsif ($context eq 'course' || $setting eq 'course') {
                        if (@secs == 0) {
                            @secs = @cleansec;
                        }
                    }
                    # determine id number
                    my $id='';
                    if (defined($fields{'id'})) {
                        if (defined($entries{$fields{'id'}})) {
                            $id=$entries{$fields{'id'}};
                        }
                        $id=~tr/A-Z/a-z/;
                    }
                    # determine email address
                    my $email='';
                    if (defined($fields{'email'})) {
                        $entries{$fields{'email'}} =~ s/^\s+|\s+$//g;
                        if (defined($entries{$fields{'email'}})) {
                            $email=$entries{$fields{'email'}};
                            unless ($email=~/^[^\@]+\@[^\@]+$/) { $email=''; }
                        }
                    }
                    # determine affiliation
                    my $inststatus='';
                    if (defined($fields{'inststatus'})) {
                        if (defined($entries{$fields{'inststatus'}})) {
                            $inststatus=$entries{$fields{'inststatus'}};
                        }
                    }
                    # determine user password
                    my $password = $genpwd;
                    if (defined($fields{'ipwd'})) {
                        if ($entries{$fields{'ipwd'}}) {
                            $password=$entries{$fields{'ipwd'}};
                        }
                    }
                    # determine user role
                    my $role = '';
                    if (defined($fields{'role'})) {
                        if ($entries{$fields{'role'}}) {
                            $entries{$fields{'role'}}  =~ s/(\s+$|^\s+)//g;
                            if ($entries{$fields{'role'}} ne '') {
                                if (grep(/^\Q$entries{$fields{'role'}}\E$/,@permitted_roles)) {
                                    $role = $entries{$fields{'role'}};
                                }
                            }
                            if ($role eq '') {
                                my $rolestr = join(', ',@permitted_roles);
                                $disallow{$counter} =
                                    &mt('[_1]: You do not have permission to add the requested role [_2] for the user.'
                                        ,'<b>'.$entries{$fields{'username'}}.'</b>'
                                        ,$entries{$fields{'role'}})
                                        .'<br />'
                                        .&mt('Allowable role(s) is/are: [_1].',$rolestr);
                                next;
                            }
                        }
                    }
                    if ($role eq '') {
                        $role = $defaultrole;
                    }
                    # Clean up whitespace
                    foreach (\$id,\$fname,\$mname,\$lname,\$gen,\$inststatus) {
                        $$_ =~ s/(\s+$|^\s+)//g;
                    }
                    my $credits;
                    if ($showcredits) {
                        if (($role eq 'st') && ($crstype ne 'Community')) {
                            $credits = $entries{$fields{'credits'}};
                            if ($credits ne '') {
                                $credits =~ s/[^\d\.]//g;
                            }
                            if ($credits eq '') {
                                $credits = $commoncredits;
                            }
                            if ($credits eq $defaultcredits) {
                                undef($credits);
                            }
                        }
                    }
                    # check against rules
                    my $checkid = 0;
                    my $newuser = 0;
                    my $uhome=&Apache::lonnet::homeserver($username,$userdomain);
                    if ($uhome eq 'no_host') {
                        if ($userdomain ne $newuserdom) {
                            if ($context eq 'course') {
                                $disallow{$counter} =
                                    &mt('[_1]: The domain specified ([_2]) is different to that of the course.',
                                       '<b>'.$username.'</b>',$userdomain);
                            } elsif ($context eq 'author') {
                                $disallow{$counter} =
                                    &mt('[_1]: The domain specified ([_2]) is different to that of the author.',
                                        '<b>'.$username.'</b>',$userdomain); 
                            } else {
                                $disallow{$counter} =
                                    &mt('[_1]: The domain specified ([_2]) is different to that of your current role.',
                                        '<b>'.$username.'</b>',$userdomain);
                            }
                            $disallow{$counter} .=
                                &mt('The user does not already exist, and you may not create a new user in a different domain.');
                            next;
                        } else {
                            unless ($password || $env{'form.login'} eq 'loc') {
                                $disallow{$counter} =
                                    &mt('[_1]: This is a new user but no default password was provided, and the authentication type requires one.',
                                        '<b>'.$username.'</b>');
                                next;
                            }
                        }
                        $checkid = 1;
                        $newuser = 1;
                        $checkuname{$username.':'.$newuserdom} = { 'newuser' => 1, 'id' => 1 };
                    } else {
                        if ($context eq 'course' || $context eq 'author') {
                            if ($userdomain eq $domain ) {
                                if ($role eq '') {
                                    my @checkroles;
                                    foreach my $role (@poss_roles) {
                                        my $endkey;
                                        if ($role ne 'st') {
                                            $endkey = ':'.$role;
                                        }
                                        if (exists($userlist{$username.':'.$userdomain.$endkey})) {
                                            if (!grep(/^\Q$role\E$/,@checkroles)) {
                                                push(@checkroles,$role);
                                            }
                                        }
                                    }
                                    if (@checkroles > 0) {
                                        %canmodify = &can_modify_userinfo($context,$domain,\@userinfo,\@checkroles);
                                    }
                                } elsif (ref($modifiable_fields{$role}) eq 'HASH') {
                                    %canmodify = %{$modifiable_fields{$role}};
                                }
                            }
                            my @newinfo = (\$fname,\$mname,\$lname,\$gen,\$email,\$id);
                            for (my $i=0; $i<@newinfo; $i++) {
                                if (${$newinfo[$i]} ne '') {
                                    if (!$canmodify{$userinfo[$i]}) {
                                        ${$newinfo[$i]} = '';
                                    }
                                }
                            }
                        }
                        if ($id) {
                            $existinguser{$userdomain}{$username} = $id;
                        }
                    }
                    $userinfo{$counter} = {
                                          username   => $username,
                                          domain     => $userdomain,
                                          fname      => $fname,
                                          mname      => $mname,
                                          lname      => $lname,
                                          gen        => $gen,
                                          email      => $email,
                                          id         => $id, 
                                          password   => $password,
                                          inststatus => $inststatus,
                                          role       => $role,
                                          sections   => \@secs,
                                          credits    => $credits,
                                          newuser    => $newuser,
                                          checkid    => $checkid,
                                        };
                }
            }
        } # end of foreach (@userdata)
        if ($counter > -1) {
            my $total = $counter + 1;
            my %prog_state = &Apache::lonhtmlcommon::Create_PrgWin($r,$total);
            my %checkids;
            if (keys(%existinguser)) {
                foreach my $dom (keys(%existinguser)) {
                    if (ref($existinguser{$dom}) eq 'HASH') {
                        my %idhash = &Apache::lonnet::idrget($dom,keys(%{$existinguser{$dom}}));
                        foreach my $username (keys(%{$existinguser{$dom}})) {
                            if ($idhash{$username} ne $existinguser{$dom}{$username}) {
                                $checkids{$username.':'.$dom} = { 'id' => $existinguser{$dom}{$username} };
                            }
                        }
                        if (keys(%checkids)) {
                            &Apache::loncommon::user_rule_check(\%checkids,{ 'id' => 1 },
                                                                \%alerts,\%rulematch,
                                                                \%idinst_results,\%curr_rules,
                                                                \%got_rules);
                        }
                    }
                }
            }
            if (keys(%checkuname)) {
                &Apache::loncommon::user_rule_check(\%checkuname,{ 'username' => 1 },
                                                    \%alerts,\%rulematch,\%inst_results,
                                                    \%curr_rules,\%got_rules);
            }
            $r->print('<ul>');
            for (my $i=0; $i<=$counter; $i++) {
                &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state);
                if ($disallow{$i}) {
                    $r->print('<li>'.$disallow{$i}.'</li>');
                } elsif (ref($userinfo{$i}) eq 'HASH') {
                    my $password = $userinfo{$i}{'password'}; 
                    my $newuser = $userinfo{$i}{'newuser'};
                    my $checkid = $userinfo{$i}{'checkid'};
                    my $id = $userinfo{$i}{'id'};
                    my $role = $userinfo{$i}{'role'};
                    my @secs;
                    if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') {
                        @secs = @{$userinfo{$i}{'sections'}};
                    }
                    my $fname = $userinfo{$i}{'fname'};
                    my $mname = $userinfo{$i}{'mname'}; 
                    my $lname = $userinfo{$i}{'lname'};
                    my $gen = $userinfo{$i}{'gen'};
                    my $email = $userinfo{$i}{'email'};
                    my $inststatus = $userinfo{$i}{'inststatus'};
                    my $credits = $userinfo{$i}{'credits'};
                    my $username = $userinfo{$i}{'username'};
                    my $userdomain = $userinfo{$i}{'domain'};
                    my $user = $username.':'.$userdomain;
                    if ($newuser) {
                        if (ref($alerts{'username'}) eq 'HASH') {
                            if (ref($alerts{'username'}{$userdomain}) eq 'HASH') {
                                if ($alerts{'username'}{$userdomain}{$username}) {
                                    $r->print('<li>'.
                                              &mt('[_1]: matches the username format at your institution, but is not known to your directory service.','<b>'.$username.'</b>').'<br />'.
                                              &mt('Consequently, the user was not created.').'</li>');
                                    next;
                                }
                            }
                        }
                        my $usertype = 'unofficial';
                        if (ref($rulematch{$user}) eq 'HASH') {
                            if ($rulematch{$user}{'username'}) {
                                $usertype = 'official';
                            }
                        }
                        unless ($cancreate{$usertype}) {
                            my $showtype = $longtypes{$usertype};
                            $r->print('<li>'.
                                      &mt('[_1]: The user does not exist, and you are not permitted to create users of type: [_2].','<b>'.$username.'</b>',$showtype).'</li>');
                            next;
                        }
                    }
                    if ($id ne '') {
                        if (exists($checkids{$user})) {
                            $checkid = 1; 
                            if (ref($alerts{'id'}) eq 'HASH') {
                                if (ref($alerts{'id'}{$userdomain}) eq 'HASH') {
                                    if ($alerts{'id'}{$userdomain}{$id}) {
                                        $r->print('<li>'.
                                                  &mt('[_1]: has a student/employee ID matching the format at your institution, but the ID is found by your directory service.',
                                                  '<b>'.$username.'</b>').'<br />'.
                                                  &mt('Consequently, the user was not created.').'</li>');
                                        next;
                                    }
                                }
                            }
                        }
                    }
                    my $multiple = 0;
                    my ($userresult,$authresult,$roleresult,$idresult);
                    my (%userres,%authres,%roleres,%idres);
                    my $singlesec = '';
                    if ($role eq 'st') {
                        my $sec;
                        if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') {
                            if (@secs > 0) {
                                $sec = $secs[0];
                            }
                        }
                        &modifystudent($userdomain,$username,$cid,$sec,
                                       $desiredhost,$context);
                        $roleresult =
                            &Apache::lonnet::modifystudent
                                ($userdomain,$username,$id,$amode,$password,
                                 $fname,$mname,$lname,$gen,$sec,$enddate,
                                 $startdate,$env{'form.forceid'},
                                 $desiredhost,$email,'manual','',$cid,
                                 '',$context,$inststatus,$credits);
                        $userresult = $roleresult;
                    } else {
                        if ($role ne '') { 
                            if ($context eq 'course' || $setting eq 'course') {
                                if ($customroles{$role}) {
                                    $role = 'cr_'.$env{'user.domain'}.'_'.
                                            $env{'user.name'}.'_'.$role;
                                }
                                if (($role ne 'cc') && ($role ne 'co')) { 
                                   if (@secs > 1) {
                                        $multiple = 1;
                                        foreach my $sec (@secs) {
                                            ($userres{$sec},$authres{$sec},$roleres{$sec},$idres{$sec}) =
                                            &modifyuserrole($context,$setting,
                                                $changeauth,$cid,$userdomain,$username,
                                                $id,$amode,$password,$fname,
                                                $mname,$lname,$gen,$sec,
                                                $env{'form.forceid'},$desiredhost,
                                                $email,$role,$enddate,
                                                $startdate,$checkid,$inststatus);
                                        }
                                    } elsif (@secs > 0) {
                                        $singlesec = $secs[0];
                                    }
                                }
                            }
                            if (!$multiple) {
                                ($userresult,$authresult,$roleresult,$idresult) = 
                                    &modifyuserrole($context,$setting,
                                                    $changeauth,$cid,$userdomain,$username, 
                                                    $id,$amode,$password,$fname,
                                                    $mname,$lname,$gen,$singlesec,
                                                    $env{'form.forceid'},$desiredhost,
                                                    $email,$role,$enddate,$startdate,
                                                    $checkid,$inststatus);
                            }
                        }
                    }
                    if ($multiple) {
                        foreach my $sec (sort(keys(%userres))) {
                            $flushc =
                                &user_change_result($r,$userres{$sec},$authres{$sec},
                                                    $roleres{$sec},$idres{$sec},\%counts,$flushc,
                                                    $username,$userdomain,\%userchg);

                        }
                    } else {
                        $flushc = 
                            &user_change_result($r,$userresult,$authresult,
                                                $roleresult,$idresult,\%counts,$flushc,
                                                $username,$userdomain,\%userchg);
                    }
                }
                $r->print('</ul>');
            } # end of loop
            &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
        }
        # Flush the course logs so reverse user roles immediately updated
        $r->register_cleanup(\&Apache::lonnet::flushcourselogs);
        $r->print("</p>\n<p>\n".&mt('Processed [quant,_1,user].',$counts{'user'}).
                  "</p>\n");
        if ($counts{'role'} > 0) {
            $r->print("<p>\n".
                      &mt('Roles added for [quant,_1,user].',$counts{'role'}).' '.&mt('If a user is currently logged-in to LON-CAPA, any new roles which are active will be available when the user next logs in.')."</p>\n");
        } else {
            $r->print('<p>'.&mt('No roles added').'</p>');
        }
        if ($counts{'auth'} > 0) {
            $r->print("<p>\n".
                      &mt('Authentication changed for [_1] existing users.',
                          $counts{'auth'})."</p>\n");
        }
        $r->print(&print_namespacing_alerts($domain,\%alerts,\%curr_rules));
        #####################################
        # Display list of students to drop  #
        #####################################
        if ($env{'form.fullup'} eq 'yes') {
            $r->print('<h3>'.&mt('Students to Drop')."</h3>\n");
            #  Get current classlist
            my $classlist = &Apache::loncoursedata::get_classlist();
            if (! defined($classlist)) {
                $r->print('<form name="studentform" method="post" action="/adm/createuser">'.
                          '<input type="hidden" name="action" value="'.$env{'form.action'}.'" />'.
                          '<p class="LC_info">'.&mt('There are no students with current/future access to the course.').'</p>'.
                          '</form>'."\n");
            } elsif (ref($classlist) eq 'HASH') {
                # Remove the students we just added from the list of students.
                foreach my $line (@userdata) {
                    my %entries=&Apache::loncommon::record_sep($line);
                    unless (($entries{$fields{'username'}} eq '') ||
                            (!defined($entries{$fields{'username'}}))) {
                        delete($classlist->{$entries{$fields{'username'}}.
                                                ':'.$domain});
                    }
                }
                # Print out list of dropped students.
                &show_drop_list($r,$classlist,'nosort',$permission);
            }
        }
    } # end of unless
    if ($env{'form.fullup'} ne 'yes') {
        $r->print('</form>');
    }
}

sub print_namespacing_alerts {
    my ($domain,$alerts,$curr_rules) = @_;
    my $output;
    if (ref($alerts) eq 'HASH') {
        if (keys(%{$alerts}) > 0) {
            if (ref($alerts->{'username'}) eq 'HASH') {
                foreach my $dom (sort(keys(%{$alerts->{'username'}}))) {
                    my $count;
                    if (ref($alerts->{'username'}{$dom}) eq 'HASH') {
                        $count = keys(%{$alerts->{'username'}{$dom}});
                    }
                    my $domdesc = &Apache::lonnet::domain($domain,'description');
                    if (ref($curr_rules->{$dom}) eq 'HASH') {
                        $output .= &Apache::loncommon::instrule_disallow_msg(
                                        'username',$domdesc,$count,'upload');
                    }
                    $output .= &Apache::loncommon::user_rule_formats($dom,
                                   $domdesc,$curr_rules->{$dom}{'username'},
                                   'username');
                }
            }
            if (ref($alerts->{'id'}) eq 'HASH') {
                foreach my $dom (sort(keys(%{$alerts->{'id'}}))) {
                    my $count;
                    if (ref($alerts->{'id'}{$dom}) eq 'HASH') {
                        $count = keys(%{$alerts->{'id'}{$dom}});
                    }
                    my $domdesc = &Apache::lonnet::domain($domain,'description');
                    if (ref($curr_rules->{$dom}) eq 'HASH') {
                        $output .= &Apache::loncommon::instrule_disallow_msg(
                                              'id',$domdesc,$count,'upload');
                    }
                    $output .= &Apache::loncommon::user_rule_formats($dom,
                                    $domdesc,$curr_rules->{$dom}{'id'},'id');
                }
            }
        }
    }
}

sub user_change_result {
    my ($r,$userresult,$authresult,$roleresult,$idresult,$counts,$flushc,
        $username,$userdomain,$userchg) = @_;
    my $okresult = 0;
    my @status;
    if ($userresult ne 'ok') {
        if ($userresult =~ /^error:(.+)$/) {
            my $error = $1;
            push(@status,
                 &mt('[_1]: Unable to add/modify: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error));
        }
    } else {
        $counts->{'user'} ++;
        $okresult = 1;
    }
    if ($authresult ne 'ok') {
        if ($authresult =~ /^error:(.+)$/) {
            my $error = $1;
            push(@status, 
                 &mt('[_1]: Unable to modify authentication: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error));
        } 
    } else {
        $counts->{'auth'} ++;
        $okresult = 1;
    }
    if ($roleresult ne 'ok') {
        if ($roleresult =~ /^error:(.+)$/) {
            my $error = $1;
            push(@status,
                 &mt('[_1]: Unable to add role: [_2]','<b>'.$username.':'.$userdomain.'</b>',$error));
        }
    } else {
        $counts->{'role'} ++;
        $okresult = 1;
    }
    if ($okresult) {
        $flushc++;
        $userchg->{$username.':'.$userdomain}=1;
        if ($flushc>15) {
            $r->rflush;
            $flushc=0;
        }
    }
    if ($idresult) {
        push(@status,$idresult);
    }
    if (@status) {
        $r->print('<li>'.join('<br />',@status).'</li>');
    }
    return $flushc;
}

# ========================================================= Menu Phase Two Drop
sub print_drop_menu {
    my ($r,$context,$permission,$crstype) = @_;
    my $heading;
    if ($crstype eq 'Community') {
        $heading = &mt("Drop Members");
    } else {
        $heading = &mt("Drop Students");
    }
    $r->print('<h3>'.$heading.'</h3>'."\n".
              '<form name="studentform" method="post" action="">'."\n");
    my $classlist = &Apache::loncoursedata::get_classlist();
    if (! defined($classlist)) {
        my $msg = '';
        if ($crstype eq 'Community') {
            $msg = &mt('There are no members currently enrolled.');
        } else {
            $msg = &mt('There are no students currently enrolled.');
        }
        $r->print('<p class="LC_info">'.$msg."</p>\n");
    } else {
        &show_drop_list($r,$classlist,'nosort',$permission,$crstype);
    }
    $r->print('</form>');
    return;
}

# ================================================================== Phase four

sub update_user_list {
    my ($r,$context,$setting,$choice,$crstype) = @_;
    my $now = time;
    my $count=0;
    if ($context eq 'course') {
        $crstype = &Apache::loncommon::course_type();
    }
    my @changelist;
    if ($choice eq 'drop') {
        @changelist = &Apache::loncommon::get_env_multiple('form.droplist');
    } else {
        @changelist = &Apache::loncommon::get_env_multiple('form.actionlist');
    }
    my %result_text = ( ok    => { 'revoke'   => 'Revoked',
                                   'delete'   => 'Deleted',
                                   'reenable' => 'Re-enabled',
                                   'activate' => 'Activated',
                                   'chgdates' => 'Changed Access Dates for',
                                   'chgsec'   => 'Changed section(s) for',
                                   'drop'     => 'Dropped',
                                 },
                        error => {'revoke'    => 'revoking',
                                  'delete'    => 'deleting',
                                  'reenable'  => 're-enabling',
                                  'activate'  => 'activating',
                                  'chgdates'  => 'changing access dates for',
                                  'chgsec'    => 'changing section for',
                                  'drop'      => 'dropping',
                                 },
                      );
    my ($startdate,$enddate);
    if ($choice eq 'chgdates' || $choice eq 'reenable' || $choice eq 'activate') {
        ($startdate,$enddate) = &get_dates_from_form();
    }
    foreach my $item (@changelist) {
        my ($role,$uname,$udom,$cid,$sec,$scope,$result,$type,$locktype,
            @sections,$scopestem,$singlesec,$showsecs,$warn_singlesec,
            $nothingtodo,$keepnosection,$credits);
        if ($choice eq 'drop') {
            ($uname,$udom,$sec) = split(/:/,$item,-1);
            $role = 'st';
            $cid = $env{'request.course.id'};
            $scopestem = '/'.$cid;
            $scopestem =~s/\_/\//g;
            if ($sec eq '') {
                $scope = $scopestem;
            } else {
                $scope = $scopestem.'/'.$sec;
            }
        } elsif ($context eq 'course') {
            ($uname,$udom,$role,$sec,$type,$locktype,$credits) =
                split(/\:/,$item);
            $cid = $env{'request.course.id'};
            $scopestem = '/'.$cid;
            $scopestem =~s/\_/\//g;
            if ($sec eq '') {
                $scope = $scopestem;
            } else {
                $scope = $scopestem.'/'.$sec;
            }
        } elsif ($context eq 'author') {
            ($uname,$udom,$role) = split(/\:/,$item,-1);
            $scope = '/'.$env{'user.domain'}.'/'.$env{'user.name'};
        } elsif ($context eq 'domain') {
            if ($setting eq 'domain') {
                ($role,$uname,$udom) = split(/\:/,$item,-1);
                $scope = '/'.$env{'request.role.domain'}.'/';
            } elsif ($setting eq 'author') { 
                ($uname,$udom,$role,$scope) = split(/\:/,$item);
            } elsif ($setting eq 'course') {
                ($uname,$udom,$role,$cid,$sec,$type,$locktype,$credits) = 
                    split(/\:/,$item);
                $scope = '/'.$cid;
                $scope =~s/\_/\//g;
                if ($sec ne '') {
                    $scope .= '/'.$sec;
                }
            }
        }
        my $plrole = &Apache::lonnet::plaintext($role,$crstype);
        my $start = $env{'form.'.$item.'_start'};
        my $end = $env{'form.'.$item.'_end'};
        if ($choice eq 'drop') {
            # drop students
            $end = $now;
            $type = 'manual';
            $result =
                &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context);
        } elsif ($choice eq 'revoke') {
            # revoke or delete user role
            $end = $now; 
            if ($role eq 'st') {
                $result = 
                    &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits);
            } else {
                $result = 
                    &Apache::lonnet::revokerole($udom,$uname,$scope,$role,
                                                '','',$context);
            }
        } elsif ($choice eq 'delete') {
            if ($role eq 'st') {
                &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$now,$start,$type,$locktype,$cid,'',$context,$credits);
            }
            $result =
                &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$now,
                                            $start,1,'',$context);
        } else {
            #reenable, activate, change access dates or change section
            if ($choice ne 'chgsec') {
                $start = $startdate; 
                $end = $enddate;
            }
            if ($choice eq 'reenable') {
                if ($role eq 'st') {
                    $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits);
                } else {
                    $result = 
                        &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
                                                    $now,'','',$context);
                }
            } elsif ($choice eq 'activate') {
                if ($role eq 'st') {
                    $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits);
                } else {
                    $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
                                            $now,'','',$context);
                }
            } elsif ($choice eq 'chgdates') {
                if ($role eq 'st') {
                    $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits);
                } else {
                    $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
                                                $start,'','',$context);
                }
            } elsif ($choice eq 'chgsec') {
                my (@newsecs,$revresult,$nochg,@retained);
                if (($role ne 'cc') && ($role ne 'co')) {
                    my @secs = sort(split(/,/,$env{'form.newsecs'}));
                    if (@secs) {
                        my %curr_groups = &Apache::longroup::coursegroups();
                        foreach my $sec (@secs) {
                            next if (($sec =~ /\W/) || ($sec eq 'none') ||
                            (exists($curr_groups{$sec})));
                            push(@newsecs,$sec);
                        }
                    }
                }
                # remove existing section if not to be retained.   
                if (!$env{'form.retainsec'} || ($role eq 'st')) {
                    if ($sec eq '') {
                        if (@newsecs == 0) {
                            $result = 'ok';
                            $nochg = 1;
                            $nothingtodo = 1;
                        } else {
                            $revresult =
                                &Apache::lonnet::revokerole($udom,$uname,
                                                            $scope,$role,
                                                            '','',$context);
                        } 
                    } else {
                        if (@newsecs > 0) {
                            if (grep(/^\Q$sec\E$/,@newsecs)) {
                                push(@retained,$sec);
                            } else {
                                $revresult =
                                    &Apache::lonnet::revokerole($udom,$uname,
                                                                $scope,$role,
                                                                '','',$context);
                            }
                        } else {
                            $revresult =
                                &Apache::lonnet::revokerole($udom,$uname,
                                                            $scope,$role,
                                                            '','',$context);
                        }
                    }
                } else {
                    if ($sec eq '') {
                        $nochg = 1;
                        $keepnosection = 1;
                    } else {
                        push(@retained,$sec);
                    }
                }
                # add new sections
                my (@diffs,@shownew);
                if (@retained) {
                    @diffs = &Apache::loncommon::compare_arrays(\@retained,\@newsecs);
                } else {
                    @diffs = @newsecs;
                }
                if (@newsecs == 0) {
                    if ($nochg) {
                        $result = 'ok';
                        $nothingtodo = 1;
                    } else {
                        if ($role eq 'st') {
                            $result = 
                                &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,undef,$end,$start,$type,$locktype,$cid,'',$context,$credits);
                        } else {
                            my $newscope = $scopestem;
                            $result = &Apache::lonnet::assignrole($udom,$uname,$newscope,$role,$end,$start,'','',$context);
                        }
                    }
                    $showsecs = &mt('No section');
                } elsif (@diffs == 0) {
                    $result = 'ok';
                    $nothingtodo = 1;
                } else {
                    foreach my $newsec (@newsecs) {
                        if (!grep(/^\Q$newsec\E$/,@retained)) {
                            if ($role eq 'st') {
                                $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$newsec,$end,$start,$type,$locktype,$cid,'',$context,$credits);
                                if (@newsecs > 1) {
                                    my $showsingle; 
                                    if ($newsec eq '') {
                                        $showsingle = &mt('No section');
                                    } else {
                                        $showsingle = $newsec;
                                    }
                                    if ($crstype eq 'Community') {
                                        $warn_singlesec = &mt('Although more than one section was indicated, a role was only added for the first section - [_1], as each community member may only be in one section at a time.','<i>'.$showsingle.'</i>');
                                    } else { 
                                        $warn_singlesec = &mt('Although more than one section was indicated, a role was only added for the first section - [_1], as each student may only be in one section of a course at a time.','<i>'.$showsingle.'</i>');
                                    }
                                    $showsecs = $showsingle; 
                                    last;
                                } else {
                                    if ($newsec eq '') {
                                        $showsecs = &mt('No section');
                                    } else {
                                        $showsecs = $newsec;
                                    }
                                }
                            } else {
                                my $newscope = $scopestem;
                                if ($newsec ne '') {
                                   $newscope .= '/'.$newsec;
                                   push(@shownew,$newsec); 
                                }
                                $result = &Apache::lonnet::assignrole($udom,$uname,
                                                        $newscope,$role,$end,$start);
                                
                            }
                        }
                    }
                }
                unless ($role eq 'st') {
                    unless ($showsecs) {
                        my @tolist = sort(@shownew,@retained);
                        if ($keepnosection) {
                            push(@tolist,&mt('No section'));
                        }
                        $showsecs = join(', ',@tolist);
                    }
                }
            }
        }
        my $extent = $scope;
        if ($choice eq 'drop' || $context eq 'course') {
            my ($cnum,$cdom,$cdesc) = &get_course_identity($cid);
            if ($cdesc) {
                $extent = $cdesc;
            }
        }
        if ($result eq 'ok' || $result eq 'ok:') {
            my $dates;
            if (($choice eq 'chgsec') || ($choice eq 'chgdates')) {
                $dates = &dates_feedback($start,$end,$now);
            }
            if ($choice eq 'chgsec') {
                if ($nothingtodo) {
                    $r->print(&mt("Section assignment for role of '[_1]' in [_2] for '[_3]' unchanged.",$plrole,$extent,'<i>'.
                          &Apache::loncommon::plainname($uname,$udom).
                          '</i>').' ');
                    if ($sec eq '') {
                        $r->print(&mt('[_1]No section[_2] - [_3]','<b>','</b>',$dates));
                    } else {
                        $r->print(&mt('Section(s): [_1] - [_2]',
                                      '<b>'.$showsecs.'</b>',$dates));
                    }
                    $r->print('<br />');
                } else {
                    $r->print(&mt("$result_text{'ok'}{$choice} role of '[_1]' in [_2] for '[_3]' to [_4] - [_5]",$plrole,$extent,
                        '<i>'.&Apache::loncommon::plainname($uname,$udom).'</i>',
                        '<b>'.$showsecs.'</b>',$dates).'<br />');
                   $count ++;
               }
               if ($warn_singlesec) {
                   $r->print('<div class="LC_warning">'.$warn_singlesec.'</div>');
               }
            } elsif ($choice eq 'chgdates') {
                $r->print(&mt("$result_text{'ok'}{$choice} role of '[_1]' in [_2] for '[_3]' - [_4]",$plrole,$extent, 
                      '<i>'.&Apache::loncommon::plainname($uname,$udom).'</i>',
                      $dates).'<br />');
               $count ++;
            } else {
                $r->print(&mt("$result_text{'ok'}{$choice} role of '[_1]' in [_2] for '[_3]'.",$plrole,$extent,
                      '<i>'.&Apache::loncommon::plainname($uname,$udom).'</i>').
                          '<br />');
                $count ++;
            }
        } else {
            $r->print(
                &mt("Error $result_text{'error'}{$choice} [_1] in [_2] for '[_3]': [_4].",
                    $plrole,$extent,
                    '<i>'.&Apache::loncommon::plainname($uname,$udom).'</i>',
                    $result).'<br />');
        }
    }
    $r->print('<form name="studentform" method="post" action="/adm/createuser">'."\n");
    if ($choice eq 'drop') {
        $r->print('<input type="hidden" name="action" value="listusers" />'."\n".
                  '<input type="hidden" name="Status" value="Active" />'."\n".
                  '<input type="hidden" name="showrole" value="st" />'."\n");
    } else {
        foreach my $item ('action','sortby','roletype','showrole','Status','secfilter','grpfilter') {
            if ($env{'form.'.$item} ne '') {
                $r->print('<input type="hidden" name="'.$item.'" value="'.$env{'form.'.$item}.
                          '" />'."\n");
            }
        }
    }
    $r->print('<p><b>'.&mt("$result_text{'ok'}{$choice} [quant,_1,user role,user roles,no user roles].",$count).'</b></p>');
    if ($count > 0) {
        if ($choice eq 'revoke' || $choice eq 'drop') {
            $r->print('<p>'.&mt('Re-enabling will re-activate data for the role.').'</p>');
        }
        # Flush the course logs so reverse user roles immediately updated
        $r->register_cleanup(\&Apache::lonnet::flushcourselogs);
    }
    if ($env{'form.makedatesdefault'}) {
        if ($choice eq 'chgdates' || $choice eq 'reenable' || $choice eq 'activate') {
            $r->print(&make_dates_default($startdate,$enddate,$context,$crstype));
        }
    }
    my $linktext = &mt('Display User Lists');
    if ($choice eq 'drop') {
        $linktext = &mt('Display current class roster');
    }
    $r->print(
        &Apache::lonhtmlcommon::actionbox(
            ['<a href="javascript:document.studentform.submit()">'.$linktext.'</a>'])
       .'</form>'."\n");
}

sub dates_feedback {
    my ($start,$end,$now) = @_;
    my $dates;
    if ($start < $now) {
        if ($end == 0) {
            $dates = &mt('role(s) active now; no end date');
        } elsif ($end > $now) {
            $dates = &mt('role(s) active now; ends [_1].',&Apache::lonlocal::locallocaltime($end));
        } else {
            $dates = &mt('role(s) expired: [_1].',&Apache::lonlocal::locallocaltime($end));
        }
     } else {
        if ($end == 0 || $end > $now) {
            $dates = &mt('future role(s); starts: [_1].',&Apache::lonlocal::locallocaltime($start));
        } else {
            $dates = &mt('role(s) expired: [_1].',&Apache::lonlocal::locallocaltime($end));
        }
    }
    return $dates;
}

sub classlist_drop {
    my ($scope,$uname,$udom,$now) = @_;
    my ($cdom,$cnum) = ($scope=~m{^/($match_domain)/($match_courseid)});
    if (&Apache::lonnet::is_course($cdom,$cnum)) {
        if (!&active_student_roles($cnum,$cdom,$uname,$udom)) {
            my %user;
            my $result = &update_classlist($cdom,$cnum,$udom,$uname,\%user,$now);
            return &mt('Drop from classlist: [_1]',
                       '<b>'.$result.'</b>').'<br />';
        }
    }
}

sub active_student_roles {
    my ($cnum,$cdom,$uname,$udom) = @_;
    my %roles =
        &Apache::lonnet::get_my_roles($uname,$udom,'userroles',
                                      ['future','active'],['st']);
    return exists($roles{"$cnum:$cdom:st"});
}

sub section_check_js {
    my $groupslist= &get_groupslist();
    my %js_lt = &Apache::lonlocal::texthash(
        mayn   => 'may not be used as the name for a section, as it is a reserved word.',
        plch   => 'Please choose a different section name.',
        mnot   => 'may not be used as a section name, as it is the name of a course group.',
        secn   => 'Section names and group names must be distinct. Please choose a different section name.',
    );
    &js_escape(\%js_lt);
    return <<"END";
function validate(caller) {
    var groups = new Array($groupslist);
    var secname = caller.value;
    if ((secname == 'all') || (secname == 'none')) {
        alert("'"+secname+"' $js_lt{'mayn'}\\n$js_lt{'plch'}");
        return 'error';
    }
    if (secname != '') {
        for (var k=0; k<groups.length; k++) {
            if (secname == groups[k]) {
                alert("'"+secname+"' $js_lt{'mnot'}\\n$js_lt{'secn'}");
                return 'error';
            }
        }
    }
    return 'ok';
}
END
}

sub set_login {
    my ($dom,$authformkrb,$authformint,$authformloc) = @_;
    my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
    my $response;
    my ($authnum,%can_assign) =
        &Apache::loncommon::get_assignable_auth($dom);
    if ($authnum) {
        $response = &Apache::loncommon::start_data_table();
        if (($can_assign{'krb4'}) || ($can_assign{'krb5'})) {
            $response .= &Apache::loncommon::start_data_table_row().
                         '<td>'.$authformkrb.'</td>'.
                         &Apache::loncommon::end_data_table_row()."\n";
        }
        if ($can_assign{'int'}) {
            $response .= &Apache::loncommon::start_data_table_row().
                         '<td>'.$authformint.'</td>'.
                         &Apache::loncommon::end_data_table_row()."\n"
        }
        if ($can_assign{'loc'}) {
            $response .= &Apache::loncommon::start_data_table_row().
                         '<td>'.$authformloc.'</td>'.
                         &Apache::loncommon::end_data_table_row()."\n";
        }
        $response .= &Apache::loncommon::end_data_table();
    }
    return $response;
}

sub course_sections {
    my ($sections_count,$role,$current_sec) = @_;
    my $output = '';
    my @sections = (sort {$a <=> $b} keys(%{$sections_count}));
    my $numsec = scalar(@sections);
    my $is_selected = ' selected="selected"';
    if ($numsec <= 1) {
        $output = '<select name="currsec_'.$role.'" >'."\n".
                  '  <option value="">'.&mt('Select').'</option>'."\n";
        if ($current_sec eq 'none') {
            $output .=       
                  '  <option value=""'.$is_selected.'>'.&mt('No section').'</option>'."\n";
        } else {
            $output .=
                  '  <option value="">'.&mt('No section').'</option>'."\n";
        }
        if ($numsec == 1) {
            if ($current_sec eq $sections[0]) {
                $output .=
                  '  <option value="'.$sections[0].'"'.$is_selected.'>'.$sections[0].'</option>'."\n";
            } else {
                $output .=  
                  '  <option value="'.$sections[0].'" >'.$sections[0].'</option>'."\n";
            }
        }
    } else {
        $output = '<select name="currsec_'.$role.'" ';
        my $multiple = 4;
        if (scalar(@sections) < 4) { $multiple = scalar(@sections); }
        if ($role eq 'st') {
            $output .= '>'."\n".
                       '  <option value="">'.&mt('Select').'</option>'."\n";
            if ($current_sec eq 'none') {
                $output .= 
                       '  <option value=""'.$is_selected.'>'.&mt('No section')."</option>\n";
            } else {
                $output .=
                       '  <option value="">'.&mt('No section')."</option>\n";
            }
        } else {
            $output .= 'multiple="multiple" size="'.$multiple.'">'."\n";
        }
        foreach my $sec (@sections) {
            if ($current_sec eq $sec) {
                $output .= '<option value="'.$sec.'"'.$is_selected.'>'.$sec."</option>\n";
            } else {
                $output .= '<option value="'.$sec.'">'.$sec."</option>\n";
            }
        }
    }
    $output .= '</select>';
    return $output;
}

sub get_groupslist {
    my $groupslist;
    my %curr_groups = &Apache::longroup::coursegroups();
    if (%curr_groups) {
        $groupslist = join('","',sort(keys(%curr_groups)));
        $groupslist = '"'.$groupslist.'"';
    }
    return $groupslist; 
}

sub setsections_javascript {
    my ($formname,$groupslist,$mode,$checkauth,$crstype,$showcredits) = @_;
    my ($checkincluded,$finish,$rolecode,$setsection_js);
    if ($mode eq 'upload') {
        $checkincluded = 'formname.name == "'.$formname.'"';
        $finish = "return 'ok';";
        $rolecode = "var role = formname.defaultrole.options[formname.defaultrole.selectedIndex].value;\n";
    } elsif ($formname eq 'cu') {
        if (($crstype eq 'Course') && ($showcredits)) {
            $checkincluded = "((role == 'st') && (formname.elements[i-2].checked == true)) || ((role != 'st') && (formname.elements[i-1].checked == true))";
        } else {
            $checkincluded = 'formname.elements[i-1].checked == true';
        }
        if ($checkauth) {
            $finish = "var authcheck = auth_check();\n".
                      "   if (authcheck == 'ok') {\n".
                      "       formname.submit();\n".
                      "   }\n";
        } else {
            $finish = 'formname.submit()';
        }
        $rolecode = "var match = str.split('_');
                var role = match[3];\n";
    } elsif (($formname eq 'enrollstudent') || ($formname eq 'selfenroll')) {
        $checkincluded = 'formname.name == "'.$formname.'"';
        if ($checkauth) {
            $finish = "var authcheck = auth_check();\n".
                      "   if (authcheck == 'ok') {\n".
                      "       formname.submit();\n".
                      "   }\n";
        } else {
            $finish = 'formname.submit()';
        }
        $rolecode = "var match = str.split('_');
                var role = match[1];\n";
    } else {
        $checkincluded = 'formname.name == "'.$formname.'"'; 
        $finish = "seccheck = 'ok';";
        $rolecode = "var match = str.split('_');
                var role = match[1];\n";
        $setsection_js = "var seccheck = 'alert';"; 
    }
    my %alerts = &Apache::lonlocal::texthash(
                    secd => 'Section designations do not apply to Course Coordinator roles.',
                    sedn => 'Section designations do not apply to Coordinator roles.',
                    accr => 'A course coordinator role will be added with access to all sections.',
                    acor => 'A coordinator role will be added with access to all sections',
                    inea => 'In each course, each user may only have one student role at a time.',
                    inco => 'In each community, each user may only have one member role at a time.',
                    youh => 'You had selected',
                    secs => 'sections.',
                    plmo => 'Please modify your selections so they include no more than one section.',
                    mayn => 'may not be used as the name for a section, as it is a reserved word.',
                    plch => 'Please choose a different section name.',
                    mnot => 'may not be used as a section name, as it is the name of a course group.',
                    secn => 'Section names and group names must be distinct. Please choose a different section name.',
                    nonw => 'Section names may only contain letters or numbers.',
                 );
    &js_escape(\%alerts);
    $setsection_js .= <<"ENDSECCODE";

function setSections(formname,crstype) {
    var re1 = /^currsec_/;
    var re2 =/\\W/;
    var trimleading = /^\\s+/;
    var trimtrailing = /\\s+\$/;
    var groups = new Array($groupslist);
    for (var i=0;i<formname.elements.length;i++) {
        var str = formname.elements[i].name;
        if (typeof(str) === "undefined") {
            continue;
        }
        var checkcurr = str.match(re1);
        if (checkcurr != null) {
            var num = i;
            $rolecode
            if ($checkincluded) {
                if (role == 'cc' || role == 'co') {
                    if (role == 'cc') {
                        alert("$alerts{'secd'}\\n$alerts{'accr'}");
                    } else {
                        alert("$alerts{'sedn'}\\n$alerts{'acor'}");
                    }
                } else {
                    var sections = '';
                    var numsec = 0;
                    var fromexisting = new Array();
                    for (var j=0; j<formname.elements[num].length; j++) {
                        if (formname.elements[num].options[j].selected == true ) {
                            var addsec = formname.elements[num].options[j].value;
                            if ((addsec != "") && (addsec != null)) {
                                fromexisting.push(addsec);
                                if (numsec == 0) {
                                    sections = addsec;
                                } else {
                                    sections = sections + "," +  addsec;
                                }
                                numsec ++;
                            }
                        }
                    }
                    var newsecs = formname.elements[num+1].value;
                    var validsecs = new Array();
                    var validsecstr = '';
                    var badsecs = new Array();
                    if (newsecs != null && newsecs != "") {
                        var numsplit;
                        if (newsecs.indexOf(',') == -1) {
                            numsplit = new Array(newsecs);
                        } else {
                            numsplit = newsecs.split(/,/g);
                        }
                        for (var m=0; m<numsplit.length; m++) {
                            var newsec = numsplit[m];
                            newsec = newsec.replace(trimleading,'');
                            newsec = newsec.replace(trimtrailing,'');
                            if (re2.test(newsec) == true) {
                                badsecs.push(newsec);
                            } else {
                                if (newsec != '') {
                                    var isnew = 1;
                                    if (fromexisting != null) {
                                        for (var n=0; n<fromexisting.length; n++) {
                                            if (newsec == fromexisting[n]) {
                                                isnew = 0;
                                            }
                                        }
                                    }
                                    if (isnew == 1) {
                                        validsecs.push(newsec);
                                    }
                                }
                            }
                        }
                        if (badsecs.length > 0) {
                            alert("$alerts{'nonw'}\\n$alerts{'plch'}");
                            return;
                        }
                        numsec = numsec + validsecs.length;
                    }
                    if ((role == 'st') && (numsec > 1)) {
                        if (crstype == 'Community') {
                            alert("$alerts{'inea'} $alerts{'youh'} "+numsec+" $alerts{'secs'}\\n$alerts{'plmo'}");
                        } else {
                            alert("$alerts{'inco'} $alerts{'youh'} "+numsec+" $alerts{'secs'}\\n$alerts{'plmo'}");
                        }
                        return;
                    } else {
                        if (validsecs != null) {
                            for (var j=0; j<validsecs.length; j++) {
                                if (validsecstr == '' || validsecstr == null) {
                                    validsecstr = validsecs[j];
                                } else {
                                    validsecstr += ','+validsecs[j];
                                }
                                if ((validsecs[j] == 'all') ||
                                    (validsecs[j] == 'none')) {
                                    alert("'"+validsecs[j]+"' $alerts{'mayn'}\\n$alerts{'plch'}");
                                    return;
                                }
                                for (var k=0; k<groups.length; k++) {
                                    if (validsecs[j] == groups[k]) {
                                        alert("'"+validsecs[j]+"' $alerts{'mnot'}\\n$alerts{'secn'}");
                                        return;
                                    }
                                }
                            }
                        }
                    }
                    if ((validsecstr != '') && (validsecstr != null)) {
                        if ((sections == '') || (sections == null)) {
                            sections = validsecstr;
                        } else {
                            sections = sections + "," + validsecstr;
                        }
                    }
                    formname.elements[num+2].value = sections;
                }
            }
        }
    }
    $finish
}
ENDSECCODE
    return $setsection_js; 
}

sub can_create_user {
    my ($dom,$context,$usertype) = @_;
    my %domconf = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
    my $cancreate = 1;
    if (&Apache::lonnet::allowed('mau',$dom)) {
        return $cancreate;
    }
    if (ref($domconf{'usercreation'}) eq 'HASH') {
        if (ref($domconf{'usercreation'}{'cancreate'}) eq 'HASH') {
            if ($context eq 'course' || $context eq 'author' || $context eq 'requestcrs') {
                my $creation = $domconf{'usercreation'}{'cancreate'}{$context};
                if ($creation eq 'none') {
                    $cancreate = 0;
                } elsif ($creation ne 'any') {
                    if (defined($usertype)) {
                        if ($creation ne $usertype) {
                            $cancreate = 0;
                        }
                    }
                }
            }
        }
    }
    return $cancreate;
}

sub can_modify_userinfo {
    my ($context,$dom,$fields,$userroles) = @_;
    my %domconfig =
       &Apache::lonnet::get_dom('configuration',['usermodification'],
                                $dom);
    my %canmodify;
    if (ref($fields) eq 'ARRAY') {
        foreach my $field (@{$fields}) {
            $canmodify{$field}  = 0;
            if (&Apache::lonnet::allowed('mau',$dom)) {
                $canmodify{$field} = 1;
            } else {
                if (ref($domconfig{'usermodification'}) eq 'HASH') {
                    if (ref($domconfig{'usermodification'}{$context}) eq 'HASH') {
                        if (ref($userroles) eq 'ARRAY') {
                            foreach my $role (@{$userroles}) {
                                my $testrole;
                                if ($context eq 'selfcreate') {
                                    $testrole = $role;
                                } else {
                                    if ($role =~ /^cr\//) {
                                        $testrole = 'cr';
                                    } else {
                                        $testrole = $role;
                                    }
                                }
                                if (ref($domconfig{'usermodification'}{$context}{$testrole}) eq 'HASH') {
                                    if ($domconfig{'usermodification'}{$context}{$testrole}{$field}) {
                                        $canmodify{$field} = 1;
                                        last;
                                    }
                                }
                            }
                        } else {
                            foreach my $key (keys(%{$domconfig{'usermodification'}{$context}})) {
                                if (ref($domconfig{'usermodification'}{$context}{$key}) eq 'HASH') {
                                    if ($domconfig{'usermodification'}{$context}{$key}{$field}) {
                                        $canmodify{$field} = 1;
                                        last;
                                    }
                                }
                            }
                        }
                    }
                } elsif ($context eq 'course') {
                    if (ref($userroles) eq 'ARRAY') {
                        if (grep(/^st$/,@{$userroles})) {
                            $canmodify{$field} = 1;
                        }
                    } else {
                        $canmodify{$field} = 1;
                    }
                }
            }
        }
    }
    return %canmodify;
}

sub check_usertype {
    my ($dom,$uname,$rules,$curr_rules,$got_rules) = @_;
    my $usertype;
    if ((ref($got_rules) eq 'HASH') && (ref($curr_rules) eq 'HASH')) {
        if (!$got_rules->{$dom}) {
            my %domconfig = &Apache::lonnet::get_dom('configuration',
                                              ['usercreation'],$dom);
            if (ref($domconfig{'usercreation'}) eq 'HASH') {
                foreach my $item ('username','id') {
                    if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') {
                        $curr_rules->{$dom}{$item} =
                                $domconfig{'usercreation'}{$item.'_rule'};
                    }
                }
            }
            $got_rules->{$dom} = 1;
        }
        if (ref($rules) eq 'HASH') {
            my @user_rules;
            if (ref($curr_rules->{$dom}{'username'}) eq 'ARRAY') {
                foreach my $rule (keys(%{$rules})) {
                    if (grep(/^\Q$rule\E/,@{$curr_rules->{$dom}{'username'}})) {
                        push(@user_rules,$rule);
                    }
                } 
            }
            if (@user_rules > 0) {
                my %rule_check = &Apache::lonnet::inst_rulecheck($dom,$uname,undef,'username',\@user_rules);
                if (keys(%rule_check) > 0) {
                    $usertype = 'unofficial';
                    foreach my $item (keys(%rule_check)) {
                        if ($rule_check{$item}) {
                            $usertype = 'official';
                            last;
                        }
                    }
                }
            }
        }
    }
    return $usertype;
}

sub roles_by_context {
    my ($context,$custom,$crstype) = @_;
    my @allroles;
    if ($context eq 'course') {
        @allroles = ('st');
        if ($env{'request.role'} =~ m{^dc\./}) {
            push(@allroles,'ad');
        }
        push(@allroles,('ta','ep','in'));
        if ($crstype eq 'Community') {
            push(@allroles,'co');
        } else {
            push(@allroles,'cc');
        }
        if ($custom) {
            push(@allroles,'cr');
        }
    } elsif ($context eq 'author') {
        @allroles = ('ca','aa');
    } elsif ($context eq 'domain') {
        @allroles = ('li','ad','dg','sc','au','dc');
    }
    return @allroles;
}

sub get_permission {
    my ($context,$crstype) = @_;
    my %permission;
    if ($context eq 'course') {
        my $custom = 1;
        my @allroles = &roles_by_context($context,$custom,$crstype);
        foreach my $role (@allroles) {
            if (&Apache::lonnet::allowed('c'.$role,$env{'request.course.id'})) {
                $permission{'cusr'} = 1;
                last;
            }
        }
        if (&Apache::lonnet::allowed('ccr',$env{'request.course.id'})) {
            $permission{'custom'} = 1;
        }
        if (&Apache::lonnet::allowed('vcl',$env{'request.course.id'})) {
            $permission{'view'} = 1;
        }
        if (!$permission{'view'}) {
            my $scope = $env{'request.course.id'}.'/'.$env{'request.course.sec'};
            $permission{'view'} =  &Apache::lonnet::allowed('vcl',$scope);
            if ($permission{'view'}) {
                $permission{'view_section'} = $env{'request.course.sec'};
            }
        }
        if (!$permission{'cusr'}) {
            if ($env{'request.course.sec'} ne '') {
                my $scope = $env{'request.course.id'}.'/'.$env{'request.course.sec'};
                $permission{'cusr'} = (&Apache::lonnet::allowed('cst',$scope));
                if ($permission{'cusr'}) {
                    $permission{'cusr_section'} = $env{'request.course.sec'};
                }
            }
        }
        if (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
            $permission{'grp_manage'} = 1;
        }
        if ($permission{'cusr'}) {
            my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
            my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
            my %coursehash = (
                'internal.selfenrollmgrdc' => $env{'course.'.$env{'request.course.id'}.'.internal.selfenrollmgrdc'},
                'internal.selfenrollmgrcc' => $env{'course.'.$env{'request.course.id'}.'.internal.selfenrollmgrcc'},
                'internal.coursecode'      => $env{'course.'.$env{'request.course.id'}.'.internal.coursecode'},
                'internal.textbook'        =>$env{'course.'.$env{'request.course.id'}.'.internal.textbook'},
            );
            my ($managed_by_cc,$managed_by_dc) = &selfenrollment_administration($cdom,$cnum,$crstype,\%coursehash);
            if (ref($managed_by_cc) eq 'ARRAY') {
                if (@{$managed_by_cc}) {
                    $permission{'selfenrolladmin'} = 1;
                }
            }
        }
    } elsif ($context eq 'author') {
        $permission{'cusr'} = &authorpriv($env{'user.name'},$env{'request.role.domain'});
        $permission{'view'} = $permission{'cusr'};
    } else {
        my @allroles = &roles_by_context($context);
        foreach my $role (@allroles) {
            if (&Apache::lonnet::allowed('c'.$role,$env{'request.role.domain'})) {
                $permission{'cusr'} = 1;
                last;
            }
        }
        if (!$permission{'cusr'}) {
            if (&Apache::lonnet::allowed('mau',$env{'request.role.domain'})) {
                $permission{'cusr'} = 1;
            }
        }
        if (&Apache::lonnet::allowed('ccr',$env{'request.role.domain'})) {
            $permission{'custom'} = 1;
        }
        $permission{'view'} = $permission{'cusr'};
    }
    my $allowed = 0;
    foreach my $perm (values(%permission)) {
        if ($perm) { $allowed=1; last; }
    }
    return (\%permission,$allowed);
}

# ==================================================== Figure out author access

sub authorpriv {
    my ($auname,$audom)=@_;
    unless ((&Apache::lonnet::allowed('cca',$audom.'/'.$auname))
         || (&Apache::lonnet::allowed('caa',$audom.'/'.$auname))) { return ''; }    return 1;
}

sub roles_on_upload {
    my ($context,$setting,$crstype,%customroles) = @_;
    my (@possible_roles,@permitted_roles);
    @possible_roles = &curr_role_permissions($context,$setting,1,$crstype);
    foreach my $role (@possible_roles) {
        if ($role eq 'cr') {
            push(@permitted_roles,keys(%customroles));
        } else {
            push(@permitted_roles,$role);
        }
    }
    return @permitted_roles;
}

sub get_course_identity {
    my ($cid) = @_;
    my ($cnum,$cdom,$cdesc);
    if ($cid eq '') {
        $cid = $env{'request.course.id'}
    }
    if ($cid ne '') {
        $cnum = $env{'course.'.$cid.'.num'};
        $cdom = $env{'course.'.$cid.'.domain'};
        $cdesc = $env{'course.'.$cid.'.description'};
        if ($cnum eq '' || $cdom eq '') {
            my %coursehash =
                &Apache::lonnet::coursedescription($cid,{'one_time' => 1});
            $cdom = $coursehash{'domain'};
            $cnum = $coursehash{'num'};
            $cdesc = $coursehash{'description'};
        }
    }
    return ($cnum,$cdom,$cdesc);
}

sub dc_setcourse_js {
    my ($formname,$mode,$context,$showcredits) = @_;
    my ($dc_setcourse_code,$authen_check);
    my $cctext = &Apache::lonnet::plaintext('cc');
    my $cotext = &Apache::lonnet::plaintext('co');
    my %alerts = &sectioncheck_alerts();
    my $role = 'role';
    if ($mode eq 'upload') {
        $role = 'courserole';
    } else {
        $authen_check = &verify_authen($formname,$context);
    }
    $dc_setcourse_code = (<<"SCRIPTTOP");
$authen_check

function setCourse() {
    var course = document.$formname.dccourse.value;
    if (course != "") {
        if (document.$formname.dcdomain.value != document.$formname.origdom.value) {
            alert("$alerts{'curd'}");
            return;
        }
        var userrole = document.$formname.$role.options[document.$formname.$role.selectedIndex].value
        var section="";
        var numsections = 0;
        var newsecs = new Array();
        for (var i=0; i<document.$formname.currsec.length; i++) {
            if (document.$formname.currsec.options[i].selected == true ) {
                if (document.$formname.currsec.options[i].value != "" && document.$formname.currsec.options[i].value != null) {
                    if (numsections == 0) {
                        section = document.$formname.currsec.options[i].value
                        numsections = 1;
                    }
                    else {
                        section = section + "," +  document.$formname.currsec.options[i].value
                        numsections ++;
                    }
                }
            }
        }
        if (document.$formname.newsec.value != "" && document.$formname.newsec.value != null) {
            if (numsections == 0) {
                section = document.$formname.newsec.value
            }
            else {
                section = section + "," +  document.$formname.newsec.value
            }
            newsecs = document.$formname.newsec.value.split(/,/g);
            numsections = numsections + newsecs.length;
        }
        if ((userrole == 'st') && (numsections > 1)) {
            if (document.$formname.crstype.value == 'Community') {
                alert("$alerts{'inco'}. $alerts{'youh'} "+numsections+" $alerts{'sect'}.\\n$alerts{'plsm'}.")
            } else {
                alert("$alerts{'inea'}. $alerts{'youh'} "+numsections+" $alerts{'sect'}.\\n$alerts{'plsm'}.")
            }
            return;
        }
        for (var j=0; j<newsecs.length; j++) {
            if ((newsecs[j] == 'all') || (newsecs[j] == 'none')) {
                alert("'"+newsecs[j]+"' $alerts{'mayn'}.\\n$alerts{'plsc'}.");
                return;
            }
            if (document.$formname.groups.value != '') {
                var groups = document.$formname.groups.value.split(/,/g);
                for (var k=0; k<groups.length; k++) {
                    if (newsecs[j] == groups[k]) {
                        if (document.$formname.crstype.value == 'Community') {
                            alert("'"+newsecs[j]+"' $alerts{'mayc'}.\\n$alerts{'secn'}. $alerts{'plsc'}.");
                        } else {
                            alert("'"+newsecs[j]+"' $alerts{'mayt'}.\\n$alerts{'secn'}. $alerts{'plsc'}.");
                        }
                        return;
                    }
                }
            }
        }
        if ((userrole == 'cc') && (numsections > 0)) {
            alert("$alerts{'secd'} $cctext $alerts{'role'}.\\n$alerts{'accr'}.");
            section = "";
        }
        if ((userrole == 'co') && (numsections > 0)) {
            alert("$alerts{'secd'} $cotext $alerts{'role'}.\\n$alerts{'accr'}.");
            section = "";
        }
SCRIPTTOP
    if ($mode ne 'upload') {
        $dc_setcourse_code .= (<<"SCRIPTMID");
        var coursename = "_$env{'request.role.domain'}"+"_"+course+"_"+userrole
        var numcourse = getIndex(document.$formname.dccourse);
        if (numcourse == "-1") {
            if (document.$formname.type == 'Community') {
                alert("$alerts{'thwc'}");
            } else {
                alert("$alerts{'thwa'}");
            }
            return;
        }
        else {
            document.$formname.elements[numcourse].name = "act"+coursename;
            var numnewsec = getIndex(document.$formname.newsec);
            if (numnewsec != "-1") {
                document.$formname.elements[numnewsec].name = "sec"+coursename;
                document.$formname.elements[numnewsec].value = section;
            }
            var numstart = getIndex(document.$formname.start);
            if (numstart != "-1") {
                document.$formname.elements[numstart].name = "start"+coursename;
            }
            var numend = getIndex(document.$formname.end);
            if (numend != "-1") {
                document.$formname.elements[numend].name = "end"+coursename
            }
SCRIPTMID
        if ($showcredits) {
            $dc_setcourse_code .= <<ENDCRED;
            var numcredits = getIndex(document.$formname.credits);
            if (numcredits != "-1") {
                document.$formname.elements[numcredits].name = "credits"+coursename;
            }
ENDCRED
        }
        $dc_setcourse_code .= <<ENDSCRIPT; 
        }
    }
    var authcheck = auth_check();
    if (authcheck == 'ok') {
        document.$formname.submit();
    }
}
ENDSCRIPT
    } else {
        $dc_setcourse_code .=  "
        document.$formname.sections.value = section;
    }
    return 'ok';
}
";
    }
    $dc_setcourse_code .= (<<"ENDSCRIPT");

    function getIndex(caller) {
        for (var i=0;i<document.$formname.elements.length;i++) {
            if (document.$formname.elements[i] == caller) {
                return i;
            }
        }
        return -1;
    }
ENDSCRIPT
    return $dc_setcourse_code;
}

sub verify_authen {
    my ($formname,$context) = @_;
    my %alerts = &authcheck_alerts();
    my $finish = "return 'ok';";
    if ($context eq 'author') {
        $finish = "document.$formname.submit();";
    }
    my $outcome = <<"ENDSCRIPT";

function auth_check() {
    var logintype;
    if (document.$formname.login.length) {
        if (document.$formname.login.length > 0) {
            var loginpicked = 0;
            for (var i=0; i<document.$formname.login.length; i++) {
                if (document.$formname.login[i].checked == true) {
                    loginpicked = 1;
                    logintype = document.$formname.login[i].value;
                }
            }
            if (loginpicked == 0) {
                alert("$alerts{'authen'}");
                return;
            }
        }
    } else {
        logintype = document.$formname.login.value;
    }
    if (logintype == 'nochange') {
        return 'ok';
    }
    var argpicked = document.$formname.elements[logintype+'arg'].value;
    if ((argpicked == null) || (argpicked == '') || (typeof argpicked == 'undefined')) {
        var alertmsg = '';
        switch (logintype) {
            case 'krb':
                alertmsg = '$alerts{'krb'}';
                break;
            case 'int':
                alertmsg = '$alerts{'ipass'}';
            case 'fsys':
                alertmsg = '$alerts{'ipass'}';
                break;
            case 'loc':
                alertmsg = '';
                break;
            default:
                alertmsg = '';
        }
        if (alertmsg != '') {
            alert(alertmsg);
            return;
        }
    }
    $finish
}
ENDSCRIPT
}

sub sectioncheck_alerts {
    my %alerts = &Apache::lonlocal::texthash(
                    curd => 'You must select a course or community in the current domain',
                    inea => 'In each course, each user may only have one student role at a time',
                    inco => 'In each community, each user may only have one member role at a time', 
                    youh => 'You had selected',
                    sect => 'sections',
                    plsm => 'Please modify your selections so they include no more than one section',
                    mayn => 'may not be used as the name for a section, as it is a reserved word',
                    plsc => 'Please choose a different section name',
                    mayt => 'may not be used as the name for a section, as it is the name of a course group',
                    mayc => 'may not be used as the name for a section, as it is the name of a community group',
                    secn => 'Section names and group names must be distinct',
                    secd => 'Section designations do not apply to ',
                    role => 'roles',
                    accr => 'role will be added with access to all sections',
                    thwa => 'There was a problem with your course selection',
                    thwc => 'There was a problem with your community selection',
                 );
    &js_escape(\%alerts);
    return %alerts;
}

sub authcheck_alerts {
    my %alerts = 
        &Apache::lonlocal::texthash(
                    authen => 'You must choose an authentication type.',
                    krb    => 'You need to specify the Kerberos domain.',
                    ipass  => 'You need to specify the initial password.',
        );
    &js_escape(\%alerts);
    return %alerts;
}

sub is_courseowner {
    my ($thiscourse,$courseowner) = @_;
    if ($courseowner eq '') {
        if ($env{'request.course.id'} eq $thiscourse) {
            $courseowner = $env{'course.'.$env{'request.course.id'}.'.internal.courseowner'};
        }
    }
    if ($courseowner ne '') {
        if ($courseowner eq $env{'user.name'}.':'.$env{'user.domain'}) {
            return 1;
        }
    }
    return;
}

sub get_selfenroll_titles {
    my @row = ('types','registered','enroll_dates','access_dates','section',
               'approval','limit');
    my %lt = &Apache::lonlocal::texthash (
                types        => 'Users allowed to self-enroll',
                registered   => 'Registration status (official courses)' ,
                enroll_dates => 'Dates self-enrollment available',
                access_dates => 'Access dates for self-enrolling users',
                section      => "Self-enrolling users' section",
                approval     => 'Processing of requests',
                limit        => 'Enrollment limit',
             );
    return (\@row,\%lt);
}

sub selfenroll_default_descs {
    my %desc = (
                 types => {
                            dom => &mt('Course domain'),
                            all => &mt('Any domain'),
                            ''  => &mt('None'),
                          },
                 limit => {
                            none         => &mt('No limit'),
                            allstudents  => &mt('Limit by total students'),
                            selfenrolled => &mt('Limit by total self-enrolled'),
                          },
                 approval => {
                                '0' => &mt('Processed automatically'),
                                '1' => &mt('Queued for approval'),
                                '2' => &mt('Queued, pending validation'),
                             },
                 registered => {
                                 0 => 'No registration required',
                                 1 => 'Registered students only',
                               },
               );
    return %desc;
}

sub selfenroll_validation_types {
    my @items = ('url','fields','button','markup');
    my %names =  &Apache::lonlocal::texthash (
            url      => 'Web address of validation server/script',
            fields   => 'Form fields to send to validator',
            button   => 'Text for validation button',
            markup   => 'Validation description (HTML)',
    );
    my @fields = ('username','domain','uniquecode','course','coursetype','description');
    return (\@items,\%names,\@fields);
}

sub get_extended_type {
    my ($cdom,$cnum,$crstype,$current) = @_;
    my $type = 'unofficial';
    my %settings;
    if (ref($current) eq 'HASH') {
        %settings = %{$current};
    } else {
        %settings = &Apache::lonnet::get('environment',['internal.coursecode','internal.textbook'],$cdom,$cnum);
    }
    if ($crstype eq 'Community') {
        $type = 'community';
    } elsif ($settings{'internal.coursecode'}) {
        $type = 'official';
    } elsif ($settings{'internal.textbook'}) {
        $type = 'textbook';
    }
    return $type;
}

sub selfenrollment_administration {
    my ($cdom,$cnum,$crstype,$coursehash) = @_;
    my %settings;
    if (ref($coursehash) eq 'HASH') {
        %settings = %{$coursehash};
    } else {
        %settings = &Apache::lonnet::get('environment',
                        ['internal.selfenrollmgrdc','internal.selfenrollmgrcc',
                         'internal.coursecode','internal.textbook'],$cdom,$cnum);
    }
    my ($possconfigs) = &get_selfenroll_titles(); 
    my %domdefaults = &Apache::lonnet::get_domain_defaults($cdom);
    my $selfenrolltype = &get_extended_type($cdom,$cnum,$crstype,\%settings);

    my (@in_course,@in_domain); 
    if ($settings{'internal.selfenrollmgrcc'} ne '') {
        @in_course = split(/,/,$settings{'internal.selfenrollmgrcc'}); 
        my @diffs = &Apache::loncommon::compare_arrays($possconfigs,\@in_course);
        unless (@diffs) {
            return (\@in_course,\@in_domain);
        }
    }
    if ($settings{'internal.selfenrollmgrdc'} ne '') {
        my @in_domain = split(/,/,$settings{'internal.selfenrollmgrdc'});
        my @diffs = &Apache::loncommon::compare_arrays(\@in_domain,$possconfigs);
        unless (@diffs) {
            return (\@in_course,\@in_domain);
        }
    }
    my @combined = @in_course;
    push(@combined,@in_domain);
    my @diffs = &Apache::loncommon::compare_arrays(\@combined,$possconfigs); 
    unless (@diffs) {
        return (\@in_course,\@in_domain);
    }
    if ($domdefaults{$selfenrolltype.'selfenrolladmdc'} eq '') {
        push(@in_course,@diffs);
    } else {
        my @defaultdc = split(/,/,$domdefaults{$selfenrolltype.'selfenrolladmdc'});
        foreach my $item (@diffs) {
            if (grep(/^\Q$item\E$/,@defaultdc)) {
                push(@in_domain,$item);
            } else {
                push(@in_course,$item);
            }
        }
    }
    return (\@in_course,\@in_domain);
}

1;


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