Index: /main/trunk/greenstone2/perllib/cgiactions/metadataaction.pm
===================================================================
--- /main/trunk/greenstone2/perllib/cgiactions/metadataaction.pm	(revision 23760)
+++ /main/trunk/greenstone2/perllib/cgiactions/metadataaction.pm	(revision 23761)
@@ -85,4 +85,17 @@
     my ($gsdl_cgi,$iis6_mode) = @_;
 
+    # Treat metavalue specially.  To transmit this through a GET request
+    # the Javascript side has url-encoded it, so here we need to decode
+    # it before proceeding
+
+    my $url_encoded_metavalue = $gsdl_cgi->param("metavalue");
+    my $url_decoded_metavalue = &unicode::url_decode($url_encoded_metavalue,1);
+
+    my $unicode_array = &unicode::utf82unicode($url_decoded_metavalue);
+
+    $url_decoded_metavalue = join("",map(chr($_),@$unicode_array));
+
+    $gsdl_cgi->param("metavalue",$url_decoded_metavalue);
+
     my $self = new baseaction($action_table,$gsdl_cgi,$iis6_mode);
 
@@ -102,5 +115,5 @@
 	
     # live metadata gets/saves value scoped (prefixed) by the current usename 
-	# so (for now) let's not bother to enforce authentication
+    # so (for now) let's not bother to enforce authentication
 
     # Obtain the collect dir
