#!/usr/bin/perl
###############################################################################
# getsub.pl   (GET SUBMITTED x) (only works on assignments)
# Chris Cera, chris@cera.ws
# Created :  1/31/2001
# Modified: everyday Last: 4/15/2001
# Version: 1.2
###############################################################################
# tested on WebCT version 3.1.3, probably incompatible with any other version
# uses http authentication at each step
# you must run this program for each assignment, get its ID from the url first
# it will create a directory tree for each person's submission, if it exists
# you must have lynx on your system in this version, cURL could also be used
# this was developed on Linux, so I don't know if it will run from windows.
#     there is no reason why it shouldn't be able to, except for the slash
#     issues that exist b/w windows and unices.  Hacking it would be minimal.
###############################################################################
# WISHLIST
#
# automatically change modification dates to match those submitted
# get this to work for quizzes
###############################################################################
#Lynx Version 2.8.4dev.7 (03 Aug 2000)
#Built on linux-gnu Aug  4 2000 05:38:40
###############################################################################

use Getopt::Std;
use File::Copy;

sub mysystem;
sub myprint;
sub testandcreate;

$VERBOSE       = 0;
$SKIP_DLOAD    = 0;
$PERF_POSTP    = 0;

###############################################################################
# CONSTANTS
###############################################################################

$PROGNAME     = "getsub";
$DOMAIN       = "webct.drexel.edu";
$strUnameFile = "./unames.txt";
$srcdir       = "getsub_src";

###############################################################################
# CHECK command line usage
###############################################################################

# this is the uniquely assigned id number for each assignment
#$idCourse  = "CS999";  # cs999 works too for some magical reason
#$idDropBox = "123456789";

getopts ('u:p:c:b:xov');

$u          = $opt_u;
$p          = $opt_p;
$idCourse   = $opt_c;
$idDropBox  = $opt_b;

# these can be overidden by hard-coding above, so check first
if ($SKIP_DLOAD == 0) {$SKIP_DLOAD = $opt_x;}
if ($PERF_POSTP == 0) {$PERF_POSTP = $opt_o;}
if ($VERBOSE    == 0) {$VERBOSE    = $opt_v;}

myprint "opt_u = $opt_u\n";
myprint "opt_p = $opt_p\n";
myprint "opt_c = $opt_c\n";
myprint "opt_b = $opt_b\n";
myprint "opt_v = $opt_v\n";
myprint "opt_x = $opt_x\n";
myprint "opt_o = $opt_o\n";

if (  $opt_u eq ""  ||
      $opt_p eq ""  ||
      $opt_c eq ""  ||
      $opt_b eq ""     ) {

    print STDOUT "Usage:  ./$PROGNAME -u userid -p passwd -c cname -b boxid [vxp]\n";
    print STDOUT "        -u userid\n";
    print STDOUT "        -p passwd\n";
    print STDOUT "        -c coursename\n";
    print STDOUT "        -b boxid\n";
    print STDOUT "        -v verbose printing\n";
    print STDOUT "        -x skip downloading step\n";
    print STDOUT "        -o perform post processing step\n";
    exit (1);
}


$urlSubmitList = "http://$DOMAIN/SCRIPT/$idCourse/scripts/student/dropbox_files_view.pl?MENU+_side_nav++$idDropBox++";


testandcreate("$idDropBox");

###############################################################################
# REAL WORK
#
#     input is simply a single column file of usernames
###############################################################################

