#!/bin/bash
# $Id: fimgs 1265 2017-06-17 12:44:48Z dezperado $

# (c) 2007-2013 Michele Martone

# This is a modified version of the original fbgs script,by Gerd Knorr
# and is capable of displaying pdf, eps, ps, and dvi files.
# Now enhanced for viewing .cbr and .cbz files :)!
#
# Note : it won't probably work on bash, version < 3.0 because of regular expressions.

# this script wants a temporary directory to stores rendered/wget'ed files
# this directory is named after the process ID

# 20070925	regular expressions failed on some configurations, so were 'cut'.. :-(
# 20090917	TODO: should work with no rar or no unzip
# 20091214	TODO: and options to wget ?
# 20090525	should use -o option to rename files to a known filename before loading them, in the temporary directory.

DIR="${TMPDIR-/var/tmp}/fbps-$$"
#GSRESOLUTION=""
#GSRESOLUTION=${GSRESOLUTION:--r240x240}
GSRESOLUTION=${GSRESOLUTION:-120x120}
shopt  -s nocasematch


# we must have write permissions in that directory
mkdir -p $DIR	|| exit 1

# we want that directory clean after this script execution, no matter what happens
trap "rm -rf $DIR" EXIT

# useless for now :)
# declare -f 

# useless, too
# export -f

# as advised in man which, for mysterious reasons ( C compatible )
which ()
{
	( alias; declare -f ; ) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot $@
}

#export -f which

# checks if the first supplied argument is in the current $PATH
function check_in_path()
{
	local cmd="$1";
	[[ -z "$cmd" ]] && return 0
	[[ -z $(which "$cmd" 2>/dev/null) ]] && return -1
	return 0
}

# output functions
function info()  { echo '  [+]' "$@" 1>&2 ;  }
function einfo() { echo '  [-]' "$@" 1>&2 ;  }
function die() { einfo "ERROR : "$@ 1>&2 ; exit -1 ; }

# our favourite framebuffer viewing program :)
FBI=fim

check_in_path $FBI  || die "no fim in \$PATH"
check_in_path sort  || die "no sort in \$PATH"
check_in_path echo  || die "no echo in \$PATH"
check_in_path find  || die "no find in \$PATH"
check_in_path wget  || die "no wget in \$PATH"
check_in_path gs    || die "no gs (ghostscript) in \$PATH"
check_in_path tar   || die "no tar in \$PATH"
check_in_path basename   || die "no basename in \$PATH"
check_in_path md5sum   || die "no md5sum in \$PATH"
#check_in_path rar   || die "no rar in \$PATH"
#check_in_path unzip || die "no unzip in \$PATH"
#check_in_path scp  || die "no scp in \$PATH"


# parse options
fbiopts="-w"
gsopts="-q"
passwd=""
opt=1

# in this way odd filenames are kept intact, be WARNED
while test "$opt" = "1"
#set -- `getopt "" "$@"`
#while [ ! -z "$1" ]
do
	case "$1" in
#		-l)	gsopts="$gsopts -r100x100"
#			shift
#			;;
#		-xl)	gsopts="$gsopts -r120x120"
#			shift
#			;;
#		-xxl)	gsopts="$gsopts -r150x150"
#			shift
#			;;
#		-q | -a)
#			fbiopts="$fbiopts $1"
#			shift
#			;;
#		-d | -m | -t | -g | -f)
#			fbiopts="$fbiopts $1 $2"
#			shift; shift
#			;;
		# explicit option passing
#		-t)	fbiopts="$fbiopts --no-framebuffer"
#			shift
#			;;
		-r)	GSRESOLUTION="$2";
			shift ; shift
			;;
#		-c)	fbiopts="$fbiopts --execute-commands $2"
#			shift; shift
#			;;
#		-F)	fbiopts="$fbiopts --final-commands $2"
#			shift; shift
#			;;
		-p)	GSPASSWORD="$2"
			shift; shift
			;;
		-m)	shift
cat << EOF
.TH fimgs 1 "(c) 2007-2011 Michele Martone"
.SH NAME
fimgs - poor man's [http://]PostScript/pdf/dvi/cbr/rar/cbz/zip viewer for the linux
framebuffer console
.SH SYNOPSIS
.B fimgs [ {fimgs-options} ] file [-- [{fim-options}]]
.SH DESCRIPTION
.B fimgs  
is a simple wrapper script which takes a PostScript or pdf or .cbr or .rar or .cbz or .zip or .dvi or any of the above prefixed with http:// or https:// or ssh:// as input, renders the pages using ghostscript into a temporary directory and finally calls \fB $FBI\fP to display them.

