Esempio n. 1
0
def get_following_arguments(i, option, input, key, command, name):
    if i + option.takes_argument >= len(input):
        raise ArgumentError(
            _n("--{0} needs an argument.", "--{0} needs {1} arguments.",
               option.takes_argument).format(key, option.takes_argument),
            command, name)

    if option.catchall:
        val_ = input[i + 1:]
    else:
        val_ = input[i + 1:i + option.takes_argument + 1]

    return len(val_), ' '.join(val_)
Esempio n. 2
0
def get_following_arguments(i, option, input, key, command, name):
    if i + option.takes_argument >= len(input):
        raise ArgumentError(
            _n("--{0} needs an argument.",
               "--{0} needs {1} arguments.",
               option.takes_argument)
            .format(key, option.takes_argument),
            command, name
            )

    if option.catchall:
        val_ = input[i+1:]
    else:
        val_ = input[
            i+1:i+option.takes_argument+1]

    return len(val_), ' '.join(val_)
Esempio n. 3
0
def SendMail(session, msg_mid, from_to_msg_ev_tuples):
    routes = _RouteTuples(session, from_to_msg_ev_tuples)

    # Randomize order of routes, so we don't always try the broken
    # one first. Any failure will bail out, but we do keep track of
    # our successes via. the event, so eventually everything sendable
    # should get sent.
    routes.sort(key=lambda k: random.randint(0, 10))

    # Update initial event state before we go through and start
    # trying to deliver stuff.
    for frm, sendmail, to, msg, events in routes:
        for ev in (events or []):
            for rcpt in to:
                ev.private_data['>'.join([frm, rcpt])] = False

    for frm, sendmail, to, msg, events in routes:
        for ev in events:
            ev.data['recipients'] = len(ev.private_data.keys())
            ev.data['delivered'] = len(
                [k for k in ev.private_data if ev.private_data[k]])

    def mark(msg, events, log=True):
        for ev in events:
            ev.flags = Event.RUNNING
            ev.message = msg
            if log:
                session.config.event_log.log_event(ev)
        session.ui.mark(msg)

    def fail(msg, events):
        mark(msg, events, log=True)
        for ev in events:
            ev.data['last_error'] = msg
        raise SendMailError(msg)

    def smtp_do_or_die(msg, events, method, *args, **kwargs):
        rc, msg = method(*args, **kwargs)
        if rc != 250:
            fail(msg + ' (%s %s)' % (rc, msg), events)

    # Do the actual delivering...
    for frm, sendmail, to, msg, events in routes:
        frm_vcard = session.config.vcards.get_vcard(frm)

        if 'sendmail' in session.config.sys.debug:
            sys.stderr.write(
                _('SendMail: from %s (%s), to %s via %s\n') %
                (frm, frm_vcard and frm_vcard.random_uid
                 or '', to, sendmail.split('@')[-1]))
        sm_write = sm_close = lambda: True

        mark(_('Connecting to %s') % sendmail.split('@')[-1], events)

        if sendmail.startswith('|'):
            sendmail %= {"rcpt": ",".join(to)}
            cmd = sendmail[1:].strip().split()
            proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
            sm_startup = None
            sm_write = proc.stdin.write

            def sm_close():
                proc.stdin.close()
                rv = proc.wait()
                if rv != 0:
                    fail(_('%s failed with exit code %d') % (cmd, rv), events)

            sm_cleanup = lambda: [proc.stdin.close(), proc.wait()]
            # FIXME: Update session UI with progress info
            for ev in events:
                ev.data['proto'] = 'subprocess'
                ev.data['command'] = cmd[0]

        elif (sendmail.startswith('smtp:') or sendmail.startswith('smtorp:')
              or sendmail.startswith('smtpssl:')
              or sendmail.startswith('smtptls:')):
            proto = sendmail.split(':', 1)[0]
            host, port = sendmail.split(':', 1)[1].replace('/',
                                                           '').rsplit(':', 1)
            smtp_ssl = proto in ('smtpssl', )  # FIXME: 'smtorp'
            if '@' in host:
                userpass, host = host.rsplit('@', 1)
                user, pwd = userpass.split(':', 1)
            else:
                user = pwd = None

            for ev in events:
                ev.data['proto'] = proto
                ev.data['host'] = host
                ev.data['auth'] = bool(user and pwd)

            if 'sendmail' in session.config.sys.debug:
                sys.stderr.write(
                    _('SMTP connection to: %s:%s as %s\n') %
                    (host, port, user or '(anon)'))

            server = (smtp_ssl and SMTP_SSL
                      or SMTP)(local_hostname='mailpile.local', timeout=25)

            def sm_startup():
                if 'sendmail' in session.config.sys.debug:
                    server.set_debuglevel(1)
                if proto == 'smtorp':
                    server.connect(host,
                                   int(port),
                                   socket_cls=session.config.get_tor_socket())
                else:
                    server.connect(host, int(port))
                if not smtp_ssl:
                    # We always try to enable TLS, even if the user just requested
                    # plain-text smtp.  But we only throw errors if the user asked
                    # for encryption.
                    try:
                        server.starttls()
                    except:
                        if sendmail.startswith('smtptls'):
                            raise InsecureSmtpError()
                if user and pwd:
                    try:
                        server.login(user, pwd)
                    except smtplib.SMTPAuthenticationError:
                        fail(_('Invalid username or password'), events)

                smtp_do_or_die(_('Sender rejected by SMTP server'), events,
                               server.mail, frm)
                for rcpt in to:
                    rc, msg = server.rcpt(rcpt)
                    if (rc == SMTORP_HASHCASH_RCODE
                            and msg.startswith(SMTORP_HASHCASH_PREFIX)):
                        rc, msg = server.rcpt(SMTorP_HashCash(rcpt, msg))
                    if rc != 250:
                        fail(_('Server rejected recpient: %s') % rcpt, events)
                rcode, rmsg = server.docmd('DATA')
                if rcode != 354:
                    fail(_('Server rejected DATA: %s %s') % (rcode, rmsg))

            def sm_write(data):
                for line in data.splitlines(True):
                    if line.startswith('.'):
                        server.send('.')
                    server.send(line)

            def sm_close():
                server.send('\r\n.\r\n')
                smtp_do_or_die(_('Error spooling mail'), events,
                               server.getreply)

            def sm_cleanup():
                if hasattr(server, 'sock'):
                    server.close()
        else:
            fail(_('Invalid sendmail command/SMTP server: %s') % sendmail)

        try:
            # Run the entire connect/login sequence in a single timer...
            if sm_startup:
                RunTimed(30, sm_startup)

            mark(_('Preparing message...'), events)
            msg_string = MessageAsString(CleanMessage(session.config, msg))
            total = len(msg_string)
            while msg_string:
                if mailpile.util.QUITTING:
                    raise TimedOut(_('Quitting'))
                mark(('Sending message... (%d%%)') %
                     (100 * (total - len(msg_string)) / total),
                     events,
                     log=False)
                RunTimed(20, sm_write, msg_string[:20480])
                msg_string = msg_string[20480:]
            RunTimed(10, sm_close)

            mark(
                _n('Message sent, %d byte', 'Message sent, %d bytes', total) %
                total, events)
            for ev in events:
                for rcpt in to:
                    vcard = session.config.vcards.get_vcard(rcpt)
                    if vcard:
                        vcard.record_history('send', time.time(), msg_mid)
                        if frm_vcard:
                            vcard.prefer_sender(rcpt, frm_vcard)
                        vcard.save()
                    ev.private_data['>'.join([frm, rcpt])] = True
                ev.data['bytes'] = total
                ev.data['delivered'] = len(
                    [k for k in ev.private_data if ev.private_data[k]])
        finally:
            sm_cleanup()
