File:  [LON-CAPA] / loncom / interface / lonuserutils.pm
Revision 1.20: download - view: text, annotated - select for diffs
Fri Dec 21 17:27:57 2007 UTC (16 years, 4 months ago) by raeburn
Branches: MAIN
CVS tags: HEAD
loncreateuser.pm
- &lonuserutils::can_modify_userinfo() used to determine if personal info field can be modified.
- Replace $home with $uhome as name of homeserver variable for newly created user.

lonuserutils.pm
can_modify_userinfo() returns a hash with information about which personal data fields are modifiable, as determined by context (author, course or domain) and roles of user being modified.  DC sets the domain configuration for user modification.

# The LearningOnline Network with CAPA
# Utility functions for managing LON-CAPA user accounts
#
# $Id: lonuserutils.pm,v 1.20 2007/12/21 17:27:57 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)=@_;
    # 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);
                    $result .= $reply.':';
                }
            }
        }
    }
    if ($result eq '') {
        $result = '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) = @_;
    my ($scope,$userresult,$authresult,$roleresult,$idresult);
    if ($setting eq 'course' || $context eq 'course') {
        $scope = '/'.$cid;
        $scope =~ s/\_/\//g;
        if ($role ne 'cc' && $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,$role,$start,$end);
    if ($userresult eq 'ok') {
        if ($role ne '') {
            $roleresult = &Apache::lonnet::assignrole($udom,$uname,$scope,
                                                      $role,$end,$start);
        }
    }
    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);
        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) = @_;
    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;
    for (my $i=0; $i<@classinfo; $i++) {
        if ($i == $ididx) {
            if (defined($user->{'id'})) {
                $classlistentry .= $user->{'id'}.':';
            } else {
                $classlistentry .= $classinfo[$i].':';
            }
        } elsif ($i == $nameidx) {
            $classlistentry .= $fullname.':';
        } 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');
    my %lt = &role_type_names();
    #
    # 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};
        # 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);
        }
        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);
            }
        }
        $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']);
    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)=@_;
    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();
    } else {
        $javascript=&upload_manager_javascript_forward_associate();
    }
    #
    # 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 $javascript_validations =
        &javascript_validations('auth',$krbdefdom,$password_choice,undef,
                                $env{'request.role.domain'});
    my $checked=(($env{'form.noFirstLine'})?' checked="checked" ':'');
    $r->print(&mt('Total number of records found in file: <b>[_1]</b>.',$distotal).
              "<br />\n");
    $r->print('<div class="LC_left_float"><h3>'.
              &mt('Identify fields in uploaded list')."</h3>\n");
    $r->print(&mt('Enter as many fields as you can.<br /> The system will inform you and bring you back to this page, <br /> if the data selected are insufficient to add users.')."<br />\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('<br /><input type="button" value="Reverse Association" '.
              'name="'.&mt('Reverse Association').'" '.
              'onClick="javascript:this.form.associate.value=\'Reverse Association\';submit(this.form);" />');
    $r->print('<label><input type="checkbox" name="noFirstLine"'.$checked.'/>'.
              &mt('Ignore First Line').'</label>');
    $r->print("<br /><br />\n".
              '<script type="text/javascript" language="Javascript">'."\n".
              $javascript."\n".$javascript_validations.'</script>');
}

###############################################################
###############################################################
sub javascript_validations {
    my ($mode,$krbdefdom,$curr_authtype,$curr_authfield,$domain)=@_;
    my $authheader;
    if ($mode eq 'auth') {
        my %param = ( formname => 'studentform',
                      kerb_def_dom => $krbdefdom,
                      curr_authtype => $curr_authtype);
        $authheader = &Apache::loncommon::authform_header(%param);
    } elsif ($mode eq 'createcourse') {
        my %param = ( formname => 'ccrs',
                      kerb_def_dom => $krbdefdom,
                      curr_authtype => $curr_authtype );
        $authheader = &Apache::loncommon::authform_header(%param);
    } elsif ($mode eq 'modifycourse') {
        my %param = ( formname => 'cmod',
                  kerb_def_dom => $krbdefdom,
                  mode => 'modifycourse',
                  curr_authtype => $curr_authtype,
                  curr_autharg => $curr_authfield );
        $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 ID number field was not specified.',
         section  => 'The optional section field was not specified.',
         email    => 'The optional email address field was not specified.',
         role     => 'The optional role field was not specified.',
         continue => 'Continue adding users?',
         );

#    my $pjump_def = &Apache::lonhtmlcommon::pjump_javascript_definition();
    my $function_name =(<<END);
function verify_message (vf,founduname,foundpwd,foundname,foundid,foundsec,foundemail) {
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;
        }
    }
END
    } else {
        $auth_checks .= (<<END);
    foundatype=1;
    if (current.argfield == null || current.argfield == '') {
        var alertmsg = '';
        switch (current.value) {
            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';
        }
    }
    if (foundemail==0) {
        if (message!='') {
            message+='\\n';
        }
        message+='$alert{'email'}';
    }
    if (message!='') {
        message+= '\\n$alert{'continue'}';
        if (confirm(message)) {
            vf.state.value='enrolling';
            vf.submit();
        }
    } else {
        vf.state.value='enrolling';
        vf.submit();
    }
}
END
    }
    my $result = $function_name;
    if ( ($mode eq 'auth') || ($mode eq 'createcourse') || ($mode eq 'modifycourse')  ) {
        $result .= $auth_checks;
    }
    $result .= $optional_checks."\n".$section_checks;
    if ( ($mode eq 'auth') || ($mode eq 'createcourse') || ($mode eq 'modifycourse')  ) {
        $result .= $authheader;
    }
    return $result;
}
###############################################################
###############################################################
sub upload_manager_javascript_forward_associate {
    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 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; }
    }
    verify_message(vf,founduname,foundpwd,foundname,foundid,foundsec,foundemail,foundrole);
}

//
// 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

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;')
         }
      }
   }
   // 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);
       vf.intarg.value='';
       vf.krbarg.value='';
       vf.locarg.value='';
   }
}

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 {
    return(<<ENDPICK);
function verify(vf,sec_caller) {
    var founduname=0;
    var foundpwd=0;
    var foundname=0;
    var foundid=0;
    var foundsec=0;
    var foundrole=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) { foundrole=1; }
    }
    verify_message(vf,founduname,foundpwd,foundname,foundid,foundsec,foundrole);
}

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;')
   }
   // intial password specified, pick internal authentication
   if (tf==8 && nw!=0) {
       changed_radio('int',document.studentform);
       set_auth_radio_buttons('int',document.studentform);
       vf.krbarg.value='';
       vf.intarg.value='';
       vf.locarg.value='';
   }
}

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)=@_;
    my $formname;
    if ($context eq 'course') {
        $formname = 'document.studentform';
    } elsif ($context eq 'author') {
        $formname = 'document.studentform';
    } elsif ($context eq 'domain') {
        $formname = 'document.studentform';
    }
    my ($krbdef,$krbdefdom) =
        &Apache::loncommon::get_kerberos_defaults($defdom);
    my %param = ( formname => $formname,
                  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);

    my $Str = "\n".'<div class="LC_left_float">';
    $Str .= &hidden_input('nfields',$i);
    $Str .= &hidden_input('keyfields',$keyfields);
    $Str .= "<h3>".&mt('Login Type')."</h3>\n";
    if ($context eq 'domain') {
        $Str .= '<p>'.&mt('Change authentication for existing users to these settings?').'&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>\n".
            &mt('Note: 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 .= '<h3>'.&mt('LON-CAPA Home Server for New Users')."</h3>\n".
                &mt('LON-CAPA domain: [_1] with home server: [_2]',$defdom,
                $home_server_pick).'<br />';
    } else {
        $Str .= $home_server_pick;
    }
    $Str .= '<h3>'.&mt('Starting and Ending Dates').
            "</h3>\n";
    $Str .= "<p>\n".$date_table."</p>\n";
    if ($context eq 'domain') {
        $Str .= '<h3>'.&mt('Settings for assigning roles:').'</h3>'."\n".
                &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 role').'</label></span>';
    }
    if ($context eq 'author') {
        $Str .= '<h3>'.&mt('Default role')."</h3>\n".
                &mt('Choose the role to assign to users without one specified in the uploaded file');
    } elsif ($context eq 'course') {
        $Str .= '<h3>'.&mt('Default role and section')."</h3>\n".
                &mt('Choose the role and/or section to assign to users without one specified in the uploaded file');
    } else {
        $Str .= '<br /><br /><b>'.&mt('Default role and/or section')."</b><br />\n".
                &mt('Role and/or section for users without one in the uploaded file.');
    }
    $Str .= '<br /><br />';
    my ($options,$cb_script,$coursepick) = &default_role_selector($context,'defaultrole',1);
    if ($context eq 'domain') {
        $Str .= '<span class="LC_role_level">'.&mt('Domain Level').'</span><br />'.$options.'<br /><br /><span class="LC_role_level">'.&mt('Course Level').'</span><br />'.$cb_script.$coursepick;
    } elsif ($context eq 'author') {
        $Str .= $options;
    } else {
        $Str .= '<table><tr><td><span class="LC_nobreak"<b>'.&mt('role').':&nbsp;</b>'.
                $options.'</span></td><td>&nbsp;</td><td><span class="LC_nobreak">'.
                '<b>'.&mt('section').':&nbsp;</b><input type="text" name="section" value="" size="12" /></span></td></tr></table>';
    }
    if ($context eq 'course') {
        $Str .= "<h3>".&mt('Full Update')."</h3>\n".
                '<label><input type="checkbox" name="fullup" value="yes">'.
                ' '.&mt('Full update (also print list of users not enrolled anymore)').
                "</label></p>\n";
    }
    if ($context eq 'course' || $context eq 'domain') {
        $Str .= &forceid_change($context);
    }
    $Str .= '</div><div class="LC_clear_float_footer"><br /><input type="button"'.
              'onClick="javascript:verify(this.form,this.form.csec)" '.
        'value="Update Users" />'."<br />\n";
    if ($context eq 'course') {
        $Str .= &mt('Note: for large courses, this operation may be time '.
                    'consuming');
    }
    $Str .= '</div>';
    $r->print($Str);
    return;
}

