[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [gettor/master] New file structure
commit e69c33647c6c352c240647b7a8fdc096c86a2d53
Author: ilv <ilv@xxxxxxxxxxxxxxxxxxxxxxxx>
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@xxxxxxxxxxxxxx)
-
- 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@xxxxxxxxxxxxxx
- 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))
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits