#!/bin/bash
# Begin dspam-learn

#!- Include shlibs
function include() {

case "$1" in


"common")

# Begin libcommon.sh

include color

[ -n "$exname" ] || exname=$(basename $0)

function gnu_options()
{
    # Quite basic
    for __i in $* ;do
	if [ "$__i"  = '--help' ];then
	    print_help
	    exit 0;
	fi
	if [ "$__i"  = '--version' ];then
	    print_version
	    exit 0;
	fi

    done
};

function print_version()
{
    echo "$exname ver. $version";
};

function print_help()
{
    print_version
    echo "$help";
};

function print_exit()
{
    echo $@;
    exit 1;
};

function print_syntax_error()
{
    [ "$*" ] ||	print_syntax_error "$FUNCNAME: no arguments"
    print_exit "${ERROR}script error:${NORMAL} $@";
};

function print_syntax_warning()
{
    [ "$*" ] || print_syntax_error "$FUNCNAME: no arguments.";
    [ "$exname" ] || print_syntax_error "$FUNCNAME: 'exname' var is null or not defined.";
    echo "$exname: ${WARNING}script warning:${NORMAL} $@";
};

function print_error()
{
    [ "$*" ] || print_syntax_warning "$FUNCNAME: no arguments.";
    [ "$exname" ] || print_exit "$FUNCNAME: 'exname' var is null or not defined.";
    print_exit "$exname: ${ERROR}error:${NORMAL} $@"
};

function print_warning()
{
    [ "$*" ] || print_syntax_warning "$FUNCNAME: no arguments.";
    [ "$exname" ] || print_syntax_error "$FUNCNAME: 'exname' var is null or not defined.";
    echo "$exname: ${WARNING}warning:${WARNING} $@"
};

function print_usage()
{
    [ "$usage" ] || print_error "$FUNCNAME: 'usage' variable is not set or empty."
    echo "usage: $usage"

#    if [ "$_options" != "" ]
#    then	
	

#    fi
}

function invert_list()
{
    newlist=" "
    for i in $*
    do
      newlist=" $i${newlist}"
    done
    echo $newlist;
};

function get_path()
{
    echo $(type -p $1)
};


function depends()
{
    for i in $@
    do
	if ! type $i > /dev/null 2>&1
	then
	   print_error "dependency check : couldn't find '$i' command."
	else
	    path=$(get_path $i)
	    
	    if ! test -z "$path" ; then
		export $i=$path
	    fi
	fi
    done
}

function require()
{
    for i in $@
    do
	if ! type $i > /dev/null 2>&1
	then
	   return 1;
	else
	    path=$(get_path $i)
	    
	    if ! test -z "$path" ; then
		export $i=$path
	    fi
	fi
    done
}

function print_octets ()
{
    [ "$*" ] || print_syntax_error "$FUNCNAME: no arguments.";
    [ "$2" ] && print_syntax_error "$FUNCNAME: too much arguments.";

    [ "$( echo "$1 < 1024" | bc )" == "1" ] && { echo -n "$1 octets"; return 0;}

    kbytes=$(echo "$1 / 1024" | bc );
    [ "$( echo "$kbytes < 1024" | bc)" == "1" ] && { echo -n "$kbytes Ko" ; return 0; }

    mbytes=$(echo "$kbytes / 1024" | bc );
    [ "$( echo "$mbytes < 1024" | bc)" == "1" ] && { echo -n "$mbytes Mo" ; return 0; }
    gbytes=$(echo "$mbytes / 1024" | bc );
    [ "$( echo "$gbytes < 1024" | bc )" == "1" ] && { echo -n "$gbytes Go" ; return 0; }
    tbytes=$(echo "$gbytes / 1024" | bc );
    echo -n "$gbytes To"

}