sub forceid_change {
    my ($context) = @_;
    my $output = 
        "<h3>".&mt('ID/Student Number')."</h3>\n".
        "<p>\n".'<label><input type="checkbox" name="forceid" value="yes">'.
        &mt('Disable ID/Student Number Safeguard and Force Change '.
        'of Conflicting IDs').'</label><br />'."\n".
        &mt('(only do if you know what you are doing.)')."</br><br />\n";
    if ($context eq 'domain') {
        $output .= '<label><input type="checkbox" name="recurseid"'.
                   ' value="yes">'. 
  &mt('Update ID/Student Number in courses in which user is Active/Future student,<br />(if forcing change).').
                   '</label></p>'."\n";
    }
    return $output;
}

###############################################################
###############################################################
sub print_upload_manager_form {
    my ($r,$context) = @_;
    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',
                             };
    my $defdom = $env{'request.role.domain'};
    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);
    }
    #
    # Determine kerberos parameters as appropriate
    my ($krbdef,$krbdefdom) =
        &Apache::loncommon::get_kerberos_defaults($defdom);
    #
    &print_upload_manager_header($r,$datatoken,$distotal,$krbdefdom,$context);
    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('ID/Student Number'),$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'}]);
        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)));
        }
    }
    $r->print('</div>');
    &print_upload_manager_footer($r,$i,$keyfields,$defdom,$today,$halfyear,
                                 $context);
}

sub setup_date_selectors {
    my ($starttime,$endtime,$mode,$nolink) = @_;
    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('studentform','startdate',$starttime,
            undef,undef,undef,undef,undef,undef,undef,$nolink);

    my $enddateform = 
        &Apache::lonhtmlcommon::date_setter('studentform','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 $startdate = &Apache::lonhtmlcommon::get_date_from_form('startdate');
    my $enddate   = &Apache::lonhtmlcommon::get_date_from_form('enddate');
    if ($env{'form.no_end_date'}) {
        $enddate = 0;
    }
    return ($startdate,$enddate);
}

sub date_setting_table {
    my ($starttime,$endtime,$mode,$bulkaction) = @_;
    my $nolink;
    if ($bulkaction) {
        $nolink = 1;
    }
    my ($startform,$endform) = 
        &setup_date_selectors($starttime,$endtime,$mode,$nolink);
    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')) { 
            $dateDefault = '<span class="LC_nobreak">'.
                '<label><input type="checkbox" name="makedatesdefault" /> '.
                &mt('make these dates the default for future enrollment').
                '</label></span>';
        }
    }
    my $perpetual = '<span class="LC_nobreak"><label><input type="checkbox" name="no_end_date"';
    if (defined($endtime) && $endtime == 0) {
        $perpetual .= ' 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().'<br />';
    if ($dateDefault) {
        $result .=  $dateDefault.'<br />'."\n";
    }
    return $result;
}

sub make_dates_default {
    my ($startdate,$enddate,$context) = @_;
    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') {
            $result .= &mt('Set default start and end dates for course').
                       '<br />'."\n";
            #
            # Refresh the course environment
            &Apache::lonnet::coursedescription($env{'request.course.id'},
                                               {'freshen_cache' => 1});
        } else {
            $result .= &mt('Unable to set default dates for course').":".$put_result.
                       '<br />';
        }
    }
    return $result;
}

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

    my %lt=&Apache::lonlocal::texthash(
                    'rol'  => "Role",
                    'grs'  => "Section",
                    'exs'  => "Existing sections",
                    'new'  => "New section",
                  );
    $options = '<select name="defaultrole">'."\n".
               ' <option value="">'.&mt('Please select').'</option>'."\n"; 
    if ($context eq 'course') {
        $options .= &default_course_roles($context,$checkpriv,%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','defaultcourse','defaultdomain','defaultdesc',"$env{'request.role.domain'}",undef,'Course');
        $cb_jscript = 
            &Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'},'defaultsec','studentform');
        $coursepick = &Apache::loncommon::start_data_table().
                      &Apache::loncommon::start_data_table_header_row().
                      '<th>'.$courseform.'</th><th>'.$lt{'rol'}.'</th>'.
                      '<th>'.$lt{'grs'}.'</th>'.
                      &Apache::loncommon::end_data_table_header_row().
                      &Apache::loncommon::start_data_table_row()."\n".
                      '<td><input type="text" name="defaultdesc" value="" onFocus="this.blur();opencrsbrowser('."'studentform','defcourse','defdomain','coursedesc',''".')" /></td>'."\n".
                      '<td><select name="courserole">'."\n".
                      &default_course_roles($context,$checkpriv,%customroles)."\n".
                      '</select></td><td>'.
                      '<table class="LC_createuser">'.
                      '<tr class="LC_section_row"><td valign"top">'.
                      $lt{'exs'}.'<br /><select name="defaultsec">'.
                      ' <option value=""><--'.&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="" /></td>'.
                      '</tr></table></td>'.
                      &Apache::loncommon::end_data_table_row().
                      &Apache::loncommon::end_data_table()."\n".
                      '<input type="hidden" name="defaultcourse" value="" />'.
                      '<input type="hidden" name="defaultdomain" value="" />';
    }
    $options .= '</select>';
    return ($options,$cb_jscript,$coursepick);
}

sub default_course_roles {
    my ($context,$checkpriv,%customroles) = @_;
    my $output;
    my $custom = 1;
    my @roles = &course_roles($context,$checkpriv,$custom);
    foreach my $role (@roles) {
        my $plrole=&Apache::lonnet::plaintext($role);
        $output .= '  <option value="'.$role.'">'.$plrole.'</option>';
    }
    if (keys(%customroles) > 0) {
        my %customroles = &my_custom_roles();
        foreach my $cust (sort(keys(%customroles))) {
            my $custrole='cr_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) = @_;
    my @allroles = &roles_by_context('course',$custom);
    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' && $env{'request.course.section'} ne '') {
                            if (!&Apache::lonnet::allowed('c'.$role,
                                             $env{'request.course.id'}.'/'.
                                             $env{'request.course.section'})) {
                                push(@roles,$role);
                            }
                        }
                    }
                }
            } else {
                @roles = @allroles;
            }
        }
    }
    return @roles;
}

sub curr_role_permissions {
    my ($context,$setting,$checkpriv) = @_; 
    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); 
        } else {
            @roles = &domain_roles($checkpriv);
        }
    } elsif ($context eq 'course') {
        @roles = &course_roles($context,$checkpriv,$custom);
    }
    return @roles;
}

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

sub my_custom_roles {
    my %returnhash=();
    my %rolehash=&Apache::lonnet::dump('roles');
    foreach my $key (keys %rolehash) {
        if ($key=~/^rolesdef\_(\w+)$/) {
            $returnhash{$1}=$1;
        }
    }
    return %returnhash;
}

sub print_userlist {
    my ($r,$mode,$permission,$context,$formname,$totcodes,$codetitles,
        $idlist,$idlist_titles) = @_;
    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 $status_select = &Apache::lonhtmlcommon::StatusOptions
        ($env{'form.Status'});

    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');
    }

