1# SHELL_FUNCTIONS.SH
2#
3# Author: "Garen Erdoisa" <scamper@trisk.com>
4# Licence: GNU GPL
5# Last update: 8/14/2011
6#
7# This code is written on behalf of the SpamBouncer project
8# and as such is donated by the Author to the SpamBouncer
9# project.
10#
11# Synopsis:
12# This is a /bin/sh functions file intended to be loaded
13# into the current environemt of "functions/mimeparts.sh"
14# which is a SpamBouncer /bin/sh script that uses these functions
15# for parsing MIME Version 1.0 encoded email.
16# This script is designed specifically for use inside SpamBouncer's
17# unique procmail recipes. It is not intended for general use or for
18# use with any other program or set of programs, and would require major
19# modifications to make it work outside of that environment.
20
21# FUNCTION SPLITPARTS()
22# expecting base filename to split into mime parts as the first command line argument.
23# expecting a part designation as the 2nd command line argument.
24function splitparts(){
25	${CAT} $1 |\
26	${SED} -ne "$3p" |\
27	${SED} -e '2,$!d;$d' >$1_$2
28
29	${CAT} $1 |\
30	${SED} -ne "$3p" |\
31	${SED} -e '2,$!d;$d' |\
32	${FORMAIL} -cX "Content-" |\
33	${SED} -e "${SPACES_TABS_TO_SPACES}" |\
34	${SED} -e '$s/.*/&\n/' >$1_$2.header
35
36	${CAT} $1 |\
37	${SED} -ne "$3p" |\
38	${SED} -e '2,$!d;$d' |\
39	${FORMAIL} -I "" >$1_$2.body
40}
41
42# FUNCTION GREPLOCALPARTS()
43# expecting filename in $1 and boundary tag in $2 for input
44function greplocalparts()
45{
46	# Save the boundary tag to a file for a later fgrep
47	# using the string in the file. I had to do it this way
48	# because fgrep misinterprets strings begining with one or two -'s when
49	# they appear on the command line as command line arguments
50	# to fgrep, while if they are in a file, fgrep uses them as
51	# a pattern to match against. Boundary strings always begining with --
52	# in the mime message body.
53	${ECHO} "$2" >${1}.boundary
54
55	# Replace any regexp meta characters in the boundary string
56	# in the pattern space only with a regexp . wildcard char.
57	# This is so sed or sh do not misinterpret the chars as
58	# /bin/sh or sed regexp meta characters.
59	# The numbers are octal.
60	# 042 " shell open/close quoted text
61	# 044 $ end of line anchor also shell meta in some cases
62	# 052 * sed match zero or more of preceeding character
63	# 054 ' forward single quote
64	# 057 / sed open/close pattern space.
65	# 133 [ regexp char list open also shell meta
66	# 134 \ sed escape the next char.
67	# 135 ] regexp char list close also shell meta
68	# 136 ^ begining of line anchor
69	# 140 ` back quote shell execute sub command
70	#
71	# All of the above are replaced with this in the pattern space.
72	# 056 . sed wild card match a single char (used to replace all of these in the pattern space)
73
74	LOCSTR=`${ECHO} "${2}" |${TR} "\042\044\052\054\057\133\134\135\136\140" "\056"`
75
76	# Use the modified boundary string with the wildcards to find the
77	# starting and ending line numbers of mime parts.
78	#
79	# We are prepending the line numbers to indicate exactly where in the part
80	# the boundary string was found. Trailing whitespaces are allowd.
81	# The two greps at the end, confirm that the strings found
82	# using this method are valid by comparing them back against the
83	# unmodified boundary string.
84	LOCALPARTS=`
85	 ${CAT} $1 |\
86         ${SED} -ne "/^--${LOCSTR}\(--\)\?\([ 	]\{1,\}\)\?$/=;//p" |\
87         ${SED} -e 's/$/;/' |\
88	 ${TR} -d '\012\015' |\
89	 ${SED} -e 's/\([0-9]\{1,\}\)\(;\)\(--\)/\1:\3/g;s/;/\n/g' |\
90	 ${GREP} -Faf ${1}.boundary |\
91	 ${EGREP} "^[0-9]+:--.+(--)?[ 	]+?$"
92	`
93}
94
95# FUNCTION GETLINEPAIRS()
96# expects a grep of the file with line numbers in front of boundary indicators as quoted input.
97# ie:
98# 3:--__Boundary
99# 9:--__Boundary
100# 130:--__Boundary
101# 824:--__Boundary--
102# It will reformat the above into:
103# "3,9 9,130 130,824"
104function getlinepairs()
105{
106# echo "function getlinepairs"
107LOCALLINEPAIRS=`
108	${ECHO} "$1" |\
109	${SED} -ne '
110			# Begin surgery on preceeding pattern space from the Grep results:
111			#
112			# Address line one only of the preceeding pattern space
113			# replace the line number from the grep with the line number
114			# followed by a comma
115			1s/^\([0-9]\{1,\}\):\(.\{1,\}\)$/\1,/p
116
117			# Next we have to duplicate some of the line numbers so
118			# we can end up with pairs. The end of one part becomes
119			# the defacto begining of the next part in a multi part
120			# message.
121			#
122			# Address line one to end of preceeding pattern space
123			# replace first match where P is the match with P;\nP,
124			# drop the 2nd match entirely.
125			1,$s/^\([0-9]\{1,\}\):\(.\{1,\}\)$/\1;\n\1,/p
126		' |\
127	${SED} -e '
128			# continued surgery on preceeding pattern space
129			# Delete the last line of the preceeding pattern space.
130			# we dont need it.
131			$d
132
133			# the tr following this strips out end of line characters
134			# in the preceeding pattern space, putting everything back
135			# just on one line so that we can seperate the lines again
136			# where the semi-colons were edited in.
137		' |\
138	${TR} -d '\012\015' |\
139	${SED} -e '
140			# continued surgery on preceeding pattern space
141			# globally replace all semi-colons with <space>, then strip
142			# any trailing space from the pattern space.
143			# This makes rows with pairs of line numbers seperated by a comma
144			# this format is sutable for use in sed to address just those
145			# lines in the main message body.
146			# The pairs of line numbers reference the begining and ending
147			# lines of each part of the mime boundary we are considering
148			# in the message body only. Line 1 being the first line of
149			# the message body after the headers.
150			s/;/ /g
151			s/ $//
152		'`
153}
154
155# FUNCTION DBECHO()
156# Conditional echo.
157# first parameter is a number that indicates if we should print the message
158# or not. If that number is greater than or equal to the current SBLOGLEVEL
159# then we do, otherwise skip it.
160function dbecho()
161{
162	LEVEL="$1"
163	if [ ${LEVEL} -le ${SBLOGLEVEL} ] && [ -f ${LOGFILE} ]; then
164		shift
165		SBLOGPREFIX="`${DATE} '+%b %d %H:%M:%S'` ${HOST} SpamBouncer[${SBPID}]:"
166		MESSAGE="${SBLOGPREFIX} $*"
167		if [ "${SBLOGFILE}" = "INTERNAL" ]; then
168			${ECHO} "${MESSAGE}"
169		elif [ -f ${SBLOGFILE} ]; then
170			${ECHO} "${MESSAGE}" >>${SBLOGFILE}
171		fi
172	fi
173}
174