--- loncom/interface/londocs.pm	2022/12/31 14:08:59	1.690
+++ loncom/interface/londocs.pm	2023/07/20 22:12:39	1.704
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Documents
 #
-# $Id: londocs.pm,v 1.690 2022/12/31 14:08:59 raeburn Exp $
+# $Id: londocs.pm,v 1.704 2023/07/20 22:12:39 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -45,7 +45,6 @@ use Apache::lontemplate();
 use Apache::lonsimplepage();
 use Apache::lonhomework();
 use Apache::lonpublisher();
-use Apache::lonparmset();
 use Apache::loncourserespicker();
 use HTML::Entities;
 use HTML::TokeParser;
@@ -719,7 +718,7 @@ sub group_import {
                 $url = $1;
                 my $marker = $2;
                 my $info = $3;
-                my ($toolid,%toolhash,%toolsettings);
+                my ($toolid,$toolprefix,$tooltype,%toolhash,%toolsettings);
                 my @extras = ('linktext','explanation','crslabel','crstitle','crsappend');
                 my @toolinfo = split(/:/,$info);
                 if ($residx) {
@@ -728,6 +727,12 @@ sub group_import {
                 } else {
                     $toolid = shift(@toolinfo);
                 }
+                if ($toolid =~ /^c/) {
+                    $tooltype = 'crs';
+                    $toolprefix = 'c';
+                } else {
+                    $tooltype = 'dom';
+                }
                 $toolid =~ s/\D//g;
                 ($toolhash{'target'},$toolhash{'width'},$toolhash{'height'},
                  $toolhash{'linktext'},$toolhash{'explanation'},$toolhash{'crslabel'},
@@ -741,127 +746,130 @@ sub group_import {
                     $toolhash{'gradable'} =~ s/\D+//g;
                 }
                 if (ref($ltitoolsref) eq 'HASH') {
-                    if (ref($ltitoolsref->{$toolid}) eq 'HASH') {
-                        my @deleted;
-                        $toolhash{'id'} = $toolid;
-                        if (($toolhash{'target'} eq 'iframe') || ($toolhash{'target'} eq 'tab') ||
-                            ($toolhash{'target'} eq 'window')) {
-                            if ($toolhash{'target'} eq 'window') {
-                                foreach my $item ('width','height') {
-                                    $toolhash{$item} =~ s/^\s+//;
-                                    $toolhash{$item} =~ s/\s+$//;
-                                    if ($toolhash{$item} =~ /\D/) {
-                                        delete($toolhash{$item});
-                                        if ($residx) {
-                                            if ($toolsettings{$item}) {
-                                                push(@deleted,$item);
+                    if (ref($ltitoolsref->{$tooltype}) eq 'HASH') {
+                        if (ref($ltitoolsref->{$tooltype}->{$toolid}) eq 'HASH') {
+                            my %tools = %{$ltitoolsref->{$tooltype}->{$toolid}};
+                            my @deleted;
+                            $toolhash{'id'} = $toolprefix.$toolid;
+                            if (($toolhash{'target'} eq 'iframe') || ($toolhash{'target'} eq 'tab') ||
+                                ($toolhash{'target'} eq 'window')) {
+                                if ($toolhash{'target'} eq 'window') {
+                                    foreach my $item ('width','height') {
+                                        $toolhash{$item} =~ s/^\s+//;
+                                        $toolhash{$item} =~ s/\s+$//;
+                                        if ($toolhash{$item} =~ /\D/) {
+                                            delete($toolhash{$item});
+                                            if ($residx) {
+                                                if ($toolsettings{$item}) {
+                                                    push(@deleted,$item);
+                                                }
                                             }
                                         }
                                     }
                                 }
-                            }
-                        } elsif ($residx) {
-                            $toolhash{'target'} = $toolsettings{'target'};
-                            if ($toolhash{'target'} eq 'window') {
-                                foreach my $item ('width','height') {
-                                    $toolhash{$item} = $toolsettings{$item};
+                            } elsif ($residx) {
+                                $toolhash{'target'} = $toolsettings{'target'};
+                                if ($toolhash{'target'} eq 'window') {
+                                    foreach my $item ('width','height') {
+                                        $toolhash{$item} = $toolsettings{$item};
+                                    }
+                                }
+                            } elsif (ref($tools{'display'}) eq 'HASH') {
+                                $toolhash{'target'} = $tools{'display'}{'target'};
+                                if ($toolhash{'target'} eq 'window') {
+                                    $toolhash{'width'} = $tools{'display'}{'width'};
+                                    $toolhash{'height'} = $tools{'display'}{'height'};
                                 }
                             }
-                        } elsif (ref($ltitoolsref->{$toolid}->{'display'}) eq 'HASH') {
-                            $toolhash{'target'} = $ltitoolsref->{$toolid}->{'display'}->{'target'};
-                            if ($toolhash{'target'} eq 'window') {
-                                $toolhash{'width'} = $ltitoolsref->{$toolid}->{'display'}->{'width'};
-                                $toolhash{'height'} = $ltitoolsref->{$toolid}->{'display'}->{'height'};
-                            }
-                        }
-                        if ($toolhash{'target'} eq 'iframe') {
-                            foreach my $item ('width','height','linktext','explanation') {
-                                delete($toolhash{$item});
-                                if ($residx) {
-                                    if ($toolsettings{$item}) {
-                                        push(@deleted,$item);
+                            if ($toolhash{'target'} eq 'iframe') {
+                                foreach my $item ('width','height','linktext','explanation') {
+                                    delete($toolhash{$item});
+                                    if ($residx) {
+                                        if ($toolsettings{$item}) {
+                                            push(@deleted,$item);
+                                        }
                                     }
                                 }
-                            }
-                        } elsif ($toolhash{'target'} eq 'tab') {
-                            foreach my $item ('width','height') {
-                                delete($toolhash{$item});
-                                if ($residx) {
-                                    if ($toolsettings{$item}) {
-                                        push(@deleted,$item);
+                            } elsif ($toolhash{'target'} eq 'tab') {
+                                foreach my $item ('width','height') {
+                                    delete($toolhash{$item});
+                                    if ($residx) {
+                                        if ($toolsettings{$item}) {
+                                            push(@deleted,$item);
+                                        }
                                     }
                                 }
                             }
-                        }
-                        if (ref($ltitoolsref->{$toolid}->{'crsconf'}) eq 'HASH') {
-                            foreach my $item ('label','title','linktext','explanation') {
-                                my $crsitem;
-                                if (($item eq 'label') || ($item eq 'title')) {
-                                    $crsitem = 'crs'.$item;
-                                } else {
-                                    $crsitem = $item;
-                                }
-                                if ($ltitoolsref->{$toolid}->{'crsconf'}->{$item}) {
-                                    $toolhash{$crsitem} =~ s/^\s+//;
-                                    $toolhash{$crsitem} =~ s/\s+$//;
-                                    if ($toolhash{$crsitem} eq '') {
+                            if (ref($tools{'crsconf'}) eq 'HASH') {
+                                foreach my $item ('label','title','linktext','explanation') {
+                                    my $crsitem;
+                                    if (($item eq 'label') || ($item eq 'title')) {
+                                        $crsitem = 'crs'.$item;
+                                    } else {
+                                        $crsitem = $item;
+                                    }
+                                    if ($tools{'crsconf'}{$item}) {
+                                        $toolhash{$crsitem} =~ s/^\s+//;
+                                        $toolhash{$crsitem} =~ s/\s+$//;
+                                        if ($toolhash{$crsitem} eq '') {
+                                            delete($toolhash{$crsitem});
+                                        }
+                                    } else {
                                         delete($toolhash{$crsitem});
                                     }
-                                } else {
-                                    delete($toolhash{$crsitem});
-                                }
-                                if (($residx) && (exists($toolsettings{$crsitem}))) {
-                                    unless (exists($toolhash{$crsitem})) {
-                                        push(@deleted,$crsitem);
+                                    if (($residx) && (exists($toolsettings{$crsitem}))) {
+                                        unless (exists($toolhash{$crsitem})) {
+                                            push(@deleted,$crsitem);
+                                        }
                                     }
                                 }
                             }
-                        }
-                        if ($toolhash{'passback'}) {
-                            my $gradesecret = UUID::Tiny::create_uuid_as_string(UUID_V4);
-                            $toolhash{'gradesecret'} = $gradesecret;
-                            $toolhash{'gradesecretdate'} = time;
-                        }
-                        if ($toolhash{'roster'}) {
-                            my $rostersecret = UUID::Tiny::create_uuid_as_string(UUID_V4);
-                            $toolhash{'rostersecret'} = $rostersecret;
-                            $toolhash{'rostersecretdate'} = time;
-                        }
-                        my $changegradable;
-                        if (($residx) && ($folder =~ /^default/)) {
-                            if ($toolsettings{'gradable'}) {
-                                unless (($toolhash{'gradable'}) || (defined($LONCAPA::map::zombies[$residx]))) {
-                                    push(@deleted,'gradable');
-                                    $changegradable = 1;
-                                }
-                            } elsif ($toolhash{'gradable'}) {
-                                $changegradable = 1;
+                            if ($toolhash{'passback'}) {
+                                my $gradesecret = UUID::Tiny::create_uuid_as_string(UUID_V4);
+                                $toolhash{'gradesecret'} = $gradesecret;
+                                $toolhash{'gradesecretdate'} = time;
+                            }
+                            if ($toolhash{'roster'}) {
+                                my $rostersecret = UUID::Tiny::create_uuid_as_string(UUID_V4);
+                                $toolhash{'rostersecret'} = $rostersecret;
+                                $toolhash{'rostersecretdate'} = time;
                             }
-                            if (($caller eq 'londocs') && (defined($LONCAPA::map::zombies[$residx]))) {
-                                $changegradable = 1;
+                            my $changegradable;
+                            if (($residx) && ($folder =~ /^default/)) {
                                 if ($toolsettings{'gradable'}) {
-                                    $toolhash{'gradable'} = 1;
+                                    unless (($toolhash{'gradable'}) || (defined($LONCAPA::map::zombies[$residx]))) {
+                                        push(@deleted,'gradable');
+                                        $changegradable = 1;
+                                    }
+                                } elsif ($toolhash{'gradable'}) {
+                                    $changegradable = 1;
+                                }
+                                if (($caller eq 'londocs') && (defined($LONCAPA::map::zombies[$residx]))) {
+                                    $changegradable = 1;
+                                    if ($toolsettings{'gradable'}) {
+                                        $toolhash{'gradable'} = 1;
+                                    }
                                 }
                             }
-                        }
-                        my $putres = &Apache::lonnet::put('exttool_'.$marker,\%toolhash,$coursedom,$coursenum);
-                        if ($putres eq 'ok') {
-                            if (@deleted) {
-                                &Apache::lonnet::del('exttool_'.$marker,\@deleted,$coursedom,$coursenum);
-                            }
-                            if (($changegradable) && ($folder =~ /^default/)) {
-                                my $val;
-                                if ($toolhash{'gradable'}) {
-                                    $val = 'yes';
-                                } else {
-                                    $val = 'no';
+                            my $putres = &Apache::lonnet::put('exttool_'.$marker,\%toolhash,$coursedom,$coursenum);
+                            if ($putres eq 'ok') {
+                                if (@deleted) {
+                                    &Apache::lonnet::del('exttool_'.$marker,\@deleted,$coursedom,$coursenum);
                                 }
-                                &LONCAPA::map::storeparameter($residx,'parameter_0_gradable',$val,
-                                                              'string_yesno');
-                                &remember_parms($residx,'gradable','set',$val);
+                                if (($changegradable) && ($folder =~ /^default/)) {
+                                    my $val;
+                                    if ($toolhash{'gradable'}) {
+                                        $val = 'yes';
+                                    } else {
+                                        $val = 'no';
+                                    }
+                                    &LONCAPA::map::storeparameter($residx,'parameter_0_gradable',$val,
+                                                                  'string_yesno');
+                                    &remember_parms($residx,'gradable','set',$val);
+                                }
+                            } else {
+                                return (&mt('Failed to save update to external tool.'),1);
                             }
-                        } else {
-                            return (&mt('Failed to save update to external tool.'),1);
                         }
                     }
                 }
@@ -1207,7 +1215,13 @@ sub docs_change_log {
 	}
 	$r->print('</ul>');
 	if ($docslog{$id}{'logentry'}{'parameter_res'}) {
-	    $r->print(&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'parameter_res'}))[0]).':<ul>');
+            my ($title,$url) = split(/\:/,$docslog{$id}{'logentry'}{'parameter_res'},3);
+            if ($title eq '') {
+                ($title) = ($url =~ m{/([^/]+)$});
+            } elsif ($is_supp) {
+                $title = &Apache::loncommon::parse_supplemental_title($title);
+            }
+            $r->print(&LONCAPA::map::qtescape($title).':<ul>');
 	    foreach my $parameter ('randompick','hiddenresource','encrypturl','randomorder','gradable') {
 		if ($docslog{$id}{'logentry'}{'parameter_action_'.$parameter}) {
 # FIXME: internationalization seems wrong here
@@ -1405,7 +1419,7 @@ sub print_paste_buffer {
     }
 
     my @currpaste = split(/,/,$env{'docs.markedcopies'});
-    my ($pasteitems,@pasteable);
+    my ($pasteitems,@pasteable,$same_institution,$checkedsameinst);
     my $clipboardcount = 0;
 
 # Construct identifiers for current contents of user's paste buffer
@@ -1418,11 +1432,13 @@ sub print_paste_buffer {
             ($url ne '')) {
             $clipboardcount ++;
             my ($is_external,$othercourse,$fromsupp,$is_uploaded_map,$parent,
-                $canpaste,$nopaste,$othercrs,$areachange,$is_exttool);
+                $canpaste,$nopaste,$othercrs,$areachange,$is_exttool,$toolcdom,
+                $toolcnum,$marker);
             my $extension = (split(/\./,$env{'docs.markedcopy_url_'.$suffix}))[-1];
             if ($url =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?:&colon;|:))//} ) {
                 $is_external = 1;
-            } elsif ($url =~ m{^/adm/$match_domain/$match_courseid/\d+/ext\.tool$}) {
+            } elsif ($url =~ m{^/adm/($match_domain)/($match_courseid)/(\d+)/ext\.tool$}) {
+                ($toolcdom,$toolcnum,$marker) = ($1,$2,$3);
                 $is_exttool = 1;
             }
             if ($folder =~ /^supplemental/) {
@@ -1460,17 +1476,56 @@ sub print_paste_buffer {
                     if ($cid ne $env{'request.course.id'}) {
                         my ($srcdom,$srcnum) = split(/_/,$cid);
                         if ($env{"user.priv.cm./$srcdom/$srcnum"} =~ /\Q:mdc&F\E/) {
-                            if (($is_exttool) && ($srcdom ne $coursedom)) {
-                                $canpaste = 0;
-                                $nopaste = &mt('Paste from another domain unavailable.');
-                            } else {
-                                $othercrs = '<br />'.&mt('(from another course)');
+                            if ($is_exttool) {
+                                if ($toolcdom ne $coursedom) {
+                                    $canpaste = 0;
+                                    $nopaste = &mt('Paste from another domain unavailable.');
+                                } elsif ($toolcnum ne $coursenum) {
+                                    my %toolsettings =
+                                        &Apache::lonnet::dump('exttool_'.$marker,$toolcdom,$toolcnum);
+                                    my %tooltypes = &Apache::loncommon::usable_exttools();
+                                    if ((($toolsettings{'id'} =~ /^c\d+$/) && (!$tooltypes{'crs'})) ||
+                                        (($toolsettings{'id'} =~ /^\d+$/) && (!$tooltypes{'dom'}))) {
+                                        $canpaste = 0;
+                                        $nopaste = &mt('Paste from another course unavailable.');
+                                    } elsif ($toolsettings{'id'} =~ /^c\d+$/) {
+                                        unless ($checkedsameinst) {
+                                            my $primary_id = &Apache::lonnet::domain($coursedom,'primary');
+                                            my $intdom = &Apache::lonnet::internet_dom($primary_id);
+                                            if ($intdom ne '') {
+                                                my $internet_names =
+                                                    &Apache::lonnet::get_internet_names($Apache::lonnet::perlvar{'lonHostID'});
+                                                if (ref($internet_names) eq 'ARRAY') {
+                                                    if (grep(/^\Q$intdom\E$/,@{$internet_names})) {
+                                                        $same_institution = 1;
+                                                    }
+                                                }
+                                            }
+                                            $checkedsameinst = 1;
+                                        }
+                                        if ($same_institution) {
+                                            $othercrs = '<br />'.&mt('(from another course)');
+                                        } else {
+                                            $nopaste = &mt('Paste from another course unavailable.');
+                                        }
+                                    } else {
+                                        $othercrs = '<br />'.&mt('(from another course)');
+                                    }
+                                }
                             }
                         } else {
                             $canpaste = 0;
                             $nopaste = &mt('Paste from another course unavailable.');
                         }
                     }
+                } elsif ($url =~ m{/res/($match_domain)/($match_username)/}) {
+                    my ($audom,$auname) = ($1,$2);
+                    unless (($auname eq $coursenum) && ($audom eq $coursedom)) {
+                        if (&Apache::lonnet::is_course($audom,$auname)) {
+                            $canpaste = 0;
+                            $nopaste = &mt('Paste from another course unavailable.');
+                        }
+                    }
                 }
                 if ($canpaste) {
                     push(@pasteable,$suffix);
@@ -1763,9 +1818,12 @@ sub do_paste_from_buffer {
         return();
     }
 
-    my (%msgs,%before,%after,@dopaste,%is_map,%notinsupp,%notincrs,%notindom,%duplicate,
-        %prefixchg,%srcdom,%srcnum,%srcmapidx,%marktomove,$save_err,$lockerrors,$allresult);
-
+    my (%msgs,%before,%after,@dopaste,%is_map,%notinsupp,%notincrs,%notindom,
+        %othcrstool,%othcrsres,%duplicate,%prefixchg,%srcdom,%srcnum,%srcmapidx,
+        %marktomove,$save_err,$lockerrors,$allresult,%currcrsltitools,
+        %currltititles,$currltimax,$gotcrsltitools);
+    $currltimax = 0;
+    $gotcrsltitools = 0;
     foreach my $suffix (@topaste) {
         my $url=&LONCAPA::map::qtescape($env{'docs.markedcopy_url_'.$suffix});
         my $cid=&LONCAPA::map::qtescape($env{'docs.markedcopy_crs_'.$suffix});
@@ -1804,13 +1862,53 @@ sub do_paste_from_buffer {
                 }
             }
 # When buffer was populated using an active role in a different course
-# disallow pasting of External Tool if course is in a different domain.
-            if (($url =~ m{/ext\.tool$}) && ($srcd ne $coursedom)) {
-                $notindom{$suffix} = 1;
-                next;
+# disallow pasting of External Tool if course is in a different domain,
+# or if External Tool use is not permitted in this course.
+            if ($url =~ m{^/adm/($match_domain)/($match_courseid)/(\d+)/ext\.tool$}) {
+                my ($toolcdom,$toolcnum,$marker) = ($1,$2,$3);
+                if ($toolcdom ne $coursedom) {
+                    $notindom{$suffix} = 1;
+                    next;
+                } elsif ($toolcnum ne $coursenum) {
+                    my %toolsettings =
+                        &Apache::lonnet::dump('exttool_'.$marker,$toolcdom,$toolcnum);
+                    my %tooltypes = &Apache::loncommon::usable_exttools();
+                    if ((($toolsettings{'id'} =~ /^c\d+$/) && (!$tooltypes{'crs'})) ||
+                        (($toolsettings{'id'} =~ /^\d+$/) && (!$tooltypes{'dom'}))) {
+                        $othcrstool{$suffix} = 1;
+                        next;
+                    }
+                    if ($toolsettings{'id'} =~ /^c\d+$/) {
+                        unless ($gotcrsltitools) {
+                            %currcrsltitools =
+                                &Apache::lonnet::get_course_lti($coursenum,$coursedom,'consumer');
+                            foreach my $item (sort(keys(%currcrsltitools))) {
+                                if (ref($currcrsltitools{$item}) eq 'HASH') {
+                                    $currltimax ++;
+                                    if (ref($currltititles{$currcrsltitools{$item}{'title'}}) eq 'ARRAY') {
+                                        push(@{$currltititles{$currcrsltitools{$item}{'title'}}},$item);
+                                    } else {
+                                        $currltititles{$currcrsltitools{$item}{'title'}} = [$item];
+                                    }
+                                }
+                            }
+                            $gotcrsltitools = 1;
+                        }
+                    }
+                }
             }
             $srcdom{$suffix} = $srcd;
             $srcnum{$suffix} = $srcn;
+        } elsif ($url =~ m{^/res/($match_domain)/($match_courseid)/}) {
+            my ($audom,$auname) = ($1,$2);
+# When buffer was populated using an active role in a different course
+# disallow pasting of published resources from Course Authoring Space
+            unless (($auname eq $coursenum) && ($audom eq $coursedom)) {
+                if (&Apache::lonnet::is_course($audom,$auname)) {
+                    $othcrsres{$suffix} = 1;
+                    next;
+                }
+            }
         }
         $srcmapidx{$suffix} = $mapidx;
         push(@dopaste,$suffix);
@@ -1862,6 +1960,8 @@ sub do_paste_from_buffer {
                 notinsupp => 'Paste failed: content type is not supported within Supplemental Content',
                 notincrs  => 'Paste failed: Item is from a different course which you do not have rights to edit.',
                 notindom  => 'Paste failed: Item is an external tool from a course in a different domain.',
+                othcrstool => 'Paste failed: Item is an external tool from a different course, for which use is not allowed in this course.',
+                othcrsres => 'Paste failed: Item is a course-authored resource from a different course',
                 duplicate => 'Paste failed: only one instance of a particular published sequence or page is allowed within each course.',
             );
 
@@ -1890,7 +1990,9 @@ sub do_paste_from_buffer {
 # Retrieve information about all course maps in main content area 
 
     my $allmaps = {};
-    my (@toclear,%mapurls,%lockerrs,%msgerrs,%results,$donechk);
+    my (@toclear,%mapurls,%lockerrs,%msgerrs,%results,$donechk,
+        @updatetoolsenc,$updatetoolscache,$checkedsameinst,
+        $same_institution);
 
 # Loop over the items to paste
     foreach my $suffix (@dopaste) {
@@ -1989,12 +2091,27 @@ sub do_paste_from_buffer {
                     $fromothercrs = 1;
                     $info{'cdom'} = $srcdom{$suffix};
                     $info{'cnum'} = $srcnum{$suffix};
+                    unless ($checkedsameinst) {
+                        my $primary_id = &Apache::lonnet::domain($coursedom,'primary');
+                        my $intdom = &Apache::lonnet::internet_dom($primary_id);
+                        if ($intdom ne '') {
+                            my $internet_names =
+                                &Apache::lonnet::get_internet_names($Apache::lonnet::perlvar{'lonHostID'});
+                            if (ref($internet_names) eq 'ARRAY') {
+                                if (grep(/^\Q$intdom\E$/,@{$internet_names})) {
+                                    $same_institution = 1;
+                                }
+                            }
+                        }
+                        $checkedsameinst = 1;
+                    }
                 }
             }
             unless (($env{'form.docs.markedcopy_options_'.$suffix} eq 'move') && (!$fromothercrs)) {
                 my (%lockerr,$msg);
                 my ($newurl,$result,$errtext) =
-                    &dbcopy(\%info,$coursedom,$coursenum,\%lockerr);
+                    &dbcopy(\%info,$coursedom,$coursenum,\%lockerr,\%currltititles,
+                            \$currltimax,\@updatetoolsenc,\$updatetoolscache,$same_institution);
                 if ($result eq 'ok') {
                     $url = $newurl;
                     $title=&mt('Copy of').' '.$title;
@@ -2163,6 +2280,10 @@ sub do_paste_from_buffer {
             }
         }
     }
+    if (($updatetoolscache) || (@updatetoolsenc)) {
+        &update_ltitools_caches($coursedom,$coursenum,$updatetoolscache,
+                                \@updatetoolsenc);
+    }
     &clear_from_buffer(\@toclear,\@currpaste);
     my $msgsarray;
     foreach my $suffix (keys(%msgs)) {
@@ -2211,6 +2332,30 @@ sub clear_from_buffer {
     return $numdel;
 }
 
+sub update_ltitools_caches {
+    my ($coursedom,$coursenum,$updatetoolscache,$updatetoolsenc) = @_;
+    my $hashid=$coursedom.'_'.$coursenum;
+    if ($updatetoolscache) {
+        &Apache::lonnet::devalidate_cache_new('courseltitools',$hashid);
+    }
+    if ((ref($updatetoolsenc) eq 'ARRAY') &&
+        (@{$updatetoolsenc})) {
+        my @ids=&Apache::lonnet::current_machine_ids();
+        my $updatedone;
+        foreach my $lonhost (@{$updatetoolsenc}) {
+            if (grep(/^\Q$lonhost\E$/,@ids)) {
+                unless ($updatedone) {
+                    &Apache::lonnet::devalidate_cache_new('crsltitoolsenc',$hashid);
+                }
+                $updatedone = 1;
+            } else {
+                &Apache::lonnet::remote_devalidate_cache($lonhost,["crsltitoolsenc:$hashid"]);
+            }
+        }
+    }
+    return;
+}
+
 sub get_newmap_url {
     my ($url,$folder,$prefixchg,$coursedom,$coursenum,$srcdom,$srcnum,
         $titleref,$allmaps,$newurls) = @_;
@@ -2272,7 +2417,8 @@ sub get_newmap_url {
 }
 
 sub dbcopy {
-    my ($dbref,$coursedom,$coursenum,$lockerrorsref) = @_;
+    my ($dbref,$coursedom,$coursenum,$lockerrorsref,$currltititles,
+        $currltimax,$updatetoolsenc,$updatetoolscache,$same_institution) = @_;
     my ($url,$result,$errtext);
     if (ref($dbref) eq 'HASH') {
         $url = $dbref->{'src'};
@@ -2316,6 +2462,117 @@ sub dbcopy {
                     my %contents=&Apache::lonnet::dump($db_name,
                                                        $dbref->{'cdom'},
                                                        $dbref->{'cnum'});
+                    my ($toolcopyerror,$toolpassback,$toolroster,%toolinfo,$oldtoolid,$defincrs);
+                    if ($url eq '/adm/'.$dbref->{'cdom'}.'/'.$dbref->{'cnum'}."/$marker/ext.tool") {
+                        if ($contents{'id'} =~ /^(|c)(\d+)$/) {
+                            $oldtoolid = $2;
+                            if ($1 eq 'c') {
+                                $defincrs = 1;
+                                %toolinfo =
+                                    &Apache::lonnet::get('ltitools',[$oldtoolid],$dbref->{'cdom'},$dbref->{'cnum'});
+                            } else {
+                                %toolinfo= &Apache::lonnet::get_domain_lti($dbref->{'cdom'},'consumer');
+                            }
+                            if (ref($toolinfo{$oldtoolid}) eq 'HASH') {
+                                if ($toolinfo{$oldtoolid}{'passback'}) {
+                                    $toolpassback = 1;
+                                }
+                                if ($toolinfo{$oldtoolid}{'roster'}) {
+                                    $toolroster = 1;
+                                }
+                            } else {
+                                $toolcopyerror = 1;
+                                $errtext = &mt('Could not retrieve original settings for pasted external tool.');
+                            }
+                        }
+                        unless (($dbref->{'cnum'} eq $coursenum) && ($dbref->{'cdom'} eq $coursedom)) {
+                            $url = "/adm/$coursedom/$coursenum/$marker/ext.tool";
+                            if ($contents{'crstitle'} ne '') {
+                                $contents{'crstitle'} = $env{'course.'.$coursedom.'_'.$coursenum.'.description'};
+                            }
+                            if (($defincrs) && (!$toolcopyerror)) {
+                                my %newtool;
+                                my $oldcdom = $dbref->{'cdom'};
+                                my $oldcnum = $dbref->{'cnum'};
+                                my $title = $toolinfo{$oldtoolid}{'title'};
+                                if (ref($currltititles) eq 'HASH') {
+                                    if (exists($currltititles->{$title})) {
+                                        $title .= ' (copied from another course)';
+                                    }
+                                }
+                                my ($newid,$iderror) =
+                                    &Apache::lonnet::get_ltitools_id('course',$coursedom,$coursenum,$title);
+                                if ($newid =~ /^\d+$/) {
+                                    %{$newtool{$newid}} = %{$toolinfo{$oldtoolid}};
+                                    $newtool{$newid}{'title'} = $title;
+                                    if (ref($currltimax)) {
+                                        $newtool{$newid}{'order'} = $$currltimax;
+                                    }
+                                    if ($newtool{$newid}{'image'} =~ m{^\Q/uploaded/$oldcdom/$oldcnum/toollogo/$oldtoolid/\E([^/]+)$}) {
+                                        my $fname = $1;
+                                        my $content = &Apache::lonnet::getfile($newtool{$newid}{'image'});
+                                        if ($content eq '-1') {
+                                            delete($newtool{$newid}{'image'});
+                                        } else {
+                                            $env{'form.'.$suffix.'.image'} = $content;
+                                            my $newlogo =
+                                                &Apache::lonnet::finishuserfileupload($coursenum,$coursedom,$suffix.'.image',"toollogo/$newid/$fname");
+                                            delete($env{'form.'.$suffix.'.image'});
+                                            if ($newlogo =~ m{^/uploaded/}) {
+                                                $newtool{$newid}{'image'} = $newlogo;
+                                            } else {
+                                                delete($newtool{$newid}{'image'});
+                                            }
+                                        }
+                                    }
+                                    my $newusable;
+                                    if ($same_institution) {
+                                        my %oldtoolsenc = &Apache::lonnet::eget('nohist_toolsenc',[$oldtoolid],$oldcdom,$oldcnum);
+                                        if (ref($oldtoolsenc{$oldtoolid}) eq 'HASH') {
+                                            my %newtoolsenc;
+                                            %{$newtoolsenc{$newid}} = %{$oldtoolsenc{$oldtoolid}};
+                                            my $putres = &Apache::lonnet::put('nohist_toolsenc',\%newtoolsenc,$coursedom,$coursenum,1);
+                                            if ($putres eq 'ok') {
+                                                if (ref($updatetoolsenc) eq 'ARRAY') {
+                                                    my $newhome = &Apache::lonnet::homeserver($coursenum,$coursedom);
+                                                    unless (grep(/^\Q$newhome\E$/,@{$updatetoolsenc})) {
+                                                        push(@{$updatetoolsenc},$newhome);
+                                                    }
+                                                }
+                                                $newusable = 1;
+                                            }
+                                        }
+                                    }
+                                    if ($newtool{$newid}{'usable'}) {
+                                        unless ($newusable) {
+                                            delete($newtool{$newid}{'usable'});
+                                        }
+                                    }
+                                    my $putres = &Apache::lonnet::put('ltitools',\%newtool,$coursedom,$coursenum);
+                                    if ($putres eq 'ok') {
+                                        $contents{'id'} = "c$newid";
+                                        if (ref($updatetoolscache)) {
+                                            $$updatetoolscache ++;
+                                        }
+                                        if (ref($currltititles->{$title}) eq 'ARRAY') {
+                                            push(@{$currltititles->{$title}},$newid);
+                                        } else {
+                                            $currltititles->{$title} = [$newid];
+                                        }
+                                        if (ref($currltimax)) {
+                                            $$currltimax ++;
+                                        }
+                                    } else {
+                                        $toolcopyerror = 1;
+                                        $errtext = &mt('Unable to save external tool definition in Course Settings.');
+                                    }
+                                } else {
+                                    $toolcopyerror = 1;
+                                    $errtext = &mt('Unable to retrieve new tool ID when adding external tool definition to Course Settings.');
+                                }
+                            }
+                        }
+                    }
                     if (exists($contents{'uploaded.photourl'})) {
                         my $photo = $contents{'uploaded.photourl'};
                         my ($subdir,$fname) =
@@ -2335,13 +2592,40 @@ sub dbcopy {
                         }
                     }
                     $db_name =~ s{_\d*$ }{_$suffix}x;
-                    if (($prefix eq 'exttool') && ($dbref->{'delgradable'}) && ($contents{'gradable'})) {
-                        delete($contents{'gradable'});
+                    if ($prefix eq 'exttool') {
+                        unless ($toolcopyerror) {
+                            foreach my $key ('oldgradesecret','gradesecret','gradesecretdate','oldrostersecret','rostersecret','rostersecretdate') {
+                                if (exists($contents{$key})) {
+                                    delete($contents{$key});
+                                }
+                            }
+                            if ($dbref->{'delgradable'}) {
+                                if (exists($contents{'gradable'})) {
+                                    delete($contents{'gradable'});
+                                }
+                            }
+                            if ($toolpassback) {
+                                if ($contents{'gradable'}) {
+                                    my $gradesecret = UUID::Tiny::create_uuid_as_string(UUID_V4);
+                                    $contents{'gradesecret'} = $gradesecret;
+                                    $contents{'gradesecretdate'} = time;
+                                }
+                            }
+                            if ($toolroster) {
+                                my $rostersecret = UUID::Tiny::create_uuid_as_string(UUID_V4);
+                                $contents{'rostersecret'} = $rostersecret;
+                                $contents{'rostersecretdate'} = time;
+                            }
+                        }
                     }
-                    $result=&Apache::lonnet::put($db_name,\%contents,
-                                                 $coursedom,$coursenum);
-                    if ($result eq 'ok') {
-                        $url =~ s{/(\d*)/(smppg|bulletinboard|ext\.tool)$}{/$suffix/$2}x;
+                    if (($prefix eq 'exttool') && ($toolcopyerror)) {
+                        $result = 'error';
+                    } else {
+                        $result=&Apache::lonnet::put($db_name,\%contents,
+                                                     $coursedom,$coursenum);
+                        if ($result eq 'ok') {
+                            $url =~ s{/(\d*)/(smppg|bulletinboard|ext\.tool)$}{/$suffix/$2}x;
+                        }
                     }
                 }
                 if (($freedlock ne 'ok') && (ref($lockerrorsref) eq 'HASH')) {
@@ -2496,18 +2780,37 @@ sub contained_map_check {
             if ($token->[1] eq 'resource') {
                 next if ($token->[2]->{'type'} eq 'zombie');
                 my $ressrc = $token->[2]->{'src'};
-                if ($ressrc =~ m{^/adm/($match_domain)/$match_courseid/\d+/ext\.tool$}) {
-                    my $srcdom = $1;
+                if ($ressrc =~ m{^/adm/($match_domain)/($match_courseid)/(\d+)/ext\.tool$}) {
+                    my ($srcdom,$srcnum,$marker) = ($1,$2,$3);
                     unless ($srcdom eq $coursedom) {
                         $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc;
                         next;
                     }
+                    unless ($srcnum eq $coursenum) {
+                        my %toolsettings =
+                            &Apache::lonnet::dump('exttool_'.$marker,$srcdom,$srcnum);
+                        my %tooltypes = &Apache::loncommon::usable_exttools();
+                        if ((($toolsettings{'id'} =~ /^c\d+$/) && (!$tooltypes{'crs'})) ||
+                            (($toolsettings{'id'} =~ /^\d+$/) && (!$tooltypes{'dom'}))) {
+                            $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc;
+                            next;
+                        }
+                    }
                 } elsif ($folder =~ /^supplemental/) {
                     unless (&supp_pasteable($ressrc)) {
                         $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc;
                         next;
                     }
                 }
+                if ($ressrc =~ m{^/res/($match_domain)/($match_courseid)/}) {
+                    my ($srcdom,$srcnum) = ($1,$2);
+                    unless (($srcnum eq $coursenum) && ($srcdom eq $coursedom)) {
+                        if (&Apache::lonnet::is_course($srcdom,$srcnum)) {
+                            $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc;
+                            next;
+                        }
+                    }
+                }
                 if ($ressrc =~ m{^/(res|uploaded)/.+\.(sequence|page)$}) {
                     if ($1 eq 'uploaded') {
                         $hierarchy->{$url}{$token->[2]->{'id'}} = $ressrc;
@@ -2642,7 +2945,7 @@ sub url_paste_fixups {
                     if ($is_exttool) {
                         $exttoolchg = 1;
                     }
-                } elsif (($rem =~ m{\d+/ext\.tool$}) &&
+                } elsif (($is_exttool) &&
                          ($env{'form.docs.markedcopy_options'} ne 'move')) {
                     $dbcopies->{$oldurl}{$id}{'src'} = $ressrc;
                     $dbcopies->{$oldurl}{$id}{'cdom'} = $srcdom;
@@ -2702,7 +3005,9 @@ sub apply_fixups {
         $oldurl,$url,$caller) = @_;
     my (%rewrites,%zombies,%removefrommap,%removeparam,%dbcopies,%retitles,
         %params,%newsubdir,%before,%after,%copies,%docmoves,%mapmoves,@msgs,
-        %resdatacopy,%lockerrors,$lockmsg);
+        %resdatacopy,%lockerrors,$lockmsg,%currcrsltitools,$gotcrsltitools,
+        %currltititles,$currltimax);
+    $currltimax = 0;
     if (ref($updated) eq 'HASH') {
         if (ref($updated->{'rewrites'}) eq 'HASH') {
             %rewrites = %{$updated->{'rewrites'}};
@@ -2853,6 +3158,7 @@ sub apply_fixups {
                 }
             }
         }
+        my ($updatetoolscache,@updatetoolsenc,$same_institution,$checkedsameinst);
         foreach my $key (keys(%updates)) {
             my (%torewrite,%toretitle,%toremove,%remparam,%currparam,%zombie,%newdb);
             if (ref($rewrites{$key}) eq 'HASH') {
@@ -2873,10 +3179,63 @@ sub apply_fixups {
             if (ref($dbcopies{$key}) eq 'HASH') {
                 foreach my $idx (keys(%{$dbcopies{$key}})) {
                     if (ref($dbcopies{$key}{$idx}) eq 'HASH') {
+                        my $oldurl = $dbcopies{$key}{$idx}{'src'};
+                        my $oldcdom = $dbcopies{$key}{$idx}{'cdom'};
+                        my $oldcnum = $dbcopies{$key}{$idx}{'cnum'};
+                        my $oldmarker;
+                        if ($oldurl =~ m{^\Q/adm/$oldcdom/$oldcnum/\E(\d+)/ext\.tool$}) {
+                            $oldmarker = $1;
+                            unless (($gotcrsltitools) ||
+                                    (($oldcnum eq $cnum) && ($oldcdom eq $cdom))) {
+                                my %oldtoolsettings=&Apache::lonnet::dump('exttool_'.$oldmarker,$oldcdom,$oldcnum);
+                                if ($oldtoolsettings{'id'} =~ /^c\d+$/) {
+                                    unless ($gotcrsltitools) {
+                                        %currcrsltitools =
+                                            &Apache::lonnet::get_course_lti($cnum,$cdom,'consumer');
+                                        foreach my $item (sort(keys(%currcrsltitools))) {
+                                            if (ref($currcrsltitools{$item}) eq 'HASH') {
+                                                $currltimax ++;
+                                                if (ref($currltititles{$currcrsltitools{$item}{'title'}}) eq 'ARRAY') {
+                                                    push(@{$currltititles{$currcrsltitools{$item}{'title'}}},$item);
+                                                } else {
+                                                    $currltititles{$currcrsltitools{$item}{'title'}} = [$item];
+                                                }
+                                            }
+                                        }
+                                        $gotcrsltitools = 1;
+                                    }
+                                    unless ($checkedsameinst) {
+                                        my $primary_id = &Apache::lonnet::domain($cdom,'primary');
+                                        my $intdom = &Apache::lonnet::internet_dom($primary_id);
+                                        if ($intdom ne '') {
+                                            my $internet_names =
+                                                &Apache::lonnet::get_internet_names($Apache::lonnet::perlvar{'lonHostID'});
+                                            if (ref($internet_names) eq 'ARRAY') {
+                                                if (grep(/^\Q$intdom\E$/,@{$internet_names})) {
+                                                    $same_institution = 1;
+                                                }
+                                            }
+                                        }
+                                        $checkedsameinst = 1;
+                                    }
+                                }
+                            }
+                        }
                         my ($newurl,$result,$errtext) =
-                            &dbcopy($dbcopies{$key}{$idx},$cdom,$cnum,\%lockerrors);
+                            &dbcopy($dbcopies{$key}{$idx},$cdom,$cnum,\%lockerrors,\%currltititles,
+                                    \$currltimax,\@updatetoolsenc,\$updatetoolscache,$same_institution);
                         if ($result eq 'ok') {
                             $newdb{$idx} = $newurl;
+                            if ($newurl =~ /ext\.tool$/) {
+                                if ($torewrite{$idx} eq "/adm/$oldcdom/$oldcnum/$oldmarker/ext.tool") {
+                                    if ($newurl =~ m{^\Q/adm/$cdom/$cnum/\E(\d+)/ext.tool$}) {
+                                        my $newmarker = $1;
+                                        unless ($oldmarker eq $newmarker) {
+                                            $torewrite{$idx} = "/adm/$oldcdom/$oldcnum/$newmarker/ext.tool";
+                                        }
+                                    }
+                                }
+                            }
                         } elsif (ref($errors) eq 'HASH') {
                             $errors->{$key} = 1;
                         }
@@ -3015,6 +3374,10 @@ sub apply_fixups {
                 }
             }
         }
+        if (($updatetoolscache) || (@updatetoolsenc)) {
+            &update_ltitools_caches($cdom,$cnum,$updatetoolscache,
+                                    \@updatetoolsenc);
+        }
     }
     return ('ok',\@msgs,$lockmsg);
 }
@@ -3109,7 +3472,7 @@ sub update_parameter {
             my ($name,$url)=split(/\:/,$LONCAPA::map::resources[$res]);
             $name=&LONCAPA::map::qtescape($name);
             $url=&LONCAPA::map::qtescape($url);
-            next unless ($name && $url);
+            next unless $url;
             my $is_map;
             if ($url =~ m{/uploaded/.+\.(page|sequence)$}) {
                 $is_map = 1;
@@ -3739,7 +4102,7 @@ sub multiple_check_form {
     return unless (ref($listsref) eq 'HASH');
     my $disabled;
     unless ($canedit) {
-        $disabled = 'disabled="disabled"'; 
+        $disabled = ' disabled="disabled"';
     }
     my $output =
     '<form action="/adm/coursedocs" method="post" name="togglemult'.$caller.'">'.
@@ -3777,7 +4140,7 @@ sub multiple_check_form {
             '</label></span></td>'."\n".
             '<td class="LC_docs_entry_parameter">'.
             '<span class="LC_nobreak LC_docs_copy">'.
-            '<label><input type="checkbox" name="copyall" id="copyall" onclick="propagateState(this.form,'."'copy'".')"'. $disabled.' />'.&mt('Copy').
+            '<label><input type="checkbox" name="copyall" id="copyall" onclick="propagateState(this.form,'."'copy'".')"'.$disabled.' />'.&mt('Copy').
             '</label></span></td>'.
             '</tr></table>'."\n";
     }
@@ -4294,7 +4657,7 @@ END
                     $nomodal = 1;
                 }
             }
-            my ($checkencrypt,$shownurl);
+            my $checkencrypt;
             if (!$env{'request.role.adv'}) {
                 if (((&LONCAPA::map::getparameter($orderidx,'parameter_encrypturl'))[0]=~/^yes$/i) ||
                     ($isencrypted) || (&Apache::lonnet::EXT('resource.0.encrypturl',$symb) =~ /^yes$/i)) {
@@ -4314,7 +4677,7 @@ END
                 my $currenc = $env{'request.enc'};
                 $env{'request.enc'} = 1;
                 $shownsymb = &Apache::lonenc::encrypted($symb);
-                $shownurl = &Apache::lonenc::encrypted($url);
+                my $shownurl = &Apache::lonenc::encrypted($url);
                 if (&Apache::lonnet::symbverify($symb,$url)) {
                     $url = $shownurl;
                 } else {
@@ -4329,7 +4692,8 @@ END
                         $url = &Apache::lonnet::clutter($url);
                     }
                 }
-                $shownurl = $url;
+            } else {
+                $url = '';
             }
             unless ($env{'request.role.adv'}) {
                 if ((&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i) {
@@ -4340,8 +4704,8 @@ END
                     $hiddenres = 1;
                 }
             }
-            if ($url ne '') {
-                $url = $shownurl.(($shownurl=~/\?/)?'&':'?').'symb='.&escape($shownsymb);
+            if (($url ne '') && ($shownsymb ne '')) {
+                $url .= (($url=~/\?/)?'&':'?').'symb='.&escape($shownsymb);
             }
 	}
     } elsif ($supplementalflag) {
@@ -4539,7 +4903,7 @@ $form_end;
     } else {
         $reinit = &mt('(re-initialize course to access)');
     }
-    $line.='<td class="LC_docs_entry_commands"'.$tdalign.'><span class="LC_nobreak">'.$editlink.$renamelink;
+    $line.='<td class="LC_docs_entry_commands"'.$tdalign.'><span class="LC_nobreak">'.$editlink.$renamelink.'</span>';
     if ($orig_url =~ /$LONCAPA::assess_re/) {
         $line.= '<br />';
         if ($curralias ne '') {
@@ -4550,7 +4914,7 @@ $form_end;
                    $lt{'sa'}.'</a></span>';
         }
     }
-    $line.='</td><td>';
+    $line.='</td><td><span class="LC_nobreak">';
     my ($link,$nolink);
     if (($url=~m{/adm/(coursedocs|supplemental)}) || (!$allowed && $url)) {
         if ($allowed && !$env{'request.role.adv'} && !$isfolder && !$ispage) {
@@ -4646,7 +5010,7 @@ $form_end;
         my ($enctext,$hidtext,$formhidden,$formurlhidden);
         if ((&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i) {
             $hidtext = ' checked="checked"';
-            if (($ishash) && (ref($filtersref->{'randomorder'}) eq 'ARRAY')) {
+            if (($ishash) && (ref($filtersref->{'hiddenresource'}) eq 'ARRAY')) {
                 push(@{$filtersref->{'hiddenresource'}},$orderidx);
             }
         }
@@ -5718,6 +6082,7 @@ sub handler {
     my $containertag;
     my $pathitem;
     my %ltitools;
+    my $posslti;
     my $hiddentop;
     my $navmap;
     my $filterFunc = sub { my $res = shift; return (!$res->randomout() && !$res->is_map()) };
@@ -5951,8 +6316,19 @@ sub handler {
                 }
             }
             my $tabidstr = join("','",@tabids);
-            %ltitools = &Apache::lonnet::get_domain_lti($coursedom,'consumer');
-            my $posslti = keys(%ltitools);
+            my (%domtools,%crstools);
+            my %tooltypes = &Apache::loncommon::usable_exttools();
+            if ($tooltypes{'dom'}) {
+                %domtools = &Apache::lonnet::get_domain_lti($coursedom,'consumer');
+            }
+            if ($tooltypes{'crs'}) {
+                %crstools = &Apache::lonnet::get_course_lti($coursenum,$coursedom,'consumer');
+            }
+            %ltitools = (
+                          dom => \%domtools,
+                          crs => \%crstools,
+                        );
+            $posslti = scalar(keys(%domtools)) + scalar(keys(%crstools));
             my $hostname = $r->hostname();
 	    $script .= &editing_js($udom,$uname,$supplementalflag,$coursedom,$coursenum,$posslti,
                                    $londocroot,$canedit,$hostname,\$navmap).
@@ -6156,6 +6532,7 @@ sub handler {
                 'dire' => 'Directory:',
                 'cate' => 'Category:',
                 'tmpl' => 'Template:',
+                'empd' => 'No resources found',
                 'comment' => 'Comment',
                 'parse' => 'Upload embedded images/multimedia files if HTML file',
                 'bb5'      => 'Blackboard 5',
@@ -6205,10 +6582,7 @@ sub handler {
 	my $fileupload=(<<FIUP);
         $quotainfo
 	$lt{'file'}:<br />
-	<input type="file" name="uploaddoc" class="LC_flUpload" size="40" $disabled />
-        <input type="hidden" id="LC_free_space" value="$free_space" />
 FIUP
-
 	my $checkbox=(<<CHBO);
 	<!-- <label>$lt{'parse'}?
 	<input type="checkbox" name="parserflag" />
@@ -6228,6 +6602,8 @@ CHBO
         <fieldset id="uploadimsform" style="display: none;">
         <legend>$lt{'imsf'}</legend>
         $fileupload
+        <input type="file" name="uploaddoc" id="uploaddocims" class="LC_flUpload LC_uploaddoc" size="40" $disabled />
+        <input type="hidden" id="LC_free_space_ims" value="$free_space" />
         <br />
         <p>
         $lt{'cms'}:&nbsp; 
@@ -6254,6 +6630,8 @@ IMSFORM
         <legend>$lt{'upfi'}</legend>
 	<input type="hidden" name="active" value="aa" />
     $fileupload
+        <input type="file" name="uploaddoc" class="LC_flUpload" size="40" $disabled />
+        <input type="hidden" id="LC_free_space" value="$free_space" />
 	<br />
 	$lt{'title'}:<br />
 	<input type="text" size="60" name="comment" $disabled />
@@ -6304,13 +6682,20 @@ SEDFFORM
         <form action="/adm/coursedocs" method="post" name="crsresimportform" onsubmit="return validImportCrsRes();">
         <fieldset id="importcrsresform" style="display: none;">
         <legend>$lt{'imcr'}</legend>
+        <div id="importcrsrescontent" style="display: none;">
         <input type="hidden" name="active" value="bb" />
         $pickfile
         <p>
-        $lt{'title'}: <input type="textbox" name="crsrestitle" value="" $disabled />
+        $lt{'title'}: <input type="text" name="crsrestitle" value="" $disabled />
         </p>
         <input type="hidden" name="importdetail" value="" />
         <input type="submit" name="crsres" value="$lt{'impo'}" $disabled /><br />
+        </div>
+        <div id="importcrsresempty" style="display: none;">
+        <p>
+        $lt{'empd'}
+        </p>
+        </div>
         </fieldset>
         </form>
 CRSFORM
@@ -6530,167 +6915,64 @@ NROSTFORM
         $help{'Web_Page'}
         </form>
 NWEBFORM
-
+        my $showpath = &HTML::Entities::encode($env{'form.folderpath'},'<>&"');
         my @ids=&Apache::lonnet::current_machine_ids();
-        my (%select_menus,$rolehomes);
-        my $numauthor = 0;
-        my $numcrsdirs = 0;
-        my ($showstdprob,$showswitch,$switchlink);
-        my $toppath = "/priv/$env{'user.domain'}/$env{'user.name'}"; 
-        my $exclude = &Apache::lonnet::priv_exclude();
+        my $machines_str = "'".join("','",@ids)."'";
+        my (%is_home,%toppath,$rolehomes);
         if ($env{'user.author'}) {
-            $numauthor ++;
-            $select_menus{'author'}->{'text'} = &Apache::lonnet::plaintext('au');
             if (grep(/^\Q$env{'user.home'}\E$/,@ids)) {
-                my $is_home = 1;
-                my %subdirs;
-                &Apache::lonnet::recursedirs($is_home,1,'',$exclude,0,$toppath,'',\%subdirs);
-                $select_menus{'author'}->{'default'} = '/'; 
-                my @ordered = ();
-                foreach my $relpath (sort { lc($a) cmp lc($b) } (keys(%subdirs))) {
-                    $select_menus{'author'}->{'select2'}->{$relpath} = $relpath;
-                    push(@ordered,$relpath);
-                }
-                $select_menus{'author'}->{'order'} = \@ordered;
-                $showstdprob = 'block';
-            } else {
-                $rolehomes = '<input type="hidden" name="rolehome_author" value="'.$env{'user.home'}.'" />'."\n";
-                $select_menus{'author'}->{'select2'}->{'switch'} = &mt('Switch server required');
-                $select_menus{'author'}->{'default'} = 'switch';
-                $select_menus{'author'}->{'order'} = ['switch'];
-                $showstdprob = 'none';
+                $is_home{'author'} = 1;
             }
+            $rolehomes = '<input type="hidden" id="rolehome_author" name="rolehome_author" value="'.$env{'user.home'}.'" />'."\n";
         }
         my %roleshash = &Apache::lonnet::get_my_roles($env{'user.name'},$env{'user.domain'},'userroles',
                                                       ['active'],['ca','aa']);
-        my $crshome = $env{'course.'.$env{'request.course.id'}.'.home'};
-        my (%by_roletype,%at_home);
+        my %by_roletype;
         if (keys(%roleshash)) {
             foreach my $entry (keys(%roleshash)) {
                 my ($auname,$audom,$roletype) = split(/:/,$entry);
                 my $key = $entry;
                 $key =~ s/:/___/g;
-                $by_roletype{$roletype}{$auname.'___'.$audom} = 1;
-                $select_menus{$key}->{'text'} = &Apache::lonnet::plaintext($roletype)." ($audom/$auname)";
+                my $author = $auname.'___'.$audom;
+                $by_roletype{$roletype}{$author} = 1;
                 my $rolehome = &Apache::lonnet::homeserver($auname,$audom);
-                if (grep(/^\Q$rolehome\E$/,@ids)) {    
-                    $at_home{$auname.'___'.$audom} = 1;
-                    my $is_home = 1;
-                    my (%subdirs,@ordered);
-                    my $toppath="/priv/$audom/$auname";
-                    &Apache::lonnet::recursedirs($is_home,1,'',$exclude,0,$toppath,'',\%subdirs);
-                    $select_menus{$key}->{'default'} = '/';
-                    foreach my $relpath (sort { lc($a) cmp lc($b) } (keys(%subdirs))) {
-                        $select_menus{$key}->{'select2'}->{$relpath} = $relpath;
-                        push(@ordered,$relpath);
-                    }
-                    $select_menus{$key}->{'order'} = \@ordered;
-                } else {
-                    $rolehomes .= '<input type="hidden" name="rolehome_coauthor" value="'.$roletype.'='.$audom.'/'.$auname.'='.$rolehome.'" />'."\n";
-                    $select_menus{$key}->{'select2'}->{'switch'} = &mt('Switch server required');
-                    $select_menus{$key}->{'default'} = 'switch';
-                    $select_menus{$key}->{'order'} = ['switch'];
-                }
-                $numauthor ++;
-            }
-        }
-        my ($pickdir,$showtitle);
-        if ($numauthor) {
-            my @order;
-            my $defrole;
-            if ($env{'user.author'}) {
-                push(@order,'author');
-                $defrole = 'author';
-            }
-            if (keys(%by_roletype)) {
-                foreach my $possrole ('ca','aa') {
-                    if (ref($by_roletype{$possrole}) eq 'HASH') {
-                        foreach my $author (sort { lc($a) cmp lc($b) } (keys(%{$by_roletype{$possrole}}))) {
-                            unless ($defrole) {
-                                $defrole = $author;
-                                if ($at_home{$author}) {
-                                    $showstdprob = 'block'; 
-                                } else {
-                                    $showstdprob = 'none';
-                                }
-                            }
-                            push(@order,$author.'___'.$possrole);
-                        }
-                    }
+                $toppath{$author} = "/priv/$audom/$auname";
+                if (grep(/^\Q$rolehome\E$/,@ids)) {
+                    $is_home{$author} = 1;
                 }
+                $rolehomes .= '<input type="hidden" id="rolehome_coauthor_'.$roletype.'_'.$audom.'/'.$auname.'" '.
+                              'name="rolehome_coauthor" value="'.$roletype.'='.$audom.'/'.$auname.'='.$rolehome.'" />'."\n";
             }
-            $select_menus{'course'}->{'text'} = &mt('Course Resource');
-            if (grep(/^\Q$crshome\E$/,@ids)) {
-                my $is_home = 1;
-                my %subdirs;
-                my $toppath="/priv/$coursedom/$coursenum";
-                &Apache::lonnet::recursedirs($is_home,1,'',$exclude,0,$toppath,'',\%subdirs);
-                $numcrsdirs = keys(%subdirs);
-                $select_menus{'course'}->{'default'} = '/';
-                my @ordered = ();
-                foreach my $relpath (sort { lc($a) cmp lc($b) } (keys(%subdirs))) {
-                    $select_menus{'course'}->{'select2'}->{$relpath} = $relpath;
-                    push(@ordered,$relpath);
-                }
-                $select_menus{'course'}->{'order'} = \@ordered;
-            } else {
-                $rolehomes .= '<input type="hidden" name="rolehome_course" value="'.$crshome.'" />'."\n";
-                $select_menus{'course'}->{'select2'}->{'switch'} = &mt('Switch server required');
-                $select_menus{'course'}->{'default'} = 'switch';
-                $select_menus{'course'}->{'order'} = ['switch'];
-            }
-            push(@order,'course');
-            $pickdir = $lt{'loca'}.
-                       &Apache::loncommon::linked_select_forms('courseresform','<br />'.$lt{'dire'},
-                                                               $defrole,'authorrole','authorpath',
-                                                               \%select_menus,\@order,'toggleCrsResTitle();',
-                                                               '','priv').'<br />';
-            $showtitle = 'none';
-        } else {
-            my $is_home;
-            $showtitle = 'inline';
-            if (grep(/^\Q$crshome\E$/,@ids)) {
-                $is_home = 1;
-                $showstdprob = 'block';
-                $pickdir .= '<input type="hidden" name="authorrole" value="course" />'; 
-                my $toppath="/priv/$coursedom/$coursenum'}";
-                my %subdirs;
-                &Apache::lonnet::recursedirs($is_home,1,'',$exclude,0,$toppath,'',\%subdirs);
-                $numcrsdirs = keys(%subdirs); 
-                if ($numcrsdirs) {
-                    $pickdir .= $lt{'dire'}.' <select name="authorpath">'."\n".
-                                 '<option value="/">/</option>'."\n";
-                    foreach my $key (sort { lc($a) cmp lc($b) } (keys(%subdirs))) {
-                        $pickdir .= '<option value="'.$key.'">'.$key.'</option>'."\n";
+        }
+        my $crshome = $env{'course.'.$env{'request.course.id'}.'.home'};
+        if (grep(/^\Q$crshome\E$/,@ids)) {
+            $is_home{'course'} = 1;
+        }
+        $rolehomes .= '<input type="hidden" id="rolehome_course" name="rolehome_course" value="'.$crshome.'" />'."\n";
+        my $pickdir = $lt{'loca'}.
+                   '<select name="authorrole" onchange="populateDirSelects(this.form,'."'authorrole','authorpath'".',1,1,0);">'."\n".
+                   '<option value="" selected="selected">'.&mt('Select').'</option>'."\n";
+        if ($env{'user.author'}) {
+            $pickdir .= '<option value="author">'.&Apache::lonnet::plaintext('au').'</option>'."\n";
+        }
+        if (keys(%by_roletype)) {
+            foreach my $possrole ('ca','aa') {
+                if (ref($by_roletype{$possrole}) eq 'HASH') {
+                    my $roletitle = &Apache::lonnet::plaintext($possrole);
+                    foreach my $author (sort { lc($a) cmp lc($b) } (keys(%{$by_roletype{$possrole}}))) {
+                        my ($none,$where,$auname,$audom) = split(/\//,$toppath{$author});
+                        $pickdir .= '<option value="'.$author.'___'.$possrole.'">'.
+                                     $roletitle." ($audom/$auname)</option>\n";
                     }
-                    $pickdir .= '</select>';
-                } else {
-                    $pickdir .= '<input type="hidden" name="authorpath" value="/" />'."\n";   
                 }
-            } else {
-                $showstdprob = 'none';
-                $rolehomes .= '<input type="hidden" name="rolehome_course" value="'.$crshome.'" />'."\n"; 
-                my @order;
-                $select_menus{'course'}->{'text'} = &mt('Course Resource');
-                $select_menus{'course'}->{'select2'}->{'switch'} = &mt('Switch server required');
-                $select_menus{'course'}->{'default'} = 'switch';
-                $select_menus{'course'}->{'order'} = ['switch'];
-                push(@order,'course');
-                my $defrole = 'course';
-                $pickdir = $lt{'loca'}.
-                           &Apache::loncommon::linked_select_forms('courseresform','<br />'.$lt{'dire'},
-                                                                   $defrole,'authorrole','authorpath',
-                                                                   \%select_menus,\@order,'toggleCrsResTitle();',
-                                                                   '','priv').'<br />';
-                $showtitle = 'none';
-
             }
         }
-        if ($showstdprob eq 'none') {
-            $showswitch = 'block';
-        } else {
-            $showswitch = 'none';
-        }
+        $pickdir .= '<option value="course">'.&mt('Course Resource').'</option>'."\n".
+                    '</select><br />'."\n".
+                    $lt{'dire'}.
+                    '<select name="authorpath" onchange="toggleCrsResTitle();">'.
+                    '<option value=""></option>'.
+                    '</select><br />'."\n";
 
         my %seltemplate_menus;
         my @files = &Apache::lonhomework::get_template_list('problem');
@@ -6731,9 +7013,9 @@ NWEBFORM
                                                                 "resize_scrollbox('contentscroll','1','0');",
                                                                 "toggleExampleText();",'template').'<br />';
         my $templatepreview =  '<a href="#" target="sample" onclick="javascript:getExample(600,420,\'yes\',true);  return false;">'.
-                               '<span id="newresexample">'.&mt('Example').'<span></a>';
+                               '<span id="newresexample">'.&mt('Example').'</span></a>';
         my $crsresform=(<<RESFORM);
-        <a class="LC_menubuttons_link" href="javascript:toggleCrsRes('res','$numauthor','$numcrsdirs');">
+        <a class="LC_menubuttons_link" href="javascript:toggleCrsRes('res');">
         $lt{'stpr'}</a>$help{'Course_Resource'}
         <form action="/adm/coursedocs" method="post" name="courseresform">
         <fieldset id="crsresform" style="display:none;">
@@ -6741,7 +7023,9 @@ NWEBFORM
         <input type="hidden" name="active" value="bb" />
         <p>
         $pickdir
-        <div id="newstdproblem" style="display:$showstdprob;">
+        </p>
+        <div id="newstdproblem" style="display:none;">
+        <p>
         <span class="LC_nobreak">$lt{'news'}?&nbsp;
         <label><input type="radio" name="newsubdir" value="0" onclick="toggleNewsubdir(this.form);" checked="checked" $disabled />No</label>
         &nbsp;
@@ -6749,10 +7033,11 @@ NWEBFORM
         </span><span id="newsubdir"></span>
         <input type="hidden" name="newsubdirname" id="newsubdirname" value="" autocomplete="off" />
         </p>
+        </div>
         $lt{'fnam'}
         <input type="text" size="20" name="newresourcename" autocomplete="off" $disabled />
+        <div id="newresource" style="display:none">
         <p>
-        <div id="newresource" style="display:$showtitle">
         $lt{'addp'}
         <label><input type="radio" name="newresourceadd" value="0" checked="checked" onclick="toggleNewInCourse(this.form);" $disabled />
         $lt{'no'}</label>&nbsp;&nbsp;
@@ -6760,25 +7045,24 @@ NWEBFORM
         $lt{'yes'}</label>
         <span id="newrestitle"></span>
         <input type="hidden" size="20" name="newresourcetitle" id="newresourcetitle" autocomplete="off" $disabled />
-        </div>
         </p>
+        </div>
         <p>
         $lt{'uste'}
         <label><input type="radio" name="newresusetemp" value="0" checked="checked" onclick="toggleWithTemplate(this.form);" $disabled />
         $lt{'no'}</label>&nbsp;&nbsp;
         <label><input type="radio" name="newresusetemp" value="1" onclick="toggleWithTemplate(this.form);" $disabled />
         $lt{'yes'}</label>
+        </p>
         <div id="newrestemplate" style="display:none">
         $templates
         $templatepreview
         </div>
-        </p>
         <span class="LC_nobreak">
-        <input type="hidden" name="folderpath" value="$env{'form.folderpath'}" />
+        <input type="hidden" name="folderpath" value="$showpath" />
         <input type="submit" name="newcrs" value="$lt{'crpr'}" $disabled />
         </span>
-        </div>
-        <div id="stdprobswitch" style="display:$showswitch;">
+        <div id="stdprobswitch" style="display:none;">
         $rolehomes
         <input type="button" name="switchfornewprob" value="$lt{'swit'}" onclick="switchForProb();" />
         </div>
@@ -6858,7 +7142,7 @@ NGFFORM
         my @external = (
         {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/extres.png" alt="'.$lt{extr}.'" onclick="toggleExternal(\'ext\');" />'=>$extresourcesform}
         );
-        if (keys(%ltitools)) {
+        if ($posslti) {
             push(@external,
                  {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/exttool.png" alt="'.$lt{extt}.'" onclick="toggleExternal(\'tool\');" />'=>$exttoolform},
             );
@@ -6880,7 +7164,7 @@ NGFFORM
         {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/simpprob.png" alt="'.$lt{sipr}.'" onclick="javascript:makesmpproblem();" />'=>$newsmpproblemform},
         {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/dropbox.png" alt="'.$lt{drbx}.'" onclick="javascript:makedropbox();" />'=>$newdropboxform},
         {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/scoreupfrm.png" alt="'.$lt{scuf}.'" onclick="javascript:makeexamupload();" />'=>$newexuploadform},
-        {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/simpprob.png" alt="'.$lt{stpr}.'" onclick="javascript:toggleCrsRes(\'res\','."'$numauthor','$numcrsdirs'".');" />'=>$crsresform},
+        {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/simpprob.png" alt="'.$lt{stpr}.'" onclick="javascript:toggleCrsRes(\'res\');" />'=>$crsresform},
         );
         $gradingform = &create_form_ul(&create_list_elements(@gradingforma));
 
@@ -6897,7 +7181,7 @@ my %orderhash = (
                 'aa' => ['Upload',$fileuploadform],
                 'bb' => ['Import',$importpubform],
                 'cc' => ['External',$externalform],
-                'dd' => ['Grading',$gradingform],
+                'dd' => ['Assessment',$gradingform],
                 'ff' => ['Other',$specialdocumentsform],
                 );
 unless ($container eq 'page') {
@@ -6950,6 +7234,8 @@ unless ($container eq 'page') {
         <legend>$lt{'upfi'}</legend>
 	<input type="hidden" name="active" value="ee" />
 	$fileupload
+        <input type="file" name="uploaddoc" id="uploaddocsupp" class="LC_flUpload LC_uploaddoc" size="40" $disabled />
+        <input type="hidden" id="LC_free_space_supp" value="$free_space" />
 	<br />
 	<br />
 	<span class="LC_nobreak">
@@ -6962,6 +7248,7 @@ unless ($container eq 'page') {
 	$pathitem
 	<input type="hidden" name="cmd" value="upload_supplemental" />
         <input type='submit' value="$lt{'upld'}" />
+        </fieldset>
         </form>
 SUPDOCFORM
 
@@ -7041,7 +7328,7 @@ my @specialdocs = (
         my @supexternal = (
             {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/extres.png" alt="'.$lt{extr}.'" onclick="javascript:toggleExternal(\'suppext\')" />'
              =>$supextform});
-        if (keys(%ltitools)) {
+        if ($posslti) {
             push(@supexternal,
                  {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/exttool.png" alt="'.$lt{extt}.'" onclick="javascript:toggleExternal(\'supptool\')" />'
             =>$supexttoolform});
@@ -7516,6 +7803,8 @@ sub editing_js {
                                           tinc    => 'Title in course',
                                           sunm    => 'Sub-directory name',
                                           edri    => 'Editing rights unavailable for your current role.',
+                                          sele    => 'Select',
+                                          swit    => 'Switch server required',
                                         );
     &js_escape(\%js_lt);
     my $crstype = &Apache::loncommon::course_type();
@@ -7528,6 +7817,8 @@ sub editing_js {
     my $toplevelmain = &escape(&default_folderpath($coursenum,$coursedom,$navmapref));
     my $toplevelsupp = &supplemental_base();
     my $showfile_js = &Apache::loncommon::show_crsfiles_js();
+    my @ids=&Apache::lonnet::current_machine_ids();
+    my $machines_str = "'".join("','",@ids)."'";
     if ($env{'docs.exit.'.$env{'request.course.id'}} =~ /^direct_(.+)$/) {
         my $caller = $1;
         if ($caller =~ /^supplemental/) {
@@ -7879,27 +8170,21 @@ function toggleMap(caller) {
     return;
 }
 
-function toggleCrsRes(caller,numauthorrole,numcrsdirs) {
+function toggleCrsRes(caller) {
     var disp = 'none';
     if (document.getElementById('crsresform')) {
         if (caller == 'res') {
-            var curr = document.getElementById('crsresform').style.display;
+            var form = document.getElementById('crsresform');
+            var curr = form.style.display;
             if (curr == 'none') {
                 disp='block';
-                numauthor = parseInt(numauthorrole);
-                if (numauthor > 0) {
-                    document.courseresform.authorrole.selectedIndex = 0;
-                    select1priv_changed();
-                    document.courseresform.authorpath.selectedIndex = 0;
-                    document.courseresform.newresourceadd.selectedIndex = 0;
-                    toggleNewInCourse(document.courseresform);
-                    if (document.getElementById('newresource')) {
-                        document.getElementById('newresource').style.display = 'none';
-                    }
-                } else {
-                    if (numcrsdirs) {
-                        document.courseresform.authorpath.selectedIndex = 0;
-                    }
+                document.courseresform.authorrole.selectedIndex = 0;
+                document.courseresform.authorpath.selectedIndex = 0;
+                document.courseresform.newresourceadd.selectedIndex = 0;
+                populateDirSelects(form,'authorrole','authorpath',1,0,0);
+                toggleNewInCourse(document.courseresform);
+                if (document.getElementById('newresource')) {
+                    document.getElementById('newresource').style.display = 'none';
                 }
                 if (document.courseresform.newresusetemp.length) {
                     document.courseresform.newresusetemp[0].checked = true;
@@ -7953,7 +8238,8 @@ function toggleNewsubdir(form) {
 
 function toggleCrsResTitle() {
     if (document.getElementById('newresource')) {
-        if (document.courseresform.authorrole.options[document.courseresform.authorrole.selectedIndex].value == 'course') {
+        var selloc = document.courseresform.authorrole.options[document.courseresform.authorrole.selectedIndex].value;
+        if (selloc == 'course') {
             document.getElementById('newresource').style.display = 'inline';
             document.courseresform.newresourceadd[0].checked = true;
             toggleNewInCourse(document.courseresform);
@@ -8060,7 +8346,22 @@ function toggleImportCrsres(caller) {
             var curr = document.getElementById('importcrsresform').style.display;
             if (curr == 'none') {
                 disp='block';
-                populateCrsSelects(document.crsresimportform,'coursepath','coursefile',1,'',1,0,1,1);
+                populateCrsSelects(document.crsresimportform,'coursepath','coursefile',1,'',1,0,1,1,0);
+                if ((document.getElementById('importcrsrescontent')) &&
+                    (document.getElementById('importcrsresempty'))) {
+                    var selelem = document.crsresimportform.elements['coursepath'];
+                    var numdirs = 0;
+                    if (selelem.options.length) {
+                        numdirs = selelem.options.length - 1;
+                    }
+                    if (numdirs) {
+                        document.getElementById('importcrsrescontent').style.display='block';
+                        document.getElementById('importcrsresempty').style.display='none';
+                    } else {
+                        document.getElementById('importcrsrescontent').style.display='none';
+                        document.getElementById('importcrsresempty').style.display='block';
+                    }
+                }
             }
         }
         document.getElementById('importcrsresform').style.display=disp;
@@ -8071,6 +8372,100 @@ function toggleImportCrsres(caller) {
 
 $showfile_js
 
+function populateDirSelects(form,locsel,dirsel,setdir,recurse,nonemptydir) {
+    var location = form.elements[locsel].options[form.elements[locsel].selectedIndex].value;
+    if ((setdir) && (dirsel != null) && (dirsel != 'undefined') && (dirsel != '')) {
+        var selelem = form.elements[dirsel];
+        var i, numfiles = selelem.options.length -1;
+        if (numfiles >=0) {
+            for (i = numfiles; i >= 0; i--) {
+                selelem.remove(i);
+            }
+        }
+        if ((location == '') || (location == null) || (location == 'undefined')) {
+             if (selelem.options.length == 0) {
+                 selelem.options[selelem.options.length] = new Option('','');
+                 selelem.selectedIndex = 0;
+             }
+             if (document.getElementById('newstdproblem')) {
+                 document.getElementById('newstdproblem').style.display = 'none';
+             }
+             return;
+        }
+        var machineIds = new Array($machines_str);
+        var athome = 0;
+        var role = location;
+        if ((location == 'author') || (location == 'course')) {
+            if (document.getElementById('rolehome_'+location)) {
+                var currhome = document.getElementById('rolehome_'+location).value;
+                if ((currhome != '') && (currhome != null) && (currhome != 'undefined')) {
+                    if (machineIds.includes(currhome)) {
+                        athome = 1;
+                    }
+                }
+            }
+        } else {
+            const roleinfo = location.split('___');
+            role = encodeURIComponent(roleinfo[0]+'./'+roleinfo[1]);
+            if (document.getElementById('rolehome_coauthor_'+roleinfo[1]+'_'+roleinfo[0])) {
+                var currhome = document.getElementById('rolehome_coauthor_'+roleinfo[1]+'_'+roleinfo[0]).value;
+                if ((currhome != '') && (currhome != null) && (currhome != 'undefined')) {
+                    if (machineIds.includes(currhome)) {
+                        athome = 1;
+                    }
+                }
+            }
+        }
+        if (athome) {
+            if (document.getElementById('stdprobswitch')) {
+                document.getElementById('stdprobswitch').style.display = 'none';
+            }
+            if (document.getElementById('newstdproblem')) {
+                document.getElementById('newstdproblem').style.display = 'none';
+            }
+            var http = new XMLHttpRequest();
+            var url = "/adm/courseauthor";
+            var params = "role="+role+"&rec="+recurse+"&nonempty="+nonemptydir+"&addtop=1";
+            http.open("POST", url, true);
+            http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+            http.onreadystatechange = function() {
+                if (http.readyState == 4 && http.status == 200) {
+                    var data = JSON.parse(http.responseText);
+                    if (Array.isArray(data.dirs)) {
+                        var len = data.dirs.length;
+                        if (len) {
+                            if (len > 1) {
+                                selelem.options[selelem.options.length] = new Option('$js_lt{sele}','');
+                            }
+                        }
+                        if (len) {
+                            var j;
+                            for (j = 0; j < len; j++) {
+                                selelem.options[selelem.options.length] = new Option(data.dirs[j],data.dirs[j]);
+                            }
+                            selelem.selectedIndex = 0;
+                            if (len == 1) {
+                                toggleCrsResTitle();
+                            }
+                        }
+                    }
+                }
+            }
+            http.send(params);
+        } else {
+            selelem.options[selelem.options.length] = new Option('$js_lt{swit}','switch');
+            selelem.selectedIndex = 0;
+            if (document.getElementById('stdprobswitch')) {
+                document.getElementById('stdprobswitch').style.display = 'block';
+            }
+            if (document.getElementById('newstdproblem')) {
+                document.getElementById('newstdproblem').style.display = 'none';
+            }
+        }
+    }
+    return;
+}
+
 function switchForProb() {
     if (document.courseresform.authorpath.options[document.courseresform.authorpath.selectedIndex].value == 'switch') {
         var url = '/adm/switchserver?otherserver=';
@@ -9102,7 +9497,7 @@ END
 <sourceavail></sourceavail>
 <standards></standards>
 <subject></subject>
-<title></title>
+<title>Course Authoring Rights</title>
 END
                                     close($fh);
                                 }