#    if ($context eq 'course') { 
#        $r->print(&display_adv_courseroles());
#    }
    #
    # Interface output
    $r->print('<form name="studentform" method="post" action="/adm/createuser">'."\n".
              '<input type="hidden" name="action" value="'.
              $env{'form.action'}.'" />');
    $r->print("<p>\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" >';
        foreach my $outputformat ('html','csv','excel') {
            my $option = '<option value="'.$outputformat.'" ';
            if ($outputformat eq $env{'form.output'}) {
                $option .= 'selected ';
            }
            $option .='>'.$lt{$outputformat}.'</option>';
            $output_selector .= "\n".$option;
        }
        $output_selector .= '</select>';
        $r->print('<label>'.&mt('Output Format: [_1]',$output_selector).'</label>'.('&nbsp;'x3));
    }
    $r->print('<label>'.&mt('User Status: [_1]',$status_select).'</label>'.('&nbsp;'x3)."\n");
    my $roleselected = '';
    if ($env{'form.showrole'} eq 'Any') {
       $roleselected = ' selected="selected" '; 
    }
    my $role_select;
    if ($context eq 'domain') {
        $role_select = &domain_roles_select();
        $r->print('<label>'.&mt('Role Type: [_1]',$role_select).'</label>');
    } else {
        $role_select = '<select name="showrole">'."\n".
                       '<option value="Any" '.$roleselected.'>'.
                       &mt('Any role').'</option>';
        my @poss_roles = &curr_role_permissions($context);
        foreach my $role (@poss_roles) {
            $roleselected = '';
            if ($role eq $env{'form.showrole'}) {
                $roleselected = ' selected="selected" ';
            }
            my $plrole=&Apache::lonnet::plaintext($role);
            $role_select .= '<option value="'.$role.'"'.$roleselected.'>'.$plrole.'</option>';
        }
        $roleselected = '';
        if ($env{'form.showrole'} eq 'cr') {
            $roleselected = ' selected="selected" ';
        }
        $role_select .= '<option value="cr"'.$roleselected.'>'.&mt('Custom role').'</option>'.
                        '</select>';
        $r->print('<label>'.&mt('Role: [_1]',$role_select).'</label>');
    }
    if (!(($context eq 'domain') && ($env{'form.roletype'} eq 'course'))) {
        $r->print(&list_submit_button(&mt('Update Display'))."\n</p>\n");
    }
    my ($indexhash,$keylist) = &make_keylist_array();
    my (%userlist,%userinfo);
    if ($context eq 'domain' && $env{'form.roletype'} eq 'course') {
        my $courseform =
            &Apache::lonhtmlcommon::course_selection($formname,$totcodes,
                                         $codetitles,$idlist,$idlist_titles);
        $r->print('<p>'.&Apache::lonhtmlcommon::start_pick_box()."\n".
                  &Apache::lonhtmlcommon::start_pick_box()."\n".
                  &Apache::lonhtmlcommon::row_title(&mt('Select Course(s)'),
                                                    'LC_oddrow_value')."\n".
                  $courseform."\n".
                  &Apache::lonhtmlcommon::row_closure(1).
                  &Apache::lonhtmlcommon::end_pick_box().'</p>'.
                  '<p>'.&list_submit_button(&mt('Update Display')).
                  "\n</p>\n");
        if ($env{'form.coursepick'}) {
            $r->print('<hr />'.&mt('Searching').' ...<br />&nbsp;<br />');
        }
    } else {
        $r->print('<hr />'.&mt('Searching').' ...<br />&nbsp;<br />');
    }
    $r->rflush();
    if ($context eq 'course') {
        my $classlist = &Apache::loncoursedata::get_classlist();
        my $secidx = &Apache::loncoursedata::CL_SECTION();
        foreach my $student (keys(%{$classlist})) {
            if (exists($permission->{'view_section'})) {
                if ($classlist->{$student}[$secidx] ne $permission->{'view_section'}) {
                    next;
                } else {
                    $userlist{$student} = $classlist->{$student};
                }
            } else {
                $userlist{$student} = $classlist->{$student};
            }
        }
        my $cid =$env{'request.course.id'};
        my ($cnum,$cdom) = &get_course_identity($cid);
        my $showroles;
        if ($env{'form.showrole'} ne 'Any') {
            $showroles = [$env{'form.showrole'}];
        } else {
            $showroles = undef;
        }
        my %advrolehash = &Apache::lonnet::get_my_roles($cnum,$cdom,undef,
                                                        \@statuses,$showroles);
        &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') {
                %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') {
                                my @possroles = &roles_by_context($context);
                            } else {
                                @possroles = ($env{'form.showrole'}); 
                            }
                            foreach my $author (sort(keys(%{$dom_roles{$key}}))) {
                                my ($role,$authorname,$authordom) = split(/:/,$author);
                                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') {
                if ($env{'form.coursepick'}) {
                    my %courses = &process_coursepick();
                    my %allusers; 
                    foreach my $cid (keys(%courses)) {
                        my %coursehash =
                            &Apache::lonnet::coursedescription($cid,{'one_time' => 1});
                        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);
                            unshift(@roles,'cr');
                        } 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);
                        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) {
        if ($context eq 'author') {
            $r->print(&mt('There are no co-authors to display.')."\n");
        } elsif ($context eq 'domain') {
            if ($env{'form.roletype'} eq 'domain') {
                $r->print(&mt('There are no users with domain roles to display.')."\n");
            } elsif ($env{'form.roletype'} eq 'author') {
                $r->print(&mt('There are no authors or co-authors to display.')."\n");
            } elsif ($env{'form.roletype'} eq 'course') {
                $r->print(&mt('There are no course users to display')."\n"); 
            }
        } elsif ($context eq 'course') {
            $r->print(&mt('There are no course users to display.')."\n");
        }
    } 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);
        } else {
            ($usercount) = &show_users_list($r,$context,$env{'form.output'},
                               $permission,$env{'form.Status'},\%userlist,$keylist);
        }
        if (!$usercount) {
            $r->print('<br />'.&mt('There are no users matching the search criteria.')); 
        }
    }
    $r->print('<input type="hidden" name="phase" value="'.
              $env{'form.phase'}.'" /></form>');
}

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

sub gather_userinfo {
    my ($context,$format,$userlist,$indexhash,$userinfo,$rolehash,$permission) = @_;
    foreach my $item (keys(%{$rolehash})) {
        @{$userlist->{$item}} = ();
        my %userdata;
        if ($context eq 'author' || $context eq 'course') { 
            ($userdata{'username'},$userdata{'domain'},$userdata{'role'}) =
                split(/:/,$item);
            ($userdata{'start'},$userdata{'end'})=split(/:/,$rolehash->{$item});
            &build_user_record(\%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(\%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(\%userdata,$userinfo,$indexhash,$uniqid,$userlist);
                    }
                }
            } elsif ($env{'form.roletype'} eq 'course') {
                ($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">';
                                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'}}))) {
                                    $userdata{'extent'} .= $sec.$space.$rolehash->{$item}{$cid}{'secs'}{$sec}.$spanend;
                                }
                            }
                        }
                    }
                }
                &build_user_record(\%userdata,$userinfo,$indexhash,$item,$userlist);
            }
        }
    }
    return;
}

