Index: client/1.0/pkgd.eagle
==================================================================
--- client/1.0/pkgd.eagle
+++ client/1.0/pkgd.eagle
@@ -23,11 +23,21 @@
   #
   # NOTE: This procedure sets up the default values for all configuration
   #       parameters used by the package downloader client.  There are no
   #       arguments.
   #
-  proc setupDownloadVars {} {
+  proc setupDownloadVars { script } {
+    #
+    # NOTE: What is the fully qualified path to the directory containing the
+    #       package downloader client?
+    #
+    variable clientDirectory
+
+    if {![info exists clientDirectory]} then {
+      set clientDirectory [file dirname $script]
+    }
+
     #
     # NOTE: Prevent progress messages from being displayed while downloading
     #       from the repository, etc?  By default, this is enabled.
     #
     variable quiet; # DEFAULT: true
@@ -76,10 +86,56 @@
     #       directory.
     #
     return [file join [file dirname [info library]] pkgd]
   }
 
+  #
+  # NOTE: This procedure returns non-zero if the specified file seems to be
+  #       an OpenPGP signature file.  The fileName argument is the name of
+  #       the file to check, which may or may not exist.
+  #
+  proc isPgpSignatureFileName { fileName } {
+    if {[string length $fileName] == 0} then {
+      return false
+    }
+
+    set extension [file extension]
+
+    if {$extension eq ".asc"} then {
+      if {[file exists $fileName]} then {
+        return [::PackageRepository::isPgpSignature [readFile $fileName]]
+      } else {
+        return true
+      }
+    } else {
+      return false
+    }
+  }
+
+  #
+  # NOTE: This procedure returns non-zero if the specified file seems to be
+  #       a Harpy script certificate file.  The fileName argument is the name
+  #       of the file to check, which may or may not exist.
+  #
+  proc isHarpyCertificateFileName { fileName } {
+    if {[string length $fileName] == 0} then {
+      return false
+    }
+
+    set extension [file extension]
+
+    if {$extension eq ".harpy"} then {
+      if {[file exists $fileName]} then {
+        return [::PackageRepository::isHarpyCertificate [readFile $fileName]]
+      } else {
+        return true
+      }
+    } else {
+      return false
+    }
+  }
+
   #
   # NOTE: This procedure adds a directory to the auto-path of the specified
   #       language (i.e. native Tcl or Eagle).  The directory will not be
   #       added if it is already present.  The language argument must be the
   #       literal string "eagle" or the literal string "tcl".  The directory
@@ -125,71 +181,133 @@
     } else {
       error "unsupported language, no idea how to modify auto-path"
     }
   }
 
