#!/bin/bash

# CRYPTNOTE for Linux
# Author: Didier Staudenmann
version=1.0.1
versiondate=2012-07-25
# Auto-opening crypted file in an installed or existing editor, cli or gui editor.
# Encrypts and removes the clear file inside itself each time the editor saves it.
# Like Locknote for Windows, but for Linux and probably less secure cause the
# clear content is temporarly written on filesystem. When opening in a new tab,
# the clear file check process will run until every tab of the editor are closed.
# This software comes with absolutely no warranty of any kind. Backup your data !

# TODO swap files. one check process for all files
# ./cryptnote --log=cryptnote.log 2>>cryptnote.log # logs and errors in same file
# kill -9 $(ps aux | grep ' /bin/bash .*cryptnote' | grep -v grep | awk '{print $2}') # kills check processes if not renamed

# DEFAULTS ########################################################################################
# increase maxloadtime and decreasetime if the load fail
parano="" # false
slow="" # false
maxworktime=500 # not less than 1 ! minutes. time max to look for a change, not limit if parano. if parano, time to look for a leecher
checktime=2 # sleep time for a file existence check iteration
maxloadtime=5 # not less than 1 ! seconds without process state change before assuming editor has loaded or before stopping waiting for pid if the filelock isn't detected (load is too fast in a new tab)
decreasetime=2 # not less than 1 ! seconds of cpu decrease before assuming editor has loaded if the filelock isn't detected ...
deltacputreshold=4 # not less than 1 ! minimale charge difference for significant cpu change
nonsignificanttime=1 # not less than 1 ! seconds with no significant cpu charge change before assuming charge is constant
clieditors="vi vim edit pico nano ed joe diakonos less" # less leaves the clear file on disk during display
guieditors="leafpad scite gedit scribes medit xedit kedit kate tea geany gphpedit gvim"

# FUNCTIONS #######################################################################################

function printusage {
    echo "Usage : $selfname [--help] [--file=<FILE>] [--editor=<EDITOR>]"
    echo "                  [--mode=gui|cli] [--slow] [--parano]"
    echo "                  [--log=<LOGFILE>]"
    echo ""
    echo "Options :"
    echo "    --file          Use anoter file than $selfname"
    echo "    --editor        Use an explicit editor"
    echo "    --mode          gui : for asynchrone editors in a window"
    echo "                    cli : for synchrone editors in a terminal"
    echo "    --slow          If an editor fail to load the file, use this option"
    echo "                    (file so big, gui so slow or editor so heavy)"
    echo "    --parano        Kills others file users and check for leechers after"
    echo "                    the editor is closed. If an editor fail to load the"
    echo "                    file, or when launching a wrapped editor don't use"
    echo "                    this option"
}

function printhelp {
    echo "Cryptnote for Linux"
    echo "Version $version $versiondate"
    echo "Author: Didier Staudenmann"
    echo ""
    echo "Auto-opening crypted file in an installed or existing editor, cli or gui editor."
    echo "Encrypts and removes the clear file inside itself each time the editor saves it."
    echo "Like Locknote for Windows, but for Linux and probably less secure cause the"
    echo "clear content is temporarly written on filesystem. When opening in a new tab,"
    echo "the clear file check process will run until every tab of the editor are closed."
    echo "This software comes with absolutely no warranty of any kind. Backup your data !"
    echo ""
    printusage
    echo "    --log           Signs in file :"
    echo "                    + or - : increasing load time"
    echo "                    .      : checking clear file existence"
    echo "                    x or / : checking leechers"
    echo "                    #      : checking new editor pid"
    echo "                    ?      : editor pid not found"
}

function log {
    if [[ "$logfile" != "" && "$1" == "-n" ]] ; then
        echo -n $2 >> $logfile
    else
        if [ $logfile ] ; then echo -n $(date +"%H:%M:%S")" " >> $logfile ; echo $* >> $logfile ; fi
    fi
}

function morestatetime {
    statestarttime=$(date +%s)
    deltasign=""
    let maxstatetime=statestarttime+maxloadtime
    let maxdecreasetime=statestarttime+decreasetime
    log -n "+-"
}

