commit 1be3efddc0a35e38a67712e65395179252e89aef Author: Isis Lovecruft isis@torproject.org Date: Thu Aug 28 10:55:30 2014 +0000
Refactor and update bridgedb.email package Sphinx documentation. --- lib/bridgedb/email/autoresponder.py | 109 +++++++++++++++++------------------ lib/bridgedb/email/dkim.py | 20 ++++--- lib/bridgedb/email/request.py | 7 ++- lib/bridgedb/email/server.py | 84 ++++++++++++++------------- lib/bridgedb/email/templates.py | 14 ++++- 5 files changed, 126 insertions(+), 108 deletions(-)
diff --git a/lib/bridgedb/email/autoresponder.py b/lib/bridgedb/email/autoresponder.py index aea8cae..44f4079 100644 --- a/lib/bridgedb/email/autoresponder.py +++ b/lib/bridgedb/email/autoresponder.py @@ -12,14 +12,15 @@ # :license: see LICENSE for licensing information #_____________________________________________________________________________
-"""Functionality for autoresponding to incoming emails. - +""" .. py:module:: bridgedb.email.autoresponder :synopsis: Functionality for autoresponding to incoming emails.
bridgedb.email.autoresponder ============================
+Functionality for autoresponding to incoming emails. + ::
bridgedb.email.autoresponder @@ -66,15 +67,16 @@ def createResponseBody(lines, context, client, lang='en'):
:param list lines: The list of lines from the original request sent by the client. - :type context: class:`MailServerContext` + :type context: class:`bridgedb.email.server.MailServerContext` :param context: The context which contains settings for the email server. :type client: :api:`twisted.mail.smtp.Address` :param client: The client's email address which should be in the - :header:`To:` header of the response email. + ``'To:'`` header of the response email. :param str lang: The 2-5 character locale code to use for translating the email. This is obtained from a client sending a email to a valid plus address which includes the translation desired, i.e. by sending an - email to ``bridges+fa@torproject.org``, the client should receive a + email to `bridges+fa@torproject.org + mailto:bridges+fa@torproject.org`__, the client should receive a response in Farsi. :rtype: None or str :returns: None if we shouldn't respond to the client (i.e., if they have @@ -136,21 +138,20 @@ def generateResponse(fromAddress, client, body, subject=None, the :header:`From:` header. :type client: :api:`twisted.mail.smtp.Address` :param client: The client's email address which should be in the - :header:`To:` header of the response email. - :param str subject: The string to write to the :header:`subject` header. + ``'To:'`` header of the response email. + :param str subject: The string to write to the ``Subject:'`` header. :param str body: The body of the email. If a **gpgContext** is also given, and that ``Context`` has email signing configured, then :meth:`EmailResponse.writeBody` will generate and include any ascii-armored OpenPGP signatures in the **body**. :type messageID: None or str - :param messageID: The :rfc:`2822` specifier for the :header:`Message-ID:` + :param messageID: The :rfc:`2822` specifier for the ``'Message-ID:'`` header, if including one is desirable. - :type gpgContext: None or ``gpgme.Context``. + :type gpgContext: None or ``gpgme.Context`` :param gpgContext: A pre-configured GPGME context. See - :func:`~crypto.getGPGContext`. - :rtype: :class:`EmailResponse` - :returns: A ``EmailResponse`` which contains the entire email. To obtain - the contents of the email, including all headers, simply use + :func:`~bridgedb.crypto.getGPGContext`. + :returns: An :class:`EmailResponse` which contains the entire email. To + obtain the contents of the email, including all headers, simply use :meth:`EmailResponse.readContents`. """ response = EmailResponse(gpgContext) @@ -180,20 +181,18 @@ class EmailResponse(object): keyfile, for example, rather than simply pasting it into the body of the email.)
- :type _buff: unicode or buffer - :cvar _buff: Used internally to write lines for the response email into - the ``_mailfile``. The reason why both of these attributes have two - possible types is for the same Python-buggy reasons which require - :data:`~bridgedb.crypto.NEW_BUFFER_INTERFACE`. - :type mailfile: :class:`io.StringIO` or :class:`io.BytesIO`. - :cvar mailfile: An in-memory file for storing the formatted headers and - body of the response email. - - :ivar str delimiter: Delimiter between lines written to the - :cvar:`mailfile`. - :ivar bool closed: ``True`` if :meth:`close` has been called. - :type to: :api:`twisted.mail.smtp.Address` - :ivar to: The client's email address which this response should be sent to. + :cvar _buff: (unicode or buffer) Used internally to write lines for the + response email into the ``_mailfile``. The reason why both of these + attributes have two possible types is for the same Python-buggy + reasons which require :data:`~bridgedb.crypto.NEW_BUFFER_INTERFACE`. + :cvar mailfile: (:class:`io.StringIO` or :class:`io.BytesIO`) An in-memory + file for storing the formatted headers and body of the response email. + + :var str delimiter: Delimiter between lines written to the + :data:`mailfile`. + :var bool closed: ``True`` if :meth:`close` has been called. + :var to: An :api:`twisted.mail.smtp.Address` for the client's email address + which this response should be sent to. """ _buff = buffer if NEW_BUFFER_INTERFACE else unicode mailfile = io.BytesIO if NEW_BUFFER_INTERFACE else io.StringIO @@ -202,7 +201,7 @@ class EmailResponse(object): """Create a response to an email we have recieved.
This class deals with correctly formatting text for the response email - headers and the response body into an instance of :cvar:`mailfile`. + headers and the response body into an instance of :data:`mailfile`.
:type gpgContext: None or ``gpgme.Context`` :param gpgContext: A pre-configured GPGME context. See @@ -219,20 +218,20 @@ class EmailResponse(object): self.to = None
def close(self): - """Close our :ivar:`mailfile` and set :ivar:`closed` to ``True``.""" + """Close our :data:`mailfile` and set :data:`closed` to ``True``.""" logging.debug("Closing %s.mailfile..." % (self.__class__.__name__)) self.mailfile.close() self.closed = True
def read(self, size=None): - """Read, at most, **size** bytes from our :ivar:`mailfile`. + """Read, at most, **size** bytes from our :data:`mailfile`.
.. note:: This method is required by Twisted's SMTP system.
:param int size: The number of bytes to read. Defaults to ``None``, which reads until EOF. :rtype: str - :returns: The bytes read from the :ivar:`mailfile`. + :returns: The bytes read from the :data:`mailfile`. """ contents = '' logging.debug("Reading%s from %s.mailfile..." @@ -249,12 +248,12 @@ class EmailResponse(object): return contents
def readContents(self): - """Read the all the contents written thus far to the :cvar:`mailfile`, + """Read the all the contents written thus far to the :data:`mailfile`, and then :meth:`seek` to return to the original pointer position we were at before this method was called.
:rtype: str - :returns: The entire contents of the :cvar:`mailfile`. + :returns: The entire contents of the :data:`mailfile`. """ pointer = self.mailfile.tell() self.mailfile.seek(0) @@ -263,17 +262,17 @@ class EmailResponse(object): return contents
def rewind(self): - """Rewind to the very beginning of the :cvar:`mailfile`.""" + """Rewind to the very beginning of the :data:`mailfile`.""" logging.debug("Rewinding %s.mailfile..." % self.__class__.__name__) self.mailfile.seek(0)
def write(self, line): - """Write the **line** to the :ivar:`mailfile`. + """Write the **line** to the :data:`mailfile`.
- Any **line** written to me will have :ivar:`delimiter` appended to it + Any **line** written to me will have :data:`delimiter` appended to it beforehand.
- :param str line: Something to append into the :ivar:`mailfile`. + :param str line: Something to append into the :data:`mailfile`. """ if line.find('\r\n') != -1: # If **line** contains newlines, send it to :meth:`writelines` to @@ -288,8 +287,8 @@ class EmailResponse(object): def writelines(self, lines): """Calls :meth:`write` for each line in **lines**.
- Line endings of ``'\r\n'`` will be replaced with :ivar:`delimiter` - (i.e. ``'\n'``). See :api:`twisted.mail.smtp.SMTPClient.getMailData` + Line endings of ``'\r\n'`` will be replaced with :data:`delimiter` + (i.e. ``'\n'``). See :api:`twisted.mail.smtp.SMTPClient.getMailData` for the reason.
:type lines: basestring or list @@ -308,17 +307,17 @@ class EmailResponse(object): contentType='text/plain; charset="utf-8"', **kwargs): """Write all headers into the response email.
- :param str fromAddress: The email address for the ``From:`` header. - :param str toAddress: The email address for the ``To:`` header. + :param str fromAddress: The email address for the ``'From:'`` header. + :param str toAddress: The email address for the ``'To:'`` header. :type subject: None or str - :param subject: The ``Subject:`` header. + :param subject: The ``'Subject:'`` header. :type inReplyTo: None or str - :param inReplyTo: If set, an ``In-Reply-To:`` header will be - generated. This should be set to the ``Message-ID:`` header from + :param inReplyTo: If set, an ``'In-Reply-To:'`` header will be + generated. This should be set to the ``'Message-ID:'`` header from the client's original request email. :param bool includeMessageID: If ``True``, generate and include a - ``Message-ID:`` header for the response. - :param str contentType: The ``Content-Type:`` header. + ``'Message-ID:'`` header for the response. + :param str contentType: The ``'Content-Type:'`` header. :kwargs: If given, the key will become the name of the header, and the value will become the Contents of that header. """ @@ -398,7 +397,7 @@ class SMTPAutoresponder(smtp.SMTPClient): """Gather all the data for building the response to the client.
This method must return a file-like object containing the data of the - message to be sent. Lines in the file should be delimited by '\n'. + message to be sent. Lines in the file should be delimited by ``\n``.
:rtype: ``None`` or :class:`EmailResponse` :returns: An ``EmailResponse``, if we have a response to send in reply @@ -438,7 +437,7 @@ class SMTPAutoresponder(smtp.SMTPClient):
:rtype: list :returns: A list containing the client's - :func:`normalized <addr.normalizeEmail>` email + :func:`normalized <bridgedb.parse.addr.normalizeEmail>` email :api:`Address <twisted.mail.smtp.Address>`, if it originated from a domain that we accept and the address was well-formed. Otherwise, returns ``None``. Even though we're likely to respond to only one @@ -604,19 +603,19 @@ class SMTPAutoresponder(smtp.SMTPClient): def runChecks(self, client): """Run checks on the incoming message, and only reply if they pass.
- 1. Check if the client's address is whitelisted. + 1. Check if the client's address is whitelisted.
- 2. If it's not whitelisted, check that the domain names, taken from + 2. If it's not whitelisted, check that the domain names, taken from the SMTP ``MAIL FROM:`` command and the email ``'From:'`` header, can be :func:`canonicalized <addr.canonicalizeEmailDomain>`.
- 3. Check that those canonical domains match. + 3. Check that those canonical domains match.
- 4. If the incoming message is from a domain which supports DKIM + 4. If the incoming message is from a domain which supports DKIM signing, then run :func:`bridgedb.email.dkim.checkDKIM` as well.
.. note:: Calling this method sets the ``canonicalFromEmail`` and - :ivar:``canonicalDomainRules`` attributes of the :ivar:`incoming` + :data:``canonicalDomainRules`` attributes of the :data:`incoming` message.
:param client: An :api:`twisted.mail.smtp.Address`, which contains @@ -687,7 +686,7 @@ class SMTPAutoresponder(smtp.SMTPClient): return True
def send(self, response, retries=0, timeout=30, reaktor=reactor): - """Send our **response** in reply to :ivar:`incoming`. + """Send our **response** in reply to :data:`incoming`.
:type client: :api:`twisted.mail.smtp.Address` :param client: The email address of the client. @@ -695,7 +694,7 @@ class SMTPAutoresponder(smtp.SMTPClient): :param int retries: Try resending this many times. (default: ``0``) :param int timeout: Timeout after this many seconds. (default: ``30``) :rtype: :api:`Deferred <twisted.internet.defer.Deferred>` - :returns: Our :ivar:`deferred`. + :returns: Our :data:`deferred`. """ logging.info("Sending reply to %s ..." % str(response.to))
diff --git a/lib/bridgedb/email/dkim.py b/lib/bridgedb/email/dkim.py index 9abcf3f..d797dbc 100644 --- a/lib/bridgedb/email/dkim.py +++ b/lib/bridgedb/email/dkim.py @@ -12,8 +12,7 @@ # :license: see LICENSE for licensing information #_____________________________________________________________________________
-"""Functions for checking DKIM verification results in email headers. - +""" .. py:module:: bridgedb.email.dkim :synopsis: Functions for checking DKIM verification results in email headers. @@ -21,6 +20,8 @@ bridgedb.email.dkim ===================
+Functions for checking DKIM verification results in email headers. + ::
bridgedb.email.dkim @@ -40,17 +41,20 @@ def checkDKIM(message, rules): a domain for which we're configured (in the ``EMAIL_DOMAIN_RULES`` dictionary in the config file) to check DKIM verification results for.
+ Returns ``False`` if: + + 1. We're supposed to expect and check the DKIM headers for the + client's email provider domain. + 2. Those headers were *not* okay. + + Otherwise, returns ``True``. + :type message: :api:`twisted.mail.smtp.rfc822.Message` :param message: The incoming client request email, including headers. :param dict rules: The list of configured ``EMAIL_DOMAIN_RULES`` for the canonical domain which the client's email request originated from. - :rtype: bool - :returns: ``False`` if: - 1. We're supposed to expect and check the DKIM headers for the - client's email provider domain. - 2. Those headers were *not* okay. - Otherwise, returns ``True``. + :returns: ``False`` if the checks failed, ``True`` otherwise. """ logging.info("Checking DKIM verification results...") logging.debug("Domain has rules: %s" % ', '.join(rules)) diff --git a/lib/bridgedb/email/request.py b/lib/bridgedb/email/request.py index 7a6e7cc..cd7b47d 100644 --- a/lib/bridgedb/email/request.py +++ b/lib/bridgedb/email/request.py @@ -12,9 +12,7 @@ # :license: see LICENSE for licensing information #_____________________________________________________________________________
-"""Classes for parsing and storing information about requests for bridges -which are sent to the email distributor. - +""" .. py:module:: bridgedb.email.request :synopsis: Classes for parsing and storing information about requests for bridges which are sent to the email distributor. @@ -22,6 +20,9 @@ which are sent to the email distributor. bridgedb.email.request ======================
+Classes for parsing and storing information about requests for bridges +which are sent to the email distributor. + ::
bridgedb.email.request diff --git a/lib/bridgedb/email/server.py b/lib/bridgedb/email/server.py index 625849d..110c381 100644 --- a/lib/bridgedb/email/server.py +++ b/lib/bridgedb/email/server.py @@ -13,8 +13,7 @@ #_____________________________________________________________________________
-"""Servers which interface with clients and distribute bridges over SMTP. - +""" .. py:module:: bridgedb.email.server :synopsis: Servers which interface with clients and distribute bridges over SMTP. @@ -22,6 +21,8 @@ bridgedb.email.server =====================
+Servers which interface with clients and distribute bridges over SMTP. + ::
bridgedb.email.server @@ -81,7 +82,7 @@ class MailServerContext(object): :ivar str smtpServer: The IP address to use for outgoing SMTP. :ivar str smtpFromAddr: Use this address in the raw SMTP ``MAIL FROM`` line for outgoing mail. (default: ``bridges@torproject.org``) - :ivar str fromAddr: Use this address in the email :header:`From:` + :ivar str fromAddr: Use this address in the email ``From:`` line for outgoing mail. (default: ``bridges@torproject.org``) :ivar int nBridges: The number of bridges to send for each email. :ivar list blacklist: A list of blacklisted email addresses, taken from @@ -98,12 +99,12 @@ class MailServerContext(object): """Create a context for storing configs for email bridge distribution.
:type config: :class:`bridgedb.persistent.Conf` - :type distributor: :class:`bridgedb.Dist.EmailBasedDistributor`. + :type distributor: :class:`bridgedb.Dist.EmailBasedDistributor` :param distributor: The distributor will handle getting the correct bridges (or none) for a client for us. - :type schedule: :class:`bridgedb.schedule.ScheduledInterval`. + :type schedule: :class:`bridgedb.schedule.ScheduledInterval` :param schedule: An interval-based scheduler, used to help the - :ivar:`distributor` know if we should give bridges to a client. + :data:`distributor` know if we should give bridges to a client. """ self.config = config self.distributor = distributor @@ -156,20 +157,23 @@ class MailServerContext(object): class SMTPMessage(object): """Plugs into the Twisted Mail and receives an incoming message.
- :ivar list lines: A list of lines from an incoming email message. - :ivar int nBytes: The number of bytes received thus far. - :ivar bool ignoring: If ``True``, we're ignoring the rest of this message - because it exceeded :ivar:`MailServerContext.maximumSize`. - :ivar canonicalFromSMTP: See :meth:`SMTPAutoresponder.runChecks`. - :ivar canonicalFromEmail: See :meth:`SMTPAutoresponder.runChecks`. - :ivar canonicalDomainRules: See :meth:`SMTPAutoresponder.runChecks`. - :type message: :api:`twisted.mail.smtp.rfc822.Message` or ``None`` - :ivar message: The incoming email message. - :type responder: :class:`autoresponder.SMTPAutoresponder` - :ivar responder: A parser and checker for the incoming :ivar:`message`. If - it decides to do so, it will build a - :meth:`~autoresponder.SMTPAutoresponder.reply` email and - :meth:`~autoresponder.SMTPAutoresponder.send` it. + :var list lines: A list of lines from an incoming email message. + :var int nBytes: The number of bytes received thus far. + :var bool ignoring: If ``True``, we're ignoring the rest of this message + because it exceeded :data:`MailServerContext.maximumSize`. + :var canonicalFromSMTP: See + :meth:`~bridgedb.email.autoresponder.SMTPAutoresponder.runChecks`. + :var canonicalFromEmail: See + :meth:`~bridgedb.email.autoresponder.SMTPAutoresponder.runChecks`. + :var canonicalDomainRules: See + :meth:`~bridgedb.email.autoresponder.SMTPAutoresponder.runChecks`. + :var message: (:api:`twisted.mail.smtp.rfc822.Message` or ``None``) The + incoming email message. + :var responder: A :class:`~bridgedb.email.autoresponder.SMTPAutoresponder` + which parses and checks the incoming :data:`message`. If it decides to + do so, it will build a + :meth:`~bridgedb.email.autoresponder.SMTPAutoresponder.reply` email + and :meth:`~bridgedb.email.autoresponder.SMTPAutoresponder.send` it. """ implements(smtp.IMessage)
@@ -219,7 +223,7 @@ class SMTPMessage(object): logging.exception(error)
def eomReceived(self): - """Tell the :ivar:`responder` to reply when we receive an EOM.""" + """Tell the :data:`responder` to reply when we receive an EOM.""" if not self.ignoring: self.message = self.getIncomingMessage() self.responder.reply() @@ -230,7 +234,7 @@ class SMTPMessage(object): pass
def getIncomingMessage(self): - """Create and parse an :rfc:`2822` message object for all :ivar:`lines` + """Create and parse an :rfc:`2822` message object for all :data:`lines` received thus far.
:rtype: :api:`twisted.mail.smtp.rfc822.Message` @@ -248,13 +252,13 @@ class SMTPIncomingDelivery(smtp.SMTP): for incoming connections.
:type context: :class:`MailServerContext` - :ivar context: A context containing SMTP/Email configuration settings. - :ivar deferred: A :api:`deferred <twisted.internet.defer.Deferred>` which + :var context: A context containing SMTP/Email configuration settings. + :var deferred: A :api:`deferred <twisted.internet.defer.Deferred>` which will be returned when :meth:`reply` is called. Additional callbacks may be set on this deferred in order to schedule additional actions when the response is being sent. :type fromCanonicalSMTP: str or ``None`` - :ivar fromCanonicalSMTP: If set, this is the canonicalized domain name of + :var fromCanonicalSMTP: If set, this is the canonicalized domain name of the address we received from incoming connection's ``MAIL FROM:``. """ implements(smtp.IMessageDelivery) @@ -265,7 +269,7 @@ class SMTPIncomingDelivery(smtp.SMTP):
@classmethod def setContext(cls, context): - """Set our :ivar:`context` to a new :class:`MailServerContext.""" + """Set our :data:`context` to a new :class:`MailServerContext`.""" cls.context = context
def receivedHeader(self, helo, origin, recipients): @@ -289,15 +293,15 @@ class SMTPIncomingDelivery(smtp.SMTP):
This is done at the SMTP layer. Meaning that if a Postfix or other email server is proxying emails from the outside world to BridgeDB, - the :api:`origin.domain <twisted.email.smtp.Address.domain` will be + the :api:`origin.domain <twisted.email.smtp.Address.domain>` will be set to the local hostname. Therefore, if the SMTP ``MAIL FROM:`` domain name is our own hostname (as returned from :func:`socket.gethostname`) or our own FQDN, allow the connection.
Otherwise, if the ``MAIL FROM:`` domain has a canonical domain in our - mapping (taken from :ivar:`context.canon <MailServerContext.canon>`, which - is taken in turn from the ``EMAIL_DOMAIN_MAP``), then our - :ivar:`fromCanonicalSMTP` is set to that domain. + mapping (taken from our :data:`context.canon`, which is taken in turn + from the ``EMAIL_DOMAIN_MAP``), then our :data:`fromCanonicalSMTP` is + set to that domain.
:type helo: tuple :param helo: The lines received during SMTP client HELO. @@ -381,7 +385,7 @@ class SMTPIncomingDelivery(smtp.SMTP):
class SMTPIncomingDeliveryFactory(object): - """Factory for :class:`SMTPIncomingDelivery`s. + """Factory for :class:`SMTPIncomingDelivery` s.
This class is used to distinguish between different messages delivered over the same connection. This can be used to optimize delivery of a @@ -389,8 +393,8 @@ class SMTPIncomingDeliveryFactory(object): :api:`IMessageDelivery <twisted.mail.smtp.IMessageDelivery>` implementors due to their lack of information.
- :ivar context: A :class:`MailServerContext` for storing configuration settings. - :ivar delivery: A :class:`SMTPIncomingDelivery` to deliver incoming + :var context: A :class:`MailServerContext` for storing configuration settings. + :var delivery: A :class:`SMTPIncomingDelivery` to deliver incoming SMTP messages to. """ implements(smtp.IMessageDeliveryFactory) @@ -403,7 +407,7 @@ class SMTPIncomingDeliveryFactory(object):
@classmethod def setContext(cls, context): - """Set our :ivar:`context` and the context for our :ivar:`delivery`.""" + """Set our :data:`context` and the context for our :data:`delivery`.""" cls.context = context cls.delivery.setContext(cls.context)
@@ -414,11 +418,11 @@ class SMTPIncomingDeliveryFactory(object):
class SMTPIncomingServerFactory(smtp.SMTPFactory): """Plugs into :api:`twisted.mail.smtp.SMTPFactory`; creates a new - :class:`SMTPMessageDelivery`, which handles response email automation, - whenever we get a incoming connection on the SMTP port. + :class:`SMTPIncomingDeliveryFactory`, which handles response email + automation whenever we get a incoming connection on the SMTP port.
- .. warning:: My :ivar:`context` isn't an OpenSSL context, as is used for - the :api:`twisted.mail.smtp.ESMTPSender` + .. warning:: My :data:`context` isn't an OpenSSL context, as is used for + the :api:`twisted.mail.smtp.ESMTPSender`.
:ivar context: A :class:`MailServerContext` for storing configuration settings. :ivar deliveryFactory: A :class:`SMTPIncomingDeliveryFactory` for @@ -440,7 +444,7 @@ class SMTPIncomingServerFactory(smtp.SMTPFactory):
@classmethod def setContext(cls, context): - """Set :ivar:`context` and :ivar:`deliveryFactory`.context.""" + """Set :data:`context` and :data:`deliveryFactory`.context.""" cls.context = context cls.deliveryFactory.setContext(cls.context)
@@ -456,7 +460,7 @@ def addServer(config, distributor, schedule): """Set up a SMTP server which listens on the configured ``EMAIL_PORT`` for incoming connections, and responds as necessary to requests for bridges.
- :type config: :class:`bridgedb.persistent.Conf` + :type config: :class:`bridgedb.configure.Conf` :param config: A configuration object. :type distributor: :class:`bridgedb.Dist.EmailBasedDistributor` :param dist: A distributor which will handle database interactions, and diff --git a/lib/bridgedb/email/templates.py b/lib/bridgedb/email/templates.py index e4d5389..dda9f65 100644 --- a/lib/bridgedb/email/templates.py +++ b/lib/bridgedb/email/templates.py @@ -10,14 +10,15 @@ # :license: see LICENSE for licensing information #_____________________________________________________________________________
-"""Templates for formatting emails sent out by the email distributor. - +""" .. py:module:: bridgedb.email.templates :synopsis: Templates for formatting emails sent out by the email distributor.
bridgedb.email.templates ======================== + +Templates for formatting emails sent out by the email distributor. """
from __future__ import print_function @@ -34,6 +35,9 @@ from bridgedb.HTTPServer import TEMPLATE_DIR
def addCommands(template): + """Add some text telling a client about supported email command, as well as + which Pluggable Transports are currently available. + """ # Tell them about the various email commands: cmdlist = [] cmdlist.append(template.gettext(strings.EMAIL_MISC_TEXT.get(3))) @@ -95,6 +99,12 @@ def addBridgeAnswer(template, answer): return bridgeLines
def addHowto(template): + """Add help text on how to add bridges to Tor Browser. + + :type template: ``gettext.NullTranslation`` or ``gettext.GNUTranslation`` + :param template: A gettext translations instance, optionally with fallback + languages set. + """ howToTBB = template.gettext(strings.HOWTO_TBB[1]) % strings.EMAIL_SPRINTF["HOWTO_TBB1"] howToTBB += u'\n\n' howToTBB += template.gettext(strings.HOWTO_TBB[2])
tor-commits@lists.torproject.org