In case of compressed archives (in zip or rar formats), the images are decompressed into a directory and displayed using \fB fim\fP.
In this latter case, only images contained in the archive will be displayed (no nested archives or pdf's or ps's or dvi's).

The temporary directory name is taken from the \$TMPDIR environment variable. 

.SH OPTIONS
To pass through options to \fB fim\fP, you may specify them after "--".

.B -r {resolution}
Specify resolution for the 'gs' -r option (e.g.: 96x96; default $GSRESOLUTION). 
.TP

.B -m
Dump a man page for fimgs.
.TP

.B -p {password}
Specify password for the 'gs' -p (password) option.
.TP

.B -h
Will display a help message.
.\" Additionally you can specify -l, -xl or -xxl to get the pages
.\" rendered with 100, 120 or 150 dpi (default is 75).
.SH SEE ALSO
fim(1), fimrc(1), gs(1), fbi(1), fbgs(1), bash(1)
.SH AUTHOR
Michele Martone <dezperado _ GUESS _ autistici.org>. 
EOF
			exit;
			;;
		-h)	
			#help text
			echo "$0 [{fimgs-options}] {files} [-- [fim-options]] "
			echo -e "\nNote that any file in {files} may be a (correctly named) :"
			echo -e " PDF (.pdf) file"
			echo -e " Postscript (.ps) file"
			echo -e " TAR (.tar) archive"
			echo -e " BZ2 (.bz2) archive"
			echo -e " GZIP (.gz) archive"
			echo -e " https://  resource (web resource)"
			echo -e " http://  resource (web resource)"
			echo -e "\nNote that you cannot view files named like options (no -- meta-option apply to fimgs)."
			echo -e "\n \`man fimgs\`   will give you more info."
			exit 1
			;;
	        *)	
			[[ "$1" =~ '^-.*' ]] && fbiopts="$fbiopts $1";
			break;;
#		-*)	echo "unknown option: $1"
#			exit 1
#			;;
#		*)	opt=0
#			;;
	esac
#	shift
done
###############################################################################
###############################################################################
##		HANDLING OF CBR AND CBZ ARCHIVES
###############################################################################
UNCBZ="unzip" ; ZOPT="-x '*/*'" # suits for Info-ZIP implementation
UNCBR="rar x"                   # suits for Alexander Roshal's RAR 3.51
UNTAR="tar xf"
UNTGZ="tar xzf"
UNBZ="tar xjf"
#while [[ "$1" != "" ]]
#while [[ "$#" -gt "0" ]]
while test x"$opt" = x"1"
#while shift
do
	f="$1";
	if test x"$f" == x"--" ; then shift; while test "$#" -gt "0" ; do f="$1"; fbiopts="$fbiopts $1" ; shift; done; f=/dev/null  ; fi 
	shift;
	[[ "$f" =~ 'https://' ]] && { fn="$DIR"/"`basename $f`" && wget "$f" -O "$fn" && trap "rm $fn" EXIT ; f="$fn"; }
	[[ "$f" =~ 'http://' ]] && { fn="$DIR"/"`basename $f`" && wget "$f" -O "$fn" && trap "rm $fn" EXIT ; f="$fn"; }
	[[ "$f" =~ 'ssh:' ]] && { bfn="`basename ${f/#ssh:/}`" && fn="$DIR"/"`echo $bfn | sed s/^.*://`" && scp "${f/ssh:/}" "$fn" && trap "rm $fn" EXIT ; f="$fn"; }
	[[ -z "$f" ]] && break ;
	#while [[ ! -f "$f" ]] ; do shift ; [[ "$#" -lt 0 ]] && break 2 ; done
###############################################################################
##		HANDLING OF DVI,PS AND PDF FILES
###############################################################################
#[[ "$f" =~ .dvi$ ]] && f="/tmp/$$.ps" && dvips -q "$f" -o "$f" &&  trap "rm $f ; rm -fR $DIR" EXIT
#[[ -f "$f" ]] || { echo "an option!" ;  fbiopts="$fbiopts $f" ; break ; } # not a file, but an option


[[ "$f" =~ .dvi$ ]] && fbiopts=" -P $fbiopts"
[[ "$f" =~ .pdf$ ]] && fbiopts=" -P $fbiopts"
[[ "$f" =~ .ps$  ]] && fbiopts=" -P $fbiopts"
[[ "$f" =~ .eps$  ]] && fbiopts=" -P $fbiopts"

if ( [[ "$f" =~ .ps$  ]] || [[ "$f" =~ .pdf$  ]] ) || ( [[ "$f" =~ .eps$  ]] || [[ "$f" =~ .dvi$  ]] )
then 