function setstatspid {
    if [[ "$statspid" == "" && "$editorpid" != "" ]] ; then statspid=$editorpid ; fi
    if [[ "$statspid" == "" ]] ; then
        log -n "#"
        stats=$(ps aux | grep "$editorname $tmpclr" | grep -v "grep $editorname $tmpclr")
        changereason="commandline"
    else
        stats=$(ps u $editorpid | sed 1d)
    fi
    if [[ "$stats" == "" ]] ; then
        stats=$(ps aux | grep "$tmpclr" | grep -v "grep $tmpclr")
        changereason="filename"
    fi
    if [[ "$stats" == "" && "$instancesbefore" != "" ]] ; then
        for instance in $instancesbefore ; do
            if [[ "$stats" == "" ]] ; then
                stats=$(ps u $instance | sed 1d)
                changereason="instance"
            fi
        done
    fi
    statspid=$(echo $stats | awk '{print $2}')
}

function stats { # doesn't modify editor pid
    setstatspid
    state=$(echo $stats | awk '{print $8}')
    cpu=$(echo $stats | awk '{print $3}' | sed 's/\.//' | sed 's/^0\([0-9]\)$/\1/')
    if [[ "$init" == "" ]] ; then init=$cpu ; fi
    if [[ "$state" != "$previousstate" ]] ; then # state changed (starting, working or becoming idle)
        morestatetime
    fi
    if [[ "$cpu" == "" ]] ; then
        if [[ "$editorpid" == "" ]] ; then log "unknown editorpid" ; fi
    else
        let deltacpu=cpu-previouscpu
        deltaabs=$(echo $deltacpu | sed 's/-//')
        if [[ $deltacpu == "0" || "$deltacpu" == "" || "$deltaabs" -lt "$deltacputreshold" ]] ; then
            if [[ "$deltacpu" != "" ]] ; then
                if [[ $(date +%s) -gt "$maxnonsignificanttime" ]] ; then
                    deltasign=0
                    storedprevious=$previoussign # for logging only
                    previoussign=$deltasign
                fi
            fi
        else
            let maxnonsignificanttime=$(date +%s)+nonsignificanttime
            deltasign=$(echo $deltacpu | cut -c1 | sed 's/[1-9]/+/')
            if [[ "$deltasign" == "+" || "$previoussign" == "" || "$previoussign" == "+" ]] ; then
                let maxdecreasetime=$(date +%s)+decreasetime
                log -n "-"
            fi
            storedprevious=$previoussign # for logging only
            previoussign=$deltasign
        fi
        if [[ "$deltasign" == "+" || "$deltasign" == "-" ]] ; then lastchange=$deltasign ; fi
        if [[ "$cpu" -gt "$maxcpu" ]] ; then maxcpu=$cpu ; fi
        if [[ $logfile && ( "$previousstate" != "$state" || "$previouscpu" != "$cpu" || "$storedprevious" != "$deltasign" ) ]] ; then
            if [[ "$statspid" == "$editorpid" ]] ; then
                editorstr="v ($editorpid)"
            else
                editorstats=$(ps u $editorpid | sed 1d)
                if [[ "$editorstats" == "" ]] ; then
                    editorstr="x ($editorpid died)"
                else
                    editorcpu=$(echo $editorstats | awk '{print $3}' | sed 's/\.//' | sed 's/^0\([0-9]\)$/\1/')
                    editorstate=$(echo $editorstats | awk '{print $8}')
                    editorstr="x ($editorpid|$editorstate|$editorcpu)"
                fi
            fi
            log "$statspid$editorstr state=$state cpu=$cpu/$maxcpu ($deltacpu) $deltasign fusers=$fileusers"
        fi
    fi
    previousstate=$state
    previouscpu=$cpu
}

function killleechers { # kills but doesn't remove, fileusers should be already computed and parano tested
    log -n "x"
    if [[ "$fileusers" != "" && "$fileusers" != "$editorpid" ]] ; then
        leechers=$(echo $fileusers | sed "s/$editorpid//")
        echo "killing another process than $editorpid using $tmpclr : $leechers" >> /dev/stderr
        ps u $fileusers >> /dev/stderr
        kill -9 $leechers
        stopreason=leeched
    fi
}