function checkfile ()
{
    [ "$*" ] || print_syntax_error "$FUNCNAME: no arguments.";
    [ "$3" ] && print_syntax_error "$FUNCNAME: too much arguments.";


    for i in $(echo $1 | sed 's/\(.\)/ /g')
    do
	case "$i" in
		"")
			:
		;;
                "e")
                        if ! [ -e "$2" ]
			then 
	                        echo "'$2' is not found."
        	                return 1
			fi;;
		"f")
			if ! [ -f "$2" ]
			then
				echo "'$2' is not a regular file."
				return 1
			fi;;
		"d")
			if ! [ -d "$2" ]
			then
				echo "'$2' is not a directory."
				return 1
			fi;;
		"r")
	                if ! [ -r "$2" ]
			then
	                        echo "'$2' is not readable."
	                        return 1
			fi;;
                "w")
			if ! [ -w "$2" ]
			then
	                        echo "'$2' is not writable."
	                        return 1
			fi;;
                "x")
                        if ! [ -x "$2" ]
			then
	                        echo "'$2' is not executable/openable."
	                        return 1
			fi;;
		"l")
			if ! [ -L "$2" ]
			then
				echo "'$2' is not a symbolic link."
				return 1
			fi;;
	esac
    done

    return 0;
};


function matches()
{
    [ "$*" ] || print_syntax_error "$FUNCNAME: no arguments.";
    [ "$3" ] && print_syntax_error "$FUNCNAME: too much arguments.";

    #echo "sed s${2}X/g"
    rest="$(echo "$1" | sed "s${2}X/g")"
    
    #echo "$rest";
    if [ "$rest" != "X" ] ;then
	return 1
    else
	return 0
    fi
}


# TODO : make a better search configurability with check-file style option.
function find_conf_file()
{
    [ "$*" ] || print_syntax_error "$FUNCNAME: no arguments.";
    [ "$2" ] && print_syntax_error "$FUNCNAME: too much arguments.";

    poss="~/.$1 ~/.vlfs/$1 "

    [ -d "$VLFS_CONF_DIR" ] && poss="$VLFS_CONF_DIR/$1 $poss"
    [ -d "$VLFS_PREFIX" ] && poss="$VLFS_PREFIX/etc/$1 $poss"

    poss="/etc/$1 /usr/etc/$1 /usr/local/etc/$1 "

    for i in $poss ;do
	n=$(eval echo "$i")
	if [ -f "$n" -a -r "$n" ]; then
	    echo "$n"
	    return 0
	fi
    done

    # return first choice
    for i in $poss ;do
	n=$(eval echo "$i")
	echo "$n"
	return 1
    done
}





# End libcommon.sh

;;

"color")

#!/bin/sh
# Begin libcolor.sh

# If COLUMNS hasn't been set yet (bash sets it but not when called as
# sh), do it ourself

if [ -z "$COLUMNS" ]
then
    # Get the console device if we don't have it already
    # This is ok by the FHS as there is a fallback if
    # /usr/bin/tty isn't available, for example at bootup.

    test -x /usr/bin/tty && CONSOLE=`/usr/bin/tty`
    test -z "$CONSOLE" && CONSOLE=/dev/console

    # Get the console size (rows columns)

    stty size > /dev/null 2>&1
    if [ "$?" == 0 ]
    then
	[ "$CONSOLE" == "/dev/console" ] && SIZE=$(stty size < $CONSOLE) \
                                         || SIZE=$(stty size)

        # Strip off the rows leaving the columns

        COLUMNS=${SIZE#*\ }
    else
	COLUMNS=80
    fi

fi

SIZE_LINE=$COLUMNS
SIZE_ELT=$[$COLUMNS - 30 - 4]
SIZE_INFO=20


COL=$[$COLUMNS - 10]
WCOL=$[$COLUMNS - 30]
SCOL=$[$COLUMNS - 4]
LCOL=$[$COLUMNS - 1]


function ascii_color()
{
    if [ "$1" != "no" ]; then

	SET_COL=$(echo -en "[${COL}G")
	SET_SCOL=$(echo -en "[${SCOL}G")
	SET_WCOL=$(echo -en "[${WCOL}G")
	SET_LCOL=$(echo -en "[${LCOL}G")
	
	SET_BEGINCOL=$(echo -en "[0G")
	
	
	
	NORMAL=$(echo -en "[0;37m")
	RED=$(echo -en "[1;31m")
	GREEN=$(echo -en "[1;32m")
	YELLOW=$(echo -en "[1;33m")
	BLUE=$(echo -en "[1;34m")
	GRAY=$(echo -en "[1;30m")
	WHITE=$(echo -en "[1;37m")
	
	SUCCESS=$GREEN
	WARNING=$YELLOW
	FAILURE=$RED
	NOOP=$BLUE
	ON=$SUCCESS
	OFF=$FAILURE
	ERROR=$FAILURE
	
	ascii_color="yes"
    else

	SET_COL=
	SET_SCOL=
	SET_WCOL=
	SET_LCOL=
	
	SET_BEGINCOL=
	
	
	
	NORMAL=
	RED=
	GREEN=
	YELLOW=
	BLUE=
	GRAY=
	WHITE=
	
	SUCCESS=
	WARNING=
	FAILURE=
	NOOP=
	ON=
	OFF=
	ERROR=

	ascii_color="no"
	
    fi

}

ascii_color "$ascii_color"



# End libcolor.sh

;;

"parse")