sub build_user_record {
    my ($userdata,$userinfo,$indexhash,$record_key,$userlist) = @_;
    next if ($userdata->{'start'} eq '-1' && $userdata->{'end'} eq '-1');
    &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('Year');
    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('Semester');
    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('Department');
    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;
    if ($coursefilter eq 'all') {
        %courses = &Apache::lonnet::courseiddump($cdom,'.','.','.','.','.',
                                                 undef,undef,'Course');
    } elsif ($coursefilter eq 'category') {
        my $instcode = &instcode_from_coursefilter();
        %courses = &Apache::lonnet::courseiddump($cdom,'.','.',$instcode,'.','.',
                                                 undef,undef,'Course');
    } 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 display_adv_courseroles {
    my $output;
    #
    # List course personnel
    my %coursepersonnel = 
       &Apache::lonnet::get_course_adv_roles($env{'request.course.id'});
    #
    $output = '<br />'.&Apache::loncommon::start_data_table();
    foreach my $role (sort(keys(%coursepersonnel))) {
        next if ($role =~ /^\s*$/);
        $output .= &Apache::loncommon::start_data_table_row().
                  '<td>'.$role.'</td><td>';
        foreach my $user (split(',',$coursepersonnel{$role})) {
            my ($puname,$pudom)=split(':',$user);
            $output .= ' '.&Apache::loncommon::aboutmewrapper(
                       &Apache::loncommon::plainname($puname,$pudom),
                       $puname,$pudom);
        }
        $output .= '</td>'.&Apache::loncommon::end_data_table_row();
    }
    $output .= &Apache::loncommon::end_data_table();
}

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();
    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)=@_;
    #
    # 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'));
    } else {
        push(@sortable,'extent');
    }
    if (!grep(/^\Q$sortby\E$/,@sortable)) {
        $sortby = 'username';
    }
    my $setting = $env{'form.roleaction'};
    my ($cid,$cdom,$cnum,$classgroups,$displayphotos,$displayclickers);
    if ($context eq 'course') {
        $cid=$env{'request.course.id'};
        ($cnum,$cdom) = &get_course_identity($cid);
        ($classgroups) = &Apache::loncoursedata::get_group_memberships(
                                     $userlist,$keylist,$cdom,$cnum);
        if ($mode eq 'autoenroll') {
            $env{'form.showrole'} = 'st';
        } else {
            if (! exists($env{'form.displayphotos'})) {
                $env{'form.displayphotos'} = 'off';
            }
            $displayphotos = $env{'form.displayphotos'};
            if (! exists($env{'form.displayclickers'})) {
                $env{'form.displayclickers'} = 'off';
            }
            $displayclickers = $env{'form.displayclickers'};
            if ($env{'course.'.$cid.'.internal.showphoto'}) {
                $r->print('
<script type="text/javascript">
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>
               ');
            }
            $r->print(<<END);
<input type="hidden" name="displayphotos" value="$displayphotos" />
<input type="hidden" name="displayclickers" value="$displayclickers" />
END
        }
    }
    if ($mode ne 'autoenroll') {
        my $check_uncheck_js = &Apache::loncommon::check_uncheck_jscript();
        my $alert = &mt("You must select at least one user by checking a user's 'Select' checkbox");
        my $singconfirm = &mt(' for a single user');
        my $multconfirm = &mt(' for multiple users');
        my $date_sec_selector = &date_section_javascript($context,$setting,$statusmode); 
        $r->print(<<END);

<script type="text/javascript" language="Javascript">
$check_uncheck_js

function verify_action (field) {
    var numchecked = 0;
    var singconf = '$singconfirm';
    var multconf = '$multconfirm';
    if (field.length > 0) {
        for (i = 0; i < field.length; i++) {
            if (field[i].checked == true) {
               numchecked ++;
            }
        }
    } else {
        if (field.checked == true) {
            numchecked ++;
        }
    }
    if (numchecked == 0) {
        alert("$alert");
    } 
    else {
        var message = document.studentform.bulkaction[document.studentform.bulkaction.selectedIndex].text;
        if (numchecked == 1) { 
            message += singconf;
        } 
        else {
            message += multconf; 
        }
        if (confirm(message)) {
            document.studentform.phase.value = 'bulkchange';
            document.studentform.submit();
        }
    }
}

function username_display_launch(username,domain) {
    var target;
    for (var i=0; i<document.studentform.usernamelink.length; i++) {
        if (document.studentform.usernamelink[i].checked) {
            target = document.studentform.usernamelink[i].value;
        }
    }
    if (target == 'modify') {
        document.studentform.srchterm.value=username;
        document.studentform.srchdomain.value=domain;
        document.studentform.phase.value='get_user_info';
        document.studentform.action.value = 'singleuser';
        document.studentform.submit();
    }
    else {
        document.location.href = '/adm/'+domain+'/'+username+'/aboutme';
    }
}
</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 %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",
                       'type'       => "enroll type/action",
                       'email'      => "email address",
                       'clicker'    => "clicker id",
                       'photo'      => "photo",
                       'extent'     => "extent",
                       'pr'         => "Proceed",
                       'ca'         => "check all",
                       'ua'         => "uncheck all",
                       'ac'         => "Action to take for selected users",
                       'link'       => "Behavior of username links",
                       'aboutme'    => "Display a user's personal page",
                       'modify'     => "Modify a user's information",
                      );
    if ($context eq 'domain' && $env{'form.roletype'} eq 'course') {
        $lt{'extent'} = &mt('Course(s): description, section(s), status');
    } elsif ($context eq 'author') {
        $lt{'extent'} = &mt('Author'); 
    }
    my @cols = ('username','domain','id','fullname');
    if ($context eq 'course') {
        push(@cols,'section');
    }
    if (!($context eq 'domain' && $env{'form.roletype'} eq 'course')) { 
        push(@cols,('start','end'));
    }
    if ($env{'form.showrole'} eq 'Any' || $env{'form.showrole'} eq 'cr') {
        push(@cols,'role');
    }
    if ($context eq 'domain' && ($env{'form.roletype'} eq 'author' ||
                                $env{'form.roletype'} eq 'course')) {
        push (@cols,'extent');
    }
    if (($statusmode eq 'Any') && 
        (!($context eq 'domain' && $env{'form.roletype'} eq 'course'))) {
        push(@cols,'status');
    }
    if ($context eq 'course') {
        push(@cols,'groups');
    }
    push(@cols,'email');

    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'});
    }
    my $results_description;
    if ($mode ne 'autoenroll') {
        $results_description = &results_header_row($rolefilter,$statusmode,
                                                   $context,$permission);
        $r->print('<b>'.$results_description.'</b><br />');
    }
    my ($output,$actionselect);
    if ($mode eq 'html' || $mode eq 'view' || $mode eq 'autoenroll') {
        if ($mode ne 'autoenroll') {
            if ($permission->{'cusr'}) {
                $actionselect = &select_actions($context,$setting,$statusmode);
            }
            $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
            $output = '<p>';
            my @linkdests = ('aboutme');
            if ($permission->{'cusr'}) {
                push (@linkdests,'modify');
                $output .= '<span class="LC_nobreak">'.$lt{'link'}.':&nbsp;';
                my $usernamelink = $env{'form.usernamelink'};
                if ($usernamelink eq '') {
                    $usernamelink = 'aboutme';
                }
                foreach my $item (@linkdests) {
                    my $checkedstr = '';
                    if ($item eq $usernamelink) {
                        $checkedstr = ' checked="checked" ';
                    }
                    $output .= '<label><input type="radio" name="usernamelink" value="'.$item.'"'.$checkedstr.'>&nbsp;'.$lt{$item}.'</label>&nbsp;&nbsp;';
                }
                $output .= '</span><br />';
            } else {
                $output .= &mt("Click on a username to view the user's personal page.").'<br />';
            }
            if ($actionselect) {
                $output .= <<"END"; 
$lt{'ac'}:&nbsp;$actionselect <input type="button" value="$lt{'pr'}" onclick="javascript:verify_action(document.studentform.actionlist)" /></p>
<p><input type="button" value="$lt{'ca'}" onclick="javascript:checkAll(document.studentform.actionlist)" /> &nbsp;
<input type="button" value="$lt{'ua'}" onclick="javascript:uncheckAll(document.studentform.actionlist)" />
END
            }
        }
        $output .= "\n<p>\n".
                  &Apache::loncommon::start_data_table().
                  &Apache::loncommon::start_data_table_header_row();
        if ($mode eq 'autoenroll') {
            $output .= "
 <th><a href=\"javascript:document.studentform.sortby.value='type';document.studentform.submit();\">$lt{'type'}</a></th>
            ";
        } else {
            $output .= "\n".'<th>'.&mt('Count').'</th>'."\n";
            if ($actionselect) {
                $output .= '<th>'.&mt('Select').'</th>'."\n";
            }
        }
        foreach my $item (@cols) {
            $output .= "<th><a href=\"javascript:document.studentform.sortby.value='$item';document.studentform.submit();\">$lt{$item}</a></th>\n";
        }
        my %role_types = &role_type_names();
        if ($context eq 'course' && $mode ne 'autoenroll') {
            if ($env{'form.showrole'} eq 'st' || $env{'form.showrole'} eq 'Any') {
                # Clicker display on or off?
                my %clicker_options = &Apache::lonlocal::texthash(
                                                            'on' => 'Show',
                                                            'off' => 'Hide',
                                                           );
                my $clickerchg = 'on';
                if ($displayclickers eq 'on') {
                    $clickerchg = 'off';
                }
                $output .= '    <th>'."\n".'     '.
                    '<a href="javascript:document.studentform.displayclickers.value='.
                      "'".$clickerchg."'".';document.studentform.submit();">'.
                      $clicker_options{$clickerchg}.'</a>&nbsp;'.$lt{'clicker'}."\n".
                      '    </th>'."\n";

                # Photo display on or off?
                if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) {
                    my %photo_options = &Apache::lonlocal::texthash(
                                                            'on' => 'Show',
                                                            'off' => 'Hide',
                                                                );
                    my $photochg = 'on';
                    if ($displayphotos eq 'on') {
                        $photochg = 'off';
                    }
                    $output .= '    <th>'."\n".'     '.
                '<a href="javascript:document.studentform.displayphotos.value='.
                      "'".$photochg."'".';document.studentform.submit();">'.
                      $photo_options{$photochg}.'</a>&nbsp;'.$lt{'photo'}."\n".
                      '    </th>'."\n";
                }
            }
        }
        $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("Problems occured in writing the csv file.  ".
                      "This error has been logged.  ".
                      "Please alert your LON-CAPA administrator.");
            $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;
    # Get groups, role, permanent e-mail so we can sort on them if
    # necessary.
    foreach my $user (keys(%{$userlist})) {
        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') {
                ($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 (ref($classgroups) eq 'HASH') {
            $groups = $classgroups->{$user};
        }
        if (ref($groups->{active}) eq 'HASH') {
            $userlist->{$user}->[$index{'groups'}] = join(', ',keys(%{$groups->{'active'}}));
        }
        my %emails   = &Apache::loncommon::getemails($uname,$udom);
        if ($emails{'permanentemail'} =~ /\S/) {
            $userlist->{$user}->[$index{'email'}] = $emails{'permanentemail'};
        }
        $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 = 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 $role = $in{'role'};
        $in{'role'}=&Apache::lonnet::plaintext($sdata->[$index{'role'}]); 
        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 ($mode eq 'view' || $mode eq 'html' || $mode eq 'autoenroll') {
            $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;Change</label>';
                    $autocount ++;
                } else {
                    $cellentry = '<table border="0" cellspacing="0"><tr><td rowspan="2"><b>'.&mt('manual').'</b></td><td><nobr><label><input type="checkbox" name="chgmanual" value="'.$in{'username'}.':'.$in{'domain'}.'" />&nbsp;Change</label></nobr></td></tr><tr><td><nobr>';
                    $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 .= '</nobr></td></tr></table>';
                }
                $r->print("<td>$cellentry</td>\n");
            } else {
                $r->print("<td>$rowcount</td>\n");
                $checkval;
                if ($actionselect) {
                    $checkval = $user; 
                    if ($context eq 'course') {
                        if ($role eq 'st') {
                            $checkval .= ':st';
                        }
                        $checkval .= ':'.$in{'section'};
                        if ($role eq 'st') {
                            $checkval .= ':'.$in{'type'}.':'.$in{'lockedtype'};
                        }
                    }
                    $r->print('<td><input type="checkbox" name="actionlist" value="'.
                              $checkval.'"></td>');
                }
            }
            foreach my $item (@cols) {
                if ($item eq 'username') {
                    $r->print('<td>'.&print_username_link($mode,$permission,
                                                          \%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");
                } else {
                    $r->print('<td>'.$in{$item}.'</td>'."\n");
                }
            }
            if (($context eq 'course') && ($mode ne 'autoenroll')) {
                if ($env{'form.showrole'} eq 'st' || $env{'form.showrole'} eq 'Any') {
                    if ($displayclickers eq 'on') {
                        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>  ');
                    }
                    if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) {
                        if ($displayphotos eq 'on' && $sdata->[$index{'role'}] eq 'st') {
                            my $imgurl =
                        &Apache::lonnet::retrievestudentphoto($in{'domain'},$in{'username'},
                                                          'gif','thumbnail');
                            $r->print('    <td align="right"><a href="javascript:photowindow('."'".&Apache::lonnet::studentphoto($in{'domain'},$in{'username'},'jpg')."'".')"><img src="'.$imgurl.'" border="1"></a></td>');
                        } else {
                            $r->print('    <td>&nbsp;</td>  ');
                        }
                    }
                }
            }
            $r->print(&Apache::loncommon::end_data_table_row());
        } elsif ($mode eq 'csv') {
            next if (! defined($CSVfile));
            # no need to bother with $linkto
            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'});
            }
            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($item) && $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') {
            $r->print(&Apache::loncommon::end_data_table().'<br />');
    } elsif ($mode eq 'excel') {
        $excel_workbook->close();
        $r->print('<p><a href="'.$excel_filename.'">'.
                  &mt('Your Excel spreadsheet').'</a> '.&mt('is ready for download').'.</p>'."\n");
    } elsif ($mode eq 'csv') {
        close($CSVfile);
        $r->print('<a href="'.$CSVfilename.'">'.
                  &mt('Your CSV file').'</a> is ready for download.'.
                  "\n");
        $r->rflush();
    }
    if ($mode eq 'autoenroll') {
        return ($usercount,$autocount,$manualcount,$lockcount,$unlockcount);
    } else {
        return ($usercount);
    }
}

