3 # sub-mailhandler.py - frontend for rdm-mailhandler.rb
6 # This script parses the header of a message until it finds a known email;
7 # then use that email to look for a subaddress pattern that provides a
8 # project to rdm-mailhandler.rb
10 # It works by using an email of the form:
11 # <user+project@example.com>
12 # Most mail servers will deliver this to <user@example.com>, so the + part
13 # is used to determine the project. A default ptoject can be specified.
16 # Copyright 2010 Thomas Guyot-Sionnest <tguyot@gmail.com>
18 # This program is free software: you can redistribute it and/or modify
19 # it under the terms of the GNU General Public License as published by
20 # the Free Software Foundation, either version 3 of the License, or
21 # (at your option) any later version.
23 # This program is distributed in the hope that it will be useful,
24 # but WITHOUT ANY WARRANTY; without even the implied warranty of
25 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 # GNU General Public License for more details.
28 # You should have received a copy of the GNU General Public License
29 # along with this program. If not, see <http://www.gnu.org/licenses/>.
34 from optparse
import OptionParser
35 from subprocess
import Popen
, PIPE
37 oparser
= OptionParser(usage
='%prog -h | -e <email> [ -p <project> ] -- <command-line>',
38 description
='''The <command-line> portion is the full
39 rdm-mailhandler.rb command that would normally be executed as the mail
40 handler. The full path to the executable is required. This command should not
41 include a project; use the build-in --project argument instead.''')
43 oparser
.add_option('-e', '--email', type='string', dest
='email',
44 help='Known email to look for (i.e. redmine recipient)')
45 oparser
.add_option('-p', '--project', type='string', dest
='project',
46 help='Default project to pass to rdm-mailhandler.rb if there is no subaddress')
48 (options
, args
) = oparser
.parse_args()
50 # Get email split and make sute it's not having weird formatting already
51 if options
.email
is None: oparser
.error('You must provide an email address')
54 esplit
= options
.email
.index('@')
56 oparser
.error('Not an email address')
58 # Split out email to use the individual parts here and later:
59 ename
= options
.email
[:esplit
]
60 edomain
= options
.email
[esplit
+1:]
63 oparser
.error('Email provided contains a subaddress already')
68 oparser
.error('Duplicate @ in email address')
72 # Read-in the headers...
75 line
= sys
.stdin
.readline()
77 if line
.strip() == '': break
80 eo
= email
.parser
.HeaderParser()
81 msg
= eo
.parsestr(buf
, headersonly
=True)
83 # Fetch all email addresses out of them...
84 tos
= msg
.get_all('to', [])
85 ccs
= msg
.get_all('cc', [])
86 resent_tos
= msg
.get_all('resent-to', [])
87 resent_ccs
= msg
.get_all('resent-cc', [])
88 all_recipients
= email
.utils
.getaddresses(tos
+ ccs
+ resent_tos
+ resent_ccs
)
90 # And look for a matching one
92 for n
, e
in all_recipients
:
98 # If we have a subaddress, get it.
100 ssplit
= email
.rindex('+')
101 subaddr
= email
[ssplit
+1:]
102 email
= email
[:ssplit
]
106 # Now check email and subaddress, then break if found
107 if email
== ename
and domain
== edomain
:
112 # Finally, execute the handler and pass it the whole thing
114 projectarg
= ['-p', project
]
115 elif options
.project
:
116 projectarg
= ['-p', options
.project
]
120 handler
= Popen(args
+ projectarg
, stdin
=PIPE
, stdout
=sys
.stdout
, stderr
=sys
.stderr
, shell
=False)
121 handler
.stdin
.write(buf
)
123 handler
.stdin
.write(l
)
125 handler
.stdin
.close()
127 sys
.exit(handler
.returncode
)