#!/bin/sh
# Begin libparse.sh

include common
include color
include pretty

function remove()
{

    depends sed

    content=$(cat -)

    while test "$1"; do
	case "$1" in
	    "comment")
		content=$(echo "$content" | sed 's/\#.*$//g')
		;;
	    "empty-line")
		content=$(echo "$content" | grep -v "^$")
		
		;;
            "trim-lines")
		# TODO : DO NOT WORK WITH TABS !!
		content=$(echo "$content" | sed 's/^ *//g')
		content=$(echo "$content" | sed 's/ *$//g')
		;;
	    
	esac
	shift
    done
	
   echo "$content";

}



# End libparse.sh

;;

"pretty")

#!/bin/sh
# Begin of libpretty.sh

#
#
#
#
# - print_status
#
#
#



# INCLUDE
include color

#
# === Begin Code
#


# TODO : cutline without counting the colors chars line.
cutline()
{
	usage_string="usage: $FUNCNAME {nbchar}"

        if test "$#" = "0"
        then
                echo $usage_string
                return 1
        fi
	
	__esc_char=$(echo -en "\033\[[0-9]\+;[0-9]\+m")

	__content="$(cat - )"

	__size=$[$1 - 3]

	__size_esc_chars=$(echo -n "$__content" | wc -c )

#	echo "size with esc chars : $__size_esc_chars" >&2
	__size_content=$(echo -n "$__content" | sed "s/$__esc_char//g" | wc -c )
#	echo "size WITHOUT esc chars : $__size_content" >&2

	__size_diff=$[$__size_esc_chars - $__size_content]

#	echo "DIFF : $__size_diff" >&2

	__final_size=$[$__size + $__size_diff]

#	echo "final DIFF : $__final_size" >&2
  

	if [ "$__size_content" -gt "$[$__final_size + 2 ]" ];then
	    test "$ascii_color" != "no" && 
	    __content="$(echo -n "$__content" | cut -c -$__final_size)$GRAY..$NORMAL" ||
	    __content="$(echo -n "$__content" | cut -c -$__final_size).."
	    
	else
	    __content="$(echo "$__content                                                                                                                                                                                                                                                 " | cut -c -$[$__final_size + 2])"
	fi

	echo -en "$__content"
#	echo -en "'$__content'" >&2

}

Title()
{
	usage_string="usage: $FUNCNAME {string}"

        if test "$#" = "0"
        then
                echo $usage_string
                return 1
        fi

	echo -e "

${WHITE}    $*${NORMAL}
"
}


# Limited to 1 line long
Section()
{
	usage_string="usage: $FUNCNAME {string}"

        if test "$#" = "0"
        then
                echo $usage_string
                return 1
        fi

	__content="$(echo -n "$*" | cutline $SIZE_LINE)"
	    echo -e "
${WHITE}$__content${NORMAL}"
	
};

Elt()
{
	usage_string="usage: $FUNCNAME {string}"

        if test "$#" = "0"
        then
                echo $usage_string
                return 1
        fi
	

	__content="$(echo -n "$*" | cutline $SIZE_ELT)"
	__elt=" - $__content"
#	__info="$(echo -n "" | cutline $SIZE_INFO)"

# 	if test -z "$__elt" ;then
# 	else
# 	    echo
# 	fi

	test "$ascii_color" != "no" && echo -n "$SET_BEGINCOL$__elt${NORMAL}"



}