sub print_username_link {
    my ($mode,$permission,$in) = @_;
    my $output;
    if ($mode eq 'autoenroll') {
        $output = $in->{'username'};
    } elsif (!$permission->{'cusr'}) {
        $output = &Apache::loncommon::aboutmewrapper($in->{'username'},
                                                     $in->{'username'},
                                                     $in->{'domain'});
    } 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',
             );
    return %lt;
}

sub select_actions {
    my ($context,$setting,$statusmode) = @_;
    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",
    );
    my ($output,$options,%choices);
    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') {
            $options .= '
<option value="chgsec">'.$lt{'chgsec'}.'</option>';
            $choices{'sections'} = 1;
        }
    }
    if ($options) {
        $output = '<select name="bulkaction" onchange="javascript:opendatebrowser(this.form,'."'studentform'".')" />'."\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";
            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;
    if (($context eq 'course') || ($context eq 'domain' && $setting eq 'course'))  {
        $title = &mt('Date and Section selector');
    } else {
        $title = &mt('Date selector');
    }
    my $output = '
<script type="text/javascript">
    var stdeditbrowser;'."\n";
    $output .= <<"ENDONE";
    function opendatebrowser(callingform,formname) {
        var bulkaction = callingform.bulkaction.options[callingform.bulkaction.selectedIndex].value;
        if (bulkaction == 'revoke' || bulkaction == 'delete' || bulkaction == '') {
            return;
        }
        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) = @_;
    my $callingform = $env{'form.callingform'};
    my $formname = 'dateselect';  
    my $groupslist = &get_groupslist();
    my $sec_js = &setsections_javascript($formname,$groupslist);
    my $output = <<"END";
<script type="text/javascript">

$sec_js

function saveselections(formname) {

END
    if ($env{'form.bulkaction'} eq 'chgsec') {
        $output .= <<"END";
        opener.document.$callingform.retainsec.value = formname.retainsec.value;
        setSections(formname);
        if (seccheck == 'ok') {
            opener.document.$callingform.newsecs.value = formname.sections.value;
            window.close();
        }
        return;
END
    } else {
        if ($context eq 'course') {
            if (($env{'form.bulkaction'} eq 'reenable') || 
                ($env{'form.bulkaction'} eq 'activate') || 
                ($env{'form.bulkaction'} eq 'chgdates')) {
                $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;
    window.close();
END
    }
    $output .= '
}
</script>
';
    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 role in a course that is not a student role, a user may have roles in more than one section of a course 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'});
    }
    $output .= '<h3>'.$headertext.'</h3>'.
               '<form name="'.$formname.'" method="post">'."\n".
                $date_items;
    if ($context eq 'course' && $env{'form.bulkaction'} eq 'chgsec') {
        my ($cnum,$cdom) = &get_course_identity();
        my %sections_count =
            &Apache::loncommon::get_sections($cdom,$cnum);
        my $info;
        if ($env{'form.showrole'} eq 'st') {
            $output .= '<p>'.$lt{'fors'}.'</p>'; 
        } elsif ($env{'form.shorole'} 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 $sections_select .= &course_sections(\%sections_count,$env{'form.showrole'});
        my $secbox = '<p>'.&Apache::lonhtmlcommon::start_pick_box()."\n".
                     &Apache::lonhtmlcommon::row_title(&mt('New section to assign'),'LC_oddrow_value')."\n".
                     '<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" />'."\n".
                     '<input type="hidden" name="sections" value="" />'."\n".
                     '</td></tr></table>'."\n".
                     &Apache::lonhtmlcommon::row_closure(1)."\n".
                     &Apache::lonhtmlcommon::end_pick_box().'</p>';
        $output .= $info.$secbox;
    }
    $output .= '<p>'.
&mt('Use "Save" to update the main window with your selections.').'<br /><br />'.
'<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) = @_;
    my %sections_count = &Apache::loncommon::get_sections($cdom,$cnum);
    my $sections_select .= &course_sections(\%sections_count,$role);
    my $secbox = '<p>'.&Apache::lonhtmlcommon::start_pick_box()."\n";
    if ($mode eq 'upload') {
        my ($options,$cb_script,$coursepick) =
            &default_role_selector($context,1);
        $secbox .= &Apache::lonhtmlcommon::row_title('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" />'."\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".
               &Apache::lonhtmlcommon::end_pick_box().'</p>';
    return $secbox;
}

sub results_header_row {
    my ($rolefilter,$statusmode,$context,$permission) = @_;
    my ($description,$showfilter);
    if ($rolefilter ne 'Any') {
        $showfilter = $rolefilter;
    }
    if ($context eq 'course') {
        $description = &mt('Course - ').$env{'course.'.$env{'request.course.id'}.'.description'}.': ';
        if ($statusmode eq 'Expired') {
            $description .= &mt('Users in course with expired [_1] roles',$showfilter);
        } elsif ($statusmode eq 'Future') {
            $description .= &mt('Users in course with future [_1] roles',$showfilter);
        } elsif ($statusmode eq 'Active') {
            $description .= &mt('Users in course with active [_1] roles',$showfilter);
        } else {
            if ($rolefilter eq 'Any') {
                $description .= &mt('All users in course');
            } else {
                $description .= &mt('All users in course with [_1] roles',$rolefilter);
            }
        }
        if (exists($permission->{'view_section'})) {
            if ($env{'form.showrole'} eq 'st') {
                $description .= ' '.&mt('(section [_1] only)',$permission->{'view_section'});
            } elsif ($env{'form.showrole'} eq 'any') {
                $description .= ' '.&mt('(section [_1] only)',$permission->{'view_section'});
            }
        }
    } elsif ($context eq 'author') {
        $description = 
            &mt('Author space for <span class="LC_cusr_emph">[_1]</span>',
        &Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'})).':&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 - ').$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') {
            my $coursefilter = $env{'form.coursepick'};
            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').' - ';
            }
            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 show_drop_list {
    my ($r,$classlist,$keylist,$nosort,$permission)=@_;
    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 ($classgroups) = &Apache::loncoursedata::get_group_memberships(
                                              $classlist,$keylist,$cdom,$cnum);
    #
    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">
$check_uncheck_js
</script>
<p>
<input type="hidden" name="phase" value="four">
END

my %lt=&Apache::lonlocal::texthash('usrn'   => "username",
                                   'dom'    => "domain",
                                   'sn'     => "student name",
                                   'sec'    => "section",
                                   'start'  => "start date",
                                   'end'    => "end date",
                                   'groups' => "active groups",
                                   );
    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>ID</th>
    <th>$lt{'sn'}</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&sortby=username">$lt{'usrn'}</a>
    </th><th>
       <a href="/adm/createuser?action=$action&sortby=domain">$lt{'dom'}</a>
    </th><th>
       <a href="/adm/createuser?action=$action&sortby=id">ID</a>
    </th><th>
       <a href="/adm/createuser?action=$action&sortby=fullname">$lt{'sn'}</a>
    </th><th>
       <a href="/adm/createuser?action=$action&sortby=section">$lt{'sec'}</a>
    </th><th>
       <a href="/adm/createuser?action=$action&sortby=start">$lt{'start'}</a>
    </th><th>
       <a href="/adm/createuser?action=$action&sortby=end">$lt{'end'}</a>
    </th><th>
       <a href="/adm/createuser?action=$action&sortby=groups">$lt{'groups'}</a>
    </th>
END
        $r->print(&Apache::loncommon::end_data_table_header_row());
    }
    #
    # Sort the students
    my %index;
    my $i;
    foreach (@$keylist) {
        $index{$_} = $i++;
    }
    $index{'groups'} = scalar(@$keylist);
    my $index  = $index{$sortby};
    my $second = $index{'username'};
    my $third  = $index{'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->[$index{'username'}];
        my $domain   = $sdata->[$index{'domain'}];
        my $section  = $sdata->[$index{'section'}];
        my $name     = $sdata->[$index{'fullname'}];
        my $id       = $sdata->[$index{'id'}];
        my $start    = $sdata->[$index{'start'}];
        my $end      = $sdata->[$index{'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 $status   = $sdata->[$index{'status'}];
        next if ($status ne 'Active');
        if ($env{'request.course.sec'} ne '') {
            if ($section ne $env{'request.course.sec'}) {
                next;
            }
        }
        my $studentkey = $student.':'.$section;
        my $startitem = '<input type="hidden" name="'.$studentkey.'_start" value="'.$sdata->[$index{'start'}].'" />';
        #
        $r->print(&Apache::loncommon::start_data_table_row());
        $r->print(<<"END");
    <td><input type="checkbox" name="droplist" value="$student"></td>
    <td>$username</td>
    <td>$domain</td>
    <td>$id</td>
    <td>$name</td>
    <td>$section</td>
    <td>$start</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'   => "Expire Users' Roles",
                       'ca'   => "check all",
                       'ua'   => "uncheck all",
                                       );
    $r->print(<<"END");
</p><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><input type=submit value="$lt{'dp'}"></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 .= "<h3>".&mt('Upload a file containing information about users')."</h3>\n";
    $str .= &Apache::loncommon::upfile_select_html();
    $str .= "<p>\n";
    $str .= '<input type="submit" name="fileupload" value="'.
        &mt('Upload file of users').'">'."\n";
    $str .= '<label><input type="checkbox" name="noFirstLine" /> '.
        &mt('Ignore First Line')."</label></p>\n";
    $str .= &Apache::loncommon::help_open_topic("Course_Create_Class_List",
                         &mt("How do I create a users list from a spreadsheet")).
                             "<br />\n";
    $str .= &Apache::loncommon::help_open_topic("Course_Convert_To_CSV",
                           &mt("How do I create a CSV file from a spreadsheet")).
                               "<br />\n";
    $str .= &Apache::loncommon::end_page();
    $r->print($str);
    return;
}

# ================================================= Drop/Add from uploaded file
sub upfile_drop_add {
    my ($r,$context) = @_;
    &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];
        }
    }
    #
    # Store the field choices away
    foreach my $field (qw/username names
                       fname mname lname gen id sec ipwd email role/) {
        $env{'form.'.$field.'_choice'}=$fields{$field};
    }
    &Apache::loncommon::store_course_settings('enrollment_upload',
                                              { 'username_choice' => 'scalar',
                                                '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' });
    #
    my ($startdate,$enddate) = &get_dates_from_form();
    if ($env{'form.makedatesdefault'}) {
        $r->print(&make_dates_default($startdate,$enddate));
    }
    # Determine domain and desired host (home server)
    my $domain=$env{'request.role.domain'};
    my $desiredhost = $env{'form.lcserver'};
    if (lc($desiredhost) eq 'default') {
        $desiredhost = undef;
    } else {
        my %home_servers = &Apache::lonnet::get_servers($domain,'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 ($cid,$defaultsec,$defaultrole,$setting);
    if ($context eq 'domain') {
        $setting = $env{'form.roleaction'};
        if ($setting eq 'domain') {
            $defaultrole = $env{'form.defaultrole'};
        } elsif ($setting eq 'course') {
            $defaultrole = $env{'form.courserole'};
        }  
    } elsif ($context eq 'author') {
        $defaultrole = $env{'form.defaultrole'};
    }
    if ($context eq 'domain' && $setting eq 'course') { 
        if ($env{'form.newsec'} ne '') {
            $defaultsec = $env{'form.newsec'};
        } elsif ($env{'form.defaultsec'} ne '') {
            $defaultsec = $env{'form.defaultsec'}
        }
    }
    if ($env{'request.course.id'} ne '') {
        $cid = $env{'request.course.id'};
    } elsif ($env{'form.defaultdomain'} ne '' && $env{'form.defaultcourse'} ne '') {
        $cid = $env{'form.defaultdomain'}.'_'.
               $env{'form.defaultcourse'};
    }
    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");
        }
        my %counts = (
                       user => 0,
                       auth => 0,
                       role => 0,
                     );
        my $flushc=0;
        my %student=();
        my %curr_groups;
        my %userchg;
        if ($context eq 'course') {
            # Get information about course groups
            %curr_groups = &Apache::longroup::coursegroups();
        }
        my (%curr_rules,%got_rules,%alerts);
        # Get new users list
        foreach (@userdata) {
            my %entries=&Apache::loncommon::record_sep($_);
            # Determine user name
            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'}})) {
                    $r->print('<br />'.
      &mt('<b>[_1]</b>: Unacceptable username for user [_2] [_3] [_4] [_5]',
          $entries{$fields{'username'}},$fname,$mname,$lname,$gen).
                              '</b>');
                } else {
                    my $username = $entries{$fields{'username'}};
                    my $sec;
                    if ($context eq 'course' || $setting eq 'course') {
                        # determine section number
                        if (defined($fields{'sec'})) {
                            if (defined($entries{$fields{'sec'}})) {
                                $sec=$entries{$fields{'sec'}};
                            }
                        } else {
                            $sec = $defaultsec;
                        }
                        # remove non alphanumeric values from section
                        $sec =~ s/\W//g;
                        if ($sec eq "none" || $sec eq 'all') {
                            $r->print('<br />'.
      &mt('<b>[_1]</b>: Unable to enroll: section name "[_2]" for user [_3] [_4] [_5] [_6] is a reserved word.',
                                      $username,$sec,$fname,$mname,$lname,$gen));
                            next;
                        } elsif (($sec ne '') && (exists($curr_groups{$sec}))) {
                            $r->print('<br />'.
      &mt('<b>[_1]</b>: Unable to enroll: section name "[_2]" for user [_3] [_4] [_5] [_6] is a course group. Section names and group names must be distinct.',
                                      $username,$sec,$fname,$mname,$lname,$gen));
                            next;
                        }
                    }
                    # 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'})) {
                        if (defined($entries{$fields{'email'}})) {
                            $email=$entries{$fields{'email'}};
                            unless ($email=~/^[^\@]+\@[^\@]+$/) { $email=''; }                        }
                    }
                    # 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'}}) {
                            my @poss_roles = 
                                 &curr_role_permissions($context,$setting);
                            if (grep(/^\Q$entries{$fields{'role'}}\E/,@poss_roles)) {
                                $role=$entries{$fields{'role'}};
                            } else {
                                my $rolestr = join(', ',@poss_roles);
                                $r->print('<br />'.
      &mt('<b>[_1]</b>: You do not have permission to add the requested role [_2] for the user.',$entries{$fields{'username'}},$entries{$fields{'role'}}).'<br />'.&mt('Allowable role(s) is/are: [_1].',$rolestr)."\n");
                                next;
                            }
                        }
                    }
                    if ($role eq '') {
                        $role = $defaultrole;
                    }
                    # Clean up whitespace
                    foreach (\$domain,\$username,\$id,\$fname,\$mname,
                             \$lname,\$gen,\$sec,\$role) {
                        $$_ =~ s/(\s+$|^\s+)//g;
                    }
                    # check against rules
                    my $checkid = 0;
                    my $newuser = 0;
                    my (%rulematch,%inst_results,%idinst_results);
                    my $uhome=&Apache::lonnet::homeserver($username,$domain);
                    if ($uhome eq 'no_host') {
                        $checkid = 1;
                        $newuser = 1;
                        my $checkhash;
                        my $checks = { 'username' => 1 };
                        $checkhash->{$username.':'.$domain} = { 'newuser' => 1, };
                        &Apache::loncommon::user_rule_check($checkhash,$checks,
                            \%alerts,\%rulematch,\%inst_results,\%curr_rules,
                            \%got_rules);
                        if (ref($alerts{'username'}) eq 'HASH') {
                            if (ref($alerts{'username'}{$domain}) eq 'HASH') {
                                next if ($alerts{'username'}{$domain}{$username});
                            }
                        }
                    } else {
# FIXME check if user info can be updated.   
                    }
                    if ($id ne '') {
                        if (!$newuser) {
                            my %idhash = &Apache::lonnet::idrget($domain,($username));
                            if ($idhash{$username} ne $id) {
                                $checkid = 1;
                            }
                        }
                        if ($checkid) {
                            my $checkhash;
                            my $checks = { 'id' => 1 };
                            $checkhash->{$username.':'.$domain} = { 'newuser' => $newuser,
                                                                    'id'  => $id };
                            &Apache::loncommon::user_rule_check($checkhash,$checks,
                                \%alerts,\%rulematch,\%idinst_results,\%curr_rules,
                                \%got_rules);
                            if (ref($alerts{'id'}) eq 'HASH') {
                                if (ref($alerts{'id'}{$domain}) eq 'HASH') {
                                    next if ($alerts{'id'}{$domain}{$id});
                                }
                            }
                        }
                    }
                    if ($password || $env{'form.login'} eq 'loc') {
                        my ($userresult,$authresult,$roleresult);
                        if ($role eq 'st') {
                            &modifystudent($domain,$username,$cid,$sec,
                                           $desiredhost);
                            $roleresult = 
                                &Apache::lonnet::modifystudent
                                    ($domain,$username,$id,$amode,$password,
                                     $fname,$mname,$lname,$gen,$sec,$enddate,
                                     $startdate,$env{'form.forceid'},
                                     $desiredhost,$email);
                        } else {
                            ($userresult,$authresult,$roleresult) = 
                                &modifyuserrole($context,$setting,
                                    $changeauth,$cid,$domain,$username, 
                                    $id,$amode,$password,$fname,
                                    $mname,$lname,$gen,$sec,
                                    $env{'form.forceid'},$desiredhost,
                                    $email,$role,$enddate,$startdate,$checkid);
                        }
                        $flushc = 
                            &user_change_result($r,$userresult,$authresult,
                                                $roleresult,\%counts,$flushc,
                                                $username,%userchg);
                    } else {
                        if ($context eq 'course') {
                            $r->print('<br />'. 
      &mt('<b>[_1]</b>: Unable to enroll.  No password specified.',$username)
                                     );
                        } elsif ($context eq 'author') {
                            $r->print('<br />'.
      &mt('<b>[_1]</b>: Unable to add co-author.  No password specified.',$username)
                                     );
                        } else {
                            $r->print('<br />'.
      &mt('<b>[_1]</b>: Unable to add user.  No password specified.',$username)
                                     );
                        }
                    }
                }
            }
        } # end of foreach (@userdata)
        # Flush the course logs so reverse user roles immediately updated
        &Apache::lonnet::flushcourselogs();
        $r->print("</p>\n<p>\n".&mt('Processed [_1] user(s).',$counts{'user'}).
                  "</p>\n");
        if ($counts{'role'} > 0) {
            $r->print("<p>\n".
                      &mt('Roles added for [_1] users. If user is active, the new role will be available when the user next logs in to LON-CAPA.',$counts{'role'})."</p>\n");
        }
        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));
        $r->print('<form name="uploadresult" action="/adm/createuser">');
        $r->print(&Apache::lonhtmlcommon::echo_form_input(['phase','prevphase','currstate']));
        $r->print('</form>');
        #####################################
        #           Drop students           #
        #####################################
        if ($env{'form.fullup'} eq 'yes') {
            $r->print('<h3>'.&mt('Dropping Students')."</h3>\n");
            #  Get current classlist
            my ($classlist,$keylist)=&Apache::loncoursedata::get_classlist();
            if (! defined($classlist)) {
                $r->print(&mt('There are no students currently enrolled.').
                          "\n");
            } else {
                # Remove the students we just added from the list of students.
                foreach (@userdata) {
                    my %entries=&Apache::loncommon::record_sep($_);
                    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,$keylist,'nosort');
            }
        }
    } # end of unless
}

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

