[tor-commits] [gettor/master] New file structure

ilv at torproject.org ilv at torproject.org
Tue Sep 22 23:39:11 UTC 2015


commit e69c33647c6c352c240647b7a8fdc096c86a2d53
Author: ilv <ilv at users.noreply.github.com>
Date:   Fri Aug 1 20:32:13 2014 -0400

    New file structure
---
 src/core.cfg   |   11 ++
 src/gettor.cfg |   11 --
 src/gettor.py  |  445 -------------------------------------------------
 src/smtp.py    |  504 --------------------------------------------------------
 4 files changed, 11 insertions(+), 960 deletions(-)

diff --git a/src/core.cfg b/src/core.cfg
new file mode 100644
index 0000000..3492681
--- /dev/null
+++ b/src/core.cfg
@@ -0,0 +1,11 @@
+[general]
+basedir: ./
+
+[links]
+dir: providers/
+os: linux, windows, osx
+locales: es, en
+
+[log]
+dir:  log/
+level: DEBUG
diff --git a/src/gettor.cfg b/src/gettor.cfg
deleted file mode 100644
index 3492681..0000000
--- a/src/gettor.cfg
+++ /dev/null
@@ -1,11 +0,0 @@
-[general]
-basedir: ./
-
-[links]
-dir: providers/
-os: linux, windows, osx
-locales: es, en
-
-[log]
-dir:  log/
-level: DEBUG
diff --git a/src/gettor.py b/src/gettor.py
deleted file mode 100644
index a71a062..0000000
--- a/src/gettor.py
+++ /dev/null
@@ -1,445 +0,0 @@
-import os
-import re
-import inspect
-import logging
-import tempfile
-import ConfigParser
-
-"""
-    GetTor main module.
-
-    Classes:
-        SingleLevelFilter: Filter logging levels.
-        Core: Get links from providers.
-
-    Methods:
-        SingleLevelFilter.filter(): Filter logging levels. All except
-                                    the one specified will be filtered.
-
-        Core.get_links(): Get the links. It throws ValueError and
-                          RuntimeError on failure.
-
-        Core.create_links_file(): Create a file to store links of a given
-                                  provider.
-
-        Core.add_link(): Add a link to a links file of a given provider.
-
-    Exceptions:
-        ValueError: Request for an unsupported locale/operating system.
-        RuntimeError: Something went wrong internally.
-"""
-
-
-class SingleLevelFilter(logging.Filter):
-    """
-        Filter logging levels to create separated logs.
-
-        Public methods:
-            filter(record)
-    """
-
-    def __init__(self, passlevel, reject):
-        """
-            Initialize a new object with level to be filtered.
-
-            If reject value is false, all but the passlevel will be
-            filtered. Useful for logging in separated files.
-        """
-
-        self.passlevel = passlevel
-        self.reject = reject
-
-    def filter(self, record):
-        """
-            Do the actual filtering.
-        """
-        if self.reject:
-            return (record.levelno != self.passlevel)
-        else:
-            return (record.levelno == self.passlevel)
-
-
-class Core(object):
-    """
-        Gets links from providers and delivers them to other modules.
-
-        Public methods:
-            get_links(operating_system, locale)
-    """
-
-    def __init__(self, config_file):
-    	"""
-            Initialize a new object by reading a configuration file.
-
-            Raises a RuntimeError if the configuration file doesn't exists
-            or if something goes wrong while reading options from it.
-
-            Arguments:
-                config_file: path for the configuration file
-        """
-
-        logging.basicConfig(format='[%(levelname)s] %(asctime)s - %(message)s',
-                            datefmt="%Y-%m-%d %H:%M:%S")
-        logger = logging.getLogger(__name__)
-        config = ConfigParser.ConfigParser()
-
-        if os.path.isfile(config_file):
-            logger.info("Reading configuration from %s" % config_file)
-            config.read(config_file)
-        else:
-            logger.error("Error while trying to read %s" % config_file)
-            raise RuntimeError("Couldn't read the configuration file %s"
-                               % config_file)
-
-        # Handle the gets internally to catch proper exceptions
-        try:
-            self.basedir = self._get_config_option('general',
-                                                   'basedir', config)
-        except RuntimeError as e:
-            logger.warning("%s misconfigured. %s" % (config_file, str(e)))
-        try:
-            self.linksdir = self._get_config_option('links', 'dir', config)
-            self.linksdir = os.path.join(self.basedir, self.linksdir)
-        except RuntimeError as e:
-            logger.warning("%s misconfigured. %s" % (config_file, str(e)))
-
-        try:
-            self.supported_locales = self._get_config_option('links',
-                                                             'locales',
-                                                             config)
-        except RuntimeError as e:
-            logger.warning("%s misconfigured. %s" % (config_file, str(e)))
-
-        try:
-            self.supported_os = self._get_config_option('links', 'os', config)
-        except RuntimeError as e:
-            logger.warning("%s misconfigured. %s" % (config_file, str(e)))
-
-        try:
-            self.loglevel = self._get_config_option('log', 'level', config)
-        except RuntimeError as e:
-            logger.warning("%s misconfigured. %s" % (config_file, str(e)))
-
-        try:
-            self.logdir = self._get_config_option('log', 'dir', config)
-            self.logdir = os.path.join(self.basedir, self.logdir)
-        except RuntimeError as e:
-            logger.warning("%s misconfigured. %s" % (config_file, str(e)))
-
-        # Better log format
-        string_format = '[%(levelname)7s] %(asctime)s - %(message)s'
-        formatter = logging.Formatter(string_format, '%Y-%m-%d %H:%M:%S')
-
-        # Keep logs separated (and filtered)
-        # all.log depends on level specified on configuration file
-        all_log = logging.FileHandler(os.path.join(self.logdir, 'all.log'),
-                                      mode='a+')
-        all_log.setLevel(logging.getLevelName(self.loglevel))
-        all_log.setFormatter(formatter)
-
-        debug_log = logging.FileHandler(os.path.join(self.logdir, 'debug.log'),
-                                        mode='a+')
-        debug_log.setLevel('DEBUG')
-        debug_log.addFilter(SingleLevelFilter(logging.DEBUG, False))
-        debug_log.setFormatter(formatter)
-
-        info_log = logging.FileHandler(os.path.join(self.logdir, 'info.log'),
-                                       mode='a+')
-        info_log.setLevel('INFO')
-        info_log.addFilter(SingleLevelFilter(logging.INFO, False))
-        info_log.setFormatter(formatter)
-
-        warn_log = logging.FileHandler(os.path.join(self.logdir, 'warn.log'),
-                                       mode='a+')
-        warn_log.setLevel('WARNING')
-        warn_log.addFilter(SingleLevelFilter(logging.WARNING, False))
-        warn_log.setFormatter(formatter)
-
-        error_log = logging.FileHandler(os.path.join(self.logdir, 'error.log'),
-                                        mode='a+')
-        error_log.setLevel('ERROR')
-        error_log.addFilter(SingleLevelFilter(logging.ERROR, False))
-        error_log.setFormatter(formatter)
-
-        logger.addHandler(all_log)
-        logger.addHandler(info_log)
-        logger.addHandler(debug_log)
-        logger.addHandler(warn_log)
-        logger.addHandler(error_log)
-
-        self.logger = logger
-        self.logger.setLevel(logging.getLevelName(self.loglevel))
-        logger.info('Redirecting logging to %s' % self.logdir)
-
-        # Stop logging on stdout from now on
-        logger.propagate = False
-        self.logger.debug("New core object created")
-
-    def get_links(self, service, operating_system, locale):
-        """
-            Public method to obtain links.
-
-            Checks for supported locales and operating systems. It returns
-            ValueError if the locale or operating system is not supported.
-            It raises RuntimeError if something goes wrong while trying
-            to obtain the links. It returns a string on success. This
-            method should be called from the services modules of GetTor
-            (e.g. SMTP).
-        """
-
-        # Which module called us and what was asking for?
-        self.logger.info("%s did a request for %s, %s." %
-                         (service, operating_system, locale))
-
-        if locale not in self.supported_locales:
-            self.logger.warning("Request for unsupported locale: %s" % locale)
-            raise ValueError("Locale %s not supported at the moment" % locale)
-
-        if operating_system not in self.supported_os:
-            self.logger.warning("Request for unsupported operating system: %s"
-                                % operating_system)
-            raise ValueError("Operating system %s not supported at the moment"
-                             % operating_system)
-
-        # This could change in the future, let's leave it isolated.
-        links = self._get_links(operating_system, locale)
-
-        if links is None:
-            self.logger.error("Couldn't get the links", exc_info=True)
-            raise RuntimeError("Something went wrong internally. See logs for \
-                                detailed info.")
-
-        self.logger.info("Returning the links")
-        return links
-
-    def _get_links(self, operating_system, locale):
-        """
-            Private method to obtain the links.
-
-            Looks for the links inside each provider file. On success
-            returns a string with the links. On failure returns None.
-            This should only be called from get_links() method.
-
-            Parameters:
-                os: string describing the operating system
-                locale: string describing the locale
-        """
-
-        # Read the links files using ConfigParser
-        # See the README for more details on the format used
-        links = []
-
-        # Look for files ending with .links
-        p = re.compile('.*\.links$')
-
-        for name in os.listdir(self.linksdir):
-            path = os.path.abspath(os.path.join(self.linksdir, name))
-            if os.path.isfile(path) and p.match(path):
-                links.append(path)
-
-        # Let's create a dictionary linking each provider with the links
-        # found for operating_system and locale. This way makes it easy
-        # to check if no links were found.
-        providers = {}
-
-        self.logger.info("Reading links from providers directory")
-        for name in links:
-            self.logger.debug("-- Reading %s" % name)
-            # We're reading files listed on linksdir, so they must exist!
-            config = ConfigParser.ConfigParser()
-            config.read(name)
-
-            try:
-                pname = self._get_config_option('provider',
-                                                'name', config)
-            except RuntimeError as e:
-                self.logger.warning("Links misconfiguration %s" % str(e))
-
-            self.logger.debug("-- Checking if %s has links for %s in %s" %
-                              (pname, operating_system, locale))
-
-            try:
-                providers[pname] = self._get_config_option(operating_system,
-                                                           locale, config)
-            except RuntimeError as e:
-                self.logger.warning("-- Links misconfiguration %s" % str(e))
-
-            # Each provider must have a fingerprint of the key used to
-            # sign the uploaded packages
-            try:
-                self.logger.debug("-- Trying to get fingerprint from %s",
-                                  pname)
-                fingerprint = self._get_config_option('key', 'fingerprint',
-                                                      config)
-                providers[pname] = providers[pname] + "\nFingerprint: "
-                providers[pname] = providers[pname] + fingerprint
-                self.logger.debug("-- Fingerprint added %s", fingerprint)
-            except ValueError as e:
-                self.logger.warning("-- No fingerprint found for provider %s" %
-                                    pname)
-
-        # Create the final links list with all providers
-        all_links = []
-
-        self.logger.debug("Joining all links found for %s in %s" %
-                          (operating_system, locale))
-        for key in providers.keys():
-            all_links.append(
-                "\n%s\n%s\n" % (key, ''.join(providers[key]))
-            )
-
-        if all_links:
-            return "".join(all_links)
-        else:
-            self.logger.warning("Trying to get supported os and locales, but \
-                                 no links were found")
-            return None
-
-    def get_supported_os(self):
-        """
-            Public method to obtain the list of supported operating systems
-
-            Returns a list of strings
-        """
-        return self.supported_os.split(',')
-
-    def _get_config_option(self, section, option, config):
-        """
-            Private method to get configuration options.
-
-            It tries to obtain a value from a section in config using
-            ConfigParser. It catches possible exceptions and raises
-            RuntimeError if something goes wrong.
-
-            Arguments:
-                config: ConfigParser object
-                section: section inside config
-                option: option inside section
-
-            Returns the value of the option inside the section in the
-            config object.
-        """
-
-        try:
-            value = config.get(section, option)
-            return value
-        # This exceptions should appear when messing with the configuration
-        except (ConfigParser.NoSectionError,
-                ConfigParser.NoOptionError,
-                ConfigParser.InterpolationError,
-                ConfigParser.MissingSectionHeaderError,
-                ConfigParser.ParsingError) as e:
-            raise RuntimeError("%s" % str(e))
-        # No other errors should occurr, unless something's terribly wrong
-        except ConfigParser.Error as e:
-            raise RuntimeError("Unexpected error: %s" % str(e))
-
-    def create_links_file(self, provider, fingerprint):
-        """
-            Public method to create a links file for a provider.
-
-            This should be used by all providers since it writes the links
-            file with the proper format. It backs up the old links file
-            (if exists) and creates a new one. The name for the links file
-            is the provider's name in lowercase. It receives the fingerprint
-            of the key that signed the packages.
-
-            It raises a general exception if something goes wrong while
-            creating the new file.
-
-            Arguments:
-                provider: Provider's name. The links file will use this
-                          name in lower case.
-                fingerprint: Fingerprint of the key that signed the packages
-                             to be uploaded to the provider.
-        """
-        linksfile = os.path.join(self.linksdir, provider.lower() + '.links')
-        linksfile_backup = ""
-        self.logger.info("Request to create new %s" % linksfile)
-
-        if os.path.isfile(linksfile):
-            # Backup the old file in case something fails
-            linksfile_backup = linksfile + '.backup'
-            self.logger.info("Backing up %s to %s"
-                             % (linksfile, linksfile_backup))
-            os.rename(linksfile, linksfile_backup)
-
-        try:
-            # This creates an empty links file (with no links)
-            content = ConfigParser.RawConfigParser()
-            content.add_section('provider')
-            content.set('provider', 'name', provider)
-            content.add_section('key')
-            content.set('key', 'fingerprint', fingerprint)
-            content.add_section('linux')
-            content.add_section('windows')
-            content.add_section('osx')
-            with open(linksfile, 'w+') as f:
-                content.write(f)
-                self.logger.info("New %s created" % linksfile)
-        except Exception as e:
-            if linksfile_backup:
-                os.rename(linksfile_backup, linksfile)
-
-    def add_link(self, provider, operating_system, locale, link):
-        """
-            Public method to add a link to a provider's links file.
-
-            It uses ConfigParser to add a link into the operating_system
-            section, under the locale option. It check for valid format;
-            the provider's script should use the right format (see design).
-            It raises ValueError in case the operating_system or locale
-            are not supported (see config file for supported ones), or if
-            if there is not a section for the operating_system in the
-            links file, or if there is no links file for the given provider,
-            or if the link format doesn't seem legit.
-        """
-        linksfile = os.path.join(self.linksdir, provider.lower() + '.links')
-
-        # Don't try to add unsupported stuff
-        if locale not in self.supported_locales:
-            self.logger.warning("Trying to add link for unsupported locale: %s"
-                                % locale)
-            raise ValueError("Locale %s not supported at the moment" % locale)
-
-        if operating_system not in self.supported_os:
-            self.logger.warning("Trying to add link for unsupported operating \
-                                system: %s" % operating_system)
-            raise ValueError("Operating system %s not supported at the moment"
-                             % operating_system)
-
-        # Check if the link has a legit format
-        # e.g. https://db.tt/JjfUTb04 https://db.tt/MEfUTb04
-        p = re.compile('^https://.+\shttps://.+$')
-
-        if not p.match(link):
-            self.logger.warning("Trying to add an invalid link: %s"
-                                % link)
-            raise ValueError("Link '%s' doesn't seem to have a valid format"
-                             % link)
-
-        if os.path.isfile(linksfile):
-            content = ConfigParser.RawConfigParser()
-            content.readfp(open(linksfile))
-            # Check if exists and entry for locale; if not, create it
-            try:
-                links = content.get(operating_system, locale)
-                links = links + ",\n" + link
-                content.set(operating_system, locale, links)
-                with open(linksfile, 'w') as f:
-                    content.write(f)
-                self.logger.info("Link %s added to %s %s in %s"
-                                 % (link, operating_system, locale, provider))
-            except ConfigParser.NoOptionError:
-                content.set(operating_system, locale, link)
-                with open(linksfile, 'w') as f:
-                    content.write(f)
-                self.logger.info("Link %s added to %s-%s in %s"
-                                 % (link, operating_system, locale, provider))
-            except ConfigParser.NoSectionError:
-                # This shouldn't happen, but just in case
-                self.logger.error("Unknown section %s in links file")
-                raise ValueError("Unknown %s section in links file"
-                                 % operating_system)
-        else:
-            raise ValueError("There is no links file for %s" % provider)
diff --git a/src/smtp.py b/src/smtp.py
deleted file mode 100644
index e29aa2d..0000000
--- a/src/smtp.py
+++ /dev/null
@@ -1,504 +0,0 @@
-import os
-import re
-import sys
-import time
-import email
-import gettext
-import hashlib
-import logging
-import ConfigParser
-
-import gettor
-
-
-class SingleLevelFilter(logging.Filter):
-    """
-    Filter logging levels to create separated logs.
-
-    Public methods:
-        filter(record)
-    """
-
-    def __init__(self, passlevel, reject):
-        """
-        Initialize a new object with level to be filtered.
-
-        If reject value is false, all but the passlevel will be
-        filtered. Useful for logging in separated files.
-        """
-
-        self.passlevel = passlevel
-        self.reject = reject
-
-    def filter(self, record):
-        """
-        Do the actual filtering.
-        """
-        if self.reject:
-            return (record.levelno != self.passlevel)
-        else:
-            return (record.levelno == self.passlevel)
-
-
-class SMTP(object):
-    """
-    Class for the GetTor's SMTP service. Provides an interface to
-    interact with requests received by email.
-    """
-
-    def __init__(self, config_file):
-    	"""
-        Create new object by reading a configuration file.
-
-        Args:
-
-        - config (string): the path of the file that will be used as
-                           configuration
-        """
-        logging.basicConfig(format='[%(levelname)s] %(asctime)s - %(message)s',
-                            datefmt="%Y-%m-%d %H:%M:%S")
-        logger = logging.getLogger(__name__)
-        config = ConfigParser.ConfigParser()
-
-        if os.path.isfile(config_file):
-            logger.info("Reading configuration from %s" % config_file)
-            config.read(config_file)
-        else:
-            logger.error("Error while trying to read %s" % config_file)
-            raise RuntimeError("Couldn't read the configuration file %s"
-                               % config_file)
-
-        # Handle the gets internally to catch proper exceptions
-        try:
-            self.basedir = self._get_config_option('general',
-                                                   'basedir', config)
-        except RuntimeError as e:
-            logger.warning("%s misconfigured. %s" % (config_file, str(e)))
-
-        try:
-            self.delay = self._get_config_option('general',
-                                                 'delay', config)
-            # There has to be a better way for this...
-            if self.delay == 'False':
-                self.delay = False
-
-        except RuntimeError as e:
-            logger.warning("%s misconfigured. %s" % (config_file, str(e)))
-
-        try:
-            self.our_addr = self._get_config_option('general',
-                                                    'our_addr', config)
-        except RuntimeError as e:
-            logger.warning("%s misconfigured. %s" % (config_file, str(e)))
-
-        try:
-            self.logdir = self._get_config_option('log',
-                                                  'dir', config)
-            self.logdir = os.path.join(self.basedir, self.logdir)
-        except RuntimeError as e:
-            logger.warning("%s misconfigured. %s" % (config_file, str(e)))
-
-        try:
-            self.logdir_emails = self._get_config_option('log',
-                                                         'emails_dir',
-                                                         config)
-            self.logdir_emails = os.path.join(self.logdir, self.logdir_emails)
-        except RuntimeError as e:
-            logger.warning("%s misconfigured. %s" % (config_file, str(e)))
-
-        try:
-            self.loglevel = self._get_config_option('log',
-                                                    'level', config)
-        except RuntimeError as e:
-            logger.warning("%s misconfigured. %s" % (config_file, str(e)))
-
-        self.core = gettor.Core('gettor.cfg')
-
-        # Better log format
-        string_format = '[%(levelname)7s] %(asctime)s - %(message)s'
-        formatter = logging.Formatter(string_format, '%Y-%m-%d %H:%M:%S')
-
-        # Keep logs separated (and filtered)
-        # all.log depends on level specified on configuration file
-        all_log = logging.FileHandler(os.path.join(self.logdir, 'all.log'),
-                                      mode='a+')
-        all_log.setLevel(logging.getLevelName(self.loglevel))
-        all_log.setFormatter(formatter)
-
-        debug_log = logging.FileHandler(os.path.join(self.logdir, 'debug.log'),
-                                        mode='a+')
-        debug_log.setLevel('DEBUG')
-        debug_log.addFilter(SingleLevelFilter(logging.DEBUG, False))
-        debug_log.setFormatter(formatter)
-
-        info_log = logging.FileHandler(os.path.join(self.logdir, 'info.log'),
-                                       mode='a+')
-        info_log.setLevel('INFO')
-        info_log.addFilter(SingleLevelFilter(logging.INFO, False))
-        info_log.setFormatter(formatter)
-
-        warn_log = logging.FileHandler(os.path.join(self.logdir, 'warn.log'),
-                                       mode='a+')
-        warn_log.setLevel('WARNING')
-        warn_log.addFilter(SingleLevelFilter(logging.WARNING, False))
-        warn_log.setFormatter(formatter)
-
-        error_log = logging.FileHandler(os.path.join(self.logdir, 'error.log'),
-                                        mode='a+')
-        error_log.setLevel('ERROR')
-        error_log.addFilter(SingleLevelFilter(logging.ERROR, False))
-        error_log.setFormatter(formatter)
-
-        logger.addHandler(all_log)
-        logger.addHandler(info_log)
-        logger.addHandler(debug_log)
-        logger.addHandler(warn_log)
-        logger.addHandler(error_log)
-
-        self.logger = logger
-        self.logger.setLevel(logging.getLevelName(self.loglevel))
-        logger.debug('Redirecting logging to %s' % self.logdir)
-
-        # Stop logging on stdout from now on
-        logger.propagate = False
-        self.logger.debug("New smtp object created")
-
-    def _get_sha1(self, string):
-        """
-        Get the sha1 of a string
-
-        Used whenever we want to do things with addresses (log, blacklist, etc)
-
-        Returns a string
-        """
-        return str(hashlib.sha1(string).hexdigest())
-
-    def _log_request(self, addr, content):
-        """
-        Log a given request
-
-        This should be called when something goes wrong. It saves the
-        email content that triggered the malfunctioning
-
-        Raises:
-
-        - RuntimeError: if something goes wrong while trying to save the
-                        email
-        """
-        # We don't store the original address, but rather its sha1 digest
-        # in order to know when some specific addresses are doing weird
-        # requests
-        log_addr = self._get_sha1(addr)
-        filename = str(time.time()) + '.log'
-        path = self.logdir_emails + filename
-        abs_path = os.path.abspath(path)
-
-        log_file = open(abs_path, 'w+')
-        log_file.write(content)
-        log_file.close()
-
-        self.logger.debug("Logging request from %s in %s"
-                          % (log_addr, abs_path))
-
-    def _check_blacklist(self, addr):
-        """
-        Check if an email is blacklisted
-
-        It opens the corresponding blacklist file and search for the
-        sender address.
-
-        Raises:
-
-        - BlacklistError: if the user is blacklisted.
-        """
-        anon_addr = self._get_sha1(addr)
-        self.logger.debug("Checking if address %s is blacklisted" %
-                          anon_addr)
-
-    def _get_locale(self):
-        """
-        Get the locale from an email address
-
-        It process the email received and look for the locale in the
-        recipient address (e.g. gettor+en at torproject.org)
-
-        If no locale found, english by default
-
-        Returns a string containing the locale
-        """
-        self.logger.debug("Trying to obtain locale from recipient address")
-
-        # If no match found, english by default
-        locale = 'en'
-
-        # Look for gettor+locale at torproject.org
-        m = re.match('gettor\+(\w\w)@torproject\.org', self.to_addr)
-        if m:
-            self.logger.debug("Request for locale %s" % m.groups())
-            locale = "%s" % m.groups()
-
-        return locale
-
-    def _get_normalized_address(self, addr):
-        """
-        Get normalized address
-
-        It looks for anything inside the last '<' and '>'. Code taken
-        from the old GetTor (utils.py)
-
-        On success, returns the normalized address
-        On failure, returns ValueError
-        """
-        if '<' in addr:
-            idx = addr.rindex('<')
-            addr = addr[idx:]
-            m = re.search(r'<([^>]*)>', addr)
-            if m is None:
-                raise ValueError("Couldn't extract normalized address from %s"
-                                 % addr)
-            addr = m.group(1)
-        return addr
-
-    def _parse_email(self):
-        """
-        Parse the email received
-
-        It obtains the locale and parse the text for the rest of the info
-
-        Returns a 3-tuple with locale, os and type
-        """
-        self.logger.debug("Parsing email")
-
-        locale = self._get_locale()
-        request = self._parse_text()
-        request['locale'] = locale
-
-        return request
-
-    def _parse_text(self):
-        """
-        Parse the text part of the email received
-
-        It tries to figure out what the user is asking, namely, the type
-        of request, the package and os required (if applies)
-
-        Returns a tuple with the type of request and os (None if request
-        is for help)
-        """
-        self.logger.debug("Parsing email text part")
-
-        # By default we asume the request is asking for links
-        request = {}
-        request['type'] = 'links'
-        request['os'] = None
-
-        # The core knows what OS are supported
-        supported_os = self.core.get_supported_os()
-
-        lines = self.raw_msg.split('\n')
-        found_os = False
-        for line in lines:
-            # Check for help request
-            if re.match('.*help.*', line, re.IGNORECASE):
-                request['type'] = 'help'
-                break
-            # Check for os
-            for supported in supported_os:
-                p = '.*' + supported + '.*'
-                if re.match(p, line, re.IGNORECASE):
-                    request['os'] = supported
-                    found_os = True
-            if found_os:
-                break
-
-            if request['type'] == 'links' and not request['os']:
-                # Windows by default?
-                request['os'] = 'windows'
-
-        return request
-
-    def _create_email(self, from_addr, to_addr, subject, msg):
-        """
-        Create an email object
-
-        This object will be used to construct the reply. Comment lines
-        331-334, 339, and uncomment lines 336, 337, 340 to test it
-        without having an SMTP server
-
-        Returns the email object
-        """
-        self.logger.debug("Creating email object for replying")
-        # email_obj = MIMEtext(msg)
-        # email_obj['Subject'] = subject
-        # email_obj['From'] = from_addr
-        # email_obj['To'] = to_addr
-
-        reply = "From: " + from_addr + ", To: " + to_addr
-        reply = reply + ", Subject: " + subject + "\n\n" + msg
-
-        # return email_obj
-        return reply
-
-    def _send_email(self, from_addr, to_addr, subject, msg):
-        """
-        Send an email
-
-        It takes a from and to addresses, a subject and the content, creates
-        an email and send it. Comment lines 350-352 and uncomment line 353
-        to test it without having an SMTP server
-        """
-        email_obj = self._create_email(from_addr, to_addr, subject, msg)
-        # s = smtplib.SMTP("localhost")
-        # s.sendmail(from_addr, to_addr, msg.as_string())
-        # s.quit()
-        print email_obj
-        self.logger.debug("Email sent")
-
-    def _send_delay(self, locale, from_addr, to_addr):
-        """
-        Send delay message
-
-        If delay is setted on configuration, then sends a reply to the
-        user saying that the package is on the way
-        """
-        self.logger.debug("Delay is setted. Sending a delay message.")
-
-        # Obtain the content in the proper language and send it
-        t = gettext.translation(locale, './i18n', languages=[locale])
-        _ = t.ugettext
-
-        delay_msg = _('delay_msg')
-        delay_subject = _('delay_subject')
-        self._send_email(from_addr, to_addr, delay_subject, delay_msg)
-
-    def _send_links(self, links, locale, from_addr, to_addr):
-        """
-        Send the links to the user
-
-        It gets the message in the proper language (according to the
-        locale), replace variables in that message and call to send the
-        email
-        """
-        self.logger.debug("Request for links in %s" % locale)
-
-        # Obtain the content in the proper language and send it
-        t = gettext.translation(locale, './i18n', languages=[locale])
-        _ = t.ugettext
-
-        links_msg = _('links_msg')
-        links_subject = _('links_subject')
-        links_msg = links_msg % ('linux', locale, links, links)
-        self._send_email(from_addr, to_addr, links_subject, links_msg)
-
-    def _send_help(self, locale, from_addr, to_addr):
-        """
-        Send help message to the user
-
-        It gets the message in the proper language (according to the
-        locale), replace variables in that message (if any) and call to send
-        the email
-        """
-        self.logger.debug("Request for help in %s" % locale)
-
-        # Obtain the content in the proper language and send it
-        t = gettext.translation(locale, './i18n', languages=[locale])
-        _ = t.ugettext
-
-        help_msg = _('help_msg')
-        help_subject = _('help_subject')
-        self._send_email(from_addr, to_addr, help_subject, help_msg)
-
-    def process_email(self, raw_msg):
-        """
-        Process the email received.
-
-        It creates an email object from the string received. The processing
-        flow is as following:
-            - Check for blacklisted address
-            - Parse the email
-            - Check the type of request
-            - Send reply
-
-        Raises:
-            - ValueError if the address is blacklisted, or if the request
-            asks for unsupported locales and/or operating systems, or if
-            it's not possible to recognize what type of request (help, links)
-            the user is asking
-
-            - InternalError if something goes wrong while trying to obtain
-            the links from the Core
-        """
-        self.raw_msg = raw_msg
-        self.parsed_msg = email.message_from_string(raw_msg)
-        # Just for easy access
-        self.from_addr = self.parsed_msg['From']
-        self.norm_from_addr = self._get_normalized_address(self.from_addr)
-        self.to_addr = self.parsed_msg['To']
-
-        # We have the info we need on self.parsed_msg
-        try:
-            self._check_blacklist(self._get_sha1(self.from_addr))
-        except ValueError as e:
-            raise ValueError("The address %s is blacklisted!" %
-                             self._get_sha1(self.from_addr))
-
-        # Try to figure out what the user is asking
-        request = self._parse_email()
-
-        # Two possible options: asking for help or for the links
-        # If not, it means malformed message, and no default values
-        self.logger.info("New request for %s" % request['type'])
-        if request['type'] == 'help':
-            self._send_help(request['locale'], self.our_addr,
-                            self.norm_from_addr)
-        elif request['type'] == 'links':
-            if self.delay:
-                self._send_delay(request['locale'], self.our_addr,
-                                 self.norm_from_addr)
-
-            try:
-                self.logger.info("Asking Core for links in %s for %s" %
-                                 (request['locale'], request['os']))
-
-                links = self.core.get_links('SMTP', request['os'],
-                                            request['locale'])
-
-                self._send_links(links, request['locale'], self.our_addr,
-                                 self.norm_from_addr)
-            except ValueError as e:
-                raise ValueError(str(e))
-            except RuntimeError as e:
-                raise RuntimeError(str(e))
-        else:
-            raise ValueError("Malformed message. No default values either")
-
-    def _get_config_option(self, section, option, config):
-        """
-            Private method to get configuration options.
-
-            It tries to obtain a value from a section in config using
-            ConfigParser. It catches possible exceptions and raises
-            RuntimeError if something goes wrong.
-
-            Arguments:
-                config: ConfigParser object
-                section: section inside config
-                option: option inside section
-
-            Returns the value of the option inside the section in the
-            config object.
-        """
-
-        try:
-            value = config.get(section, option)
-            return value
-        # This exceptions should appear when messing with the configuration
-        except (ConfigParser.NoSectionError,
-                ConfigParser.NoOptionError,
-                ConfigParser.InterpolationError,
-                ConfigParser.MissingSectionHeaderError,
-                ConfigParser.ParsingError) as e:
-            raise RuntimeError("%s" % str(e))
-        # No other errors should occurr, unless something's terribly wrong
-        except ConfigParser.Error as e:
-            raise RuntimeError("Unexpected error: %s" % str(e))





More information about the tor-commits mailing list