Feed()
{
    usage_string="usage: $FUNCNAME"

    if test "$#" -gt "0"
    then
	echo $usage_string
	return 1
    fi



    [ -z "$__info" ] && __info="$(echo -n "" | cutline $SIZE_INFO)"

    test "$ascii_color" == "yes" && echo ""
    test "$ascii_color" == "no" && echo "$__elt $__info $__status $__char"

    unset __elt
    unset __info
    unset __char
    unset __status
   
};

Feedback()
{
    errorlevel="$?"

    usage_string="usage: $FUNCNAME [{fail-label} [{ok-label}  [{fail-string} [{ok-string}]]]]"

    if test "$#" -gt "5"
    then
	echo $usage_string
	return 1
    fi

    if test "$errorlevel" = "0" ; then
	test  "$4" && print_info "$4"
	test  "$4" && print_status "$2" || print_status success
    else
	test  "$3" && print_info "$3"
	test  "$1" && print_status "$1" || print_status failure
    fi

    Feed 
    return $errorlevel
}

print_info()
{
	usage_string="usage: $FUNCNAME {string}"

        if test "$#" = "0" 
        then
                echo $usage_string
                return 1
        fi

	__content=$(echo -n "$*" | cutline "$SIZE_INFO")

	__info="$__content"
	
	test "$ascii_color" != "no" && echo -n "${SET_WCOL}${GRAY}$__info${NORMAL}"
};

print_info_char()
{
    
    usage_string="usage: $FUNCNAME {string}"

    if test "$#" = "0" 
    then
	echo $usage_string
	return 1
    fi

    __char=$(echo $* | cut -c 1)

    test "$ascii_color" != "no" && echo -n "${SET_LCOL}${WHITE}$__char${NORMAL}"

    
};

set_col()
{

    usage_string="usage: $FUNCNAME {number}"

    if test "$#" != "1" 
    then
	echo $usage_string
	return 1
    fi

    echo -en "\033[${1}G";

};


print_status()
{

	usage_string="usage: $FUNCNAME {success|warning|failure|on|off|noop} {short|long} {string}"


        if test "$#" = "0"
        then
                echo $usage_string
                return 1
        fi


        if test "$2" != "short" && test "$2" != "long" && test "$#" != "1"
        then
		echo "$FUNCNAME: '$2' is a bad second argument, try : short long"
                echo $usage_string
                return 1
        fi


	type_method=$2

	if  test "$#" = "1"  
	then
	    type_method="long"
	fi


        case "$1" in
                success)
			if test "$type_method" = "long" 
			then
			    __status="[${SUCCESS}  OK  ${NORMAL}]"
			else
			    echo -n "${SUCCESS}"
			    shift; shift;
			    echo -n "$*${NORMAL}"
			fi
                        ;;
                warning)
			if test "$type_method" = "long" 
			then
			    __status="[${WARNING} ATTN ${NORMAL}]"
			else
			    echo -n "${WARNING}"
			    shift; shift;
			    echo -n "$*${NORMAL}"
			fi
                        ;;
                failure)
			if test "$type_method" = "long" 
			then
			    __status="[${FAILURE}FAILED${NORMAL}]"
			else
			    echo -n "${FAILURE}"
			    shift; shift;
			    echo -n "$*${NORMAL}"
			fi
                        ;;
		on)
			if test "$type_method" = "long" 
			then
			    __status="[${ON}  ON  ${NORMAL}]"
			else
			    echo -n "${ON}"
			    shift; shift;
			    echo -n "$*${NORMAL}"
			fi
			;;
		off)
			if test "$type_method" = "long" 
			then
			    __status="[${OFF}  OFF ${NORMAL}]"
			else
			    echo -n "${OFF}"
			    shift; shift;
			    echo -n "$*${NORMAL}"
			fi
			;;
		noop)
			if test "$type_method" = "long" 
			then
			    __status="[${NOOP}  NA  ${NORMAL}]"
			else
			    echo -n "${NOOP}"
			    shift; shift;
			    echo -n "$*${NORMAL}"
			fi
			;;


	        *)
			echo "$FUNCNAME: '$1' is a bad first argument."
        	        echo $usage_string
	                return 1
			;;

        esac

    test "$ascii_color" != "no" && echo -n "${SET_COL}$__status"
    return 0
}


