diff options
| -rwxr-xr-x | patch-save.py | 90 | 
1 files changed, 90 insertions, 0 deletions
diff --git a/patch-save.py b/patch-save.py new file mode 100755 index 0000000..1c0516f --- /dev/null +++ b/patch-save.py @@ -0,0 +1,90 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2022 Laurent Pinchart +# +# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com> +# +# Patch save script for mutt that handles mailman From header mangling. +# +# To install, copy the script to ~/.mutt/, and add the following lines to your +# .muttrc to bind to ctrl-h. +# +# set pipe_split=yes +# macro index \Ch "<enter-command>unset wait_key<enter> +#   <enter-command>set pipe_decode<enter> +#   <tag-prefix><pipe-entry>~/.mutt/patch-save.py<enter> +#   <enter-command>unset pipe_decode<enter> +#   <enter-command>set wait_key<enter>" "output git patches" +# + +import email +import pathlib +import re +import sys + + +def sanitize(s): +    out = '' + +    for c in s: +        if c in '[]': +            continue + +        if c in "'": +            c = '.' +        elif c in '/:': +            c = '-' +        elif c in '*()" \t\n\r': +            c = '_' + +        out += c + +    return out + + +def main(argv): + +    # Parse the message from stdin as binary, as we can't assume any particular +    # encoding. +    msg = email.message_from_binary_file(sys.stdin.buffer) + +    # mailman can mangle the From header to work around DMARC rejection rules. +    # It then formats From as "Name via mailing-list <mailing-list@domain>" and +    # stores the original sender in the Reply-to header. Restore the original +    # author in the From header to please git-am. +    from_header = msg.get('From') +    reply_to = msg.get('Reply-to') +    if reply_to and ' via ' in from_header: +        msg.replace_header('From', reply_to) + +    subject = msg.get('Subject') +    if not subject: +        return 1 + +    # The subject can be an str instance or an email.header.Header instance. +    # Convert it to str in all cases. +    subject = str(subject) + +    # Strip everything before the [PATCH] or [RESEND] tag. +    match = re.search(r'\[(PATCH|RESEND) [^]]*\].*', subject) +    if match: +        subject = match.group(0) + +    # Sanitize the subject. +    subject = sanitize(subject) + +    subject = subject.replace('..', '.') +    subject = subject.replace('-_', '_') +    subject = subject.replace('__', '_') + +    subject = subject.strip() +    subject = subject.rstrip('.') + +    file_name = pathlib.Path.home() / '.maildir' / 'patches' / (subject + '.patch') +    open(file_name, 'wb').write(bytes(msg)) + +    return 0 + + +if __name__ == '__main__': +    sys.exit(main(sys.argv))  | 