@@ -137,4 +150,5 @@
     }
     else {
+	binmode(GIN,":utf8");
         # Read everything in and concatenate them into $metavalue
 	my $metavalue = "";
@@ -220,5 +234,4 @@
     my $infodbtype = $self->{'infodbtype'};
   
-    # don't user authenticate for now
     if ($baseaction::authentication_enabled) {
 	# Ensure the user is allowed to edit this collection
@@ -283,7 +296,4 @@
     my $gsdlhome  = $self->{'gsdlhome'};
 
-	
-	
-    # don't user authenticate for now
     if ($baseaction::authentication_enabled) {
 	# Ensure the user is allowed to edit this collection
@@ -302,5 +312,5 @@
     my $metapos   = $self->{'metapos'};
     my $metavalue = $self->{'metavalue'};
-	my $infodbtype = $self->{'infodbtype'};
+    my $infodbtype = $self->{'infodbtype'};
 	
     # To people who know $collect_tail please add some comments
@@ -316,28 +326,28 @@
     # Set the metadata value
     if (defined $metapos) {
-		$doc_rec->{$metaname}->[$metapos] = $metavalue;
+	$doc_rec->{$metaname}->[$metapos] = $metavalue;
     }
     else {
-		$doc_rec->{$metaname} = [ $metavalue ];
+	$doc_rec->{$metaname} = [ $metavalue ];
     }
  
-	my $status = &dbutil::set_infodb_entry($infodbtype, $infodb_file_path,$docid,$doc_rec);
+    my $status = &dbutil::set_infodb_entry($infodbtype, $infodb_file_path,$docid,$doc_rec);
     if ($status != 0) {
-        # Catch error if gdbmget failed
-		my $mess = "Failed to set metadata key: $docid\n";
-	
-		$mess .= "PATH: $ENV{'PATH'}\n";
-		$mess .= "Exit status: $status\n";
-		$mess .= "System Error Message: $!\n";
-
-		$gsdl_cgi->generate_error($mess);
+        # Catch error if set infodb entry failed
+	my $mess = "Failed to set metadata key: $docid\n";
+	
+	$mess .= "PATH: $ENV{'PATH'}\n";
+	$mess .= "Exit status: $status\n";
+	$mess .= "System Error Message: $!\n";
+	
+	$gsdl_cgi->generate_error($mess);
     }
     else {
-		my $mess = "set-document-metadata successful: Key[$docid]\n";
-		$mess .= "  $metaname";
-		$mess .= "->[$metapos]" if (defined $metapos);
-		$mess .= " = $metavalue";
-
-		$gsdl_cgi->generate_ok_message($mess);
+	my $mess = "set-document-metadata successful: Key[$docid]\n";
+	$mess .= "  $metaname";
+	$mess .= "->[$metapos]" if (defined $metapos);
+	$mess .= " = $metavalue";
+	
+	$gsdl_cgi->generate_ok_message($mess);
     }
     
@@ -352,15 +362,29 @@
     my $metaname = $parser->{'parameters'}->{'metaname'};
     my $metamode = $parser->{'parameters'}->{'metamode'};
-
-    # Find the right metadata tag and checks if we are going to override it
-    # Note: This over writes the first metadata block it encountered. If there are multiple Sections in the doc.xml, it might not behave as you would expect
-    my $name_attr = $attrHash->{'name'};
-    if (($name_attr eq $metaname) && ($metamode eq "override")) {
-        # Get the value and override the current value
-	my $metavalue = $parser->{'parameters'}->{'metavalue'};
-	$attrHash->{'_content'} = $metavalue;
-
-	# Don't want it to wipe out any other pieces of metadata
-	$parser->{'parameters'}->{'metamode'} = "done";
+    
+    my $opt_doc_secnum = $parser->{'parameters'}->{'secnum'};
+    
+    # Find the right metadata tag and checks if we are going to
+    # override it
+    #
+    # Note: This over writes the first metadata block it
+    # encountered. If there are multiple Sections in the doc.xml, it
+    # might not behave as you would expect
+
+    my $curr_secnum = $parser->{'parameters'}->{'curr_section_num'};
+##    print STDERR "**** checking $opt_doc_secnum <=> $curr_secnum\n";
+##    print STDERR "**** metamode = $metamode\n";
+    
+    if ((!defined $opt_doc_secnum) || ($opt_doc_secnum eq $curr_secnum)) {
+	my $name_attr = $attrHash->{'name'};
+	if (($name_attr eq $metaname) && ($metamode eq "override")) {
+##	    print STDERR "**** got match!!\n";
+	    # Get the value and override the current value
+	    my $metavalue = $parser->{'parameters'}->{'metavalue'};
+	    $attrHash->{'_content'} = $metavalue;
+	    
+	    # Don't want it to wipe out any other pieces of metadata
+	    $parser->{'parameters'}->{'metamode'} = "done";
+	}
     }
 
@@ -378,6 +402,9 @@
     # NOTE: This appends new metadata element to all description fields.
     # If there are multiple Sections/SubSections, the new metadata block will get appended to all of them
-    if ($metamode eq "accumulate") {
-	# tack a new metadata tag on to the end of the <Metadata>+ block
+    if (($metamode eq "accumulate") || ($metamode eq "override")) {
+	# If get to here and metamode is override, the this means there 
+	# was no existing value to overide => treat as an append operation
+
+	# Tack a new metadata tag on to the end of the <Metadata>+ block
 	my $metaname = $parser->{'parameters'}->{'metaname'};
 	my $metavalue = $parser->{'parameters'}->{'metavalue'};
@@ -390,5 +417,8 @@
 	my $description_content = $attrHash->{'_content'};
 
+##	print STDERR "**** appending to doc.xml\n";
+
 	push(@$description_content,"    ", $append_metadata ,"\n        ");
+	$parser->{'parameters'}->{'metamode'} = "done";
     }
 
@@ -399,12 +429,54 @@
 
 
+
+sub dxml_start_section
+{
+    my ($tagname, $attrHash, $contextArray, $parentDataArray, $parser) = @_;
+
+    my $new_depth = scalar(@$contextArray);
+
+    if ($new_depth == 1) {
+	$parser->{'parameters'}->{'curr_section_depth'} = 1;
+	$parser->{'parameters'}->{'curr_section_num'}   = "";
+    }
+
+    my $old_depth  = $parser->{'parameters'}->{'curr_section_depth'};
+    my $old_secnum = $parser->{'parameters'}->{'curr_section_num'};
+
+    my $new_secnum;
+
+    if ($new_depth > $old_depth) {
+	# child subsection
+	$new_secnum = "$old_secnum.1";
+    }
+    elsif ($new_depth == $old_depth) {
+	# sibling section => increase it's value by 1
+	my ($tail_num) = ($old_secnum =~ m/\.(\d+)$/);
+	$tail_num++;
+	$new_secnum = $old_secnum;
+	$new_secnum =~ s/\.(\d+)$/\.$tail_num/;
+    }
+    else {
+	# back up to parent section => lopp off tail
+	$new_secnum = $old_secnum;
+	$new_secnum =~ s/\.\d+$//;
+    }
+
+    $parser->{'parameters'}->{'curr_section_depth'} = $new_depth;
+    $parser->{'parameters'}->{'curr_section_num'}   = $new_secnum;
+
+    print STDERR "*** In Section: $new_secnum\n";
+}
+
 sub edit_xml_file
 {
     my $self = shift @_;
-    my ($gsdl_cgi, $filename, $rules, $options) = @_;
+    my ($gsdl_cgi, $filename, $start_rules, $rules, $options) = @_;
 
     # use XML::Rules to add it in (read in and out again)
-    my $parser = XML::Rules->new(rules => $rules, 
-				 style => 'filter' );
+    my $parser = XML::Rules->new(start_rules     => $start_rules,
+				 rules           => $rules, 
+				 style           => 'filter',
+                                 output_encoding => 'utf8' );
 
     my $xml_in = "";
@@ -420,14 +492,18 @@
 	close(MIN);
 	
-	# Matched lines will get handled by the call backs
-	my $xml_out = "";
-	$parser->filter($xml_in,\$xml_out, $options);
-    
-	if (!open(MOUT,">$filename")) {
+	my $MOUT;    
+	if (!open($MOUT,">$filename")) {
 	    $gsdl_cgi->generate_error("Unable to write out to $filename: $!");
 	}
 	else {
-	    print MOUT $xml_out;
-	    close(MOUT);	    
+	    # Matched lines will get handled by the call backs
+##	    my $xml_out = "";
+
+	    binmode($MOUT,":utf8");
+	    $parser->filter($xml_in,$MOUT, $options);
+
+#	    binmode(MOUT,":utf8");
+#	    print MOUT $xml_out;
+	    close($MOUT);	    
 	}
     }
@@ -438,5 +514,9 @@
 {
     my $self = shift @_;
-    my ($gsdl_cgi, $doc_xml_filename, $metaname, $metavalue, $metapos, $metamode) = @_;
+    my ($gsdl_cgi, $doc_xml_filename, $metaname, $metavalue, $metapos, $metamode, $opt_secnum) = @_;
+
+    # To monitor which section/subsection number we are in
+    my @start_rules = 
+	( 'Section'    => \&dxml_start_section );
 
     # use XML::Rules to add it in (read in and out again)
@@ -444,6 +524,6 @@
     my @rules = 
 	( _default => 'raw',
-	  'Metadata' => \&dxml_metadata,
-	  'Description' => \&dxml_description );
+	  'Metadata'    => \&dxml_metadata,
+	  'Description' => \&dxml_description);
 	  
     # Sets the parameters
@@ -451,7 +531,11 @@
 		    'metapos'   => $metapos,
 		    'metavalue' => $metavalue,
-			'metamode'  => $metamode };
+		    'metamode'  => $metamode };
 			
-    $self->edit_xml_file($gsdl_cgi,$doc_xml_filename,\@rules,$options);
+    if (defined $opt_secnum) {
+	$options->{'secnum'} = $opt_secnum;
+    }
+
+    $self->edit_xml_file($gsdl_cgi,$doc_xml_filename,\@start_rules,\@rules,$options);
 }
 
@@ -467,5 +551,4 @@
     my $infodbtype = $self->{'infodbtype'};
 	
-    # don't user authenticate for now
     if ($baseaction::authentication_enabled) {
 	# Ensure the user is allowed to edit this collection
@@ -488,5 +571,5 @@
     $metapos = 0 if (!defined $metapos);
 
-	my $metamode   = $self->{'metamode'};
+    my $metamode   = $self->{'metamode'};
     if ((!defined $metamode) || ($metamode =~ m/^\s*$/)) {
 	# make "accumulate" the default (less destructive, as won't actually 
@@ -496,6 +579,8 @@
     
     # Obtain the doc.xml path for the specified docID
+    my ($docid_root,$docid_secnum) = ($docid =~ m/^(.*?)(\..*)?$/);
+
     my $arcinfo_doc_filename = &dbutil::get_infodb_file_path($infodbtype, "archiveinf-doc", $archive_dir);
-    my $doc_rec = &dbutil::read_infodb_entry($infodbtype, $arcinfo_doc_filename, $docid);
+    my $doc_rec = &dbutil::read_infodb_entry($infodbtype, $arcinfo_doc_filename, $docid_root);
     my $doc_xml_file = $doc_rec->{'doc-file'}->[0];
     
@@ -509,17 +594,16 @@
     # Running import.pl -groupsize will cause this to have multiple sections in one doc.xml
     $self->edit_doc_xml($gsdl_cgi,$doc_xml_filename,
-			$metaname,$metavalue,$metapos,$metamode);
-
-	my $mess = "set-archives-metadata successful: Key[$docid]\n";
-	$mess .= "  $metaname";
-	$mess .= "->[$metapos]" if (defined $metapos);
-	$mess .= " = $metavalue";
-    $mess .= " ($metamode)\n";
-	
-	$gsdl_cgi->generate_ok_message($mess);
-		
+			$metaname,$metavalue,$metapos,$metamode,$docid_secnum);
+    
     # Release the lock once it is done
     $self->unlock_collection($username, $collect);
-	
+
+    my $mess = "set-archives-metadata successful: Key[$docid]\n";
+    $mess .= "  $metaname";
+    $mess .= "->[$metapos]" if (defined $metapos);
+    $mess .= " = $metavalue";
+    $mess .= " ($metamode)\n";
+	
+    $gsdl_cgi->generate_ok_message($mess);	
 }
 
@@ -536,8 +620,17 @@
     # Don't do anything if we are not in the right FileSet
     my $file_regexp = $parser->{'parameters'}->{'current_file'};
-    return [$tagname => $attrHash] if (!($parser->{'parameters'}->{'src_file'} =~ /$file_regexp/));
-    
+    if ($file_regexp =~ /\.\*/) {
+	# Only interested in a file_regexp if it specifies precisely one
+	# file.  
+	# So, skip anything with a .* in it as it is too general
+	return [$tagname => $attrHash];
+    }
+    my $src_file = $parser->{'parameters'}->{'src_file'};
+    if (!($src_file =~ /$file_regexp/)) {
+	return [$tagname => $attrHash];
+    }
+##    print STDERR "*** mxl metamode = $metamode\n";
+
     # Find the right metadata tag and checks if we are going to override it
-    # Note: This over writes the first metadata block it encountered even if it doesn't belong to the source file we specified
     my $name_attr = $attrHash->{'name'};
     if (($name_attr eq $metaname) && ($metamode eq "override")) {
@@ -546,4 +639,6 @@
 	$attrHash->{'_content'} = $metavalue;
 
+##	print STDERR "**** overrideing metadata.xml\n";
+
 	# Don't want it to wipe out any other pieces of metadata
 	$parser->{'parameters'}->{'metamode'} = "done";
@@ -565,10 +660,23 @@
     # Don't do anything if we are not in the right FileSet
     my $file_regexp = $parser->{'parameters'}->{'current_file'};
-    return [$tagname => $attrHash] if (!($parser->{'parameters'}->{'src_file'} =~ /$file_regexp/));
+    if ($file_regexp =~ /\.\*/) {
+	# Only interested in a file_regexp if it specifies precisely one
+	# file.  
+	# So, skip anything with a .* in it as it is too general
+	return [$tagname => $attrHash];
+    }
+    my $src_file = $parser->{'parameters'}->{'src_file'};
+    if (!($src_file =~ /$file_regexp/)) {
+	return [$tagname => $attrHash];
+    }
 
     # Accumulate the metadata block to the end of the description block
     # Note: This adds metadata block to all description blocks, so if there are 
     # multiple FileSets, it will add to all of them
-    if ($metamode eq "accumulate") {
+    if (($metamode eq "accumulate") || ($metamode eq "override")) {
+	# if metamode was "override" but get to here then it failed to
+	# find an item to override, in which case it should append its 
+	# value to the end, just like the "accumulate" mode
+
 	# tack a new metadata tag on to the end of the <Metadata>+ block
 	my $metaname = $parser->{'parameters'}->{'metaname'};
@@ -582,5 +690,11 @@
 	my $description_content = $attrHash->{'_content'};
 
+##	print STDERR "*** appending to metadata.xml\n";
+
+	# append the new metadata element to the end of the current
+	# content contained inside this tag
 	push(@$description_content,"    ", $append_metadata ,"\n        ");
+
+	$parser->{'parameters'}->{'metamode'} = "done";
     }
 
@@ -647,23 +761,28 @@
 	}
 	close(MIN);	
-	
+
         # Filter with the call-back functions
 	my $xml_out = "";
-	$parser->filter($xml_in,\$xml_out, { metaname => $metaname,
-					     metavalue => $metavalue,
-                                             metamode => $metamode,
-					     src_file => $src_file,
-					     current_file => undef} );
-
-	if (!open(MOUT,">$metadata_xml_filename")) {
+
+	my $MOUT;
+	if (!open($MOUT,">$metadata_xml_filename")) {
 	    $gsdl_cgi->generate_error("Unable to write out to $metadata_xml_filename: $!");
 	}
 	else {
+	    binmode($MOUT,":utf8");
+
             # Some wise person please find out how to keep the DTD and encode lines in after it gets filtered by this XML::Rules
             # At the moment, I will just hack it!
-            my $header_with_utf8_dtd = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE DirectoryMetadata SYSTEM \"http://greenstone.org/dtd/DirectoryMetadata/1.0/DirectoryMetadata.dtd\">";
-            $xml_out =~ s/\<\?xml\sversion\=\"1.0\"\?\>/$header_with_utf8_dtd/;
-	    print MOUT $xml_out;
-	    close(MOUT);	    
+            #my $header_with_utf8_dtd = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+	    #$header_with_utf8_dtd .= "<!DOCTYPE DirectoryMetadata SYSTEM \"http://greenstone.org/dtd/DirectoryMetadata/1.0/DirectoryMetadata.dtd\">";
+            #$xml_out =~ s/\<\?xml\sversion\=\"1.0\"\?\>/$header_with_utf8_dtd/;
+	    #print MOUT $xml_out;
+
+	    $parser->filter($xml_in, $MOUT, { metaname => $metaname,
+					      metavalue => $metavalue,
+					      metamode => $metamode,
+					      src_file => $src_file,
+					      current_file => undef} );
+	    close($MOUT);	    
 	}
     }
@@ -681,9 +800,9 @@
     my $infodbtype = $self->{'infodbtype'};
 	
-    # don't user authenticate for now
     if ($baseaction::authentication_enabled) {
 	# Ensure the user is allowed to edit this collection
 	$self->authenticate_user($username, $collect);
     }
+
 
     # Obtain the collect and archive dir    
@@ -705,4 +824,8 @@
     my $metaname   = $self->{'metaname'};
     my $metavalue  = $self->{'metavalue'};
+##    $metavalue =~ s/&amp;lt;(.*?)&amp;gt;/<$1>/g;
+    $metavalue =~ s/&lt;(.*?)&gt;/<$1>/g;
+    print STDERR "*** set import meta: val = $metavalue\n";
+    
     my $metamode   = $self->{'metamode'};
     if ((!defined $metamode) || ($metamode =~ m/^\s*$/)) {
@@ -721,10 +844,10 @@
 
 	# This now stores the full pathname
-	$import_filename = $doc_rec->{'src-file'}->[0];
+	$import_filename = $doc_rec->{'src-file'}->[0];	
     }
     else {
         $import_filename = &util::filename_cat($collect_dir,$collect,$import_file);
     }
-        
+
     # figure out correct metadata.xml file [?]
     # Assuming the metadata.xml file is next to the source file
@@ -745,4 +868,12 @@
     # Release the lock once it is done
     $self->unlock_collection($username, $collect);
+
+    my $mess = "set-import-metadata successful: Key[$docid] -> $metadata_xml_filename\n";
+    $mess .= "  $metaname";
+    $mess .= " = $metavalue";
+    $mess .= " ($metamode)\n";
+	
+    $gsdl_cgi->generate_ok_message($mess);
+    
 }
 
@@ -817,5 +948,4 @@
     my $infodbtype = $self->{'infodbtype'};
 	
-    # don't user authenticate for now
     if ($baseaction::authentication_enabled) {
 	# Ensure the user is allowed to edit this collection
@@ -912,5 +1042,7 @@
 
 
-# Was trying to reused the codes, but the functions need to be broken down more before they can be reused, otherwise there will be too much overhead and duplicate process...
+# Was trying to reused the codes, but the functions need to be broken
+# down more before they can be reused, otherwise there will be too
+# much overhead and duplicate process...
 sub insert_metadata
 {
@@ -923,8 +1055,9 @@
     my $infodbtype = $self->{'infodbtype'};
 	
-    # If the import metadata and gdbm database have been updated, we need to insert some notification to warn user that the the text they see at the moment is not indexed and require a rebuild.
+    # If the import metadata and gdbm database have been updated, we
+    # need to insert some notification to warn user that the the text
+    # they see at the moment is not indexed and require a rebuild.
     my $rebuild_pending_macro = "_rebuildpendingmessage_";
 
-    # don't user authenticate for now
     if ($baseaction::authentication_enabled) {
 	# Ensure the user is allowed to edit this collection
