#!/bin/sh
#
# @package      hubzero-filexfer
# @file         importfile
# @copyright    Copyright (c) 2004-2020 The Regents of the University of California.
# @license      http://opensource.org/licenses/MIT MIT
#
# Copyright (c) 2004-2020 The Regents of the University of California.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# HUBzero is a registered trademark of The Regents of the University of California.
#

# ----------------------------------------------------------------------
#  USAGE: importfile ?options? ?--label text? file file ...
#
#    options:
#      -h or --help
#        Prints a help message.
#
#      -f or --for <text>
#        Short explanation of what the data will be used for; for
#        example, "for CNTBands 2.0".  If given, this text is inserted
#        into the upload form to help explain what it will be used for.
#
#      -l or --label <text>
#        Prompt for subsequent file arguments using this label string.
#        The default label just uses the file name.
#
#      -m or --mode acsii|binary|auto
#        In "binary" mode, files are transferred exactly as-is.  In
#        "ascii" mode, control-M characters are removed, which helps
#        when loading Windows files into the Linux environment.  The
#        default is "auto", which removes control-M from text files
#        but leaves binary files intact.
#
#      -p or --provenance
#        Print more verbose results showing the provenance information
#        for all files uploaded.  Instead of a series of space-separated
#        file names, this produces one line for each file showing the
#        final file name and where it came from, which is either the
#        file name on the user's desktop or @CLIPBOARD meaning that the
#        user pasted information into the text entry area.  For example:
#           foo.tgz <= gui15.tar.gz
#           bar.txt <= @CLIPBOARD
#
#      --
#        Remaining arguments are treated as file names, even if
#        they start with a -.
#
#  This is the client that users invoke to transfer files from their
#  desktop into their session.  This works a lot like a download
#  operation (see exportfile command) but the file downloaded is
#  merely a form that the user can use to upload information.  This
#  client tries to connect to a server to handle the transfer.  If
#  necessary, the client tries to spawn the server and then connect
#  to it.  The server uses the "clientaction" program to open the
#  upload form on the user's desktop.  The user then chooses one
#  or more files and posts the results back to the server, which
#  stores the files in the specified names and then notifies this
#  client that they are ready.
#

# ----------------------------------------------------------------------
#\
. /etc/environ.sh
#\
use -e -r rappture
#\
exec tclsh "$0" ${1+"$@"}
# ----------------------------------------------------------------------
# tclsh executes everything from here on...

# load util procedures from this path
lappend auto_path /usr/share/hubzero-filexfer

array set options {
  --for ""
  --label @DEFAULT
  --mode auto
  --provenance 0
}
set usage "$argv0 \[-f|--for text\] \[-l|--label text\] file file ..."
set manpage "
USAGE: $usage

  options:
    -h or --help
      Prints this help message.

    -f or --for <text>
      Short explanation of what the data will be used for; for
      example, \"for CNTBands 2.0\".  If given, this text is inserted
      into the upload form to help explain what it will be used for.

    -l or --label <text>
      Prompt for subsequent file arguments using this label string.
      The default label just uses the file name.

    -m or --mode acsii|binary|auto
      In \"binary\" mode, files are transferred exactly as-is.  In
      \"ascii\" mode, control-M characters are removed, which helps
      when loading Windows files into the Linux environment.  The
      default is \"auto\", which removes control-M from text files
      but leaves binary files intact.

    -p or --provenance
      Print more verbose results showing the provenance information
      for all files uploaded.  Instead of a series of space-separated
      file names, this produces one line for each file showing the
      final file name and where it came from, which is either the
      file name on the user's desktop or @CLIPBOARD meaning that the
      user pasted information into the text entry area.  For example:
         foo.tgz <= gui15.tar.gz
         bar.txt <= @CLIPBOARD

    --
      Remaining arguments are treated as file names, even if they
      start with a -.

    file
      Uploaded file will be saved in this file name within your
      tool session. If file is @@ then the file is given the same
      name it had before it was uploaded. If no file arguments
      are included, the default is \"@@\", meaning upload a single
      file and use the name it had on the desktop.

You can use this command to transfer one or more files from your
desktop to your tool session via a web browser.  This command causes
a web page to pop up prompting you for various files on your desktop.
Choose one or more files and submit the form.  The files will be
uploaded to your tool session and saved in the file names specified
on the command line.

This command returns a list of names for files actually uploaded."

#
# Parse all command-line arguments and build up a list of files:
#   label1 file1  label2 file2 ...
#
set uploadlist ""

