Browse Source

„MailAttachmentParser_nativ.sh“ hinzufügen

master
Stephan Geisler 3 years ago
parent
commit
6cf31d1290
  1. 575
      MailAttachmentParser_nativ.sh

575
MailAttachmentParser_nativ.sh

@ -0,0 +1,575 @@
#!/bin/bash
# /volume1/homes/admin/script/MailAttachmentParser/MailAttachmentParser_nativ.sh
# 2019-08-25 @ geimist
# durchsucht den angegebenen Quellordner nach E-Mails mit Dateianlage, extrahiert und entpackt diese ggf. in den Zielordner mit laufender Nr.
# (eingebette Anlagen (Content-Transfer-Encoding: quoted-printable) können derzeit nicht gesichert werden - war bei .csv bei mir der Fall)
# https://www.synology-forum.de/showthread.html?103185-Mail-an-NAS-und-den-Anhang-verwerten&p=833583&viewfull=1#post833583
#################################
# #
# PARAMETER ANPASSEN #
# #
#################################
MAILDIR="/volume1/homes/admin/.Maildir/cur" # Quellverzeichnis
DESTDIR="/volume1/homes/admin/Mailanlagen/" # Zielverzeichnis
DELDIR="/volume1/homes/admin/.Maildir/.Trash/cur" # Löschverzeichnis
delmail="yes" # "yes" um abgearbeite E-Mails zu löschen
unzipPW="0000" # Kennwort zum entpacken
#################################
# #
# ab hier nichts mehr ändern! #
# #
#################################
# Arbeitsverzeichnis auslesen und hineinwechseln:
OLDIFS=$IFS # ursprünglichen Fieldseparator sichern
APPDIR=$(cd $(dirname $0);pwd)
cd ${APPDIR}
if [ -d "$DESTDIR" ]; then
DESTDIR="${DESTDIR%/}/"
else
mkdir -p "$DESTDIR"
DESTDIR="${DESTDIR%/}/"
fi
mime_inspect()
{
################################################################
#### MIME interface ####
#### analysiert E-Maildateien und gibt sie geordnet aus ####
#### https://gist.github.com/markusfisch/2649043 ####
################################################################
# Parse message in MIME format and create a temporary cache directory
mime_parse()
{
MIME_CACHE=${MIME_CACHE:-`mktemp -d ${BIN}.XXXXXXXXXX`}
# trap 'rm -rf "$MIME_CACHE"; exit' EXIT
local D=$MIME_CACHE
local HEADER=1
local LAST=
local BOUNDARY=
while read
do
REPLY=${REPLY%$CR}
[ "$REPLY" == '.' ] && break
# in mime header
if [ "$HEADER" ]
then
# header closed
[ "$REPLY" ] || {
HEADER=
[ -r "$D/content-type" ] && {
local VALUE
value "`< "$D/content-type"`" \
'[Bb][Oo][Uu][Nn][Dd][Aa][Rr][Yy]='
[ "$VALUE" ] && {
BOUNDARY=$VALUE
echo "$BOUNDARY" > "$D/boundary"
}
}
[ -r "$D/content-disposition" ] && {
local VALUE
value "`< $D/content-disposition`" \
'[Ff][Ii][Ll][Ee][Nn][Aa][Mm][Ee]='
[ "$VALUE" ] && {
echo "$VALUE" >> "$MIME_CACHE/attachments"
echo "$D" >> "$MIME_CACHE/attachments-paths"
}
}
continue
}
local F
if [[ "$REPLY" == [' '$'\t']* ]]
then
[ "$LAST" ] || continue
F=$LAST
else
F=`lower "${REPLY%%:*}"`
LAST=$F
fi
echo ${REPLY#*:} >> "$D/$F"
continue
elif [ "$BOUNDARY" ] && [ "${REPLY:0:2}" == '--' ]
then
[[ "$REPLY" == --$BOUNDARY* ]] && {
[ "$D" == "$MIME_CACHE" ] || D=${D%/*}
if [ "$REPLY" == "--$BOUNDARY--" ]
then
if [ -r "$D/boundary" ]
then
BOUNDARY=`< "$D/boundary"`
else
BOUNDARY=
fi
HEADER=
else
local PART=1
[ -r "$D/parts" ] && {
PART=`< "$D/parts"`
(( ++PART ))
}
echo $PART > "$D/parts"
D="$D/part-$PART"
mkdir "$D" || return 1
HEADER=1
fi
}
continue
fi
echo "$REPLY"$CR >> $D/body
done
}
# Free MIME data structure
mime_free()
{
rm -rf $MIME_CACHE
MIME_CACHE=
}
# Decode possibly encoded message text
#
# @param 1 - message directory
mime_decode_message()
{
local F="$1/body"
[ -r "$F" ] && {
local T=`< "$1/content-type"` CS='cat'
case "$T" in
[Tt][Ee][Xx][Tt]/*)
local VALUE
value "$T" '[Cc][Hh][Aa][Rr][Ss][Ee][Tt]='
[ "$VALUE" ] &&
CS="iconv -f $VALUE -t utf-8"
;;
esac
case "`< "$1/content-transfer-encoding"`" in
*[Qq][Uu][Oo][Tt][Ee][Dd]-[Pp][Rr][Ii][Nn][Tt][Aa][Bb][Ll][Ee]*)
decode_quoted_printable
;;
*[Bb][Aa][Ss][Ee]64*)
base64 -d -i
;;
*)
cat
;;
esac < "$F" | $CS
} 2>/dev/null
}
# Display message with header information
#
# @param 1 - message directory
mime_display_message()
{
# echo headers
{
local H HEADERS=${HEADERS:-from to subject date attachments}
local M=0
# get length of longest header label
{
local L
for H in $HEADERS
do
L=${#H}
(( L > M )) &&
M=$L
done
}
local W=$(( ${WIDTH:-80}-(M+2) ))
for H in $HEADERS
do
local F="$1/$H"
while ! [ -r "$F" ]
do
[ "$F" == "$MIME_CACHE/$H" ] && break
F="$MIME_CACHE/$H"
done
[ -r "$F" ] || continue
local S
if [ "$H" == 'attachments' ]
then
S=`< "$F"`
S=${S//$'\n'/ }
else
S=`decode_encoded_word < "$F"`
fi
local N L=${#S} LABEL=$H
for (( N = 0; N < L; N += W ))
do
printf "%-${M}s %-${W}s\n" "$LABEL" "${S:$N:$W}"
LABEL=
done
done
[ "$H" ] && echo
}
mime_decode_message "$1"
}
# Returns true if content type is text
#
# @param 1 - file with content type
mime_content_is_text()
{
case "`< "$1"`" in
*[Tt][Ee][Xx][Tt]/[Pp][Ll][Aa][Ii][Nn]*|\
*[Tt][Ee][Xx][Tt]/[Hh][Tt][Mm][Ll]*)
return 0
;;
esac 2>/dev/null
return 1
}
# Traverse message tree to find message text
#
# @param 1 - directory in MIME tree
# @param 2 - callback function
mime_find_message()
{
(( $# < 2 )) && return 1
local TYPE=0
case "`< "$1/content-type"`" in
*[Mm][Uu][Ll][Tt][Ii][Pp][Aa][Rr][Tt]/[Aa][Ll][Tt][Ee][Rr][Nn][Aa][Tt][Ii][Vv][Ee]*)
TYPE=1
;;
*[Mm][Uu][Ll][Tt][Ii][Pp][Aa][Rr][Tt]/[Dd][Ii][Gg][Ee][Ss][Tt]*)
TYPE=2
;;
esac 2>/dev/null
local N PARTS=`< "$1/parts"`
for (( N=1; N < PARTS; ++N ))
do
local P="$1/part-$N"
[ -r "$P/body" ] &&
mime_content_is_text "$P/content-type" && {
$2 "$P"
(( TYPE == 2 )) || return 0
}
(( TYPE == 2 )) && return 0
[ -r "$P/parts" ] && mime_find_message "$P" "$2" && return 0
done
return 1
}
# Echo message from MIME data structure
#
# @param 1 - callback function (optional)
mime_message()
{
local C=${1:-mime_display_message}
[ -r "$MIME_CACHE/parts" ] &&
mime_find_message "$MIME_CACHE" $C &&
return
[ -r "$MIME_CACHE/content-type" ] && {
mime_content_is_text "$MIME_CACHE/content-type" ||
return
}
$C "$MIME_CACHE"
}
##############################################################################
#### Encoding/Decoding
##############################################################################
# Decode quoted-printable-encoded stream
decode_quoted_printable()
{
local C=0 EOF=0
while (( ! EOF ))
do
read -d '=' || EOF=1
(( C )) &&
if [[ $REPLY == [$'\r'$'\n']* ]]
then
REPLY=${REPLY:1}
else
printf \\x"${REPLY:0:2}"
REPLY=${REPLY:2}
fi
echo -n "$REPLY"
C=1
done
}
# Decode MIME encoded-word syntax
decode_encoded_word()
{
while read
do
while [[ $REPLY == *'=?'* ]]
do
echo -n ${REPLY%%'=?'*}
local A=${REPLY#*'?='} V=${REPLY#*'=?'}
V=${V%%'?='*}
local P=( ${V//\?/ } )
if (( ${#P[@]} == 3 ))
then
case "${P[1]}" in
[Qq])
echo -n "${P[2]}" | decode_quoted_printable
;;
[Bb])
echo -n "${P[2]}" | base64 -d -i
;;
esac | iconv -f "${P[0]}" -t utf-8
else
echo -n $V
fi
REPLY=$A
done
echo -n $REPLY
done
}
which iconv &>/dev/null || iconv() {
cat
}
which base64 &>/dev/null || {
echo 'error: base64 not found!' >&2
echo 'Either install it or get this fallback implementation:' >&2
echo 'https://gist.github.com/2648733' >&2
exit 1
}
##############################################################################
#### String auxiliaries
##############################################################################
# Make string lower case
#
# @param 1 - some string
if [ $BASH_VERSINFO ] && (( ${BASH_VERSINFO[0]} > 3 ))
then
lower()
{
echo "${1,,}"
}
else
lower()
{
echo "$1" | tr '[:upper:]' '[:lower:]'
}
fi
# Find a key/value pair in the given string and set VALUE accordingly
#
# @param 1 - string
# @param 2 - pattern of key
value()
{
[[ "$1" == *$2* ]] || {
VALUE=
return
}
VALUE=${1#*$2}
local QUOTE="${VALUE:0:1}"
case "$QUOTE" in
'"'|"'")
;;
*)
QUOTE=
;;
esac
if [ "$QUOTE" ]
then
VALUE=${VALUE:1}
VALUE=${VALUE%%$QUOTE*}
else
VALUE=${VALUE%% *}
fi
}
##############################################################################
#### Features
##############################################################################
# Manually check data structure
#
# @param 1 - message file
inspect()
{
[ -r "$1" ] || {
echo "error: file $1 not found" >&2
return 1
}
echo "(unpacking \"$1\")"
mime_parse < "$1" &&
cd "$MIME_CACHE" && \
ls && \
PS1='inspect> ' bash && \
cd ..
# mime_free
}
# Dump message text
#
# @param 1 - message file
dump()
{
mime_parse < "$1" &&
mime_message
# mime_free
}
##############################################################################
#### Command processing
##############################################################################
# Process arguments
#
# @param ... - arguments
mime()
{
(( $# < 1 )) && {
cat <<EOF
usage: ${BIN} [-di] FILE...
d dump message (default)
i inspect message tree
EOF
return
}
local F ACTION=dump
for F in "$@"
do
case "$F" in
-i)
ACTION=inspect
continue
;;
-d)
ACTION=dump
continue
;;
-*)
echo "error: unkown flag '$F'" >&2
return
;;
esac
$ACTION "$F"
done
}
#readonly BIN=${0##*/}
BIN=${0##*/}
#readonly CR=$'\r'
CR=$'\r'
mime "$@"
}
IFS=$'\012'
for i in $(find "$MAILDIR" -type f)
do
IFS=$OLDIFS
filename=$(basename "$i")
if ( cat "$i" | grep -q "base64" ) && ( cat "$i" | egrep -q "attachment" ) ; then # prüfen, ob "base64" und "attachment" in der Mail vorkommen
echo "verarbeite: $i"
mime_inspect "$i" > /dev/null
mkdir "${APPDIR}/$MIME_CACHE/decoded/"
rowid=0
while read j # Quelle zeilenweise einlesen
do
((rowid+=1))
echo -n " gefundene Anlage: $j "
base64log=$(base64 -di "$(sed -n "${rowid}p" "${APPDIR}/$MIME_CACHE/attachments-paths")/body" > "${APPDIR}/$MIME_CACHE/decoded/$j")
# check Extension / ggf. entpacken
if echo "${APPDIR}/$MIME_CACHE/decoded/$j" | egrep -q "*.7z|*.zip"; then
echo "(wird entpackt)"
7z e "${APPDIR}/$MIME_CACHE/decoded/$j" -o"${APPDIR}/$MIME_CACHE/decoded/" -p${unzipPW} -aou > /dev/null
rm "${APPDIR}/$MIME_CACHE/decoded/$j"
else
echo -e
fi
# nach Zielordner verschieben mit Zähler je Extension:
IFS=$'\012'
for d in $(find "${APPDIR}/$MIME_CACHE/decoded/" -type f)
do
IFS=$OLDIFS
name_d=$(basename "$d")
fileextension="${name_d##*.}"
name_d="${name_d%.*}"
count=$(ls -t "${DESTDIR}" | egrep -o "^$name_d.*.$fileextension$" | wc -l)
decfilename="${DESTDIR}${name_d}_(${count}).${fileextension}"
mv "$d" "$decfilename"
echo " Zieldatei: ${name_d}_(${count}).${fileextension}"
done
done < "${APPDIR}/$MIME_CACHE/attachments"
# Quelldatei löschen:
if [ $delmail = "yes" ]; then
echo " Quelldatei wird nach $DELDIR verschoben"
mv "$i" "$DELDIR"
fi
# Temp löschen:
mime_free
echo -e
fi
done
Loading…
Cancel
Save