source: rtems-tools/rtemstoolkit/mailer.py @ 3618a62

Last change on this file since 3618a62 was 7051ba5, checked in by Chris Johns <chrisj@…>, on Oct 22, 2017 at 7:09:39 AM

bsb-builder: Add email support, and config report types.

  • Property mode set to 100644
File size: 5.8 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2013-2016 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions are met:
10#
11# 1. Redistributions of source code must retain the above copyright notice,
12# this list of conditions and the following disclaimer.
13#
14# 2. Redistributions in binary form must reproduce the above copyright notice,
15# this list of conditions and the following disclaimer in the documentation
16# and/or other materials provided with the distribution.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28# POSSIBILITY OF SUCH DAMAGE.
29#
30
31#
32# Manage emailing results or reports.
33#
34
35from __future__ import print_function
36
37import os
38import smtplib
39import socket
40
41#
42# Support to handle use in a package and as a unit test.
43# If there is a better way to let us know.
44#
45try:
46    from . import error
47    from . import options
48    from . import path
49except (ValueError, SystemError):
50    import error
51    import options
52    import path
53
54_options = {
55    '--mail'     : 'Send email report or results.',
56    '--smtp-host': 'SMTP host to send via.',
57    '--mail-to'  : 'Email address to send the email too.',
58    '--mail-from': 'Email address the report is from.'
59}
60
61def append_options(opts):
62    for o in _options:
63        opts[o] = _options[o]
64
65def add_arguments(argsp):
66    argsp.add_argument('--mail', help = _options['--mail'], action = 'store_true')
67    for o in ['--smtp-host', '--mail-to', '--mail-from']:
68        argsp.add_argument(o, help = _options[o], type = str)
69
70class mail:
71    def __init__(self, opts):
72        self.opts = opts
73
74    def _args_are_macros(self):
75        return type(self.opts) is 'command_line'
76
77    def _get_arg(self, arg):
78        if self._args_are_macros():
79            value = self.opts.find_arg(arg)[1]
80        else:
81            if arg.startswith('--'):
82                arg = arg[2:]
83            arg = arg.replace('-', '_')
84            if arg in vars(self.opts):
85                value = vars(self.opts)[arg]
86            else:
87                value = None
88        return value
89
90    def from_address(self):
91
92        def _clean(l):
93            if '#' in l:
94                l = l[:l.index('#')]
95            if '\r' in l:
96                l = l[:l.index('r')]
97            if '\n' in l:
98                l = l[:l.index('\n')]
99            return l.strip()
100
101        addr = self._get_arg('--mail-from')
102        if addr is not None:
103            return addr
104        mailrc = None
105        if 'MAILRC' in os.environ:
106            mailrc = os.environ['MAILRC']
107        if mailrc is None and 'HOME' in os.environ:
108            mailrc = path.join(os.environ['HOME'], '.mailrc')
109        if mailrc is not None and path.exists(mailrc):
110            # set from="Joe Blow <joe@blow.org>"
111            try:
112                with open(mailrc, 'r') as mrc:
113                    lines = mrc.readlines()
114            except IOError as err:
115                raise error.general('error reading: %s' % (mailrc))
116            for l in lines:
117                l = _clean(l)
118                if 'from' in l:
119                    fa = l[l.index('from') + len('from'):]
120                    if '=' in fa:
121                        addr = fa[fa.index('=') + 1:].replace('"', ' ').strip()
122            if addr is not None:
123                return addr
124        if self._args_are_macros():
125            addr = self.opts.defaults.get_value('%{_sbgit_mail}')
126        else:
127            raise error.general('no valid from address for mail')
128        return addr
129
130    def smtp_host(self):
131        host = self._get_arg('--smtp-host')
132        if host is not None:
133            return host[1]
134        if self._args_are_macros():
135            host = self.opts.defaults.get_value('%{_mail_smtp_host}')
136        if host is not None:
137            return host
138        return 'localhost'
139
140    def send(self, to_addr, subject, body):
141        from_addr = self.from_address()
142        msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n" % \
143            (from_addr, to_addr, subject) + body
144        try:
145            s = smtplib.SMTP(self.smtp_host())
146            s.sendmail(from_addr, [to_addr], msg)
147        except smtplib.SMTPException as se:
148            raise error.general('sending mail: %s' % (str(se)))
149        except socket.error as se:
150            raise error.general('sending mail: %s' % (str(se)))
151
152    def send_file_as_body(self, to_addr, subject, name, intro = None):
153        try:
154            with open(name, 'r') as f:
155                body = f.readlines()
156        except IOError as err:
157            raise error.general('error reading mail body: %s' % (name))
158        if intro is not None:
159            body = intro + body
160        self.send(to_addr, from_addr, body)
161
162if __name__ == '__main__':
163    import sys
164    optargs = {}
165    append_options(optargs)
166    opts = options.load(sys.argv, optargs = optargs, defaults = 'defaults.mc')
167    m = mail(opts)
168    print('From: %s' % (m.from_address()))
169    print('SMTP Host: %s' % (m.smtp_host()))
170    m.send(m.from_address(), 'Test mailer.py', 'This is a test')
Note: See TracBrowser for help on using the repository browser.