Esempio n. 4
0
def SendMail(session, msg_mid, from_to_msg_ev_tuples):
    routes = _RouteTuples(session, from_to_msg_ev_tuples)

    # Randomize order of routes, so we don't always try the broken
    # one first. Any failure will bail out, but we do keep track of
    # our successes via. the event, so eventually everything sendable
    # should get sent.
    routes.sort(key=lambda k: random.randint(0, 10))

    # Update initial event state before we go through and start
    # trying to deliver stuff.
    for frm, sendmail, to, msg, events in routes:
        for ev in (events or []):
            for rcpt in to:
                ev.private_data['>'.join([frm, rcpt])] = False

    for frm, sendmail, to, msg, events in routes:
        for ev in events:
            ev.data['recipients'] = len(ev.private_data.keys())
            ev.data['delivered'] = len([k for k in ev.private_data
                                        if ev.private_data[k]])

    def mark(msg, events, log=True):
        for ev in events:
            ev.flags = Event.RUNNING
            ev.message = msg
            if log:
                session.config.event_log.log_event(ev)
        session.ui.mark(msg)

    def fail(msg, events):
        mark(msg, events, log=True)
        for ev in events:
            ev.data['last_error'] = msg
        raise SendMailError(msg)

    def smtp_do_or_die(msg, events, method, *args, **kwargs):
        rc, msg = method(*args, **kwargs)
        if rc != 250:
           fail(msg + ' (%s %s)' % (rc, msg), events)

    # Do the actual delivering...
    for frm, sendmail, to, msg, events in routes:
        frm_vcard = session.config.vcards.get_vcard(frm)

        if 'sendmail' in session.config.sys.debug:
            sys.stderr.write(_('SendMail: from %s (%s), to %s via %s\n'
                               ) % (frm,
                                    frm_vcard and frm_vcard.random_uid or '',
                                    to, sendmail.split('@')[-1]))
        sm_write = sm_close = lambda: True

        mark(_('Connecting to %s') % sendmail.split('@')[-1], events)

        if sendmail.startswith('|'):
            sendmail %= {"rcpt": ",".join(to)}
            cmd = sendmail[1:].strip().split()
            proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
            sm_startup = None
            sm_write = proc.stdin.write
            def sm_close():
                proc.stdin.close()
                rv = proc.wait()
                if rv != 0:
                    fail(_('%s failed with exit code %d') % (cmd, rv), events)
            sm_cleanup = lambda: [proc.stdin.close(), proc.wait()]
            # FIXME: Update session UI with progress info
            for ev in events:
                ev.data['proto'] = 'subprocess'
                ev.data['command'] = cmd[0]

        elif (sendmail.startswith('smtp:') or
              sendmail.startswith('smtorp:') or
              sendmail.startswith('smtpssl:') or
              sendmail.startswith('smtptls:')):
            proto = sendmail.split(':', 1)[0]
            host, port = sendmail.split(':', 1
                                        )[1].replace('/', '').rsplit(':', 1)
            smtp_ssl = proto in ('smtpssl', )  # FIXME: 'smtorp'
            if '@' in host:
                userpass, host = host.rsplit('@', 1)
                user, pwd = userpass.split(':', 1)
            else:
                user = pwd = None

            for ev in events:
                ev.data['proto'] = proto
                ev.data['host'] = host
                ev.data['auth'] = bool(user and pwd)

            if 'sendmail' in session.config.sys.debug:
                sys.stderr.write(_('SMTP connection to: %s:%s as %s\n'
                                   ) % (host, port, user or '(anon)'))

            server = (smtp_ssl and SMTP_SSL or SMTP
                      )(local_hostname='mailpile.local', timeout=25)
            def sm_startup():
                if 'sendmail' in session.config.sys.debug:
                    server.set_debuglevel(1)
                if proto == 'smtorp':
                    server.connect(host, int(port),
                                   socket_cls=session.config.get_tor_socket())
                else:
                    server.connect(host, int(port))
                if not smtp_ssl:
                    # We always try to enable TLS, even if the user just requested
                    # plain-text smtp.  But we only throw errors if the user asked
                    # for encryption.
                    try:
                        server.starttls()
                    except:
                        if sendmail.startswith('smtptls'):
                            raise InsecureSmtpError()
                if user and pwd:
                    try:
                        server.login(user, pwd)
                    except smtplib.SMTPAuthenticationError:
                        fail(_('Invalid username or password'), events)

                smtp_do_or_die(_('Sender rejected by SMTP server'),
                               events, server.mail, frm)
                for rcpt in to:
                    rc, msg = server.rcpt(rcpt)
                    if (rc == SMTORP_HASHCASH_RCODE and
                            msg.startswith(SMTORP_HASHCASH_PREFIX)):
                        rc, msg = server.rcpt(SMTorP_HashCash(rcpt, msg))
                    if rc != 250:
                        fail(_('Server rejected recpient: %s') % rcpt, events)
                rcode, rmsg = server.docmd('DATA')
                if rcode != 354:
                    fail(_('Server rejected DATA: %s %s') % (rcode, rmsg))

            def sm_write(data):
                for line in data.splitlines(True):
                    if line.startswith('.'):
                        server.send('.')
                    server.send(line)

            def sm_close():
                server.send('\r\n.\r\n')
                smtp_do_or_die(_('Error spooling mail'),
                               events, server.getreply)

            def sm_cleanup():
                if hasattr(server, 'sock'):
                    server.close()
        else:
            fail(_('Invalid sendmail command/SMTP server: %s') % sendmail)

        try:
            # Run the entire connect/login sequence in a single timer...
            if sm_startup:
                RunTimed(30, sm_startup)

            mark(_('Preparing message...'), events)
            msg_string = MessageAsString(CleanMessage(session.config, msg))
            total = len(msg_string)
            while msg_string:
                if mailpile.util.QUITTING:
                    raise TimedOut(_('Quitting'))
                mark(('Sending message... (%d%%)'
                      ) % (100 * (total-len(msg_string))/total), events,
                     log=False)
                RunTimed(20, sm_write, msg_string[:20480])
                msg_string = msg_string[20480:]
            RunTimed(10, sm_close)

            mark(_n('Message sent, %d byte',
                    'Message sent, %d bytes',
                    total
                    ) % total, events)
            for ev in events:
                for rcpt in to:
                    vcard = session.config.vcards.get_vcard(rcpt)
                    if vcard:
                        vcard.record_history('send', time.time(), msg_mid)
                        if frm_vcard:
                            vcard.prefer_sender(rcpt, frm_vcard)
                        vcard.save()
                    ev.private_data['>'.join([frm, rcpt])] = True
                ev.data['bytes'] = total
                ev.data['delivered'] = len([k for k in ev.private_data
                                            if ev.private_data[k]])
        finally:
            sm_cleanup()