# End of libpretty.sh

;; 
*)
   echo "$FUNCNAME: '$1' not found."
   exit 1;;
esac

}

#!- 

include common
include pretty
include parse

version="0.0.6"

usage="$exname
or $exname {ham|spam}"

#
# VARS
#

test "$HOME" || print_error "HOME var not defined";
test "$USER" || print_error "USER var not defined";


if test -z "$DSPAMLEARN_RC" ; then
    DSPAMLEARN_ETC="$HOME/.dspam"
    DSPAMLEARN_RC="$DSPAMLEARN_ETC/dspam-learn.rc /etc/mail/dspam-learn.rc"
fi

#
# QUICK SANITY CHECKS
#

# Check that external programs are accessible 

depends ls grep cat cut touch stat xargs find dspam formail sort uniq

rc_file=""

opt="";
for i in $DSPAMLEARN_RC; do
    opt="$opt $(eval echo $i)"
done

for f in $opt; do
  if checkfile fr "$f" >/dev/null 2>&1; then
      CONFIG="$CONFIG
$("$cat" "$f" | remove comment empty-line trim-lines)"
  fi; 
done

test "$CONFIG" || print_error "config file not found or empty. Looked in '$DSPAMLEARN_RC'..."


# Check specific function of some programs

# ls does accept the --time-style ?
if ! "$ls" --time-style=+date:%Y%m%d%H%M.%S / >/dev/null 2>&1; then
    print_error "'$ls' doesn't support the --time-style argument, please upgrade your coreutils tools."
fi


# -------------------------------------------------------------------------
# FUNCTIONS
# -------------------------------------------------------------------------


#
# CHECK TIME RELATED FUNCTIONS
#

# get_mtime : 
# input : 1 arg : a filename
# output : stdout : mtime of filename
function get_mtime()
{
    echo $("$ls" -l  --time=ctime --time-style=+date:%Y%m%d%H%M.%S -- "$1" | "$xargs" echo | "$cut" -f 6 -d " " | "$cut" -f 2 -d:);
};


# TODO: The "gt" could not work on some systems ? because of too big integers?
function newer_than_cc()
{
    test -z "$1" -o -z "$2" && return 0

    v1="$("$stat" -c %Z "$1" 2>/dev/null)"
    v2="$("$stat" -c %Z "$2" 2>/dev/null)"

    test -z "$v1" -o -z "$v2" && return 0

    [ "$v1" -gt "$v2" ] && return 0 || return 1
}

function newer_than_cm()
{
    test -z "$1" -o -z "$2" && return 1
    [ "$("$stat" -c %Z "$1")" -gt "$("$stat" -c %Y "$2")" ] && return 0 || return 1
}

function newer_than_mm()
{
    test -z "$1" -o -z "$2" && return 1
    [ "$("$stat" -c %Y "$1")" -gt "$("$stat" -c %Y "$2")" ] && return 0 || return 1
}

#
# CONFIG FILE READING FUNCTIONS
#

get_md5_list()
{
    if ! matches "$1" '/\(spam\|ham\)/' ;then
	print_syntax_error "$FUNCNAME : with arguments '$@' should be 'spam' or 'ham'"
    fi
    eval echo $(echo "$CONFIG" | "$grep" ^$1_md5_file -m 1 | "$cut" -f 2- -d " ")
}

get_maildir()
{
    eval echo $(echo "$CONFIG" | "$grep" ^maildir -m 1 | "$cut" -f 2- -d " ")
}

get_timestamp_file()
{
    eval echo $(echo "$CONFIG" | "$grep" ^timestamp_file -m 1 | "$cut" -f 2- -d " ")
}

