#!/bin/sh
#
# @package      hubzero-filexfer
# @file         importfile
# @author       Michael McLennan <mmclennan@purdue.edu>
# @author       Derrick Kearney <dsk@purdue.edu>
# @author       Nicholas J. Kisseberth <nkissebe@purdue.edu>
# @copyright    Copyright (c) 2004-2013 HUBzero Foundation, LLC.
# @license      http://www.gnu.org/licenses/lgpl-3.0.html LGPLv3
#
# Copyright (c) 2004-2013 HUBzero Foundation, LLC.
#
# This file is part of: The HUBzero(R) Platform for Scientific Collaboration
#
# The HUBzero(R) Platform for Scientific Collaboration (HUBzero) is free
# software: you can redistribute it and/or modify it under the terms of
# the GNU Lesser General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# HUBzero is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# HUBzero is a registered trademark of HUBzero Foundation, LLC.
#

# ----------------------------------------------------------------------
#  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.
#
# ======================================================================
#  AUTHOR:  Michael McLennan, Purdue University
#  Copyright (c) 2004-2007  Purdue Research Foundation
#
#  See the file "license.terms" for information on usage and
#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# ======================================================================

# ----------------------------------------------------------------------
#\
. /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