+  #
+  # NOTE: This procedure downloads a single file from the package file server,
+  #       writing its contents to the specified local file name.  It can also
+  #       verify the PGP signatures.  When a PGP signature file is
+  #       downloaded, this procedure assumes the corresponding data file was
+  #       already downloaded (i.e. since OpenPGP needs both to perform the
+  #       signature checks).  The language argument must be one of the
+  #       literal strings "eagle", "tcl", or "client".  The version argument
+  #       must be one of the literal strings "8.4", "8.5", or "8.6" when the
+  #       language is "tcl" -OR- the literal string "1.0" when the language
+  #       is either "eagle" or "client".  The fileName argument is a file
+  #       name relative to the language and version-specific directory on the
+  #       package file server.  The localFileName argument is the file name
+  #       where the downloaded file should be written.  The usePgp argument
+  #       should be non-zero when an OpenPGP signature file needs to be
+  #       downloaded and verified for the downloaded file.
+  #
+  proc downloadOneFile { language version fileName localFileName usePgp } {
+    variable baseUri
+    variable downloadUri
+    variable quiet
+
+    #
+    # NOTE: First, build the full relative file name to download from the
+    #       remote package repository.
+    #
+    set fileName [file join $language $version $fileName]
+    set uri [subst $downloadUri]
+
+    if {[isEagle]} then {
+      writeFile $localFileName [interp readorgetscriptfile -- "" $uri]
+    } else {
+      writeFile $localFileName \
+          [::PackageRepository::getFileViaHttp $uri 10 stdout $quiet]
+    }
+
+    #
+    #
+    #
+    if {$usePgp && [isPgpSignatureFileName $localFileName]} then {
+      #
+      #
+      #
+      if {![::PackageRepository::verifyPgpSignature $localFileName]} then {
+        error [appendArgs \
+            "bad PGP signature \"" $localFileName \"]
+      }
+    }
+  }
+
   #
   # NOTE: This procedure attempts to download a list of files, optionally
   #       persistening them for subsequent uses by the target language.
-  #       The language argument must be the literal string "eagle" or the
-  #       literal string "tcl".  The version argument must be the literal
-  #       string "8.4", "8.5", or "8.6" when the language is "tcl" -OR-
-  #       the literal string "1.0" when the language is "eagle".  The
-  #       fileNames argument must be a well-formed list of file names to
-  #       download, each one relative to the language/version-specific
-  #       directory on the package file server.  The persistent argument
-  #       should be non-zero if the downloaded files should be saved to
-  #       permanent storage for subsequent use.  The usePgp argument
-  #       should be non-zero when an OpenPGP signature file needs to be
-  #       downloaded and verified for each downloaded file.  The
+  #       The language argument must be one of the literal strings "eagle",
+  #       "tcl", or "client".  The version argument must be one of the
+  #       literal strings "8.4", "8.5", or "8.6" when the language is "tcl"
+  #       -OR- the literal string "1.0" when the language is either "eagle"
+  #       or "client".  The fileNames argument must be a well-formed list
+  #       of file names to download, each one relative to the language and
+  #       version-specific directory on the package file server.  The
+  #       persistent argument should be non-zero if the downloaded files
+  #       should be saved to permanent storage for subsequent use.  The
+  #       usePgp argument should be non-zero when an OpenPGP signature file
+  #       needs to be downloaded and verified for each downloaded file.  The
   #       useAutoPath argument should be non-zero to modify the auto-path
   #       to include the temporary or persistent directories containing
   #       the downloaded files.
   #
   # <public>
   proc downloadFiles {
           language version fileNames persistent usePgp useAutoPath } {
+    global env
     variable baseUri
+    variable clientDirectory
     variable downloadUri
     variable persistentDirectory
     variable quiet
+
+    set client false
 
     if {[string length $language] == 0 || $language eq "eagle"} then {
       if {$version ne "1.0"} then {
         error "unsupported Eagle version"
       }
     } elseif {$language eq "tcl"} then {
       if {$version ne "8.4" && $version ne "8.5" && $version ne "8.6"} then {
         error "unsupported Tcl version"
       }
+    } elseif {$language eq "client"} then {
+      if {$version ne "1.0"} then {
+        error "unsupported client version"
+      }
+
+      set client true
     } else {
       error "unsupported language"
     }
 
-    if {$persistent} then {
-      set downloadRootDirectory $persistentDirectory
-    } else {
-      set directoryNameOnly [appendArgs \
-          pkgd_ [string trim [pid] -] _ [string trim [clock seconds] -]]
-
-      global env
-
-      if {[info exists env(PKGD_TEMP)]} then {
-        set downloadRootDirectory $env(PKGD_TEMP)
-      } elseif {[info exists env(TEMP)]} then {
-        set downloadRootDirectory $env(TEMP)
-      } elseif {[info exists env(TMP)]} then {
-        set downloadRootDirectory $env(TMP)
-      } else {
-        error "please set PKGD_TEMP (via environment) to temporary directory"
-      }
-
-      set downloadRootDirectory [file join \
-          $downloadRootDirectory $directoryNameOnly]
-    }
-
-    set downloadDirectories [list]
+    if {[info exists env(PKGD_TEMP)]} then {
+      set temporaryRootDirectory $env(PKGD_TEMP)
+    } elseif {[info exists env(TEMP)]} then {
+      set temporaryRootDirectory $env(TEMP)
+    } elseif {[info exists env(TMP)]} then {
+      set temporaryRootDirectory $env(TMP)
+    } else {
+      error "please set PKGD_TEMP (via environment) to temporary directory"
+    }
+
+    set temporaryDirectory [file join $temporaryRootDirectory \
+        [appendArgs pkgd_ [string trim [pid] -] _ [string trim \
+        [clock seconds] -]]]
+
+    if {$persistent} then {
+      if {$client} then {
+        set downloadRootDirectory $clientDirectory
+      } else {
+        set downloadRootDirectory $persistentDirectory
+      }
+    } else {
+      set downloadRootDirectory $temporaryDirectory
+    }
+
+    set downloadedFileNames [list]
 
     foreach fileName $fileNames {
       if {[string length $fileName] == 0 || \
           [file pathtype $fileName] ne "relative"} then {
         error [appendArgs \
@@ -201,61 +319,51 @@
       if {[llength $directoryParts] == 0} then {
         error [appendArgs \
             "bad file name \"" $fileName "\", no directory parts"]
       }
 
-      set downloadDirectory [file normalize [eval file join \
-          [list $downloadRootDirectory] $directoryParts]]
+      set downloadDirectory(temporary) [file normalize [eval \
+          file join [list $temporaryDirectory] $directoryParts]]
+
+      set downloadDirectory(persistent) [file normalize [eval \
+          file join [list $downloadRootDirectory] $directoryParts]]
 
       set downloadFileName [file normalize [file join \
-          $downloadDirectory [file tail $fileName]]]
+          $downloadDirectory(temporary) [file tail $fileName]]]
 
-      if {!$persistent} then {
-        catch {file delete $downloadFileName}
+      if {[file exists $downloadFileName]} then {
+        error [appendArgs \
+            "temporary file name \"" $downloadFileName \
+            "\" already exists"]
       }
 
       file mkdir [file dirname $downloadFileName]
 
-      set savedFileName $fileName
-      set fileName [file join $language $version $fileName]
-      set uri [subst $downloadUri]
-      set fileName $savedFileName
-
-      if {[isEagle]} then {
-        writeFile $downloadFileName \
-            [interp readorgetscriptfile -- "" $uri]
-      } else {
-        writeFile $downloadFileName \
-            [::PackageRepository::getFileViaHttp $uri 10 stdout $quiet]
-      }
-
-      if {$usePgp} then {
-        set downloadSignatureFileName [appendArgs $downloadFileName .asc]
-
-        set savedFileName $fileName
-        set fileName [file join \
-            $language $version [appendArgs $fileName .asc]]
-
-        set uri [subst $downloadUri]
-        set fileName $savedFileName
-
-        if {[isEagle]} then {
-          writeFile $downloadSignatureFileName \
-              [interp readorgetscriptfile -- "" $uri]
-        } else {
-          writeFile $downloadSignatureFileName \
-              [::PackageRepository::getFileViaHttp $uri 10 stdout $quiet]
-        }
-
-        if {![::PackageRepository::verifyPgpSignature \
-            $downloadSignatureFileName]} then {
-          error [appendArgs \
-              "bad PGP signature \"" $downloadSignatureFileName \"]
-        }
-      }
-
-      lappend downloadDirectories $downloadDirectory
+      downloadOneFile $language $version $fileName $downloadFileName $usePgp
+
+      lappend downloadedFileNames $downloadFileName
+
+      if {$usePgp && ![isPgpSignatureFileName $downloadFileName] && \
+          ![isHarpyCertificateFileName $downloadFileName]} then {
+        downloadOneFile $language $version [appendArgs $fileName .asc] \
+            [appendArgs $downloadFileName .asc] $usePgp
+
+        lappend downloadedFileNames [appendArgs $downloadFileName .asc]
+      }
+    }
+
+    set downloadDirectories [list]
+
+    foreach downloadedFileName $downloadedFileNames {
+      if {$persistent} then {
+
+
+
+
+      } else {
+        lappend downloadDirectories [file dirname $downloadedFileName]
+      }
     }
 
     set downloadDirectories [lsort -unique $downloadDirectories]
 
     if {$useAutoPath} then {
@@ -279,13 +387,13 @@
   ::PackageRepository::maybeReadSettingsFile [info script]
 
   #
   # NOTE: Setup the variables, within this namespace, used by this script.
   #
-  setupDownloadVars
+  setupDownloadVars [info script]
 
   #
   # NOTE: Provide the package to the interpreter.
   #
   package provide Eagle.Package.Downloader \
     [expr {[isEagle] ? [info engine PatchLevel] : "1.0"}]
 }