get_dirs()
{
    if ! matches "$1" '/\(spam\|ham\)/' ;then
	print_syntax_error "$FUNCNAME : with arguments '$@' should be 'spam' or 'ham'"
    fi

    
    opt="";
    for i in $(echo "$CONFIG" | "$grep" ^${1}box | "$cut" -f 2- -d " ");do
	opt="$opt
$(eval echo "$MAILDIR/$i")"
    done

    opt="$(echo "$opt" | "$sort" | "$uniq" )"

    # verify that each opt is directory
    if [ -f "$TIMESTAMP_FILE" ]; then
	for i in $opt ; do
	    type=""
	    for j in $MAILBOXES_FORMAT ;do
	        if is_${j}_newer "$i" "$TIMESTAMP_FILE"; then
		    type=$j
		    break
		fi
	    done
	    test "$type" && echo "$type:$i"
	done
    else
	for i in $opt ; do
	    type=""
	    for j in $MAILBOXES_FORMAT ;do
	        if is_${j} "$i" ; then
		    type=$j
		    break
		fi
	    done
	    test "$type" && echo "$type:$i"
	done
    fi
};

#
# MAIL ACCESS FUNCTIONS
#

MAILBOXES_FORMAT="mbox maildir"

is_maildir()
{
    # Sanity check

    [ -d "$1" ] || return 1
    for __j in "$1/new" "$1/cur" ;do
	[ -d "$__j" ] || return 1
    done

    # Non empty check

    file=$("$find" "$1"  -regex ".*/\(cur\|new\)/.*" \
	-maxdepth 2 \
	-mindepth 2 \
	-type f 2>/dev/null)

    test -z "$file" && return 1
    return 0
}

# $1 is maildir, $2 is TIMESTAMP file
is_maildir_newer()
{
    # Sanity check

    [ -d "$1" ] || return 1
    bad="yes"

    # Sanity + Timestamp check

    for __j in "$1/new" "$1/cur" ;do
	[ -d "$__j" ] || return 1
	newer_than_cm "$__j" "$2" && bad="no"
    done
    test "$bad" = yes && return 1
    
    # Non empty check

    file=$("$find" "$1"  -regex ".*/\(cur\|new\)/.*" \
	-cnewer "$2" \
	-maxdepth 2 \
	-mindepth 2 \
	-type f 2>/dev/null)

    test -z "$file" && return 1
    return 0

}

is_mbox()
{
    # TODO : isn't there a better check for mbox format ?
    [ -f "$1" ] || return 1

    # Non empty check

    "$grep" "^From" "$1" -m 1 >/dev/null 2>&1 && return 0
    return 1
}

# $1 is maildir, $2 is TIMESTAMP file
is_mbox_newer()
{
    # TODO : isn't there a better check for mbox format ?
    [ -f "$1" ] || return 1

    newer_than_mm "$1" "$2" || return 1

    # Non empty check

    "$grep" "^From" "$1" -m 1 >/dev/null 2>&1 && return 0
    return 1
}

# $1 is path, and $2 is function to pipe mail in...
iterate_thru_mail_mbox()
{
    maildir_size="$[$(echo "$MAILDIR" | wc -c) + 1]"
    section_name=$(echo "$1" | "$cut" -c${maildir_size}-)
    "$grep" ^From $1 -m 1 >/dev/null 2>&1 && Section $section_name

    if newer_than_cc "$1" "$newer"; then 
	newer=$1
    fi

    "$cat" "$1" | "$formail" -s "$exname" "$2"
}

# $1 is path, and $2 is function to pipe mail in...
iterate_thru_mail_maildir()
{
    if [ -f "$TIMESTAMP_FILE" ]; then

	   file=$("$find" "$1"  -regex ".*/\(cur\|new\)/.*" \
	                           -cnewer "$TIMESTAMP_FILE" \
                                   -maxdepth 2 \
                                   -mindepth 2 \
                                   -type f 2>/dev/null)
    else
	   file=$("$find" "$1"  -regex ".*/\(cur\|new\)/.*" \
                                   -maxdepth 2 \
                                   -mindepth 2 \
                                   -type f 2>/dev/null)
    fi	

    

    bool2=false
    for i in $file; do

	test $bool2 = "true" || Section "$(basename $(dirname $(dirname $i)))"
	bool2=true

	
	if newer_than_cc "$i" "$newer"; then 
	    newer=$i
	    print_info_char "U"
	else
	    print_info_char " "
	fi

	"$cat" "$i" | "learn_as_$2"
	
    done

};

