Diff for /loncom/publisher/lonpublisher.pm between versions 1.157 and 1.295.2.1.2.2

version 1.157, 2003/12/29 19:13:23 version 1.295.2.1.2.2, 2024/06/01 22:41:28
Line 66  invocation by F<loncapa_apache.conf>: Line 66  invocation by F<loncapa_apache.conf>:
   
 =head1 OVERVIEW  =head1 OVERVIEW
   
 Authors can only write-access the C</~authorname/> space. They can  Authors can only write-access the C</priv/domain/authorname/> space. 
 copy resources into the resource area through the publication step,  They can copy resources into the resource area through the 
 and move them back through a recover step. Authors do not have direct  publication step, and move them back through a recover step. 
 write-access to their resource space.  Authors do not have direct write-access to their resource space.
   
 During the publication step, several events will be  During the publication step, several events will be
 triggered. Metadata is gathered, where a wizard manages default  triggered. Metadata is gathered, where a wizard manages default
Line 102  to publication space. Line 102  to publication space.
 Many of the undocumented subroutines implement various magical  Many of the undocumented subroutines implement various magical
 parsing shortcuts.  parsing shortcuts.
   
 =over 4  
   
 =cut  =cut
   
 ######################################################################  ######################################################################
Line 118  use Apache::File; Line 116  use Apache::File;
 use File::Copy;  use File::Copy;
 use Apache::Constants qw(:common :http :methods);  use Apache::Constants qw(:common :http :methods);
 use HTML::LCParser;  use HTML::LCParser;
   use HTML::Entities;
   use Encode::Encoder;
 use Apache::lonxml;  use Apache::lonxml;
 use Apache::loncacc;  
 use DBI;  use DBI;
 use Apache::lonnet();  use Apache::lonnet;
 use Apache::loncommon();  use Apache::loncommon();
   use Apache::lonhtmlcommon;
 use Apache::lonmysql;  use Apache::lonmysql;
 use Apache::lonlocal;  use Apache::lonlocal;
 use Apache::loncfile;  use Apache::loncfile;
 use Apache::lonmeta;  use LONCAPA::lonmetadata;
   use Apache::lonmsg;
 use vars qw(%metadatafields %metadatakeys);  use vars qw(%metadatafields %metadatakeys);
   use LONCAPA qw(:DEFAULT :match);
    
   
 my %addid;  my %addid;
 my %nokey;  my %nokey;
Line 137  my $docroot; Line 140  my $docroot;
 my $cuname;  my $cuname;
 my $cudom;  my $cudom;
   
   my $registered_cleanup;
   my $modified_urls;
   
   my $lock;
   
 =pod  =pod
   
   =over 4
   
 =item B<metaeval>  =item B<metaeval>
   
 Evaluates a string that contains metadata.  This subroutine  Evaluates a string that contains metadata.  This subroutine
Line 177  sub metaeval { Line 187  sub metaeval {
  if ($token->[0] eq 'S') {   if ($token->[0] eq 'S') {
     my $entry=$token->[1];      my $entry=$token->[1];
     my $unikey=$entry;      my $unikey=$entry;
       next if ($entry =~ m/^(?:parameter|stores)_/);
     if (defined($token->[2]->{'package'})) {       if (defined($token->[2]->{'package'})) { 
  $unikey.='_package_'.$token->[2]->{'package'};   $unikey.="\0package\0".$token->[2]->{'package'};
     }       } 
     if (defined($token->[2]->{'part'})) {       if (defined($token->[2]->{'part'})) { 
  $unikey.='_'.$token->[2]->{'part'};    $unikey.="\0".$token->[2]->{'part'}; 
     }      }
     if (defined($token->[2]->{'id'})) {       if (defined($token->[2]->{'id'})) { 
  $unikey.='_'.$token->[2]->{'id'};   $unikey.="\0".$token->[2]->{'id'};
     }       } 
     if (defined($token->[2]->{'name'})) {       if (defined($token->[2]->{'name'})) { 
  $unikey.='_'.$token->[2]->{'name'};    $unikey.="\0".$token->[2]->{'name'}; 
     }      }
     foreach (@{$token->[3]}) {      foreach my $item (@{$token->[3]}) {
  $metadatafields{$unikey.'.'.$_}=$token->[2]->{$_};   $metadatafields{$unikey.'.'.$item}=$token->[2]->{$item};
  if ($metadatakeys{$unikey}) {   if ($metadatakeys{$unikey}) {
     $metadatakeys{$unikey}.=','.$_;      $metadatakeys{$unikey}.=','.$item;
  } else {   } else {
     $metadatakeys{$unikey}=$_;      $metadatakeys{$unikey}=$item;
  }   }
     }      }
     my $newentry=$parser->get_text('/'.$entry);      my $newentry=$parser->get_text('/'.$entry);
     if ($entry eq 'customdistributionfile') {      if (($entry eq 'customdistributionfile') ||
    ($entry eq 'sourcerights')) {
  $newentry=~s/^\s*//;   $newentry=~s/^\s*//;
  if ($newentry !~m|^/res|) { $newentry=$prefix.$newentry; }   if ($newentry !~m|^/res|) { $newentry=$prefix.$newentry; }
     }      }
 # actually store  # actually store
     $metadatafields{$unikey}=$newentry;      if ( $entry eq 'rule' && exists($metadatafields{$unikey})) {
    $metadatafields{$unikey}.=','.$newentry;
       } else {
    $metadatafields{$unikey}=$newentry;
       }
  }   }
     }      }
 }  }
Line 249  sub metaread { Line 265  sub metaread {
     my ($logfile,$fn,$prefix)=@_;      my ($logfile,$fn,$prefix)=@_;
     unless (-e $fn) {      unless (-e $fn) {
  print($logfile 'No file '.$fn."\n");   print($logfile 'No file '.$fn."\n");
         return '<br /><b>'.&mt('No file').':</b> <tt>'.          return '<p class="LC_warning">'
     &Apache::loncfile::display($fn).'</tt>';                .&mt('No file: [_1]',&Apache::loncfile::display($fn))
                 .'</p>';
     }      }
     print($logfile 'Processing '.$fn."\n");      print($logfile 'Processing '.$fn."\n");
     my $metastring;      my $metastring;
Line 259  sub metaread { Line 276  sub metaread {
  $metastring=join('',<$metafh>);   $metastring=join('',<$metafh>);
     }      }
     &metaeval($metastring,$prefix);      &metaeval($metastring,$prefix);
     return '<br /><b>'.&mt('Processed file').':</b> <tt>'.      return '<p class="LC_info">'
  &Apache::loncfile::display($fn).'</tt>';            .&mt('Processed file: [_1]',&Apache::loncfile::display($fn))
             .'</p>';
 }  }
   
 #########################################  #########################################
