1#!/bin/sh -norc
2#
3# MIMEPARTS.SH
4# Author: "Garen Erdoisa" <scamper@trisk.com>
5# Licence: GNU GPL
6# Last Update: 8/14/2011
7#
8# Synopsis:
9# This /bin/sh custom shell script written on behalf of the SpamBouncer project
10# and as such is donated by the Author to the SpamBouncer project.
11#
12# This software is specifically designed to work in conjuction with and as a part of
13# SpamBouncer 3.0 or higher, it is not intended for any other use.
14#
15# Use of this code with any other software will likely not work without major modifications.
16#
17# For a description of base64 encoding see:
18# RFC 1521 http://www.ietf.org/rfc/rfc1521.txt Para: 5.2
19#
20# Expecting the following exported variables
21# export SED ECHO NL DECODEBASE64 SBLOGLEVEL GREP EGREP SBDIR SPACES_TABS_TO_SPACES MESSAGETMPDIR WC SBPID DATE HOST LOGFILE SBLOGFILE SBHEADERS HASHCOMMAND
22#
23# Expecting the following command line arguments:
24#
25# These are local variables, not global. They don't belong at all in sb-config-default.rc
26# and if you define them there it will have no effect.
27# Don't change these or something will likely break.
28thisfilename=$0
29sourcefilename="$1"
30OUTLINE="$2"
31#PART="$3"
32PART=1
33RECURSELEVEL="$4"
34RECURSELIMIT="$5"
35LOCALBOUNDARY="$6"
36
37# Four /bin/sh functions: splitparts(), greplocalparts(), getlinepairs(), dbecho()
38# are defined by this file.
39#
40# The dot at the begining of the line is diliberate.
41# Don't change it or it will break this script.
42# The dot causes the shell_functions.sh to be read into the current
43# shell environment as if it were a part of this file.
44. ${SBDIR}/functions/shell_functions.sh
45
46# dbecho is a function defined in shell_functions.sh that will only
47# echo the text if the SBLOGLEVEL >= ARG1
48# It's for debugging.
49
50# Debug info
51if ! [ "${OUTLINE}" = "1" ]; then
52	dbecho 7 "Debug[${SBLOGLEVEL}]: [${OUTLINE}]: Recursive entry into file: ${thisfilename}"
53fi
54#dbecho 8 "Debug[${SBLOGLEVEL}]: MESSAGETMPDIR=\"${MESSAGETMPDIR}\""
55#dbecho 8 "Debug[${SBLOGLEVEL}]: sourcefilename=${MESSAGETMPDIR}/${sourcefilename}"
56#dbecho 8 "Debug[${SBLOGLEVEL}]: OUTLINE=${OUTLINE}"
57#dbecho 8 "Debug[${SBLOGLEVEL}]: RECURSELEVEL=${RECURSELEVEL}"
58#dbecho 8 "Debug[${SBLOGLEVEL}]: RECURSELIMIT=${RECURSELIMIT}"
59#dbecho 8 "Debug[${SBLOGLEVEL}]: LOCALBOUNDARY=${LOCALBOUNDARY}"
60
61# Unless exported from the calling process, all other variables should be local to this routine.
62dbecho 8 "Debug[${SBLOGLEVEL}]: Recursion level: ${RECURSELEVEL} of ${RECURSELIMIT}; Outline Level: ${OUTLINE}"
63
64# Outline tracks the current outline level we are at in the parse.
65# dbecho 8 "Debug[${SBLOGLEVEL}]: Outline: \"${OUTLINE}\""
66
67filename="${sourcefilename}"
68LOCALPARTS=0
69LOCALLINEPAIRS=0
70
71# LOCALPARTS
72dbecho 7 "Parsing: ${MESSAGETMPDIR}/${filename} LOCALBOUNDARY=${LOCALBOUNDARY}"
73
74greplocalparts "${MESSAGETMPDIR}/${filename}" "${LOCALBOUNDARY}"
75dbecho 7 "Debug[${SBLOGLEVEL}]: LOCALPARTS=${LOCALPARTS}"
76
77VALIDATEPARTBEGIN=`${ECHO} "${LOCALPARTS}" |${SED} -e '1!d;s/^\([0-9]\{1,\}:\)\(--\)\(.\{1,\}\)$/\2/'`
78VALIDATEPARTENDING=`${ECHO} "${LOCALPARTS}" |${SED} -e '$!d;s/^\([0-9]\{1,\}:--\)\(.\{1,\}\)\(--\)$/\3/'`
79if [ "${VALIDATEPARTBEGIN}" = "--" ] && [ "${VALIDATEPARTENDING}" = "--" ]; then
80	VALIDPART=yes
81else
82	VALIDPART=no
83	dbecho 8 "Debug[${SBLOGLEVEL}]: Mime part was not properly closed. Attempting repair."
84	if ! [ "${VALIDATEPARTENDING}" = "--" ]; then
85		(${CAT} ${MESSAGETMPDIR}/${filename};${ECHO} "";${ECHO} "--${LOCALBOUNDARY}--";${ECHO} "") >>${MESSAGETMPDIR}/${filename}_repair
86	fi
87
88	greplocalparts "${MESSAGETMPDIR}/${filename}_repair" "${LOCALBOUNDARY}"
89	dbecho 7 "Debug[${SBLOGLEVEL}]: repair LOCALPARTS=${LOCALPARTS}"
90	VALIDATEPARTBEGIN=`${ECHO} "${LOCALPARTS}" |${SED} -e '1!d;s/^\([0-9]\{1,\}:\)\(--\)\(.\{1,\}\)$/\2/'`
91	VALIDATEPARTENDING=`${ECHO} "${LOCALPARTS}" |${SED} -e '$!d;s/^\([0-9]\{1,\}:--\)\(.\{1,\}\)\(--\)$/\3/'`
92
93	if [ "${VALIDATEPARTBEGIN}" = "--" ] && [ "${VALIDATEPARTENDING}" = "--" ]; then
94		VALIDPART=yes
95		dbecho 8 "Debug[${SBLOGLEVEL}]: Mime part sucessfully closed. Continuing."
96		${MV} ${MESSAGETMPDIR}/${filename}_repair ${MESSAGETMPDIR}/${filename}
97	else
98		dbecho 8 "Debug[${SBLOGLEVEL}]: Mime part was not properly opened. Repair unsucessful, giving up."
99	fi
100fi
101
102dbecho 8 "Debug[${SBLOGLEVEL}]: OUTLINE=${OUTLINE} VALIDPART=${VALIDPART}"
103if [ "${VALIDPART}" = "yes" ];then
104	# LOCALLINEPAIRS
105	# dbecho 8 "Debug[${SBLOGLEVEL}]: getlinepairs \"${LOCALPARTS}\""
106	getlinepairs "${LOCALPARTS}"
107	dbecho 8 "Debug[${SBLOGLEVEL}]: LOCALLINEPAIRS=${LOCALLINEPAIRS}"
108	#Commented this out because I converted the LOCALLINEPAIRS to be all on one line.
109	#COUNT=`${ECHO} "${LOCALLINEPAIRS}" |grep -En "" |${SED} -nre '$s/^([0-9]+):(.+)$/\1/p'`
110	#dbecho 8 "Debug[${SBLOGLEVEL}]: COUNT=$COUNT"
111	for i in ${LOCALLINEPAIRS}
112	do
113		dbecho 8 "Debug[${SBLOGLEVEL}]: splitparts \"${MESSAGETMPDIR}/MIME_${OUTLINE}\" \"${PART}\" \"$i\""
114		# This function creates the body/header files
115		splitparts "${MESSAGETMPDIR}/MIME_${OUTLINE}" "${PART}" "$i"
116		#Check part header to see if we need to recurse here
117		dbecho 8 "Debug[${SBLOGLEVEL}]: checkpart \"${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.header\""
118		# some boundary tags are quoted.
119		checkpart=`${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.header |\
120			${SED} -e '
121				/^[C][Oo][Nn][Tt][Ee][Nn][Tt]-[Tt][Yy][Pp][Ee]: [Mm][Uu][Ll][Tt][Ii][Pp][Aa][Rr][Tt]\/\(.\{1,\}\);\( \)\?[Bb][Oo][Uu][Nn][Dd][Aa][Rr][Yy]=".\{1,\}"\(;.*\)\?$/!d
122				s/^\([C][Oo][Nn][Tt][Ee][Nn][Tt]-[Tt][Yy][Pp][Ee]: [Mm][Uu][Ll][Tt][Ii][Pp][Aa][Rr][Tt]\/.\{1,\}; \?[Bb][Oo][Uu][Nn][Dd][Aa][Rr][Yy]="\)\([^"]\{1,\}\)\("\)\(;.*\)\?$/\2/
123			'`
124		# some boundary tags are not quoted.
125		# Note: unquoted boundary tags can not contain ; or :
126		if [ "${checkpart}" = "" ]; then
127		  checkpart=`${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.header |\
128			${SED} -e '
129				/^[C][Oo][Nn][Tt][Ee][Nn][Tt]-[Tt][Yy][Pp][Ee]: [Mm][Uu][Ll][Tt][Ii][Pp][Aa][Rr][Tt]\/\(.\{1,\}\);\( \)\?[Bb][Oo][Uu][Nn][Dd][Aa][Rr][Yy]=[^"]\{1,\}\(;.*\)\?$/!d
130				s/^\([C][Oo][Nn][Tt][Ee][Nn][Tt]-[Tt][Yy][Pp][Ee]: [Mm][Uu][Ll][Tt][Ii][Pp][Aa][Rr][Tt]\/.\{1,\}; \?[Bb][Oo][Uu][Nn][Dd][Aa][Rr][Yy]=\)\([^";:]\{1,\}\)\(;.*\)\?$/\2/
131			'`
132		fi
133		# Check for Content-Type headers = text or html or quoted printable
134		# if such parts are found, and are base64 encoded, then decode them.
135		# and/or calculate the sha1 hash of them.
136		# I'm not doing anything with quoted printable or 8bit text at this time.
137		#
138		# Note: For future consideration, test parts that claim 7bit encoding to see if they
139		# are actually 7bit. If not, the encoding tag is lying, which could be a spam indicator.
140		#
141		# Content-Type: text/(plain|html)
142		checkcontentype_text_plain_html=`${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.header |\
143			${SED} -e '
144				/^[C][Oo][Nn][Tt][Ee][Nn][Tt]-[Tt][Yy][Pp][Ee]: [Tt][Ee][Xx][Tt]\/\([Pp][Ll][Aa][Ii][Nn]\|[Hh][Tt][Mm][Ll]\)\(;.*\)\?$/!d
145			'`
146		if ! [ "${checkcontentype_text_plain_html}" = "" ]; then
147			dbecho 8 "Debug[${SBLOGLEVEL}]: checkcontentype_text_plain_html=\"${checkcontentype_text_plain_html}\""
148		fi
149		# Content-Type: application/(.+)
150		checkcontentype_application=`${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.header |\
151			${SED} -e '
152				/^[C][Oo][Nn][Tt][Ee][Nn][Tt]-[Tt][Yy][Pp][Ee]: [Aa][Pp][Pp][Ll][Ii][Cc][Aa][Tt][Ii][Oo][Nn]\/.\{1,\}\(;.*\)\?$/!d
153			'`
154		if ! [ "${checkcontentype_application}" = "" ]; then
155			dbecho 8 "Debug[${SBLOGLEVEL}]: checkcontentype_application=\"${checkcontentype_application}\""
156		fi
157		# Content-Type: image/(.+)
158		checkcontentype_image=`${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.header |\
159			${SED} -e '
160				/^[C][Oo][Nn][Tt][Ee][Nn][Tt]-[Tt][Yy][Pp][Ee]: [Ii][Mm][Aa][Gg][Ee]\/.\{1,\}\(;.*\)\?$/!d
161			'`
162		if ! [ "${checkcontentype_image}" = "" ]; then
163			dbecho 8 "Debug[${SBLOGLEVEL}]: checkcontentype_image=\"${checkcontentype_image}\""
164		fi
165
166		# Content-Transfer-Encoding: base64
167		checkencodingbase64=`${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.header |\
168			${SED} -e '
169				/^[C][Oo][Nn][Tt][Ee][Nn][Tt]-[Tt][Rr][Aa][Nn][Ss][Ff][Ee][Rr]-[Ee][Nn][Cc][Oo][Dd][Ii][Nn][Gg]: [Bb][Aa][Ss][Ee]64\(;.*\)\?$/!d
170			'`
171		if ! [ "${checkencodingbase64}" = "" ]; then
172			dbecho 8 "Debug[${SBLOGLEVEL}]: Found base64 encoding tag in MIME_${OUTLINE}_${PART}.header"
173			checkcontent_disposition_attachment_filename=`${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.header |\
174				${SED} -e '/^[C][Oo][Nn][Tt][Ee][Nn][Tt]-[Dd][Ii][Ss][Pp][Oo][Ss][Ii][Tt][Ii][Oo][Nn]: [Aa][Tt][Tt][Aa][Cc][Hh][Mm][Ee][Nn][Tt].*[; ]\?[Ff][Ii][Ll][Ee][Nn][Aa][Mm][Ee]=.\{1,\}\(;.*\)\?$/!d' |\
175				${SED} -e 's/^\([C][Oo][Nn][Tt][Ee][Nn][Tt]-[Dd][Ii][Ss][Pp][Oo][Ss][Ii][Tt][Ii][Oo][Nn]: [Aa][Tt][Tt][Aa][Cc][Hh][Mm][Ee][Nn][Tt].*[; ]\?[Ff][Ii][Ll][Ee][Nn][Aa][Mm][Ee]=\)\(.\{1,\}\)\(\(;.*\)\?\)$/\2/' |\
176				${SED} -e 's/^\("\)\(.\{1,\}\)\("\)$/\2/'
177			`
178			if ! [ "${checkcontent_disposition_attachment_filename}" = "" ];then
179				dbecho 8 "Debug[${SBLOGLEVEL}]: checkcontent_disposition_attachment_filename=\"${checkcontent_disposition_attachment_filename}\""
180			fi
181			checkcontent_type_name=`${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.header |\
182				${SED} -e '/^[C][Oo][Nn][Tt][Ee][Nn][Tt]-[Tt][Yy][Pp][Ee]: .*[; ]\?[Nn][Aa][Mm][Ee]=.\{1,\}\(;.*\)\?$/!d' |\
183				${SED} -e 's/^\([C][Oo][Nn][Tt][Ee][Nn][Tt]-[Tt][Yy][Pp][Ee]: .*[; ]\?[Nn][Aa][Mm][Ee]=\)\(.\{1,\}\)\(\(;.*\)\?\)$/\2/' |\
184				${SED} -e 's/^\("\)\(.\{1,\}\)\("\)$/\2/'
185			`
186			if ! [ "${checkcontent_type_name}" = "" ];then
187				dbecho 8 "Debug[${SBLOGLEVEL}]: checkcontent_type_name=\"${checkcontent_type_name}\""
188			fi
189		fi
190
191		# Content-Transfer-Encoding: 7bit
192		checkencoding7bit=`${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.header |\
193			${SED} -e '
194				/^[C][Oo][Nn][Tt][Ee][Nn][Tt]-[Tt][Rr][Aa][Nn][Ss][Ff][Ee][Rr]-[Ee][Nn][Cc][Oo][Dd][Ii][Nn][Gg]: \?.*7[Bb][Ii][Tt]\(;.*\)\?$/!d
195			'`
196		if ! [ "${checkencoding7bit}" = "" ]; then
197			dbecho 8 "Debug[${SBLOGLEVEL}]: Found 7bit encoding tag in MIME_${OUTLINE}_${PART}.header"
198			# dbecho 8 "Debug[${SBLOGLEVEL}]: ${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body |${TR} -d \"\000-\177\" |${WC} -c"
199			checkcontent7bit=`${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body |${TR} -d "\000-\177" |${WC} -c`
200			if ! [ "${checkcontent7bit}" = "0" ]; then
201				dbecho 8 "Debug[${SBLOGLEVEL}]: 8bit byte count=${checkcontent7bit} MIME_${OUTLINE}_${PART}.body is not 7bit!"
202				# This code mimics the following for SpamBouncer logging:
203				#  SBLOG="C3N: MIME Part ${OUTLINE}_${PART} claims 7bit encoding but has 8bit content"
204				#  INCLUDERC=${SBDIR}/functions/loglevel.rc
205				# Note the header in the log
206				dbecho 3 "SBNote: MIME Part ${OUTLINE}_${PART} claims 7bit encoding but has 8bit content"
207				if [ "${SBHEADERS}" = "COMPLETE" ] || [ "${SBHEADERS}" = "BRIEF" ]; then
208					# Add the header to the email.
209					${ECHO} "X-SBNote: MIME Part ${OUTLINE}_${PART} claims 7bit encoding but has 8bit content" >>${MESSAGETMPDIR}/sbheaders-created-during-autopsy
210				fi
211			else
212				dbecho 8 "Debug[${SBLOGLEVEL}]: Confirmed: 8bit byte count=${checkcontent7bit} MIME_${OUTLINE}_${PART}.body is 7bit."
213			fi
214		fi
215
216		# This is where we decide what to include in the Message Body Autopsy. The rest will be ignored.
217
218		# Pick up the part header files if any and include them in the autopsy so
219		# SpamBouncer can check the language charset headers, and other Content- headers.
220		if [ -f ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.header ]; then
221			dbecho 7 "Debug[${SBLOGLEVEL}]: Including file: ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.header"
222			${ECHO} "${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.header" >>${MESSAGETMPDIR}/plain_body_files_to_parse.txt
223		fi
224		# If the Content-Type: mime part header claims the part is text/html, then include it in the autopsy. Decode base64 if necessary.
225		if ! [ "${checkcontentype_text_plain_html}" = "" ]; then
226			if ! [ "${checkencodingbase64}" = "" ]; then
227				#dbecho 8 "Debug[${SBLOGLEVEL}]: ${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body |${DECODEBASE64} >${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.plain"
228				${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body |\
229				${DECODEBASE64} |\
230				${SED} -e 's/^From /\\From /;s/^\.$/\\./' >${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.plain
231				dbecho 7 "Debug[${SBLOGLEVEL}]: Including file: ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.plain"
232				${ECHO} "${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.plain" >>${MESSAGETMPDIR}/plain_body_files_to_parse.txt
233			else
234				#dbecho 8 "Debug[${SBLOGLEVEL}]: ${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body >${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.plain"
235				${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body |\
236				${SED} -e 's/^From /\\From /;s/^\.$/\\./' >${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.plain
237				dbecho 7 "Debug[${SBLOGLEVEL}]: Including file: ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.plain"
238				${ECHO} "${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.plain" >>${MESSAGETMPDIR}/plain_body_files_to_parse.txt
239			fi
240		fi
241		# If the Content-Type: mime part header claims the part is an application or image then
242		# Calculate the sha1 hash of the MIME body part or if the part is base64 encoded,
243		# calculate the sha1 hash of the decoded body part.
244		# This hash could be checked against or added to a database of spammy sha1 hash's.
245		# or against a databse of sha1 hashes that have been whitelisted.
246		# such as might exist for bank logo .jpg's, trademark loogo's etc.
247		# ie: ~/.sbSpammyHashCache
248		if ! [ "${checkcontentype_application}" = "" ] || \
249		   ! [ "${checkcontentype_image}" = "" ] || \
250		   ! [ "${checkcontent_disposition_attachment_filename}" = "" ] || \
251		   ! [ "${checkcontent_type_name}" = "" ];\
252		then
253			if ! [ "${checkencodingbase64}" = "" ]; then
254				(((${ECHO} "base64 decoded sha1 hash=\"<";\
255				   ${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body |\
256				   ${DECODEBASE64} |\
257				   ${HASHCOMMAND};\
258				   ${ECHO} ">\"")|\
259				  ${TR} -d '\012\015');\
260				 ${ECHO} "") \
261					>${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.hash
262				dbecho 7 "Debug[${SBLOGLEVEL}]: Including file: ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.hash"
263				${ECHO} "${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.hash" \
264					>>${MESSAGETMPDIR}/plain_body_files_to_parse.txt
265			else
266				(((${ECHO} "sha1 hash=\"<";\
267				   ${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body |\
268				   ${HASHCOMMAND};\
269				   ${ECHO} ">\"")|\
270				  ${TR} -d '\012\015');\
271				 ${ECHO} "") \
272					>${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.hash
273				dbecho 7 "Debug[${SBLOGLEVEL}]: Including file: ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.hash"
274				${ECHO} "${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.hash" \
275					>>${MESSAGETMPDIR}/plain_body_files_to_parse.txt
276			fi
277			hash=`${CAT} ${MESSAGETMPDIR}/MIME_${OUTLINE}_${PART}.body.hash |\
278				${SED} -re 's/^(.*sha1 hash=")([<].+[>])"$/\2/'`
279			dbecho 8 "Debug[${SBLOGLEVEL}]: hash=\"${hash}\""
280			check_spammy_mimepart_hash=''
281			if [ -f ${HOME}/.sbSpammyHashCache ]; then
282				# dbecho 8 "Debug[${SBLOGLEVEL}]: ${GREP} -x \"${hash}\" ${HOME}/.sbSpammyHashCache"
283				#
284				# Note: this code could be adjusted to check a dns blocklist for a spammy hash instead of a file
285				# ie: something like this:
286				# check_spammy_mimepart_hash=`${HOST} ${hash}.hashcheck.dnsbl.example.org`
287				# where 127.0.0.2 = hash signature of a mime part found in spamtraps
288				#       127.0.0.3 = hash signature of a known virus/trojen or other dangerous attachment
289				#	127.0.0.4 = hash signature of a known good logo/trademark, possible spam victim.
290				#
291				# Check a file of sha1 signatures of mime parts found in spam.
292				# special case:
293				# Note: da39a3ee5e6b4b0d3255bfef95601890afd80709 is the sha1 hash of a zero byte or NULL message
294				# ie: echo -ne "" |openssl base64 -d |openssl sha1
295				# if that is the result of the decode, then ignore it.
296				# The hash is likely the result of a previously defanged message.
297				# probably from a virus filter that removed the part, but otherwise
298				# left the mime structure intact then delivered the defanged message.
299				if ! [ "${hash}" = "<da39a3ee5e6b4b0d3255bfef95601890afd80709>" ]; then
300					check_spammy_mimepart_hash=`${GREP} -x "${hash}" ${HOME}/.sbSpammyHashCache`
301				fi
302				# dbecho 8 "Debug[${SBLOGLEVEL}]: check_spammy_mimepart_hash=\"${check_spammy_mimepart_hash}\""
303			fi
304			if ! [ "${check_spammy_mimepart_hash}" = "" ]; then
305				# This code mimics the following for SpamBouncer logging:
306				#  SBLOG="C3T: Spammy Hash (MIME part ${OUTLINE}_${PART})"
307				#  INCLUDERC=${SBDIR}/functions/loglevel.rc
308				dbecho 4 "Found sha1 hash \"${hash}\" cached."
309				dbecho 3 "SBPattern: Spammy Hash (MIME part ${OUTLINE}_${PART})"
310				if [ "${SBHEADERS}" = "COMPLETE" ] || [ "${SBHEADERS}" = "BRIEF" ]; then
311					${ECHO} "X-SBPattern: Spammy Hash (MIME part ${OUTLINE}_${PART})" >>${MESSAGETMPDIR}/sbheaders-created-during-autopsy
312				fi
313			fi
314		fi
315
316		# Are we done extracting mime parts? If not then recurse to extract the next set of MIME parts in outline format.
317		# This is where this file calls itself to do this magic.
318		if ! [ "${checkpart}" = "" ]; then
319			dbecho 8 "Debug[${SBLOGLEVEL}]: checkpart=\"${checkpart}\""
320			if ! [ "${RECURSELEVEL}" -ge "${RECURSELIMIT}" ]; then
321				# dbecho 8 "Debug[${SBLOGLEVEL}]: ${SBDIR}/functions/mimeparts.sh MIME_${OUTLINE}_${PART} ${OUTLINE}_${PART} $[RECURSELEVEL+1] ${RECURSELIMIT} ${checkpart}"
322				# This is where we do the recursion if it's needed.
323				${SBDIR}/functions/mimeparts.sh "MIME_${OUTLINE}_${PART}" "${OUTLINE}_${PART}" "${PART}" "$[RECURSELEVEL+1]" "${RECURSELIMIT}" "${checkpart}"
324				dbecho 7 "Debug[${SBLOGLEVEL}]: [${OUTLINE}_${PART}] Recursive exit from file: ${thisfilename}"
325			else
326				dbecho 3 "MIME Recurse limit reached: RECURSELEVEL=${RECURSELEVEL} >= RECURSELIMIT=${RECURSELIMIT}"
327			fi
328		fi
329		PART=$[PART+1]
330	done
331fi
332