#
# MAIN FUNCTIONS 
# 

# $* are all in this form : 
#   "maildir:/path/to/courier/dir" with
#    <driver>:<path-to-file>
iterate_thru_mail()
{

    "$touch" "$DSPAMLEARN_SPAM_MD5_LST"
    "$touch" "$DSPAMLEARN_HAM_MD5_LST"

    for k in ham spam;do
	bool1=false
	for l in $(get_dirs $k);do
	    test $bool1 = "true" || Title "Learn $k..." 
	    bool1=true

	    type=$(echo "$l" | "$cut" -f1 -d:)
	    path=$(echo "$l" | "$cut" -f2 -d:)
	    
	    iterate_thru_mail_$type "$path" "$k"
	done
    done
}

# take an arg: learns stdin as mail if its MD5 is not in the list. And has
# not already been classified as Spam.
learn_as_spam()
{
    content=$("$cat" -)

    Elt "Sub: $(echo "$content" | "$grep" ^Subject: -m 1 | "$cut" -f 2- -d " ")"

    md5=$(echo "$content" | md5sum | "$cut" -f1 -d" ")

    if ! "$cat" "$DSPAMLEARN_SPAM_MD5_LST" | "$grep" ^$md5\$ >/dev/null 2>&1 &&
       ! echo "$content" | "$grep" "^X-DSPAM-Result: Spam\$" >/dev/null 2>&1; then
	if echo "$content" | "$grep" "^X-DSPAM-Signature:" >/dev/null 2>&1 ; then

	    print_info "addspam"
	    echo "$content" | "$dspam" --addspam --user "$USER" --stdout >/dev/null 2>&1
	    Feedback warning success "dspam failed" "Innocent->spam"

	else

	    print_info "corpus"
	    echo "$content" | "$dspam" --corpus --addspam --user "$USER" --stdout >/dev/null 2>&1
	    Feedback warning success "dspam failed" "learning as spam"

	fi
	echo "$md5" >> "$DSPAMLEARN_SPAM_MD5_LST"
    else 
	if echo "$content" | "$grep" "^X-DSPAM-Result: Spam\$" >/dev/null 2>&1; then
	    print_info "was Spam"
	    print_status noop
	    Feed
	else
	    print_info "already learnt"
	    print_status noop
	    Feed
	fi
    fi
    return 0
};

# take an arg: learns stdin as mail if its MD5 is not in the list. And has
# not already been classified as Innocent.
learn_as_ham()
{

    content=$("$cat" -)

    Elt "Sub: $(echo "$content" | "$grep" ^Subject: -m 1 | "$cut" -f 2- -d " ")"

    md5=$(echo "$content" | md5sum | "$cut" -f1 -d" ")
 
    if ! "$cat" "$DSPAMLEARN_HAM_MD5_LST" | "$grep" ^$md5\$ >/dev/null 2>&1 &&
       ! echo "$content" | "$grep" "^X-DSPAM-Result: Innocent\$" >/dev/null 2>&1 
    then

	if echo "$content" | "$grep" "^X-DSPAM-Signature:" >/dev/null 2>&1 ; then

	    print_info "falsepositive"
	    echo "$content" | "$dspam" --falsepositive --user "$USER" --stdout  >/dev/null 2>&1
	    Feedback warning success "dspam failed" "Learning as fp"

	else

	    print_info "corpus"
	    echo "$content" | "$dspam" --corpus --user "$USER" --stdout >/dev/null 2>&1
	    Feedback warning success "dspam failed" "Learning as ham"

	fi

	echo "$md5" >> "$DSPAMLEARN_HAM_MD5_LST"
    else 
	if echo "$content" | "$grep" "^X-DSPAM-Result: Innocent\$" >/dev/null 2>&1 ; then
	    print_info "was Innocent"
	    print_status noop
	    Feed
	else
	    print_info "already learnt"
	    print_status noop
	    Feed
	fi
    fi

    return 0

};