Line 269  sub metaread { Line 287  sub metaread {
 sub coursedependencies {  sub coursedependencies {
     my $url=&Apache::lonnet::declutter(shift);      my $url=&Apache::lonnet::declutter(shift);
     $url=~s/\.meta$//;      $url=~s/\.meta$//;
     my ($adomain,$aauthor)=($url=~/^(\w+)\/(\w+)\//);      my ($adomain,$aauthor)=($url=~ m{^($match_domain)/($match_username)/});
     my $regexp=$url;      my $regexp=quotemeta($url);
     $regexp=~s/(\W)/\\$1/g;  
     $regexp='___'.$regexp.'___course';      $regexp='___'.$regexp.'___course';
     my %evaldata=&Apache::lonnet::dump('nohist_resevaldata',$adomain,      my %evaldata=&Apache::lonnet::dump('nohist_resevaldata',$adomain,
        $aauthor,$regexp);         $aauthor,$regexp);
     my %courses=();      my %courses=();
     foreach (keys %evaldata) {      foreach my $item (keys(%evaldata)) {
  if ($_=~/^([a-zA-Z0-9]+_[a-zA-Z0-9]+)___.+___course$/) {   if ($item=~/^([a-zA-Z0-9]+_[a-zA-Z0-9]+)___.+___course$/) {
     $courses{$1}=1;      $courses{$1}=1;
         }          }
     }      }
Line 301  string which presents the form field (fo Line 318  string which presents the form field (fo
   
 =item B<textfield>  =item B<textfield>
   
   =item B<text_with_browse_field>
   
 =item B<hiddenfield>  =item B<hiddenfield>
   
   =item B<checkbox>
   
 =item B<selectbox>  =item B<selectbox>
   
 =back  =back
Line 312  string which presents the form field (fo Line 333  string which presents the form field (fo
 #########################################  #########################################
 #########################################  #########################################
 sub textfield {  sub textfield {
     my ($title,$name,$value)=@_;      my ($title,$name,$value,$noline)=@_;
     $value=~s/^\s+//gs;      $value=~s/^\s+//gs;
     $value=~s/\s+$//gs;      $value=~s/\s+$//gs;
     $value=~s/\s+/ /gs;      $value=~s/\s+/ /gs;
     $title=&mt($title);      $title=&mt($title);
     return "\n<p><font color=\"#800000\" face=\"helvetica\"><b>$title:".      $env{'form.'.$name}=$value;
            "</b></font></p><br />".      return "\n".&Apache::lonhtmlcommon::row_title($title)
            '<input type="text" name="'.$name.'" size=80 value="'.$value.'" />';             .'<input type="text" name="'.$name.'" size="80" value="'.$value.'" />'
              .&Apache::lonhtmlcommon::row_closure($noline);
   }
   
   sub text_with_browse_field {
       my ($title,$name,$value,$restriction,$noline)=@_;
       $value=~s/^\s+//gs;
       $value=~s/\s+$//gs;
       $value=~s/\s+/ /gs;
       $title=&mt($title);
       $env{'form.'.$name}=$value;
       return "\n".&Apache::lonhtmlcommon::row_title($title)
             .'<input type="text" name="'.$name.'" size="80" value="'.$value.'" />'
             .'<br />'
     .'<a href="javascript:openbrowser(\'pubform\',\''.$name.'\',\''.$restriction.'\');">'
             .&mt('Select')
             .'</a>&nbsp;'
     .'<a href="javascript:opensearcher(\'pubform\',\''.$name.'\');">'
             .&mt('Search')
             .'</a>'
             .&Apache::lonhtmlcommon::row_closure($noline);
 }  }
   
 sub hiddenfield {  sub hiddenfield {
     my ($name,$value)=@_;      my ($name,$value)=@_;
       $env{'form.'.$name}=$value;
     return "\n".'<input type="hidden" name="'.$name.'" value="'.$value.'" />';      return "\n".'<input type="hidden" name="'.$name.'" value="'.$value.'" />';
 }  }
   
   sub checkbox {
       my ($name,$text)=@_;
       return "\n<label><input type='checkbox' name='$name' /> ".
    &mt($text)."</label>";
   }
   
 sub selectbox {  sub selectbox {
     my ($title,$name,$value,$functionref,@idlist)=@_;      my ($title,$name,$value,$functionref,@idlist)=@_;
     $title=&mt($title);      $title=&mt($title);
     $value=(split(/\s*,\s*/,$value))[-1];      $value=(split(/\s*,\s*/,$value))[-1];
     my $selout="\n<p><font color=\"#800000\" face=\"helvetica\"><b>$title:".      if (defined($value)) {
  '</b></font></p><br /><select name="'.$name.'">';   $env{'form.'.$name}=$value;
     foreach (@idlist) {      } else {
         $selout.='<option value=\''.$_.'\'';   $env{'form.'.$name}=$idlist[0];
         if ($_ eq $value) {      }
     $selout.=' selected>'.&{$functionref}($_).'</option>';      my $selout="\n".&Apache::lonhtmlcommon::row_title($title)
  }                .'<select name="'.$name.'">';
         else {$selout.='>'.&{$functionref}($_).'</option>';}      foreach my $id (@idlist) {
           $selout.='<option value="'.$id.'"';
           if ($id eq $value) {
       $selout.=' selected="selected"';
           }
           $selout.='>'.&{$functionref}($id).'</option>';
       }
       $selout.='</select>'.&Apache::lonhtmlcommon::row_closure();
       return $selout;
   }
   
   sub select_level_form {
       my ($value,$name)=@_;
       $env{'form.'.$name}=$value;
       if (!defined($value)) { $env{'form.'.$name}=0; }
       return  &Apache::loncommon::select_level_form($value,$name);
   }
   
   sub common_access {
       my ($name,$text,$options)=@_;
       return unless (ref($options) eq 'ARRAY');
       my $formname = 'pubdirpref';
       my $chkname = 'common'.$name;
       my $chkid = 'LC_'.$chkname;
       my $divid = $chkid.'div';
       my $customdivid = 'LC_customfile'; 
       my $selname = $chkname.'select';
       my $selid = $chkid.'select';
       my $selonchange;
       if ($name eq 'dist') {
           $selonchange = ' onchange="showHideCustom(this,'."'$customdivid'".');"';
       }
       my %lt = &Apache::lonlocal::texthash(
                                               'default' => 'System wide - can be used for any courses system wide',
                                               'domain'  => 'Domain only - use limited to courses in the domai',
                                               'custom'  => 'Customized right of use ...',
                                               'public'  => 'Public - no authentication or authorization required for use',
                                               'closed'  => 'Closed - XML source is closed to everyone',
                                               'open'    => 'Open - XML source is open to people who want to use it',
                                               'sel'     => 'Select',
                                           );
       my $output = <<"END";
   <span class="LC_nobreak">
   <label>
   <input type="checkbox" name="commonaccess" value="$name" id="$chkid"  
   onclick="showHideAccess(this,'$divid');" />
   $text</label></span>
   <div id="$divid" style="padding:0;clear:both;margin:0;border:0;display:none">
   <select name="$selname" id="$selid" $selonchange>
   <option value="" selected="selected">$lt{'sel'}</option>
   END
       foreach my $val (@{$options}) {
           $output .= '<option value="'.$val.'">'.$lt{$val}.'</option>'."\n";
       }
       $output .= '
   </select>';
       if ($name eq 'dist') {
           $output .= <<"END";
   <div id="$customdivid" style="padding:0;clear:both;margin:0;border:0;display:none">
   <input type="text" name="commoncustomrights" size="60" value="" />
   <a href="javascript:openbrowser('$formname','commoncustomrights','rights');">
   $lt{'sel'}</a></div>
   END
     }      }
     return $selout.'</select>';      $output .= '
   </div>
   ';
 }  }
   
 #########################################  #########################################
Line 364  sub urlfixup { Line 476  sub urlfixup {
     if ($url =~ /^mailto:/i) { return $url; }      if ($url =~ /^mailto:/i) { return $url; }
     #internal document links need no fixing      #internal document links need no fixing
     if ($url =~ /^\#/) { return $url; }       if ($url =~ /^\#/) { return $url; } 
     my ($host)=($url=~/(?:http\:\/\/)*([^\/]+)/);      my ($host)=($url=~m{(?:(?:http|https|ftp)://)*([^/]+)});
     foreach (values %Apache::lonnet::hostname) {      my @lonids = &Apache::lonnet::machine_ids($host);
  if ($_ eq $host) {      if (@lonids) {
     $url=~s/^http\:\/\///;   $url=~s{^(?:http|https|ftp)://}{};
             $url=~s/^$host//;   $url=~s/^\Q$host\E//;
         }  
     }      }
     if ($url=~/^http\:\/\//) { return $url; }      if ($url=~m{^(?:http|https|ftp)://}) { return $url; }
     $url=~s/\~$cuname/res\/$cudom\/$cuname/;      $url=~s{\Q~$cuname\E}{res/$cudom/$cuname};
     return $url;      return $url;
 }  }
   
Line 413  Currently undocumented Line 524  Currently undocumented
 #########################################  #########################################
 #########################################  #########################################
 sub set_allow {  sub set_allow {
     my ($allow,$logfile,$target,$tag,$oldurl)=@_;      my ($allow,$logfile,$target,$tag,$oldurl,$type)=@_;
     my $newurl=&urlfixup($oldurl,$target);      my $newurl=&urlfixup($oldurl,$target);
     my $return_url=$oldurl;      my $return_url=$oldurl;
     print $logfile 'GUYURL: '.$tag.':'.$oldurl.' - '.$newurl."\n";      print $logfile 'GUYURL: '.$tag.':'.$oldurl.' - '.$newurl."\n";
Line 423  sub set_allow { Line 534  sub set_allow {
     }      }
     if (($newurl !~ /^javascript:/i) &&      if (($newurl !~ /^javascript:/i) &&
  ($newurl !~ /^mailto:/i) &&   ($newurl !~ /^mailto:/i) &&
  ($newurl !~ /^http:/i) &&   ($newurl !~ /^(?:http|https|ftp):/i) &&
  ($newurl !~ /^\#/)) {   ($newurl !~ /^\#/)) {
           if (($type eq 'src') || ($type eq 'href')) {
               if ($newurl =~ /^([^?]+)\?[^?]*$/) {
                   $newurl = $1;
               }
           }
  $$allow{&absoluteurl($newurl,$target)}=1;   $$allow{&absoluteurl($newurl,$target)}=1;
     }      }
     return $return_url      return $return_url;
 }  }
   
 #########################################  #########################################
Line 450  sub get_subscribed_hosts { Line 566  sub get_subscribed_hosts {
     $target=~/(.*)\/([^\/]+)$/;      $target=~/(.*)\/([^\/]+)$/;
     my $srcf=$2;      my $srcf=$2;
     opendir(DIR,$1);      opendir(DIR,$1);
       # cycle through listed files, subscriptions used to exist
       # as "filename.lonid"
     while ($filename=readdir(DIR)) {      while ($filename=readdir(DIR)) {
  if ($filename=~/\Q$srcf\E\.(\w+)$/) {   if ($filename=~/\Q$srcf\E\.($match_lonid)$/) {
     my $subhost=$1;      my $subhost=$1;
     if (($subhost ne 'meta' && $subhost ne 'subscription') &&      if (($subhost ne 'meta' 
    && $subhost ne 'subscription' 
    && $subhost ne 'meta.subscription'
    && $subhost ne 'tmp') &&
                 ($subhost ne $Apache::lonnet::perlvar{'lonHostID'})) {                  ($subhost ne $Apache::lonnet::perlvar{'lonHostID'})) {
  push(@subscribed,$subhost);   push(@subscribed,$subhost);
     }      }
Line 462  sub get_subscribed_hosts { Line 583  sub get_subscribed_hosts {
     closedir(DIR);      closedir(DIR);
     my $sh;      my $sh;
     if ( $sh=Apache::File->new("$target.subscription") ) {      if ( $sh=Apache::File->new("$target.subscription") ) {
  &Apache::lonnet::logthis("opened $target.subscription");  
  while (my $subline=<$sh>) {   while (my $subline=<$sh>) {
     &Apache::lonnet::logthis("Trying $subline");      if ($subline =~ /^($match_lonid):/) { 
     if ($subline =~ /(^\w+):/) {   
                 if ($1 ne $Apache::lonnet::perlvar{'lonHostID'}) {                   if ($1 ne $Apache::lonnet::perlvar{'lonHostID'}) { 
                    push(@subscribed,$1);                     push(@subscribed,$1);
         }          }
             } else {  
  &Apache::lonnet::logthis("No Match for $subline");  
     }      }
  }   }
     } else {  
  &Apache::lonnet::logthis("Unable to open $target.subscription");  
     }      }
     return @subscribed;      return @subscribed;
 }  }
Line 504  sub get_max_ids_indices { Line 619  sub get_max_ids_indices {
     my %duplicatedids;      my %duplicatedids;
   
     my $parser=HTML::LCParser->new($content);      my $parser=HTML::LCParser->new($content);
       $parser->xml_mode(1);
     my $token;      my $token;
     while ($token=$parser->get_token) {      while ($token=$parser->get_token) {
  if ($token->[0] eq 'S') {   if ($token->[0] eq 'S') {
     my $counter;      my $counter;
     if ($counter=$addid{$token->[1]}) {      if ($counter=$addid{$token->[1]}) {
  if ($counter eq 'id') {   if ($counter eq 'id') {
     if (defined($token->[2]->{'id'})) {      if (defined($token->[2]->{'id'}) &&
    $token->[2]->{'id'} !~ /^\s*$/) {
  $maxid=($token->[2]->{'id'}>$maxid)?$token->[2]->{'id'}:$maxid;   $maxid=($token->[2]->{'id'}>$maxid)?$token->[2]->{'id'}:$maxid;
  if (exists($allids{$token->[2]->{'id'}})) {   if (exists($allids{$token->[2]->{'id'}})) {
     $duplicateids=1;      $duplicateids=1;
Line 522  sub get_max_ids_indices { Line 639  sub get_max_ids_indices {
  $needsfixup=1;   $needsfixup=1;
     }      }
  } else {   } else {
     if (defined($token->[2]->{'index'})) {      if (defined($token->[2]->{'index'}) &&
    $token->[2]->{'index'} !~ /^\s*$/) {
  $maxindex=($token->[2]->{'index'}>$maxindex)?$token->[2]->{'index'}:$maxindex;   $maxindex=($token->[2]->{'index'}>$maxindex)?$token->[2]->{'index'}:$maxindex;
     } else {      } else {
  $needsfixup=1;   $needsfixup=1;
Line 564  sub get_all_text_unbalanced { Line 682  sub get_all_text_unbalanced {
  } elsif ($token->[0] eq 'E')  {   } elsif ($token->[0] eq 'E')  {
     $result.=$token->[2];      $result.=$token->[2];
  }   }
  if ($result =~ /(.*)\Q$tag\E(.*)/s) {   if ($result =~ /\Q$tag\E/s) {
       ($result,my $redo)=$result =~ /(.*)\Q$tag\E(.*)/is;
     #&Apache::lonnet::logthis('Got a winner with leftovers ::'.$2);      #&Apache::lonnet::logthis('Got a winner with leftovers ::'.$2);
     #&Apache::lonnet::logthis('Result is :'.$1);      #&Apache::lonnet::logthis('Result is :'.$1);
     $result=$1;      $redo=$tag.$redo;
     my $redo=$tag.$2;  
     push (@$pars,HTML::LCParser->new(\$redo));      push (@$pars,HTML::LCParser->new(\$redo));
     $$pars[-1]->xml_mode('1');      $$pars[-1]->xml_mode('1');
     last;      last;
Line 608  sub fix_ids_and_indices { Line 726  sub fix_ids_and_indices {
    join(', ',@duplicatedids));     join(', ',@duplicatedids));
     if ($duplicateids) {      if ($duplicateids) {
  print $logfile "Duplicate ID(s) exist, ".join(', ',@duplicatedids)."\n";   print $logfile "Duplicate ID(s) exist, ".join(', ',@duplicatedids)."\n";
  my $outstring='<font color="red">'.&mt('Unable to publish file, it contains duplicated ID(s), ID(s) need to be unique. The duplicated ID(s) are').': '.join(', ',@duplicatedids).'</font>';   my $outstring='<span class="LC_error">'.&mt('Unable to publish file, it contains duplicated ID(s), ID(s) need to be unique. The duplicated ID(s) are').': '.join(', ',@duplicatedids).'</span>';
  return ($outstring,1);   return ($outstring,1);
     }      }
     if ($needsfixup) {      if ($needsfixup) {
Line 617  sub fix_ids_and_indices { Line 735  sub fix_ids_and_indices {
                 "Max Index: $maxindex (min 10)\n";                  "Max Index: $maxindex (min 10)\n";
     }      }
     my $outstring='';      my $outstring='';
       my $responsecounter=1;
     my @parser;      my @parser;
     $parser[0]=HTML::LCParser->new(\$content);      $parser[0]=HTML::LCParser->new(\$content);
     $parser[-1]->xml_mode(1);      $parser[-1]->xml_mode(1);
Line 631  sub fix_ids_and_indices { Line 750  sub fix_ids_and_indices {
     $allow{$token->[2]->{'src'}}=1;      $allow{$token->[2]->{'src'}}=1;
     next;      next;
  }   }
    if ($lctag eq 'base') { next; }
                   if (($lctag eq 'part') || ($lctag eq 'problem')) {
                       $responsecounter=0;
                   }
                   if ($lctag=~/response$/) { $responsecounter++; }
                   if ($lctag eq 'import') { $responsecounter++; }
  my %parms=%{$token->[2]};   my %parms=%{$token->[2]};
  $counter=$addid{$tag};   $counter=$addid{$tag};
  if (!$counter) { $counter=$addid{$lctag}; }   if (!$counter) { $counter=$addid{$lctag}; }
  if ($counter) {   if ($counter) {
     if ($counter eq 'id') {      if ($counter eq 'id') {
  unless (defined($parms{'id'})) {   unless (defined($parms{'id'}) &&
    $parms{'id'}!~/^\s*$/) {
     $maxid++;      $maxid++;
     $parms{'id'}=$maxid;      $parms{'id'}=$maxid;
     print $logfile 'ID: '.$tag.':'.$maxid."\n";      print $logfile 'ID(new) : '.$tag.':'.$maxid."\n";
    } else {
       print $logfile 'ID(kept): '.$tag.':'.$parms{'id'}."\n";
  }   }
     } elsif ($counter eq 'index') {      } elsif ($counter eq 'index') {
  unless (defined($parms{'index'})) {   unless (defined($parms{'index'}) &&
    $parms{'index'}!~/^\s*$/) {
     $maxindex++;      $maxindex++;
     $parms{'index'}=$maxindex;      $parms{'index'}=$maxindex;
     print $logfile 'Index: '.$tag.':'.$maxindex."\n";      print $logfile 'Index: '.$tag.':'.$maxindex."\n";
  }   }
     }      }
  }   }
  foreach my $type ('src','href','background','bgimg') {                  unless ($parms{'type'} eq 'zombie') {
     foreach my $key (keys(%parms)) {      foreach my $type ('src','href','background','bgimg') {
  if ($key =~ /^$type$/i) {   foreach my $key (keys(%parms)) {
     $parms{$key}=&set_allow(\%allow,$logfile,      if ($key =~ /^$type$/i) {
     $target,$tag,                                  next if (($lctag eq 'img') && ($type eq 'src') && 
     $parms{$key});                                           ($parms{$key} =~ m{^data\:image/gif;base64,}));
    $parms{$key}=&set_allow(\%allow,$logfile,
    $target,$tag,
    $parms{$key},$type);
       }
  }   }
     }      }
  }   }
Line 665  sub fix_ids_and_indices { Line 798  sub fix_ids_and_indices {
     ($lctag eq 'image')) {      ($lctag eq 'image')) {
     my $next_token=$parser[-1]->get_token();      my $next_token=$parser[-1]->get_token();
     if ($next_token->[0] eq 'T') {      if ($next_token->[0] eq 'T') {
                           $next_token->[1] =~ s/[\n\r\f]+//g;
  $next_token->[1]=&set_allow(\%allow,$logfile,   $next_token->[1]=&set_allow(\%allow,$logfile,
     $target,$tag,      $target,$tag,
     $next_token->[1]);      $next_token->[1]);
Line 709  sub fix_ids_and_indices { Line 843  sub fix_ids_and_indices {
  }   }
  my $newparmstring='';   my $newparmstring='';
  my $endtag='';   my $endtag='';
  foreach (keys %parms) {   foreach my $parkey (keys(%parms)) {
     if ($_ eq '/') {      if ($parkey eq '/') {
  $endtag=' /';   $endtag=' /';
     } else {       } else { 
  my $quote=($parms{$_}=~/\"/?"'":'"');   my $quote=($parms{$parkey}=~/\"/?"'":'"');
  $newparmstring.=' '.$_.'='.$quote.$parms{$_}.$quote;   $newparmstring.=' '.$parkey.'='.$quote.$parms{$parkey}.$quote;
     }      }
  }   }
  if (!$endtag) { if ($token->[4]=~m:/>$:) { $endtag=' /'; }; }   if (!$endtag) { if ($token->[4]=~m:/>$:) { $endtag=' /'; }; }
  $outstring.='<'.$tag.$newparmstring.$endtag.'>';   $outstring.='<'.$tag.$newparmstring.$endtag.'>';
  if ($lctag eq 'm' || $lctag eq 'script'    if ($lctag eq 'm' || $lctag eq 'answer' || $lctag eq 'display' ||
                     || $lctag eq 'display' || $lctag eq 'tex') {                      $lctag eq 'tex') {
     $outstring.=&get_all_text_unbalanced('/'.$lctag,\@parser);      $outstring.=&get_all_text_unbalanced('/'.$lctag,\@parser);
  }                  } elsif ($lctag eq 'script') {
                       if ($parms{'type'} eq 'loncapa/perl') {
                           $outstring.=&get_all_text_unbalanced('/'.$lctag,\@parser);
                       } else {
                           my $script = &get_all_text_unbalanced('/'.$lctag,\@parser);
                           if ($script =~ m{\.set\w+(Src|Swf)\(["']}i) {
                               my @srcs = split(/\.set/i,$script);
                               if (scalar(@srcs) > 1) {
                                   foreach my $item (@srcs) {
                                       if ($item =~ m{^(FlashPlayerSwf|MediaSrc|XMPSrc|ConfigurationSrc|PosterImageSrc)\((['"])(?:(?!\2).)+\2\)}is) {
                                           my $srctype = $1;
                                           my $quote = $2;
                                           my ($url) = ($item =~ m{^\Q$srctype($quote\E([^$quote]+)\Q$quote)\E});
                                           $url = &urlfixup($url);
                                           unless ($url=~m{^(?:http|https|ftp)://}) {
                                               $allow{&absoluteurl($url,$target)}=1;
                                               if ($srctype eq 'ConfigurationSrc') {
                                                   if ($url =~ m{^(.+/)configuration_express\.xml$}) {
   #
   # Camtasia 8.1: express_show/spritesheet.png needed, and included in zip archive.
   # Not referenced directly in <main>.html or <main>_player.html files,
   # so add this file to %allow (where <main> is name user gave to file/archive).
   #
                                                       my $spritesheet = $1.'express_show/spritesheet.png';
                                                       $allow{&absoluteurl($spritesheet,$target)}=1;
   
   #
   # Camtasia 8.4: skins/express_show/spritesheet.min.css needed, and included in zip archive.
   # Not referenced directly in <main>.html or <main>_player.html files,
   # so add this file to %allow (where <main> is name user gave to file/archive).
   #
                                                       my $spritecss = $1.'express_show/spritesheet.min.css';
                                                       $allow{&absoluteurl($spritecss,$target)}=1;
                                                   }
                                               } elsif ($srctype eq 'PosterImageSrc') {
                                                   if ($url =~ m{^(.+)_First_Frame\.png$}) {
                                                       my $prefix = $1;
   #
   # Camtasia 8.1: <main>_Thumbnails.png needed, and included in zip archive.
   # Not referenced directly in <main>.html or <main>_player.html files,
   # so add this file to %allow (where <main> is name user gave to file/archive).
   #
                                                       my $thumbnail = $prefix.'_Thumbnails.png';
                                                       $allow{&absoluteurl($thumbnail,$target)}=1;
                                                   }
                                               }
                                           }
                                       }
                                   }
                               }
                           }
                           if ($script =~ m{\.addMediaSrc\((["'])((?!\1).+)\1\);}) {
                               my $src = $2;
                               if ($src) {
                                   my $url = &urlfixup($src);
                                   unless ($url=~m{^(?:http|https|ftp)://}) {
                                       $allow{&absoluteurl($url,$target)}=1;
                                   }
                               }
                           }
                           if ($script =~ /\(document,\s*(['"])script\1,\s*\[([^\]]+)\]\);/s) {
                               my $scriptslist = $2;
                               my @srcs = split(/\s*,\s*/,$scriptslist);
                               foreach my $src (@srcs) {
                                   if ($src =~ /(["'])(?:(?!\1).)+\.js\1/) {
                                       my $quote = $1;
                                       my ($url) = ($src =~ m/\Q$quote\E([^$quote]+)\Q$quote\E/);
                                       $url = &urlfixup($url);
                                       unless ($url=~m{^(?:http|https|ftp)://}) {
                                           $allow{&absoluteurl($url,$target)}=1;
                                       }
                                   }
                               }
                           }
                           if ($script =~ m{loadScript\(\s*(['"])((?:(?!\1).)+\.js)\1,\s*function}is) {
                               my $src = $2;
                               if ($src) {
                                   my $url = &urlfixup($src);
                                   unless ($url=~m{^(?:http|https|ftp)://}) {
                                       $allow{&absoluteurl($url,$target)}=1;
                                   }
                               }
                           }
                           $outstring .= $script;
                       }
                   }
     } elsif ($token->[0] eq 'E') {      } elsif ($token->[0] eq 'E') {
  if ($token->[2]) {   if ($token->[2]) {
     unless ($token->[1] eq 'allow') {      unless ($token->[1] eq 'allow') {
  $outstring.='</'.$token->[1].'>';   $outstring.='</'.$token->[1].'>';
     }      }
  }                  }
                   if ((($token->[1] eq 'part') || ($token->[1] eq 'problem'))
                       && (!$responsecounter)) {
                       my $outstring='<span class="LC_error">'.&mt('Found [_1] without responses. This resource cannot be published.',$token->[1]).'</span>';
                       return ($outstring,1);
                   }
     } else {      } else {
  $outstring.=$token->[1];   $outstring.=$token->[1];
     }      }
Line 771  sub store_metadata { Line 995  sub store_metadata {
     # Determine if the table exists      # Determine if the table exists
     my $status = &Apache::lonmysql::check_table('metadata');      my $status = &Apache::lonmysql::check_table('metadata');
     if (! defined($status)) {      if (! defined($status)) {
         $error='<font color="red">WARNING: Cannot connect to '.          $error='<span class="LC_error">'
             'database!</font>';                .&mt('WARNING: Cannot connect to database!')
                 .'</span>';
         &Apache::lonnet::logthis($error);          &Apache::lonnet::logthis($error);
         return ($error,undef);          return ($error,undef);
     }      }
     if ($status == 0) {      if ($status == 0) {
         # It would be nice to actually create the table....          # It would be nice to actually create the table....
         $error ='<font color="red">WARNING: The metadata table does not '.          $error ='<span class="LC_error">'
             'exist in the LON-CAPA database.</font>';                 .&mt('WARNING: The metadata table does not exist in the LON-CAPA database!')
                  .'</span>';
         &Apache::lonnet::logthis($error);          &Apache::lonnet::logthis($error);
         return ($error,undef);          return ($error,undef);
     }      }
     if (($metadata{'obsolete'}) || ($metadata{'copyright'} eq 'priv') ||      my $dbh = &Apache::lonmysql::get_dbh();
  ($metadata{'copyright'} eq 'custom')) {      if (($metadata{'obsolete'}) || ($metadata{'copyright'} eq 'priv')) {
 # remove this entry          # remove this entry
  $status=&Apache::lonmysql::remove_from_table   my $delitem = 'url = '.$dbh->quote($metadata{'url'});
     ('metadata','url',$metadata{'url'});   $status = &LONCAPA::lonmetadata::delete_metadata($dbh,undef,$delitem);
                                                          
     } else {      } else {
 # store new data          $status = &LONCAPA::lonmetadata::update_metadata($dbh,undef,undef,
 # adjust some values to metadatadatabase (e.g., "usage" is a reserved word)                                                           \%metadata);
  $metadata{'creationdate'}=  
     &Apache::lonmysql::sqltime($metadata{'creationdate'});   
  $metadata{'lastrevisiondate'}=  
     &Apache::lonmysql::sqltime($metadata{'lastrevisiondate'});  
  $metadata{'sequsage'}=$metadata{'usage'};  
  $metadata{'sequsage_list'}=$metadata{'usage_list'};  
  my %newmetadata=();  
 # see if we have old entries  
  my @oldmeta=&Apache::lonmysql::get_rows('metadata',  
  "url LIKE BINARY '".  
  $metadata{'url'}."'");  
  if ($#oldmeta==0) {  
 # yes, there is one old entry, transfer to newmetadata  
     %newmetadata=&Apache::lonmeta::metadata_col_to_hash(@{$oldmeta[0]});  
 # remove old entry  
     $status=&Apache::lonmysql::remove_from_table  
  ('metadata','url',$metadata{'url'});  
  } elsif ($#oldmeta>0) {  
 # more than one entry fit - how did that happen?  
     $error='<font color="red">Error occured retrieving old values in '.  
       'metadata table in LON-CAPA database: '.$#oldmeta.  
       ' matches</font>';  
     &Apache::lonnet::logthis($error);  
     return ($error,undef);  
  }  
 # store new data on top of it  
  foreach (keys %metadata) {  
     $newmetadata{$_}=$metadata{$_};  
  }  
  $status = &Apache::lonmysql::store_row('metadata',\%newmetadata);  
     }      }
     if (! defined($status)) {      if (defined($status) && $status ne '') {
         $error='<font color="red">Error occured storing new values in '.          $error='<span class="LC_error">'
             'metadata table in LON-CAPA database</font>';                .&mt('Error occurred saving new values in metadata table in LON-CAPA database!')
                 .'</span>';
         &Apache::lonnet::logthis($error);          &Apache::lonnet::logthis($error);
           &Apache::lonnet::logthis($status);
         return ($error,undef);          return ($error,undef);
     }      }
     return (undef,$status);      return (undef,'success');
 }  }
   
   
   # ========================================== Parse file for errors and warnings
   
   sub checkonthis {
       my ($r,$source)=@_;
       my $uri=&Apache::lonnet::hreflocation($source);
       $uri=~s/\/$//;
       my $result=&Apache::lonnet::ssi_body($uri,
    ('grade_target'=>'web',
     'return_only_error_and_warning_counts' => 1));
       my ($errorcount,$warningcount)=split(':',$result);
       if (($errorcount) || ($warningcount)) {
           $r->print('<h3>'.&mt('Warnings and Errors').'</h3>');
           $r->print('<tt>'.$uri.'</tt>:');
           $r->print('<ul>');
           if ($warningcount) {
               $r->print('<li><div class="LC_warning">'
                        .&mt('[quant,_1,warning]',$warningcount)
                        .'</div></li>');
           }
           if ($errorcount) {
               $r->print('<li><div class="LC_error">'
                        .&mt('[quant,_1,error]',$errorcount)
                        .' <img src="/adm/lonMisc/bomb.gif" />'
                        .'</div></li>');
           }
           $r->print('</ul>');
       } else {
    #$r->print('<font color="green">'.&mt('ok').'</font>');
       }
       $r->rflush();
       return ($warningcount,$errorcount);
   }
   
 # ============================================== Parse file itself for metadata  # ============================================== Parse file itself for metadata
 #  #
 # parses a file with target meta, sets global %metadatafields %metadatakeys   # parses a file with target meta, sets global %metadatafields %metadatakeys 
Line 863  backup copies, performs any automatic pr Line 1095  backup copies, performs any automatic pr
 especially for rat and ssi files),  especially for rat and ssi files),
   
 Returns a 2 element array, the first is the string to be shown to the  Returns a 2 element array, the first is the string to be shown to the
 user, the second is an error code, either 1 (an error occured) or 0  user, the second is an error code, either 1 (an error occurred) or 0
 (no error occurred)  (no error occurred)
   
 I<Additional documentation needed.>  I<Additional documentation needed.>
Line 882  sub publish { Line 1114  sub publish {
     my %allow=();      my %allow=();
   
     unless ($logfile=Apache::File->new('>>'.$source.'.log')) {      unless ($logfile=Apache::File->new('>>'.$source.'.log')) {
  return ('<font color="red">'.&mt('No write permission to user directory, FAIL').'</font>',1);   return ('<span class="LC_error">'.&mt('No write permission to user directory, FAIL').'</span>',1);
     }      }
     print $logfile       print $logfile 
 "\n\n================= Publish ".localtime()." Phase One  ================\n".$ENV{'user.name'}.'@'.$ENV{'user.domain'}."\n";  "\n\n================= Publish ".localtime()." Phase One  ================\n".$env{'user.name'}.':'.$env{'user.domain'}."\n";
   
     if (($style eq 'ssi') || ($style eq 'rat') || ($style eq 'prv')) {      if (($style eq 'ssi') || ($style eq 'rat') || ($style eq 'prv')) {
 # ------------------------------------------------------- This needs processing  # ------------------------------------------------------- This needs processing
Line 896  sub publish { Line 1128  sub publish {
     print $logfile "Copied original file to ".$copyfile."\n";      print $logfile "Copied original file to ".$copyfile."\n";
         } else {          } else {
     print $logfile "Unable to write backup ".$copyfile.':'.$!."\n";      print $logfile "Unable to write backup ".$copyfile.':'.$!."\n";
     return ("<font color=\"red\">Failed to write backup copy, $!,FAIL</font>",1);      return ("<span class=\"LC_error\">".&mt("Failed to write backup copy, [_1], FAIL",$1)."</span>",1);
         }          }
 # ------------------------------------------------------------- IDs and indices  # ------------------------------------------------------------- IDs and indices
   
Line 906  sub publish { Line 1138  sub publish {
  if ($error) { return ($outstring,$error); }   if ($error) { return ($outstring,$error); }
 # ------------------------------------------------------------ Construct Allows  # ------------------------------------------------------------ Construct Allows
           
  $scrout.='<h3>'.&mt('Dependencies').'</h3>';          my $outdep=''; # Collect dependencies output data
         my $allowstr='';          my $allowstr='';
         foreach (sort(keys(%allow))) {          foreach my $thisdep (sort(keys(%allow))) {
    my $thisdep=$_;  
    if ($thisdep !~ /[^\s]/) { next; }     if ($thisdep !~ /[^\s]/) { next; }
              if ($thisdep =~/\$/) {
                 $outdep.='<div class="LC_warning">'
                          .&mt('The resource depends on another resource with variable filename, i.e., [_1].','<tt>'.$thisdep.'</tt>').'<br />'
                          .&mt('You likely need to explicitly allow access to all possible dependencies using the [_1]-tag.','<tt>&lt;allow&gt;</tt>')
                          ."</div>\n";
              }
            unless ($style eq 'rat') {              unless ($style eq 'rat') { 
               $allowstr.="\n".'<allow src="'.$thisdep.'" />';                $allowstr.="\n".'<allow src="'.$thisdep.'" />';
    }     }
            $scrout.='<br />';            $outdep.='<div>';
            unless ($thisdep=~/\*/) {             if ($thisdep!~/[\*\$]/ && $thisdep!~m|^/adm/|) {
        $scrout.='<a href="'.$thisdep.'">';         $outdep.='<a href="'.$thisdep.'">';
            }             }
            $scrout.='<tt>'.$thisdep.'</tt>';             $outdep.='<tt>'.$thisdep.'</tt>';
            unless ($thisdep=~/\*/) {             if ($thisdep!~/[\*\$]/ && $thisdep!~m|^/adm/|) {
        $scrout.='</a>';         $outdep.='</a>';
                if (                 if (
        &Apache::lonnet::getfile($Apache::lonnet::perlvar{'lonDocRoot'}.'/'.         &Apache::lonnet::getfile($Apache::lonnet::perlvar{'lonDocRoot'}.'/'.
                                             $thisdep.'.meta') eq '-1') {                                              $thisdep.'.meta') eq '-1') {
    $scrout.= ' - <font color="red">'.&mt('Currently not available').     $outdep.= ' - <span class="LC_error">'.&mt('Currently not available').
        '</font>';         '</span>';
                } else {                 } else {
   #
   # Store the fact that the dependency has been used by the target file
   # Unfortunately, usage is erroneously named sequsage in lonmeta.pm
   # The translation happens in lonmetadata.pm
   #
                    my %temphash=(&Apache::lonnet::declutter($target).'___'.                     my %temphash=(&Apache::lonnet::declutter($target).'___'.
                              &Apache::lonnet::declutter($thisdep).'___usage'                               &Apache::lonnet::declutter($thisdep).'___usage'
                                  => time);                                   => time);
                    $thisdep=~/^\/res\/(\w+)\/(\w+)\//;                     $thisdep=~m{^/res/($match_domain)/($match_username)/};
                    if ((defined($1)) && (defined($2))) {                     if ((defined($1)) && (defined($2))) {
                       &Apache::lonnet::put('nohist_resevaldata',\%temphash,                        &Apache::lonnet::put('nohist_resevaldata',\%temphash,
    $1,$2);     $1,$2);
    }     }
        }         }
            }             }
              $outdep.='</div><br />';
         }          }
         $outstring=~s/\n*(\<\/[^\>]+\>)\s*$/$allowstr\n$1\n/s;  
   
 ### FIXME: is this really what we want?          if ($outdep) {
 # I dont' think so, to will corrupt any UTF-8 resources at least,               $scrout.='<h3>'.&mt('Dependencies').'</h3>'
 # and any encoding other than ISO-8859-1 will probably break                      .$outdep
  #Encode any High ASCII characters          }
  #$outstring=&HTML::Entities::encode($outstring,"\200-\377");          $outstring=~s/\n*(\<\/[^\>]+\>[^<]*)$/$allowstr\n$1\n/s;
   
 # ------------------------------------------------------------- Write modified.  # ------------------------------------------------------------- Write modified.
   
         {          {
           my $org;            my $org;
           unless ($org=Apache::File->new('>'.$source)) {            unless ($org=Apache::File->new('>'.$source)) {
              print $logfile "No write permit to $source\n";               print $logfile "No write permit to $source\n";
              return ('<font color="red">'.&mt('No write permission to').               return ('<span class="LC_error">'.&mt('No write permission to').
      ' '.$source.       ' '.$source.
      ', '.&mt('FAIL').'</font>',1);       ', '.&mt('FAIL').'</span>',1);
   }    }
           print($org $outstring);            print($org $outstring);
         }          }
Line 971  sub publish { Line 1214  sub publish {
      my %oldparmstores=();       my %oldparmstores=();
             
     unless ($batch) {      unless ($batch) {
      $scrout.='<h3>'.&mt('Metadata Information').' ' .       $scrout.='<h3>'.&mt('Metadata').' ' .
        Apache::loncommon::help_open_topic("Metadata_Description")         &Apache::loncommon::help_open_topic("Metadata_Description")
        . '</h3>';         . '</h3>';
     }      }
   
 # ------------------------------------------------ First, check out environment  # ------------------------------------------------ First, check out environment
      unless (-e $source.'.meta') {       if ((!(-e $source.'.meta')) || ($env{'form.forceoverride'})) {
         $metadatafields{'author'}=$ENV{'environment.firstname'}.' '.          $metadatafields{'author'}=$env{'environment.firstname'}.' '.
                           $ENV{'environment.middlename'}.' '.                            $env{'environment.middlename'}.' '.
                   $ENV{'environment.lastname'}.' '.                    $env{'environment.lastname'}.' '.
                   $ENV{'environment.generation'};                    $env{'environment.generation'};
         $metadatafields{'author'}=~s/\s+/ /g;          $metadatafields{'author'}=~s/\s+/ /g;
         $metadatafields{'author'}=~s/\s+$//;          $metadatafields{'author'}=~s/\s+$//;
         $metadatafields{'owner'}=$cuname.'@'.$cudom;          $metadatafields{'owner'}=$cuname.':'.$cudom;
   
 # ------------------------------------------------ Check out directory hierachy  # ------------------------------------------------ Check out directory hierachy
   
         my $thisdisfn=$source;          my $thisdisfn=$source;
         $thisdisfn=~s/^\/home\/\Q$cuname\E\///;  
   
         my @urlparts=split(/\//,$thisdisfn);          $thisdisfn=~s/^\Q$docroot\E\/priv\/\Q$cudom\E\/\Q$cuname\E\///;
           my @urlparts=('.',split(/\//,$thisdisfn));
         $#urlparts--;          $#urlparts--;
   
         my $currentpath='/home/'.$cuname.'/';          my $currentpath=$docroot.'/priv/'.$cudom.'/'.$cuname.'/';
   
  my $prefix='../'x($#urlparts);   my $prefix='../'x($#urlparts);
         foreach (@urlparts) {          foreach my $subdir (@urlparts) {
     $currentpath.=$_.'/';      $currentpath.=$subdir.'/';
             $scrout.=&metaread($logfile,$currentpath.'default.meta',$prefix);              $scrout.=&metaread($logfile,$currentpath.'default.meta',$prefix);
     $prefix=~s|^\.\./||;      $prefix=~s|^\.\./||;
         }          }
   
 # ----------------------------------------------------------- Parse file itself  # ----------------------------------------------------------- Parse file itself
 # read %metadatafields from file itself  # read %metadatafields from file itself
     
Line 1009  sub publish { Line 1253  sub publish {
   
 # ------------------- Clear out parameters and stores (there should not be any)  # ------------------- Clear out parameters and stores (there should not be any)
   
         foreach (keys %metadatafields) {          foreach my $field (keys(%metadatafields)) {
     if (($_=~/^parameter/) || ($_=~/^stores/)) {      if (($field=~/^parameter/) || ($field=~/^stores/)) {
  delete $metadatafields{$_};   delete $metadatafields{$field};
             }              }
         }          }
   
Line 1020  sub publish { Line 1264  sub publish {
   
         $scrout.=&metaread($logfile,$source.'.meta');          $scrout.=&metaread($logfile,$source.'.meta');
   
         foreach (keys %metadatafields) {          foreach my $field (keys(%metadatafields)) {
     if (($_=~/^parameter/) || ($_=~/^stores/)) {      if (($field=~/^parameter/) || ($field=~/^stores/)) {
                 $oldparmstores{$_}=1;                  $oldparmstores{$field}=1;
  delete $metadatafields{$_};   delete $metadatafields{$field};
             }              }
         }          }
   # ------------------------------------------------------------- Save some stuff
           my %savemeta=();
           if ($metadatafields{'title'}) { $savemeta{'title'}=$metadatafields{'title'}; }
 # ------------------------------------------ See if anything new in file itself  # ------------------------------------------ See if anything new in file itself
     
  $allmeta=&parseformeta($source,$style);   $allmeta=&parseformeta($source,$style);
   # ----------------------------------------------------------- Restore the stuff
           foreach my $item (keys(%savemeta)) {
       $metadatafields{$item}=$savemeta{$item};
    }
    }     }
   
                 
 # ---------------- Find and document discrepancies in the parameters and stores  # ---------------- Find and document discrepancies in the parameters and stores
   
     my $chparms='';      my $chparms='';
     foreach (sort keys %metadatafields) {      foreach my $field (sort(keys(%metadatafields))) {
  if (($_=~/^parameter/) || ($_=~/^stores/)) {   if (($field=~/^parameter/) || ($field=~/^stores/)) {
     unless ($_=~/\.\w+$/) {       unless ($field=~/\.\w+$/) {
  unless ($oldparmstores{$_}) {   unless ($oldparmstores{$field}) {
     print $logfile 'New: '.$_."\n";      my $disp_key = $field;
     $chparms.=$_.' ';      $disp_key =~ tr/\0/_/;
       print $logfile ('New: '.$disp_key."\n");
       $chparms .= $disp_key.' ';
  }   }
     }      }
  }   }
     }      }
     if ($chparms) {      if ($chparms) {
  $scrout.='<p><b>'.&mt('New parameters or stored values').   $scrout.='<p><b>'.&mt('New parameters or saved values').
     ':</b> '.$chparms.'</p>';      ':</b> '.$chparms.'</p>';
     }      }
   
     $chparms='';      $chparms='';
     foreach (sort keys %oldparmstores) {      foreach my $olditem (sort(keys(%oldparmstores))) {
  if (($_=~/^parameter/) || ($_=~/^stores/)) {   if (($olditem=~/^parameter/) || ($olditem=~/^stores/)) {
     unless (($metadatafields{$_.'.name'}) ||      unless (($metadatafields{$olditem.'.name'}) ||
     ($metadatafields{$_.'.package'}) || ($_=~/\.\w+$/)) {      ($metadatafields{$olditem.'.package'}) || ($olditem=~/\.\w+$/)) {
  print $logfile 'Obsolete: '.$_."\n";   my $disp_key = $olditem;
  $chparms.=$_.' ';   $disp_key =~ tr/\0/_/;
    print $logfile ('Obsolete: '.$disp_key."\n");
    $chparms.=$disp_key.' ';
     }      }
  }   }
     }      }
     if ($chparms) {      if ($chparms) {
  $scrout.='<p><b>'.&mt('Obsolete parameters or stored values').':</b> '.          $scrout.='<p><b>'.&mt('Obsolete parameters or saved values').':</b> '
     $chparms.'</p><h1><font color="red">'.&mt('Warning!').          .$chparms.'</p>'
     '</font></h1><p><font color="red" size="+1">'.                  .'<p class="LC_warning"><b>'.&mt('Warning!').'</b><br />'
     &mt('If this resource is in active use, student performance data from the previous version may become inaccessible.').'</font></p><hr />';                  .&mt('If this resource is in active use, student performance data from the previous version may become inaccessible.')
                   .'</p><hr />';
       }
       if ($metadatafields{'copyright'} eq 'priv') {
           $scrout.='<p class="LC_warning"><b>'.&mt('Warning!').'</b><br />'
                   .&mt('Copyright/distribution option "Private" is no longer supported. Select another option from below. Consider "Custom Rights" for maximum control over the usage of your resource.')
                   .'</p><hr />';
     }      }
   
 # ------------------------------------------------------- Now have all metadata  # ------------------------------------------------------- Now have all metadata
Line 1076  sub publish { Line 1337  sub publish {
  $textonly=~s/\<script[^\<]+\<\/script\>//g;   $textonly=~s/\<script[^\<]+\<\/script\>//g;
  $textonly=~s/\<m\>[^\<]+\<\/m\>//g;   $textonly=~s/\<m\>[^\<]+\<\/m\>//g;
  $textonly=~s/\<[^\>]*\>//g;   $textonly=~s/\<[^\>]*\>//g;
  $textonly=~tr/A-Z/a-z/;  
  $textonly=~s/[\$\&][a-z]\w*//g;  
  $textonly=~s/[^a-z\s]//g;  
   
  foreach ($textonly=~m/(\w+)/g) {  
     unless ($nokey{$_}) {  
  $keywords{$_}=1;  
     }   
  }  
     }  
   
           #this is a work simplification for german authors for present
           $textonly=HTML::Entities::decode($textonly);           #decode HTML-character
           $textonly=Encode::Encoder::encode('utf8', $textonly);  #encode to perl internal unicode
           $textonly=~tr/A-ZÜÄÖ/a-züäö/;      #add lowercase rule for german "Umlaute"
           $textonly=~s/[\$\&][a-z]\w*//g;
           $textonly=~s/[^a-z^ü^ä^ö^ß\s]//g;  #dont delete german "Umlaute"
   
           foreach ($textonly=~m/[^\s]+/g) {  #match all but whitespaces
               unless ($nokey{$_}) {
                   $keywords{$_}=1;
               }
           }
   
   
       }
                           
     foreach (split(/\W+/,$metadatafields{'keywords'})) {      foreach my $addkey (split(/[\"\'\,\;]/,$metadatafields{'keywords'})) {
  $keywords{$_}=1;   $addkey=~s/\s+/ /g;
    $addkey=~s/^\s//;
    $addkey=~s/\s$//;
    if ($addkey=~/\w/) {
       $keywords{$addkey}=1;
    }
     }      }
 # --------------------------------------------------- Now we also have keywords  # --------------------------------------------------- Now we also have keywords
 # =============================================================================  # =============================================================================
 # INTERACTIVE MODE  # interactive mode html goes into $intr_scrout
 #  # batch mode throws away this HTML
     unless ($batch) {  # additionally all of the field functions have a by product of setting
         $scrout.=  #   $env{'from.'..} so that it can be used by the phase two handler in
     '<form name="pubform" action="/adm/publish" method="post">'.  #    batch mode
             '<p><input type="submit" value="'.&mt('Finalize Publication').'" /></p>'.  
             &hiddenfield('phase','two').      my $intr_scrout.='<br />'
             &hiddenfield('filename',$ENV{'form.filename'}).                      .'<form name="pubform" action="/adm/publish" method="post">';
     &hiddenfield('allmeta',&Apache::lonnet::escape($allmeta)).      unless ($env{'form.makeobsolete'}) {
             &hiddenfield('dependencies',join(',',keys %allow)).         $intr_scrout.='<p class="LC_warning">'
             &textfield('Title','title',$metadatafields{'title'}).                      .&mt('Searching for your resource will be based on the following metadata. Please provide as much data as possible.')
             &textfield('Author(s)','author',$metadatafields{'author'}).                      .'</p>'
     &textfield('Subject','subject',$metadatafields{'subject'});                      .'<p><input type="submit" value="'
                       .&mt('Finalize Publication')
 # --------------------------------------------------- Scan content for keywords                      .'" /> <a href="'.&Apache::loncfile::url($source).'">'.&mt('Cancel').'</a></p>';
       }
         my $keywords_help = Apache::loncommon::help_open_topic("Publishing_Keywords");      $intr_scrout.=&Apache::lonhtmlcommon::start_pick_box();
         my $KEYWORDS=&mt('Keywords');      $intr_scrout.=
  my $CheckAll=&mt('check all');   &hiddenfield('phase','two').
  my $UncheckAll=&mt('uncheck all');   &hiddenfield('filename',$env{'form.filename'}).
  my $keywordout=<<"END";   &hiddenfield('allmeta',&escape($allmeta)).
    &hiddenfield('dependencies',join(',',keys(%allow)));
       unless ($env{'form.makeobsolete'}) {
          $intr_scrout.=
    &textfield('Title','title',$metadatafields{'title'}).
    &textfield('Author(s)','author',$metadatafields{'author'}).
    &textfield('Subject','subject',$metadatafields{'subject'});
    # --------------------------------------------------- Scan content for keywords
   
       my $keywords_help = &Apache::loncommon::help_open_topic("Publishing_Keywords");
       my $keywordout=<<"END";
 <script>  <script>
 function checkAll(field) {  function checkAll(field) {
     for (i = 0; i < field.length; i++)      for (i = 0; i < field.length; i++)
Line 1125  function uncheckAll(field) { Line 1406  function uncheckAll(field) {
         field[i].checked = false ;          field[i].checked = false ;
 }  }
 </script>  </script>
 <p><font color="#800000" face="helvetica"><b>$KEYWORDS:</b></font>  
  $keywords_help</b>  
 <input type="button" value="$CheckAll" onclick="javascript:checkAll(document.pubform.keywords)" />   
 <input type="button" value="$UncheckAll" onclick="javascript:uncheckAll(document.pubform.keywords)" />   
 </p>  
 <br />  
 END  END
  $keywordout.='<table border="2"><tr>';      $keywordout.="\n".&Apache::lonhtmlcommon::row_title(&mt('Keywords'))
  my $colcount=0;                  .$keywords_help
                   .'<input type="button" value="'.&mt('check all').'" onclick="javascript:checkAll(document.pubform.keywords)" />'
  foreach (sort keys %keywords) {                  .'<input type="button" value="'.&mt('uncheck all').'" onclick="javascript:uncheckAll(document.pubform.keywords)" />'
     $keywordout.='<td><input type="checkbox" name="keywords" value="'.$_.'"';                  .'</p><br />'
     if ($metadatafields{'keywords'}) {                  .&Apache::loncommon::start_data_table();
  if ($metadatafields{'keywords'}=~/\Q$_\E/) {      my $cols_per_row = 10;
     $keywordout.=' checked="on"';      my $colcount=0;
  }      my $wordcount=0;
     } elsif (&Apache::loncommon::keyword($_)) {      my $numkeywords = scalar(keys(%keywords));
  $keywordout.=' checked="on"';  
     }      foreach my $word (sort(keys(%keywords))) {
     $keywordout.=' />'.$_.'</td>';          if ($colcount == 0) {
     if ($colcount>10) {              $keywordout .= &Apache::loncommon::start_data_table_row();
  $keywordout.="</tr><tr>\n";          }
  $colcount=0;          $colcount++;
     }          $wordcount++;
     $colcount++;          if (($wordcount == $numkeywords) && ($colcount < $cols_per_row)) {
  }              my $colspan = 1+$cols_per_row-$colcount;
               $keywordout .= '<td colspan="'.$colspan.'">';
  $keywordout.='</tr></table>';          } else {
               $keywordout .= '<td>';
  $scrout.=$keywordout;          }
           $keywordout.='<label><input type="checkbox" name="keywords" value="'.$word.'"';
  $scrout.=&textfield('Additional Keywords','addkey','');          if ($metadatafields{'keywords'}) {
               if ($metadatafields{'keywords'}=~/\Q$word\E/) {
                   $keywordout.=' checked="checked"';
                   $env{'form.keywords'}.=$word.',';
               }
           } elsif (&Apache::loncommon::keyword($word)) {
               $keywordout.=' checked="checked"';
               $env{'form.keywords'}.=$word.',';
           }
           $keywordout.=' />'.$word.'</label></td>';
           if ($colcount == $cols_per_row) {
               $keywordout.=&Apache::loncommon::end_data_table_row();
               $colcount=0;
           }
       }
       if ($colcount > 0) {
           $keywordout .= &Apache::loncommon::end_data_table_row();
       }
   
  $scrout.=&textfield('Notes','notes',$metadatafields{'notes'});      $env{'form.keywords'}=~s/\,$//;
   
  $scrout.=      $keywordout.=&Apache::loncommon::end_data_table_row()
     "\n<p><font color=\"#800000\" face=\"helvetica\"><b>".&mt('Abstract').":".                   .&Apache::loncommon::end_data_table()
     "</b></font></p><br />".                   .&Apache::lonhtmlcommon::row_closure();
     '<textarea cols="80" rows="5" name="abstract">'.  
     $metadatafields{'abstract'}.'</textarea></p>';  
   
  $source=~/\.(\w+)$/;      $intr_scrout.=$keywordout;
   
       $intr_scrout.=&textfield('Additional Keywords','addkey','');
   
  $scrout.=      $intr_scrout.=&textfield('Notes','notes',$metadatafields{'notes'});
     "\n<p><font color=\"#800000\" face=\"helvetica\"><b>".  
     &mt('Lowest Grade Level').':'.  
            "</b></font></p><br />".  
    &Apache::loncommon::select_level_form($metadatafields{'lowestgradelevel'},'lowestgradelevel').  
     "\n<p><font color=\"#800000\" face=\"helvetica\"><b>".  
     &mt('Highest Grade Level').':'.  
            "</b></font></p><br />".  
    &Apache::loncommon::select_level_form($metadatafields{'highestgradelevel'},'highestgradelevel').  
            &textfield('Standards','standards',$metadatafields{'standards'});  
   
       $intr_scrout.="\n".&Apache::lonhtmlcommon::row_title(&mt('Abstract'))
                    .'<textarea cols="80" rows="5" name="abstract">'
                    .$metadatafields{'abstract'}
                    .'</textarea>'
                    .&Apache::lonhtmlcommon::row_closure();
   
       $source=~/\.(\w+)$/;
   
       $intr_scrout.="\n".&Apache::lonhtmlcommon::row_title(&mt('Grade Levels'))
                    .&mt('Lowest Grade Level:').'&nbsp;'
                    .&select_level_form($metadatafields{'lowestgradelevel'},'lowestgradelevel')
   #                .&Apache::lonhtmlcommon::row_closure();
   #   $intr_scrout.="\n".&Apache::lonhtmlcommon::row_title(&mt('Highest Grade Level'))
                    .' '.&mt('Highest Grade Level:').'&nbsp;'
                    .&select_level_form($metadatafields{'highestgradelevel'},'highestgradelevel')
                    .&Apache::lonhtmlcommon::row_closure();
   
  $scrout.=&hiddenfield('mime',$1);      $intr_scrout.=&textfield('Standards','standards',$metadatafields{'standards'});
   
  my $defaultlanguage=$metadatafields{'language'};      $intr_scrout.=&hiddenfield('mime',$1);
  $defaultlanguage =~ s/\s*notset\s*//g;  
  $defaultlanguage =~ s/^,\s*//g;  
  $defaultlanguage =~ s/,\s*$//g;  
   
  $scrout.=&selectbox('Language','language',      my $defaultlanguage=$metadatafields{'language'};
     $defaultlanguage,      $defaultlanguage =~ s/\s*notset\s*//g;
     \&Apache::loncommon::languagedescription,      $defaultlanguage =~ s/^,\s*//g;
     (&Apache::loncommon::languageids),      $defaultlanguage =~ s/,\s*$//g;
    );  
   
  unless ($metadatafields{'creationdate'}) {      $intr_scrout.=&selectbox('Language','language',
     $metadatafields{'creationdate'}=time;       $defaultlanguage,
  }       \&Apache::loncommon::languagedescription,
  $scrout.=&hiddenfield('creationdate',       (&Apache::loncommon::languageids),
       &Apache::lonmysql::unsqltime($metadatafields{'creationdate'}));       );
   
  $scrout.=&hiddenfield('lastrevisiondate',time);      unless ($metadatafields{'creationdate'}) {
    $metadatafields{'creationdate'}=time;
       }
       $intr_scrout.=&hiddenfield('creationdate',
          &Apache::lonmysql::unsqltime($metadatafields{'creationdate'}));
   
       $intr_scrout.=&hiddenfield('lastrevisiondate',time);
   
  $scrout.=&textfield('Publisher/Owner','owner',      my $pubowner_last;
     $metadatafields{'owner'});      if ($style eq 'prv') {
           $pubowner_last = 1;
       }
       $intr_scrout.=&textfield('Publisher/Owner','owner',
        $metadatafields{'owner'},$pubowner_last);
   
   # ---------------------------------------------- Retrofix for unused copyright
       if ($metadatafields{'copyright'} eq 'free') {
    $metadatafields{'copyright'}='default';
    $metadatafields{'sourceavail'}='open';
       }
       if ($metadatafields{'copyright'} eq 'priv') {
           $metadatafields{'copyright'}='domain';
       }
   # ------------------------------------------------ Dial in reasonable defaults
       my $defaultoption=$metadatafields{'copyright'};
       unless ($defaultoption) { $defaultoption='default'; }
       my $defaultsourceoption=$metadatafields{'sourceavail'};
       unless ($defaultsourceoption) { $defaultsourceoption='closed'; }
       unless ($style eq 'prv') {
 # -------------------------------------------------- Correct copyright for rat.  # -------------------------------------------------- Correct copyright for rat.
         my $defaultoption=$metadatafields{'copyright'};   if ($style eq 'rat') {
         unless ($defaultoption) { $defaultoption='default'; }  # -------------------------------------- Retrofix for non-applicable copyright
  unless ($style eq 'prv') {      if ($metadatafields{'copyright'} eq 'public') { 
     if ($style eq 'rat') {   delete $metadatafields{'copyright'};
  if ($metadatafields{'copyright'} eq 'public') {    $defaultoption='default';
     delete $metadatafields{'copyright'};      }
                     $defaultoption='default';      $intr_scrout.=&selectbox('Copyright/Distribution','copyright',
  }       $defaultoption,
  $scrout.=&selectbox('Copyright/Distribution','copyright',       \&Apache::loncommon::copyrightdescription,
     $defaultoption,      (grep !/^(public|priv)$/,(&Apache::loncommon::copyrightids)));
     \&Apache::loncommon::copyrightdescription,  
     (grep !/^public$/,(&Apache::loncommon::copyrightids)));  
     } else {  
  $scrout.=&selectbox('Copyright/Distribution','copyright',  
     $defaultoption,  
     \&Apache::loncommon::copyrightdescription,  
     (&Apache::loncommon::copyrightids));  
     }  
       
     my $copyright_help =  
  Apache::loncommon::help_open_topic('Publishing_Copyright');  
     $scrout =~ s/DISTRIBUTION:/'DISTRIBUTION: ' . $copyright_help/ge;  
     $scrout.=&textfield('Custom Distribution File','customdistributionfile',  
  $metadatafields{'customdistributionfile'}).  
     $copyright_help;  
     my $uctitle=uc(&mt('Obsolete'));  
             $scrout.=  
  "\n<p><font color=\"#800000\" face=\"helvetica\"><b>$uctitle:".  
  '</b></font> <input type="checkbox" name="obsolete" ';  
     if ($metadatafields{'obsolete'}) {  
  $scrout.=' checked="1" ';  
     }  
     $scrout.='/ ></p>'.  
  &textfield('Suggested Replacement for Obsolete File',  
     'obsoletereplacement',  
     $metadatafields{'obsoletereplacement'});  
  } else {   } else {
     $scrout.=&hiddenfield('copyright','private');      $intr_scrout.=&selectbox('Copyright/Distribution','copyright',
  }       $defaultoption,
  return ($scrout.'<p><input type="submit" value="'.       \&Apache::loncommon::copyrightdescription,
  &mt('Finalize Publication').'" /></p></form>',0);       (grep !/^priv$/,(&Apache::loncommon::copyrightids)));
 # =============================================================================   }
 # BATCH MODE   my $copyright_help =
 #      &Apache::loncommon::help_open_topic('Publishing_Copyright');
           my $replace=&mt('Copyright/Distribution:');
    $intr_scrout =~ s/$replace/$replace.' '.$copyright_help/ge;
   
    $intr_scrout.=&text_with_browse_field('Custom Distribution File','customdistributionfile',$metadatafields{'customdistributionfile'},'rights');
    $intr_scrout.=&selectbox('Source Distribution','sourceavail',
    $defaultsourceoption,
    \&Apache::loncommon::source_copyrightdescription,
    (&Apache::loncommon::source_copyrightids));
   # $intr_scrout.=&text_with_browse_field('Source Custom Distribution File','sourcerights',$metadatafields{'sourcerights'},'rights');
    my $uctitle=&mt('Obsolete');
           my $obsolete_checked=($metadatafields{'obsolete'})?' checked="checked"':'';
           $intr_scrout.="\n".&Apache::lonhtmlcommon::row_title($uctitle)
                        .'<input type="checkbox" name="obsolete"'.$obsolete_checked.' />'
                        .&Apache::lonhtmlcommon::row_closure(1);
           $intr_scrout.=&text_with_browse_field('Suggested Replacement for Obsolete File',
       'obsoletereplacement',
       $metadatafields{'obsoletereplacement'},'',1);
     } else {      } else {
 # Transfer metadata directly to environment for stage 2   $intr_scrout.=&hiddenfield('copyright','private');
  foreach (keys %metadatafields) {      }
     $ENV{'form.'.$_}=$metadatafields{$_};     } else {
  }         $intr_scrout.=
  $ENV{'form.addkey'}='';   &hiddenfield('title',$metadatafields{'title'}).
  $ENV{'form.keywords'}='';   &hiddenfield('author',$metadatafields{'author'}).
  foreach (keys %keywords) {   &hiddenfield('subject',$metadatafields{'subject'}).
     if ($metadatafields{'keywords'}) {   &hiddenfield('keywords',$metadatafields{'keywords'}).
  if ($metadatafields{'keywords'}=~/\Q$_\E/) {    &hiddenfield('abstract',$metadatafields{'abstract'}).
     $ENV{'form.keywords'}.=$_.',';    &hiddenfield('notes',$metadatafields{'notes'}).
  }   &hiddenfield('mime',$metadatafields{'mime'}).
     } elsif (&Apache::loncommon::keyword($_)) {   &hiddenfield('creationdate',$metadatafields{'creationdate'}).
  $ENV{'form.keywords'}.=$_.',';   &hiddenfield('lastrevisiondate',time).
     }   &hiddenfield('owner',$metadatafields{'owner'}).
  }   &hiddenfield('lowestgradelevel',$metadatafields{'lowestgradelevel'}).
  $ENV{'form.keywords'}=~s/\,$//;   &hiddenfield('standards',$metadatafields{'standards'}).
  unless ($ENV{'form.creationdate'}) { $ENV{'form.creationdate'}=time; }   &hiddenfield('highestgradelevel',$metadatafields{'highestgradelevel'}).
  $ENV{'form.lastrevisiondate'}=time;   &hiddenfield('language',$metadatafields{'language'}).
  if ((($style eq 'rat') && ($ENV{'form.copyright'} eq 'public')) ||   &hiddenfield('copyright',$metadatafields{'copyright'}).
     (!$ENV{'form.copyright'})) {    &hiddenfield('sourceavail',$metadatafields{'sourceavail'}).
     $ENV{'form.copyright'}='default';   &hiddenfield('customdistributionfile',$metadatafields{'customdistributionfile'}).
  }   &hiddenfield('obsolete',1).
  $ENV{'form.allmeta'}=&Apache::lonnet::escape($allmeta);   &text_with_browse_field('Suggested Replacement for Obsolete File',
  return ($scrout,0);      'obsoletereplacement',
       $metadatafields{'obsoletereplacement'},'',1);
      }
       if (!$batch) {
    $scrout.=$intr_scrout
               .&Apache::lonhtmlcommon::end_pick_box()
               .'<p><input type="submit" value="'
       .&mt($env{'form.makeobsolete'}?'Make Obsolete':'Finalize Publication')
               .'" /></p>'
               .'</form>';
     }      }
       return($scrout,0);
 }  }
   
 #########################################  #########################################
Line 1309  Returns: Line 1625  Returns:
   
 =over 4  =over 4
   
 =item Scalar string  =item integer
   
   0: fail
   1: success
   
 String contains status (errors and warnings) and information associated with  =back
 the server's attempts at publication.       
   
 =cut  =cut
   
Line 1324  sub phasetwo { Line 1642  sub phasetwo {
     my ($r,$source,$target,$style,$distarget,$batch)=@_;      my ($r,$source,$target,$style,$distarget,$batch)=@_;
     $source=~s/\/+/\//g;      $source=~s/\/+/\//g;
     $target=~s/\/+/\//g;      $target=~s/\/+/\//g;
   #
     if ($target=~/\_\_\_/) {  # Unless trying to get rid of something, check name validity
  $r->print(  #
  '<font color="red">'.&mt('Unsupported character combination').      unless ($env{'form.obsolete'}) {
   ' "<tt>___</tt>" '.&mt('in filename, FAIL').'</font>');   if ($target=~/(\_\_\_|\&\&\&|\:\:\:)/) {
         return 0;      $r->print('<span class="LC_error">'.
         &mt('Unsupported character combination [_1] in filename, FAIL.',"<tt>'.$1.'</tt>").
         '</span>');
       return 0;
    }
    unless ($target=~/\.(\w+)$/) {
       $r->print('<span class="LC_error">'.&mt('No valid extension found in filename, FAIL').'</span>');
       return 0;
    }
    if ($target=~/\.(\d+)\.(\w+)$/) {
       $r->print('<span class="LC_error">'.&mt('Filename of resource contains internal version number. Cannot publish such resources, FAIL').'</span>');
       return 0;
    }
     }      }
   
   #
   # End name check
   #
     $distarget=~s/\/+/\//g;      $distarget=~s/\/+/\//g;
     my $logfile;      my $logfile;
     unless ($logfile=Apache::File->new('>>'.$source.'.log')) {      unless ($logfile=Apache::File->new('>>'.$source.'.log')) {
  $r->print(   $r->print(
         '<font color="red">'.          '<span class="LC_error">'.
  &mt('No write permission to user directory, FAIL').'</font>');   &mt('No write permission to user directory, FAIL').'</span>');
         return 0;          return 0;
     }      }
       
       if ($source =~ /\.rights$/) {
    $r->print('<p><span class="LC_warning">'.&mt('Warning: It can take up to 1 hour for rights changes to fully propagate.').'</span></p>');
       }
   
     print $logfile       print $logfile 
         "\n================= Publish ".localtime()." Phase Two  ================\n".$ENV{'user.name'}.'@'.$ENV{'user.domain'}."\n";          "\n================= Publish ".localtime()." Phase Two  ================\n".$env{'user.name'}.':'.$env{'user.domain'}."\n";
           
     %metadatafields=();      %metadatafields=();
     %metadatakeys=();      %metadatakeys=();
       
     &metaeval(&Apache::lonnet::unescape($ENV{'form.allmeta'}));      &metaeval(&unescape($env{'form.allmeta'}));
       
     $metadatafields{'title'}=$ENV{'form.title'};      if ($batch) {
     $metadatafields{'author'}=$ENV{'form.author'};          my %commonaccess;
     $metadatafields{'subject'}=$ENV{'form.subject'};          map { $commonaccess{$_} = 1; } &Apache::loncommon::get_env_multiple('form.commonaccess');
     $metadatafields{'notes'}=$ENV{'form.notes'};          if ($commonaccess{'dist'}) {
     $metadatafields{'abstract'}=$ENV{'form.abstract'};              unless ($style eq 'prv') { 
     $metadatafields{'mime'}=$ENV{'form.mime'};                  if ($env{'form.commondistselect'} eq 'custom') {
     $metadatafields{'language'}=$ENV{'form.language'};                      unless ($source =~ /\.rights$/) {
     $metadatafields{'creationdate'}=$ENV{'form.creationdate'};                          if ($env{'form.commoncustomrights'} =~ m{^/res/.+\.rights$}) { 
     $metadatafields{'lastrevisiondate'}=$ENV{'form.lastrevisiondate'};                              $env{'form.customdistributionfile'} = $env{'form.commoncustomrights'}; 
     $metadatafields{'owner'}=$ENV{'form.owner'};                              $env{'form.copyright'} = $env{'form.commondistselect'};
     $metadatafields{'copyright'}=$ENV{'form.copyright'};                          }
     $metadatafields{'standards'}=$ENV{'form.standards'};                      }
     $metadatafields{'lowestgradelevel'}=$ENV{'form.lowestgradelevel'};                  } elsif ($env{'form.commondistselect'} =~ /^default|domain|public$/) {
     $metadatafields{'highestgradelevel'}=$ENV{'form.highestgradelevel'};                      $env{'form.copyright'} = $env{'form.commondistselect'};
                   }
               }
           }
           unless ($style eq 'prv') {
               if ($commonaccess{'source'}) {
                   if (($env{'form.commonsourceselect'} eq 'open') || ($env{'form.commonsourceselect'} eq 'closed')) {
                       $env{'form.sourceavail'} = $env{'form.commonsourceselect'};
                   }
               }
           }
       }
   
       $metadatafields{'title'}=$env{'form.title'};
       $metadatafields{'author'}=$env{'form.author'};
       $metadatafields{'subject'}=$env{'form.subject'};
       $metadatafields{'notes'}=$env{'form.notes'};
       $metadatafields{'abstract'}=$env{'form.abstract'};
       $metadatafields{'mime'}=$env{'form.mime'};
       $metadatafields{'language'}=$env{'form.language'};
       $metadatafields{'creationdate'}=$env{'form.creationdate'};
       $metadatafields{'lastrevisiondate'}=$env{'form.lastrevisiondate'};
       $metadatafields{'owner'}=$env{'form.owner'};
       $metadatafields{'copyright'}=$env{'form.copyright'};
       $metadatafields{'standards'}=$env{'form.standards'};
       $metadatafields{'lowestgradelevel'}=$env{'form.lowestgradelevel'};
       $metadatafields{'highestgradelevel'}=$env{'form.highestgradelevel'};
     $metadatafields{'customdistributionfile'}=      $metadatafields{'customdistributionfile'}=
                                  $ENV{'form.customdistributionfile'};                                   $env{'form.customdistributionfile'};
     $metadatafields{'obsolete'}=$ENV{'form.obsolete'};      $metadatafields{'sourceavail'}=$env{'form.sourceavail'};
       $metadatafields{'obsolete'}=$env{'form.obsolete'};
     $metadatafields{'obsoletereplacement'}=      $metadatafields{'obsoletereplacement'}=
                         $ENV{'form.obsoletereplacement'};                          $env{'form.obsoletereplacement'};
     $metadatafields{'dependencies'}=$ENV{'form.dependencies'};      $metadatafields{'dependencies'}=$env{'form.dependencies'};
     $metadatafields{'modifyinguser'}=$ENV{'user.name'}.'@'.      $metadatafields{'modifyinguser'}=$env{'user.name'}.':'.
                                  $ENV{'user.domain'};                                   $env{'user.domain'};
     $metadatafields{'authorspace'}=$cuname.'@'.$cudom;      $metadatafields{'authorspace'}=$cuname.':'.$cudom;
       $metadatafields{'domain'}=$cudom;
           
     my $allkeywords=$ENV{'form.addkey'};      my $allkeywords=$env{'form.addkey'};
     if (exists($ENV{'form.keywords'})) {      if (exists($env{'form.keywords'})) {
         if (ref($ENV{'form.keywords'})) {          if (ref($env{'form.keywords'})) {
             $allkeywords .= ','.join(',',@{$ENV{'form.keywords'}});              $allkeywords .= ','.join(',',@{$env{'form.keywords'}});
         } else {          } else {
             $allkeywords .= ','.$ENV{'form.keywords'};              $allkeywords .= ','.$env{'form.keywords'};
         }          }
     }      }
     $allkeywords=~s/\W+/\,/;      $allkeywords=~s/[\"\']//g;
     $allkeywords=~s/^\,//;      $allkeywords=~s/\s*[\;\,]\s*/\,/g;
       $allkeywords=~s/\s+/ /g;
       $allkeywords=~s/^[ \,]//;
       $allkeywords=~s/[ \,]$//;
     $metadatafields{'keywords'}=$allkeywords;      $metadatafields{'keywords'}=$allkeywords;
           
 # check if custom distribution file is specified  # check if custom distribution file is specified
     if ($metadatafields{'copyright'} eq 'custom') {      if ($metadatafields{'copyright'} eq 'custom') {
  my $file=$metadatafields{'customdistributionfile'};   my $file=$metadatafields{'customdistributionfile'};
  unless ($file=~/\.rights$/) {   unless ($file=~/\.rights$/) {
             return               $r->print(
                 '<font color="red">'.&mt('No valid custom distribution rights file specified, FAIL').                  '<span class="LC_error">'.&mt('No valid custom distribution rights file specified, FAIL').
  '</font>';   '</span>');
       return 0;
         }          }
     }      }
     {      {
         print $logfile "\nWrite metadata file for ".$source;          print $logfile "\nWrite metadata file for ".$source;
         my $mfh;          my $mfh;
         unless ($mfh=Apache::File->new('>'.$source.'.meta')) {          unless ($mfh=Apache::File->new('>'.$source.'.meta')) {
             return               $r->print( 
                 '<font color="red">'.&mt('Could not write metadata, FAIL').                  '<span class="LC_error">'.&mt('Could not write metadata, FAIL').
  '</font>';   '</span>');
         }      return 0;
         foreach (sort keys %metadatafields) {          }
             unless ($_=~/\./) {          foreach my $field (sort(keys(%metadatafields))) {
                 my $unikey=$_;              unless ($field=~/\./) {
                   my $unikey=$field;
                 $unikey=~/^([A-Za-z]+)/;                  $unikey=~/^([A-Za-z]+)/;
                 my $tag=$1;                  my $tag=$1;
                 $tag=~tr/A-Z/a-z/;                  $tag=~tr/A-Z/a-z/;
                 print $mfh "\n\<$tag";                  print $mfh "\n\<$tag";
                 foreach (split(/\,/,$metadatakeys{$unikey})) {                  foreach my $item (split(/\,/,$metadatakeys{$unikey})) {
                     my $value=$metadatafields{$unikey.'.'.$_};                      my $value=$metadatafields{$unikey.'.'.$item};
                     $value=~s/\"/\'\'/g;                      $value=~s/\"/\'\'/g;
                     print $mfh ' '.$_.'="'.$value.'"';                      print $mfh ' '.$item.'="'.$value.'"';
                 }                  }
                 print $mfh '>'.                  print $mfh '>'.
                     &HTML::Entities::encode($metadatafields{$unikey})                      &HTML::Entities::encode($metadatafields{$unikey},'<>&"')
                         .'</'.$tag.'>';                          .'</'.$tag.'>';
             }              }
         }          }
Line 1434  sub phasetwo { Line 1806  sub phasetwo {
  $r->print($error);   $r->print($error);
  print $logfile "\n".$error;   print $logfile "\n".$error;
     }      }
   # --------------------------------------------- Delete author resource messages
       my $delresult=&Apache::lonmsg::del_url_author_res_msg($target); 
       $r->print('<p>'.&mt('Removing error messages:').' '.$delresult.'</p>');
       print $logfile "\nRemoving error messages: $delresult";
 # ----------------------------------------------------------- Copy old versions  # ----------------------------------------------------------- Copy old versions
         
     if (-e $target) {      if (-e $target) {
Line 1444  sub phasetwo { Line 1819  sub phasetwo {
         my $srcf=$2;          my $srcf=$2;
         my $srct=$3;          my $srct=$3;
         my $srcd=$1;          my $srcd=$1;
         unless ($srcd=~/^\/home\/httpd\/html\/res/) {          my $docroot = $Apache::lonnet::perlvar{'lonDocRoot'};
           unless ($srcd=~/^\Q$docroot\E\/res/) {
             print $logfile "\nPANIC: Target dir is ".$srcd;              print $logfile "\nPANIC: Target dir is ".$srcd;
             return "<font color=\"red\">Invalid target directory, FAIL</font>";              $r->print(
    "<span class=\"LC_error\">".&mt('Invalid target directory, FAIL')."</span>");
       return 0;
         }          }
         opendir(DIR,$srcd);          opendir(DIR,$srcd);
         while ($filename=readdir(DIR)) {          while ($filename=readdir(DIR)) {
Line 1454  sub phasetwo { Line 1832  sub phasetwo {
                 unlink($srcd.'/'.$filename);                  unlink($srcd.'/'.$filename);
                 unlink($srcd.'/'.$filename.'.meta');                  unlink($srcd.'/'.$filename.'.meta');
             } else {              } else {
                 if ($filename=~/\Q$srcf\E\.(\d+)\.\Q$srct\E$/) {                  if ($filename=~/^\Q$srcf\E\.(\d+)\.\Q$srct\E$/) {
                     $maxversion=($1>$maxversion)?$1:$maxversion;                      $maxversion=($1>$maxversion)?$1:$maxversion;
                 }                  }
             }              }
         }          }
         closedir(DIR);          closedir(DIR);
         $maxversion++;          $maxversion++;
         $r->print('<p>Creating old version '.$maxversion.'</p>');          $r->print('<p>'.&mt('Creating old version [_1]',$maxversion).'</p>');
         print $logfile "\nCreating old version ".$maxversion."\n";          print $logfile "\nCreating old version ".$maxversion."\n";
                   
         my $copyfile=$srcd.'/'.$srcf.'.'.$maxversion.'.'.$srct;          my $copyfile=$srcd.'/'.$srcf.'.'.$maxversion.'.'.$srct;
                   
         if (copy($target,$copyfile)) {          if (copy($target,$copyfile)) {
     print $logfile "Copied old target to ".$copyfile."\n";      print $logfile "Copied old target to ".$copyfile."\n";
             $r->print('<p>'.&mt('Copied old target file').'</p>');              $r->print(&Apache::lonhtmlcommon::confirm_success(&mt('Copied old target file')));
         } else {          } else {
     print $logfile "Unable to write ".$copyfile.':'.$!."\n";      print $logfile "Unable to write ".$copyfile.':'.$!."\n";
             return "<font color=\"red\">".&mt('Failed to copy old target').              $r->print(&Apache::lonhtmlcommon::confirm_success(&mt('Failed to copy old target').", $!",1));
  ", $!, ".&mt('FAIL')."</font>";      return 0;
         }          }
                   
 # --------------------------------------------------------------- Copy Metadata  # --------------------------------------------------------------- Copy Metadata
Line 1481  sub phasetwo { Line 1859  sub phasetwo {
                   
         if (copy($target.'.meta',$copyfile)) {          if (copy($target.'.meta',$copyfile)) {
     print $logfile "Copied old target metadata to ".$copyfile."\n";      print $logfile "Copied old target metadata to ".$copyfile."\n";
             $r->print('<p>'.&mt('Copied old metadata').'</p>')              $r->print(&Apache::lonhtmlcommon::confirm_success(&mt('Copied old metadata')));
         } else {          } else {
     print $logfile "Unable to write metadata ".$copyfile.':'.$!."\n";      print $logfile "Unable to write metadata ".$copyfile.':'.$!."\n";
             if (-e $target.'.meta') {              if (-e $target.'.meta') {
                 return                   $r->print(&Apache::lonhtmlcommon::confirm_success(
                     "<font color=\"red\">".                             &mt('Failed to write old metadata copy').", $!",1));
 &mt('Failed to write old metadata copy').", $!, ".&mt('FAIL')."</font>";   return 0;
     }      }
         }          }
                   
Line 1508  sub phasetwo { Line 1886  sub phasetwo {
         $path.="/$parts[$count]";          $path.="/$parts[$count]";
         if ((-e $path)!=1) {          if ((-e $path)!=1) {
             print $logfile "\nCreating directory ".$path;              print $logfile "\nCreating directory ".$path;
             $r->print('<p>'.&mt('Created directory').' '.$parts[$count].'</p>');  
             mkdir($path,0777);              mkdir($path,0777);
               $r->print('<p>'
                        .&mt('Created directory [_1]'
                            ,'<span class="LC_filename">'.$parts[$count].'</span>')
                        .'</p>'
               );
         }          }
     }      }
           
     if (copy($source,$copyfile)) {      if (copy($source,$copyfile)) {
         print $logfile "\nCopied original source to ".$copyfile."\n";          print $logfile "\nCopied original source to ".$copyfile."\n";
         $r->print('<p>'.&mt('Copied source file').'</p>');          $r->print(&Apache::lonhtmlcommon::confirm_success(&mt('Copied source file')));
     } else {      } else {
         print $logfile "\nUnable to write ".$copyfile.':'.$!."\n";          print $logfile "\nUnable to write ".$copyfile.':'.$!."\n";
         return "<font color=\"red\">".          $r->print(&Apache::lonhtmlcommon::confirm_success(
     &mt('Failed to copy source').", $!, ".&mt('FAIL')."</font>";      &mt('Failed to copy source').", $!",1));
    return 0;
     }      }
           
   # ---------------------------------------------- Delete local tmp-preview files
       unlink($copyfile.'.tmp');
 # --------------------------------------------------------------- Copy Metadata  # --------------------------------------------------------------- Copy Metadata
   
     $copyfile=$copyfile.'.meta';      $copyfile=$copyfile.'.meta';
           
     if (copy($source.'.meta',$copyfile)) {      if (copy($source.'.meta',$copyfile)) {
         print $logfile "\nCopied original metadata to ".$copyfile."\n";          print $logfile "\nCopied original metadata to ".$copyfile."\n";
         $r->print('<p>'.&mt('Copied metadata').'</p>');          $r->print(&Apache::lonhtmlcommon::confirm_success(&mt('Copied metadata')));
     } else {      } else {
         print $logfile "\nUnable to write metadata ".$copyfile.':'.$!."\n";          print $logfile "\nUnable to write metadata ".$copyfile.':'.$!."\n";
         return           $r->print(&Apache::lonhtmlcommon::confirm_success(
             "<font color=\"red\">".&mt('Failed to write metadata copy').", $!, ".&mt('FAIL')."</font>";                    &mt('Failed to write metadata copy').", $!",1));
    return 0;
     }      }
     $r->rflush;      $r->rflush;
 # --------------------------------------------------- Send update notifications  
   
     my @subscribed=&get_subscribed_hosts($target);  # ------------------------------------------------------------- Trigger updates
     foreach my $subhost (@subscribed) {      push(@{$modified_urls},[$target,$source]);
  $r->print('<p>'.&mt('Notifying host').' '.$subhost.':');$r->rflush;      &notify_in_cleanup($r);
  print $logfile "\nNotifying host ".$subhost.':';  
  my $reply=&Apache::lonnet::critical('update:'.$target,$subhost);  # ---------------------------------------------------------- Clear local caches
  $r->print($reply.'</p><br />');$r->rflush;      my $thisdistarget=$target;
  print $logfile $reply;      $thisdistarget=~s/^\Q$docroot\E//;
     }      &Apache::lonnet::devalidate_cache_new('resversion',$target);
           &Apache::lonnet::devalidate_cache_new('meta',
 # ---------------------------------------- Send update notifications, meta only   &Apache::lonnet::declutter($thisdistarget));
   
   # ------------------------------------------------------------- Everything done
       $logfile->close();
       $r->print('<p class="LC_success">'.&mt('Done').'</p>');
   
     my @subscribedmeta=&get_subscribed_hosts("$target.meta");  
     foreach my $subhost (@subscribedmeta) {  
  $r->print('<p>'.  
 &mt('Notifying host for metadata only').' '.$subhost.':');$r->rflush;  
  print $logfile "\nNotifying host for metadata only ".$subhost.':';  
  my $reply=&Apache::lonnet::critical('update:'.$target.'.meta',  
     $subhost);  
  $r->print($reply.'</p><br />');$r->rflush;  
  print $logfile $reply;  
     }  
       
 # --------------------------------------------------- Notify subscribed courses  
     my %courses=&coursedependencies($target);  
     my $now=time;  
     foreach (keys %courses) {  
  $r->print('<p>'.&mt('Notifying course').' '.$_.':');$r->rflush;  
  print $logfile "\nNotifying host ".$_.':';  
         my ($cdom,$cname)=split(/\_/,$_);  
  my $reply=&Apache::lonnet::cput  
                   ('versionupdate',{$target => $now},$cdom,$cname);  
  $r->print($reply.'</p><br />');$r->rflush;  
  print $logfile $reply;  
     }  
 # ------------------------------------------------ Provide link to new resource  # ------------------------------------------------ Provide link to new resource
     unless ($batch) {      unless ($batch) {
         my $thisdistarget=$target;  
         $thisdistarget=~s/^\Q$docroot\E//;  
           
         my $thissrc=$source;  
         $thissrc=~s/^\/home\/(\w+)\/public_html/\/priv\/$1/;  
                   
           my $thissrc=&Apache::loncfile::url($source);
         my $thissrcdir=$thissrc;          my $thissrcdir=$thissrc;
         $thissrcdir=~s/\/[^\/]+$/\//;          $thissrcdir=~s/\/[^\/]+$/\//;
                   
           
         $r->print(          $r->print(
            '<hr /><a href="'.$thisdistarget.'"><font size="+2">'.              &Apache::lonhtmlcommon::actionbox([
            &mt('View Published Version').'</font></a>'.                  '<a href="'.$thisdistarget.'">'.
            '<p><a href="'.$thissrc.'"><font size=+2>'.                  &mt('View Published Version').
   &mt('Back to Source').'</font></a></p>'.                  '</a>',
            '<p><a href="'.$thissrcdir.                  '<a href="'.$thissrc.'">'.
                    '"><font size="+2">'.                  &mt('Back to Source').
   &mt('Back to Source Directory').'</font></a></p>');                  '</a>',
                   '<a href="'.$thissrcdir.'">'.
                   &mt('Back to Source Directory').
                   '</a>'])
           );
       }
       return 1;
   }
   
   sub notify_in_cleanup {
       my ($r) = @_;
       unless ($registered_cleanup) {
           my $handlers = $r->get_handlers('PerlCleanupHandler');
           $r->set_handlers('PerlCleanupHandler' => [\&notify,@{$handlers}]);
           $registered_cleanup=1;
       }
   }
   
   # =============================================================== Notifications
   sub notify {  
   # --------------------------------------------------- Send update notifications
       foreach my $targetsource (@{$modified_urls}){
    my ($target,$source)=@{$targetsource};
    my $logfile=Apache::File->new('>>'.$source.'.log');
    print $logfile "\nCleanup phase: Notifications\n";
    my @subscribed=&get_subscribed_hosts($target);
    foreach my $subhost (@subscribed) {
       print $logfile "\nNotifying host ".$subhost.':';
       my $reply=&Apache::lonnet::critical('update:'.$target,$subhost);
       print $logfile $reply;
    }
   # ---------------------------------------- Send update notifications, meta only
    my @subscribedmeta=&get_subscribed_hosts("$target.meta");
    foreach my $subhost (@subscribedmeta) {
       print $logfile "\nNotifying host for metadata only ".$subhost.':';
       my $reply=&Apache::lonnet::critical('update:'.$target.'.meta',
    $subhost);
       print $logfile $reply;
    } 
   # --------------------------------------------------- Notify subscribed courses
    my %courses=&coursedependencies($target);
    my $now=time;
    foreach my $course (keys(%courses)) {
       print $logfile "\nNotifying course ".$course.':';
       my ($cdom,$cname)=split(/\_/,$course);
       my $reply=&Apache::lonnet::cput
    ('versionupdate',{$target => $now},$cdom,$cname);
       print $logfile $reply;
    }
    print $logfile "\n============ Done ============\n";
    $logfile->close();
     }      }
     return '<p><font color="green">'.&mt('Done').'</font></p>';      if ($lock) { &Apache::lonnet::remove_lock($lock); }
       return OK;
 }  }
   
 #########################################  #########################################
   
 sub batchpublish {  sub batchpublish {
     my ($r,$srcfile,$targetfile)=@_;      my ($r,$srcfile,$targetfile)=@_;
     #publication pollutes %ENV with form.* values      #publication pollutes %env with form.* values
     my %oldENV=%ENV;      my %oldenv=%env;
     $srcfile=~s/\/+/\//g;      $srcfile=~s/\/+/\//g;
     $targetfile=~s/\/+/\//g;      $targetfile=~s/\/+/\//g;
     my $thisdisfn=$srcfile;  
     $thisdisfn=~s/\/home\/korte\/public_html\///;  
     $srcfile=~s/\/+/\//g;      $srcfile=~s/\/+/\//g;
   
     my $docroot=$r->dir_config('lonDocRoot');      my $docroot=$r->dir_config('lonDocRoot');
Line 1620  sub batchpublish { Line 2030  sub batchpublish {
   
     my $thisembstyle=&Apache::loncommon::fileembstyle($thistype);      my $thisembstyle=&Apache::loncommon::fileembstyle($thistype);
             
     $r->print('<h2>'.&mt('Publishing').' <tt>'.$thisdisfn.'</tt></h2>');      $r->print('<h2>'
                .&mt('Publishing [_1]',&Apache::loncfile::display($srcfile))
                .'</h2>'
       );
   
 # phase one takes  # phase one takes
 #  my ($source,$target,$style,$batch)=@_;  #  my ($source,$target,$style,$batch)=@_;
Line 1628  sub batchpublish { Line 2041  sub batchpublish {
     $r->print('<p>'.$outstring.'</p>');      $r->print('<p>'.$outstring.'</p>');
 # phase two takes  # phase two takes
 # my ($source,$target,$style,$distarget,batch)=@_;  # my ($source,$target,$style,$distarget,batch)=@_;
 # $ENV{'form.allmeta'},$ENV{'form.title'},$ENV{'form.author'},...  # $env{'form.allmeta'},$env{'form.title'},$env{'form.author'},...
     if (!$error) {      if (!$error) {
  $r->print('<p>');   $r->print('<p>');
  &phasetwo($r,$srcfile,$targetfile,$thisembstyle,$thisdistarget,1);   &phasetwo($r,$srcfile,$targetfile,$thisembstyle,$thisdistarget,1);
  $r->print('</p>');   $r->print('</p>');
     }      }
     %ENV=%oldENV;      %env=%oldenv;
     return '';      return '';
 }  }
   
Line 1644  sub publishdirectory { Line 2057  sub publishdirectory {
     my ($r,$fn,$thisdisfn)=@_;      my ($r,$fn,$thisdisfn)=@_;
     $fn=~s/\/+/\//g;      $fn=~s/\/+/\//g;
     $thisdisfn=~s/\/+/\//g;      $thisdisfn=~s/\/+/\//g;
     my $resdir=      my $thisdisresdir=$thisdisfn;
  $Apache::lonnet::perlvar{'lonDocRoot'}.'/res/'.$cudom.'/'.$cuname.'/'.      $thisdisresdir=~s/^\/priv\//\/res\//;
  $thisdisfn;      my $resdir = $r->dir_config('lonDocRoot').$thisdisresdir;
     $r->print('<h1>'.&mt('Directory').' <tt>'.$thisdisfn.'</tt></h1>'.      $r->print('<form name="pubdirpref" method="post" action="">'
       &mt('Target').': <tt>'.$resdir.'</tt><br />');               .&Apache::lonhtmlcommon::start_pick_box()
                .&Apache::lonhtmlcommon::row_title(&mt('Directory'))
               .'<span class="LC_filename">'.$thisdisfn.'</span>'
               .&Apache::lonhtmlcommon::row_closure()
               .&Apache::lonhtmlcommon::row_title(&mt('Target'))
               .'<span class="LC_filename">'.$thisdisresdir.'</span>'
       );
       my %reasons = &Apache::lonlocal::texthash(
                         mod => 'Authoring Space file postdates published file',
                         modmeta => 'Authoring Space metadata file postdates published file',
                         unpub => 'Resource is unpublished',
       );
   
     my $dirptr=16384; # Mask indicating a directory in stat.cmode.      my $dirptr=16384; # Mask indicating a directory in stat.cmode.
       unless ($env{'form.phase'} eq 'two') {
     opendir(DIR,$fn);  # ask user what they want
     my @files=sort(readdir(DIR));          $r->print(&Apache::lonhtmlcommon::row_closure()
     foreach my $filename (@files) {                   .&Apache::lonhtmlcommon::row_title(&mt('Options')
  my ($cdev,$cino,$cmode,$cnlink,                   .&Apache::loncommon::help_open_topic('Publishing_Directory_Options')));
             $cuid,$cgid,$crdev,$csize,          $r->print(&hiddenfield('phase','two').
             $catime,$cmtime,$cctime,    &hiddenfield('filename',$env{'form.filename'}).
             $cblksize,$cblocks)=stat($fn.'/'.$filename);                    '<fieldset><legend>'.&mt('Recurse').'</legend>'.
                     &checkbox('pubrec','include subdirectories').
  my $extension='';                    '</fieldset>'.
  if ($filename=~/\.(\w+)$/) { $extension=$1; }                    '<fieldset><legend>'.&mt('Force').'</legend>'.
  if ($cmode&$dirptr) {                    &checkbox('forcerepub','force republication of previously published files').'<br />'.
     if (($filename!~/^\./) && ($ENV{'form.pubrec'})) {                    &checkbox('forceoverride','force directory level metadata over existing').
  &publishdirectory($r,$fn.'/'.$filename,$thisdisfn.'/'.$filename);                    '</fieldset>'.
     }                    '<fieldset><legend>'.&mt('Exclude').'</legend>'.
  } elsif ((&Apache::loncommon::fileembstyle($extension) ne 'hdn') &&                    &checkbox('excludeunpub','exclude currently unpublished files').'<br />'.
  ($filename!~/^[\#\.]/) && ($filename!~/\~$/)) {                    &checkbox('excludemod','exclude modified files').'<br />'.
 # find out publication status and/or exiting metadata                    &checkbox('excludemodmeta','exclude files with modified metadata').
     my $publishthis=0;                    '</fieldset>'.
     if (-e $resdir.'/'.$filename) {                    '<fieldset><legend>'.&mt('Actions').'</legend>'.
         my ($rdev,$rino,$rmode,$rnlink,                    &checkbox('obsolete','make file(s) obsolete').'<br />'.
     $ruid,$rgid,$rrdev,$rsize,                    &common_access('dist',&mt('apply common copyright/distribution'),
     $ratime,$rmtime,$rctime,                                   ['default','domain','public','custom']).'<br />'.
     $rblksize,$rblocks)=stat($resdir.'/'.$filename);                    &common_access('source',&mt('apply common source availability'),
         if (($rmtime<$cmtime) || ($ENV{'form.forcerepub'})) {                                   ['closed','open']).
                     '</fieldset>'
           );
           $r->print(&Apache::lonhtmlcommon::row_closure(1)
                    .&Apache::lonhtmlcommon::end_pick_box()
                    .'<br /><input type="submit" value="'.&mt('Publish Directory').'" /></form>'
           );
           $lock=0;
       } else {
           $r->print(&Apache::lonhtmlcommon::row_closure(1)
                    .&Apache::lonhtmlcommon::end_pick_box()
           );
           my %commonaccess;
           map { $commonaccess{$_} = 1; } &Apache::loncommon::get_env_multiple('form.commonaccess');
           unless ($lock) { $lock=&Apache::lonnet::set_lock(&mt('Publishing [_1]',$fn)); }
           if ($lock) {
               &notify_in_cleanup($r);
           }
   # actually publish things
    opendir(DIR,$fn);
    my @files=sort(readdir(DIR));
    foreach my $filename (@files) {
       my ($cdev,$cino,$cmode,$cnlink,
    $cuid,$cgid,$crdev,$csize,
    $catime,$cmtime,$cctime,
    $cblksize,$cblocks)=stat($fn.'/'.$filename);
   
       my $extension='';
       if ($filename=~/\.(\w+)$/) { $extension=$1; }
       if ($cmode&$dirptr) {
    if (($filename!~/^\./) && ($env{'form.pubrec'})) {
       &publishdirectory($r,$fn.'/'.$filename,$thisdisfn.'/'.$filename);
    }
       } elsif ((&Apache::loncommon::fileembstyle($extension) ne 'hdn') &&
        ($filename!~/^[\#\.]/) && ($filename!~/\~$/)) {
   # find out publication status and/or existing metadata
    my $publishthis=0;
                   my $skipthis;
    if (-e $resdir.'/'.$filename) {
       my ($rdev,$rino,$rmode,$rnlink,
    $ruid,$rgid,$rrdev,$rsize,
    $ratime,$rmtime,$rctime,
    $rblksize,$rblocks)=stat($resdir.'/'.$filename);
       if (($rmtime<$cmtime) || ($env{'form.forcerepub'})) {
 # previously published, modified now  # previously published, modified now
     $publishthis=1;                          if ($env{'form.excludemod'}) {
                 }                              $skipthis='mod';
     } else {                          } else {
                               $publishthis=1;
                           }
       }
                       unless ($skipthis) {
                           my $meta_cmtime = (stat($fn.'/'.$filename.'.meta'))[9];
                           my $meta_rmtime = (stat($resdir.'/'.$filename.'.meta'))[9];
                           if ( $meta_rmtime<$meta_cmtime ) {
                               if ($env{'form.excludemodmeta'}) {
                                   $skipthis='modmeta';
                                   $publishthis=0;
                               } else {
                                   $publishthis=1;
                               }
                           } else {
                               unless (&Apache::loncommon::fileembstyle($extension) eq 'prv') {
                                   if ($commonaccess{'dist'}) {
                                       my ($currdist,$currdistfile,$currsourceavail);
                                       my $currdist =  &Apache::lonnet::metadata($thisdisresdir.'/'.$filename,'copyright');
                                       if ($currdist eq 'custom') {
                                           $currdistfile =  &Apache::lonnet::metadata($thisdisresdir.'/'.$filename,'customdistributionfile');
                                       }
                                       if ($env{'form.commondistselect'} eq 'custom') {
                                           if ($env{'form.commoncustomrights'} =~ m{^/res/.+\.rights$}) {
                                               if ($currdist eq 'custom') {
                                                   unless ($env{'form.commoncustomrights'} eq $currdistfile) {
                                                       $publishthis=1;
                                                   }
                                               } else {
                                                   $publishthis=1;
                                               }
                                           }
                                       } elsif ($env{'form.commondistselect'} =~ /^default|domain|public$/) {
                                           unless ($currdist eq $env{'form.commondistselect'}) {
                                               $publishthis=1;
                                           }
                                       }
                                   }
                               }
                           }
                       }
    } else {
 # never published  # never published
  $publishthis=1;                      if ($env{'form.excludeunpub'}) {
     }                          $skipthis='unpub';
     if ($publishthis) {                      } else {
                 &batchpublish($r,$fn.'/'.$filename,$resdir.'/'.$filename);                          $publishthis=1;
     } else {                      }
  $r->print('<br />'.&mt('Skipping').' '.$filename.'<br />');   }
   
    if ($publishthis) {
       &batchpublish($r,$fn.'/'.$filename,$resdir.'/'.$filename);
    } else {
                       my $reason;
                       if ($skipthis) {
                           $reason = $reasons{$skipthis};
                       } else {
                           $reason = &mt('No changes needed to published resource or metadata');
                       }
                       $r->print('<br />'.&mt('Skipping').' '.$filename);
                       if ($reason) {
                           $r->print(' ('.$reason.')');
                       }
                       $r->print('<br />');
    }
    $r->rflush();
     }      }
     $r->rflush();  
  }   }
    closedir(DIR);
     }      }
     closedir(DIR);  }
   
   #########################################
   # publish a default.meta file
   
   sub defaultmetapublish {
       my ($r,$fn,$cuname,$cudom)=@_;
       unless (-e $fn) {
          return HTTP_NOT_FOUND;
       }
       my $target=$fn;
       $target=~s/^\Q$Apache::lonnet::perlvar{'lonDocRoot'}\E\/priv\//\Q$Apache::lonnet::perlvar{'lonDocRoot'}\E\/res\//;
   
   
       &Apache::loncommon::content_type($r,'text/html');
       $r->send_http_header;
   
       $r->print(&Apache::loncommon::start_page('Metadata Publication'));
   
   # ---------------------------------------------------------------- Write Source
       my $copyfile=$target;
       
       my @parts=split(/\//,$copyfile);
       my $path="/$parts[1]/$parts[2]/$parts[3]/$parts[4]";
       
       my $count;
       for ($count=5;$count<$#parts;$count++) {
           $path.="/$parts[$count]";
           if ((-e $path)!=1) {
               mkdir($path,0777);
               $r->print('<p>'
                        .&mt('Created directory [_1]'
                            ,'<span class="LC_filename">'.$parts[$count].'</span>')
                        .'</p>'
               );
           }
       }
       
       if (copy($fn,$copyfile)) {
           $r->print('<p>'.&mt('Copied source file').'</p>');
       } else {
           return "<span class=\"LC_error\">".
       &mt('Failed to copy source').", $!, ".&mt('FAIL')."</span>";
       }
   
   # --------------------------------------------------- Send update notifications
   
       my @subscribed=&get_subscribed_hosts($target);
       foreach my $subhost (@subscribed) {
    $r->print('<p>'.&mt('Notifying host').' '.$subhost.':');$r->rflush;
    my $reply=&Apache::lonnet::critical('update:'.$target,$subhost);
    $r->print($reply.'</p><br />');$r->rflush;
       }
   # ------------------------------------------------------------------- Link back
       $r->print("<a href='".&Apache::loncfile::display($fn)."'>".&mt('Back to Metadata').'</a>');
       $r->print(&Apache::loncommon::end_page());
       return OK;
 }  }
 #########################################  #########################################
   
Line 1747  sub handler { Line 2328  sub handler {
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
                                             ['filename']);                                              ['filename']);
   
   # -------------------------------------- Flag and buffer for registered cleanup
       $registered_cleanup=0;
       @{$modified_urls}=();
 # -------------------------------------------------------------- Check filename  # -------------------------------------------------------------- Check filename
   
     my $fn=&Apache::lonnet::unescape($ENV{'form.filename'});      my $fn=&unescape($env{'form.filename'});
       ($cuname,$cudom)=&Apache::lonnet::constructaccess($fn);
   # ----------------------------------------------------- Do we have permissions?
        unless (($cuname) && ($cudom)) {
          $r->log_reason($env{'user.name'}.' at '.$env{'user.domain'}.
                         ' trying to publish file '.$env{'form.filename'}.
                         ' - not authorized', 
                         $r->filename); 
          return HTTP_NOT_ACCEPTABLE;
        }
   # ----------------------------------------------------------------- Get docroot
       $docroot=$r->dir_config('lonDocRoot');
   
   
   # special publication: default.meta file
       if ($fn=~/\/default.meta$/) {
    return &defaultmetapublish($r,$fn,$cuname,$cudom); 
       }
       $fn=~s/\.meta$//;
   
     # sanity test on the filename 
    
     unless ($fn) {       unless ($fn) { 
  $r->log_reason($cuname.' at '.$cudom.   $r->log_reason($cuname.' at '.$cudom.
        ' trying to publish empty filename', $r->filename);          ' trying to publish empty filename', $r->filename); 
  return HTTP_NOT_FOUND;   return HTTP_NOT_FOUND;
     }       } 
   
     ($cuname,$cudom)=      unless (-e $docroot.$fn) { 
  &Apache::loncacc::constructaccess($fn,$r->dir_config('lonDefDomain'));  
     unless (($cuname) && ($cudom)) {  
  $r->log_reason($cuname.' at '.$cudom.  
        ' trying to publish file '.$ENV{'form.filename'}.  
        ' ('.$fn.') - not authorized',   
        $r->filename);   
  return HTTP_NOT_ACCEPTABLE;  
     }  
   
     unless (&Apache::lonnet::homeserver($cuname,$cudom)   
     eq $r->dir_config('lonHostID')) {  
  $r->log_reason($cuname.' at '.$cudom.  
        ' trying to publish file '.$ENV{'form.filename'}.  
        ' ('.$fn.') - not homeserver ('.  
        &Apache::lonnet::homeserver($cuname,$cudom).')',   
        $r->filename);   
  return HTTP_NOT_ACCEPTABLE;  
     }  
   
     $fn=~s/^http\:\/\/[^\/]+//;  
     $fn=~s/^\/\~(\w+)/\/home\/$1\/public_html/;  
   
     my $targetdir='';  
     $docroot=$r->dir_config('lonDocRoot');   
     if ($1 ne $cuname) {  
  $r->log_reason($cuname.' at '.$cudom.  
        ' trying to publish unowned file '.  
        $ENV{'form.filename'}.' ('.$fn.')',   
        $r->filename);   
  return HTTP_NOT_ACCEPTABLE;  
     } else {  
  $targetdir=$docroot.'/res/'.$cudom;  
     }  
                                    
     
     unless (-e $fn) {   
  $r->log_reason($cuname.' at '.$cudom.   $r->log_reason($cuname.' at '.$cudom.
        ' trying to publish non-existing file '.         ' trying to publish non-existing file '.
        $ENV{'form.filename'}.' ('.$fn.')',          $env{'form.filename'}.' ('.$fn.')', 
        $r->filename);          $r->filename); 
  return HTTP_NOT_FOUND;   return HTTP_NOT_FOUND;
     }       } 
   
     unless ($ENV{'form.phase'} eq 'two') {  
   
 # -------------------------------- File is there and owned, init lookup tables.  # -------------------------------- File is there and owned, init lookup tables.
   
  %addid=();      %addid=();
       
  {      {
     my $fh=Apache::File->new($r->dir_config('lonTabDir').'/addid.tab');   my $fh=Apache::File->new($r->dir_config('lonTabDir').'/addid.tab');
     while (<$fh>=~/(\w+)\s+(\w+)/) {   while (<$fh>=~/(\w+)\s+(\w+)/) {
  $addid{$1}=$2;      $addid{$1}=$2;
     }  
  }   }
       }
   
  %nokey=();      %nokey=();
   
  {      {
     my $fh=Apache::File->new($r->dir_config('lonIncludes').'/un_keyword.tab');   my $fh=Apache::File->new($r->dir_config('lonIncludes').'/un_keyword.tab');
     while (<$fh>) {   while (<$fh>) {
  my $word=$_;      my $word=$_;
  chomp($word);      chomp($word);
  $nokey{$word}=1;      $nokey{$word}=1;
     }  
  }   }
   
     }      }
   
 # ---------------------------------------------------------- Start page output.  # ---------------------------------------------------------- Start page output.
   
     &Apache::loncommon::content_type($r,'text/html');      &Apache::loncommon::content_type($r,'text/html');
     $r->send_http_header;      $r->send_http_header;
       
       # Breadcrumbs
       &Apache::lonhtmlcommon::clear_breadcrumbs();
       &Apache::lonhtmlcommon::add_breadcrumb({
           'text'  => 'Authoring Space',
           'href'  => &Apache::loncommon::authorspace($fn),
       });
       &Apache::lonhtmlcommon::add_breadcrumb({
           'text'  => 'Resource Publication',
           'href'  => '',
       });
   
       my $js='<script type="text/javascript">'.
    &Apache::loncommon::browser_and_searcher_javascript().
    '</script>';
       my $startargs = {};
       if ($fn=~/\/$/) {
           unless ($env{'form.phase'} eq 'two') {
               $startargs->{'add_entries'} = { onload => 'javascript:setDefaultAccess();' };
               $js .= <<"END";
   <script type="text/javascript">
   // <![CDATA[
   function showHideAccess(caller,div) {
       if (document.getElementById(div)) {
           if (caller.checked) {
               document.getElementById(div).style.display='inline-block';
           } else {
               document.getElementById(div).style.display='none';
           }
       }
   }
   
     $r->print('<html><head><title>LON-CAPA Publishing</title></head>');  function showHideCustom(caller,divid) {
     $r->print(&Apache::loncommon::bodytag('Resource Publication'));      if (document.getElementById(divid)) {
           if (caller.options[caller.selectedIndex].value == 'custom') {
               document.getElementById(divid).style.display="inline-block";
     my $thisfn=$fn;          } else {
               document.getElementById(divid).style.display="none";
     my $thistarget=$thisfn;          }
             }
     $thistarget=~s/^\/home/$targetdir/;  }
     $thistarget=~s/\/public\_html//;  function setDefaultAccess() {
       var chkids = Array('LC_commondist','LC_commonsource');
     my $thisdistarget=$thistarget;      for (var i=0; i<chkids.length; i++) {
     $thisdistarget=~s/^\Q$docroot\E//;          if (document.getElementById(chkids[i])) {
               document.getElementById(chkids[i]).checked = false;
           }
           if (document.getElementById(chkids[i]+'select')) {
              document.getElementById(chkids[i]+'select').selectedIndex = 0; 
           }
           if (document.getElementById(chkids[i]+'div')) {
               document.getElementById(chkids[i]+'div').style.display = 'none';
           }
       }
   }
   // ]]>
   </script>
   
     my $thisdisfn=$thisfn;  END
     $thisdisfn=~s/^\/home\/\Q$cuname\E\/public_html\///;          }
       }
       $r->print(&Apache::loncommon::start_page('Resource Publication',$js,$startargs)
                .&Apache::lonhtmlcommon::breadcrumbs()
                .&Apache::loncommon::head_subbox(
                     &Apache::loncommon::CSTR_pageheader($docroot.$fn))
       );
   
       my $thisdisfn=&HTML::Entities::encode($fn,'<>&"');
       my $thistarget=$fn;
       $thistarget=~s/^\/priv\//\/res\//;
       my $thisdistarget=&HTML::Entities::encode($thistarget,'<>&"');
   
     if ($fn=~/\/$/) {      if ($fn=~/\/$/) {
 # -------------------------------------------------------- This is a directory  # -------------------------------------------------------- This is a directory
  &publishdirectory($r,$fn,$thisdisfn);   &publishdirectory($r,$docroot.$fn,$thisdisfn);
  $r->print('<hr><font size="+2">'.&mt('Done').'</font><br><a href="/priv/'          $r->print(
   .$cuname.'/'.$thisdisfn              '<br /><br />'.
   .'">'.&mt('Return to Directory').'</a>');              &Apache::lonhtmlcommon::actionbox([
                   '<a href="'.$thisdisfn.'">'.&mt('Return to Directory').'</a>']));
   
     } else {      } else {
 # ---------------------- Evaluate individual file, and then output information.  # ---------------------- Evaluate individual file, and then output information.
  $thisfn=~/\.(\w+)$/;   $fn=~/\.(\w+)$/;
  my $thistype=$1;   my $thistype=$1;
  my $thisembstyle=&Apache::loncommon::fileembstyle($thistype);   my $thisembstyle=&Apache::loncommon::fileembstyle($thistype);
  $r->print('<h2>'.&mt('Publishing').' '.          if ($thistype eq 'page') {  $thisembstyle = 'rat'; }
   &Apache::loncommon::filedescription($thistype).' <tt>');  
   
           $r->print('<h2>'
                    .&mt('Publishing [_1]'
                        ,'<span class="LC_filename">'.$thisdisfn.'</span>')
                    .'</h2>'
           );
   
           $r->print('<h3>'.&mt('Resource Details').'</h3>');
   
           $r->print(&Apache::lonhtmlcommon::start_pick_box());
   
           $r->print(&Apache::lonhtmlcommon::row_title(&mt('Type'))
                    .&Apache::loncommon::filedescription($thistype)
                    .&Apache::lonhtmlcommon::row_closure()
                    );
   
           $r->print(&Apache::lonhtmlcommon::row_title(&mt('Link to Resource'))
                    .'<tt>'
                    );
  $r->print(<<ENDCAPTION);   $r->print(<<ENDCAPTION);
 <a href='javascript:void(window.open("/~$cuname/$thisdisfn","cat","height=300,width=500,scrollbars=1,resizable=1,menubar=0,location=1"))'>  <a href='javascript:void(window.open("$thisdisfn","cat","height=300,width=500,scrollbars=1,resizable=1,menubar=0,location=1"))'>
 $thisdisfn</a>  $thisdisfn</a>
 ENDCAPTION  ENDCAPTION
         $r->print('</tt></h2><b>'.&mt('Target').':</b> <tt>'.          $r->print('</tt>'
   $thisdistarget.'</tt><br />');                   .&Apache::lonhtmlcommon::row_closure()
                       );
  if (($cuname ne $ENV{'user.name'})||($cudom ne $ENV{'user.domain'})) {  
     $r->print('<h3><font color="red">'.&mt('Co-Author').': '.          $r->print(&Apache::lonhtmlcommon::row_title(&mt('Target'))
       $cuname.&mt(' at ').$cudom.'</font></h3>');                   .'<tt>'.$thisdistarget.'</tt>'
                    );
    if (($cuname ne $env{'user.name'})||($cudom ne $env{'user.domain'})) {
               $r->print(&Apache::lonhtmlcommon::row_closure()
                        .&Apache::lonhtmlcommon::row_title(&mt('Co-Author'))
                        .'<span class="LC_warning">'
        .&Apache::loncommon::plainname($cuname,$cudom) .' ('.$cuname.':'.$cudom.')'
                        .'</span>'
                        );
  }   }
   
  if (&Apache::loncommon::fileembstyle($thistype) eq 'ssi') {   if (&Apache::loncommon::fileembstyle($thistype) eq 'ssi') {
               $r->print(&Apache::lonhtmlcommon::row_closure()
                        .&Apache::lonhtmlcommon::row_title(&mt('Diffs')));
     $r->print(<<ENDDIFF);      $r->print(<<ENDDIFF);
 <br />  <a href='javascript:void(window.open("/adm/diff?filename=$thisdisfn&amp;versiontwo=priv","cat","height=300,width=500,scrollbars=1,resizable=1,menubar=0,location=1"))'>
 <a href='javascript:void(window.open("/adm/diff?filename=/~$cuname/$thisdisfn&versiontwo=priv","cat","height=300,width=500,scrollbars=1,resizable=1,menubar=0,location=1"))'>  
 ENDDIFF  ENDDIFF
             $r->print(&mt('Diffs with Current Version').'</a><br />');              $r->print(&mt('Diffs with Current Version').'</a>');
  }   }
           
           $r->print(&Apache::lonhtmlcommon::row_closure(1)
                    .&Apache::lonhtmlcommon::end_pick_box()
                    );
       
 # ------------------ Publishing from $thisfn to $thistarget with $thisembstyle.  # ---------------------- Publishing from $fn to $thistarget with $thisembstyle.
   
  unless ($ENV{'form.phase'} eq 'two') {   unless ($env{'form.phase'} eq 'two') {
     my ($outstring,$error)=&publish($thisfn,$thistarget,$thisembstyle);  # ---------------------------------------------------------- Parse for problems
     $r->print('<hr />'.$outstring);      my ($warningcount,$errorcount);
       if ($thisembstyle eq 'ssi') {
    ($warningcount,$errorcount)=&checkonthis($r,$fn);
       }
       unless ($errorcount) {
    my ($outstring,$error)=
       &publish($docroot.$fn,$docroot.$thistarget,$thisembstyle);
    $r->print($outstring);
       } else {
    $r->print('<h3 class="LC_error">'.
     &mt('The document contains errors and cannot be published.').
     '</h3>');
       }
  } else {   } else {
     $r->print('<hr />'.      &phasetwo($r,$docroot.$fn,$docroot.$thistarget,$thisembstyle,$thisdistarget); 
     &phasetwo($r,$thisfn,$thistarget,$thisembstyle,$thisdistarget));   
  }   }
     }      }
     $r->print('</body></html>');      $r->print(&Apache::loncommon::end_page());
   
     return OK;      return OK;
 }  }
Line 1908  __END__ Line 2565  __END__
   
 =back  =back
   
 =back  
   
 =cut  =cut
   

Removed from v.1.157  
changed lines
  Added in v.1.295.2.1.2.2


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