if (! $SKIP_DLOAD) {

    open (input, "<$strUnameFile");

    if (-e $strUnameFile) {
        print STDERR "$PROGNAME will read in your list of usernames ...\n";
    }
    else {
        print STDERR "$strUnameFile is NOT FOUND\n";
        exit (1);
    }

    $i = 0;
    while ( <input> ) {
    
        # blasts newline
        chop ($uname = $_);
    
        $unames[$i++] = $uname;
        $SRCFILE = "test/$_";
    
        print STDERR "checking -->$uname<-- .... \n";
    
        # the href we are grabbing is given by a relative path
        # do a source dump of that address, but first authenticate
    
        chop ($data = `lynx --source -auth=$u:$p $urlSubmitList$uname | grep HREF`);
    
        # output will look like
        # <A HREF="/SCRIPT/CS999/scripts/student/dropbox_files_view.pl?FILE_VIEW+_side_nav++123456789+asmt2.tar.gz+abrader" TARGET="right" onClick="doSelect('asmt2.tar.gz')"> asmt2.tar.gz</A>
        #      ^^^^^^^^^^^^
        #
        #    which has form
        #    <a href="....?FILE_VIEW+_side_nav++[$idDropBox]++[FILE]++[$uname]</a>
    
        #    ... so we'll pick up everything after first '>' and before next '<'
    
        $pos = 0;
        $switch = 1;
        while ( ($pos = index ($data,"HREF",$pos) ) > -1) {
    
            # check if first time in loop for this user
            if ($switch == 1) {

                # create directory if DNE
                testandcreate ("$idDropBox/$uname");

                $switch = 0;
            }
    
            $end_bracket = index ($data, ">", $pos);
            $stt_bracket = index ($data, "<", $end_bracket);
    
            # +2 is b/c there is always a space after the end bracket.
            # +1 at the end just works, and didn't care enough to find out why :D
            $len = ($stt_bracket - 1) - ($end_bracket + 2) + 1;
    
            # print STDERR "end=$end_bracket\nstt=$stt_bracket\npos=$pos\n";
            # print STDERR "len=$len\n";
    
            # rip out the filename from the url
            $filename = substr ($data, $end_bracket+2, $len);
    
            print STDERR "    has submitted -->$filename<--\n";
    
            $urlSubmission = "$DOMAIN/SCRIPT/$idCourse/scripts/student/dropbox_files_view.pl?FILE_VIEW+_side_nav++$idDropBox+$filename+$uname";
    
            mysystem ("lynx --source -auth=$u:$p $urlSubmission | grep -v xmp > $idDropBox/$uname/$filename");
    
            # might want to find a way use threads that way these calls could be
            # run in parallel.  That could be detrimental to webct though.  It
            # would be an interesting test.
    
            $pos = $end_bracket;
            $filename = "";
        }
        # if ($i >= 2) { exit (1); }
    }
    close (input);
}    


###############################################################################
# post processing
###############################################################################
# flatten dirs, put all files in one directory
# handles most types
###############################################################################

