# # Read this file into your .procmailrc with a line of the form: # INCLUDERC=mimepart.txt # # After inclusion, the variable BODY_PART contains the text of the first # text/plain body-part in the message, if there is one. If CONTENT_TYPE # is set to a different type before this file is read, the first part of # that type is extracted instead. # # If the message was a multipart, the variable BOUNDARY is a pattern that # matches the boundary string of the multipart containing the extracted # part, and the variable PART_HEADER contains the header of the extracted # body part (incuding the leading BOUNDARY). # # BUGS: # - Doesn't work if the Content-Type field contains legal but extraneous # whitespace (e.g. "Content-Type: text / plain"), unless of course the # calling rcfile explicitly sets the CONTENT_TYPE variable for that. # - Trims trailing blank lines from the extracted body part. # CONTENT_TYPE=${CONTENT_TYPE:-text/plain} # Construct an expression to match the content-type that we want. CONTENT_HEADER="(.+($))?Content-Type:\<+$\CONTENT_TYPE.*($)(.+($))*" # If the type is text/plain, this also must match a body part with no # header at all. :0 * CONTENT_TYPE ?? text/plain { CONTENT_HEADER="($CONTENT_HEADER)?" } # Check for a top-level multipart message with a boundary. :0 * 9876543210^0 Content-Type(.|$[ ])*boundary="\/[^"]+ * 9876543210^0 Content-Type(.|$[ ])*boundary=\/[^; ]+ { BOUNDARY=$\MATCH # Check for a nested multipart. A recursive include would be needed # to do this more than one level deep. :0 B * 9876543210^0 Content-Type(.|$[ ])*boundary="\/[^"]+ * 9876543210^0 Content-Type(.|$[ ])*boundary=\/[^; ]+ { BOUNDARY="($BOUNDARY|$\MATCH)" } # Now find the first body part header with the desired content type. :0 B * $ ^\/--$BOUNDARY($)$CONTENT_HEADER($) { # Make sure LINEBUF is big enough for us to do the next assignment. :0 * 2^1 MATCH ?? > 1 * $ MATCH ?? > $LINEBUF { LINEBUF=$= } PART_HEADER="$MATCH" # Ideally we'd use exactly the MATCHed part header here to construct a # new fixed expression to match this header again. Unfortunately there # is a bug or misfeature in procmail such that when a variable expanded # in a regex context contains a newline followed by whitespace, that # whitespace is discarded, and the resulting pattern fails to match. # Narrow the BOUNDARY to the string we actually found in this part. :0 * PART_HEADER ?? ^^--\/.+ { BOUNDARY=$\MATCH } # Construct the new expression to match this specific part header. PART_BEGINNING="--$BOUNDARY($)$CONTENT_HEADER($)" } # Otherwise bail, there is no part of the desired type. :0 E { SWITCHRC } # Now extract just the desired part, including the closing BOUNDARY. :0 B * $ 9876543210^0 ^$PART_BEGINNING\/(.|$)*($)--$BOUNDARY($) * $ 9876543210^0 ^$PART_BEGINNING\/(.|$)*($)--$BOUNDARY--($) { # Make sure LINEBUF is big enough for us to do the next assignment. :0 * 2^1 MATCH ?? > 1 * $ MATCH ?? > $LINEBUF { LINEBUF=$= } BODY_PART="$MATCH" } # Now we know that the last line in BODY_PART that begins with a hyphen # must be the closing BOUNDARY string, and that there is nothing in # BODY_PART after the final newline ... so we can trim the BOUNDARY by # sacrificing any blank lines that immediately precede it. :0 * BODY_PART ?? ^^\/(.|$)*($)-- * MATCH ?? ^^\/(.|$)*[^-] { BODY_PART="$MATCH" } # Special-case for empty body parts :0E * $ BODY_PART ?? ^^($)*--$BOUNDARY { BODY_PART="" } } # No BOUNDARY string, it must be a single-part message. :0E * $ ^$CONTENT_HEADER * B ?? ^^\/(.|$)+ { # Make sure LINEBUF is big enough for us to do the next assignment. :0 * 2^1 MATCH ?? > 1 * $ MATCH ?? > $LINEBUF { LINEBUF=$= } BODY_PART="$MATCH" } # Unset "local" variables CONTENT_HEADER PART_BEGINNING # Copyright (c) 2003 Barton E. Schaefer # # NO WARRANTY # # THIS PROGRAM IS PROVIDED FREE OF CHARGE. THERE IS NO WARRANTY # FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN # OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES # PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED # OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS # TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE # PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, # REPAIR OR CORRECTION. # # IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING # WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR # REDISTRIBUTE THE PROGRAM, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY # GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE # USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS # OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU # OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER # PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGES. #