# ========================================================= Menu Phase Two Drop
sub print_drop_menu {
    my ($r,$context,$permission) = @_;
    $r->print('<h3>'.&mt("Drop Students").'</h3>'."\n".
              '<form name="studentform" method="post">'."\n");
    my $cid=$env{'request.course.id'};
    my ($classlist,$keylist) = &Apache::loncoursedata::get_classlist();
    if (! defined($classlist)) {
        $r->print(&mt('There are no students currently enrolled.')."\n");
        return;
    }
    # Print out the available choices
    &show_drop_list($r,$classlist,$keylist,$permission);
    $r->print('</form>'. &Apache::loncommon::end_page());
    return;
}

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

sub update_user_list {
    my ($r,$context,$setting,$choice) = @_;
    my $now = time;
    my $count=0;
    my @changelist;
    if ($choice ne '') {
        @changelist = &Apache::loncommon::get_env_multiple('form.actionlist');
    } else {
        @changelist = &Apache::loncommon::get_env_multiple('form.droplist');
    }
    my %result_text = ( ok    => { 'revoke'   => 'Revoked',
                                   'delete'   => 'Deleted',
                                   'reenable' => 'Re-enabled',
                                   'activate' => 'Activated',
                                   'chgdates' => 'Changed Access Dates for',
                                   'chgsec'   => 'Changed section 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);
        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) = split(/\:/,$item,-1);
            $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) = 
                    split(/\:/,$item);
                $scope = '/'.$cid;
                $scope =~s/\_/\//g;
                if ($sec ne '') {
                    $scope .= '/'.$sec;
                }
            }
        }
        my $plrole = &Apache::lonnet::plaintext($role);
        my ($uid,$first,$middle,$last,$gene,$sec);
        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);
        } 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);
            } else {
                $result = 
                    &Apache::lonnet::revokerole($udom,$uname,$scope,$role);
            }
        } elsif ($choice eq 'delete') {
            $start = -1;
            $end = -1;
            if ($role eq 'st') {
# FIXME - how does role deletion affect classlist?
                &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid);
            } else {
                $result =
                    &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$now,
                                                0,1);
             }
        } 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);
                } else {
                    $result = 
                        &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
                                                    $now);
                }
            } 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);
                } else {
                    $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
                                            $now);
                }
            } 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);
                } else {
                    $result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
                                                $start);
                }
            } elsif ($choice eq 'chgsec') {
                my (@newsecs,$revresult,$nochg,@retained);
                if ($role ne 'cc') {
                    @newsecs = split(/,/,$env{'form.newsecs'});
                }
                # remove existing section if not to be retained.   
                if (!$env{'form.retainsec'}) {
                    if ($sec eq '') {
                        if (@newsecs == 0) {
                            $result = &mt('No change in section assignment (none)');
                            $nochg = 1;
                        }
                    } else {
                        if (!grep(/^\Q$sec\E$/,@newsecs)) {
                            $revresult =
                               &Apache::lonnet::revokerole($udom,$uname,$scope,$role);
                        } else {
                            push(@retained,$sec);
                        }
                    }
                } else {
                    push(@retained,$sec);
                }
                # add new sections
                if (@newsecs == 0) {
                    if (!$nochg) {
                        if ($sec ne '') {
                            if ($role eq 'st') {
                                $result = 
                                    &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,undef,$end,$start,$type,$locktype,$cid);
                            } else {
                                my $newscope = $scopestem;
                                $result = &Apache::lonnet::assignrole($udom,$uname,$newscope,$role,$end,$start);
                            }
                        }
                    }
                } 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);
                            } else {
                                my $newscope = $scopestem;
                                if ($newsec ne '') {
                                   $newscope .= '/'.$newsec;
                                }
                                $result = &Apache::lonnet::assignrole($udom,$uname,
                                                        $newscope,$role,$end,$start);
                            }
                        }
                    }
                }
            }
        }
        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:') {
            $r->print(&mt("$result_text{'ok'}{$choice} role of '[_1]' in [_2] for [_3]",
                          $plrole,$extent,$uname.':'.$udom).'<br />');
            $count++;
        } else {
            $r->print(
                &mt("Error $result_text{'error'}{$choice} [_1] in [_2] for [_3]:[_4]",
                    $plrole,$extent,$uname.':'.$udom,$result).'<br />');
        }
    }
    $r->print('<p><b>'.&mt("$result_text{'ok'}{$choice} role(s) for [quant,_1,user,users,users].",$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
        &Apache::lonnet::flushcourselogs();
    }
    if ($env{'form.makedatesdefault'}) {
        if ($choice eq 'chgdates' || $choice eq 'reenable' || $choice eq 'activate') {
            $r->print(&make_dates_default($startdate,$enddate));
        }
    }
}