# -----------------------------------------------------------------------------
# CODE
# -----------------------------------------------------------------------------

#
# PARSING ARGUMENTS
#

help="
MODE FULL-AUTO:

dspam-learn

     dspam-learn looks in dspam-learn.rc to fetch all the
  mail it has to learn and learn them. 

MODE ONE-SHOT:

dspam-learn {ham|spam}

     dspam looks in dspam-learn.rc and interpret STDIN as one mail
  to learn as ham or spam (depending on the only argument). It'll
  launch dspam accordingly.

If you need more help, perhaps you could try in README or FAQ provided
in the source distribution. You can also mail me at vaab@free.fr"

gnu_options $*

if [ "$#" -gt 1 ];
then
    echo "$exname : doesn't take so much arguments."
    echo "You should try '$exname --help'."
    print_usage
    exit 1;
fi

if [ "$#" = 1 ] && ! matches "$1" '/\(spam\|ham\)/' ;then
    echo "$exname : bad second argument should be ham or spam."
    print_usage
    exit 1;
fi


#
# PARSING CONFIG FILE
#


DSPAMLEARN_HAM_MD5_LST="$(get_md5_list ham)"
DSPAMLEARN_SPAM_MD5_LST="$(get_md5_list spam)"

test -z "$DSPAMLEARN_HAM_MD5_LST" && print_error "No 'ham_md5_list' option in config file ?"
test -z "$DSPAMLEARN_SPAM_MD5_LST" && print_error "No 'spam_md5_list' option in config file ?"


if test -z "$(echo "$CONFIG" | "$grep" ^hambox -m 1 | "$cut" -f 2- -d " ")" ;then
    print_error "No hambox option found in config file !"
fi

if test -z "$(echo "$CONFIG" | "$grep" ^spambox -m 1 | "$cut" -f 2- -d " ")" ;then
    print_error "No spambox option found in config file !"
fi


TIMESTAMP_FILE="$(get_timestamp_file)"

if [ "$#" = 1 ]; then

    if test "$1" = "ham" ;then
	"$touch" "$DSPAMLEARN_HAM_MD5_LST" || 
	print_error "couldn't access $DSPAMLEARN_HAM_MD5_LST";
    fi
    if test "$1" = "spam" ;then
	"$touch" "$DSPAMLEARN_SPAM_MD5_LST" || 
	print_error "couldn't access $DSPAMLEARN_SPAM_MD5_LST";
    fi

    learn_as_$1
    exit "$?"
fi

MAILDIR="$(get_maildir)"

test -z "$MAILDIR" && print_error "No correct maildir option found in config file !"

checkfile dr "$MAILDIR" || print_error "maildir '$MAILDIR' not accessible"

#
# FULL-AUTOMATIC MODE :
#

if [ -f "$TIMESTAMP_FILE" ]; then
    newer="$("$cat" $TIMESTAMP_FILE)";
    if ! [ -f "$newer" ] ; then
	newer=""
    fi
else
    newer="";
fi


# echo "Mail dir is : '$MAILDIR'"
# echo "timestamp_file is : '$TIMESTAMP_FILE'"
# echo "spam_md5_file is : '$DSPAMLEARN_SPAM_MD5_LST'"
# echo "ham_md5_file is : '$DSPAMLEARN_HAM_MD5_LST'"
# echo "spambox is : '$(get_dirs spam)'"
# echo "hambox is : '$(get_dirs ham)'"

iterate_thru_mail  

if [ "$newer" != "" ] ; then
    echo "$newer" > "$TIMESTAMP_FILE" || print_error "couldn't access '$TIMESTAMP_FILE'"
    
# This will update the timestamp file, so that next time we launch dspam-learn,
# it'll look only at file newer than timestamp. (new files or modified files
# since last dspam-learn.)

    "$touch" -m -t $(get_mtime "$newer") "$TIMESTAMP_FILE" || print_error "couldn't access '$TIMESTAMP_FILE'"
fi


# End dspam-learn