Esempio n. 5
0
def SendMail(session, msg_mid, from_to_msg_ev_tuples):
    routes = _RouteTuples(session, from_to_msg_ev_tuples)

    # Randomize order of routes, so we don't always try the broken
    # one first. Any failure will bail out, but we do keep track of
    # our successes via. the event, so eventually everything sendable
    # should get sent.
    routes.sort(key=lambda k: random.randint(0, 10))

    # Update initial event state before we go through and start
    # trying to deliver stuff.
    for frm, sendmail, to, msg, events in routes:
        for ev in (events or []):
            for rcpt in to:
                ev.private_data['>'.join([frm, rcpt])] = False

    for frm, sendmail, to, msg, events in routes:
        for ev in events:
            ev.data['recipients'] = len(ev.private_data.keys())
            ev.data['delivered'] = len([k for k in ev.private_data
                                        if ev.private_data[k]])

    def mark(msg, events, log=True):
        for ev in events:
            ev.flags = Event.RUNNING
            ev.message = msg
            if log:
                session.config.event_log.log_event(ev)
        session.ui.mark(msg)

    # Do the actual delivering...
    for frm, sendmail, to, msg, events in routes:

        if 'sendmail' in session.config.sys.debug:
            sys.stderr.write(_('SendMail: from %s, to %s via %s\n'
                               ) % (frm, to, sendmail))
        sm_write = sm_close = lambda: True

        mark(_('Connecting to %s') % sendmail, events)

        if sendmail.startswith('|'):
            sendmail %= {"rcpt": ",".join(to)}
            cmd = sendmail[1:].strip().split()
            proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
            sm_startup = None
            sm_write = proc.stdin.write
            sm_close = proc.stdin.close
            sm_cleanup = lambda: [sm_close(), proc.wait()]
            # FIXME: Update session UI with progress info
            for ev in events:
                ev.data['proto'] = 'subprocess'
                ev.data['command'] = cmd[0]

        elif (sendmail.startswith('smtp:') or
              sendmail.startswith('smtorp:') or
              sendmail.startswith('smtpssl:') or
              sendmail.startswith('smtptls:')):
            proto = sendmail.split(':', 1)[0]
            host, port = sendmail.split(':', 1
                                        )[1].replace('/', '').rsplit(':', 1)
            smtp_ssl = proto in ('smtpssl', )  # FIXME: 'smtorp'
            if '@' in host:
                userpass, host = host.rsplit('@', 1)
                user, pwd = userpass.split(':', 1)
            else:
                user = pwd = None

            for ev in events:
                ev.data['proto'] = proto
                ev.data['host'] = host
                ev.data['auth'] = bool(user and pwd)

            if 'sendmail' in session.config.sys.debug:
                sys.stderr.write(_('SMTP connection to: %s:%s as %s@%s\n'
                                   ) % (host, port, user, pwd))

            server = smtp_ssl and SMTP_SSL() or SMTP()
            def sm_startup():
                if proto == 'smtorp':
                    server.connect(host, int(port),
                                   socket_cls=session.config.get_tor_socket())
                else:
                    server.connect(host, int(port))
                server.ehlo()
                if not smtp_ssl:
                    # We always try to enable TLS, even if the user just requested
                    # plain-text smtp.  But we only throw errors if the user asked
                    # for encryption.
                    try:
                        server.starttls()
                        server.ehlo()
                    except:
                        if sendmail.startswith('smtptls'):
                            raise InsecureSmtpError()
                if user and pwd:
                    server.login(user, pwd)

                server.mail(frm)
                for rcpt in to:
                    server.rcpt(rcpt)
                server.docmd('DATA')

            def sm_write(data):
                for line in data.splitlines(True):
                    if line.startswith('.'):
                        server.send('.')
                    server.send(line)

            def sm_close():
                server.send('\r\n.\r\n')

            def sm_cleanup():
                if hasattr(server, 'sock'):
                    server.close()
        else:
            raise Exception(_('Invalid sendmail command/SMTP server: %s'
                              ) % sendmail)

        try:
            # Run the entire connect/login sequence in a single timer...
            if sm_startup:
                RunTimed(30, sm_startup)

            mark(_('Preparing message...'), events)
            msg_string = MessageAsString(CleanMessage(session.config, msg))
            total = len(msg_string)
            while msg_string:
                if mailpile.util.QUITTING:
                    raise TimedOut(_('Quitting'))
                mark(('Sending message... (%d%%)'
                      ) % (100 * (total-len(msg_string))/total), events,
                     log=False)
                RunTimed(20, sm_write, msg_string[:20480])
                msg_string = msg_string[20480:]
            RunTimed(10, sm_close)
            for ev in events:
                for rcpt in to:
                    vcard = session.config.vcards.get_vcard(rcpt)
                    if vcard:
                        vcard.record_history('send', time.time(), msg_mid)
                    ev.private_data['>'.join([frm, rcpt])] = True
                ev.data['bytes'] = total
                ev.data['delivered'] = len([k for k in ev.private_data
                                            if ev.private_data[k]])
            mark(_n('Message sent, %d byte',
                    'Message sent, %d bytes',
                    total
                    ) % total, events)
        finally:
            sm_cleanup()