function removeclearfile {
    if [[ -e $tmpclr ]] ; then
        log "removing clear file"
        rm -f $tmpclr
        let maxchecktime=$(date +%s)+maxworkseconds
    fi
}

function killfileusers { # kills but doesn't remove
    log -n "/"
    if [[ "$fileusers" == "" ]] ; then
        fileusers=$(fuser $tmpclr 2> /dev/null | sed 's/ //g')
    fi
    if [[ "$fileusers" != "" ]] ; then
        log "killing file users $fileusers"
        ps u $fileusers >> /dev/stderr
        kill -9 $fileusers
        stopreason=leeched
        leechers=$fileusers
    fi
}

function waitforlockrelease { # and kills leechers or set pid, fileusers should be already computed
    log "wait for lock release fileusers=$fileusers editorpid=$editorpid"
    if [[ "$lockdetected" == "" ]] ; then
        lockdetected=$fileusers
    fi
    while [[ "$fileusers" != "" ]] ; do
        if [[ "$editorpid" == "" ]] ; then
            editorpid=$fileusers
            editorname=$(ps u $fileusers | sed 1d | awk '{print $11}')
            log "new editor pid from file users : editopid=$editorpid editorname=$editorname"
        fi
        if [ ! $slow ] ; then killleechers ; fi
        fileusers=$(fuser $tmpclr 2> /dev/null | sed 's/ //g')
        if [ $logfile ] ; then stats ; fi
    done
}

function checkfileexistence { # and save it if has changed
    if [[ "$fileusers" == "" ]] ; then
        fileusers=$(fuser $tmpclr 2> /dev/null | sed 's/ //g')
    fi
    if [[ $parano && "$editorpid" != "" ]] ; then killleechers ; fi
    log -n "."
    if [ -e $tmpclr ] ; then
        log "$tmpclr exists, fileusers=$fileusers"
        while [[ "$fileusers" != "" ]] ; do
            waitforlockrelease
        done
        # test if changed
        newhash=$(md5sum $tmpclr)
        if [[ "$hash" == "$newhash" ]] ; then
            log "no change, removing clear file"
            rm -f $tmpclr 2>/dev/null
        else
            # encrypt and remove
            log "encrypting"
            openssl enc -$cipher -e -out $tmpcry -in $tmpclr $openssloptions
            removeclearfile
            crysize=$(wc -c $tmpcry 2> /dev/null)
            if [[ "$crysize" == "0" || "$crysize" == "" ]] ; then
                echo "Error : no crypted content, file not saved" >> /dev/stderr
            else
                line=$(grep -n "^$begintag$" "$selfpath" | cut -d: -f1)
                # include between tags below
                head -n $line $selfpath > $tmpself
                cat $tmpcry >> $tmpself
                echo $endtag >> $tmpself
                mv $tmpself $selfpath
                chmod u+x $selfpath
                log "content saved, removing tmp crypted file"
                rm -f $tmpcry
            fi
            hash=$newhash
        fi
        if [ $logfile ] ; then
            stats
            if [[ "$stopreason" != "" ]] ; then
                if [ ! $parano ] ; then text=" during max $maxworktime minutes" ; fi
                if [[ "$editorpid" != "" ]] ; then text="$text or till editor $editorpid is closed" ; fi
                log "looking for clear file$text"
            fi
        fi
        let maxchecktime=$(date +%s)+maxworkseconds
    fi
}

function testtime {
    if [[ $(date +%s) -gt "$maxstatetime" ]] ; then
        log "no lock detected after maxloadtime"
        stopreason=maxloadtime
    fi
    if [[ ( "$deltasign" == "-" || "$deltasign" == "0" ) && "$lastchange" == "-" && $(date +%s) -gt "$maxdecreasetime" ]] ; then
        log "no lock detected after decreasetime"
        stopreason=decreasetime
    fi
}

function waitforeditor { # fileusers should be already computed FIXME file too big for maxloadtime or too small to detect fuser TODO test many instances, instances closed...
    starttime=$(date +%s)
    let "maxstatetime=$inittime+$maxloadtime"
    previouscpu=0
    maxcpu=0
    while [[ $stopreason == "" ]] ; do
        fileusers=$(fuser $tmpclr 2> /dev/null | sed 's/ //g')

        if [[ -e "$pidfile" && "$guipid" != "" ]] ; then
            guipid=$(cat $pidfile 2>/dev/null)
            log "removing pid file"
            rm -f $pidfile
            if [[ "$editorpid" == "" ]] ; then
                editorpid=$guipid
                log "new editorpid=$editorpid from gui pid file"
                if [ $logfile ] ; then ps u $editorpid | sed 1d >> $logfile ; fi
            else
                log "gui pid $guipid found in file, but editorpid $editorpid already set, fileusers=$fileusers"
                if [[ $parano && "$guipid" != "$editorpid" ]] ; then
                    log "killing $guipid and $editorpid"
                    ps u $editorpid | sed 1d >> /dev/stderr
                    kill -9 $editorpid
                    ps u $guipid | sed 1d >> /dev/stderr
                    kill -9 $guipid
                    stopreason=incoherence
                    killfileusers
                    removeclearfile
                fi
            fi
        fi

        if [[ "$fileusers" != "" ]] ; then # loading
            log "lock detected: $fileusers, loading"
            stopreason=loaded
            waitforlockrelease # can change stopreason to leeched
        fi

        stats
        if [[ "$editorpid" == "" && "$statspid" != "" && ! $parano ]] ; then
            editorpid=$statspid
            log "new editorpid=$editorpid from stats ($changereason)"
        fi

        if [[ "$stopreason" == "" ]] ; then
            if [[ "$state" == "" ]] ; then
                if [[ "$editorpid" == "" ]] ; then # editorpid still unknown
                    testtime

                else # process has died, killed, closed early, gui wrapped or new tab ?
                    instancesremaining=$(ps aux | grep $editorname | grep -v "grep $editorname" | awk '{print $2":"$11}' | grep "^[0-9][0-9]*:$editorname$" | cut -d: -f1 | tr '\n' ' ' | sed 's/ $//')
                    countremainings=$(echo $instancesremaining | wc -w)
                    log "process $editorpid has died, instancesremaining=$instancesremaining"

                    if [ $parano ] ; then # new tab or gui wrapper forbidden
                        echo "editor with pid $editorpid terminated abruptly" >> /dev/stderr
                        stopreason=terminated

                    else
                        if [[ "$countbefore" == "0" && "$countremainings" == "0" ]] ; then # look for a gui editor wrapped
                            if [[ "$mode" == "cli" ]] ; then
                                echo "editor with pid $editorpid closed early" >> /dev/stderr
                                 stopreason=closedearly
                            else # looking for an gui editor wrapped
                                testtime
                            fi
                        else
                            if [[ "$instancesremaining" == "$instancesbefore" && "$countremainings" == "1" ]] ; then # look for a new tab, already loaded or not already ?
                                log "process $editorpid has died, one instance of $editoname before launch, using $instancesbefore"
                                editorpid=$instancesbefore
                                morestatetime

                            else
                                if [[ "$countremainings" == "0" ]] ; then
                                    echo "editor has died, $instancesbefore instances closed" >> /dev/stderr
                                    stopreason=terminated
                                else
                                    echo "incoherent number of editor instances before=$instancesbefore now=$instancesremaining" >> /dev/stderr
                                    stopreason=incoherence
                                fi
                            fi
                        fi
                    fi
                fi
            else # still alive,lock not detected
                testtime
                if [ $parano ] ; then killleechers ; fi
            fi
        fi
    done
    if [ $logfile ] ; then
        stoptime=$(date +%s)
        let loadtime=stoptime-starttime
        let launchtime=stoptime-inittime
        let loadremaining=maxstatetime-stoptime
        let decreaseremaining=maxdecreasetime-stoptime
        log "stopreason=$stopreason launchtime=$launchtime loadtime=$loadtime loadremaining=$loadremaining decreaseremaining=$decreaseremaining"
    fi
}

