%PDF- %PDF-
Direktori : /proc/thread-self/root/usr/lib/calibre/calibre/gui2/wizard/ |
Current File : //proc/thread-self/root/usr/lib/calibre/calibre/gui2/wizard/send_email.py |
#!/usr/bin/env python3 __license__ = 'GPL v3' __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>' __docformat__ = 'restructuredtext en' import sys from functools import partial from threading import Thread from qt.core import ( QWidget, pyqtSignal, QDialog, Qt, QLabel, QLineEdit, QDialogButtonBox, QGridLayout, QCheckBox, QIcon, QVBoxLayout, QPushButton, QPlainTextEdit, QHBoxLayout) from calibre import prints from calibre.gui2.wizard.send_email_ui import Ui_Form from calibre.utils.smtp import config as smtp_prefs from calibre.gui2 import error_dialog, question_dialog from polyglot.binary import as_hex_unicode, from_hex_unicode from polyglot.io import PolyglotStringIO class TestEmail(QDialog): test_done = pyqtSignal(object) def __init__(self, pa, parent): QDialog.__init__(self, parent) self.test_func = parent.test_email_settings self.setWindowTitle(_("Test email settings")) self.setWindowIcon(QIcon(I('config.ui'))) l = QVBoxLayout(self) opts = smtp_prefs().parse() self.from_ = la = QLabel(_("Send test mail from %s to:")%opts.from_) l.addWidget(la) self.to = le = QLineEdit(self) if pa: self.to.setText(pa) self.test_button = b = QPushButton(_('&Test'), self) b.clicked.connect(self.start_test) self.test_done.connect(self.on_test_done, type=Qt.ConnectionType.QueuedConnection) self.h = h = QHBoxLayout() h.addWidget(le), h.addWidget(b) l.addLayout(h) if opts.relay_host: self.la = la = QLabel(_('Using: %(un)s:%(pw)s@%(host)s:%(port)s and %(enc)s encryption')% dict(un=opts.relay_username, pw=from_hex_unicode(opts.relay_password), host=opts.relay_host, port=opts.relay_port, enc=opts.encryption)) l.addWidget(la) self.log = QPlainTextEdit(self) l.addWidget(self.log) self.bb = bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) bb.rejected.connect(self.reject), bb.accepted.connect(self.accept) l.addWidget(bb) def start_test(self, *args): if not self.to.text().strip(): return error_dialog(self, _('No email address'), _( 'No email address to send mail to has been specified. You' ' must specify a To: address before running the test.'), show=True) self.log.setPlainText(_('Sending email, please wait...')) self.test_button.setEnabled(False) t = Thread(target=self.run_test, name='TestEmailSending') t.daemon = True t.start() def run_test(self): from email.utils import parseaddr q = self.to.text().strip() addr = parseaddr(q)[-1] if not addr or '@' not in q: tb = f'{self.to.text().strip()} is not a valid email address' else: try: tb = self.test_func(addr) or _('Email successfully sent') except Exception: import traceback tb = traceback.format_exc() self.test_done.emit(tb) def on_test_done(self, txt): if self.isVisible(): self.test_button.setEnabled(True) self.log.setPlainText(txt) class RelaySetup(QDialog): def __init__(self, service, parent): QDialog.__init__(self, parent) self.l = l = QGridLayout() self.setLayout(l) self.bb = bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok|QDialogButtonBox.StandardButton.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) self.tl = QLabel(('<p>'+_('Setup sending email using') + ' <b>{name}</b><p>' + _('If you don\'t have an account, you can sign up for a free {name} email ' 'account at <a href="https://{url}">{url}</a>. {extra}')).format( **service)) l.addWidget(self.tl, 0, 0, 3, 0) self.tl.setWordWrap(True) self.tl.setOpenExternalLinks(True) for name, label in ( ['from_', _('Your %s &email address:')], ['password', _('Your %s &password:')], ): la = QLabel(label%service['name']) le = QLineEdit(self) setattr(self, name, le) setattr(self, name+'_label', la) r = l.rowCount() l.addWidget(la, r, 0) l.addWidget(le, r, 1) la.setBuddy(le) if name == 'password': self.ptoggle = QCheckBox(_('&Show password'), self) l.addWidget(self.ptoggle, r, 2) self.ptoggle.stateChanged.connect( lambda s: self.password.setEchoMode(QLineEdit.EchoMode.Normal if s == Qt.CheckState.Checked else QLineEdit.EchoMode.Password)) self.password.setEchoMode(QLineEdit.EchoMode.Password) self.bl = QLabel('<p>' + _( 'If you plan to use email to send books to your Kindle, remember to' ' add your %s email address to the allowed email addresses in your ' 'Amazon.com Kindle management page.')%service['name']) self.bl.setWordWrap(True) l.addWidget(self.bl, l.rowCount(), 0, 3, 0) l.addWidget(bb, l.rowCount(), 0, 3, 0) self.setWindowTitle(_('Setup') + ' ' + service['name']) self.resize(self.sizeHint()) self.service = service @property def service_username(self): na = self.from_.text() from email.utils import parseaddr addr = parseaddr(na)[-1] if not addr or '@' not in na: return '' return addr def accept(self): pw = self.password.text() if not pw: return error_dialog(self, _('No password'), _( 'You must specify a password'), show=True) fr = self.from_.text().strip() if not fr: return error_dialog(self, _('No email address'), _( 'You must specify an email address'), show=True) un = self.service_username if not un: return error_dialog(self, _('Incorrect email address'), _( 'The email address "{}" is not valid').format(self.from_.text()), show=True) QDialog.accept(self) class SendEmail(QWidget, Ui_Form): changed_signal = pyqtSignal() def __init__(self, parent=None): QWidget.__init__(self, parent) self.setupUi(self) def initialize(self, preferred_to_address): self.preferred_to_address = preferred_to_address opts = smtp_prefs().parse() self.smtp_opts = opts if opts.from_: self.email_from.setText(opts.from_) self.email_from.textChanged.connect(self.changed) if opts.relay_host: self.relay_host.setText(opts.relay_host) self.relay_host.textChanged.connect(self.changed) self.relay_port.setValue(opts.relay_port) self.relay_port.valueChanged.connect(self.changed) if opts.relay_username: self.relay_username.setText(opts.relay_username) self.relay_username.textChanged.connect(self.changed) if opts.relay_password: self.relay_password.setText(from_hex_unicode(opts.relay_password)) self.relay_password.textChanged.connect(self.changed) getattr(self, 'relay_'+opts.encryption.lower()).setChecked(True) self.relay_tls.toggled.connect(self.changed) for x in ('gmx', 'hotmail'): button = getattr(self, 'relay_use_'+x) button.clicked.connect(partial(self.create_service_relay, x)) self.relay_show_password.stateChanged.connect( lambda state : self.relay_password.setEchoMode( QLineEdit.EchoMode.Password if state == 0 else QLineEdit.EchoMode.Normal)) self.test_email_button.clicked.connect(self.test_email) def changed(self, *args): self.changed_signal.emit() def test_email(self, *args): pa = self.preferred_to_address() to_set = pa is not None if self.set_email_settings(to_set): opts = smtp_prefs().parse() if not opts.relay_password or question_dialog(self, _('OK to proceed?'), _('This will display your email password on the screen' '. Is it OK to proceed?'), show_copy_button=False): TestEmail(pa, self).exec() def test_email_settings(self, to): opts = smtp_prefs().parse() from calibre.utils.smtp import sendmail, create_mail buf = PolyglotStringIO() debug_out = partial(prints, file=buf) oout, oerr = sys.stdout, sys.stderr sys.stdout = sys.stderr = buf tb = None try: msg = create_mail(opts.from_, to, 'Test mail from calibre', 'Test mail from calibre') sendmail(msg, from_=opts.from_, to=[to], verbose=3, timeout=30, relay=opts.relay_host, username=opts.relay_username, debug_output=debug_out, password=from_hex_unicode(opts.relay_password), encryption=opts.encryption, port=opts.relay_port) except: import traceback tb = traceback.format_exc() tb += '\n\nLog:\n' + buf.getvalue() finally: sys.stdout, sys.stderr = oout, oerr return tb def create_service_relay(self, service, *args): service = { 'gmx': { 'name': 'GMX', 'relay': 'mail.gmx.com', 'port': 587, 'username': '@gmx.com', 'url': 'www.gmx.com', 'extra': _('Before using this account to send mail, you must enable the' ' "Enable access to this account via POP3 and IMAP" option in GMX' ' under More > E-mail Settings > POP3 & IMAP.'), 'at_in_username': True, }, 'gmail': { 'name': 'Gmail', 'relay': 'smtp.gmail.com', 'port': 587, 'username': '@gmail.com', 'url': 'www.gmail.com', 'extra': _( 'Google recently deliberately broke their email sending protocol (SMTP) support in' ' an attempt to force everyone to use their web interface so they can' ' show you more ads. They are trying to claim that SMTP is insecure,' ' that is incorrect and simply an excuse. To use a Gmail account' ' you will need to "allow less secure apps" as described' ' <a href="https://support.google.com/accounts/answer/6010255">here</a>.'), 'at_in_username': True, }, 'hotmail': { 'name': 'Outlook', 'relay': 'smtp-mail.outlook.com', 'port': 587, 'username': '@outlook.com', 'url': 'outlook.live.com/owa/', 'extra': _('If you are setting up a new' ' Outlook account, Microsoft requires that you ' ' verify your account periodically, before it' ' will let calibre send email.'), 'at_in_username': True, } }[service] d = RelaySetup(service, self) if d.exec() != QDialog.DialogCode.Accepted: return self.relay_username.setText(d.service_username) self.relay_password.setText(d.password.text()) self.email_from.setText(d.from_.text()) self.relay_host.setText(service['relay']) self.relay_port.setValue(service['port']) self.relay_tls.setChecked(True) def set_email_settings(self, to_set): from_ = str(self.email_from.text()).strip() if to_set and not from_: error_dialog(self, _('Bad configuration'), _('You must set the From email address')).exec() return False username = str(self.relay_username.text()).strip() password = str(self.relay_password.text()).strip() host = str(self.relay_host.text()).strip() enc_method = ('TLS' if self.relay_tls.isChecked() else 'SSL' if self.relay_ssl.isChecked() else 'NONE') if host: # Validate input if ((username and not password) or (not username and password)): error_dialog(self, _('Bad configuration'), _('You must either set both the username <b>and</b> password for ' 'the mail server or no username and no password at all.')).exec() return False if not (username and password) and not question_dialog( self, _('Are you sure?'), _('No username and password set for mailserver. Most ' ' mailservers need a username and password. Are you sure?')): return False conf = smtp_prefs() conf.set('from_', from_) conf.set('relay_host', host if host else None) conf.set('relay_port', self.relay_port.value()) conf.set('relay_username', username if username else None) conf.set('relay_password', as_hex_unicode(password)) conf.set('encryption', enc_method) return True