annotate mercurial/mail.py @ 8564:6b9ec23b09fc

named branches: improve pre-push logic (issue736) Each named branch is considered separately, and the push is allowed if no new branch heads are created for any named branch to be pushed. Due to some tests's use of --debug, their output will change after this addition. This has been fixed as well. Co-contributor: Henrik Stuart <henrik.stuart@edlund.dk>
author Sune Foldager <cryo@cyanite.org>
date Sat, 23 May 2009 17:04:31 +0200
parents 6fbbb90261b1
children 2de7d96593db
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
1 # mail.py - mail sending bits for mercurial
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
2 #
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
4 #
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 7948
diff changeset
5 # This software may be used and distributed according to the terms of the
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 7948
diff changeset
6 # GNU General Public License version 2, incorporated herein by reference.
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
7
3891
6b4127c7d52a Simplify i18n imports
Matt Mackall <mpm@selenic.com>
parents: 3877
diff changeset
8 from i18n import _
8312
b87a50b7125c separate import lines from mercurial and general python modules
Simon Heimberg <simohe@besonet.ch>
parents: 8225
diff changeset
9 import util, encoding
8332
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
10 import os, smtplib, socket, quopri
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
11 import email.Header, email.MIMEText, email.Utils
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
12
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
13 def _smtp(ui):
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
14 '''build an smtp connection and return a function to send mail'''
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
15 local_hostname = ui.config('smtp', 'local_hostname')
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
16 s = smtplib.SMTP(local_hostname=local_hostname)
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
17 mailhost = ui.config('smtp', 'host')
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
18 if not mailhost:
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
19 raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
20 mailport = int(ui.config('smtp', 'port', 25))
2964
26c8d37496c2 fix typo in mail.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 2929
diff changeset
21 ui.note(_('sending mail: smtp host %s, port %s\n') %
26c8d37496c2 fix typo in mail.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 2929
diff changeset
22 (mailhost, mailport))
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
23 s.connect(host=mailhost, port=mailport)
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
24 if ui.configbool('smtp', 'tls'):
4093
669f99f78db0 mail.py: don't try to use TLS if python doesn't have SSL support
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 2964
diff changeset
25 if not hasattr(socket, 'ssl'):
669f99f78db0 mail.py: don't try to use TLS if python doesn't have SSL support
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 2964
diff changeset
26 raise util.Abort(_("can't use TLS: Python SSL support "
669f99f78db0 mail.py: don't try to use TLS if python doesn't have SSL support
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 2964
diff changeset
27 "not installed"))
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
28 ui.note(_('(using tls)\n'))
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
29 s.ehlo()
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
30 s.starttls()
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
31 s.ehlo()
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
32 username = ui.config('smtp', 'username')
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
33 password = ui.config('smtp', 'password')
5749
4fba4fee0718 Patchbomb: Prompt password when using SMTP/TLS and no password in .hgrc.
Arun Thomas <arun.thomas@gmail.com>
parents: 5472
diff changeset
34 if username and not password:
4fba4fee0718 Patchbomb: Prompt password when using SMTP/TLS and no password in .hgrc.
Arun Thomas <arun.thomas@gmail.com>
parents: 5472
diff changeset
35 password = ui.getpass()
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
36 if username and password:
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
37 ui.note(_('(authenticating to mail server as %s)\n') %
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
38 (username))
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
39 s.login(username, password)
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
40
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
41 def send(sender, recipients, msg):
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
42 try:
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
43 return s.sendmail(sender, recipients, msg)
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
44 except smtplib.SMTPRecipientsRefused, inst:
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
45 recipients = [r[1] for r in inst.recipients.values()]
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
46 raise util.Abort('\n' + '\n'.join(recipients))
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
47 except smtplib.SMTPException, inst:
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
48 raise util.Abort(inst)
5947
528c986f0162 Backed out changeset dc6ed2736c81
Bryan O'Sullivan <bos@serpentine.com>
parents: 5866
diff changeset
49
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
50 return send
5947
528c986f0162 Backed out changeset dc6ed2736c81
Bryan O'Sullivan <bos@serpentine.com>
parents: 5866
diff changeset
51
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
52 def _sendmail(ui, sender, recipients, msg):
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
53 '''send mail using sendmail.'''
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
54 program = ui.config('email', 'method')
5975
75d9fe70c654 templater: move email function to util
Matt Mackall <mpm@selenic.com>
parents: 5973
diff changeset
55 cmdline = '%s -f %s %s' % (program, util.email(sender),
75d9fe70c654 templater: move email function to util
Matt Mackall <mpm@selenic.com>
parents: 5973
diff changeset
56 ' '.join(map(util.email, recipients)))
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
57 ui.note(_('sending mail: %s\n') % cmdline)
6548
962eb403165b replace usage of os.popen() with util.popen()
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5975
diff changeset
58 fp = util.popen(cmdline, 'w')
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
59 fp.write(msg)
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
60 ret = fp.close()
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
61 if ret:
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
62 raise util.Abort('%s %s' % (
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
63 os.path.basename(program.split(None, 1)[0]),
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
64 util.explain_exit(ret)[0]))
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
65
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
66 def connect(ui):
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
67 '''make a mail connection. return a function to send mail.
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
68 call as sendmail(sender, list-of-recipients, msg).'''
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
69 if ui.config('email', 'method', 'smtp') == 'smtp':
5947
528c986f0162 Backed out changeset dc6ed2736c81
Bryan O'Sullivan <bos@serpentine.com>
parents: 5866
diff changeset
70 return _smtp(ui)
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
71 return lambda s, r, m: _sendmail(ui, s, r, m)
2889
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
72
20b95aef3fe0 Move ui.sendmail to mail.connect/sendmail
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
73 def sendmail(ui, sender, recipients, msg):
5973
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
74 send = connect(ui)
ea77f6f77514 patchbomb: undo backout and fix bugs in the earlier patch
Matt Mackall <mpm@selenic.com>
parents: 5947
diff changeset
75 return send(sender, recipients, msg)
4489
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
76
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
77 def validateconfig(ui):
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
78 '''determine if we have enough config data to try sending email.'''
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
79 method = ui.config('email', 'method', 'smtp')
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
80 if method == 'smtp':
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
81 if not ui.config('smtp', 'host'):
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
82 raise util.Abort(_('smtp specified as email transport, '
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
83 'but no smtp host configured'))
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
84 else:
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
85 if not util.find_exe(method):
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
86 raise util.Abort(_('%r specified as email transport, '
a11e13d50645 patchbomb: Validate email config before we start prompting for info.
Bryan O'Sullivan <bos@serpentine.com>
parents: 4096
diff changeset
87 'but not in PATH') % method)
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
88
7191
d14212218582 mail: mime-encode patches that are utf-8
Christian Ebert <blacktrash@gmx.net>
parents: 7114
diff changeset
89 def mimetextpatch(s, subtype='plain', display=False):
d14212218582 mail: mime-encode patches that are utf-8
Christian Ebert <blacktrash@gmx.net>
parents: 7114
diff changeset
90 '''If patch in utf-8 transfer-encode it.'''
8332
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
91
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
92 enc = None
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
93 for line in s.splitlines():
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
94 if len(line) > 950:
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
95 s = quopri.encodestring(s)
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
96 enc = "quoted-printable"
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
97 break
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
98
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
99 cs = 'us-ascii'
7191
d14212218582 mail: mime-encode patches that are utf-8
Christian Ebert <blacktrash@gmx.net>
parents: 7114
diff changeset
100 if not display:
8332
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
101 try:
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
102 s.decode('us-ascii')
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
103 except UnicodeDecodeError:
7191
d14212218582 mail: mime-encode patches that are utf-8
Christian Ebert <blacktrash@gmx.net>
parents: 7114
diff changeset
104 try:
8332
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
105 s.decode('utf-8')
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
106 cs = 'utf-8'
7191
d14212218582 mail: mime-encode patches that are utf-8
Christian Ebert <blacktrash@gmx.net>
parents: 7114
diff changeset
107 except UnicodeDecodeError:
8332
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
108 # We'll go with us-ascii as a fallback.
7191
d14212218582 mail: mime-encode patches that are utf-8
Christian Ebert <blacktrash@gmx.net>
parents: 7114
diff changeset
109 pass
8332
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
110
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
111 msg = email.MIMEText.MIMEText(s, subtype, cs)
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
112 if enc:
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
113 del msg['Content-Transfer-Encoding']
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
114 msg['Content-Transfer-Encoding'] = enc
3e544c074459 patchbomb: quoted-printable encode overly long lines
Rocco Rutte <pdmef@gmx.net>
parents: 8312
diff changeset
115 return msg
7191
d14212218582 mail: mime-encode patches that are utf-8
Christian Ebert <blacktrash@gmx.net>
parents: 7114
diff changeset
116
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
117 def _charsets(ui):
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
118 '''Obtains charsets to send mail parts not containing patches.'''
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
119 charsets = [cs.lower() for cs in ui.configlist('email', 'charsets')]
7948
de377b1a9a84 move encoding bits from util to encoding
Matt Mackall <mpm@selenic.com>
parents: 7195
diff changeset
120 fallbacks = [encoding.fallbackencoding.lower(),
de377b1a9a84 move encoding bits from util to encoding
Matt Mackall <mpm@selenic.com>
parents: 7195
diff changeset
121 encoding.encoding.lower(), 'utf-8']
8343
6fbbb90261b1 mail: updated comment
Martin Geisler <mg@lazybytes.net>
parents: 8332
diff changeset
122 for cs in fallbacks: # find unique charsets while keeping order
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
123 if cs not in charsets:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
124 charsets.append(cs)
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
125 return [cs for cs in charsets if not cs.endswith('ascii')]
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
126
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
127 def _encode(ui, s, charsets):
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
128 '''Returns (converted) string, charset tuple.
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
129 Finds out best charset by cycling through sendcharsets in descending
7948
de377b1a9a84 move encoding bits from util to encoding
Matt Mackall <mpm@selenic.com>
parents: 7195
diff changeset
130 order. Tries both encoding and fallbackencoding for input. Only as
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
131 last resort send as is in fake ascii.
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
132 Caveat: Do not use for mail parts containing patches!'''
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
133 try:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
134 s.decode('ascii')
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
135 except UnicodeDecodeError:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
136 sendcharsets = charsets or _charsets(ui)
7948
de377b1a9a84 move encoding bits from util to encoding
Matt Mackall <mpm@selenic.com>
parents: 7195
diff changeset
137 for ics in (encoding.encoding, encoding.fallbackencoding):
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
138 try:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
139 u = s.decode(ics)
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
140 except UnicodeDecodeError:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
141 continue
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
142 for ocs in sendcharsets:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
143 try:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
144 return u.encode(ocs), ocs
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
145 except UnicodeEncodeError:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
146 pass
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
147 except LookupError:
7195
9fabcb1fe68d mail: correct typo in variable name
Christian Ebert <blacktrash@gmx.net>
parents: 7191
diff changeset
148 ui.warn(_('ignoring invalid sendcharset: %s\n') % ocs)
7114
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
149 # if ascii, or all conversion attempts fail, send (broken) ascii
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
150 return s, 'us-ascii'
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
151
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
152 def headencode(ui, s, charsets=None, display=False):
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
153 '''Returns RFC-2047 compliant header from given string.'''
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
154 if not display:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
155 # split into words?
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
156 s, cs = _encode(ui, s, charsets)
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
157 return str(email.Header.Header(s, cs))
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
158 return s
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
159
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
160 def addressencode(ui, address, charsets=None, display=False):
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
161 '''Turns address into RFC-2047 compliant header.'''
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
162 if display or not address:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
163 return address or ''
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
164 name, addr = email.Utils.parseaddr(address)
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
165 name = headencode(ui, name, charsets)
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
166 try:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
167 acc, dom = addr.split('@')
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
168 acc = acc.encode('ascii')
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
169 dom = dom.encode('idna')
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
170 addr = '%s@%s' % (acc, dom)
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
171 except UnicodeDecodeError:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
172 raise util.Abort(_('invalid email address: %s') % addr)
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
173 except ValueError:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
174 try:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
175 # too strict?
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
176 addr = addr.encode('ascii')
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
177 except UnicodeDecodeError:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
178 raise util.Abort(_('invalid local address: %s') % addr)
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
179 return email.Utils.formataddr((name, addr))
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
180
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
181 def mimeencode(ui, s, charsets=None, display=False):
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
182 '''creates mime text object, encodes it if needed, and sets
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
183 charset and transfer-encoding accordingly.'''
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
184 cs = 'us-ascii'
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
185 if not display:
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
186 s, cs = _encode(ui, s, charsets)
30e49d54c537 mail: add methods to handle non-ascii chars
Christian Ebert <blacktrash@gmx.net>
parents: 6548
diff changeset
187 return email.MIMEText.MIMEText(s, 'plain', cs)