function checkrunning {
    running=$(ps $editorpid | sed 1d | awk '{print $1}')
    if [[ "$editorpid" == "" || "$running" == "" ]] ; then
        log "editor $editorname $editorpid has died"

        if [ $parano ] ; then
            killfileusers
            removeclearfile
            running=""
        else
            setstatspid
            if [[ "$statspid" != "" ]] ; then
                editorpid=$statspid
                log "new editorpid=$editorpid from stats ($changereason)"
            fi
        fi
    fi
    if [[ "$editorpid" == "" ]] ; then
        log -n "?"
        running="?"
    else
        running=$(ps $editorpid | sed 1d | awk '{print $1}')
    fi
}

function lookforleechers {
    killfileusers
    removeclearfile
    log "waiting for leechers during max $maxworktime minutes or till a leecher is killed"
    let maxchecktime=$(date +%s)+maxworkseconds
    leechers=""
    while [[ "$leechers" == "" && $(date +%s) -lt "$maxchecktime" ]] ; do
        sleep $checktime
        killfileusers
        removeclearfile
        setstatspid
        if [[ "$statspid" != "" ]] ; then
            log "killing leecher $statspid"
            kill -9 $statspid
        fi
    done
    log "end of leechers process"
}

function checkoption {
    if [[ "$1" != "" ]] ; then
        optionstr=$1
        hastoshift=1
        if $(echo $optionstr | grep = >/dev/null 2>&1) ; then
            option=$(echo "$optionstr" | cut -d= -f1)
            value=$(echo "$optionstr" | cut -d= -f2-)
        else
            option=$optionstr
            value=$2
            hastoshift=0
        fi
        if [[ "$option" == "--help" ]] ; then showhelp=0 ; return 1 ; fi
        if [[ "$option" == "--parano" ]] ; then parano=0 ; return 1 ; fi
        if [[ "$option" == "--slow" ]] ; then slow=0 ; return 1 ; fi

        # next options need a value
        if [[ "$value" == "" || $(echo "$value" | cut -c-2) == "--" ]] ; then
            echo option $option needs a value >> /dev/stderr
            printusage >> /dev/stderr
            exit 1
        fi
        if [[ "$option" == "--editor" ]] ; then editor=$value ; return $hastoshift ; fi
        if [[ "$option" == "--mode" ]] ; then
            if [[ "$value" != "gui" && "$value" != "cli" ]] ; then
                echo "only gui or cli are legal for mode option" >> /dev/stderr
                printusage >> /dev/stderr
                exit 1
            fi
            mode=$value
            return $hastoshift
        fi
        if [[ "$option" == "--file" ]] ; then explicitfile=$value ; return $hastoshift ; fi
        if [[ "$option" == "--maxloadtime" ]] ; then maxloadtime=$value ; return $hastoshift ; fi
        if [[ "$option" == "--log" ]] ; then
            logfile=$value
            echo "" >> $logfile
            return $hastoshift
        fi
        echo unknown option : $option >> /dev/stderr
        printusage >> /dev/stderr
        exit 1
    fi
}

function computekeys {
    md5=$(echo -n $password | md5sum | cut -c-16)
    sha=$(echo -n $password | shasum | cut -c-16)
    for i in $(seq 16) ; do
        char=$(echo $sha | cut -c$i)
        key="$key"0"$char"
        char=$(echo $md5 | cut -c$i)
        iv="$iv"0"$char"
    done
}

function checkeditors { # choose an editor if not set and force mode if known
    checkedmode=$1
    if [[ "$checkedmode" == "cli" && "$editor" == "" && "$EDITOR" != "" ]] ; then editor=$EDITOR ; fi
    checkededitors=$(echo $* | tr ' ' '\n' | grep -v checkeditors | grep -v $checkedmode)
    if [[ "$editor" == "" || "$editorname" != "" ]] ; then
        # check for checkedmode editors, force mode if editor is set and known
        for checkededitor in $checkededitors ; do
            if which $checkededitor > /dev/null ; then
                if [[ "$editor" == "" ]] ; then
                    editor=$checkededitor
                    mode=$checkedmode
                else
                   if [[ "$editorname" == "$checkededitor" ]] ; then
                       log "forcing $checkedmode mode for explicit editor $editor"
                       mode=$checkedmode
                   fi
                fi
            fi
        done
    fi
}