while {[llength $argv] > 0} {
    set opt [lindex $argv 0]
    set argv [lrange $argv 1 end]

    if {"-" != [string index $opt 0]} {
        lappend uploadlist $options(--label) $options(--mode) $opt
        continue
    }

    switch -- $opt {
        -f - --for {
            if {[llength $argv] == 0} {
                puts stderr "missing value for $opt"
                exit 1
            }
            set options(--for) " [lindex $argv 0]"
            set argv [lrange $argv 1 end]
        }
        -l - --label {
            if {[llength $argv] == 0} {
                puts stderr "missing value for $opt"
                exit 1
            }
            set options(--label) [lindex $argv 0]
            set argv [lrange $argv 1 end]
        }
        -m - --mode {
            if {[llength $argv] == 0} {
                puts stderr "missing value for $opt"
                exit 1
            }
            set options(--mode) [lindex $argv 0]
            if {[lsearch {ascii binary auto} [string tolower $options(--mode)]] < 0} {
                puts stderr "bad mode \"$options(--mode)\": should be ascii, binary, or auto"
                exit 1
            }
            set argv [lrange $argv 1 end]
        }
        -p - --provenance {
            set options(--provenance) 1
        }
        -h - --help {
            puts $manpage
            exit
        }
        -- {
            foreach file $argv {
                lappend uploadlist $options(--label) $options(--mode) $file
            }
            set argv ""
        }
        default {
            puts stderr "bad option \"$opt\""
            puts stderr $usage
            exit 1
        }
    }
}

#
# Load the template for the upload form.
#
set installdir /usr/share/hubzero-filexfer
set fid [open [file join $installdir upload.html] r]
set html [read $fid]
close $fid

#
# Load the settings from the user's resources file.
# In particular, figure out filexfer_port so we know how to talk
# to the filexfer server.
#
if {[catch {filexfer::resources} result]} {
    puts stderr "can't load resource configuration:"
    puts stderr $result
    exit 1
}
array set settings $result

if {![info exists settings(port)]} {
    puts stderr "missing filexfer_port in resource settings"
    exit 1
}
if {![info exists settings(cookie)]} {
    puts stderr "missing filexfer_cookie in resource settings"
    exit 1
}

#
# Make a connection to the filexfer server.  Spawn the server, if
# necessary.
#
set buffer ""
proc server_mesg {sid} {
    global finished buffer options

    if {[gets $sid line] < 0} {
        set finished 1
    } else {
        append buffer $line "\n"
        if {[info complete $buffer]} {
            set cmd $buffer
            set buffer ""
            set word [lindex $cmd 0]
            switch -- $word {
              ERROR {
                set mesg [lindex $cmd 1]
                puts stderr $mesg
                exit 1
              }
              IMPORTED {
                # print list of files created
                set flist ""
                foreach rec [lrange $cmd 1 end] {
                    set line [lindex $rec 0]
                    catch {unset extra}
                    array set extra [lrange $rec 1 end]
                    if {$options(--provenance)} {
                        if {[info exists extra(-filename)]} {
                            set line "$line <= $extra(-filename)"
                        } else {
                            set line "$line <= @CLIPBOARD"
                        }
                    }
                    lappend flist $line
                }
                if {[llength $flist] > 0} {
                    puts [join $flist \n]
                } else {
                    puts stderr "no files uploaded -- did you forget to choose a file?"
                    exit 1
                }
              }
              default {
                puts "HUH? $cmd"
              }
            }
        }
    }
}

# no args? then upload a single file
if {[llength $uploadlist] == 0} {
    lappend uploadlist $options(--label) auto @@
}

if {[catch {filexfer::connect $settings(port) server_mesg} sid]} {
    puts stderr "can't connect to filexfer server: $sid"
    exit 1
}

#
# Substitute the upload list into the @REPEAT(...)@ area of
# the HTML text.
#
while {[regexp -indices {@REPEAT\((.+?)\)@} $html match inner]} {
    foreach {s0 s1} $match break
    foreach {p0 p1} $inner break
    set template [string range $html $p0 $p1]

    set expanded ""
    set n 1
    foreach {label mode file} $uploadlist {
        if {[string equal $file @@] || [string equal $file @USE_REMOTE@]} {
            set file @USE_REMOTE@
            set controls "display: none;"
        } else {
            set controls ""
        }
        if {[string equal $label @DEFAULT]} {
            if {[string equal $file @USE_REMOTE@]} {
                set label "File"
            } else {
                set label "File [file tail $file]"
            }
        }
        if {[file pathtype $file] == "relative"} {
            set file [file normalize [file join [pwd] $file]]
        }

        append expanded [string map [list \
            @INDEX@ $n \
            @LABEL@ $label \
            @MODE@ $mode \
            @DEST@ $file \
            @CONTROLS@ $controls \
        ] $template]
        incr n
    }
    set html [string replace $html $s0 $s1 $expanded]
}

#
# Substitute the rest of the @NAME@ fields.
#
set hubname "???"
if {[info exists settings(hubname)]} {
    set hubname $settings(hubname)
}

set csspath "tools/assets/css"
if {[info exists settings(hubtemplate)]} {
    set csspath "templates/$settings(hubtemplate)/css"
}

set html [string map [list \
    @FOR@ $options(--for) \
    @HUBNAME@ $hubname \
    @CSSPATH@ $csspath \
] $html]

set file "/tmp/upload[pid].html"
set fid [open $file w]
puts -nonewline $fid $html
close $fid

puts $sid [list IMPORT $file $settings(cookie) FILEXFER/1.0]

vwait finished  ;# wait for server to close