BDIR=''
if check_in_path md5sum
then
	DIRS=$(echo "$f" | md5sum )
	DIRS=${DIRS// /}
	DIRS=${DIRS//-/}
	BDIR="$DIR/$DIRS"
	# this means that giving duplicate input files will overwrite the original render directory...
else
	BDIR="$DIR/"$(basename "$f")
fi
mkdir -p $BDIR  	|| die "failed mkdir $BDIR"
info "rendering $f to $BDIR.."

#this is a workaround for gs's .. bug ..

[[ "$f" =~ "^\.\."  ]] && f="$PWD/$f"

# note : we cannot render gs renderable documents with more than 1000 pages...
gs	-dSAFER -dNOPAUSE -dBATCH			\
	-sPDFPassword="$GSPASSWORD"			\
	-sDEVICE=png256 -r${GSRESOLUTION} -sOutputFile=$BDIR/ps%03d.png	\
	$gsopts						\
	"$f" || die "ghostscript failed rendering!"
# still unused options :
#	-sDEVICE=tiffpack				\
#	-sOutputFile=$DIR/ps%03d.tiff

# tell the user we are done :-)
#echo -ne "\\007"
#echo stuff : `ls -l $DIR`
#echo "contents of $DIR:"
#$FBI $fbiopts -P $DIR/ps*.png
#$FBI $fbiopts -P $DIR/ps*.png 2>/dev/null
#fbi $fbiopts -P $DIR/ps*.tiff
# sanity check
#pages=`ls $DIR/ 2>/dev/null | wc -l`
#if test "$pages" -eq "0"; then
#	echo
#	echo "Oops: ghostscript wrote no pages ($pages)?"
#	echo
#	exit 1
#elif ( ( [[ "$f" =~ \\.cbr$  ]] || [[ "$f" =~ \\.cbz$  ]] ) || ( [[ "$f" =~ \\.rar$  ]] || [[ "$f" =~ \\.zip$  ]] ) || ( [[ "$f" =~ \\.tgz$  ]] || [[ "$f" =~ \\.tar.gz$  ]] ) || ( [[ "$f" =~ \\.tar$  ]] || [[ "$f" =~ \\.tar.bz2$  ]] ) )  && ! [[ "$f" =~ '^http://' ]]
elif ( ( [[ "$f" =~ .CBR$  ]] || [[ "$f" =~ .CBZ$  ]] || [[ "$f" =~ .cbr$  ]] || [[ "$f" =~ .cbz$  ]] ) || ( [[ "$f" =~ .rar$  ]] || [[ "$f" =~ .zip$  ]] ) || ( [[ "$f" =~ .tgz$  ]] || [[ "$f" =~ .tar.gz$  ]] ) || ( [[ "$f" =~ .tar$  ]] || [[ "$f" =~ .tar.bz2$  ]] ) )  && ! [[ "$f" =~ 'http://' ]] && ! [[ "$f" =~ 'https://' ]]
then
# in the case of an archive ...
# an ideal fimgs script would unpack recursively in search for interesting files..


# 20070925 there were problems with '\\.' so i put '.' only :/
[[ "$f" =~ .cbr$    ]] && ( $UNCBR "$f"    "$DIR"  ) 
#[[ "$f" =~ .CBR$    ]] && ( $UNCBR "$f"    "$DIR"  ) 
[[ "$f" =~ .rar$    ]] && ( $UNCBR "$f"    "$DIR"  ) 
[[ "$f" =~ .cbz$    ]] && ( $UNCBZ "$f" $ZOPT -d "$DIR" ) 
#[[ "$f" =~ .CBZ$    ]] && ( $UNCBZ "$f" $ZOPT -d "$DIR" ) 
[[ "$f" =~ .zip$    ]] && ( $UNCBZ "$f" $ZOPT -d "$DIR" ) 
[[ "$f" =~ .tgz$    ]] && ( $UNTGZ "$f" -C "$DIR" ) 
[[ "$f" =~ .tar.gz$ ]] && ( $UNTGZ "$f" -C "$DIR" ) 
[[ "$f" =~ .tar$    ]] && ( $UNTAR "$f" -C "$DIR" ) 
[[ "$f" =~ .tar.bz2$ ]] && ( $UNBZ "$f" -C "$DIR" ) 

# ... but this fimgs script is lazy and it gets satisfied with a bare decompress !

# lone file handling..
#[[ "$?" == 0 ]] || echo "this script is not suited for file $f" 
else
	[[ -f "$DIR/`basename $f`" ]] || cp -- "$f" "$DIR" || die "problems copying $f to $DIR"
fi
#fi
done
# show pages
#fbiopts=
#$FBI $fbiopts -P -- $DIR/* $DIR/*/* $DIR/*/*/* $DIR/*/*/*/* $DIR/*/*/*/*/* $DIR/*/*/*/*/*/* $DIR/*/*/*/*/*/*/*
#echo "options are $fbiopts"

# there should be some filter to avoid feed garbage to fim ... 
find $DIR/ -type f -iname '*.jpg' -or -iname '*.jpeg' -or -iname '*.png' -or -iname '*.gif' -or -iname '*.bmp' -or -iname '*.tiff' | sort -n | $FBI $fbiopts  -- -

# when no framebuffer device is available, we could invoke another console viewer, couldn't we ?
# cacaview $DIR/*

# the old syntax
# $FBI $fbiopts -P  `find $DIR -iname '*.png' -or -iname '*.jpg' -or -iname '*.gif' -or -iname '*.jpeg' -or -iname '*.tiff' -or -iname '*.bmp'`

# or the older one ..
#$FBI $fbiopts -P -- $files

# or the ancient one
#fbi $fbiopts -P $DIR/ps*.tiff