function decimaldiv { # displays $1 / $2 ( carefull : 0.1 => .0 )
    v=$(echo $1*10/$2 | bc)
    c=$(echo -n $v | wc -c)
    let p=c-1
    r=$(echo $v | cut -c-$p  2>/dev/null | tr '\n' ' ' | sed 's/ //g' ; echo -n "." ; echo -n $v | cut -c$c 2>/dev/null)
    r=$(echo $r | sed 's/\.0$//') # not to merge with precedent line
    if [[ "$r" == "" ]] ; then echo 0 ; else echo $r ; fi
}

# REQUISITES ####################################################################################

selfpath=$0 # for usage
selfname=$(echo $0 | awk -F/ '{print $NF}') # for usage

if checkoption $1 $2 ; then shift ; fi
while shift ; do
    if checkoption $1 $2 ; then shift ; fi
done

if [[ "$showhelp" == "0" ]] ; then
    printhelp
    exit 0
fi

# check for binaries
for binary in openssl md5sum shasum fuser ; do
    if ! which $binary > /dev/null ; then
        echo "$binary not found, run apt-get install $binary" >> /dev/stderr
        exit 1
    fi
done

# check for editors
editorname=$(echo $editor | awk -F/ '{print $NF}') # if explicit editor is set
if [[ "$editor" != "" && "$mode" != "" && "$mode" == "cli" ]] ; then
    # doesn't force mode for gui editors, authorizes synchrone launch for gui editors
    checkeditors cli $clieditors
else
    checkeditors gui $guieditors
    checkeditors cli $clieditors
fi
if [[ "$editor" == "" ]] ; then
    if [[ "$mode" == "" ]] ; then mode=text ; fi
    echo "No $mode editor found. Use --editor option" >> /dev/stderr
    exit 1
fi
editorname=$(echo $editor | awk -F/ '{print $NF}')
if [[ "$mode" == "" ]] ; then
    executable=$(ls -l "$editor" 2>/dev/null | cut -d\  -f1 | grep x)
        if [[ $(which $editor) ]] ; then
            echo "Unknown $editorname mode. Use --mode option" >> /dev/stderr
        else
            if [[ -f $editor && "$executable" == "" ]] ; then
                echo "no execution permission for $editor" >> /dev/stderr
            else
                if [[ -f $editor ]] ; then
                    echo "Unknown $editorname mode. Use --mode option" >> /dev/stderr
                else
                    echo "$editor not found" >> /dev/stderr
                fi
            fi
        fi
    exit 1
fi

# check if using another file
if [[ "$explicitfile" != "" ]] ; then
    selfpath=$explicitfile
else
    selfpath=$0
fi

if [ $slow ] ; then
    let checktime=checktime*2
    let maxloadtime=maxloadtime*2
    let decreasetime=decreasetime*2
fi
if [ $parano ] ; then
    let maxworktime=$maxworktime*2
    checktime=$(decimaldiv $checktime 4)
fi
log "checktime=$checktime maxloadtime=$maxloadtime decreasetime=$decreasetime maxworktime=$maxworktime"
let maxworkseconds=maxworktime*60


# LET'S GO ######################################################################################

selfname=$(echo $selfpath | awk -F/ '{print $NF}')
stamp=$(date +%s)
tmpcry=".$selfname""_cry_""$stamp"
tmpclr=".$selfname""_clr_""$stamp"
tmpself=".$selfname""_slf_""$stamp"
pidfile=".$selfname""_pid_""$stamp"
tag="CRYPTNOTE CONTENT"
begintag="---- BEGIN $tag ----"
endtag="---- END $tag ----"
cipher="aes-128-cbc"

# check file existence
if [ -f $selfpath ] ; then
    log "$selfpath exists"
    # check for existing content
    content=$(awk "/$begintag/,/$endtag/{print}" $selfpath | grep -v "^$begintag$" | grep -v "^$endtag$")
else
    content=""
    log "$selfpath doesn't exist, creating empty file"
    echo $begintag > $selfpath
    echo $endtag >> $selfpath
    chmod u+x $selfpath
fi