sub classlist_drop {
    my ($scope,$uname,$udom,$now,$action) = @_;
    my ($cdom,$cnum) = ($scope=~m{^/($match_domain)/($match_courseid)});
    my $cid=$cdom.'_'.$cnum;
    my $user = $uname.':'.$udom;
    if ($action eq 'drop') {
        if (!&active_student_roles($cnum,$cdom,$uname,$udom)) {
            my $result =
                &Apache::lonnet::cput('classlist',
                                      { $user => $now },
                                      $env{'course.'.$cid.'.domain'},
                                      $env{'course.'.$cid.'.num'});
            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();
    return <<"END";
function validate(caller) {
    var groups = new Array($groupslist);
    var secname = caller.value;
    if ((secname == 'all') || (secname == 'none')) {
        alert("'"+secname+"' may not be used as the name for a section, as it is a reserved word.\\nPlease choose a different section name.");
        return 'error';
    }
    if (secname != '') {
        for (var k=0; k<groups.length; k++) {
            if (secname == groups[k]) {
                alert("'"+secname+"' may not be used as the name for a section, as it is the name of a course group.\\nSection names and group names must be distinct. Please choose a different section name.");
                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) = @_;
    my $output = '';
    my @sections = (sort {$a <=> $b} keys %{$sections_count});
    if (scalar(@sections) == 1) {
        $output = '<select name="currsec_'.$role.'" >'."\n".
                  '  <option value="">Select</option>'."\n".
                  '  <option value="">No section</option>'."\n".
                  '  <option value="'.$sections[0].'" >'.$sections[0].'</option>'."\n";
    } else {
        $output = '<select name="currsec_'.$role.'" ';
        my $multiple = 4;
        if (scalar(@sections) < 4) { $multiple = scalar(@sections); }
        $output .= 'multiple="multiple" size="'.$multiple.'">'."\n";
        foreach my $sec (@sections) {
            $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 ($form,$groupslist) = @_;
    my ($checkincluded,$finish,$roleplace,$setsection_js);
    if ($form eq 'cu') {
        $checkincluded = 'formname.elements[i-1].checked == true';
        $finish = 'formname.submit()';
        $roleplace = 3;
    } else {
        $checkincluded = 'formname.name == "'.$form.'"'; 
        $finish = "seccheck = 'ok';";
        $roleplace = 1;
        $setsection_js = "var seccheck = 'alert';"; 
    }
    my %alerts = &Apache::lonlocal::texthash(
                    secd => 'Section designations do not apply to Course Coordinator roles.',
                    accr => 'A course 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.',
                    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.',
                 );                
    $setsection_js .= <<"ENDSECCODE";

function setSections(formname) {
    var re1 = /^currsec_/;
    var groups = new Array($groupslist);
    for (var i=0;i<formname.elements.length;i++) {
        var str = formname.elements[i].name;
        var checkcurr = str.match(re1);
        if (checkcurr != null) {
            if ($checkincluded) {
                var match = str.split('_');
                var role = match[$roleplace];
                if (role == 'cc') {
                    alert("$alerts{'secd'}\\n$alerts{'accr'}");
                }
                else {
                    var sections = '';
                    var numsec = 0;
                    var sections;
                    for (var j=0; j<formname.elements[i].length; j++) {
                        if (formname.elements[i].options[j].selected == true ) {
                            if (formname.elements[i].options[j].value != "") {
                                if (numsec == 0) {
                                    if (formname.elements[i].options[j].value != "") {
                                        sections = formname.elements[i].options[j].value;
                                        numsec ++;
                                    }
                                }
                                else {
                                    sections = sections + "," +  formname.elements[i].options[j].value
                                    numsec ++;
                                }
                            }
                        }
                    }
                    if (numsec > 0) {
                        if (formname.elements[i+1].value != "" && formname.elements[i+1].value != null) {
                            sections = sections + "," +  formname.elements[i+1].value;
                        }
                    }
                    else {
                        sections = formname.elements[i+1].value;
                    }
                    var newsecs = formname.elements[i+1].value;
                    var numsplit;
                    if (newsecs != null && newsecs != "") {
                        numsplit = newsecs.split(/,/g);
                        numsec = numsec + numsplit.length;
                    }

                    if ((role == 'st') && (numsec > 1)) {
                        alert("$alerts{'inea'} $alerts{'youh'} "+numsec+" $alerts{'secs'}\\n$alerts{'plmo'}")
                        return;
                    }
                    else {
                        if (numsplit != null) {
                            for (var j=0; j<numsplit.length; j++) {
                                if ((numsplit[j] == 'all') ||
                                    (numsplit[j] == 'none')) {
                                    alert("'"+numsplit[j]+"' $alerts{'mayn'}\\n$alerts{'plch'}");
                                    return;
                                }
                                for (var k=0; k<groups.length; k++) {
                                    if (numsplit[j] == groups[k]) {
                                        alert("'"+numsplit[j]+"' $alerts{'mnot'}\\n$alerts{'secn'}");
                                        return;
                                    }
                                }
                            }
                        }
                        formname.elements[i+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 (ref($domconf{'usercreation'}) eq 'HASH') {
        if (ref($domconf{'usercreation'}{'cancreate'}) eq 'HASH') {
            if ($context eq 'course' || $context eq 'author') {
                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 ($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) = @_;
    my $usertype;
    if (ref($rules) eq 'HASH') {
        my @user_rules = keys(%{$rules});
        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) = @_;
    my @allroles;
    if ($context eq 'course') {
        @allroles = ('st','ad','ta','ep','in','cc');
        if ($custom) {
            push(@allroles,'cr');
        }
    } elsif ($context eq 'author') {
        @allroles = ('ca','aa');
    } elsif ($context eq 'domain') {
        @allroles = ('li','dg','sc','au','dc');
    }
    return @allroles;
}

sub get_permission {
    my ($context,$roles) = @_;
    my %permission;
    if ($context eq 'course') {
        my $custom = 1;
        my @allroles = &roles_by_context($context,$custom);
        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;
        }
    } 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 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) = @_;
    my $dc_setcourse_code;
    my $cctext = &Apache::lonnet::plaintext('cc');
    my %alerts = &sectioncheck_alerts();
    my $role = 'role';
    if ($mode eq 'upload') {
        $role = 'courserole';
    }
    $dc_setcourse_code = (<<"SCRIPTTOP");
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)) {
            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]) {
                        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 = "";
        }
SCRIPTTOP
    if ($mode ne 'upload') {
        $dc_setcourse_code .= (<<"ENDSCRIPT");
        var coursename = "_$env{'request.role.domain'}"+"_"+course+"_"+userrole
        var numcourse = getIndex(document.$formname.dccourse);
        if (numcourse == "-1") {
            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
            }
        }
    }
    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
}

sub sectioncheck_alerts {
    my %alerts = &Apache::lonlocal::texthash(
                    curd => 'You must select a course in the current domain',
                    inea => 'In each course, each user may only have one student 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',
                    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'
                 );
    return %alerts;
}


1;


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