if ($PERF_POSTP) {

    myprint "start post-processing\n";

    open (input, "<$strUnameFile");

    if (-e $strUnameFile) {
        print STDERR "$PROGNAME will read in your list of usernames ...\n";
    }
    else {
        print STDERR "$strUnameFile is NOT FOUND\n";
        exit (1);
    }

    testandcreate ("$idDropBox/$srcdir/");

    $switch = 1;
    BIG: while ( <input> ) {
    
        # blasts newline
        chop ($uname = $_);

        # check if it exists
        if (! -e "$idDropBox/$uname/") {
            next;
        }

        testandcreate ("$idDropBox/$srcdir/$uname");
    
        # the grep gets rid of . and ..
        
        opendir DROPBOX, "$idDropBox/$uname/" or die "weird error";
    	@allfiles = map "$idDropBox/$uname/$_", readdir DROPBOX;
    	#@allfiles = grep !/^$idDropBox\/$uname/\./, map "$idDropBox/$uname/$_", readdir DROPBOX;
    
        if (@allfiles == 0) {
            next;
        }


    	# allfiles is not prepended with absolute dir information
    	SMALL: while ($e = pop @allfiles) {

            myprint "pp:    $e\n";
            myprint "allfiles = @allfiles\n";

            #swap
            #$e is filename
            #$f is qualified filename

            @temp  = split ('/', $e); # just to get arg count

            if (! -d "$e") {
                $dir = "$temp[0]";
                for ($i = 1; $i <= (scalar @temp) - 2; $i++) {
                    $dir = "$dir/$temp[$i]";
                }
            }
            else {
                $dir = $e;
            }

            myprint "dir: $dir\n"; 

            $f = $e;
            $e = $temp [ (scalar @temp) - 1];

            if ($e eq "."  ||  $e eq "..") {
                next;
            }

            if    (-f $f) {
                # file
                ###########
                #determine type
                #if its an encoding, unencode and put back for later
                #else its a source textfile, finish it


                # this depends on file extensions
                @ext = split ('\.', $e);

                $last_ext_num = (scalar @ext) - 1; # 1st last ext
                $last_ext = $ext [$last_ext_num];;

                # create same as $f, filename w/o last extension
                $newguy = "$ext[0]";
                for ($i = 1; $i <= (scalar @ext) - 2; $i++) {
                    $newguy = "$newguy.$ext[$i]";
                }

                myprint "eee:  $e\n";
                myprint "new:  $newguy\n";

                ##########################
                # begin file type handling
                ##########################

                myprint ("It is a *.$last_ext file\n");

                ## UUENCODE
                if    ( $last_ext eq "uue" || 
                        $last_ext eq "UUE" ||
                        $last_ext eq "uu"  ||
                        $last_ext eq "UU"      ) {

                    mysystem ("uudecode -o $dir/$newguy $f");
                    mysystem ("rm $f");
                    # prepend at beginning
                    unshift @allfiles, "$dir/$newguy";
                    next SMALL;
                }

                ## GNU ZIP
                elsif ($last_ext eq "gz" || $last_ext eq "GZ") {
                    mysystem ("gunzip $f");
                    # gunzip deletes it for you by default

                    # prepend at beginning
                    unshift @allfiles, "$dir/$newguy";
                    next SMALL;
                }

                ## WINZIP
                elsif ($last_ext eq "zip" || $last_ext eq "ZIP") {
                    mysystem ("cd $dir && unzip $e");
                    mysystem ("rm $f");
                    redo BIG;
                }

                ## TAPE ARCHIVE
                elsif ($last_ext eq "tar" || $last_ext eq "TAR") {
                    mysystem ("cd $dir && tar xvf $e");
                    mysystem ("rm $f");
                    redo BIG;
                }

                elsif (  $last_ext eq "c"   || 
                         $last_ext eq "C"   ||
                         $last_ext eq "cpp" ||
                         $last_ext eq "CPP" ||
                         $last_ext eq "cc"  ||
                         $last_ext eq "CC"  ||
                         $last_ext eq "cxx" ||
                         $last_ext eq "CXX" ||
                         $last_ext eq "h"   ||
                         $last_ext eq "H"      ) {

                    myprint "$f: $last_ext is a source file, ADDING\n";
                    copy ("$f", "$idDropBox/$srcdir/$uname");
                    #mysystem ("g++ -E $f > $idDropBox/$srcdir/$uname/$e");
                }

                ## ELSE
                else {
                    # must not be encoded or source
                    #   its probably a doc, pdf
                    myprint "$f: $last_ext isn't encoded, IGNORING\n";
                }
            }
            elsif (-d $f) {
                # directory
                ###########
                #append it into @allfiles, and continue looping
    
                opendir NEW, "$f" or die "can't open $f";
                @newfiles = grep !/^\./, map "$dir/$_", readdir NEW;

                print STDERR "checking dir $f:  appending @newfiles";

                push @allfiles, @newfiles;
            }
            else {
                print STDERR "$f not a file or directory?\n";
                exit (1);
            }
    	}
    	closedir DROPBOX;
    }
    #print STDERR "EXECUTE: moss -d -l cc -c "Your comment here" */*.[Cc][Xx][Xx] */*.[Hh] */*.[Cc] */*.[Cc][Pp][Pp] */*.[Cc][Cc]\n";

    #print STDERR "EXECUTE: moss -d -l cc -c "Your comment here" $idDropBox/$srcdir/*/*.[Cc][Xx][Xx] $idDropBox/$srcdir/*/*.[Hh] $idDropBox/$srcdir/*/*.[Cc] $idDropBox/$srcdir/*/*.[Cc][Pp][Pp] $idDropBox/$srcdir/*/*.[Cc][Cc]\n";
}




sub mysystem {

    my ($arg) = @_;

    if ($VERBOSE) {
        print STDERR "$arg\n";
    }
    return system ("$arg");
}




# prints if at verbose depth
sub myprint {

    my ($arg, $depth) = @_;

    if ($depth eq "") {$depth=0};
 
    if ($VERBOSE >= $depth) {
        print STDERR "$arg";
    }
}

sub testandcreate {

    my ($arg) = @_;

    if (-e "$arg") {
        myprint "$arg/ exists, not created.\n";
    }
    else {
        myprint "$arg/ doesn't exist, created.\n";
        mysystem ("mkdir $arg");
    }
}