if [[ "$content" == "" ]] ; then # empty content, tmp fil will be created
    echo -n "enter new password: "
    read -s password
    echo
    echo -n "re-enter same password: "
    read -s password2
    echo
    if [[ "$password" != "$password2" ]] ; then
        echo "passwords are differents" >> /dev/stderr
        exit 1
    fi
    computekeys
    openssloptions="-a -K $key -iv $iv"

else
    # extract content in temp file
    echo -n "enter password: "
    read -s password
    echo
    awk "/$begintag/,/$endtag/{print}" $selfpath | grep -v "^$begintag$" | grep -v "^$endtag$" > $tmpcry
    computekeys
    openssloptions="-a -K $key -iv $iv"
    log "extracting content in $tmpcry"
    openssl enc -$cipher -d -in $tmpcry -out $tmpclr $openssloptions
    success=$?
    rm -f $tmpcry
    if [ $parano ] ; then killfileusers ; fi # don't remove !
    if [[ "$success" != "0" ]] ; then
        echo "decryption failed" >> /dev/stderr
        removeclearfile
        exit 1
    fi
    hash=$(md5sum $tmpclr)
fi

if [[ "$stopreason" == "leeched" ]] ; then
    lookforleechers & # will remove
    exit 1
fi

# launch check process first even if cli editor
inittime=$(date +%s)
instancesbefore=$(ps aux | grep $editorname | grep -v "grep $editorname" | grep -v $selfpath | awk '{print $2}' | tr '\n' ' ' | sed 's/ $//')
countbefore=$(echo $instancesbefore | wc -w)
log "instancesbefore=$instancesbefore"
if [[ $logfile && $parano ]] ; then ps u $instancesbefore >> $logfile ; fi
{
    editorpid=$(cat $pidfile 2>/dev/null)
    if [[ "$editorpid" != "" ]] ; then
        log "new editorpid=$editorpid from gui pid file, removing pid file"
        if [ $logfile ] ; then ps u $editorpid | sed 1d >> $logfile ; fi
        rm -f $pidfile
    fi

    waitforeditor

    if [ $parano ] ; then
        removeclearfile
    else
        checkfileexistence # file can be saved quickly once editor opened
    fi

    if [ $logfile ] ; then
        let removetime=$(date +%s)-stoptime
        let totaltime=$(date +%s)-inittime
        log "totaltime=$totaltime removetime=$removetime"
        stats
    fi

    if [[ ( "$stopreason" == "terminated" || "$stopreason" == "incoherence" && $parano ) || "$stopreason" == "leeched" ]] ; then
        lookforleechers

    else # look for clear file to encrypt
        checkrunning
        if [ $logfile ] ; then
            stats
            if [ ! $parano ] ; then text=" during max $maxworktime minutes" ; fi
            if [[ "$editorpid" != "" ]] ; then text="$text or till editor $editorpid is closed" ; fi
            log "looking to encrypt clear file$text"
        fi
        let maxchecktime=$(date +%s)+maxworkseconds
        while [[ "$running" != "" && ( $(date +%s) -lt "$maxchecktime" || $parano ) ]] ; do # no time limit if parano
            sleep $checktime
            checkfileexistence
            checkrunning
            if [ $logfile ] ; then stats ; fi
        done

        if [ $parano ] ; then
            lookforleechers # will remove
        else
            checkfileexistence
        fi

        if [ $logfile ] ; then
            instancesafter=$(ps aux | grep $editorname | grep -v "grep $editorname" | grep -v $selfpath | awk '{print $2}' | tr '\n' ' ' | sed 's/ $//')
            countafter=$(echo $instancesbefore | wc -w)
            log "instancesafter=$instancesafter"
            if [[ $parano ]] ; then ps u $instancesafter >> $logfile ; fi
        fi
    fi

    log "end of check process"
} &

# launch editor
log "$mode lauch of editor $editor"
if [[ "$mode" == "cli" ]] ; then
    $editor $editoptions $tmpclr
    log "$editorname closed"
else
    $editor $editoptions $tmpclr & guipid=${!}
    echo "$guipid" > $pidfile
fi

exit 0

# CRYPTED CONTENT ###############################################################################

---- BEGIN CRYPTNOTE CONTENT ----
---- END CRYPTNOTE CONTENT ----
