1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
# portage.py -- core Portage functionality
# Copyright 1998-2004 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id$
# Since python ebuilds remove the 'email' module when USE=build
# is enabled, use a local import so that
# portage.proxy.lazyimport._preload_portage_submodules()
# can load this module even though the 'email' module is missing.
# The elog mail modules won't work, but at least an ImportError
# won't cause portage to crash during stage builds. Since the
# 'smtlib' module imports the 'email' module, that's imported
# locally as well.
import socket
import sys
import time
from portage import os
from portage import _encodings
from portage import _unicode_decode, _unicode_encode
from portage.localization import _
import portage
if sys.hexversion >= 0x3000000:
basestring = str
def TextMessage(_text):
from email.mime.text import MIMEText
mimetext = MIMEText(_text)
if sys.hexversion >= 0x3000000:
mimetext.set_charset("UTF-8")
return mimetext
def create_message(sender, recipient, subject, body, attachments=None):
from email.header import Header
from email.mime.base import MIMEBase as BaseMessage
from email.mime.multipart import MIMEMultipart as MultipartMessage
if sys.hexversion < 0x3000000:
sender = _unicode_encode(sender,
encoding=_encodings['content'], errors='strict')
recipient = _unicode_encode(recipient,
encoding=_encodings['content'], errors='strict')
subject = _unicode_encode(subject,
encoding=_encodings['content'], errors='backslashreplace')
body = _unicode_encode(body,
encoding=_encodings['content'], errors='backslashreplace')
if attachments == None:
mymessage = TextMessage(body)
else:
mymessage = MultipartMessage()
mymessage.attach(TextMessage(body))
for x in attachments:
if isinstance(x, BaseMessage):
mymessage.attach(x)
elif isinstance(x, basestring):
if sys.hexversion < 0x3000000:
x = _unicode_encode(x,
encoding=_encodings['content'],
errors='backslashreplace')
mymessage.attach(TextMessage(x))
else:
raise portage.exception.PortageException(_("Can't handle type of attachment: %s") % type(x))
mymessage.set_unixfrom(sender)
mymessage["To"] = recipient
mymessage["From"] = sender
# Use Header as a workaround so that long subject lines are wrapped
# correctly by <=python-2.6 (gentoo bug #263370, python issue #1974).
mymessage["Subject"] = Header(subject)
mymessage["Date"] = time.strftime("%a, %d %b %Y %H:%M:%S %z")
return mymessage
def send_mail(mysettings, message):
import smtplib
mymailhost = "localhost"
mymailport = 25
mymailuser = ""
mymailpasswd = ""
myrecipient = "root@localhost"
# Syntax for PORTAGE_ELOG_MAILURI (if defined):
# adress [[user:passwd@]mailserver[:port]]
# where adress: recipient adress
# user: username for smtp auth (defaults to none)
# passwd: password for smtp auth (defaults to none)
# mailserver: smtp server that should be used to deliver the mail (defaults to localhost)
# alternatively this can also be the absolute path to a sendmail binary if you don't want to use smtp
# port: port to use on the given smtp server (defaults to 25, values > 100000 indicate that starttls should be used on (port-100000))
if " " in mysettings["PORTAGE_ELOG_MAILURI"]:
myrecipient, mymailuri = mysettings["PORTAGE_ELOG_MAILURI"].split()
if "@" in mymailuri:
myauthdata, myconndata = mymailuri.rsplit("@", 1)
try:
mymailuser,mymailpasswd = myauthdata.split(":")
except ValueError:
print(_("!!! invalid SMTP AUTH configuration, trying unauthenticated ..."))
else:
myconndata = mymailuri
if ":" in myconndata:
mymailhost,mymailport = myconndata.split(":")
else:
mymailhost = myconndata
else:
myrecipient = mysettings["PORTAGE_ELOG_MAILURI"]
myfrom = message.get("From")
if sys.hexversion < 0x3000000:
myrecipient = _unicode_encode(myrecipient,
encoding=_encodings['content'], errors='strict')
mymailhost = _unicode_encode(mymailhost,
encoding=_encodings['content'], errors='strict')
mymailport = _unicode_encode(mymailport,
encoding=_encodings['content'], errors='strict')
myfrom = _unicode_encode(myfrom,
encoding=_encodings['content'], errors='strict')
mymailuser = _unicode_encode(mymailuser,
encoding=_encodings['content'], errors='strict')
mymailpasswd = _unicode_encode(mymailpasswd,
encoding=_encodings['content'], errors='strict')
# user wants to use a sendmail binary instead of smtp
if mymailhost[0] == os.sep and os.path.exists(mymailhost):
fd = os.popen(mymailhost+" -f "+myfrom+" "+myrecipient, "w")
fd.write(message.as_string())
if fd.close() != None:
sys.stderr.write(_("!!! %s returned with a non-zero exit code. This generally indicates an error.\n") % mymailhost)
else:
try:
if int(mymailport) > 100000:
myconn = smtplib.SMTP(mymailhost, int(mymailport) - 100000)
myconn.ehlo()
if not myconn.has_extn("STARTTLS"):
raise portage.exception.PortageException(_("!!! TLS support requested for logmail but not suported by server"))
myconn.starttls()
myconn.ehlo()
else:
myconn = smtplib.SMTP(mymailhost, mymailport)
if mymailuser != "" and mymailpasswd != "":
myconn.login(mymailuser, mymailpasswd)
message_str = message.as_string()
if sys.hexversion >= 0x3000000:
# Force ascii encoding in order to avoid UnicodeEncodeError
# from smtplib.sendmail with python3 (bug #291331).
message_str = _unicode_encode(message_str,
encoding='ascii', errors='backslashreplace')
message_str = _unicode_decode(message_str,
encoding='ascii', errors='replace')
myconn.sendmail(myfrom, myrecipient, message_str)
myconn.quit()
except smtplib.SMTPException as e:
raise portage.exception.PortageException(_("!!! An error occured while trying to send logmail:\n")+str(e))
except socket.error as e:
raise portage.exception.PortageException(_("!!! A network error occured while trying to send logmail:\n%s\nSure you configured PORTAGE_ELOG_MAILURI correctly?") % str(e))
return
|