Esempio n. 6
0
for dir in sys.argv [2:]:

    # eventually expand directories to their content
    if os.path.isdir (dir):
        files = map (lambda x, dir = dir: \
                     os.path.join (dir, x), os.listdir (dir))

        # in the case of a directory, use only .bib extension...
        files = filter (lambda f: os.path.splitext (f) [1] == '.bib',
                        files)
    else:
        files = [dir]


    # loop over the files
    for f in files:
        # try to open the database
        try:
            b = bibopen (f)
            print (_n(u"file “%s” is ok [%d entry]",
                      u"file “%s” is ok [%d entries]",
                      len(b))
                   % (f, len (b))).encode(charset)
        except (Exceptions.ParserError, KeyError), err:
            broken.append (str (err))

# write the error messages (expected to be well formated)
if len (broken) > 0:
    print string.join (broken, "\n")
    sys.exit (1)
Esempio n. 7
0
def SendMail(session, from_to_msg_ev_tuples):
    routes = _RouteTuples(session, from_to_msg_ev_tuples)

    # Randomize order of routes, so we don't always try the broken
    # one first. Any failure will bail out, but we do keep track of
    # our successes via. the event, so eventually everything sendable
    # should get sent.
    routes.sort(key=lambda k: random.randint(0, 10))

    # Update initial event state before we go through and start
    # trying to deliver stuff.
    for frm, sendmail, to, msg, events in routes:
        for ev in (events or []):
            for rcpt in to:
                ev.private_data['>'.join([frm, rcpt])] = False

    for frm, sendmail, to, msg, events in routes:
        for ev in events:
            ev.data['recipients'] = len(ev.private_data.keys())
            ev.data['delivered'] = len(
                [k for k in ev.private_data if ev.private_data[k]])

    def mark(msg, events, log=True):
        for ev in events:
            ev.flags = Event.RUNNING
            ev.message = msg
            if log:
                session.config.event_log.log_event(ev)
        session.ui.mark(msg)

    # Do the actual delivering...
    for frm, sendmail, to, msg, events in routes:

        if 'sendmail' in session.config.sys.debug:
            sys.stderr.write(
                _('SendMail: from %s, to %s via %s\n') % (frm, to, sendmail))
        sm_write = sm_close = lambda: True

        mark(_('Connecting to %s') % sendmail, events)

        if sendmail.startswith('|'):
            sendmail %= {"rcpt": ",".join(to)}
            cmd = sendmail[1:].strip().split()
            proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
            sm_startup = None
            sm_write = proc.stdin.write
            sm_close = proc.stdin.close
            sm_cleanup = lambda: [sm_close(), proc.wait()]
            # FIXME: Update session UI with progress info
            for ev in events:
                ev.data['proto'] = 'subprocess'
                ev.data['command'] = cmd[0]

        elif (sendmail.startswith('smtp:') or sendmail.startswith('smtorp:')
              or sendmail.startswith('smtpssl:')
              or sendmail.startswith('smtptls:')):
            proto = sendmail.split(':', 1)[0]
            host, port = sendmail.split(':', 1)[1].replace('/',
                                                           '').rsplit(':', 1)
            smtp_ssl = proto in ('smtpssl', )  # FIXME: 'smtorp'
            if '@' in host:
                userpass, host = host.rsplit('@', 1)
                user, pwd = userpass.split(':', 1)
            else:
                user = pwd = None

            for ev in events:
                ev.data['proto'] = proto
                ev.data['host'] = host
                ev.data['auth'] = bool(user and pwd)

            if 'sendmail' in session.config.sys.debug:
                sys.stderr.write(
                    _('SMTP connection to: %s:%s as %s@%s\n') %
                    (host, port, user, pwd))

            server = smtp_ssl and SMTP_SSL() or SMTP()

            def sm_startup():
                if proto == 'smtorp':
                    server.connect(host,
                                   int(port),
                                   socket_cls=session.config.get_tor_socket())
                else:
                    server.connect(host, int(port))
                server.ehlo()
                if not smtp_ssl:
                    # We always try to enable TLS, even if the user just requested
                    # plain-text smtp.  But we only throw errors if the user asked
                    # for encryption.
                    try:
                        server.starttls()
                        server.ehlo()
                    except:
                        if sendmail.startswith('smtptls'):
                            raise InsecureSmtpError()
                if user and pwd:
                    server.login(user, pwd)

                server.mail(frm)
                for rcpt in to:
                    server.rcpt(rcpt)
                server.docmd('DATA')

            def sm_write(data):
                for line in data.splitlines(True):
                    if line.startswith('.'):
                        server.send('.')
                    server.send(line)

            def sm_close():
                server.send('\r\n.\r\n')

            def sm_cleanup():
                if hasattr(server, 'sock'):
                    server.close()
        else:
            raise Exception(
                _('Invalid sendmail command/SMTP server: %s') % sendmail)

        try:
            # Run the entire connect/login sequence in a single timer...
            if sm_startup:
                RunTimed(30, sm_startup)

            mark(_('Preparing message...'), events)
            msg_string = MessageAsString(CleanMessage(session.config, msg))
            total = len(msg_string)
            while msg_string:
                if mailpile.util.QUITTING:
                    raise TimedOut(_('Quitting'))
                mark(('Sending message... (%d%%)') %
                     (100 * (total - len(msg_string)) / total),
                     events,
                     log=False)
                RunTimed(20, sm_write, msg_string[:20480])
                msg_string = msg_string[20480:]
            RunTimed(10, sm_close)
            for ev in events:
                for rcpt in to:
                    ev.private_data['>'.join([frm, rcpt])] = True
                ev.data['bytes'] = total
                ev.data['delivered'] = len(
                    [k for k in ev.private_data if ev.private_data[k]])
            mark(
                _n('Message sent, %d byte', 'Message sent, %d bytes', total) %
                total, events)
        finally:
            sm_cleanup()