Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dax/jmc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Rousselie <david.rousselie@happycoders.org>2010-06-04 21:59:40 +0400
committerDavid Rousselie <david.rousselie@happycoders.org>2010-06-04 21:59:40 +0400
commit6cba8014502d61d22b297dad36ad6b9ea440bfed (patch)
tree19c241bc37ab3673d9766a4954e9045f4a93461c
parent74feff9ea9711a7725dd4909fc7a755c95e05311 (diff)
release JMC 0.3 beta3
-rw-r--r--.gitignore1
-rw-r--r--Makefile8
-rwxr-xr-xcoverage.py952
-rw-r--r--debian/changelog6
-rw-r--r--debian/control2
-rw-r--r--debian/patches/debian-changes-0.3b35745
-rw-r--r--debian/patches/series1
-rw-r--r--debian/source/format1
-rw-r--r--setup.py2
-rw-r--r--src/jmc.egg-info/PKG-INFO2
10 files changed, 5761 insertions, 959 deletions
diff --git a/.gitignore b/.gitignore
index e6a85b5..ed4c4b6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
*flymake.py
.ropeproject
*.pyc
+dist
diff --git a/Makefile b/Makefile
index bfe797e..9f525f6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
PYTHON=`which python`
DESTDIR=/
-BUILDIR=$(CURDIR)/debian/jcl
-PROJECT=jcl
-VERSION=0.1b2
+BUILDIR=$(CURDIR)/debian/jmc
+PROJECT=jmc
+VERSION=0.3b3
all:
@echo "make source - Create source package"
@@ -23,7 +23,7 @@ buildrpm:
builddeb:
$(PYTHON) setup.py sdist $(COMPILE) --dist-dir=../
rename -f 's/$(PROJECT)-(.*)\.tar\.gz/$(PROJECT)_$$1\.orig\.tar\.gz/' ../*
- dpkg-buildpackage -i -I -rfakeroot
+ dpkg-buildpackage -us -uc -i -I -rfakeroot
clean:
$(PYTHON) setup.py clean
diff --git a/coverage.py b/coverage.py
deleted file mode 100755
index 66e55e0..0000000
--- a/coverage.py
+++ /dev/null
@@ -1,952 +0,0 @@
-#!/usr/bin/python
-#
-# Perforce Defect Tracking Integration Project
-# <http://www.ravenbrook.com/project/p4dti/>
-#
-# COVERAGE.PY -- COVERAGE TESTING
-#
-# Gareth Rees, Ravenbrook Limited, 2001-12-04
-# Ned Batchelder, 2004-12-12
-# http://nedbatchelder.com/code/modules/coverage.html
-#
-#
-# 1. INTRODUCTION
-#
-# This module provides coverage testing for Python code.
-#
-# The intended readership is all Python developers.
-#
-# This document is not confidential.
-#
-# See [GDR 2001-12-04a] for the command-line interface, programmatic
-# interface and limitations. See [GDR 2001-12-04b] for requirements and
-# design.
-
-r"""Usage:
-
-coverage.py -x [-p] MODULE.py [ARG1 ARG2 ...]
- Execute module, passing the given command-line arguments, collecting
- coverage data. With the -p option, write to a temporary file containing
- the machine name and process ID.
-
-coverage.py -e
- Erase collected coverage data.
-
-coverage.py -c
- Collect data from multiple coverage files (as created by -p option above)
- and store it into a single file representing the union of the coverage.
-
-coverage.py -r [-m] [-o dir1,dir2,...] FILE1 FILE2 ...
- Report on the statement coverage for the given files. With the -m
- option, show line numbers of the statements that weren't executed.
-
-coverage.py -a [-d dir] [-o dir1,dir2,...] FILE1 FILE2 ...
- Make annotated copies of the given files, marking statements that
- are executed with > and statements that are missed with !. With
- the -d option, make the copies in that directory. Without the -d
- option, make each copy in the same directory as the original.
-
--o dir,dir2,...
- Omit reporting or annotating files when their filename path starts with
- a directory listed in the omit list.
- e.g. python coverage.py -i -r -o c:\python23,lib\enthought\traits
-
-Coverage data is saved in the file .coverage by default. Set the
-COVERAGE_FILE environment variable to save it somewhere else."""
-
-__version__ = "2.6.20060823" # see detailed history at the end of this file.
-
-import compiler
-import compiler.visitor
-import os
-import re
-import string
-import sys
-import threading
-import types
-from socket import gethostname
-
-# 2. IMPLEMENTATION
-#
-# This uses the "singleton" pattern.
-#
-# The word "morf" means a module object (from which the source file can
-# be deduced by suitable manipulation of the __file__ attribute) or a
-# filename.
-#
-# When we generate a coverage report we have to canonicalize every
-# filename in the coverage dictionary just in case it refers to the
-# module we are reporting on. It seems a shame to throw away this
-# information so the data in the coverage dictionary is transferred to
-# the 'cexecuted' dictionary under the canonical filenames.
-#
-# The coverage dictionary is called "c" and the trace function "t". The
-# reason for these short names is that Python looks up variables by name
-# at runtime and so execution time depends on the length of variables!
-# In the bottleneck of this application it's appropriate to abbreviate
-# names to increase speed.
-
-class StatementFindingAstVisitor(compiler.visitor.ASTVisitor):
- def __init__(self, statements, excluded, suite_spots):
- compiler.visitor.ASTVisitor.__init__(self)
- self.statements = statements
- self.excluded = excluded
- self.suite_spots = suite_spots
- self.excluding_suite = 0
-
- def doRecursive(self, node):
- self.recordNodeLine(node)
- for n in node.getChildNodes():
- self.dispatch(n)
-
- visitStmt = visitModule = doRecursive
-
- def doCode(self, node):
- if hasattr(node, 'decorators') and node.decorators:
- self.dispatch(node.decorators)
- self.recordAndDispatch(node.code)
- else:
- self.doSuite(node, node.code)
-
- visitFunction = visitClass = doCode
-
- def getFirstLine(self, node):
- # Find the first line in the tree node.
- lineno = node.lineno
- for n in node.getChildNodes():
- f = self.getFirstLine(n)
- if lineno and f:
- lineno = min(lineno, f)
- else:
- lineno = lineno or f
- return lineno
-
- def getLastLine(self, node):
- # Find the first line in the tree node.
- lineno = node.lineno
- for n in node.getChildNodes():
- lineno = max(lineno, self.getLastLine(n))
- return lineno
-
- def doStatement(self, node):
- self.recordLine(self.getFirstLine(node))
-
- visitAssert = visitAssign = visitAssTuple = visitDiscard = visitPrint = \
- visitPrintnl = visitRaise = visitSubscript = visitDecorators = \
- doStatement
-
- def recordNodeLine(self, node):
- return self.recordLine(node.lineno)
-
- def recordLine(self, lineno):
- # Returns a bool, whether the line is included or excluded.
- if lineno:
- # Multi-line tests introducing suites have to get charged to their
- # keyword.
- if lineno in self.suite_spots:
- lineno = self.suite_spots[lineno][0]
- # If we're inside an exluded suite, record that this line was
- # excluded.
- if self.excluding_suite:
- self.excluded[lineno] = 1
- return 0
- # If this line is excluded, or suite_spots maps this line to
- # another line that is exlcuded, then we're excluded.
- elif self.excluded.has_key(lineno) or \
- self.suite_spots.has_key(lineno) and \
- self.excluded.has_key(self.suite_spots[lineno][1]):
- return 0
- # Otherwise, this is an executable line.
- else:
- self.statements[lineno] = 1
- return 1
- return 0
-
- default = recordNodeLine
-
- def recordAndDispatch(self, node):
- self.recordNodeLine(node)
- self.dispatch(node)
-
- def doSuite(self, intro, body, exclude=0):
- exsuite = self.excluding_suite
- if exclude or (intro and not self.recordNodeLine(intro)):
- self.excluding_suite = 1
- self.recordAndDispatch(body)
- self.excluding_suite = exsuite
-
- def doPlainWordSuite(self, prevsuite, suite):
- # Finding the exclude lines for else's is tricky, because they aren't
- # present in the compiler parse tree. Look at the previous suite,
- # and find its last line. If any line between there and the else's
- # first line are excluded, then we exclude the else.
- lastprev = self.getLastLine(prevsuite)
- firstelse = self.getFirstLine(suite)
- for l in range(lastprev+1, firstelse):
- if self.suite_spots.has_key(l):
- self.doSuite(None, suite, exclude=self.excluded.has_key(l))
- break
- else:
- self.doSuite(None, suite)
-
- def doElse(self, prevsuite, node):
- if node.else_:
- self.doPlainWordSuite(prevsuite, node.else_)
-
- def visitFor(self, node):
- self.doSuite(node, node.body)
- self.doElse(node.body, node)
-
- def visitIf(self, node):
- # The first test has to be handled separately from the rest.
- # The first test is credited to the line with the "if", but the others
- # are credited to the line with the test for the elif.
- self.doSuite(node, node.tests[0][1])
- for t, n in node.tests[1:]:
- self.doSuite(t, n)
- self.doElse(node.tests[-1][1], node)
-
- def visitWhile(self, node):
- self.doSuite(node, node.body)
- self.doElse(node.body, node)
-
- def visitTryExcept(self, node):
- self.doSuite(node, node.body)
- for i in range(len(node.handlers)):
- a, b, h = node.handlers[i]
- if not a:
- # It's a plain "except:". Find the previous suite.
- if i > 0:
- prev = node.handlers[i-1][2]
- else:
- prev = node.body
- self.doPlainWordSuite(prev, h)
- else:
- self.doSuite(a, h)
- self.doElse(node.handlers[-1][2], node)
-
- def visitTryFinally(self, node):
- self.doSuite(node, node.body)
- self.doPlainWordSuite(node.body, node.final)
-
- def visitGlobal(self, node):
- # "global" statements don't execute like others (they don't call the
- # trace function), so don't record their line numbers.
- pass
-
-the_coverage = None
-
-class CoverageException(Exception): pass
-
-class coverage:
- # Name of the cache file (unless environment variable is set).
- cache_default = ".coverage"
-
- # Environment variable naming the cache file.
- cache_env = "COVERAGE_FILE"
-
- # A dictionary with an entry for (Python source file name, line number
- # in that file) if that line has been executed.
- c = {}
-
- # A map from canonical Python source file name to a dictionary in
- # which there's an entry for each line number that has been
- # executed.
- cexecuted = {}
-
- # Cache of results of calling the analysis2() method, so that you can
- # specify both -r and -a without doing double work.
- analysis_cache = {}
-
- # Cache of results of calling the canonical_filename() method, to
- # avoid duplicating work.
- canonical_filename_cache = {}
-
- def __init__(self):
- global the_coverage
- if the_coverage:
- raise CoverageException, "Only one coverage object allowed."
- self.usecache = 1
- self.cache = None
- self.exclude_re = ''
- self.nesting = 0
- self.cstack = []
- self.xstack = []
- self.relative_dir = os.path.normcase(os.path.abspath(os.curdir)+os.path.sep)
-
- # t(f, x, y). This method is passed to sys.settrace as a trace function.
- # See [van Rossum 2001-07-20b, 9.2] for an explanation of sys.settrace and
- # the arguments and return value of the trace function.
- # See [van Rossum 2001-07-20a, 3.2] for a description of frame and code
- # objects.
-
- def t(self, f, w, a): #pragma: no cover
- if w == 'line':
- self.c[(f.f_code.co_filename, f.f_lineno)] = 1
- for c in self.cstack:
- c[(f.f_code.co_filename, f.f_lineno)] = 1
- return self.t
-
- def help(self, error=None):
- if error:
- print error
- print
- print __doc__
- sys.exit(1)
-
- def command_line(self, argv, help=None):
- import getopt
- help = help or self.help
- settings = {}
- optmap = {
- '-a': 'annotate',
- '-c': 'collect',
- '-d:': 'directory=',
- '-e': 'erase',
- '-h': 'help',
- '-i': 'ignore-errors',
- '-m': 'show-missing',
- '-p': 'parallel-mode',
- '-r': 'report',
- '-x': 'execute',
- '-o:': 'omit=',
- }
- short_opts = string.join(map(lambda o: o[1:], optmap.keys()), '')
- long_opts = optmap.values()
- options, args = getopt.getopt(argv, short_opts, long_opts)
- for o, a in options:
- if optmap.has_key(o):
- settings[optmap[o]] = 1
- elif optmap.has_key(o + ':'):
- settings[optmap[o + ':']] = a
- elif o[2:] in long_opts:
- settings[o[2:]] = 1
- elif o[2:] + '=' in long_opts:
- settings[o[2:]+'='] = a
- else: #pragma: no cover
- pass # Can't get here, because getopt won't return anything unknown.
-
- if settings.get('help'):
- help()
-
- for i in ['erase', 'execute']:
- for j in ['annotate', 'report', 'collect']:
- if settings.get(i) and settings.get(j):
- help("You can't specify the '%s' and '%s' "
- "options at the same time." % (i, j))
-
- args_needed = (settings.get('execute')
- or settings.get('annotate')
- or settings.get('report'))
- action = (settings.get('erase')
- or settings.get('collect')
- or args_needed)
- if not action:
- help("You must specify at least one of -e, -x, -c, -r, or -a.")
- if not args_needed and args:
- help("Unexpected arguments: %s" % " ".join(args))
-
- self.get_ready(settings.get('parallel-mode'))
- self.exclude('#pragma[: ]+[nN][oO] [cC][oO][vV][eE][rR]')
-
- if settings.get('erase'):
- self.erase()
- if settings.get('execute'):
- if not args:
- help("Nothing to do.")
- sys.argv = args
- self.start()
- import __main__
- sys.path[0] = os.path.dirname(sys.argv[0])
- execfile(sys.argv[0], __main__.__dict__)
- if settings.get('collect'):
- self.collect()
- if not args:
- args = self.cexecuted.keys()
-
- ignore_errors = settings.get('ignore-errors')
- show_missing = settings.get('show-missing')
- directory = settings.get('directory=')
-
- omit = settings.get('omit=')
- if omit is not None:
- omit = omit.split(',')
- else:
- omit = []
-
- if settings.get('report'):
- self.report(args, show_missing, ignore_errors, omit_prefixes=omit)
- if settings.get('annotate'):
- self.annotate(args, directory, ignore_errors, omit_prefixes=omit)
-
- def use_cache(self, usecache, cache_file=None):
- self.usecache = usecache
- if cache_file and not self.cache:
- self.cache_default = cache_file
-
- def get_ready(self, parallel_mode=False):
- if self.usecache and not self.cache:
- self.cache = os.environ.get(self.cache_env, self.cache_default)
- if parallel_mode:
- self.cache += "." + gethostname() + "." + str(os.getpid())
- self.restore()
- self.analysis_cache = {}
-
- def start(self, parallel_mode=False):
- self.get_ready(parallel_mode)
- if self.nesting == 0: #pragma: no cover
- sys.settrace(self.t)
- if hasattr(threading, 'settrace'):
- threading.settrace(self.t)
- self.nesting += 1
-
- def stop(self):
- self.nesting -= 1
- if self.nesting == 0: #pragma: no cover
- sys.settrace(None)
- if hasattr(threading, 'settrace'):
- threading.settrace(None)
-
- def erase(self):
- self.c = {}
- self.analysis_cache = {}
- self.cexecuted = {}
- if self.cache and os.path.exists(self.cache):
- os.remove(self.cache)
- self.exclude_re = ""
-
- def exclude(self, re):
- if self.exclude_re:
- self.exclude_re += "|"
- self.exclude_re += "(" + re + ")"
-
- def begin_recursive(self):
- self.cstack.append(self.c)
- self.xstack.append(self.exclude_re)
-
- def end_recursive(self):
- self.c = self.cstack.pop()
- self.exclude_re = self.xstack.pop()
-
- # save(). Save coverage data to the coverage cache.
-
- def save(self):
- if self.usecache and self.cache:
- self.canonicalize_filenames()
- cache = open(self.cache, 'wb')
- import marshal
- marshal.dump(self.cexecuted, cache)
- cache.close()
-
- # restore(). Restore coverage data from the coverage cache (if it exists).
-
- def restore(self):
- self.c = {}
- self.cexecuted = {}
- assert self.usecache
- if os.path.exists(self.cache):
- self.cexecuted = self.restore_file(self.cache)
-
- def restore_file(self, file_name):
- try:
- cache = open(file_name, 'rb')
- import marshal
- cexecuted = marshal.load(cache)
- cache.close()
- if isinstance(cexecuted, types.DictType):
- return cexecuted
- else:
- return {}
- except:
- return {}
-
- # collect(). Collect data in multiple files produced by parallel mode
-
- def collect(self):
- cache_dir, local = os.path.split(self.cache)
- for file in os.listdir(cache_dir):
- if not file.startswith(local):
- continue
-
- full_path = os.path.join(cache_dir, file)
- cexecuted = self.restore_file(full_path)
- self.merge_data(cexecuted)
-
- def merge_data(self, new_data):
- for file_name, file_data in new_data.items():
- if self.cexecuted.has_key(file_name):
- self.merge_file_data(self.cexecuted[file_name], file_data)
- else:
- self.cexecuted[file_name] = file_data
-
- def merge_file_data(self, cache_data, new_data):
- for line_number in new_data.keys():
- if not cache_data.has_key(line_number):
- cache_data[line_number] = new_data[line_number]
-
- # canonical_filename(filename). Return a canonical filename for the
- # file (that is, an absolute path with no redundant components and
- # normalized case). See [GDR 2001-12-04b, 3.3].
-
- def canonical_filename(self, filename):
- if not self.canonical_filename_cache.has_key(filename):
- f = filename
- if os.path.isabs(f) and not os.path.exists(f):
- f = os.path.basename(f)
- if not os.path.isabs(f):
- for path in [os.curdir] + sys.path:
- g = os.path.join(path, f)
- if os.path.exists(g):
- f = g
- break
- cf = os.path.normcase(os.path.abspath(f))
- self.canonical_filename_cache[filename] = cf
- return self.canonical_filename_cache[filename]
-
- # canonicalize_filenames(). Copy results from "c" to "cexecuted",
- # canonicalizing filenames on the way. Clear the "c" map.
-
- def canonicalize_filenames(self):
- for filename, lineno in self.c.keys():
- f = self.canonical_filename(filename)
- if not self.cexecuted.has_key(f):
- self.cexecuted[f] = {}
- self.cexecuted[f][lineno] = 1
- self.c = {}
-
- # morf_filename(morf). Return the filename for a module or file.
-
- def morf_filename(self, morf):
- if isinstance(morf, types.ModuleType):
- if not hasattr(morf, '__file__'):
- raise CoverageException, "Module has no __file__ attribute."
- file = morf.__file__
- else:
- file = morf
- return self.canonical_filename(file)
-
- # analyze_morf(morf). Analyze the module or filename passed as
- # the argument. If the source code can't be found, raise an error.
- # Otherwise, return a tuple of (1) the canonical filename of the
- # source code for the module, (2) a list of lines of statements
- # in the source code, and (3) a list of lines of excluded statements.
-
- def analyze_morf(self, morf):
- if self.analysis_cache.has_key(morf):
- return self.analysis_cache[morf]
- filename = self.morf_filename(morf)
- ext = os.path.splitext(filename)[1]
- if ext == '.pyc':
- if not os.path.exists(filename[0:-1]):
- raise CoverageException, ("No source for compiled code '%s'."
- % filename)
- filename = filename[0:-1]
- elif ext != '.py':
- raise CoverageException, "File '%s' not Python source." % filename
- source = open(filename, 'r')
- lines, excluded_lines = self.find_executable_statements(
- source.read(), exclude=self.exclude_re
- )
- source.close()
- result = filename, lines, excluded_lines
- self.analysis_cache[morf] = result
- return result
-
- def get_suite_spots(self, tree, spots):
- import symbol, token
- for i in range(1, len(tree)):
- if type(tree[i]) == type(()):
- if tree[i][0] == symbol.suite:
- # Found a suite, look back for the colon and keyword.
- lineno_colon = lineno_word = None
- for j in range(i-1, 0, -1):
- if tree[j][0] == token.COLON:
- lineno_colon = tree[j][2]
- elif tree[j][0] == token.NAME:
- if tree[j][1] == 'elif':
- # Find the line number of the first non-terminal
- # after the keyword.
- t = tree[j+1]
- while t and token.ISNONTERMINAL(t[0]):
- t = t[1]
- if t:
- lineno_word = t[2]
- else:
- lineno_word = tree[j][2]
- break
- elif tree[j][0] == symbol.except_clause:
- # "except" clauses look like:
- # ('except_clause', ('NAME', 'except', lineno), ...)
- if tree[j][1][0] == token.NAME:
- lineno_word = tree[j][1][2]
- break
- if lineno_colon and lineno_word:
- # Found colon and keyword, mark all the lines
- # between the two with the two line numbers.
- for l in range(lineno_word, lineno_colon+1):
- spots[l] = (lineno_word, lineno_colon)
- self.get_suite_spots(tree[i], spots)
-
- def find_executable_statements(self, text, exclude=None):
- # Find lines which match an exclusion pattern.
- excluded = {}
- suite_spots = {}
- if exclude:
- reExclude = re.compile(exclude)
- lines = text.split('\n')
- for i in range(len(lines)):
- if reExclude.search(lines[i]):
- excluded[i+1] = 1
-
- import parser
- tree = parser.suite(text+'\n\n').totuple(1)
- self.get_suite_spots(tree, suite_spots)
-
- # Use the compiler module to parse the text and find the executable
- # statements. We add newlines to be impervious to final partial lines.
- statements = {}
- ast = compiler.parse(text+'\n\n')
- visitor = StatementFindingAstVisitor(statements, excluded, suite_spots)
- compiler.walk(ast, visitor, walker=visitor)
-
- lines = statements.keys()
- lines.sort()
- excluded_lines = excluded.keys()
- excluded_lines.sort()
- return lines, excluded_lines
-
- # format_lines(statements, lines). Format a list of line numbers
- # for printing by coalescing groups of lines as long as the lines
- # represent consecutive statements. This will coalesce even if
- # there are gaps between statements, so if statements =
- # [1,2,3,4,5,10,11,12,13,14] and lines = [1,2,5,10,11,13,14] then
- # format_lines will return "1-2, 5-11, 13-14".
-
- def format_lines(self, statements, lines):
- pairs = []
- i = 0
- j = 0
- start = None
- pairs = []
- while i < len(statements) and j < len(lines):
- if statements[i] == lines[j]:
- if start == None:
- start = lines[j]
- end = lines[j]
- j = j + 1
- elif start:
- pairs.append((start, end))
- start = None
- i = i + 1
- if start:
- pairs.append((start, end))
- def stringify(pair):
- start, end = pair
- if start == end:
- return "%d" % start
- else:
- return "%d-%d" % (start, end)
- return string.join(map(stringify, pairs), ", ")
-
- # Backward compatibility with version 1.
- def analysis(self, morf):
- f, s, _, m, mf = self.analysis2(morf)
- return f, s, m, mf
-
- def analysis2(self, morf):
- filename, statements, excluded = self.analyze_morf(morf)
- self.canonicalize_filenames()
- if not self.cexecuted.has_key(filename):
- self.cexecuted[filename] = {}
- missing = []
- for line in statements:
- if not self.cexecuted[filename].has_key(line):
- missing.append(line)
- return (filename, statements, excluded, missing,
- self.format_lines(statements, missing))
-
- def relative_filename(self, filename):
- """ Convert filename to relative filename from self.relative_dir.
- """
- return filename.replace(self.relative_dir, "")
-
- def morf_name(self, morf):
- """ Return the name of morf as used in report.
- """
- if isinstance(morf, types.ModuleType):
- return morf.__name__
- else:
- return self.relative_filename(os.path.splitext(morf)[0])
-
- def filter_by_prefix(self, morfs, omit_prefixes):
- """ Return list of morfs where the morf name does not begin
- with any one of the omit_prefixes.
- """
- filtered_morfs = []
- for morf in morfs:
- for prefix in omit_prefixes:
- if self.morf_name(morf).startswith(prefix):
- break
- else:
- filtered_morfs.append(morf)
-
- return filtered_morfs
-
- def morf_name_compare(self, x, y):
- return cmp(self.morf_name(x), self.morf_name(y))
-
- def report(self, morfs, show_missing=1, ignore_errors=0, file=None, omit_prefixes=[]):
- if not isinstance(morfs, types.ListType):
- morfs = [morfs]
- morfs = self.filter_by_prefix(morfs, omit_prefixes)
- morfs.sort(self.morf_name_compare)
-
- max_name = max([5,] + map(len, map(self.morf_name, morfs)))
- fmt_name = "%%- %ds " % max_name
- fmt_err = fmt_name + "%s: %s"
- header = fmt_name % "Name" + " Stmts Exec Cover"
- fmt_coverage = fmt_name + "% 6d % 6d % 5d%%"
- if show_missing:
- header = header + " Missing"
- fmt_coverage = fmt_coverage + " %s"
- if not file:
- file = sys.stdout
- print >>file, header
- print >>file, "-" * len(header)
- total_statements = 0
- total_executed = 0
- for morf in morfs:
- name = self.morf_name(morf)
- try:
- _, statements, _, missing, readable = self.analysis2(morf)
- n = len(statements)
- m = n - len(missing)
- if n > 0:
- pc = 100.0 * m / n
- else:
- pc = 100.0
- args = (name, n, m, pc)
- if show_missing:
- args = args + (readable,)
- print >>file, fmt_coverage % args
- total_statements = total_statements + n
- total_executed = total_executed + m
- except KeyboardInterrupt: #pragma: no cover
- raise
- except:
- if not ignore_errors:
- type, msg = sys.exc_info()[0:2]
- print >>file, fmt_err % (name, type, msg)
- if len(morfs) > 1:
- print >>file, "-" * len(header)
- if total_statements > 0:
- pc = 100.0 * total_executed / total_statements
- else:
- pc = 100.0
- args = ("TOTAL", total_statements, total_executed, pc)
- if show_missing:
- args = args + ("",)
- print >>file, fmt_coverage % args
-
- # annotate(morfs, ignore_errors).
-
- blank_re = re.compile(r"\s*(#|$)")
- else_re = re.compile(r"\s*else\s*:\s*(#|$)")
-
- def annotate(self, morfs, directory=None, ignore_errors=0, omit_prefixes=[]):
- morfs = self.filter_by_prefix(morfs, omit_prefixes)
- for morf in morfs:
- try:
- filename, statements, excluded, missing, _ = self.analysis2(morf)
- self.annotate_file(filename, statements, excluded, missing, directory)
- except KeyboardInterrupt:
- raise
- except:
- if not ignore_errors:
- raise
-
- def annotate_file(self, filename, statements, excluded, missing, directory=None):
- source = open(filename, 'r')
- if directory:
- dest_file = os.path.join(directory,
- os.path.basename(filename)
- + ',cover')
- else:
- dest_file = filename + ',cover'
- dest = open(dest_file, 'w')
- lineno = 0
- i = 0
- j = 0
- covered = 1
- while 1:
- line = source.readline()
- if line == '':
- break
- lineno = lineno + 1
- while i < len(statements) and statements[i] < lineno:
- i = i + 1
- while j < len(missing) and missing[j] < lineno:
- j = j + 1
- if i < len(statements) and statements[i] == lineno:
- covered = j >= len(missing) or missing[j] > lineno
- if self.blank_re.match(line):
- dest.write(' ')
- elif self.else_re.match(line):
- # Special logic for lines containing only 'else:'.
- # See [GDR 2001-12-04b, 3.2].
- if i >= len(statements) and j >= len(missing):
- dest.write('! ')
- elif i >= len(statements) or j >= len(missing):
- dest.write('> ')
- elif statements[i] == missing[j]:
- dest.write('! ')
- else:
- dest.write('> ')
- elif lineno in excluded:
- dest.write('- ')
- elif covered:
- dest.write('> ')
- else:
- dest.write('! ')
- dest.write(line)
- source.close()
- dest.close()
-
-# Singleton object.
-the_coverage = coverage()
-
-# Module functions call methods in the singleton object.
-def use_cache(*args, **kw): return the_coverage.use_cache(*args, **kw)
-def start(*args, **kw): return the_coverage.start(*args, **kw)
-def stop(*args, **kw): return the_coverage.stop(*args, **kw)
-def erase(*args, **kw): return the_coverage.erase(*args, **kw)
-def begin_recursive(*args, **kw): return the_coverage.begin_recursive(*args, **kw)
-def end_recursive(*args, **kw): return the_coverage.end_recursive(*args, **kw)
-def exclude(*args, **kw): return the_coverage.exclude(*args, **kw)
-def analysis(*args, **kw): return the_coverage.analysis(*args, **kw)
-def analysis2(*args, **kw): return the_coverage.analysis2(*args, **kw)
-def report(*args, **kw): return the_coverage.report(*args, **kw)
-def annotate(*args, **kw): return the_coverage.annotate(*args, **kw)
-def annotate_file(*args, **kw): return the_coverage.annotate_file(*args, **kw)
-
-# Save coverage data when Python exits. (The atexit module wasn't
-# introduced until Python 2.0, so use sys.exitfunc when it's not
-# available.)
-try:
- import atexit
- atexit.register(the_coverage.save)
-except ImportError:
- sys.exitfunc = the_coverage.save
-
-# Command-line interface.
-if __name__ == '__main__':
- the_coverage.command_line(sys.argv[1:])
-
-
-# A. REFERENCES
-#
-# [GDR 2001-12-04a] "Statement coverage for Python"; Gareth Rees;
-# Ravenbrook Limited; 2001-12-04;
-# <http://www.nedbatchelder.com/code/modules/rees-coverage.html>.
-#
-# [GDR 2001-12-04b] "Statement coverage for Python: design and
-# analysis"; Gareth Rees; Ravenbrook Limited; 2001-12-04;
-# <http://www.nedbatchelder.com/code/modules/rees-design.html>.
-#
-# [van Rossum 2001-07-20a] "Python Reference Manual (releae 2.1.1)";
-# Guide van Rossum; 2001-07-20;
-# <http://www.python.org/doc/2.1.1/ref/ref.html>.
-#
-# [van Rossum 2001-07-20b] "Python Library Reference"; Guido van Rossum;
-# 2001-07-20; <http://www.python.org/doc/2.1.1/lib/lib.html>.
-#
-#
-# B. DOCUMENT HISTORY
-#
-# 2001-12-04 GDR Created.
-#
-# 2001-12-06 GDR Added command-line interface and source code
-# annotation.
-#
-# 2001-12-09 GDR Moved design and interface to separate documents.
-#
-# 2001-12-10 GDR Open cache file as binary on Windows. Allow
-# simultaneous -e and -x, or -a and -r.
-#
-# 2001-12-12 GDR Added command-line help. Cache analysis so that it
-# only needs to be done once when you specify -a and -r.
-#
-# 2001-12-13 GDR Improved speed while recording. Portable between
-# Python 1.5.2 and 2.1.1.
-#
-# 2002-01-03 GDR Module-level functions work correctly.
-#
-# 2002-01-07 GDR Update sys.path when running a file with the -x option,
-# so that it matches the value the program would get if it were run on
-# its own.
-#
-# 2004-12-12 NMB Significant code changes.
-# - Finding executable statements has been rewritten so that docstrings and
-# other quirks of Python execution aren't mistakenly identified as missing
-# lines.
-# - Lines can be excluded from consideration, even entire suites of lines.
-# - The filesystem cache of covered lines can be disabled programmatically.
-# - Modernized the code.
-#
-# 2004-12-14 NMB Minor tweaks. Return 'analysis' to its original behavior
-# and add 'analysis2'. Add a global for 'annotate', and factor it, adding
-# 'annotate_file'.
-#
-# 2004-12-31 NMB Allow for keyword arguments in the module global functions.
-# Thanks, Allen.
-#
-# 2005-12-02 NMB Call threading.settrace so that all threads are measured.
-# Thanks Martin Fuzzey. Add a file argument to report so that reports can be
-# captured to a different destination.
-#
-# 2005-12-03 NMB coverage.py can now measure itself.
-#
-# 2005-12-04 NMB Adapted Greg Rogers' patch for using relative filenames,
-# and sorting and omitting files to report on.
-#
-# 2006-07-23 NMB Applied Joseph Tate's patch for function decorators.
-#
-# 2006-08-21 NMB Applied Sigve Tjora and Mark van der Wal's fixes for argument
-# handling.
-#
-# 2006-08-22 NMB Applied Geoff Bache's parallel mode patch.
-#
-# 2006-08-23 NMB Refactorings to improve testability. Fixes to command-line
-# logic for parallel mode and collect.
-
-# C. COPYRIGHT AND LICENCE
-#
-# Copyright 2001 Gareth Rees. All rights reserved.
-# Copyright 2004-2006 Ned Batchelder. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the
-# distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
-# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-# DAMAGE.
-#
-# $Id: coverage.py 47 2006-08-24 01:08:48Z Ned $
diff --git a/debian/changelog b/debian/changelog
index 50b5334..000c192 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+jmc (0.3b3) unstable; urgency=low
+
+ * JMC version 0.3 beta 3
+
+ -- David Rousselie <dax@happycoders.org> Fri, 04 Jun 2010 19:44:55 +0200
+
jmc (0.3b2) unstable; urgency=low
* JMC version 0.3 beta 2
diff --git a/debian/control b/debian/control
index 89fd0f8..8f3d72f 100644
--- a/debian/control
+++ b/debian/control
@@ -7,7 +7,7 @@ Standards-Version: 3.8.4
Package: python-jmc
Architecture: all
-Depends: ${python:Depends}, python-jcl (= 0.1b2)
+Depends: ${python:Depends}, python-jcl (= 0.1b3)
Provides: ${python:Provides}
Description: JMC is an email gateway for Jabber
JMC is a jabber service to check email from POP3 and IMAP4 server and
diff --git a/debian/patches/debian-changes-0.3b3 b/debian/patches/debian-changes-0.3b3
new file mode 100644
index 0000000..11b7e2d
--- /dev/null
+++ b/debian/patches/debian-changes-0.3b3
@@ -0,0 +1,5745 @@
+Description: Upstream changes introduced in version 0.3b3
+ This patch has been created by dpkg-source during the package build.
+ Here's the last changelog entry, hopefully it gives details on why
+ those changes were made:
+ .
+ jmc (0.3b3) unstable; urgency=low
+ .
+ * JMC version 0.3 beta 3
+ .
+ The person named in the Author field signed this changelog entry.
+Author: David Rousselie <dax@happycoders.org>
+
+---
+The information above should follow the Patch Tagging Guidelines, please
+checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
+are templates for supplementary fields that you might want to add:
+
+Origin: <vendor|upstream|other>, <url of original patch>
+Bug: <url in upstream bugtracker>
+Bug-Debian: http://bugs.debian.org/<bugnumber>
+Forwarded: <no|not-needed|url proving that it has been forwarded>
+Reviewed-By: <name and email of someone who approved the patch>
+Last-Update: <YYYY-MM-DD>
+
+--- /dev/null
++++ jmc-0.3b3/jmc-local.conf
+@@ -0,0 +1,45 @@
++[jabber]
++server: localhost
++port: 5275
++secret: secret
++service_jid: jmc.octo-dro-linux
++#supported language: en, fr (See src/jmc/lang.py to add more)
++language: en
++
++[db]
++#SQLite config
++type: sqlite
++host:
++name: /tmp/jmc.db
++#Mysql config
++#type: mysql
++#host: root:pass@localhost
++#name: /jmc
++#db_url: %(type)s://%(host)s%(name)s?debug=1&debugThreading=1
++db_url: %(type)s://%(host)s%(name)s
++
++
++[component]
++pid_file: /tmp/jmc.pid
++#motd: "Message of the day"
++welcome_message: "Welcome to Jabber Mail Component"
++# a comma separated list of JIDs
++admins: admin@localhost
++log_file: /tmp/jmc.log
++
++[jmc]
++mail_default_encoding: iso-8859-1
++check_interval: 1
++
++[vcard]
++url: http://people.happycoders.org/dax/projects/jmc
++
++[smtp]
++smtp_default_login: test
++smtp_default_password: test
++smtp_default_host: testhost
++smtp_default_port: 25
++smtp_default_tls: True
++smtp_default_label: Default SMTP Server
++enable_smtp_default_account: False
++
+--- /dev/null
++++ jmc-0.3b3/Makefile
+@@ -0,0 +1,32 @@
++PYTHON=`which python`
++DESTDIR=/
++BUILDIR=$(CURDIR)/debian/jmc
++PROJECT=jmc
++VERSION=0.3b3
++
++all:
++ @echo "make source - Create source package"
++ @echo "make install - Install on local system"
++ @echo "make buildrpm - Generate a rpm package"
++ @echo "make builddeb - Generate a deb package"
++ @echo "make clean - Get rid of scratch and byte files"
++
++source:
++ $(PYTHON) setup.py sdist $(COMPILE)
++
++install:
++ $(PYTHON) setup.py install --root $(DESTDIR) $(COMPILE)
++
++buildrpm:
++ $(PYTHON) setup.py bdist_rpm --post-install=rpm/postinstall --pre-uninstall=rpm/preuninstall
++
++builddeb:
++ $(PYTHON) setup.py sdist $(COMPILE) --dist-dir=../
++ rename -f 's/$(PROJECT)-(.*)\.tar\.gz/$(PROJECT)_$$1\.orig\.tar\.gz/' ../*
++ dpkg-buildpackage -us -uc -i -I -rfakeroot
++
++clean:
++ $(PYTHON) setup.py clean
++ fakeroot $(MAKE) -f $(CURDIR)/debian/rules clean
++ rm -rf build/ MANIFEST
++ find . -name '*.pyc' -delete
+--- /dev/null
++++ jmc-0.3b3/analyse_profiling.py
+@@ -0,0 +1,27 @@
++# -*- coding: utf-8 -*-
++##
++## analyse_profiling.py
++## Login : David Rousselie <dax@happycoders.org>
++## Started on Thu May 29 19:09:02 2008 David Rousselie
++## $Id$
++##
++## Copyright (C) 2008 David Rousselie
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++##
++
++import pstats
++
++stats = pstats.Stats("jmc.prof")
++stats.strip_dirs().sort_stats('time').print_stats()
+--- /dev/null
++++ jmc-0.3b3/run_tests.py
+@@ -0,0 +1,71 @@
++# -*- coding: utf-8 -*-
++##
++## run_tests.py
++## Login : David Rousselie <dax@happycoders.org>
++## Started on Wed Aug 9 21:37:35 2006 David Rousselie
++## $Id$
++##
++## Copyright (C) 2006 David Rousselie
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++##
++
++import coverage
++coverage.erase()
++coverage.start()
++
++import logging
++import unittest
++from test import test_support
++
++import sys
++sys.path.append("src")
++reload(sys)
++sys.setdefaultencoding('utf8')
++del sys.setdefaultencoding
++
++import jmc
++import jmc.jabber
++import jmc.jabber.component
++
++import jmc.tests
++
++def suite():
++ return jmc.tests.suite()
++
++if __name__ == '__main__':
++ class MyTestProgram(unittest.TestProgram):
++ def runTests(self):
++ """run tests but do not exit after"""
++ self.testRunner = unittest.TextTestRunner(verbosity=self.verbosity)
++ self.testRunner.run(self.test)
++
++ logger = logging.getLogger()
++ logger.addHandler(logging.StreamHandler())
++ logger.setLevel(logging.CRITICAL)
++
++ MyTestProgram(defaultTest='suite')
++
++coverage.report(["src/jmc/__init__.py",
++ "src/jmc/lang.py",
++ "src/jmc/runner.py",
++ "src/jmc/jabber/__init__.py",
++ "src/jmc/jabber/command.py",
++ "src/jmc/jabber/component.py",
++ "src/jmc/jabber/disco.py",
++ "src/jmc/jabber/message.py",
++ "src/jmc/jabber/presence.py",
++ "src/jmc/jabber/presence.py",
++ "src/jmc/model/__init__.py",
++ "src/jmc/model/account.py"])
+--- /dev/null
++++ jmc-0.3b3/profile_jmc.py
+@@ -0,0 +1,27 @@
++# -*- coding: utf-8 -*-
++##
++## profile_jmc.py
++## Login : David Rousselie <dax@happycoders.org>
++## Started on Thu May 29 19:09:02 2008 David Rousselie
++## $Id$
++##
++## Copyright (C) 2008 David Rousselie
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++##
++
++import cProfile
++import jmc.runner as runner
++
++cProfile.run("runner.main()", "jmc.prof")
+--- /dev/null
++++ jmc-0.3b3/resolv.conf
+@@ -0,0 +1,2 @@
++# Generated by NetworkManager
++nameserver 192.168.10.110
+--- /dev/null
++++ jmc-0.3b3/COPYING
+@@ -0,0 +1,340 @@
++ GNU GENERAL PUBLIC LICENSE
++ Version 2, June 1991
++
++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
++ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ Everyone is permitted to copy and distribute verbatim copies
++ of this license document, but changing it is not allowed.
++
++ Preamble
++
++ The licenses for most software are designed to take away your
++freedom to share and change it. By contrast, the GNU General Public
++License is intended to guarantee your freedom to share and change free
++software--to make sure the software is free for all its users. This
++General Public License applies to most of the Free Software
++Foundation's software and to any other program whose authors commit to
++using it. (Some other Free Software Foundation software is covered by
++the GNU Library General Public License instead.) You can apply it to
++your programs, too.
++
++ When we speak of free software, we are referring to freedom, not
++price. Our General Public Licenses are designed to make sure that you
++have the freedom to distribute copies of free software (and charge for
++this service if you wish), that you receive source code or can get it
++if you want it, that you can change the software or use pieces of it
++in new free programs; and that you know you can do these things.
++
++ To protect your rights, we need to make restrictions that forbid
++anyone to deny you these rights or to ask you to surrender the rights.
++These restrictions translate to certain responsibilities for you if you
++distribute copies of the software, or if you modify it.
++
++ For example, if you distribute copies of such a program, whether
++gratis or for a fee, you must give the recipients all the rights that
++you have. You must make sure that they, too, receive or can get the
++source code. And you must show them these terms so they know their
++rights.
++
++ We protect your rights with two steps: (1) copyright the software, and
++(2) offer you this license which gives you legal permission to copy,
++distribute and/or modify the software.
++
++ Also, for each author's protection and ours, we want to make certain
++that everyone understands that there is no warranty for this free
++software. If the software is modified by someone else and passed on, we
++want its recipients to know that what they have is not the original, so
++that any problems introduced by others will not reflect on the original
++authors' reputations.
++
++ Finally, any free program is threatened constantly by software
++patents. We wish to avoid the danger that redistributors of a free
++program will individually obtain patent licenses, in effect making the
++program proprietary. To prevent this, we have made it clear that any
++patent must be licensed for everyone's free use or not licensed at all.
++
++ The precise terms and conditions for copying, distribution and
++modification follow.
++
++ GNU GENERAL PUBLIC LICENSE
++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++
++ 0. This License applies to any program or other work which contains
++a notice placed by the copyright holder saying it may be distributed
++under the terms of this General Public License. The "Program", below,
++refers to any such program or work, and a "work based on the Program"
++means either the Program or any derivative work under copyright law:
++that is to say, a work containing the Program or a portion of it,
++either verbatim or with modifications and/or translated into another
++language. (Hereinafter, translation is included without limitation in
++the term "modification".) Each licensee is addressed as "you".
++
++Activities other than copying, distribution and modification are not
++covered by this License; they are outside its scope. The act of
++running the Program is not restricted, and the output from the Program
++is covered only if its contents constitute a work based on the
++Program (independent of having been made by running the Program).
++Whether that is true depends on what the Program does.
++
++ 1. You may copy and distribute verbatim copies of the Program's
++source code as you receive it, in any medium, provided that you
++conspicuously and appropriately publish on each copy an appropriate
++copyright notice and disclaimer of warranty; keep intact all the
++notices that refer to this License and to the absence of any warranty;
++and give any other recipients of the Program a copy of this License
++along with the Program.
++
++You may charge a fee for the physical act of transferring a copy, and
++you may at your option offer warranty protection in exchange for a fee.
++
++ 2. You may modify your copy or copies of the Program or any portion
++of it, thus forming a work based on the Program, and copy and
++distribute such modifications or work under the terms of Section 1
++above, provided that you also meet all of these conditions:
++
++ a) You must cause the modified files to carry prominent notices
++ stating that you changed the files and the date of any change.
++
++ b) You must cause any work that you distribute or publish, that in
++ whole or in part contains or is derived from the Program or any
++ part thereof, to be licensed as a whole at no charge to all third
++ parties under the terms of this License.
++
++ c) If the modified program normally reads commands interactively
++ when run, you must cause it, when started running for such
++ interactive use in the most ordinary way, to print or display an
++ announcement including an appropriate copyright notice and a
++ notice that there is no warranty (or else, saying that you provide
++ a warranty) and that users may redistribute the program under
++ these conditions, and telling the user how to view a copy of this
++ License. (Exception: if the Program itself is interactive but
++ does not normally print such an announcement, your work based on
++ the Program is not required to print an announcement.)
++
++These requirements apply to the modified work as a whole. If
++identifiable sections of that work are not derived from the Program,
++and can be reasonably considered independent and separate works in
++themselves, then this License, and its terms, do not apply to those
++sections when you distribute them as separate works. But when you
++distribute the same sections as part of a whole which is a work based
++on the Program, the distribution of the whole must be on the terms of
++this License, whose permissions for other licensees extend to the
++entire whole, and thus to each and every part regardless of who wrote it.
++
++Thus, it is not the intent of this section to claim rights or contest
++your rights to work written entirely by you; rather, the intent is to
++exercise the right to control the distribution of derivative or
++collective works based on the Program.
++
++In addition, mere aggregation of another work not based on the Program
++with the Program (or with a work based on the Program) on a volume of
++a storage or distribution medium does not bring the other work under
++the scope of this License.
++
++ 3. You may copy and distribute the Program (or a work based on it,
++under Section 2) in object code or executable form under the terms of
++Sections 1 and 2 above provided that you also do one of the following:
++
++ a) Accompany it with the complete corresponding machine-readable
++ source code, which must be distributed under the terms of Sections
++ 1 and 2 above on a medium customarily used for software interchange; or,
++
++ b) Accompany it with a written offer, valid for at least three
++ years, to give any third party, for a charge no more than your
++ cost of physically performing source distribution, a complete
++ machine-readable copy of the corresponding source code, to be
++ distributed under the terms of Sections 1 and 2 above on a medium
++ customarily used for software interchange; or,
++
++ c) Accompany it with the information you received as to the offer
++ to distribute corresponding source code. (This alternative is
++ allowed only for noncommercial distribution and only if you
++ received the program in object code or executable form with such
++ an offer, in accord with Subsection b above.)
++
++The source code for a work means the preferred form of the work for
++making modifications to it. For an executable work, complete source
++code means all the source code for all modules it contains, plus any
++associated interface definition files, plus the scripts used to
++control compilation and installation of the executable. However, as a
++special exception, the source code distributed need not include
++anything that is normally distributed (in either source or binary
++form) with the major components (compiler, kernel, and so on) of the
++operating system on which the executable runs, unless that component
++itself accompanies the executable.
++
++If distribution of executable or object code is made by offering
++access to copy from a designated place, then offering equivalent
++access to copy the source code from the same place counts as
++distribution of the source code, even though third parties are not
++compelled to copy the source along with the object code.
++
++ 4. You may not copy, modify, sublicense, or distribute the Program
++except as expressly provided under this License. Any attempt
++otherwise to copy, modify, sublicense or distribute the Program is
++void, and will automatically terminate your rights under this License.
++However, parties who have received copies, or rights, from you under
++this License will not have their licenses terminated so long as such
++parties remain in full compliance.
++
++ 5. You are not required to accept this License, since you have not
++signed it. However, nothing else grants you permission to modify or
++distribute the Program or its derivative works. These actions are
++prohibited by law if you do not accept this License. Therefore, by
++modifying or distributing the Program (or any work based on the
++Program), you indicate your acceptance of this License to do so, and
++all its terms and conditions for copying, distributing or modifying
++the Program or works based on it.
++
++ 6. Each time you redistribute the Program (or any work based on the
++Program), the recipient automatically receives a license from the
++original licensor to copy, distribute or modify the Program subject to
++these terms and conditions. You may not impose any further
++restrictions on the recipients' exercise of the rights granted herein.
++You are not responsible for enforcing compliance by third parties to
++this License.
++
++ 7. If, as a consequence of a court judgment or allegation of patent
++infringement or for any other reason (not limited to patent issues),
++conditions are imposed on you (whether by court order, agreement or
++otherwise) that contradict the conditions of this License, they do not
++excuse you from the conditions of this License. If you cannot
++distribute so as to satisfy simultaneously your obligations under this
++License and any other pertinent obligations, then as a consequence you
++may not distribute the Program at all. For example, if a patent
++license would not permit royalty-free redistribution of the Program by
++all those who receive copies directly or indirectly through you, then
++the only way you could satisfy both it and this License would be to
++refrain entirely from distribution of the Program.
++
++If any portion of this section is held invalid or unenforceable under
++any particular circumstance, the balance of the section is intended to
++apply and the section as a whole is intended to apply in other
++circumstances.
++
++It is not the purpose of this section to induce you to infringe any
++patents or other property right claims or to contest validity of any
++such claims; this section has the sole purpose of protecting the
++integrity of the free software distribution system, which is
++implemented by public license practices. Many people have made
++generous contributions to the wide range of software distributed
++through that system in reliance on consistent application of that
++system; it is up to the author/donor to decide if he or she is willing
++to distribute software through any other system and a licensee cannot
++impose that choice.
++
++This section is intended to make thoroughly clear what is believed to
++be a consequence of the rest of this License.
++
++ 8. If the distribution and/or use of the Program is restricted in
++certain countries either by patents or by copyrighted interfaces, the
++original copyright holder who places the Program under this License
++may add an explicit geographical distribution limitation excluding
++those countries, so that distribution is permitted only in or among
++countries not thus excluded. In such case, this License incorporates
++the limitation as if written in the body of this License.
++
++ 9. The Free Software Foundation may publish revised and/or new versions
++of the General Public License from time to time. Such new versions will
++be similar in spirit to the present version, but may differ in detail to
++address new problems or concerns.
++
++Each version is given a distinguishing version number. If the Program
++specifies a version number of this License which applies to it and "any
++later version", you have the option of following the terms and conditions
++either of that version or of any later version published by the Free
++Software Foundation. If the Program does not specify a version number of
++this License, you may choose any version ever published by the Free Software
++Foundation.
++
++ 10. If you wish to incorporate parts of the Program into other free
++programs whose distribution conditions are different, write to the author
++to ask for permission. For software which is copyrighted by the Free
++Software Foundation, write to the Free Software Foundation; we sometimes
++make exceptions for this. Our decision will be guided by the two goals
++of preserving the free status of all derivatives of our free software and
++of promoting the sharing and reuse of software generally.
++
++ NO WARRANTY
++
++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
++REPAIR OR CORRECTION.
++
++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
++POSSIBILITY OF SUCH DAMAGES.
++
++ END OF TERMS AND CONDITIONS
++
++ How to Apply These Terms to Your New Programs
++
++ If you develop a new program, and you want it to be of the greatest
++possible use to the public, the best way to achieve this is to make it
++free software which everyone can redistribute and change under these terms.
++
++ To do so, attach the following notices to the program. It is safest
++to attach them to the start of each source file to most effectively
++convey the exclusion of warranty; and each file should have at least
++the "copyright" line and a pointer to where the full notice is found.
++
++ <one line to give the program's name and a brief idea of what it does.>
++ Copyright (C) <year> <name of author>
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++
++
++Also add information on how to contact you by electronic and paper mail.
++
++If the program is interactive, make it output a short notice like this
++when it starts in an interactive mode:
++
++ Gnomovision version 69, Copyright (C) year name of author
++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
++ This is free software, and you are welcome to redistribute it
++ under certain conditions; type `show c' for details.
++
++The hypothetical commands `show w' and `show c' should show the appropriate
++parts of the General Public License. Of course, the commands you use may
++be called something other than `show w' and `show c'; they could even be
++mouse-clicks or menu items--whatever suits your program.
++
++You should also get your employer (if you work as a programmer) or your
++school, if any, to sign a "copyright disclaimer" for the program, if
++necessary. Here is a sample; alter the names:
++
++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
++ `Gnomovision' (which makes passes at compilers) written by James Hacker.
++
++ <signature of Ty Coon>, 1 April 1989
++ Ty Coon, President of Vice
++
++This General Public License does not permit incorporating your program into
++proprietary programs. If your program is a subroutine library, you may
++consider it more useful to permit linking proprietary applications with the
++library. If this is what you want to do, use the GNU Library General
++Public License instead of this License.
+--- /dev/null
++++ jmc-0.3b3/TODO
+@@ -0,0 +1,12 @@
++* Support for attachements with size limit and file format limit
++ (e.g. only png, jpeg,... but no exe, bat,...).
++
++* Make real documentation
++
++* Support for Ad Hoc Commands (see PyMSNt cvs, avatar
++ branch). Interesting for statistics.
++
++* Support for epoll, kpoll and kqueu (see PyMSNt cvs, avatar branch
++ code).
++
++
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-11-05/POP3Account_sqlite.sql
+@@ -0,0 +1,9 @@
++-- Exported definition from 2007-11-05T19:02:34
++-- Class jmc.model.account.POP3Account
++-- Database: sqlite
++CREATE TABLE po_p3_account (
++ id INTEGER PRIMARY KEY,
++ nb_mail INT,
++ lastmail INT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-11-05/PresenceAccount_sqlite.sql
+@@ -0,0 +1,13 @@
++-- Exported definition from 2007-11-05T19:02:34
++-- Class jcl.model.account.PresenceAccount
++-- Database: sqlite
++CREATE TABLE presence_account (
++ id INTEGER PRIMARY KEY,
++ chat_action INT,
++ online_action INT,
++ away_action INT,
++ xa_action INT,
++ dnd_action INT,
++ offline_action INT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-11-05/IMAPAccount_sqlite.sql
+@@ -0,0 +1,9 @@
++-- Exported definition from 2007-11-05T19:02:34
++-- Class jmc.model.account.IMAPAccount
++-- Database: sqlite
++CREATE TABLE imap_account (
++ id INTEGER PRIMARY KEY,
++ mailbox TEXT,
++ delimiter TEXT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-11-05/User_sqlite.sql
+@@ -0,0 +1,9 @@
++-- Exported definition from 2007-11-05T19:02:34
++-- Class jcl.model.account.User
++-- Database: sqlite
++CREATE TABLE user (
++ id INTEGER PRIMARY KEY,
++ jid TEXT,
++ has_received_motd TINYINT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-11-05/LegacyJID_sqlite.sql
+@@ -0,0 +1,10 @@
++-- Exported definition from 2007-11-05T19:02:34
++-- Class jcl.model.account.LegacyJID
++-- Database: sqlite
++CREATE TABLE legacy_j_id (
++ id INTEGER PRIMARY KEY,
++ legacy_address TEXT,
++ jid TEXT,
++ account_id INT CONSTRAINT account_id_exists REFERENCES account(id) ,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-11-05/SMTPAccount_sqlite.sql
+@@ -0,0 +1,16 @@
++-- Exported definition from 2007-11-05T19:02:34
++-- Class jmc.model.account.SMTPAccount
++-- Database: sqlite
++CREATE TABLE smtp_account (
++ id INTEGER PRIMARY KEY,
++ login TEXT,
++ password TEXT,
++ host TEXT,
++ port INT,
++ tls TINYINT,
++ store_password TINYINT,
++ waiting_password_reply TINYINT,
++ default_from TEXT,
++ default_account TINYINT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-11-05/MailAccount_sqlite.sql
+@@ -0,0 +1,18 @@
++-- Exported definition from 2007-11-05T19:02:34
++-- Class jmc.model.account.MailAccount
++-- Database: sqlite
++CREATE TABLE mail_account (
++ id INTEGER PRIMARY KEY,
++ login TEXT,
++ password TEXT,
++ host TEXT,
++ port INT,
++ _ssl TINYINT,
++ _interval INT,
++ store_password TINYINT,
++ live_email_only TINYINT,
++ lastcheck INT,
++ waiting_password_reply TINYINT,
++ first_check TINYINT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-11-05/Account_sqlite.sql
+@@ -0,0 +1,14 @@
++-- Exported definition from 2007-11-05T19:02:34
++-- Class jcl.model.account.Account
++-- Database: sqlite
++CREATE TABLE account (
++ id INTEGER PRIMARY KEY,
++ name TEXT,
++ jid TEXT,
++ status TEXT,
++ in_error TINYINT,
++ enabled TINYINT,
++ lastlogin TIMESTAMP,
++ user_id INT CONSTRAINT user_id_exists REFERENCES user(id) ,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2008-05-29/POP3Account_sqlite.sql
+@@ -0,0 +1,9 @@
++-- Exported definition from 2008-05-29T19:26:03
++-- Class jmc.model.account.POP3Account
++-- Database: sqlite
++CREATE TABLE po_p3_account (
++ id INTEGER PRIMARY KEY,
++ nb_mail INT,
++ lastmail INT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2008-05-29/IMAPAccount_sqlite.sql
+@@ -0,0 +1,9 @@
++-- Exported definition from 2008-05-29T19:26:03
++-- Class jmc.model.account.IMAPAccount
++-- Database: sqlite
++CREATE TABLE imap_account (
++ id INTEGER PRIMARY KEY,
++ mailbox TEXT,
++ delimiter TEXT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2008-05-29/SMTPAccount_sqlite.sql
+@@ -0,0 +1,7 @@
++-- Exported definition from 2008-05-29T19:26:03
++-- Class jmc.model.account.SMTPAccount
++-- Database: sqlite
++CREATE TABLE smtp_account (
++ id INTEGER PRIMARY KEY,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2008-05-29/MailAccount_sqlite.sql
+@@ -0,0 +1,18 @@
++-- Exported definition from 2008-05-29T19:26:03
++-- Class jmc.model.account.MailAccount
++-- Database: sqlite
++CREATE TABLE mail_account (
++ id INTEGER PRIMARY KEY,
++ login TEXT,
++ password TEXT,
++ host TEXT,
++ port INT,
++ _ssl TINYINT,
++ _interval INT,
++ store_password TINYINT,
++ live_email_only TINYINT,
++ lastcheck INT,
++ waiting_password_reply TINYINT,
++ first_check TINYINT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2008-05-29/AbstractSMTPAccount_sqlite.sql
+@@ -0,0 +1,9 @@
++-- Exported definition from 2008-05-29T19:26:03
++-- Class jmc.model.account.AbstractSMTPAccount
++-- Database: sqlite
++CREATE TABLE abstract_smtp_account (
++ id INTEGER PRIMARY KEY,
++ default_from TEXT,
++ default_account TINYINT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2008-05-29/GlobalSMTPAccount_sqlite.sql
+@@ -0,0 +1,14 @@
++-- Exported definition from 2008-05-29T19:26:03
++-- Class jmc.model.account.GlobalSMTPAccount
++-- Database: sqlite
++CREATE TABLE global_smtp_account (
++ id INTEGER PRIMARY KEY,
++ login TEXT,
++ password TEXT,
++ host TEXT,
++ port INT,
++ tls TINYINT,
++ store_password TINYINT,
++ waiting_password_reply TINYINT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-12-04/POP3Account_sqlite.sql
+@@ -0,0 +1,9 @@
++-- Exported definition from 2007-12-04T17:57:39
++-- Class jmc.model.account.POP3Account
++-- Database: sqlite
++CREATE TABLE po_p3_account (
++ id INTEGER PRIMARY KEY,
++ nb_mail INT,
++ lastmail INT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-12-04/PresenceAccount_sqlite.sql
+@@ -0,0 +1,13 @@
++-- Exported definition from 2007-12-04T17:57:39
++-- Class jcl.model.account.PresenceAccount
++-- Database: sqlite
++CREATE TABLE presence_account (
++ id INTEGER PRIMARY KEY,
++ chat_action INT,
++ online_action INT,
++ away_action INT,
++ xa_action INT,
++ dnd_action INT,
++ offline_action INT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-12-04/upgrade_sqlite_2008-05-29.sql
+@@ -0,0 +1,66 @@
++-- Class jmc.model.account.AbstractSMTPAccount
++-- Database: sqlite
++CREATE TABLE abstract_smtp_account (
++ id INTEGER PRIMARY KEY,
++ default_from TEXT,
++ default_account TINYINT,
++ child_name VARCHAR(255)
++);
++
++-- Class jmc.model.account.GlobalSMTPAccount
++-- Database: sqlite
++CREATE TABLE global_smtp_account (
++ id INTEGER PRIMARY KEY,
++ login TEXT,
++ password TEXT,
++ host TEXT,
++ port INT,
++ tls TINYINT,
++ store_password TINYINT,
++ waiting_password_reply TINYINT,
++ child_name VARCHAR(255)
++);
++
++INSERT INTO abstract_smtp_account
++ SELECT
++ id,
++ default_from,
++ default_account,
++ "GlobalSMTPAccount"
++ FROM
++ smtp_account;
++
++INSERT INTO global_smtp_account
++ SELECT
++ id,
++ login,
++ password,
++ host,
++ port,
++ tls,
++ store_password,
++ waiting_password_reply,
++ "SMTPAccount"
++ FROM
++ smtp_account;
++
++DROP TABLE smtp_account;
++
++-- Class jmc.model.account.SMTPAccount
++-- Database: sqlite
++CREATE TABLE smtp_account (
++ id INTEGER PRIMARY KEY,
++ child_name VARCHAR(255)
++);
++
++INSERT INTO smtp_account
++ SELECT
++ id,
++ NULL
++ FROM
++ global_smtp_account;
++
++UPDATE account SET
++ child_name="AbstractSMTPAccount"
++WHERE
++ child_name="SMTPAccount";
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-12-04/IMAPAccount_sqlite.sql
+@@ -0,0 +1,9 @@
++-- Exported definition from 2007-12-04T17:57:39
++-- Class jmc.model.account.IMAPAccount
++-- Database: sqlite
++CREATE TABLE imap_account (
++ id INTEGER PRIMARY KEY,
++ mailbox TEXT,
++ delimiter TEXT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-12-04/User_sqlite.sql
+@@ -0,0 +1,9 @@
++-- Exported definition from 2007-12-04T17:57:39
++-- Class jcl.model.account.User
++-- Database: sqlite
++CREATE TABLE user (
++ id INTEGER PRIMARY KEY,
++ jid TEXT,
++ has_received_motd TINYINT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-12-04/LegacyJID_sqlite.sql
+@@ -0,0 +1,10 @@
++-- Exported definition from 2007-12-04T17:57:39
++-- Class jcl.model.account.LegacyJID
++-- Database: sqlite
++CREATE TABLE legacy_j_id (
++ id INTEGER PRIMARY KEY,
++ legacy_address TEXT,
++ jid TEXT,
++ account_id INT CONSTRAINT account_id_exists REFERENCES account(id) ,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-12-04/SMTPAccount_sqlite.sql
+@@ -0,0 +1,16 @@
++-- Exported definition from 2007-12-04T17:57:39
++-- Class jmc.model.account.SMTPAccount
++-- Database: sqlite
++CREATE TABLE smtp_account (
++ id INTEGER PRIMARY KEY,
++ login TEXT,
++ password TEXT,
++ host TEXT,
++ port INT,
++ tls TINYINT,
++ store_password TINYINT,
++ waiting_password_reply TINYINT,
++ default_from TEXT,
++ default_account TINYINT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-12-04/MailAccount_sqlite.sql
+@@ -0,0 +1,18 @@
++-- Exported definition from 2007-12-04T17:57:39
++-- Class jmc.model.account.MailAccount
++-- Database: sqlite
++CREATE TABLE mail_account (
++ id INTEGER PRIMARY KEY,
++ login TEXT,
++ password TEXT,
++ host TEXT,
++ port INT,
++ _ssl TINYINT,
++ _interval INT,
++ store_password TINYINT,
++ live_email_only TINYINT,
++ lastcheck INT,
++ waiting_password_reply TINYINT,
++ first_check TINYINT,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/sqlobject_history/2007-12-04/Account_sqlite.sql
+@@ -0,0 +1,14 @@
++-- Exported definition from 2007-12-04T17:57:39
++-- Class jcl.model.account.Account
++-- Database: sqlite
++CREATE TABLE account (
++ id INTEGER PRIMARY KEY,
++ name TEXT,
++ jid TEXT,
++ status TEXT,
++ error TEXT,
++ enabled TINYINT,
++ lastlogin TIMESTAMP,
++ user_id INT CONSTRAINT user_id_exists REFERENCES user(id) ,
++ child_name VARCHAR(255)
++)
+--- /dev/null
++++ jmc-0.3b3/conf/jmc.conf
+@@ -0,0 +1,45 @@
++[jabber]
++server: localhost
++port: 5347
++secret: secret
++service_jid: jmc.localhost
++#supported language: en, fr (See src/jmc/lang.py to add more)
++language: en
++
++[db]
++#SQLite config
++type: sqlite
++host:
++name: /var/spool/jabber/jmc.db
++#Mysql config
++#type: mysql
++#host: root:pass@localhost
++#name: /jmc
++#db_url: %(type)s://%(host)s%(name)s?debug=1&debugThreading=1
++db_url: %(type)s://%(host)s%(name)s
++
++
++[component]
++pid_file: /var/run/jabber/jmc.pid
++#motd: "Message of the day"
++welcome_message: "Welcome to Jabber Mail Component"
++# a comma separated list of JIDs
++admins: admin@localhost
++log_file: /var/log/jabber/jmc.log
++
++[jmc]
++mail_default_encoding: iso-8859-1
++check_interval: 1
++
++[vcard]
++url: http://people.happycoders.org/dax/projects/jmc
++
++[smtp]
++smtp_default_login: test
++smtp_default_password: test
++smtp_default_host: testhost
++smtp_default_port: 25
++smtp_default_tls: True
++smtp_default_label: Default SMTP Server
++enable_smtp_default_account: False
++
+--- /dev/null
++++ jmc-0.3b3/src/jmc/tests/runner.py
+@@ -0,0 +1,324 @@
++##
++## runner.py
++## Login : David Rousselie <dax@happycoders.org>
++## Started on Fri May 18 13:43:37 2007 David Rousselie
++## $Id$
++##
++## Copyright (C) 2007 David Rousselie
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++##
++
++import unittest
++import sys
++import os
++
++from jcl.tests import JCLTestCase
++from jcl.tests.runner import JCLRunner_TestCase
++
++import jcl.model as model
++from jcl.model.account import Account, PresenceAccount, User, LegacyJID
++
++import jmc
++from jmc.lang import Lang
++from jmc.runner import JMCRunner
++from jmc.jabber.component import MailComponent
++import jmc.model.account as account
++from jmc.model.account import MailAccount, IMAPAccount, POP3Account, \
++ AbstractSMTPAccount, GlobalSMTPAccount, SMTPAccount
++
++if sys.platform == "win32":
++ DB_PATH = "/c|/temp/test.db"
++else:
++ DB_PATH = "/tmp/test.db"
++DB_URL = "sqlite://" + DB_PATH# + "?debug=1&debugThreading=1"
++
++class JMCRunner_TestCase(JCLTestCase):
++ def setUp(self):
++ JCLTestCase.setUp(self, tables=[Account, PresenceAccount, User,
++ GlobalSMTPAccount, AbstractSMTPAccount])
++ self.runner = JMCRunner("Jabber Mail Component", jmc.version)
++ self.smtp_default_login = account.smtp_default_login
++ self.smtp_default_password = account.smtp_default_password
++ self.smtp_default_host = account.smtp_default_host
++ self.smtp_default_port = account.smtp_default_port
++ self.smtp_default_tls = account.smtp_default_tls
++ self.mail_default_encoding = MailAccount.default_encoding
++ self.type_globalsmtp_name = Lang.en.type_globalsmtp_name
++
++ def tearDown(self):
++ self.runner = None
++ sys.argv = [""]
++ account.smtp_default_login = self.smtp_default_login
++ account.smtp_default_password = self.smtp_default_password
++ account.smtp_default_host = self.smtp_default_host
++ account.smtp_default_port = self.smtp_default_port
++ account.smtp_default_tls = self.smtp_default_tls
++ MailAccount.default_encoding = self.mail_default_encoding
++ Lang.en.type_globalsmtp_name = self.type_globalsmtp_name
++
++ def test_configure_default(self):
++ self.runner.configure()
++ self.assertEquals(self.runner.config_file, "jmc.conf")
++ self.assertEquals(self.runner.server, "localhost")
++ self.assertEquals(self.runner.port, 5347)
++ self.assertEquals(self.runner.secret, "secret")
++ self.assertEquals(self.runner.service_jid, "jmc.localhost")
++ self.assertEquals(self.runner.language, "en")
++ self.assertEquals(self.runner.db_url, "sqlite:///var/spool/jabber/jmc.db")
++ self.assertEquals(self.runner.pid_file, "/var/run/jabber/jmc.pid")
++ self.assertFalse(self.runner.debug)
++ self.assertEquals(self.runner.mail_default_encoding, "iso-8859-1")
++ self.assertEquals(self.runner.smtp_default_login, None)
++ self.assertEquals(self.runner.smtp_default_password, None)
++ self.assertEquals(self.runner.smtp_default_host, None)
++ self.assertEquals(self.runner.smtp_default_port, 0)
++ self.assertEquals(self.runner.smtp_default_tls, False)
++ self.assertEquals(self.runner.enable_smtp_default_account, False)
++ self.assertEquals(self.runner.smtp_default_label, None)
++ self.runner.setup_smtp_default()
++ self.assertEquals(Lang.en.type_globalsmtp_name,
++ "Default SMTP Server")
++ _account = GlobalSMTPAccount(user=User(jid="user1@test.com"),
++ name="account1",
++ jid="account1@jmc.test.com")
++ self.assertEquals(_account.login, '')
++ self.assertEquals(_account.password, '')
++ self.assertEquals(_account.host, 'localhost')
++ self.assertEquals(_account.port, 25)
++ self.assertEquals(_account.tls, False)
++
++ def test_configure_configfile(self):
++ self.runner.config_file = "src/jmc/tests/jmc.conf"
++ self.runner.configure()
++ self.assertEquals(self.runner.server, "test_localhost")
++ self.assertEquals(self.runner.port, 42)
++ self.assertEquals(self.runner.secret, "test_secret")
++ self.assertEquals(self.runner.service_jid, "test_jmc.localhost")
++ self.assertEquals(self.runner.language, "test_en")
++ self.assertEquals(self.runner.db_url, "test_sqlite://root@localhost/var/spool/jabber/test_jmc.db")
++ self.assertEquals(self.runner.pid_file, "/var/run/jabber/test_jmc.pid")
++ self.assertFalse(self.runner.debug)
++ self.assertEquals(self.runner.mail_default_encoding, "test_iso-8859-1")
++ self.assertEquals(self.runner.smtp_default_login, "testlogin")
++ self.assertEquals(self.runner.smtp_default_password, "testpassword")
++ self.assertEquals(self.runner.smtp_default_host, "testhost")
++ self.assertEquals(self.runner.smtp_default_port, 2525)
++ self.assertEquals(self.runner.smtp_default_tls, True)
++ self.assertEquals(self.runner.enable_smtp_default_account, True)
++ self.assertEquals(self.runner.smtp_default_label, "SMTP Server")
++ self.runner.setup_smtp_default()
++ self.assertEquals(Lang.en.type_globalsmtp_name,
++ "SMTP Server")
++ _account = GlobalSMTPAccount(user=User(jid="user1@test.com"),
++ name="account1",
++ jid="account1@jmc.test.com")
++ self.assertEquals(_account.login, 'testlogin')
++ self.assertEquals(_account.password, 'testpassword')
++ self.assertEquals(_account.host, 'testhost')
++ self.assertEquals(_account.port, 2525)
++ self.assertEquals(_account.tls, True)
++
++ def test_configure_uncomplete_configfile(self):
++ self.runner.config_file = "src/jmc/tests/uncomplete_jmc.conf"
++ self.runner.configure()
++ self.assertEquals(self.runner.server, "test_localhost")
++ self.assertEquals(self.runner.port, 42)
++ self.assertEquals(self.runner.secret, "test_secret")
++ self.assertEquals(self.runner.service_jid, "test_jmc.localhost")
++ self.assertEquals(self.runner.language, "test_en")
++ self.assertEquals(self.runner.db_url, "test_sqlite://root@localhost/var/spool/jabber/test_jmc.db")
++ self.assertEquals(self.runner.pid_file, "/var/run/jabber/test_jmc.pid")
++ self.assertFalse(self.runner.debug)
++ self.assertEquals(self.runner.mail_default_encoding, "test_iso-8859-1")
++ self.assertEquals(self.runner.smtp_default_login, None)
++ self.assertEquals(self.runner.smtp_default_password, None)
++ self.assertEquals(self.runner.smtp_default_host, None)
++ self.assertEquals(self.runner.smtp_default_port, 0)
++ self.assertEquals(self.runner.smtp_default_tls, False)
++ self.assertEquals(self.runner.enable_smtp_default_account, False)
++ self.assertEquals(self.runner.smtp_default_label, None)
++ self.runner.setup_smtp_default()
++ self.assertEquals(Lang.en.type_globalsmtp_name,
++ "Default SMTP Server")
++ _account = GlobalSMTPAccount(user=User(jid="user1@test.com"),
++ name="account1",
++ jid="account1@jmc.test.com")
++ self.assertEquals(_account.login, '')
++ self.assertEquals(_account.password, '')
++ self.assertEquals(_account.host, 'localhost')
++ self.assertEquals(_account.port, 25)
++ self.assertEquals(_account.tls, False)
++
++ def test_configure_commandline_shortopt(self):
++ sys.argv = ["", "-c", "src/jmc/tests/jmc.conf",
++ "-S", "test2_localhost",
++ "-P", "43",
++ "-s", "test2_secret",
++ "-j", "test2_jmc.localhost",
++ "-l", "test2_en",
++ "-u", "sqlite:///tmp/test_jmc.db",
++ "-p", "/tmp/test_jmc.pid",
++ "-e", "test2_iso-8859-1",
++ "-g", "testlogin",
++ "-a", "testpassword",
++ "-t", "testhost",
++ "-r", "2525",
++ "-m", "True",
++ "-n", "True",
++ "-b", "My Global SMTP server"]
++ self.runner.configure()
++ self.assertEquals(self.runner.server, "test2_localhost")
++ self.assertEquals(self.runner.port, 43)
++ self.assertEquals(self.runner.secret, "test2_secret")
++ self.assertEquals(self.runner.service_jid, "test2_jmc.localhost")
++ self.assertEquals(self.runner.language, "test2_en")
++ self.assertEquals(self.runner.db_url, "sqlite:///tmp/test_jmc.db")
++ self.assertEquals(self.runner.pid_file, "/tmp/test_jmc.pid")
++ self.assertFalse(self.runner.debug)
++ self.assertEquals(self.runner.mail_default_encoding, "test2_iso-8859-1")
++ self.assertEquals(self.runner.smtp_default_login, "testlogin")
++ self.assertEquals(self.runner.smtp_default_password, "testpassword")
++ self.assertEquals(self.runner.smtp_default_host, "testhost")
++ self.assertEquals(self.runner.smtp_default_port, 2525)
++ self.assertEquals(self.runner.smtp_default_tls, True)
++ self.assertEquals(self.runner.enable_smtp_default_account, True)
++ self.assertEquals(self.runner.smtp_default_label, "My Global SMTP server")
++ self.runner.setup_smtp_default()
++ self.assertEquals(Lang.en.type_globalsmtp_name,
++ "My Global SMTP server")
++ _account = GlobalSMTPAccount(user=User(jid="user1@test.com"),
++ name="account1",
++ jid="account1@jmc.test.com")
++ self.assertEquals(_account.login, 'testlogin')
++ self.assertEquals(_account.password, 'testpassword')
++ self.assertEquals(_account.host, 'testhost')
++ self.assertEquals(_account.port, 2525)
++ self.assertEquals(_account.tls, True)
++
++ def test_configure_commandline_longopt(self):
++ sys.argv = ["", "--config-file", "src/jmc/tests/jmc.conf",
++ "--server", "test2_localhost",
++ "--port", "43",
++ "--secret", "test2_secret",
++ "--service-jid", "test2_jmc.localhost",
++ "--language", "test2_en",
++ "--db-url", "sqlite:///tmp/test_jmc.db",
++ "--pid-file", "/tmp/test_jmc.pid",
++ "--mail-default-encoding", "test2_iso-8859-1",
++ "--smtp-default-login", "testlogin",
++ "--smtp-default-password", "testpassword",
++ "--smtp-default-host", "testhost",
++ "--smtp-default-port", "2525",
++ "--smtp-default-tls", "True",
++ "--enable-smtp-default-account", "True",
++ "--smtp-default-label", "My Global SMTP server"]
++ self.runner.configure()
++ self.assertEquals(self.runner.server, "test2_localhost")
++ self.assertEquals(self.runner.port, 43)
++ self.assertEquals(self.runner.secret, "test2_secret")
++ self.assertEquals(self.runner.service_jid, "test2_jmc.localhost")
++ self.assertEquals(self.runner.language, "test2_en")
++ self.assertEquals(self.runner.db_url, "sqlite:///tmp/test_jmc.db")
++ self.assertEquals(self.runner.pid_file, "/tmp/test_jmc.pid")
++ self.assertFalse(self.runner.debug)
++ self.assertEquals(self.runner.mail_default_encoding, "test2_iso-8859-1")
++ self.assertEquals(self.runner.smtp_default_login, "testlogin")
++ self.assertEquals(self.runner.smtp_default_password, "testpassword")
++ self.assertEquals(self.runner.smtp_default_host, "testhost")
++ self.assertEquals(self.runner.smtp_default_port, 2525)
++ self.assertEquals(self.runner.smtp_default_tls, True)
++ self.assertEquals(self.runner.enable_smtp_default_account, True)
++ self.assertEquals(self.runner.smtp_default_label, "My Global SMTP server")
++ self.runner.setup_smtp_default()
++ self.assertEquals(Lang.en.type_globalsmtp_name,
++ "My Global SMTP server")
++ _account = GlobalSMTPAccount(user=User(jid="user1@test.com"),
++ name="account1",
++ jid="account1@jmc.test.com")
++ self.assertEquals(_account.login, 'testlogin')
++ self.assertEquals(_account.password, 'testpassword')
++ self.assertEquals(_account.host, 'testhost')
++ self.assertEquals(_account.port, 2525)
++ self.assertEquals(_account.tls, True)
++
++ def test__run(self):
++ self.runner.pid_file = "/tmp/jmc.pid"
++ self.runner.db_url = DB_URL
++ def do_nothing():
++ return (False, 0)
++ self.runner._run(do_nothing)
++ model.db_connection_str = self.runner.db_url
++ model.db_connect()
++ # dropTable should succeed because tables should exist
++ Account.dropTable()
++ PresenceAccount.dropTable()
++ User.dropTable()
++ LegacyJID.dropTable()
++ MailAccount.dropTable()
++ IMAPAccount.dropTable()
++ POP3Account.dropTable()
++ SMTPAccount.dropTable()
++ model.db_disconnect()
++ os.unlink(DB_PATH)
++ self.assertFalse(os.access("/tmp/jmc.pid", os.F_OK))
++
++ def test_run_without_smtp_default_account(self):
++ """ """
++ def run_func(mail_component_self):
++ """ """
++ self.assertEquals(mail_component_self.account_manager.account_classes,
++ (IMAPAccount, POP3Account, SMTPAccount))
++ return (False, 0)
++
++ self.runner.enable_smtp_default_account = False
++ self.runner.pid_file = "/tmp/jmc.pid"
++ self.runner.db_url = DB_URL
++ self.runner.config = None
++ old_run_func = MailComponent.run
++ MailComponent.run = run_func
++ try:
++ self.runner.run()
++ finally:
++ MailComponent.run = old_run_func
++ self.assertFalse(os.access("/tmp/jmc.pid", os.F_OK))
++
++ def test_run_with_smtp_default_account(self):
++ """ """
++ def run_func(mail_component_self):
++ """ """
++ self.assertEquals(mail_component_self.account_manager.account_classes,
++ (IMAPAccount, POP3Account, SMTPAccount,
++ GlobalSMTPAccount))
++ return (False, 0)
++
++ self.runner.enable_smtp_default_account = True
++ self.runner.pid_file = "/tmp/jmc.pid"
++ self.runner.db_url = DB_URL
++ self.runner.config = None
++ old_run_func = MailComponent.run
++ MailComponent.run = run_func
++ try:
++ self.runner.run()
++ finally:
++ MailComponent.run = old_run_func
++ self.assertFalse(os.access("/tmp/jmc.pid", os.F_OK))
++
++def suite():
++ test_suite = unittest.TestSuite()
++ test_suite.addTest(unittest.makeSuite(JMCRunner_TestCase, 'test'))
++ return test_suite
++
++if __name__ == '__main__':
++ unittest.main(defaultTest='suite')
+--- /dev/null
++++ jmc-0.3b3/src/jmc/tests/uncomplete_jmc.conf
+@@ -0,0 +1,23 @@
++[jabber]
++server: test_localhost
++port: 42
++secret: test_secret
++service_jid: test_jmc.localhost
++#supported language: en, fr (See src/jmc/lang.py to add more)
++language: test_en
++
++[db]
++#type: mysql
++type: test_sqlite
++#host: root@localhost
++host: root@localhost
++name: /var/spool/jabber/test_jmc.db
++#url: %(type)%(host)%(name)?debug=1&debugThreading=1
++db_url: %(type)s://%(host)s%(name)s
++
++[component]
++pid_file: /var/run/jabber/test_jmc.pid
++log_file: /tmp/jmc.log
++
++[jmc]
++mail_default_encoding: test_iso-8859-1
+--- /dev/null
++++ jmc-0.3b3/src/jmc/tests/__init__.py
+@@ -0,0 +1,19 @@
++"""JMC test module"""
++__revision__ = ""
++
++import unittest
++
++from jmc.tests import lang, runner
++from jmc.jabber import tests as jabber
++from jmc.model import tests as model
++
++def suite():
++ test_suite = unittest.TestSuite()
++ test_suite.addTest(lang.suite())
++ test_suite.addTest(runner.suite())
++ test_suite.addTest(jabber.suite())
++ test_suite.addTest(model.suite())
++ return test_suite
++
++if __name__ == '__main__':
++ unittest.main(defaultTest='suite')
+--- /dev/null
++++ jmc-0.3b3/src/jmc/tests/lang.py
+@@ -0,0 +1,219 @@
++# -*- coding: utf-8 -*-
++##
++## test_lang.py
++## Login : David Rousselie <david.rousselie@happycoders.org>
++## Started on Fri May 20 10:46:58 2005
++## $Id: test_lang.py,v 1.1 2005/07/11 20:39:31 dax Exp $
++##
++## Copyright (C) 2005
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++##
++
++import unittest
++
++import jcl.tests.lang
++
++import jmc.lang
++from jmc.lang import Lang
++
++from pyxmpp.iq import Iq
++
++class Lang_TestCase(unittest.TestCase):
++ def setUp(self):
++ self.lang = Lang()
++
++ def tearDown(self):
++ self.lang = None
++
++ def test_get_lang_class_exist(self):
++ lang_class = self.lang.get_lang_class("fr")
++ self.assertEquals(lang_class, Lang.fr)
++
++ def test_get_lang_class_not_exist(self):
++ lang_class = self.lang.get_lang_class("not_exist")
++ self.assertEquals(lang_class, Lang.en)
++
++ def test_get_lang_class_long_code(self):
++ lang_class = self.lang.get_lang_class("fr_FR")
++ self.assertEquals(lang_class, Lang.fr)
++
++ def test_get_lang_from_node(self):
++ iq = Iq(from_jid = "test@test.com", \
++ to_jid = "test2@test.com", \
++ stanza_type = "get")
++ iq_node = iq.get_node()
++ iq_node.setLang("fr")
++ lang = self.lang.get_lang_from_node(iq_node)
++ self.assertEquals(lang, "fr")
++
++ def test_get_lang_class_from_node(self):
++ iq = Iq(from_jid = "test@test.com", \
++ to_jid = "test2@test.com", \
++ stanza_type = "get")
++ iq_node = iq.get_node()
++ iq_node.setLang("fr")
++ lang = self.lang.get_lang_class_from_node(iq_node)
++ self.assertEquals(lang, Lang.fr)
++
++class Language_TestCase(jcl.tests.lang.Language_TestCase):
++ """Test language classes"""
++
++ def setUp(self):
++ """must define self.lang_class. Lang.en is default"""
++ self.lang_class = Lang.en
++
++ def test_strings(self):
++ jcl.tests.lang.Language_TestCase.test_strings(self)
++
++ self.assertNotEquals(self.lang_class.field_login, None)
++ self.assertNotEquals(self.lang_class.field_host, None)
++ self.assertNotEquals(self.lang_class.field_port, None)
++ self.assertNotEquals(self.lang_class.field_ssl, None)
++ self.assertNotEquals(self.lang_class.field_tls, None)
++ self.assertNotEquals(self.lang_class.field_store_password, None)
++ self.assertNotEquals(self.lang_class.field_live_email_only, None)
++ self.assertNotEquals(self.lang_class.field_interval, None)
++ self.assertNotEquals(self.lang_class.field_mailbox, None)
++
++ self.assertNotEquals(self.lang_class.field_action_1, None)
++ self.assertNotEquals(self.lang_class.field_chat_action_1, None)
++ self.assertNotEquals(self.lang_class.field_online_action_1, None)
++ self.assertNotEquals(self.lang_class.field_away_action_1, None)
++ self.assertNotEquals(self.lang_class.field_xa_action_1, None)
++ self.assertNotEquals(self.lang_class.field_dnd_action_1, None)
++ self.assertNotEquals(self.lang_class.field_offline_action_1, None)
++
++ self.assertNotEquals(self.lang_class.field_action_2, None)
++ self.assertNotEquals(self.lang_class.field_chat_action_2, None)
++ self.assertNotEquals(self.lang_class.field_online_action_2, None)
++ self.assertNotEquals(self.lang_class.field_away_action_2, None)
++ self.assertNotEquals(self.lang_class.field_xa_action_2, None)
++ self.assertNotEquals(self.lang_class.field_dnd_action_2, None)
++ self.assertNotEquals(self.lang_class.field_offline_action_2, None)
++
++ self.assertNotEquals(self.lang_class.field_default_from, None)
++ self.assertNotEquals(self.lang_class.field_default_account, None)
++
++ self.assertNotEquals(self.lang_class.new_mail_subject, None)
++ self.assertNotEquals(self.lang_class.new_digest_subject, None)
++
++ self.assertNotEquals(self.lang_class.type_imap_name, None)
++ self.assertNotEquals(self.lang_class.type_pop3_name, None)
++ self.assertNotEquals(self.lang_class.type_smtp_name, None)
++
++ self.assertNotEquals(self.lang_class.send_mail_error_no_to_header_subject,
++ None)
++ self.assertNotEquals(self.lang_class.send_mail_error_no_to_header_body,
++ None)
++ self.assertNotEquals(self.lang_class.send_mail_ok_subject, None)
++ self.assertNotEquals(self.lang_class.send_mail_ok_body, None)
++ self.assertNotEquals(self.lang_class.help_message_body, None)
++ self.assertNotEquals(self.lang_class.command_force_check, None)
++ self.assertNotEquals(self.lang_class.command_force_check_1_description, None)
++ self.assertNotEquals(self.lang_class.command_get_email, None)
++ self.assertNotEquals(self.lang_class.command_get_email_1_description, None)
++ self.assertNotEquals(self.lang_class.command_get_email_2_description, None)
++ self.assertNotEquals(self.lang_class.field_email_subject, None)
++ self.assertNotEquals(self.lang_class.mail_subject, None)
++ self.assertNotEquals(self.lang_class.field_select_more_emails, None)
++
++class SubLanguage_TestCase(Language_TestCase):
++ """
++ Test translation fallback mecanism :
++ jmc.lang.Lang.{translation class} -> jmc.lang.Lang.en -> jcl.lang.Lang.{translation class} -> jcl.lang.Lang.en
++ """
++
++ def test_fallback_jmc_en(self):
++ """
++ if a translation does not exist in JMC. It falls back to the English
++ translation.
++ """
++ value = self.lang_class.register_title
++ del self.lang_class.register_title
++ self.assertEquals(self.lang_class.register_title,
++ jmc.lang.Lang.en.register_title)
++ self.lang_class.register_title = value
++
++ def test_fallback_jcl_current(self):
++ """
++ if an attribut does not exist in JMC translation class nor in JMC
++ English class, it falls back to the current language in JCL.
++ """
++ lang_class_value = self.lang_class.register_title
++ jmc_lang_en_value = jmc.lang.Lang.en.register_title
++ del self.lang_class.register_title
++ del jmc.lang.Lang.en.register_title
++ self.assertEquals(\
++ self.lang_class.register_title,
++ jcl.lang.Lang.__dict__[self.lang_class.__name__].register_title)
++ jmc.lang.Lang.en.register_title = jmc_lang_en_value
++ self.lang_class.register_title = lang_class_value
++
++ def test_fallback_jcl_en(self):
++ """
++ if an attribut does not exist in JMC and is not translated in JCL,
++ it falls back to English in JCL
++ """
++ lang_class_value = self.lang_class.register_title
++ jmc_lang_en_value = jmc.lang.Lang.en.register_title
++ jcl_lang_class_value = jcl.lang.Lang.__dict__[self.lang_class.__name__].register_title
++ del self.lang_class.register_title
++ del jmc.lang.Lang.en.register_title
++ del jcl.lang.Lang.__dict__[self.lang_class.__name__].register_title
++ self.assertEquals(\
++ self.lang_class.register_title,
++ jcl.lang.Lang.en.register_title)
++ jcl.lang.Lang.__dict__[self.lang_class.__name__].register_title = jcl_lang_class_value
++ jmc.lang.Lang.en.register_title = jmc_lang_en_value
++ self.lang_class.register_title = lang_class_value
++
++class Language_fr_TestCase(SubLanguage_TestCase):
++ def setUp(self):
++ self.lang_class = Lang.fr
++
++class Language_nl_TestCase(Language_TestCase):
++ def setUp(self):
++ self.lang_class = Lang.nl
++
++class Language_es_TestCase(Language_TestCase):
++ def setUp(self):
++ self.lang_class = Lang.es
++
++class Language_pl_TestCase(Language_TestCase):
++ def setUp(self):
++ self.lang_class = Lang.pl
++
++class Language_cs_TestCase(Language_TestCase):
++ def setUp(self):
++ self.lang_class = Lang.cs
++
++class Language_ru_TestCase(Language_TestCase):
++ def setUp(self):
++ self.lang_class = Lang.ru
++
++def suite():
++ suite = unittest.TestSuite()
++ suite.addTest(unittest.makeSuite(Lang_TestCase, 'test'))
++ suite.addTest(unittest.makeSuite(Language_TestCase, 'test'))
++ suite.addTest(unittest.makeSuite(Language_fr_TestCase, 'test'))
++ suite.addTest(unittest.makeSuite(Language_nl_TestCase, 'test'))
++ suite.addTest(unittest.makeSuite(Language_es_TestCase, 'test'))
++ suite.addTest(unittest.makeSuite(Language_pl_TestCase, 'test'))
++ suite.addTest(unittest.makeSuite(Language_cs_TestCase, 'test'))
++ suite.addTest(unittest.makeSuite(Language_ru_TestCase, 'test'))
++ return suite
++
++if __name__ == '__main__':
++ unittest.main(defaultTest='suite')
+--- /dev/null
++++ jmc-0.3b3/src/jmc/tests/jmc.conf
+@@ -0,0 +1,32 @@
++[jabber]
++server: test_localhost
++port: 42
++secret: test_secret
++service_jid: test_jmc.localhost
++#supported language: en, fr (See src/jmc/lang.py to add more)
++language: test_en
++
++[db]
++#type: mysql
++type: test_sqlite
++#host: root@localhost
++host: root@localhost
++name: /var/spool/jabber/test_jmc.db
++#url: %(type)%(host)%(name)?debug=1&debugThreading=1
++db_url: %(type)s://%(host)s%(name)s
++
++[component]
++pid_file: /var/run/jabber/test_jmc.pid
++log_file: /tmp/jmc.log
++
++[jmc]
++mail_default_encoding: test_iso-8859-1
++
++[smtp]
++smtp_default_login: testlogin
++smtp_default_password: testpassword
++smtp_default_host: testhost
++smtp_default_port: 2525
++smtp_default_tls: True
++smtp_default_label: SMTP Server
++enable_smtp_default_account: True
+--- /dev/null
++++ jmc-0.3b3/src/jmc/model/tests/email_generator.py
+@@ -0,0 +1,66 @@
++# -*- coding: utf-8 -*-
++## email_generator.py
++## Login : David Rousselie <david.rousselie@happycoders.org>
++## Started on Tue May 17 15:33:35 2005
++## $Id: email_generator.py,v 1.1 2005/07/11 20:39:31 dax Exp $
++##
++## Copyright (C) 2005
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++##
++
++from email.Header import Header
++from email.MIMEText import MIMEText
++from email.MIMEMultipart import MIMEMultipart
++
++def _create_multipart(encoded):
++ msg = MIMEMultipart()
++ if encoded:
++ part1 = MIMEText("utf-8 multipart1 with no charset (éàê)", _charset = "")
++ msg.attach(part1)
++ part2 = MIMEText("Encoded multipart2 with 'iso-8859-15' charset (éàê)", \
++ _charset = "iso-8859-15")
++ msg.attach(part2)
++ part3 = MIMEText("Encoded multipart3 with no charset (éàê)", \
++ _charset = "")
++ msg.attach(part3)
++ else:
++ part1 = MIMEText("Not encoded multipart1")
++ msg.attach(part1)
++ part2 = MIMEText("Not encoded multipart2")
++ msg.attach(part2)
++ return msg
++
++def _create_singlepart(encoded):
++ if encoded:
++ return MIMEText("Encoded single part with 'iso-8859-15' charset (éàê)", \
++ _charset = "iso-8859-15")
++ else:
++ return MIMEText("Not encoded single part")
++
++def generate(encoded, multipart, header):
++ msg = None
++ if multipart:
++ msg = _create_multipart(encoded)
++ else:
++ msg = _create_singlepart(encoded)
++ if header:
++ if encoded:
++ msg['Subject'] = Header("encoded subject (éàê)", "iso-8859-15")
++ msg['From'] = Header("encoded from (éàê)", "iso-8859-15")
++ else:
++ msg['Subject'] = Header("not encoded subject")
++ msg['From'] = Header("not encoded from")
++ return msg
++
+--- /dev/null
++++ jmc-0.3b3/src/jmc/model/tests/account.py
+@@ -0,0 +1,1140 @@
++# -*- coding: utf-8 -*-
++##
++## test_account.py
++## Login : <dax@happycoders.org>
++## Started on Wed Feb 14 08:23:17 2007 David Rousselie
++## $Id$
++##
++## Copyright (C) 2007 David Rousselie
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++##
++
++import unittest
++import thread
++
++from jcl.tests import JCLTestCase
++import jcl.model as model
++from jcl.error import FieldError
++from jcl.model.account import Account, PresenceAccount, User
++import jmc.model.account
++from jmc.model.account import MailAccount, POP3Account, IMAPAccount, \
++ GlobalSMTPAccount, AbstractSMTPAccount, SMTPAccount
++from jmc.lang import Lang
++
++from jcl.model.tests.account import Account_TestCase, \
++ PresenceAccount_TestCase, InheritableAccount_TestCase, \
++ ExampleAccount
++from jmc.model.tests import email_generator, server
++
++class AccountModule_TestCase(unittest.TestCase):
++ def test_validate_login_with_empty_login(self):
++ self.assertRaises(FieldError, jmc.model.account.validate_login,
++ None, None, None)
++
++ def test_validate_login_with_login_with_whitespace(self):
++ self.assertRaises(FieldError, jmc.model.account.validate_login,
++ "login with spaces", None, None)
++
++ def test_validate_host_with_empty_login(self):
++ self.assertRaises(FieldError, jmc.model.account.validate_host,
++ None, None, None)
++
++ def test_validate_host_with_host_with_whitespace(self):
++ self.assertRaises(FieldError, jmc.model.account.validate_host,
++ "host with spaces", None, None)
++
++class MailAccount_TestCase(PresenceAccount_TestCase):
++ def setUp(self):
++ PresenceAccount_TestCase.setUp(self, tables=[MailAccount])
++ self.account = MailAccount(user=User(jid="user1@test.com"),
++ name="account1",
++ jid="account1@jmc.test.com")
++ self.account_class = MailAccount
++
++ def make_test(email_type, tested_func, expected_res):
++ def inner(self):
++ encoded, multipart, header = email_type
++ email = email_generator.generate(encoded,
++ multipart,
++ header)
++ part = tested_func(self, email)
++ self.assertEquals(part, expected_res)
++ return inner
++
++ test_get_decoded_part_not_encoded = \
++ make_test((False, False, False), \
++ lambda self, email: \
++ self.account.get_decoded_part(email, None),
++ u"Not encoded single part")
++
++ test_get_decoded_part_encoded = \
++ make_test((True, False, False),
++ lambda self, email: \
++ self.account.get_decoded_part(email, None),
++ u"Encoded single part with 'iso-8859-15' charset (éàê)")
++
++ test_format_message_summary_not_encoded = \
++ make_test((False, False, True),
++ lambda self, email: \
++ self.account.format_message_summary(email),
++ (u"From : not encoded from\nSubject : not encoded subject\n\n",
++ u"not encoded from"))
++
++ test_format_message_summary_encoded = \
++ make_test((True, False, True),
++ lambda self, email: \
++ self.account.format_message_summary(email),
++ (u"From : encoded from (éàê)\nSubject : encoded subject " + \
++ u"(éàê)\n\n",
++ u"encoded from (éàê)"))
++
++ test_format_message_summary_partial_encoded = \
++ make_test((True, False, True),
++ lambda self, email: \
++ email.replace_header("Subject",
++ "\" " + str(email["Subject"]) \
++ + " \" not encoded part") or \
++ email.replace_header("From",
++ "\" " + str(email["From"]) \
++ + " \" not encoded part") or \
++ self.account.format_message_summary(email),
++ (u"From : \"encoded from (éàê)\" not encoded part\nSubject " + \
++ u": \"encoded subject (éàê)\" not encoded part\n\n",
++ u"\"encoded from (éàê)\" not encoded part"))
++
++ test_format_message_single_not_encoded = \
++ make_test((False, False, True),
++ lambda self, email: \
++ self.account.format_message(email),
++ (u"From : not encoded from\nSubject : not encoded subject" + \
++ u"\n\nNot encoded single part\n",
++ u"not encoded from"))
++
++ test_format_message_single_encoded = \
++ make_test((True, False, True),
++ lambda self, email: \
++ self.account.format_message(email),
++ (u"From : encoded from (éàê)\nSubject : encoded subject " + \
++ u"(éàê)\n\nEncoded single part with 'iso-8859-15' charset" + \
++ u" (éàê)\n",
++ u"encoded from (éàê)"))
++
++ test_format_message_multi_not_encoded = \
++ make_test((False, True, True),
++ lambda self, email: \
++ self.account.format_message(email),
++ (u"From : not encoded from\nSubject : not encoded subject" + \
++ u"\n\nNot encoded multipart1\nNot encoded multipart2\n",
++ u"not encoded from"))
++
++ test_format_message_multi_encoded = \
++ make_test((True, True, True),
++ lambda self, email: \
++ self.account.format_message(email),
++ (u"From : encoded from (éàê)\nSubject : encoded subject (éà" + \
++ u"ê)\n\nutf-8 multipart1 with no charset (éàê)" + \
++ u"\nEncoded multipart2 with 'iso-8859-15' charset (éàê)\n" + \
++ u"Encoded multipart3 with no charset (éàê)\n",
++ u"encoded from (éàê)"))
++
++ def test_get_default_status_msg(self):
++ """
++ Get default status message for MailAccount.
++ Should raise NotImplementedError because get_type() method
++ is not implemented
++ """
++ try:
++ self.account.get_default_status_msg(Lang.en)
++ except NotImplementedError:
++ return
++ fail("No NotImplementedError raised")
++
++class POP3Account_TestCase(InheritableAccount_TestCase):
++ def setUp(self):
++ JCLTestCase.setUp(self, tables=[Account, PresenceAccount, User,
++ MailAccount, POP3Account])
++ self.pop3_account = POP3Account(user=User(jid="user1@test.com"),
++ name="account1",
++ jid="account1@jmc.test.com",
++ login="login")
++ self.pop3_account.password = "pass"
++ self.pop3_account.host = "localhost"
++ self.pop3_account.port = 1110
++ self.pop3_account.ssl = False
++ model.db_disconnect()
++ self.account_class = POP3Account
++
++ def make_test(responses=None, queries=None, core=None):
++ def inner(self):
++ self.server = server.DummyServer("localhost", 1110)
++ thread.start_new_thread(self.server.serve, ())
++ self.server.responses = ["+OK connected\r\n",
++ "+OK name is a valid mailbox\r\n",
++ "+OK pass\r\n"]
++ if responses:
++ self.server.responses += responses
++ self.server.queries = ["USER login\r\n",
++ "PASS pass\r\n"]
++ if queries:
++ self.server.queries += queries
++ self.server.queries += ["QUIT\r\n"]
++ self.pop3_account.connect()
++ self.failUnless(self.pop3_account.connection,
++ "Cannot establish connection")
++ if core:
++ model.db_connect()
++ core(self)
++ model.db_disconnect()
++ self.pop3_account.disconnect()
++ self.failUnless(self.server.verify_queries(),
++ "Sended queries does not match expected queries.")
++ return inner
++
++ test_connection = make_test
++
++ test_get_mail_list_summary = \
++ make_test(["+OK 2 20\r\n",
++ "+OK 10 octets\r\n" + \
++ "From: user@test.com\r\n" + \
++ "Subject: mail subject 1\r\n.\r\n",
++ "+OK 10 octets\r\n" + \
++ "From: user@test.com\r\n" + \
++ "Subject: mail subject 2\r\n.\r\n",
++ "+OK\r\n"],
++ ["STAT\r\n",
++ "TOP 1 0\r\n",
++ "TOP 2 0\r\n",
++ "RSET\r\n"],
++ lambda self: \
++ self.assertEquals(self.pop3_account.get_mail_list_summary(),
++ [("1", "mail subject 1"),
++ ("2", "mail subject 2")]))
++
++ test_get_mail_list_summary_start_index = \
++ make_test(["+OK 3 30\r\n",
++ "+OK 10 octets\r\n" + \
++ "From: user@test.com\r\n" + \
++ "Subject: mail subject 2\r\n.\r\n",
++ "+OK 10 octets\r\n" + \
++ "From: user@test.com\r\n" + \
++ "Subject: mail subject 3\r\n.\r\n",
++ "+OK\r\n"],
++ ["STAT\r\n",
++ "TOP 2 0\r\n",
++ "TOP 3 0\r\n",
++ "RSET\r\n"],
++ lambda self: \
++ self.assertEquals(self.pop3_account.get_mail_list_summary(start_index=2),
++ [("2", "mail subject 2"),
++ ("3", "mail subject 3")]))
++
++ test_get_mail_list_summary_end_index = \
++ make_test(["+OK 3 30\r\n",
++ "+OK 10 octets\r\n" + \
++ "From: user@test.com\r\n" + \
++ "Subject: mail subject 1\r\n.\r\n",
++ "+OK 10 octets\r\n" + \
++ "From: user@test.com\r\n" + \
++ "Subject: mail subject 2\r\n.\r\n",
++ "+OK\r\n"],
++ ["STAT\r\n",
++ "TOP 1 0\r\n",
++ "TOP 2 0\r\n",
++ "RSET\r\n"],
++ lambda self: \
++ self.assertEquals(self.pop3_account.get_mail_list_summary(end_index=2),
++ [("1", "mail subject 1"),
++ ("2", "mail subject 2")]))
++
++ test_get_new_mail_list = \
++ make_test(["+OK 2 20\r\n"],
++ ["STAT\r\n"],
++ lambda self: \
++ self.assertEquals(self.pop3_account.get_new_mail_list(),
++ ["1", "2"]))
++
++ test_get_mail_summary = \
++ make_test(["+OK 10 octets\r\n" + \
++ "From: user@test.com\r\n" + \
++ "Subject: subject test\r\n\r\n" + \
++ "mymessage\r\n.\r\n",
++ "+OK\r\n"],
++ ["RETR 1\r\n",
++ "RSET\r\n"],
++ lambda self: \
++ self.assertEquals(self.pop3_account.get_mail_summary(1),
++ (u"From : user@test.com\n" + \
++ u"Subject : subject test\n\n",
++ u"user@test.com")))
++
++ test_get_mail = \
++ make_test(["+OK 10 octets\r\n" + \
++ "From: user@test.com\r\n" + \
++ "Subject: subject test\r\n\r\n" + \
++ "mymessage\r\n.\r\n",
++ "+OK\r\n"],
++ ["RETR 1\r\n",
++ "RSET\r\n"],
++ lambda self: \
++ self.assertEquals(self.pop3_account.get_mail(1),
++ (u"From : user@test.com\n" + \
++ u"Subject : subject test\n\n" + \
++ u"mymessage\n",
++ u"user@test.com")))
++
++ test_unsupported_reset_command_get_mail_summary = \
++ make_test(["+OK 10 octets\r\n" + \
++ "From: user@test.com\r\n" + \
++ "Subject: subject test\r\n\r\n" + \
++ "mymessage\r\n.\r\n",
++ "-ERR unknown command\r\n"],
++ ["RETR 1\r\n",
++ "RSET\r\n"],
++ lambda self: \
++ self.assertEquals(self.pop3_account.get_mail_summary(1),
++ (u"From : user@test.com\n" + \
++ u"Subject : subject test\n\n",
++ u"user@test.com")))
++
++ test_unsupported_reset_command_get_mail = \
++ make_test(["+OK 10 octets\r\n" + \
++ "From: user@test.com\r\n" + \
++ "Subject: subject test\r\n\r\n" + \
++ "mymessage\r\n.\r\n",
++ "-ERR unknown command\r\n"],
++ ["RETR 1\r\n",
++ "RSET\r\n"],
++ lambda self: \
++ self.assertEquals(self.pop3_account.get_mail(1),
++ (u"From : user@test.com\n" + \
++ u"Subject : subject test\n\n" + \
++ u"mymessage\n",
++ u"user@test.com")))
++
++ def test_get_next_mail_index_empty(self):
++ """
++ Test get_next_mail_index with empty mail_list parameter.
++ """
++ mail_list = []
++ self.pop3_account.nb_mail = 0
++ self.pop3_account.lastmail = 0
++ result = []
++ for elt in self.pop3_account.get_next_mail_index(mail_list):
++ result.append(elt)
++ self.assertEquals(result, [])
++
++ def test_get_next_mail_index(self):
++ """
++ Test get_next_mail_index first check.
++ """
++ mail_list = [1, 2, 3, 4]
++ self.pop3_account.nb_mail = 4
++ self.pop3_account.lastmail = 0
++ result = []
++ for elt in self.pop3_account.get_next_mail_index(mail_list):
++ result.append(elt)
++ self.assertEquals(result, [1, 2, 3, 4])
++ self.assertEquals(self.pop3_account.lastmail, 4)
++
++ def test_get_next_mail_index_second_check(self):
++ """
++ Test get_next_mail_index second check (no parallel checking).
++ """
++ mail_list = [1, 2, 3, 4, 5, 6, 7, 8]
++ self.pop3_account.nb_mail = 8
++ self.pop3_account.lastmail = 4
++ result = []
++ for elt in self.pop3_account.get_next_mail_index(mail_list):
++ result.append(elt)
++ self.assertEquals(result, [5, 6, 7, 8])
++ self.assertEquals(self.pop3_account.lastmail, 8)
++
++ def test_get_next_mail_index_second_check_parallel_check(self):
++ """
++ Test get_next_mail_index second check (with parallel checking
++ but not more new emails than last index jmc stopped:
++ 3 new emails after another client checked emails).
++ """
++ mail_list = [1, 2, 3]
++ self.pop3_account.nb_mail = 3
++ self.pop3_account.lastmail = 4
++ result = []
++ for elt in self.pop3_account.get_next_mail_index(mail_list):
++ result.append(elt)
++ self.assertEquals(result, [1, 2, 3])
++ self.assertEquals(self.pop3_account.lastmail, 3)
++
++ def test_get_next_mail_index_second_check_bug_parallel_check(self):
++ """
++ Test get_next_mail_index second check (with parallel checking
++ but with more new emails than last index jmc stopped:
++ 5 new emails after another client checked emails). Cannot make
++ the difference with one new email since last jmc email check!!
++ """
++ mail_list = [1, 2, 3, 4, 5]
++ self.pop3_account.nb_mail = 5
++ self.pop3_account.lastmail = 4
++ result = []
++ for elt in self.pop3_account.get_next_mail_index(mail_list):
++ result.append(elt)
++ # with no bug it should be:
++ # self.assertEquals(result, [1, 2, 3, 4, 5])
++ self.assertEquals(result, [5])
++ self.assertEquals(self.pop3_account.lastmail, 5)
++
++ def test_get_default_status_msg(self):
++ """
++ Get default status message for POP3Account.
++ """
++ status_msg = self.pop3_account.get_default_status_msg(Lang.en)
++ self.assertEquals(status_msg, "pop3://login@localhost:1110")
++
++ def test_get_default_status_msg_ssl(self):
++ """
++ Get default status message for SSL POP3Account.
++ """
++ self.pop3_account.ssl = True
++ status_msg = self.pop3_account.get_default_status_msg(Lang.en)
++ self.assertEquals(status_msg, "pop3s://login@localhost:1110")
++
++class IMAPAccount_TestCase(InheritableAccount_TestCase):
++ def setUp(self):
++ JCLTestCase.setUp(self, tables=[Account, PresenceAccount, User,
++ MailAccount, IMAPAccount])
++ self.imap_account = IMAPAccount(user=User(jid="user1@test.com"),
++ name="account1",
++ jid="account1@jmc.test.com",
++ login="login")
++ self.imap_account.password = "pass"
++ self.imap_account.host = "localhost"
++ self.imap_account.port = 1143
++ self.imap_account.ssl = False
++ self.account_class = IMAPAccount
++
++ def make_test(self, responses=None, queries=None, core=None):
++ def inner():
++ self.server = server.DummyServer("localhost", 1143)
++ thread.start_new_thread(self.server.serve, ())
++ self.server.responses = ["* OK [CAPABILITY IMAP4 LOGIN-REFERRALS " + \
++ "AUTH=PLAIN]\r\n", \
++ lambda data: "* CAPABILITY IMAP4 " + \
++ "LOGIN-REFERRALS AUTH=PLAIN\r\n" + \
++ data.split()[0] + \
++ " OK CAPABILITY completed\r\n", \
++ lambda data: data.split()[0] + \
++ " OK LOGIN completed\r\n"]
++ if responses:
++ self.server.responses += responses
++ self.server.queries = ["^[^ ]* CAPABILITY", \
++ "^[^ ]* LOGIN login \"pass\""]
++ if queries:
++ self.server.queries += queries
++ self.server.queries += ["^[^ ]* LOGOUT"]
++ if not self.imap_account.connected:
++ self.imap_account.connect()
++ self.failUnless(self.imap_account.connection, \
++ "Cannot establish connection")
++ if core:
++ model.db_connect()
++ core(self)
++ model.db_disconnect()
++ if self.imap_account.connected:
++ self.imap_account.disconnect()
++ self.failUnless(self.server.verify_queries())
++ return inner
++
++ def test_connection(self):
++ test_func = self.make_test()
++ test_func()
++
++ def test_get_mail_list_summary(self):
++ test_func = self.make_test(\
++ [lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" +\
++ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" +\
++ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
++ data.split()[0] + \
++ " OK [READ-WRITE] SELECT completed\r\n",
++ lambda data: "* 1 FETCH ((RFC822.header) {38}\r\n" + \
++ "Subject: mail subject 1\r\n\r\nbody text\r\n)\r\n" + \
++ "* 2 FETCH ((RFC822.header) {38}\r\n" + \
++ "Subject: mail subject 2\r\n\r\nbody text\r\n)\r\n" + \
++ data.split()[0] + " OK FETCH completed\r\n"],
++ ["^[^ ]* EXAMINE INBOX",
++ "^[^ ]* FETCH 1:20 RFC822.header"],
++ lambda self: \
++ self.assertEquals(self.imap_account.get_mail_list_summary(),
++ [('1', 'mail subject 1'),
++ ('2', 'mail subject 2')]))
++ test_func()
++
++ def test_get_mail_list_summary_inbox_does_not_exist(self):
++ self.__test_select_inbox_does_not_exist(\
++ lambda: self.imap_account.get_mail_list_summary(), readonly=True)
++
++ def test_get_mail_list_summary_start_index(self):
++ test_func = self.make_test(\
++ [lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" +\
++ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" +\
++ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
++ data.split()[0] + \
++ " OK [READ-WRITE] SELECT completed\r\n",
++ lambda data: "* 2 FETCH ((RFC822.header) {38}\r\n" + \
++ "Subject: mail subject 2\r\n\r\nbody text\r\n)\r\n" + \
++ "* 3 FETCH ((RFC822.header) {38}\r\n" + \
++ "Subject: mail subject 3\r\n\r\nbody text\r\n)\r\n" + \
++ data.split()[0] + " OK FETCH completed\r\n"],
++ ["^[^ ]* EXAMINE INBOX",
++ "^[^ ]* FETCH 2:20 RFC822.header"],
++ lambda self: \
++ self.assertEquals(self.imap_account.get_mail_list_summary(start_index=2),
++ [('2', 'mail subject 2'),
++ ('3', 'mail subject 3')]))
++ test_func()
++
++ def test_get_mail_list_summary_end_index(self):
++ test_func = self.make_test(\
++ [lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" +\
++ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" +\
++ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
++ data.split()[0] + \
++ " OK [READ-WRITE] SELECT completed\r\n",
++ lambda data: "* 1 FETCH ((RFC822.header) {38}\r\n" + \
++ "Subject: mail subject 1\r\n\r\nbody text\r\n)\r\n" + \
++ "* 2 FETCH ((RFC822.header) {38}\r\n" + \
++ "Subject: mail subject 2\r\n\r\nbody text\r\n)\r\n" + \
++ data.split()[0] + " OK FETCH completed\r\n"],
++ ["^[^ ]* EXAMINE INBOX",
++ "^[^ ]* FETCH 1:2 RFC822.header"],
++ lambda self: \
++ self.assertEquals(self.imap_account.get_mail_list_summary(end_index=2),
++ [('1', 'mail subject 1'),
++ ('2', 'mail subject 2')]))
++ test_func()
++
++ def test_get_new_mail_list(self):
++ test_func = self.make_test(\
++ [lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" + \
++ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" + \
++ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
++ data.split()[0] + \
++ " OK [READ-WRITE] SELECT completed\r\n",
++ lambda data: "* SEARCH 9 10\r\n" + \
++ data.split()[0] + " OK SEARCH completed\r\n"],
++ ["^[^ ]* SELECT INBOX",
++ "^[^ ]* SEARCH RECENT"],
++ lambda self: \
++ self.assertEquals(self.imap_account.get_new_mail_list(),
++ ['9', '10']))
++ test_func()
++
++ def __test_select_inbox_does_not_exist(self, tested_func,
++ exception_message="Mailbox does not exist",
++ readonly=False):
++ def check_func(self):
++ try:
++ tested_func()
++ except Exception, e:
++ self.assertEquals(str(e), exception_message)
++ return
++ self.fail("No exception raised when selecting non existing mailbox")
++ test_func = self.make_test(\
++ [lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" + \
++ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" + \
++ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
++ data.split()[0] + \
++ " NO Mailbox does not exist\r\n"],
++ ["^[^ ]* " + (readonly and "EXAMINE" or "SELECT") + " INBOX"],
++ check_func)
++ test_func()
++
++ def test_get_new_mail_list_inbox_does_not_exist(self):
++ self.__test_select_inbox_does_not_exist(\
++ lambda: self.imap_account_get_new_mail_list())
++
++ def test_get_new_mail_list_delimiter1(self):
++ self.imap_account.mailbox = "INBOX/dir1/subdir2"
++ self.imap_account.delimiter = "."
++ test_func = self.make_test( \
++ [lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" + \
++ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" + \
++ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
++ data.split()[0] + \
++ " OK [READ-WRITE] SELECT completed\r\n",
++ lambda data: "* SEARCH 9 10\r\n" + \
++ data.split()[0] + " OK SEARCH completed\r\n"],
++ ["^[^ ]* SELECT \"?INBOX\.dir1\.subdir2\"?",
++ "^[^ ]* SEARCH RECENT"],
++ lambda self: \
++ self.assertEquals(self.imap_account.get_new_mail_list(),
++ ['9', '10']))
++ test_func()
++
++ def test_get_new_mail_list_delimiter2(self):
++ self.imap_account.mailbox = "INBOX/dir1/subdir2"
++ self.imap_account.delimiter = "/"
++ test_func = self.make_test( \
++ [lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" + \
++ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" + \
++ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
++ data.split()[0] + \
++ " OK [READ-WRITE] SELECT completed\r\n",
++ lambda data: "* SEARCH 9 10\r\n" + \
++ data.split()[0] + " OK SEARCH completed\r\n"],
++ ["^[^ ]* SELECT \"?INBOX/dir1/subdir2\"?",
++ "^[^ ]* SEARCH RECENT"],
++ lambda self: \
++ self.assertEquals(self.imap_account.get_new_mail_list(),
++ ['9', '10']))
++ test_func()
++
++ def test_get_mail_summary(self):
++ test_func = self.make_test(\
++ [lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" +\
++ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" +\
++ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
++ data.split()[0] + \
++ " OK [READ-WRITE] SELECT completed\r\n",
++ lambda data: "* 1 FETCH ((RFC822) {12}\r\nbody" + \
++ " text\r\n)\r\n" + \
++ data.split()[0] + " OK FETCH completed\r\n"],
++ ["^[^ ]* EXAMINE INBOX",
++ "^[^ ]* FETCH 1 \(RFC822.header\)"],
++ lambda self: \
++ self.assertEquals(self.imap_account.get_mail_summary(1),
++ (u"From : None\nSubject : None\n\n",
++ u"None")))
++ test_func()
++
++ def test_get_mail_summary_inbox_does_not_exist(self):
++ self.__test_select_inbox_does_not_exist(\
++ lambda: self.imap_account.get_mail_summary(1),
++ "Mailbox does not exist (email 1)", True)
++
++ def test_get_new_mail_list_inbox_does_not_exist(self):
++ def check_func(self):
++ try:
++ self.imap_account.get_new_mail_list()
++ except Exception, e:
++ self.assertEquals(str(e), "Mailbox does not exist")
++ return
++ self.fail("No exception raised when selecting non existing mailbox")
++ test_func = self.make_test(\
++ [lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" + \
++ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" + \
++ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
++ data.split()[0] + \
++ " NO Mailbox does not exist\r\n"],
++ ["^[^ ]* SELECT INBOX"],
++ check_func)
++ test_func()
++
++ def test_get_mail_summary_delimiter(self):
++ self.imap_account.mailbox = "INBOX/dir1/subdir2"
++ self.imap_account.delimiter = "."
++ test_func = self.make_test(\
++ [lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" +\
++ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" +\
++ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
++ data.split()[0] + \
++ " OK [READ-WRITE] SELECT completed\r\n",
++ lambda data: "* 1 FETCH ((RFC822) {12}\r\nbody" + \
++ " text\r\n)\r\n" + \
++ data.split()[0] + " OK FETCH completed\r\n"],
++ ["^[^ ]* EXAMINE \"?INBOX\.dir1\.subdir2\"?",
++ "^[^ ]* FETCH 1 \(RFC822.header\)"],
++ lambda self: \
++ self.assertEquals(self.imap_account.get_mail_summary(1),
++ (u"From : None\nSubject : None\n\n",
++ u"None")))
++ test_func()
++
++ def test_get_mail(self):
++ test_func = self.make_test(\
++ [lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" + \
++ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" + \
++ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
++ data.split()[0] + \
++ " OK [READ-WRITE] SELECT completed\r\n",
++ lambda data: "* 1 FETCH ((RFC822) {11}\r\nbody" + \
++ " text\r\n)\r\n" + \
++ data.split()[0] + " OK FETCH completed\r\n"],
++ ["^[^ ]* EXAMINE INBOX",
++ "^[^ ]* FETCH 1 \(RFC822\)"],
++ lambda self: \
++ self.assertEquals(self.imap_account.get_mail(1),
++ (u"From : None\nSubject : None\n\nbody text\r\n\n",
++ u"None")))
++ test_func()
++
++ def test_get_mail_inbox_does_not_exist(self):
++ self.__test_select_inbox_does_not_exist(\
++ lambda: self.imap_account.get_mail(1),
++ "Mailbox does not exist (email 1)", True)
++
++ def test_get_mail_delimiter(self):
++ self.imap_account.mailbox = "INBOX/dir1/subdir2"
++ self.imap_account.delimiter = "."
++ test_func = self.make_test(\
++ [lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" + \
++ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" + \
++ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
++ data.split()[0] + \
++ " OK [READ-WRITE] SELECT completed\r\n",
++ lambda data: "* 1 FETCH ((RFC822) {11}\r\nbody" + \
++ " text\r\n)\r\n" + \
++ data.split()[0] + " OK FETCH completed\r\n"],
++ ["^[^ ]* EXAMINE \"?INBOX\.dir1\.subdir2\"?",
++ "^[^ ]* FETCH 1 \(RFC822\)"],
++ lambda self: \
++ self.assertEquals(self.imap_account.get_mail(1),
++ (u"From : None\nSubject : None\n\nbody text\r\n\n",
++ u"None")))
++ test_func()
++
++ def test_build_folder_cache(self):
++ test_func = self.make_test(\
++ [lambda data: '* LIST () "." "INBOX"\r\n' + \
++ '* LIST () "." "INBOX.dir1"\r\n' + \
++ '* LIST () "." "INBOX.dir1.subdir1"\r\n' + \
++ '* LIST () "." "INBOX.dir1.subdir2"\r\n' + \
++ '* LIST () "." "INBOX.dir2"\r\n' + \
++ data.split()[0] + ' OK LIST completed\r\n'],
++ ["^[^ ]* LIST \"\" \*"],
++ lambda self: self.assertEquals(self.imap_account._build_folder_cache(),
++ {"INBOX":
++ {"dir1":
++ {"subdir1": {},
++ "subdir2": {}},
++ "dir2": {}}}))
++ test_func()
++
++ def test_ls_dir_base(self):
++ self.test_build_folder_cache()
++ self.assertEquals(self.imap_account.ls_dir(""),
++ ["INBOX"])
++
++ def test_ls_dir_subdir(self):
++ self.test_build_folder_cache()
++ result = self.imap_account.ls_dir("INBOX")
++ result.sort()
++ self.assertEquals(result,
++ ["dir1", "dir2"])
++
++ def test_ls_dir_subsubdir_delim1(self):
++ self.test_build_folder_cache()
++ self.imap_account.default_delimiter = "."
++ result = self.imap_account.ls_dir("INBOX/dir1")
++ result.sort()
++ self.assertEquals(result,
++ ["subdir1", "subdir2"])
++
++ def test_ls_dir_subsubdir_delim2(self):
++ self.test_build_folder_cache()
++ result = self.imap_account.ls_dir("INBOX/dir1")
++ result.sort()
++ self.assertEquals(result,
++ ["subdir1", "subdir2"])
++
++ def test_populate_handler(self):
++ self.assertEquals(".", self.imap_account.delimiter)
++ self.imap_account.mailbox = "INBOX/dir1/subdir2"
++ def call_func(self):
++ self.imap_account.populate_handler()
++ self.assertEquals("INBOX.dir1.subdir2", self.imap_account.mailbox)
++ test_func = self.make_test(\
++ [lambda data: '* LIST () "." "INBOX.dir1.subdir2"\r\n' + \
++ data.split()[0] + ' OK LIST completed\r\n'],
++ ["^[^ ]* LIST \"?INBOX.dir1.subdir2\"? \*"],
++ call_func)
++ test_func()
++
++ def test_populate_handler_wrong_default_delimiter(self):
++ self.imap_account.delimiter = "/"
++ self.imap_account.mailbox = "INBOX/dir1/subdir2"
++ def call_func(self):
++ self.imap_account.populate_handler()
++ self.assertEquals("INBOX.dir1.subdir2", self.imap_account.mailbox)
++ self.assertEquals(".", self.imap_account.delimiter)
++ test_func = self.make_test(\
++ [lambda data: data.split()[0] + ' OK LIST completed\r\n',
++ lambda data: '* LIST () "." "INBOX.dir1.subdir2"\r\n' + \
++ data.split()[0] + ' OK LIST completed\r\n'],
++ ["^[^ ]* LIST \"?INBOX/dir1/subdir2\"? \*",
++ "^[^ ]* LIST \"?INBOX.dir1.subdir2\"? \*"],
++ call_func)
++ test_func()
++
++ def test_populate_handler_wrong_mailbox(self):
++ self.assertEquals(".", self.imap_account.delimiter)
++ self.imap_account.mailbox = "INBOX.dir1.subdir2"
++ def call_func(self):
++ try:
++ self.imap_account.populate_handler()
++ except Exception, e:
++ return
++ self.fail("Exception should have been raised")
++ test_func = self.make_test(\
++ [lambda data: data.split()[0] + ' ERR LIST completed\r\n'],
++ ["^[^ ]* LIST \"?INBOX.dir1.subdir2\"? \*"],
++ call_func)
++ test_func()
++
++ def check_get_next_mail_index(self, mail_list):
++ """
++ Common tests for get_next_mail_index method.
++ """
++ result = []
++ original_mail_list = [elt for elt in mail_list]
++ for elt in self.imap_account.get_next_mail_index(mail_list):
++ result.append(elt)
++ self.assertEquals(mail_list, [])
++ self.assertEquals(result, original_mail_list)
++
++ def test_get_next_mail_index_empty(self):
++ """
++ Test get_next_mail_index with empty mail_list parameter.
++ """
++ mail_list = []
++ self.check_get_next_mail_index(mail_list)
++
++ def test_get_next_mail_index(self):
++ """
++ Test get_next_mail_index.
++ """
++ mail_list = [1, 2, 3, 4]
++ self.check_get_next_mail_index(mail_list)
++
++ def test_get_default_status_msg(self):
++ """
++ Get default status message for IMAPAccount.
++ """
++ status_msg = self.imap_account.get_default_status_msg(Lang.en)
++ self.assertEquals(status_msg, "imap://login@localhost:1143")
++
++ def test_get_default_status_msg_ssl(self):
++ """
++ Get default status message for SSL IMAPAccount.
++ """
++ self.imap_account.ssl = True
++ status_msg = self.imap_account.get_default_status_msg(Lang.en)
++ self.assertEquals(status_msg, "imaps://login@localhost:1143")
++
++class AbstractSMTPAccount_TestCase(Account_TestCase):
++ def setUp(self):
++ JCLTestCase.setUp(self, tables=[Account, ExampleAccount, User,
++ GlobalSMTPAccount, AbstractSMTPAccount])
++ self.account_class = AbstractSMTPAccount
++
++ def test_default_account_post_func_no_default_true(self):
++ user1 = User(jid="user1@test.com")
++ account11 = AbstractSMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jmc.test.com")
++ account12 = AbstractSMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jmc.test.com")
++ (name, field_type, field_options, post_func, default_func) = \
++ AbstractSMTPAccount.get_register_fields()[0]
++ value = post_func("True", None, "user1@test.com")
++ self.assertTrue(value)
++
++ def test_default_account_post_func_no_default_false(self):
++ user1 = User(jid="user1@test.com")
++ account11 = AbstractSMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jmc.test.com")
++ account12 = AbstractSMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jmc.test.com")
++ (name, field_type, field_options, post_func, default_func) = \
++ AbstractSMTPAccount.get_register_fields()[0]
++ value = post_func("False", None, "user1@test.com")
++ self.assertTrue(value)
++
++ def test_default_account_post_func_true(self):
++ user1 = User(jid="user1@test.com")
++ account11 = AbstractSMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jmc.test.com")
++ account12 = AbstractSMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jmc.test.com")
++ account12.default_account = True
++ (name, field_type, field_options, post_func, default_func) = \
++ AbstractSMTPAccount.get_register_fields()[0]
++ value = post_func("True", None, "user1@test.com")
++ self.assertTrue(value)
++ self.assertFalse(account12.default_account)
++
++ def test_default_account_post_func_false(self):
++ user1 = User(jid="user1@test.com")
++ account11 = AbstractSMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jmc.test.com")
++ account12 = AbstractSMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jmc.test.com")
++ account12.default_account = True
++ (name, field_type, field_options, post_func, default_func) = \
++ AbstractSMTPAccount.get_register_fields()[0]
++ value = post_func("False", None, "user1@test.com")
++ self.assertFalse(value)
++ self.assertTrue(account12.default_account)
++
++ def test_create_email(self):
++ account11 = AbstractSMTPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ email = account11.create_email("from@test.com",
++ "to@test.com",
++ "subject",
++ "body")
++ self.assertEqual(email['From'], "from@test.com")
++ self.assertEqual(email['To'], "to@test.com")
++ self.assertEqual(email['Subject'], "subject")
++ self.assertEqual(email.get_payload(), "body")
++
++ def test_create_email_other_headers(self):
++ account11 = AbstractSMTPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ email = account11.create_email("from@test.com",
++ "to@test.com",
++ "subject",
++ "body",
++ {"Bcc": "bcc@test.com",
++ "Cc": "cc@test.com"})
++ self.assertEqual(email['From'], "from@test.com")
++ self.assertEqual(email['To'], "to@test.com")
++ self.assertEqual(email['Subject'], "subject")
++ self.assertEqual(email['Bcc'], "bcc@test.com")
++ self.assertEqual(email['Cc'], "cc@test.com")
++ self.assertEqual(email.get_payload(), "body")
++
++class SMTPAccount_TestCase(Account_TestCase):
++ def setUp(self):
++ JCLTestCase.setUp(self, tables=[Account, ExampleAccount, User,
++ GlobalSMTPAccount,
++ AbstractSMTPAccount, SMTPAccount])
++ self.account_class = SMTPAccount
++
++ def make_test(self, responses=None, queries=None, core=None):
++ def inner():
++ self.server = server.DummyServer("localhost", 1025)
++ thread.start_new_thread(self.server.serve, ())
++ self.server.responses = []
++ if responses:
++ self.server.responses += responses
++ self.server.responses += ["221 localhost closing connection\r\n"]
++ self.server.queries = []
++ if queries:
++ self.server.queries += queries
++ self.server.queries += ["quit\r\n"]
++ if core:
++ model.db_connect()
++ core(self)
++ model.db_disconnect()
++ self.failUnless(self.server.verify_queries())
++ return inner
++
++ def test_send_email_esmtp_no_auth(self):
++ model.db_connect()
++ smtp_account = SMTPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ smtp_account.host = "localhost"
++ smtp_account.port = 1025
++ model.db_disconnect()
++ email = smtp_account.create_email("from@test.com",
++ "to@test.com",
++ "subject",
++ "body")
++ test_func = self.make_test(["220 localhost ESMTP\r\n",
++ "250-localhost Hello 127.0.0.1\r\n"
++ + "250-SIZE 52428800\r\n"
++ + "250-PIPELINING\r\n"
++ + "250 HELP\r\n",
++ "250 OK\r\n",
++ "250 Accepted\r\n",
++ "354 Enter message\r\n",
++ None, None, None, None,
++ None, None, None, None,
++ "250 OK\r\n"],
++ ["ehlo .*\r\n",
++ "mail FROM:<" + str(email['From']) + ">.*",
++ "rcpt TO:<" + str(email['To']) + ">\r\n",
++ "data\r\n"] +
++ email.as_string().split("\n") + [".\r\n"],
++ lambda self: \
++ smtp_account.send_email(email))
++ test_func()
++
++ def test_send_email_no_auth(self):
++ model.db_connect()
++ smtp_account = SMTPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ smtp_account.host = "localhost"
++ smtp_account.port = 1025
++ model.db_disconnect()
++ email = smtp_account.create_email("from@test.com",
++ "to@test.com",
++ "subject",
++ "body")
++ test_func = self.make_test(["220 localhost SMTP\r\n",
++ "504 ESMTP not supported\r\n",
++ "250-localhost Hello 127.0.0.1\r\n"
++ + "250-SIZE 52428800\r\n"
++ + "250-PIPELINING\r\n"
++ + "250 HELP\r\n",
++ "250 OK\r\n",
++ "250 Accepted\r\n",
++ "354 Enter message\r\n",
++ None, None, None, None,
++ None, None, None, None,
++ "250 OK\r\n"],
++ ["ehlo .*\r\n",
++ "helo .*\r\n",
++ "mail FROM:<" + str(email['From']) + ">.*",
++ "rcpt TO:<" + str(email['To']) + ">\r\n",
++ "data\r\n"] +
++ email.as_string().split("\n") + [".\r\n"],
++ lambda self: \
++ smtp_account.send_email(email))
++ test_func()
++
++ def test_send_email_esmtp_auth(self):
++ model.db_connect()
++ smtp_account = SMTPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ smtp_account.host = "localhost"
++ smtp_account.port = 1025
++ smtp_account.login = "user"
++ smtp_account.password = "pass"
++ model.db_disconnect()
++ email = smtp_account.create_email("from@test.com",
++ "to@test.com",
++ "subject",
++ "body")
++ test_func = self.make_test(["220 localhost ESMTP\r\n",
++ "250-localhost Hello 127.0.0.1\r\n"
++ + "250-SIZE 52428800\r\n"
++ + "250-AUTH PLAIN LOGIN CRAM-MD5\r\n"
++ + "250-PIPELINING\r\n"
++ + "250 HELP\r\n",
++ "334 ZGF4IDNmNDM2NzY0YzBhNjgyMTQ1MzhhZGNiMjE2YTYxZjRm\r\n",
++ "235 Authentication succeeded\r\n",
++ "250 OK\r\n",
++ "250 Accepted\r\n",
++ "354 Enter message\r\n",
++ None, None, None, None,
++ None, None, None, None,
++ "250 OK\r\n"],
++ ["ehlo .*\r\n",
++ "AUTH CRAM-MD5\r\n",
++ ".*\r\n",
++ "mail FROM:<" + str(email['From']) + ">.*",
++ "rcpt TO:<" + str(email['To']) + ">\r\n",
++ "data\r\n"] +
++ email.as_string().split("\n") + [".\r\n"],
++ lambda self: \
++ smtp_account.send_email(email))
++ test_func()
++
++ def test_send_email_esmtp_auth_method2(self):
++ model.db_connect()
++ smtp_account = SMTPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ smtp_account.host = "localhost"
++ smtp_account.port = 1025
++ smtp_account.login = "user"
++ smtp_account.password = "pass"
++ model.db_disconnect()
++ email = smtp_account.create_email("from@test.com",
++ "to@test.com",
++ "subject",
++ "body")
++ test_func = self.make_test(["220 localhost ESMTP\r\n",
++ "250-localhost Hello 127.0.0.1\r\n"
++ + "250-SIZE 52428800\r\n"
++ + "250-AUTH PLAIN LOGIN CRAM-MD5\r\n"
++ + "250-PIPELINING\r\n"
++ + "250 HELP\r\n",
++ "334 ZGF4IDNmNDM2NzY0YzBhNjgyMTQ1MzhhZGNiMjE2YTYxZjRm\r\n",
++ "535 Incorrect Authentication data\r\n",
++ "334 asd235r4\r\n",
++ "235 Authentication succeeded\r\n",
++ "250 OK\r\n",
++ "250 Accepted\r\n",
++ "354 Enter message\r\n",
++ None, None, None, None,
++ None, None, None, None,
++ "250 OK\r\n"],
++ ["ehlo .*\r\n",
++ "AUTH CRAM-MD5\r\n",
++ ".*\r\n",
++ "AUTH LOGIN .*\r\n",
++ ".*\r\n",
++ "mail FROM:<" + str(email['From']) + ">.*",
++ "rcpt TO:<" + str(email['To']) + ">\r\n",
++ "data\r\n"] +
++ email.as_string().split("\n") + [".\r\n"],
++ lambda self: \
++ smtp_account.send_email(email))
++ test_func()
++
++ def test_get_default_status_msg(self):
++ """
++ Get default status message for IMAPAccount.
++ """
++ smtp_account = SMTPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ smtp_account.host = "localhost"
++ smtp_account.port = 1025
++ smtp_account.login = "user"
++ smtp_account.password = "pass"
++ status_msg = smtp_account.get_default_status_msg(Lang.en)
++ self.assertEquals(status_msg, "smtp://user@localhost:1025")
++
++ def test_get_default_status_msg_ssl(self):
++ """
++ Get default status message for SSL IMAPAccount.
++ """
++ smtp_account = SMTPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ smtp_account.host = "localhost"
++ smtp_account.port = 1025
++ smtp_account.login = "user"
++ smtp_account.password = "pass"
++ smtp_account.tls = True
++ status_msg = smtp_account.get_default_status_msg(Lang.en)
++ self.assertEquals(status_msg, "smtps://user@localhost:1025")
++
++def suite():
++ suite = unittest.TestSuite()
++ suite.addTest(unittest.makeSuite(AccountModule_TestCase, 'test'))
++ suite.addTest(unittest.makeSuite(MailAccount_TestCase, 'test'))
++ suite.addTest(unittest.makeSuite(POP3Account_TestCase, 'test'))
++ suite.addTest(unittest.makeSuite(IMAPAccount_TestCase, 'test'))
++ suite.addTest(unittest.makeSuite(AbstractSMTPAccount_TestCase, 'test'))
++ suite.addTest(unittest.makeSuite(SMTPAccount_TestCase, 'test'))
++ return suite
++
++if __name__ == '__main__':
++ unittest.main(defaultTest='suite')
+--- /dev/null
++++ jmc-0.3b3/src/jmc/model/tests/__init__.py
+@@ -0,0 +1,14 @@
++"""JMC test module"""
++__revision__ = ""
++
++import unittest
++
++from jmc.model.tests import account
++
++def suite():
++ suite = unittest.TestSuite()
++ suite.addTest(account.suite())
++ return suite
++
++if __name__ == '__main__':
++ unittest.main(defaultTest='suite')
+--- /dev/null
++++ jmc-0.3b3/src/jmc/model/tests/server.py
+@@ -0,0 +1,205 @@
++##
++## dummy_server.py
++## Login : David Rousselie <david.rousselie@happycoders.org>
++## Started on Fri May 13 12:53:17 2005
++## $Id: dummy_server.py,v 1.1 2005/07/11 20:39:31 dax Exp $
++##
++## Copyright (C) 2005
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++##
++
++import sys
++import time
++import traceback
++import re
++import os
++import socket
++import types
++import select
++import xml.dom.minidom
++from pyxmpp import xmlextra
++
++def xmldiff(node1, node2):
++ if node1.nodeType == node1.TEXT_NODE:
++ if not node2.nodeType == node2.TEXT_NODE \
++ or re.compile(node2.data + "$").match(node1.data) is None:
++ raise Exception("data in text node " + node1.data + " does not match " + node2.data)
++ elif node1.nodeType == node1.DOCUMENT_NODE:
++ if not node2.nodeType == node2.DOCUMENT_NODE:
++ raise Exception("node1 is Document but not node2 (" + node2.nodeType + ")")
++ elif node1.tagName != node2.tagName:
++ raise Exception("Different tag name : " + node1.tagName + " != " + node2.tagName)
++ else:
++ for attr in node1._get_attributes().keys():
++ if not node2.hasAttribute(attr) \
++ or node1.getAttribute(attr) != node2.getAttribute(attr):
++ raise Exception("(" + node1.tagName + ") Different attributes : " + node1.getAttribute(attr) + " != " + node2.getAttribute(attr))
++ if len(node1.childNodes) != len(node2.childNodes):
++ raise Exception("(" + node1.tagName + ") Different children number : " + str(len(node1.childNodes)) + " != " + str(len(node2.childNodes)))
++ for i in range(len(node1.childNodes)):
++ xmldiff(node1.childNodes[i], node2.childNodes[i])
++
++class DummyServer:
++ def __init__(self, host, port, responses = None):
++ for res in socket.getaddrinfo(host, port, socket.AF_INET, socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
++ af, socktype, proto, canonname, sa = res
++ try:
++ s = socket.socket(af, socktype, proto)
++ except socket.error, msg:
++ print >>sys.stderr, msg
++ s = None
++ raise socket.error
++ try:
++ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
++ s.bind(sa)
++ s.listen(1)
++ except socket.error, msg:
++ print >>sys.stderr, msg
++ s.close()
++ s = None
++ raise socket.error
++ break
++ self.socket = s
++ self.responses = None
++ self.queries = None
++ self.real_queries = []
++
++ def serve(self):
++ conn = None
++ try:
++ conn, addr = self.socket.accept()
++ rfile = conn.makefile('rb', -1)
++ if self.responses:
++ data = None
++ for idx in range(len(self.responses)):
++ # if response is a function apply it (it must return a string)
++ # it is given previous received data
++ if isinstance(self.responses[idx], types.FunctionType):
++ response = self.responses[idx](data)
++ else:
++ response = self.responses[idx]
++ if response is not None:
++ #print >>sys.stderr, 'Sending : ', response
++ conn.send(response)
++ data = rfile.readline()
++ if not data:
++ break
++ else:
++ self.real_queries.append(data)
++ #print >>sys.stderr, 'Receive : ', data
++ if conn is not None:
++ conn.close()
++ if self.socket is not None:
++ self.socket.close()
++ self.socket = None
++ except:
++ type, value, stack = sys.exc_info()
++ print >>sys.stderr, "".join(traceback.format_exception
++ (type, value, stack, 5))
++
++ def verify_queries(self):
++ result = True
++ queries_len = len(self.queries)
++ if queries_len == len(self.real_queries):
++ for idx in range(queries_len):
++ real_query = self.real_queries[idx]
++ match = (re.compile(self.queries[idx], re.M).match(real_query) is not None)
++ if not match:
++ result = False
++ print >>sys.stderr, "Unexpected query :\n" + \
++ "Expected query : _" + self.queries[idx] + "_\n" + \
++ "Receive query : _" + real_query + "_\n"
++ else:
++ result = False
++ print >>sys.stderr, "Expected " + str(queries_len) + \
++ " queries, got " + str(len(self.real_queries)) + \
++ "\t" + str(self.real_queries)
++ return result
++
++class XMLDummyServer(DummyServer):
++ def __init__(self, host, port, responses, stream_handler):
++ DummyServer.__init__(self, host, port, responses)
++ self._reader = xmlextra.StreamReader(stream_handler)
++
++ def serve(self):
++ try:
++ conn, addr = self.socket.accept()
++ if self.responses:
++ data = None
++ for idx in range(len(self.responses)):
++ try:
++ # This approximation is not clean
++ # received size is based on the expected size in self.queries
++ data = conn.recv(1024 + len(self.queries[idx]))
++# print "receive : " + data
++ if data:
++ #print "-----------RECEIVE1 " + data
++ r = self._reader.feed(data)
++ except:
++ type, value, stack = sys.exc_info()
++ print "".join (traceback.format_exception
++ (type, value, stack, 5))
++ raise
++ if data:
++ self.real_queries.append(data)
++ # if response is a function apply it (it must return a string)
++ # it is given previous received data
++ if isinstance(self.responses[idx], types.FunctionType):
++ response = self.responses[idx](data)
++ else:
++ response = self.responses[idx]
++ if response is not None:
++# print >>sys.stderr, '---------SENDING : ', response
++ conn.send(response)
++ data = conn.recv(1024)
++ if data:
++# print "-----------RECEIVE2 " + data
++ r = self._reader.feed(data)
++ self.real_queries.append(data)
++ conn.close()
++ self.socket.close()
++ self.socket = None
++ except:
++ type, value, stack = sys.exc_info()
++ print "".join (traceback.format_exception
++ (type, value, stack, 5))
++ raise
++
++ def verify_queries(self):
++ result = True
++ full_real_queries = ""
++ full_recv_queries = ""
++ for idx in range(len(self.real_queries)):
++ full_real_queries += self.real_queries[idx].rstrip(os.linesep)
++ for idx in range(len(self.queries)):
++ full_recv_queries += self.queries[idx].rstrip(os.linesep)
++ # Do not receive it but add it so that xml parsing can succeed
++ #full_real_queries += "</stream:stream>"
++ real_query = xml.dom.minidom.parseString(full_real_queries)
++ recv_query = xml.dom.minidom.parseString(full_recv_queries)
++ try:
++ utils.xmldiff(real_query, recv_query)
++ except Exception, msg:
++ result = False
++ print >>sys.stderr, msg
++ return result
++
++def test():
++ server = DummyServer(("localhost", 4242))
++ server.responses = ["rep1\n", "rep2\n"]
++ server.serve()
++
++if __name__ == '__main__':
++ test()
+--- /dev/null
++++ jmc-0.3b3/src/jmc/jabber/tests/disco.py
+@@ -0,0 +1,83 @@
++##
++## disco.py
++## Login : David Rousselie <dax@happycoders.org>
++## Started on Sun Jul 8 20:59:32 2007 David Rousselie
++## $Id$
++##
++## Copyright (C) 2007 David Rousselie
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++##
++
++import unittest
++
++from jmc.jabber.disco import MailRootDiscoGetInfoHandler, \
++ IMAPAccountDiscoGetInfoHandler
++from jmc.lang import Lang
++
++class MockDiscoIndentity(object):
++ def __init__(self):
++ self.category = ""
++ self.type = ""
++
++class MockAccountManager(object):
++ def __init__(self):
++ self.has_multiple_account_type = False
++
++class MockComponent(object):
++ def __init__(self):
++ self.name = ""
++ self.disco_identity = MockDiscoIndentity()
++ self.account_manager = MockAccountManager()
++
++class MailRootDiscoGetInfoHandler_TestCase(unittest.TestCase):
++ def test_root_disco_get_info(self):
++ component = MockComponent()
++ component.name = "Mock component"
++ component.disco_identity.category = "gateway"
++ component.disco_identity.type = "smtp"
++ component.account_manager.has_multiple_account_type = True
++ handler = MailRootDiscoGetInfoHandler(component)
++ # stanza, lang_class, node, disco_obj, data
++ disco_infos = handler.handle(None, None, None, None, None)
++ self.assertTrue(disco_infos[0].has_feature("jabber:iq:gateway"))
++ self.assertTrue(disco_infos[0].has_feature("http://jabber.org/protocol/disco#info"))
++ self.assertTrue(disco_infos[0].has_feature("http://jabber.org/protocol/disco#items"))
++ self.assertTrue(disco_infos[0].has_feature("http://jabber.org/protocol/commands"))
++ self.assertEquals(len(disco_infos[0].get_identities()), 2)
++ self.assertTrue(disco_infos[0].identity_is("gateway", "smtp"))
++ self.assertTrue(disco_infos[0].identity_is("headline", "newmail"))
++
++class IMAPAccountDiscoGetInfoHandler_TestCase(unittest.TestCase):
++ def test_handle_not_imap(self):
++ component = MockComponent()
++ component.name = "Mock component"
++ component.disco_identity.category = "gateway"
++ component.disco_identity.type = "smtp"
++ component.account_manager.has_multiple_account_type = True
++ handler = IMAPAccountDiscoGetInfoHandler(component)
++ # stanza, lang_class, node, disco_obj, data
++ disco_infos = handler.handle(None, Lang.en, "account@jmc.test.com/POP3",
++ None, None)
++ self.assertTrue(disco_infos[0].has_feature("jabber:iq:register"))
++ self.assertFalse(disco_infos[0].has_feature("http://jabber.org/protocol/commands"))
++
++def suite():
++ suite = unittest.TestSuite()
++ suite.addTest(unittest.makeSuite(MailRootDiscoGetInfoHandler_TestCase, 'test'))
++ suite.addTest(unittest.makeSuite(IMAPAccountDiscoGetInfoHandler_TestCase, 'test'))
++ return suite
++
++if __name__ == '__main__':
++ unittest.main(defaultTest='suite')
+--- /dev/null
++++ jmc-0.3b3/src/jmc/jabber/tests/component.py
+@@ -0,0 +1,1584 @@
++
++
++# -*- coding: utf-8 -*-
++##
++## test_component.py
++## Login : <dax@happycoders.org>
++## Started on Wed Feb 14 18:04:49 2007 David Rousselie
++## $Id$
++##
++## Copyright (C) 2007 David Rousselie
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++##
++
++import unittest
++import sys
++import time
++import logging
++import time
++
++from sqlobject import *
++from sqlobject.dbconnection import TheURIOpener
++
++from pyxmpp.presence import Presence
++from pyxmpp.message import Message
++from pyxmpp.iq import Iq
++
++from jcl.tests import JCLTestCase
++import jcl.model as model
++from jcl.model import account
++from jcl.model.account import Account, PresenceAccount, LegacyJID, User
++from jcl.jabber.tests.presence import DefaultSubscribeHandler_TestCase, \
++ DefaultUnsubscribeHandler_TestCase
++from jcl.jabber.tests.feeder import FeederMock, SenderMock
++
++from jmc.model.account import MailAccount, IMAPAccount, POP3Account, \
++ GlobalSMTPAccount, AbstractSMTPAccount, SMTPAccount, NoAccountError
++from jmc.jabber import MailHandler
++from jmc.jabber.message import SendMailMessageHandler
++from jmc.jabber.presence import MailSubscribeHandler, \
++ MailUnsubscribeHandler, MailPresenceHandler
++from jmc.jabber.component import MailComponent, MailFeederHandler, \
++ MailSender
++from jmc.lang import Lang
++
++if sys.platform == "win32":
++ DB_PATH = "/c|/temp/jmc_test.db"
++else:
++ DB_PATH = "/tmp/jmc_test.db"
++DB_URL = DB_PATH# + "?debug=1&debugThreading=1"
++
++class MockStream(object):
++ def __init__(self,
++ jid="",
++ secret="",
++ server="",
++ port="",
++ keepalive=True):
++ self.sent = []
++ self.connection_started = False
++ self.connection_stopped = False
++ self.eof = False
++ self.socket = []
++
++ def send(self, iq):
++ self.sent.append(iq)
++
++ def set_iq_set_handler(self, iq_type, ns, handler):
++ if not iq_type in ["query"]:
++ raise Exception("IQ type unknown: " + iq_type)
++ if not ns in ["jabber:iq:version",
++ "jabber:iq:register",
++ "http://jabber.org/protocol/disco#items",
++ "http://jabber.org/protocol/disco#info"]:
++ raise Exception("Unknown namespace: " + ns)
++ if handler is None:
++ raise Exception("Handler must not be None")
++
++ set_iq_get_handler = set_iq_set_handler
++
++ def set_presence_handler(self, status, handler):
++ if not status in ["available",
++ "unavailable",
++ "probe",
++ "subscribe",
++ "subscribed",
++ "unsubscribe",
++ "unsubscribed"]:
++ raise Exception("Status unknown: " + status)
++ if handler is None:
++ raise Exception("Handler must not be None")
++
++ def set_message_handler(self, msg_type, handler):
++ if not msg_type in ["normal"]:
++ raise Exception("Message type unknown: " + msg_type)
++ if handler is None:
++ raise Exception("Handler must not be None")
++
++ def connect(self):
++ self.connection_started = True
++
++ def disconnect(self):
++ self.connection_stopped = True
++
++ def loop_iter(self, timeout):
++ time.sleep(timeout)
++
++ def close(self):
++ pass
++
++class MockMailAccount(object):
++ def _init(self):
++ self.connected = False
++ self.has_connected = False
++ self.marked_all_as_read = False
++ self._action = PresenceAccount.DO_NOTHING
++
++ def connect(self):
++ self.connected = True
++ self.has_connected = True
++
++ def mark_all_as_read(self):
++ self.marked_all_as_read = True
++
++ def disconnect(self):
++ self.connected = False
++
++ def get_action(self):
++ return self._action
++
++ action = property(get_action)
++
++class MockIMAPAccount(MockMailAccount, IMAPAccount):
++ def _init(self, *args, **kw):
++ IMAPAccount._init(self, *args, **kw)
++ MockMailAccount._init(self)
++ self.get_mail_list_summary_called = False
++
++ def ls_dir(self, imap_dir):
++ if imap_dir == "":
++ return ["INBOX"]
++ elif imap_dir == "INBOX":
++ return ["dir1", "dir2"]
++ elif imap_dir == "INBOX/dir1":
++ return ["subdir1", "subdir2"]
++ return []
++
++ def get_mail_with_attachment_list(self):
++ return [("1", "mail 1"),
++ ("2", "mail 2")]
++
++ def get_mail_list_summary(self, start_index=1, end_index=20):
++ if self.get_mail_list_summary_called:
++ return [("11", "mail 11"),
++ ("12", "mail 12"),
++ ("13", "mail 13"),
++ ("14", "mail 14"),
++ ("15", "mail 15"),
++ ("16", "mail 16"),
++ ("17", "mail 17"),
++ ("18", "mail 18"),
++ ("19", "mail 19"),
++ ("20", "mail 20")]
++ else:
++ self.get_mail_list_summary_called = True
++ return [("1", "mail 1"),
++ ("2", "mail 2"),
++ ("3", "mail 3"),
++ ("4", "mail 4"),
++ ("5", "mail 5"),
++ ("6", "mail 6"),
++ ("7", "mail 7"),
++ ("8", "mail 8"),
++ ("9", "mail 9"),
++ ("10", "mail 10")]
++
++
++class MockPOP3Account(MockMailAccount, POP3Account):
++ def _init(self, *args, **kw):
++ POP3Account._init(self, *args, **kw)
++ MockMailAccount._init(self)
++
++class MailComponent_TestCase(JCLTestCase):
++ def setUp(self):
++ JCLTestCase.setUp(self, tables=[Account, PresenceAccount, User,
++ MailAccount, IMAPAccount, POP3Account,
++ GlobalSMTPAccount,
++ AbstractSMTPAccount, SMTPAccount,
++ MockIMAPAccount, MockPOP3Account])
++ self.comp = MailComponent("jmc.test.com",
++ "password",
++ "localhost",
++ "5347",
++ None,
++ None)
++ self.comp.stream = MockStream()
++ self.comp.stream_class = MockStream
++
++ def _account_has_been_checked(self, _account, old_value):
++ if old_value == _account.lastcheck:
++ return False
++ else:
++ delta = int(time.time()) - _account.lastcheck
++ return (delta <= 1) and (delta >= 0)
++
++ ###########################################################################
++ # 'feed' test methods
++ ###########################################################################
++ def test_feed_first_check(self):
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.status = account.ONLINE
++ self.assertTrue(account11.first_check)
++ self.assertEquals(account11.error, None)
++ self.assertFalse(account11.waiting_password_reply)
++ account11.live_email_only = False
++ account11.lastcheck = 0
++ account11.password = ""
++ result = self.comp.tick_handlers[0].feeder.feed(account11)
++ self.assertEquals(len(result), 0)
++ sent = self.comp.stream.sent
++ self.assertEquals(len(sent), 0)
++ self.assertFalse(account11.first_check)
++ self.assertFalse(account11.waiting_password_reply)
++ self.assertEquals(account11.error, None)
++ self.assertFalse(account11.connected)
++ self.assertFalse(account11.has_connected)
++ self.assertFalse(account11.marked_all_as_read)
++ self.assertTrue(self._account_has_been_checked(account11,
++ 0))
++
++ def test_feed_live_email_init_no_password(self):
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.status = account.ONLINE
++ self.assertTrue(account11.first_check)
++ self.assertEquals(account11.error, None)
++ self.assertFalse(account11.waiting_password_reply)
++ account11.live_email_only = True
++ account11.password = None
++ result = self.comp.tick_handlers[0].feeder.feed(account11)
++ self.assertEquals(len(result), 0)
++ sent = self.comp.stream.sent
++ self.assertEquals(len(sent), 1)
++ self.assertEquals(sent[0].get_to(), "test1@test.com")
++ self.assertEquals(sent[0].get_from(), "account11@jmc.test.com")
++ self.assertTrue(account11.first_check)
++ self.assertTrue(account11.waiting_password_reply)
++ self.assertEquals(account11.error, None)
++ self.assertFalse(account11.connected)
++ self.assertFalse(account11.has_connected)
++ self.assertFalse(account11.marked_all_as_read)
++
++ def test_feed_live_email_init_no_password2(self):
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.status = account.ONLINE
++ self.assertTrue(account11.first_check)
++ self.assertEquals(account11.error, None)
++ account11.waiting_password_reply = True
++ account11.live_email_only = True
++ account11.password = None
++ result = self.comp.tick_handlers[0].feeder.feed(account11)
++ self.assertEquals(result, [])
++ self.assertTrue(account11.first_check)
++ self.assertTrue(account11.waiting_password_reply)
++ self.assertEquals(account11.error, None)
++ self.assertFalse(account11.connected)
++ self.assertFalse(account11.has_connected)
++ self.assertFalse(account11.marked_all_as_read)
++ self.assertEquals(len(self.comp.stream.sent), 0)
++
++ def test_feed_interval_no_check(self):
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11._action = PresenceAccount.DO_NOTHING
++ account11.first_check = False
++ account11.lastcheck = old_value = int(time.time()) - 2
++ account11.interval = 2
++ result = self.comp.tick_handlers[0].feeder.feed(account11)
++ self.assertEquals(result, [])
++ self.assertFalse(self._account_has_been_checked(account11,
++ old_value))
++
++ def test_feed_interval_first_check(self):
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11._action = PresenceAccount.DO_NOTHING
++ account11.first_check = True
++ account11.lastcheck = 0
++ account11.interval = 2
++ result = self.comp.tick_handlers[0].feeder.feed(account11)
++ self.assertEquals(result, [])
++ self.assertTrue(self._account_has_been_checked(account11, 0))
++
++ def test_feed_interval_check(self):
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11._action = PresenceAccount.DO_NOTHING
++ account11.first_check = False
++ account11.lastcheck = 0
++ account11.interval = 2
++ result = self.comp.tick_handlers[0].feeder.feed(account11)
++ self.assertEquals(result, [])
++ self.assertTrue(self._account_has_been_checked(account11, 0))
++
++ def test_feed_no_password(self):
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11._action = MailAccount.RETRIEVE
++ account11.status = account.ONLINE
++ account11.first_check = False
++ account11.lastcheck = 0
++ account11.interval = 2
++ account11.password = None
++ self.assertFalse(account11.waiting_password_reply)
++ result = self.comp.tick_handlers[0].feeder.feed(account11)
++ self.assertEquals(account11.error, None)
++ self.assertEquals(len(result), 0)
++ sent = self.comp.stream.sent
++ self.assertEquals(len(sent), 1)
++ self.assertEquals(sent[0].get_to(), "test1@test.com")
++ self.assertEquals(sent[0].get_from(), "account11@jmc.test.com")
++ self.assertTrue(self._account_has_been_checked(account11, 0))
++ self.assertFalse(account11.connected)
++ self.assertFalse(account11.has_connected)
++
++ def test_feed_unknown_action(self):
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11._action = 42 # Unknown action
++ account11.status = account.ONLINE
++ account11.first_check = False
++ account11.lastcheck = 0
++ account11.interval = 2
++ account11.password = "password"
++ account11.get_new_mail_list = lambda: []
++ result = self.comp.tick_handlers[0].feeder.feed(account11)
++ self.assertNotEquals(account11.error, None)
++ self.assertEquals(len(result), 0)
++ sent = self.comp.stream.sent
++ self.assertEquals(len(sent), 2)
++ self.assertEquals(sent[0].get_to(), "test1@test.com")
++ self.assertEquals(sent[0].get_from(), "account11@jmc.test.com")
++ self.assertEquals(sent[1].get_to(), "test1@test.com")
++ self.assertEquals(sent[1].get_from(), "account11@jmc.test.com")
++ self.assertEquals(sent[1].xmlnode.name, "presence")
++ self.assertEquals(sent[1].xmlnode.children.name, "show")
++ self.assertEquals(sent[1].xmlnode.children.content, "dnd")
++ self.assertTrue(self._account_has_been_checked(account11, 0))
++ self.assertFalse(account11.connected)
++ self.assertTrue(account11.has_connected)
++
++ def test_feed_retrieve_no_mail(self):
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11._action = MailAccount.RETRIEVE
++ account11.status = account.ONLINE
++ account11.first_check = False
++ account11.lastcheck = 0
++ account11.interval = 2
++ account11.password = "password"
++ account11.get_new_mail_list = lambda: []
++ result = self.comp.tick_handlers[0].feeder.feed(account11)
++ self.assertEquals(account11.error, None)
++ self.assertEquals(result, [])
++ self.assertTrue(self._account_has_been_checked(account11, 0))
++ self.assertFalse(account11.connected)
++ self.assertTrue(account11.has_connected)
++ self.assertEquals(len(self.comp.stream.sent), 0)
++
++ def test_feed_cancel_error(self):
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11._action = MailAccount.RETRIEVE
++ account11.status = account.DND
++ account11.error = "An error"
++ account11.first_check = False
++ account11.lastcheck = 0
++ account11.interval = 2
++ account11.password = "password"
++ account11.get_new_mail_list = lambda: []
++ result = self.comp.tick_handlers[0].feeder.feed(account11)
++ self.assertEquals(account11.error, None)
++ self.assertEquals(result, [])
++ self.assertTrue(self._account_has_been_checked(account11, 0))
++ self.assertFalse(account11.connected)
++ self.assertTrue(account11.has_connected)
++ sent = self.comp.stream.sent
++ self.assertEquals(len(sent), 1)
++ self.assertEquals(sent[0].get_to(), "test1@test.com")
++ self.assertEquals(sent[0].get_from(), "account11@jmc.test.com")
++ self.assertEquals(sent[0].xmlnode.name, "presence")
++ self.assertEquals(sent[0].xmlnode.children.name, "show")
++ self.assertEquals(sent[0].xmlnode.children.content, "online")
++
++ def test_feed_retrieve_mail(self):
++ def mock_get_mail(index):
++ return [("body1", "from1@test.com"),
++ ("body2", "from2@test.com")][index]
++ model.db_connect()
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11._action = MailAccount.RETRIEVE
++ account11.status = account.ONLINE
++ account11.first_check = False
++ account11.lastcheck = 0
++ account11.interval = 2
++ account11.password = "password"
++ account11.get_new_mail_list = lambda: [0, 1]
++ account11.get_mail = mock_get_mail
++ result = self.comp.tick_handlers[0].feeder.feed(account11)
++ self.assertEquals(account11.error, None)
++ self.assertTrue(self._account_has_been_checked(account11, 0))
++ self.assertFalse(account11.connected)
++ self.assertTrue(account11.has_connected)
++ self.assertEquals(len(self.comp.stream.sent), 0)
++ self.assertEquals(len(result), 2)
++ self.assertEquals(result[0][0],
++ "from1@test.com")
++ self.assertEquals(result[0][1],
++ account11.default_lang_class.new_mail_subject \
++ % ("from1@test.com"))
++ self.assertEquals(result[0][2], "body1")
++ self.assertEquals(result[1][0],
++ "from2@test.com")
++ self.assertEquals(result[1][1], \
++ account11.default_lang_class.new_mail_subject \
++ % ("from2@test.com"))
++ self.assertEquals(result[1][2], "body2")
++ model.db_disconnect()
++
++ def test_feed_digest_no_mail(self):
++ model.db_connect()
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11._action = MailAccount.DIGEST
++ account11.status = account.ONLINE
++ account11.first_check = False
++ account11.lastcheck = 0
++ account11.interval = 2
++ account11.password = "password"
++ account11.get_new_mail_list = lambda: []
++ result = self.comp.tick_handlers[0].feeder.feed(account11)
++ self.assertEquals(account11.error, None)
++ self.assertEquals(result, [])
++ self.assertTrue(self._account_has_been_checked(account11, 0))
++ self.assertFalse(account11.connected)
++ self.assertTrue(account11.has_connected)
++ self.assertEquals(len(self.comp.stream.sent), 0)
++ model.db_disconnect()
++
++ def test_feed_digest_mail(self):
++ def mock_get_mail_summary(index):
++ return [("body1", "from1@test.com"),
++ ("body2", "from2@test.com")][index]
++ model.db_connect()
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11._action = MailAccount.DIGEST
++ account11.status = account.ONLINE
++ account11.first_check = False
++ account11.lastcheck = 0
++ account11.interval = 2
++ account11.password = "password"
++ account11.get_new_mail_list = lambda: [0, 1]
++ account11.get_mail_summary = mock_get_mail_summary
++ result = self.comp.tick_handlers[0].feeder.feed(account11)
++ self.assertEquals(account11.error, None)
++ self.assertTrue(self._account_has_been_checked(account11, 0))
++ self.assertFalse(account11.connected)
++ self.assertTrue(account11.has_connected)
++ self.assertEquals(len(self.comp.stream.sent), 0)
++ self.assertEquals(len(result), 1)
++ self.assertEquals(result[0][1],
++ account11.default_lang_class.new_digest_subject \
++ % (2))
++ self.assertEquals(result[0][2],
++ "body1\n----------------------------------\nbody2\n----------------------------------\n")
++ model.db_disconnect()
++
++ ###########################################################################
++ # 'initialize_live_email' test methods
++ ###########################################################################
++ def test_initialize_live_email(self):
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.status = account.ONLINE
++ self.assertTrue(account11.first_check)
++ self.assertEquals(account11.error, None)
++ account11.live_email_only = True
++ account11.password = "password"
++ continue_checking = self.comp.tick_handlers[0].feeder.initialize_live_email(account11)
++ self.assertEquals(continue_checking, True)
++ self.assertFalse(account11.first_check)
++ self.assertFalse(account11.waiting_password_reply)
++ self.assertEquals(account11.error, None)
++ self.assertFalse(account11.connected)
++ self.assertTrue(account11.has_connected)
++ self.assertTrue(account11.marked_all_as_read)
++
++ def test_initialize_live_email_connection_error(self):
++ def raiser():
++ raise Exception
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.connect = raiser
++ account11.status = account.ONLINE
++ self.assertTrue(account11.first_check)
++ self.assertEquals(account11.error, None)
++ account11.live_email_only = True
++ account11.password = "password"
++ continue_checking = self.comp.tick_handlers[0].feeder.initialize_live_email(account11)
++ self.assertEquals(continue_checking, False)
++ sent = self.comp.stream.sent
++ self.assertEquals(len(sent), 2)
++ self.assertEquals(sent[0].get_to(), "test1@test.com")
++ self.assertEquals(sent[0].get_from(), "account11@jmc.test.com")
++ self.assertEquals(sent[1].get_to(), "test1@test.com")
++ self.assertEquals(sent[1].get_from(), "account11@jmc.test.com")
++ self.assertEquals(sent[1].xmlnode.name, "presence")
++ self.assertEquals(sent[1].xmlnode.children.name, "show")
++ self.assertEquals(sent[1].xmlnode.children.content, "dnd")
++ self.assertTrue(account11.first_check)
++ self.assertFalse(account11.waiting_password_reply)
++ self.assertEquals(account11.error, "")
++ self.assertFalse(account11.connected)
++ self.assertFalse(account11.has_connected)
++ self.assertFalse(account11.marked_all_as_read)
++
++ def test_initialize_live_email_mark_as_read_error(self):
++ def raiser():
++ raise Exception
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.mark_all_as_read = raiser
++ account11.status = account.ONLINE
++ self.assertTrue(account11.first_check)
++ self.assertEquals(account11.error, None)
++ account11.live_email_only = True
++ account11.password = "password"
++ continue_checking = self.comp.tick_handlers[0].feeder.initialize_live_email(account11)
++ self.assertEquals(continue_checking, False)
++ sent = self.comp.stream.sent
++ self.assertEquals(len(sent), 2)
++ self.assertEquals(sent[0].get_to(), "test1@test.com")
++ self.assertEquals(sent[0].get_from(), "account11@jmc.test.com")
++ self.assertEquals(sent[1].get_to(), "test1@test.com")
++ self.assertEquals(sent[1].get_from(), "account11@jmc.test.com")
++ self.assertEquals(sent[1].xmlnode.name, "presence")
++ self.assertEquals(sent[1].xmlnode.children.name, "show")
++ self.assertEquals(sent[1].xmlnode.children.content, "dnd")
++ self.assertTrue(account11.first_check)
++ self.assertFalse(account11.waiting_password_reply)
++ self.assertEquals(account11.error, "")
++ self.assertFalse(account11.connected)
++ self.assertTrue(account11.has_connected)
++ self.assertFalse(account11.marked_all_as_read)
++
++ def test_initialize_live_email_disconnection_error(self):
++ def raiser():
++ raise Exception
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.disconnect = raiser
++ account11.status = account.ONLINE
++ self.assertTrue(account11.first_check)
++ self.assertEquals(account11.error, None)
++ account11.live_email_only = True
++ account11.password = "password"
++ continue_checking = self.comp.tick_handlers[0].feeder.initialize_live_email(account11)
++ self.assertFalse(continue_checking)
++ sent = self.comp.stream.sent
++ self.assertEquals(len(sent), 2)
++ self.assertEquals(sent[0].get_to(), "test1@test.com")
++ self.assertEquals(sent[0].get_from(), "account11@jmc.test.com")
++ self.assertEquals(sent[1].get_to(), "test1@test.com")
++ self.assertEquals(sent[1].get_from(), "account11@jmc.test.com")
++ self.assertEquals(sent[1].xmlnode.name, "presence")
++ self.assertEquals(sent[1].xmlnode.children.name, "show")
++ self.assertEquals(sent[1].xmlnode.children.content, "dnd")
++ self.assertEquals(continue_checking, False)
++ self.assertTrue(account11.first_check)
++ self.assertFalse(account11.waiting_password_reply)
++ self.assertEquals(account11.error, "")
++ self.assertFalse(account11.connected)
++ self.assertTrue(account11.has_connected)
++ self.assertTrue(account11.marked_all_as_read)
++
++ def test_initialize_live_email_cancel_error(self):
++ account11 = MockIMAPAccount(user=User(jid="test1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.status = account.DND
++ account11.error = "An error"
++ self.assertTrue(account11.first_check)
++ account11.live_email_only = True
++ account11.password = "password"
++ continue_checking = self.comp.tick_handlers[0].feeder.initialize_live_email(account11)
++ self.assertEquals(continue_checking, True)
++ self.assertFalse(account11.first_check)
++ self.assertFalse(account11.waiting_password_reply)
++ self.assertEquals(account11.error, None)
++ self.assertFalse(account11.connected)
++ self.assertTrue(account11.has_connected)
++ self.assertTrue(account11.marked_all_as_read)
++ sent = self.comp.stream.sent
++ self.assertEquals(len(sent), 1)
++ self.assertEquals(sent[0].get_to(), "test1@test.com")
++ self.assertEquals(sent[0].get_from(), "account11@jmc.test.com")
++ self.assertEquals(sent[0].xmlnode.name, "presence")
++ self.assertEquals(sent[0].xmlnode.children.name, "show")
++ self.assertEquals(sent[0].xmlnode.children.content, "online")
++
++ def test_disco_get_info_imap_node(self):
++ self.comp.stream = MockStream()
++ self.comp.stream_class = MockStream
++ account11 = MockIMAPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ info_query = Iq(stanza_type="get",
++ from_jid="user1@test.com",
++ to_jid="jcl.test.com/IMAP")
++ disco_info = self.comp.disco_get_info("IMAP", info_query)
++ self.assertEquals(len(self.comp.stream.sent), 0)
++ self.assertTrue(disco_info.has_feature("jabber:iq:register"))
++ self.assertTrue(disco_info.has_feature("http://jabber.org/protocol/disco#info"))
++ self.assertTrue(disco_info.has_feature("http://jabber.org/protocol/disco#items"))
++
++ def test_disco_get_info_imap_node_no_account(self):
++ self.comp.stream = MockStream()
++ self.comp.stream_class = MockStream
++ account11 = MockPOP3Account(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account21 = MockIMAPAccount(user=User(jid="user2@test.com"),
++ name="account21",
++ jid="account21@jmc.test.com")
++ info_query = Iq(stanza_type="get",
++ from_jid="user1@test.com",
++ to_jid="jcl.test.com/IMAP")
++ disco_info = self.comp.disco_get_info("IMAP", info_query)
++ self.assertEquals(len(self.comp.stream.sent), 0)
++ self.assertTrue(disco_info.has_feature("jabber:iq:register"))
++ self.assertFalse(disco_info.has_feature("http://jabber.org/protocol/disco#info"))
++ self.assertFalse(disco_info.has_feature("http://jabber.org/protocol/disco#items"))
++
++ def test_disco_get_info_imap_long_node(self):
++ self.comp.stream = MockStream()
++ self.comp.stream_class = MockStream
++ account11 = MockIMAPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ info_query = Iq(stanza_type="get",
++ from_jid="user1@test.com",
++ to_jid="account11@jcl.test.com/IMAP")
++ disco_info = self.comp.disco_get_info("IMAP/account11",
++ info_query)
++ self.assertEquals(len(self.comp.stream.sent), 0)
++ self.assertTrue(disco_info.has_feature("jabber:iq:register"))
++ self.assertTrue(disco_info.has_feature("http://jabber.org/protocol/disco#info"))
++ self.assertTrue(disco_info.has_feature("http://jabber.org/protocol/disco#items"))
++
++ def test_disco_get_info_not_imap_long_node(self):
++ self.comp.stream = MockStream()
++ self.comp.stream_class = MockStream
++ account11 = MockPOP3Account(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ info_query = Iq(stanza_type="get",
++ from_jid="user1@test.com",
++ to_jid="account11@jcl.test.com/POP3")
++ disco_info = self.comp.disco_get_info("POP3/account11",
++ info_query)
++ self.assertEquals(len(self.comp.stream.sent), 0)
++ self.assertTrue(disco_info.has_feature("jabber:iq:register"))
++ self.assertFalse(disco_info.has_feature("http://jabber.org/protocol/disco#info"))
++ self.assertFalse(disco_info.has_feature("http://jabber.org/protocol/disco#items"))
++
++ def test_disco_get_info_imap_dir_node(self):
++ self.comp.stream = MockStream()
++ self.comp.stream_class = MockStream
++ account11 = MockIMAPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.mailbox = "INBOX/dir1"
++ info_query = Iq(stanza_type="get",
++ from_jid="user1@test.com",
++ to_jid="account11@jcl.test.com/IMAP/INBOX")
++ disco_info = self.comp.disco_get_info("IMAP/account11/INBOX",
++ info_query)
++ self.assertEquals(len(self.comp.stream.sent), 0)
++ self.assertTrue(disco_info.has_feature("jabber:iq:register"))
++ self.assertTrue(disco_info.has_feature("http://jabber.org/protocol/disco#info"))
++ self.assertTrue(disco_info.has_feature("http://jabber.org/protocol/disco#items"))
++
++ def test_disco_get_info_imap_dir_node_already_registered(self):
++ self.comp.stream = MockStream()
++ self.comp.stream_class = MockStream
++ account11 = MockIMAPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.mailbox = "INBOX"
++ info_query = Iq(stanza_type="get",
++ from_jid="user1@test.com",
++ to_jid="account11@jcl.test.com/IMAP/INBOX")
++ disco_info = self.comp.disco_get_info("IMAP/account11/INBOX",
++ info_query)
++ self.assertEquals(len(self.comp.stream.sent), 0)
++ self.assertTrue(disco_info.has_feature("jabber:iq:register"))
++ self.assertTrue(disco_info.has_feature("http://jabber.org/protocol/disco#info"))
++ self.assertTrue(disco_info.has_feature("http://jabber.org/protocol/disco#items"))
++
++ def test_disco_get_info_imap_dir_node_last_subdir(self):
++ self.comp.stream = MockStream()
++ self.comp.stream_class = MockStream
++ account11 = MockIMAPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.mailbox = "INBOX/dir1/subdir1"
++ info_query = Iq(stanza_type="get",
++ from_jid="user1@test.com",
++ to_jid="account11@jcl.test.com/IMAP/INBOX/dir1/subdir1")
++ disco_info = self.comp.disco_get_info("IMAP/account11/INBOX/dir1/subdir1",
++ info_query)
++ self.assertEquals(len(self.comp.stream.sent), 0)
++ self.assertTrue(disco_info.has_feature("jabber:iq:register"))
++ self.assertTrue(disco_info.has_feature("http://jabber.org/protocol/disco#info"))
++ self.assertFalse(disco_info.has_feature("http://jabber.org/protocol/disco#items"))
++
++ def test_disco_get_items_base_imap_account(self):
++ account11 = MockIMAPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jcl.test.com")
++ info_query = Iq(stanza_type="get",
++ from_jid="user1@test.com",
++ to_jid="account11@jcl.test.com/IMAP")
++ disco_items = self.comp.disco_get_items("IMAP/account11", info_query)
++ self.assertEquals(len(disco_items.get_items()), 1)
++ disco_item = disco_items.get_items()[0]
++ self.assertEquals(unicode(disco_item.get_jid()), unicode(account11.jid)
++ + "/IMAP/INBOX")
++ self.assertEquals(disco_item.get_node(), "IMAP/" + account11.name + "/INBOX")
++ self.assertEquals(disco_item.get_name(), "INBOX")
++
++ def test_disco_get_items_inbox_imap_account(self):
++ account11 = MockIMAPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jcl.test.com")
++ info_query = Iq(stanza_type="get",
++ from_jid="user1@test.com",
++ to_jid="account11@jcl.test.com/IMAP/INBOX")
++ disco_items = self.comp.disco_get_items("IMAP/account11/INBOX", info_query)
++ self.assertEquals(len(disco_items.get_items()), 2)
++ disco_item = disco_items.get_items()[0]
++ self.assertEquals(unicode(disco_item.get_jid()), unicode(account11.jid)
++ + "/IMAP/INBOX/dir1")
++ self.assertEquals(disco_item.get_node(), "IMAP/" + account11.name + "/INBOX"
++ + "/dir1")
++ self.assertEquals(disco_item.get_name(), "dir1")
++ disco_item = disco_items.get_items()[1]
++ self.assertEquals(unicode(disco_item.get_jid()), unicode(account11.jid)
++ + "/IMAP/INBOX/dir2")
++ self.assertEquals(disco_item.get_node(), "IMAP/" + account11.name + "/INBOX"
++ + "/dir2")
++ self.assertEquals(disco_item.get_name(), "dir2")
++
++ def test_disco_get_items_subdir_imap_account(self):
++ account11 = MockIMAPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jcl.test.com")
++ info_query = Iq(stanza_type="get",
++ from_jid="user1@test.com",
++ to_jid="account11@jcl.test.com/IMAP")
++ disco_items = self.comp.disco_get_items("IMAP/account11/INBOX/dir1", info_query)
++ self.assertEquals(len(disco_items.get_items()), 2)
++ disco_item = disco_items.get_items()[0]
++ self.assertEquals(unicode(disco_item.get_jid()), unicode(account11.jid)
++ + "/IMAP/INBOX/dir1/subdir1")
++ self.assertEquals(disco_item.get_node(), "IMAP/" + account11.name + "/INBOX"
++ + "/dir1/subdir1")
++ self.assertEquals(disco_item.get_name(), "subdir1")
++ disco_item = disco_items.get_items()[1]
++ self.assertEquals(unicode(disco_item.get_jid()), unicode(account11.jid)
++ + "/IMAP/INBOX/dir1/subdir2")
++ self.assertEquals(disco_item.get_node(), "IMAP/" + account11.name + "/INBOX"
++ + "/dir1/subdir2")
++ self.assertEquals(disco_item.get_name(), "subdir2")
++
++ def test_account_get_register_imap_dir_already_registered(self):
++ model.db_connect()
++ self.comp.stream = MockStream()
++ self.comp.stream_class = MockStream
++ user1 = User(jid="user1@test.com")
++ account1 = MockIMAPAccount(user=user1,
++ name="account1",
++ jid="account1@jcl.test.com")
++ account1.mailbox = "INBOX"
++ account11 = MockIMAPAccount(user=user1,
++ name="account11",
++ jid="account11@jcl.test.com")
++ account11.mailbox = "INBOX/dir1"
++ account11.password = "pass1"
++ account11.port = 993
++ account11.host = "host1"
++ account11.login = "login1"
++ account11.ssl = True
++ account11.interval = 1
++ account11.store_password = False
++ account11.live_email_only = True
++ account11.chat_action = PresenceAccount.DO_NOTHING
++ account11.online_action = PresenceAccount.DO_NOTHING
++ account11.away_action = PresenceAccount.DO_NOTHING
++ account11.xa_action = PresenceAccount.DO_NOTHING
++ account11.dnd_action = PresenceAccount.DO_NOTHING
++ account11.offline_action = PresenceAccount.DO_NOTHING
++ account21 = MockIMAPAccount(user=User(jid="user2@test.com"),
++ name="account21",
++ jid="account21@jcl.test.com")
++ model.db_disconnect()
++ self.comp.handle_get_register(Iq(stanza_type="get",
++ from_jid="user1@test.com",
++ to_jid="account1@jcl.test.com/IMAP/INBOX/dir1"))
++ self.assertEquals(len(self.comp.stream.sent), 1)
++ iq_sent = self.comp.stream.sent[0]
++ self.assertEquals(iq_sent.get_to(), "user1@test.com")
++ titles = iq_sent.xpath_eval("jir:query/jxd:x/jxd:title",
++ {"jir" : "jabber:iq:register",
++ "jxd" : "jabber:x:data"})
++ self.assertEquals(len(titles), 1)
++ self.assertEquals(titles[0].content,
++ Lang.en.register_title)
++ instructions = iq_sent.xpath_eval("jir:query/jxd:x/jxd:instructions",
++ {"jir" : "jabber:iq:register",
++ "jxd" : "jabber:x:data"})
++ self.assertEquals(len(instructions), 1)
++ self.assertEquals(instructions[0].content,
++ Lang.en.register_instructions)
++ fields = iq_sent.xpath_eval("jir:query/jxd:x/jxd:field",
++ {"jir" : "jabber:iq:register",
++ "jxd" : "jabber:x:data"})
++ self.assertEquals(len(fields), 16)
++ field = fields[0]
++ self.assertEquals(field.prop("type"), "hidden")
++ self.assertEquals(field.prop("var"), "name")
++ self.assertEquals(field.prop("label"), Lang.en.account_name)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "account11")
++ self.assertEquals(field.children.next.name, "required")
++ field = fields[1]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "chat_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_chat_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[2]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "online_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_online_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[3]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "away_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_away_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[4]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "xa_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_xa_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[5]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "dnd_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_dnd_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[6]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "offline_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_offline_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[7]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "login")
++ self.assertEquals(field.prop("label"), Lang.en.field_login)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "login1")
++ self.assertEquals(field.children.next.name, "required")
++ field = fields[8]
++ self.assertEquals(field.prop("type"), "text-private")
++ self.assertEquals(field.prop("var"), "password")
++ self.assertEquals(field.prop("label"), Lang.en.field_password)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "pass1")
++ field = fields[9]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "host")
++ self.assertEquals(field.prop("label"), Lang.en.field_host)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "host1")
++ self.assertEquals(field.children.next.name, "required")
++ field = fields[10]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "port")
++ self.assertEquals(field.prop("label"), Lang.en.field_port)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "993")
++ field = fields[11]
++ self.assertEquals(field.prop("type"), "boolean")
++ self.assertEquals(field.prop("var"), "ssl")
++ self.assertEquals(field.prop("label"), Lang.en.field_ssl)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "1")
++ field = fields[12]
++ self.assertEquals(field.prop("type"), "boolean")
++ self.assertEquals(field.prop("var"), "store_password")
++ self.assertEquals(field.prop("label"), Lang.en.field_store_password)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[13]
++ self.assertEquals(field.prop("type"), "boolean")
++ self.assertEquals(field.prop("var"), "live_email_only")
++ self.assertEquals(field.prop("label"), Lang.en.field_live_email_only)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "1")
++ field = fields[14]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "interval")
++ self.assertEquals(field.prop("label"), Lang.en.field_interval)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "1")
++ field = fields[15]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "mailbox")
++ self.assertEquals(field.prop("label"), Lang.en.field_mailbox)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "INBOX/dir1")
++
++ def test_account_get_register_imap_dir_new(self):
++ model.db_connect()
++ self.comp.stream = MockStream()
++ self.comp.stream_class = MockStream
++ user1 = User(jid="user1@test.com")
++ account1 = MockIMAPAccount(user=user1,
++ name="account1",
++ jid="account1@jcl.test.com")
++ account1.maildir = "INBOX"
++ account1.password = "pass1"
++ account1.port = 993
++ account1.host = "host1"
++ account1.login = "login1"
++ account1.ssl = True
++ account1.interval = 1
++ account1.store_password = False
++ account1.live_email_only = True
++ account1.chat_action = PresenceAccount.DO_NOTHING
++ account1.online_action = PresenceAccount.DO_NOTHING
++ account1.away_action = PresenceAccount.DO_NOTHING
++ account1.xa_action = PresenceAccount.DO_NOTHING
++ account1.dnd_action = PresenceAccount.DO_NOTHING
++ account1.offline_action = PresenceAccount.DO_NOTHING
++ account11 = MockIMAPAccount(user=user1,
++ name="account11",
++ jid="account11@jcl.test.com")
++ account11.maildir = "INBOX/dir1"
++ account11.delimiter = "/"
++ account21 = MockIMAPAccount(user=User(jid="user2@test.com"),
++ name="account21",
++ jid="account21@jcl.test.com")
++ model.db_disconnect()
++ self.comp.handle_get_register(Iq(stanza_type="get",
++ from_jid="user1@test.com",
++ to_jid="account1@jcl.test.com/IMAP/INBOX/dir1/subdir1"))
++ self.assertEquals(len(self.comp.stream.sent), 1)
++ iq_sent = self.comp.stream.sent[0]
++ self.assertEquals(iq_sent.get_to(), "user1@test.com")
++ titles = iq_sent.xpath_eval("jir:query/jxd:x/jxd:title",
++ {"jir" : "jabber:iq:register",
++ "jxd" : "jabber:x:data"})
++ self.assertEquals(len(titles), 1)
++ self.assertEquals(titles[0].content,
++ Lang.en.register_title)
++ instructions = iq_sent.xpath_eval("jir:query/jxd:x/jxd:instructions",
++ {"jir" : "jabber:iq:register",
++ "jxd" : "jabber:x:data"})
++ self.assertEquals(len(instructions), 1)
++ self.assertEquals(instructions[0].content,
++ Lang.en.register_instructions)
++ fields = iq_sent.xpath_eval("jir:query/jxd:x/jxd:field",
++ {"jir" : "jabber:iq:register",
++ "jxd" : "jabber:x:data"})
++ self.assertEquals(len(fields), 16)
++ field = fields[0]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "name")
++ self.assertEquals(field.prop("label"), Lang.en.account_name)
++ self.assertEquals(field.children.name, "required")
++ self.assertEquals(field.children.next, None)
++ field = fields[1]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "chat_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_chat_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[2]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "online_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_online_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[3]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "away_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_away_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[4]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "xa_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_xa_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[5]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "dnd_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_dnd_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[6]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "offline_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_offline_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[7]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "login")
++ self.assertEquals(field.prop("label"), Lang.en.field_login)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "login1")
++ self.assertEquals(field.children.next.name, "required")
++ field = fields[8]
++ self.assertEquals(field.prop("type"), "text-private")
++ self.assertEquals(field.prop("var"), "password")
++ self.assertEquals(field.prop("label"), Lang.en.field_password)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "pass1")
++ field = fields[9]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "host")
++ self.assertEquals(field.prop("label"), Lang.en.field_host)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "host1")
++ self.assertEquals(field.children.next.name, "required")
++ field = fields[10]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "port")
++ self.assertEquals(field.prop("label"), Lang.en.field_port)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "993")
++ field = fields[11]
++ self.assertEquals(field.prop("type"), "boolean")
++ self.assertEquals(field.prop("var"), "ssl")
++ self.assertEquals(field.prop("label"), Lang.en.field_ssl)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "1")
++ field = fields[12]
++ self.assertEquals(field.prop("type"), "boolean")
++ self.assertEquals(field.prop("var"), "store_password")
++ self.assertEquals(field.prop("label"), Lang.en.field_store_password)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[13]
++ self.assertEquals(field.prop("type"), "boolean")
++ self.assertEquals(field.prop("var"), "live_email_only")
++ self.assertEquals(field.prop("label"), Lang.en.field_live_email_only)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "1")
++ field = fields[14]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "interval")
++ self.assertEquals(field.prop("label"), Lang.en.field_interval)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "1")
++ field = fields[15]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "mailbox")
++ self.assertEquals(field.prop("label"), Lang.en.field_mailbox)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "INBOX/dir1/subdir1")
++
++ def test_account_get_register_imap_dir_new(self):
++ model.db_connect()
++ self.comp.stream = MockStream()
++ self.comp.stream_class = MockStream
++ user1 = User(jid="user1@test.com")
++ account1 = MockIMAPAccount(user=user1,
++ name="account1",
++ jid="account1@jcl.test.com")
++ account1.maildir = "INBOX"
++ account1.password = "pass1"
++ account1.port = 993
++ account1.host = "host1"
++ account1.login = "login1"
++ account1.ssl = True
++ account1.interval = 1
++ account1.store_password = False
++ account1.live_email_only = True
++ account1.chat_action = PresenceAccount.DO_NOTHING
++ account1.online_action = PresenceAccount.DO_NOTHING
++ account1.away_action = PresenceAccount.DO_NOTHING
++ account1.xa_action = PresenceAccount.DO_NOTHING
++ account1.dnd_action = PresenceAccount.DO_NOTHING
++ account1.offline_action = PresenceAccount.DO_NOTHING
++ account11 = MockIMAPAccount(user=user1,
++ name="account11",
++ jid="account11@jcl.test.com")
++ account11.maildir = "INBOX/dir1"
++ account11.delimiter = "."
++ account21 = MockIMAPAccount(user=User(jid="user2@test.com"),
++ name="account21",
++ jid="account21@jcl.test.com")
++ model.db_disconnect()
++ self.comp.handle_get_register(Iq(stanza_type="get",
++ from_jid="user1@test.com",
++ to_jid="account1@jcl.test.com/IMAP/INBOX/dir1/subdir1"))
++ self.assertEquals(len(self.comp.stream.sent), 1)
++ iq_sent = self.comp.stream.sent[0]
++ self.assertEquals(iq_sent.get_to(), "user1@test.com")
++ titles = iq_sent.xpath_eval("jir:query/jxd:x/jxd:title",
++ {"jir" : "jabber:iq:register",
++ "jxd" : "jabber:x:data"})
++ self.assertEquals(len(titles), 1)
++ self.assertEquals(titles[0].content,
++ Lang.en.register_title)
++ instructions = iq_sent.xpath_eval("jir:query/jxd:x/jxd:instructions",
++ {"jir" : "jabber:iq:register",
++ "jxd" : "jabber:x:data"})
++ self.assertEquals(len(instructions), 1)
++ self.assertEquals(instructions[0].content,
++ Lang.en.register_instructions)
++ fields = iq_sent.xpath_eval("jir:query/jxd:x/jxd:field",
++ {"jir" : "jabber:iq:register",
++ "jxd" : "jabber:x:data"})
++ self.assertEquals(len(fields), 16)
++ field = fields[0]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "name")
++ self.assertEquals(field.prop("label"), Lang.en.account_name)
++ self.assertEquals(field.children.name, "required")
++ self.assertEquals(field.children.next, None)
++ field = fields[1]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "chat_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_chat_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[2]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "online_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_online_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[3]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "away_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_away_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[4]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "xa_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_xa_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[5]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "dnd_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_dnd_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[6]
++ self.assertEquals(field.prop("type"), "list-single")
++ self.assertEquals(field.prop("var"), "offline_action")
++ self.assertEquals(field.prop("label"), Lang.en.field_offline_action)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[7]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "login")
++ self.assertEquals(field.prop("label"), Lang.en.field_login)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "login1")
++ self.assertEquals(field.children.next.name, "required")
++ field = fields[8]
++ self.assertEquals(field.prop("type"), "text-private")
++ self.assertEquals(field.prop("var"), "password")
++ self.assertEquals(field.prop("label"), Lang.en.field_password)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "pass1")
++ field = fields[9]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "host")
++ self.assertEquals(field.prop("label"), Lang.en.field_host)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "host1")
++ self.assertEquals(field.children.next.name, "required")
++ field = fields[10]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "port")
++ self.assertEquals(field.prop("label"), Lang.en.field_port)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "993")
++ field = fields[11]
++ self.assertEquals(field.prop("type"), "boolean")
++ self.assertEquals(field.prop("var"), "ssl")
++ self.assertEquals(field.prop("label"), Lang.en.field_ssl)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "1")
++ field = fields[12]
++ self.assertEquals(field.prop("type"), "boolean")
++ self.assertEquals(field.prop("var"), "store_password")
++ self.assertEquals(field.prop("label"), Lang.en.field_store_password)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "0")
++ field = fields[13]
++ self.assertEquals(field.prop("type"), "boolean")
++ self.assertEquals(field.prop("var"), "live_email_only")
++ self.assertEquals(field.prop("label"), Lang.en.field_live_email_only)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "1")
++ field = fields[14]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "interval")
++ self.assertEquals(field.prop("label"), Lang.en.field_interval)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "1")
++ field = fields[15]
++ self.assertEquals(field.prop("type"), "text-single")
++ self.assertEquals(field.prop("var"), "mailbox")
++ self.assertEquals(field.prop("label"), Lang.en.field_mailbox)
++ self.assertEquals(field.children.name, "value")
++ self.assertEquals(field.children.content, "INBOX.dir1.subdir1")
++
++class MailSender_TestCase(JCLTestCase):
++ def setUp(self):
++ JCLTestCase.setUp(self, tables=[Account, PresenceAccount, MailAccount,
++ IMAPAccount, POP3Account, User])
++
++ def test_create_message(self):
++ mail_sender = MailSender()
++ model.db_connect()
++ user1 = User(jid="test1@test.com")
++ account11 = IMAPAccount(user=user1,
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.online_action = MailAccount.RETRIEVE
++ account11.status = account.ONLINE
++ message = mail_sender.create_message(account11, ("from@test.com",
++ "subject",
++ "message body"))
++ self.assertEquals(message.get_to(), user1.jid)
++ model.db_disconnect()
++ self.assertEquals(message.get_subject(), "subject")
++ self.assertEquals(message.get_body(), "message body")
++ addresses = message.xpath_eval("add:addresses/add:address",
++ {"add": "http://jabber.org/protocol/address"})
++ self.assertEquals(len(addresses), 1)
++ self.assertEquals(addresses[0].prop("type"),
++ "replyto")
++ self.assertEquals(addresses[0].prop("jid"),
++ "from%test.com@jmc.test.com")
++
++ def test_create_message_missing_email_from(self):
++ mail_sender = MailSender()
++ model.db_connect()
++ user1 = User(jid="test1@test.com")
++ account11 = IMAPAccount(user=user1,
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.online_action = MailAccount.RETRIEVE
++ account11.status = account.ONLINE
++ message = mail_sender.create_message(account11, (None,
++ "subject",
++ "message body"))
++ self.assertEquals(message.get_to(), user1.jid)
++ self.assertEquals(message.get_subject(), "subject")
++ self.assertEquals(message.get_body(), "message body")
++ addresses = message.xpath_eval("add:addresses/add:address",
++ {"add": "http://jabber.org/protocol/address"})
++ self.assertEquals(addresses, [])
++
++ def test_create_message_digest(self):
++ mail_sender = MailSender()
++ model.db_connect()
++ user1 = User(jid="test1@test.com")
++ account11 = IMAPAccount(user=user1,
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.online_action = MailAccount.DIGEST
++ account11.status = account.ONLINE
++ message = mail_sender.create_message(account11, ("from@test.com",
++ "subject",
++ "message body"))
++ self.assertEquals(message.get_to(), user1.jid)
++ model.db_disconnect()
++ self.assertEquals(message.get_subject(), "subject")
++ self.assertEquals(message.get_body(), "message body")
++ self.assertEquals(message.get_type(), "headline")
++
++class MailHandler_TestCase(JCLTestCase):
++ def setUp(self, tables=[]):
++ self.handler = MailHandler(None)
++ JCLTestCase.setUp(self, tables=[Account, AbstractSMTPAccount,
++ GlobalSMTPAccount, SMTPAccount, User] \
++ + tables)
++
++ def test_filter(self):
++ model.db_connect()
++ user1 = User(jid="user1@test.com")
++ account11 = SMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jcl.test.com")
++ account11.default_account = True
++ account12 = SMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jcl.test.com")
++ message = Message(from_jid="user1@test.com",
++ to_jid="user2%test.com@jcl.test.com",
++ body="message")
++ accounts = self.handler.filter(message, None)
++ self.assertNotEquals(accounts, None)
++ i = 0
++ for _account in accounts:
++ i += 1
++ if i == 1:
++ self.assertEquals(_account.name, "account11")
++ self.assertEquals(i, 1)
++ model.db_disconnect()
++
++ def test_filter_root(self):
++ model.db_connect()
++ user1 = User(jid="user1@test.com")
++ account11 = SMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jcl.test.com")
++ account11.default_account = True
++ account12 = SMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jcl.test.com")
++ message = Message(from_jid="user1@test.com",
++ to_jid="jcl.test.com",
++ body="message")
++ accounts = self.handler.filter(message, None)
++ self.assertEquals(accounts, None)
++ model.db_disconnect()
++
++ def test_filter_no_default(self):
++ model.db_connect()
++ user1 = User(jid="user1@test.com")
++ account11 = SMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jcl.test.com")
++ account12 = SMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jcl.test.com")
++ message = Message(from_jid="user1@test.com",
++ to_jid="user2%test.com@jcl.test.com",
++ body="message")
++ accounts = self.handler.filter(message, None)
++ self.assertNotEquals(accounts, None)
++ i = 0
++ for _account in accounts:
++ i += 1
++ if i == 1:
++ self.assertEquals(_account.name, "account11")
++ else:
++ self.assertEquals(_account.name, "account12")
++ self.assertEquals(i, 2)
++ model.db_disconnect()
++
++ def test_filter_wrong_dest(self):
++ model.db_connect()
++ user1 = User(jid="user1@test.com")
++ account11 = SMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jcl.test.com")
++ account12 = SMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jcl.test.com")
++ message = Message(from_jid="user1@test.com",
++ to_jid="user2test.com@jcl.test.com",
++ body="message")
++ accounts = self.handler.filter(message, None)
++ self.assertEquals(accounts, None)
++ model.db_disconnect()
++
++ def test_filter_wrong_account(self):
++ model.db_connect()
++ user1 = User(jid="user1@test.com")
++ account11 = SMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jcl.test.com")
++ account12 = SMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jcl.test.com")
++ message = Message(from_jid="user3@test.com",
++ to_jid="user2%test.com@jcl.test.com",
++ body="message")
++ try:
++ accounts = self.handler.filter(message, None)
++ model.db_disconnect()
++ except NoAccountError, e:
++ model.db_disconnect()
++ self.assertNotEquals(e, None)
++ else:
++ self.fail("No exception 'NoAccountError' catched")
++
++class MailPresenceHandler_TestCase(unittest.TestCase):
++ def setUp(self):
++ self.handler = MailPresenceHandler(None)
++
++ def test_filter(self):
++ message = Message(from_jid="user1@test.com",
++ to_jid="user11%test.com@jcl.test.com",
++ body="message")
++ result = self.handler.filter(message, None)
++ self.assertNotEquals(result, None)
++
++ def test_filter_wrong_dest(self):
++ message = Message(from_jid="user1@test.com",
++ to_jid="user11@jcl.test.com",
++ body="message")
++ result = self.handler.filter(message, None)
++ self.assertEquals(result, None)
++
++ def test_filter_wrong_dest2(self):
++ message = Message(from_jid="user1@test.com",
++ to_jid="jcl.test.com",
++ body="message")
++ result = self.handler.filter(message, None)
++ self.assertEquals(result, None)
++
++class MailSubscribeHandler_TestCase(DefaultSubscribeHandler_TestCase, MailHandler_TestCase):
++ def setUp(self):
++ MailHandler_TestCase.setUp(self, tables=[LegacyJID])
++ self.handler = MailSubscribeHandler(None)
++
++ def test_handle(self):
++ model.db_connect()
++ account11 = SMTPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jcl.test.com")
++ presence = Presence(from_jid="user1@test.com",
++ to_jid="user1%test.com@jcl.test.com",
++ stanza_type="subscribe")
++ result = self.handler.handle(presence, Lang.en, [account11])
++ legacy_jids = LegacyJID.select()
++ self.assertEquals(legacy_jids.count(), 1)
++ model.db_disconnect()
++
++class MailUnsubscribeHandler_TestCase(DefaultUnsubscribeHandler_TestCase, MailHandler_TestCase):
++ def setUp(self):
++ MailHandler_TestCase.setUp(self, tables=[LegacyJID])
++ self.handler = MailUnsubscribeHandler(None)
++
++ def test_handle(self):
++ model.db_connect()
++ user1 = User(jid="user1@test.com")
++ account11 = SMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jcl.test.com")
++ account12 = SMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jcl.test.com")
++ account2 = SMTPAccount(user=User(jid="user2@test.com"),
++ name="account2",
++ jid="account2@jcl.test.com")
++ presence = Presence(from_jid="user1@test.com",
++ to_jid="u111%test.com@jcl.test.com",
++ stanza_type="unsubscribe")
++ legacy_jid111 = LegacyJID(legacy_address="u111@test.com",
++ jid="u111%test.com@jcl.test.com",
++ account=account11)
++ legacy_jid112 = LegacyJID(legacy_address="u112@test.com",
++ jid="u112%test.com@jcl.test.com",
++ account=account11)
++ legacy_jid121 = LegacyJID(legacy_address="u121@test.com",
++ jid="u121%test.com@jcl.test.com",
++ account=account12)
++ legacy_jid122 = LegacyJID(legacy_address="u122@test.com",
++ jid="u122%test.com@jcl.test.com",
++ account=account12)
++ legacy_jid21 = LegacyJID(legacy_address="u21@test.com",
++ jid="u21%test.com@jcl.test.com",
++ account=account2)
++ result = self.handler.handle(presence, Lang.en, [account11])
++ legacy_jids = LegacyJID.select()
++ self.assertEquals(legacy_jids.count(), 4)
++ removed_legacy_jid = LegacyJID.select(\
++ LegacyJID.q.jid == "u111%test.com@jcl.test.com")
++ self.assertEquals(removed_legacy_jid.count(), 0)
++ model.db_disconnect()
++
++class MailFeederHandler_TestCase(JCLTestCase):
++ def setUp(self):
++ self.handler = MailFeederHandler(FeederMock(), SenderMock())
++ JCLTestCase.setUp(self, tables=[Account, PresenceAccount, MailAccount,
++ IMAPAccount, POP3Account, SMTPAccount,
++ GlobalSMTPAccount,
++ AbstractSMTPAccount, User])
++
++ def test_filter(self):
++ model.db_connect()
++ account11 = SMTPAccount(user=User(jid="user1@test.com"),
++ name="account11",
++ jid="account11@jcl.test.com")
++ account13 = IMAPAccount(user=User(jid="user3@test.com"),
++ name="account13",
++ jid="account13@jcl.test.com")
++ account12 = POP3Account(user=User(jid="user2@test.com"),
++ name="account12",
++ jid="account12@jcl.test.com")
++ accounts = self.handler.filter(None, None)
++ i = 0
++ # SQLObject > 0.8 is needed
++ for _account in accounts:
++ i += 1
++ if i == 1:
++ self.assertEquals(_account.name, "account13")
++ else:
++ self.assertEquals(_account.name, "account12")
++ self.assertEquals(i, 2)
++ model.db_disconnect()
++
++def suite():
++ test_suite = unittest.TestSuite()
++ test_suite.addTest(unittest.makeSuite(MailComponent_TestCase, 'test'))
++ test_suite.addTest(unittest.makeSuite(MailSender_TestCase, 'test'))
++ test_suite.addTest(unittest.makeSuite(MailHandler_TestCase, 'test'))
++ test_suite.addTest(unittest.makeSuite(MailUnsubscribeHandler_TestCase, 'test'))
++ test_suite.addTest(unittest.makeSuite(MailSubscribeHandler_TestCase, 'test'))
++ test_suite.addTest(unittest.makeSuite(MailPresenceHandler_TestCase, 'test'))
++ test_suite.addTest(unittest.makeSuite(MailFeederHandler_TestCase, 'test'))
++ return test_suite
++
++if __name__ == '__main__':
++ logger = logging.getLogger()
++ logger.addHandler(logging.StreamHandler())
++ if '-v' in sys.argv:
++ logger.setLevel(logging.INFO)
++ unittest.main(defaultTest='suite')
+--- /dev/null
++++ jmc-0.3b3/src/jmc/jabber/tests/presence.py
+@@ -0,0 +1,73 @@
++# -*- coding: utf-8 -*-
++##
++## presence.py
++## Login : <dax@happycoders.org>
++## Started on Thu Dec 6 08:19:59 2007 David Rousselie
++## $Id$
++##
++## Copyright (C) 2007 David Rousselie
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++##
++
++import unittest
++import time
++
++from pyxmpp.iq import Iq
++
++from jcl.model.account import User, LegacyJID, Account
++from jcl.tests import JCLTestCase
++
++from jmc.jabber.component import MailComponent
++from jmc.jabber.presence import MailAccountIQLastHandler
++
++class MailAccountIQLastHandler_TestCase(JCLTestCase):
++ def setUp(self):
++ JCLTestCase.setUp(self, tables=[User, LegacyJID, Account])
++ self.comp = MailComponent("jmc.test.com",
++ "password",
++ "localhost",
++ "5347",
++ None, None)
++ self.handler = MailAccountIQLastHandler(self.comp)
++
++ def test_handle(self):
++ user1 = User(jid="user1@test.com")
++ account11 = Account(user=user1,
++ name="account11",
++ jid="account11@jcl.test.com")
++ account12 = Account(user=user1,
++ name="account12",
++ jid="account12@jcl.test.com")
++ info_query = Iq(from_jid="user1@test.com",
++ to_jid="account11@jcl.test.com",
++ stanza_type="get")
++ account11.lastcheck = int(time.time())
++ time.sleep(1)
++ result = self.handler.handle(info_query, None, account11)
++ self.assertEquals(len(result), 1)
++ self.assertEquals(result[0].get_to(), "user1@test.com")
++ self.assertEquals(result[0].get_from(), "account11@jcl.test.com")
++ self.assertEquals(result[0].get_type(), "result")
++ self.assertNotEquals(result[0].xmlnode.children, None)
++ self.assertEquals(result[0].xmlnode.children.name, "query")
++ self.assertEquals(int(result[0].xmlnode.children.prop("seconds")), 1)
++
++def suite():
++ test_suite = unittest.TestSuite()
++ test_suite.addTest(unittest.makeSuite(MailAccountIQLastHandler_TestCase, 'test'))
++ return test_suite
++
++if __name__ == '__main__':
++ unittest.main(defaultTest='suite')
+--- /dev/null
++++ jmc-0.3b3/src/jmc/jabber/tests/__init__.py
+@@ -0,0 +1,18 @@
++"""JMC test module"""
++__revision__ = ""
++
++import unittest
++
++from jmc.jabber.tests import component, disco, command, message, presence
++
++def suite():
++ test_suite = unittest.TestSuite()
++ test_suite.addTest(component.suite())
++ test_suite.addTest(disco.suite())
++ test_suite.addTest(command.suite())
++ test_suite.addTest(message.suite())
++ test_suite.addTest(presence.suite())
++ return test_suite
++
++if __name__ == '__main__':
++ unittest.main(defaultTest='suite')
+--- /dev/null
++++ jmc-0.3b3/src/jmc/jabber/tests/message.py
+@@ -0,0 +1,256 @@
++##
++## message.py
++## Login : <dax@happycoders.org>
++## Started on Tue Nov 6 19:00:22 2007 David Rousselie
++## $Id$
++##
++## Copyright (C) 2007 David Rousselie
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++##
++
++import unittest
++import re
++
++from pyxmpp.message import Message
++
++from jcl.tests import JCLTestCase
++from jcl.model.account import Account, User
++
++from jmc.model.account import GlobalSMTPAccount, AbstractSMTPAccount, \
++ SMTPAccount
++from jmc.jabber.message import SendMailMessageHandler, \
++ RootSendMailMessageHandler
++from jmc.lang import Lang
++
++class MockSMTPAccount(object):
++ def __init__(self):
++ self.email_sent = 0
++ self.default_from = "user1@test.com"
++ self.email = None
++
++ def send_email(self, email):
++ self.email = email
++ self.email_sent += 1
++
++ def create_email(self, from_addr, to_addr, subject, body,
++ other_headers=None):
++ return (from_addr, to_addr, subject, body, other_headers)
++
++class SendMailMessageHandler_TestCase(unittest.TestCase):
++ def setUp(self):
++ self.handler = SendMailMessageHandler(None)
++
++ def test_get_email_to_headers_from_message(self):
++ to_regexp = re.compile("^\s*(?i)to\s*:\s*(?P<to_email>.*)")
++ (message, to_header) = self.handler.get_email_headers_from_message(\
++ "To: dest@test.com\ntest body\n", [to_regexp], ["to_email"])
++ self.assertEquals(message, "test body\n")
++ self.assertEquals(to_header, ["dest@test.com"])
++
++ def test_get_email_headers_from_message(self):
++ to_regexp = re.compile("^\s*(?i)to\s*:\s*(?P<to_email>.*)")
++ cc_regexp = re.compile("^\s*(?i)cc\s*:\s*(?P<cc_email>.*)")
++ bcc_regexp = re.compile("^\s*(?i)bcc\s*:\s*(?P<bcc_email>.*)")
++ subject_regexp = re.compile("^\s*(?i)subject\s*:\s*(?P<subject_email>.*)")
++ (message, headers) = self.handler.get_email_headers_from_message(\
++ "To: dest@test.com\nCc: cc@test.com\n"
++ + "Bcc: bcc@test.com\n"
++ + "Subject: test subject\ntest body\n",
++ [to_regexp, cc_regexp, bcc_regexp, subject_regexp],
++ ["to_email", "cc_email", "bcc_email", "subject_email"])
++ self.assertEquals(message, "test body\n")
++ self.assertEquals(headers, ["dest@test.com",
++ "cc@test.com",
++ "bcc@test.com",
++ "test subject"])
++
++ def test_get_email_headers_from_message_unordered(self):
++ to_regexp = re.compile("^\s*(?i)to\s*:\s*(?P<to_email>.*)")
++ cc_regexp = re.compile("^\s*(?i)cc\s*:\s*(?P<cc_email>.*)")
++ bcc_regexp = re.compile("^\s*(?i)bcc\s*:\s*(?P<bcc_email>.*)")
++ subject_regexp = re.compile("^\s*(?i)subject\s*:\s*(?P<subject_email>.*)")
++ (message, headers) = self.handler.get_email_headers_from_message(\
++ "To: dest@test.com\nCc: cc@test.com\n"
++ + "Bcc: bcc@test.com\n"
++ + "Subject: test subject\ntest body\n",
++ [cc_regexp, to_regexp, subject_regexp, bcc_regexp],
++ ["cc_email", "to_email", "subject_email", "bcc_email"])
++ self.assertEquals(message, "test body\n")
++ self.assertEquals(headers, ["cc@test.com",
++ "dest@test.com",
++ "test subject",
++ "bcc@test.com"])
++
++ def test_handle(self):
++ mock_account = MockSMTPAccount()
++ message = Message(from_jid="user1@test.com",
++ to_jid="real_dest%test.com@jmc.test.com",
++ subject="real subject",
++ body="To: dest@test.com\nCc: cc@test.com\n" \
++ + "Bcc: bcc@test.com\n" \
++ + "Subject: test subject\ntest body\n")
++ result = self.handler.handle(\
++ message, Lang.en, [mock_account])
++ self.assertEquals(len(result), 1)
++ self.assertEquals(result[0].stanza_type, "message")
++ self.assertEquals(result[0].get_from(), "real_dest%test.com@jmc.test.com")
++ self.assertEquals(result[0].get_to(), "user1@test.com")
++ self.assertEquals(result[0].get_subject(),
++ Lang.en.send_mail_ok_subject)
++ self.assertEquals(result[0].get_body(),
++ Lang.en.send_mail_ok_body % \
++ ("real_dest@test.com, dest@test.com"))
++ self.assertEquals(mock_account.email_sent, 1)
++ self.assertEquals(mock_account.email[0], "user1@test.com")
++ self.assertEquals(mock_account.email[1], "real_dest@test.com, dest@test.com")
++ self.assertEquals(mock_account.email[2], "real subject")
++ self.assertEquals(mock_account.email[3], "test body\n")
++ self.assertEquals(mock_account.email[4], {u"Bcc": "bcc@test.com",
++ u"Cc": "cc@test.com"})
++
++class RootSendMailMessageHandler_TestCase(JCLTestCase):
++ def setUp(self):
++ JCLTestCase.setUp(self, tables=[Account, GlobalSMTPAccount,
++ AbstractSMTPAccount,
++ SMTPAccount, User])
++ self.handler = RootSendMailMessageHandler(None)
++
++ def test_filter(self):
++ user1 = User(jid="user1@test.com")
++ account11 = SMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jmc.test.com")
++ account11.default_account = True
++ account12 = SMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jmc.test.com")
++ message = Message(from_jid="user1@test.com",
++ to_jid="account11@jmc.test.com",
++ body="message")
++ accounts = self.handler.filter(message, None)
++ self.assertEquals(accounts.count(), 1)
++
++ def test_filter_no_default_account(self):
++ user1 = User(jid="user1@test.com")
++ account11 = SMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jmc.test.com")
++ account12 = SMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jmc.test.com")
++ message = Message(from_jid="user1@test.com",
++ to_jid="account11@jmc.test.com",
++ body="message")
++ accounts = self.handler.filter(message, None)
++ self.assertEquals(accounts.count(), 2)
++ self.assertEquals(accounts[0].name, "account11")
++
++ def test_filter_wrong_dest(self):
++ user1 = User(jid="user1@test.com")
++ account11 = SMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jmc.test.com")
++ account12 = SMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jmc.test.com")
++ message = Message(from_jid="user1@test.com",
++ to_jid="user2%test.com@jmc.test.com",
++ body="message")
++ accounts = self.handler.filter(message, None)
++ self.assertEquals(accounts.count(), 2)
++
++ def test_filter_wrong_user(self):
++ user1 = User(jid="user1@test.com")
++ account11 = SMTPAccount(user=user1,
++ name="account11",
++ jid="account11@jmc.test.com")
++ account12 = SMTPAccount(user=user1,
++ name="account12",
++ jid="account12@jmc.test.com")
++ message = Message(from_jid="user2@test.com",
++ to_jid="account11@jmc.test.com",
++ body="message")
++ accounts = self.handler.filter(message, None)
++ self.assertEquals(accounts.count(), 0)
++
++ def test_handle(self):
++ mock_account = MockSMTPAccount()
++ message = Message(from_jid="user1@test.com",
++ to_jid="jmc.test.com",
++ subject="real subject",
++ body="To: dest@test.com\nCc: cc@test.com\n" \
++ + "Bcc: bcc@test.com\n" \
++ + "Subject: test subject\ntest body\n")
++ result = self.handler.handle(\
++ message, Lang.en, [mock_account])
++ self.assertEquals(len(result), 1)
++ self.assertEquals(result[0].get_type(), None)
++ self.assertEquals(result[0].get_from(), "jmc.test.com")
++ self.assertEquals(result[0].get_to(), "user1@test.com")
++ self.assertEquals(result[0].get_subject(),
++ Lang.en.send_mail_ok_subject)
++ self.assertEquals(result[0].get_body(),
++ Lang.en.send_mail_ok_body % ("dest@test.com"))
++ self.assertEquals(mock_account.email_sent, 1)
++ self.assertEquals(mock_account.email[0], "user1@test.com")
++ self.assertEquals(mock_account.email[1], "dest@test.com")
++ self.assertEquals(mock_account.email[2], "real subject")
++ self.assertEquals(mock_account.email[3], "test body\n")
++ self.assertEquals(mock_account.email[4], {u"Bcc": "bcc@test.com",
++ u"Cc": "cc@test.com"})
++
++ def test_handle_email_not_found_in_header(self):
++ message = Message(from_jid="user1@test.com",
++ to_jid="jmc.test.com",
++ subject="message subject",
++ body="message body")
++ accounts = [MockSMTPAccount()]
++ result = self.handler.handle(message, Lang.en, accounts)
++ self.assertEquals(len(result), 1)
++ self.assertEquals(result[0].get_type(), "error")
++ self.assertEquals(result[0].get_from(), "jmc.test.com")
++ self.assertEquals(result[0].get_to(), "user1@test.com")
++ self.assertEquals(result[0].get_subject(),
++ Lang.en.send_mail_error_no_to_header_subject)
++ self.assertEquals(result[0].get_body(),
++ Lang.en.send_mail_error_no_to_header_body)
++
++ def test_handle_no_jabber_subject(self):
++ mock_account = MockSMTPAccount()
++ message = Message(from_jid="user1@test.com",
++ to_jid="jmc.test.com",
++ subject="",
++ body="To: dest@test.com\nCc: cc@test.com\n" \
++ + "Bcc: bcc@test.com\n" \
++ + "Subject: test subject\ntest body\n")
++ message_to_send = self.handler.handle(\
++ message, Lang.en, [mock_account])
++ self.assertNotEquals(message_to_send, None)
++ self.assertEquals(mock_account.email_sent, 1)
++ self.assertEquals(mock_account.email[0], "user1@test.com")
++ self.assertEquals(mock_account.email[1], "dest@test.com")
++ self.assertEquals(mock_account.email[2], "test subject")
++ self.assertEquals(mock_account.email[3], "test body\n")
++ self.assertEquals(mock_account.email[4], {u"Bcc": "bcc@test.com",
++ u"Cc": "cc@test.com"})
++
++def suite():
++ test_suite = unittest.TestSuite()
++ test_suite.addTest(unittest.makeSuite(SendMailMessageHandler_TestCase, 'test'))
++ test_suite.addTest(unittest.makeSuite(RootSendMailMessageHandler_TestCase, 'test'))
++ return test_suite
++
++if __name__ == '__main__':
++ unittest.main(defaultTest='suite')
+--- /dev/null
++++ jmc-0.3b3/src/jmc/jabber/tests/command.py
+@@ -0,0 +1,595 @@
++# -*- coding: utf-8 -*-
++##
++## command.py
++## Login : David Rousselie <dax@happycoders.org>
++## Started on Tue Oct 23 18:53:28 2007 David Rousselie
++## $Id$
++##
++## Copyright (C) 2007 David Rousselie
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++##
++
++import unittest
++import tempfile
++from ConfigParser import ConfigParser
++import os
++import sys
++import logging
++import time
++
++from pyxmpp.iq import Iq
++from pyxmpp.jabber.dataforms import Field
++import pyxmpp.xmlextra
++
++import jcl.tests
++from jcl.tests import JCLTestCase
++from jcl.jabber.feeder import Feeder
++from jcl.model.account import User, Account, PresenceAccount
++from jcl.jabber.tests.command import JCLCommandManagerTestCase
++import jcl.jabber.command as command
++import jcl.jabber.tests.command
++
++from jmc.model.account import POP3Account, IMAPAccount, SMTPAccount, \
++ MailAccount, GlobalSMTPAccount, AbstractSMTPAccount
++from jmc.jabber.component import MailComponent
++from jmc.lang import Lang
++from jmc.jabber.tests.component import MockIMAPAccount
++from jmc.jabber.command import MailCommandManager
++
++PYXMPP_NS = pyxmpp.xmlextra.COMMON_NS
++
++class MailCommandManagerTestCase(JCLCommandManagerTestCase):
++ def setUp(self, tables=[]):
++ tables += [POP3Account, IMAPAccount, GlobalSMTPAccount,
++ AbstractSMTPAccount, SMTPAccount,
++ MailAccount, MockIMAPAccount, User, Account, PresenceAccount]
++ JCLTestCase.setUp(self, tables=tables)
++ self.config_file = tempfile.mktemp(".conf", "jmctest", jcl.tests.DB_DIR)
++ self.config = ConfigParser()
++ self.config.read(self.config_file)
++ self.comp = MailComponent("jmc.test.com",
++ "password",
++ "localhost",
++ "5347",
++ self.config,
++ self.config_file)
++ self.comp.set_admins(["admin@test.com"])
++ self.command_manager = MailCommandManager(self.comp,
++ self.comp.account_manager)
++ self.comp.account_manager.account_classes = (POP3Account, IMAPAccount,
++ GlobalSMTPAccount,
++ AbstractSMTPAccount,
++ SMTPAccount, MockIMAPAccount)
++ self.user1 = User(jid="test1@test.com")
++ self.account11 = MockIMAPAccount(user=self.user1,
++ name="account11",
++ jid="account11@" + unicode(self.comp.jid))
++ self.account12 = MockIMAPAccount(user=self.user1,
++ name="account12",
++ jid="account12@" + unicode(self.comp.jid))
++ self.user2 = User(jid="test2@test.com")
++ self.account21 = MockIMAPAccount(user=self.user2,
++ name="account21",
++ jid="account21@" + unicode(self.comp.jid))
++ self.account22 = MockIMAPAccount(user=self.user2,
++ name="account11",
++ jid="account11@" + unicode(self.comp.jid))
++ self.user3 = User(jid="test3@test.com")
++ self.account31 = MockIMAPAccount(user=self.user3,
++ name="account31",
++ jid="account31@" + unicode(self.comp.jid))
++ self.account32 = MockIMAPAccount(user=self.user3,
++ name="account32",
++ jid="account32@" + unicode(self.comp.jid))
++ self.info_query = Iq(stanza_type="set",
++ from_jid="admin@test.com",
++ to_jid=self.comp.jid)
++ self.command_node = self.info_query.set_new_content(command.COMMAND_NS,
++ "command")
++ class MockFeederHandler(Feeder):
++ def __init__(self, component):
++ Feeder.__init__(self, component)
++ self.checked_accounts = []
++
++ def feed(self, _account):
++ self.checked_accounts.append(_account)
++ assert((int(time.time()) - _account.lastcheck \
++ >= (_account.interval * self.component.time_unit)))
++ return []
++
++ self.comp.tick_handlers[0].feeder = MockFeederHandler(self.comp)
++
++ def tearDown(self):
++ JCLTestCase.tearDown(self)
++ if os.path.exists(self.config_file):
++ os.unlink(self.config_file)
++
++class MailCommandManagerForceCheckCommand_TestCase(MailCommandManagerTestCase):
++ """
++ Test 'force-check' ad-hoc command
++ """
++
++ def setUp(self, tables=[]):
++ """
++ Prepare data
++ """
++ MailCommandManagerTestCase.setUp(self, tables)
++ self.command_node.setProp("node", "jmc#force-check")
++
++ def test_execute_force_check(self):
++ self.info_query.set_from("test1@test.com")
++ self.info_query.set_to("account11@" + unicode(self.comp.jid))
++ result = self.command_manager.apply_command_action(\
++ self.info_query,
++ "jmc#force-check",
++ "execute")
++ result_iq = result[0].xmlnode
++ result_iq.setNs(None)
++ self.assertTrue(jcl.tests.is_xml_equal(\
++ u"<iq from='account11@" + unicode(self.comp.jid)
++ + "' to='test1@test.com' type='result'>"
++ + "<command xmlns='http://jabber.org/protocol/commands' "
++ + "status='completed'>"
++ + "</command></iq>",
++ result_iq, True, test_sibling=False))
++ feeder = self.comp.tick_handlers[0].feeder
++ self.assertEquals(len(feeder.checked_accounts), 1)
++ self.assertEquals(feeder.checked_accounts[0], self.account11)
++
++ def test_execute_force_check_root_node(self):
++ self.info_query.set_from("test1@test.com")
++ result = self.command_manager.apply_command_action(\
++ self.info_query,
++ "jmc#force-check",
++ "execute")
++ result_iq = result[0].xmlnode
++ result_iq.setNs(None)
++ self.assertTrue(jcl.tests.is_xml_equal(\
++ u"<iq from='jmc.test.com' to='test1@test.com' type='result'>"
++ + "<command xmlns='http://jabber.org/protocol/commands'"
++ + "status='executing'>"
++ + "<actions execute='complete'><complete/></actions>"
++ + "<x xmlns='jabber:x:data' type='form'>"
++ + "<title>" + Lang.en.command_force_check + "</title>"
++ + "<instructions>" + Lang.en.command_force_check_1_description
++ + "</instructions>"
++ + "<field var='account_names' type='list-multi' label='"
++ + Lang.en.field_accounts + "'>"
++ + "<option label=\"account11 (IMAP)\">"
++ + "<value>account11/test1@test.com</value></option>"
++ + "<option label=\"account12 (IMAP)\">"
++ + "<value>account12/test1@test.com</value></option>"
++ + "<option label=\"account11 (MockIMAP)\">"
++ + "<value>account11/test1@test.com</value></option>"
++ + "<option label=\"account12 (MockIMAP)\">"
++ + "<value>account12/test1@test.com</value></option>"
++ + "</field></x></command></iq>",
++ result_iq, True))
++ session_id = result_iq.children.prop("sessionid")
++ self.assertNotEquals(session_id, None)
++ context_session = self.command_manager.sessions[session_id][1]
++ self.assertEquals(context_session["user_jids"],
++ ["test1@test.com"])
++
++ # Second step
++ info_query = jcl.jabber.tests.command.prepare_submit(\
++ node="jmc#force-check",
++ session_id=session_id,
++ from_jid="test1@test.com",
++ to_jid=unicode(self.comp.jid),
++ fields=[Field(field_type="list-multi",
++ name="account_names",
++ values=["account11/test1@test.com",
++ "account12/test1@test.com"])],
++ action="complete")
++ result = self.command_manager.apply_command_action(\
++ info_query,
++ "jmc#force-check",
++ "execute")
++ result_iq = result[0].xmlnode
++ result_iq.setNs(None)
++ self.assertTrue(jcl.tests.is_xml_equal(\
++ u"<iq from='" + unicode(self.comp.jid)
++ + "' to='test1@test.com' type='result'>"
++ + "<command xmlns='http://jabber.org/protocol/commands' "
++ + "status='completed'>"
++ + "</command></iq>",
++ result_iq, True, test_sibling=False))
++ self.assertEquals(context_session["account_names"],
++ ["account11/test1@test.com",
++ "account12/test1@test.com"])
++ feeder = self.comp.tick_handlers[0].feeder
++ self.assertEquals(len(feeder.checked_accounts), 2)
++ self.assertEquals(feeder.checked_accounts[0], self.account11)
++ self.assertEquals(feeder.checked_accounts[1], self.account12)
++
++class MailCommandManagerGetEmailCommand_TestCase(MailCommandManagerTestCase):
++ """
++ Test 'get-email' ad-hoc command
++ """
++
++ def setUp(self, tables=[]):
++ """
++ Prepare data
++ """
++ MailCommandManagerTestCase.setUp(self, tables)
++ self.command_node.setProp("node", "jmc#get-email")
++ def get_email(email_index):
++ """
++ Mock method for IMAPAccount.get_email
++ """
++ return ("mail body " + str(email_index),
++ "from" + str(email_index) + "@test.com")
++ self.account11.__dict__["get_mail"] = get_email
++
++ def check_step_1(self, result, options="<option label=\"mail 1\">" \
++ + "<value>1</value></option>" \
++ + "<option label=\"mail 2\">" \
++ + "<value>2</value></option>" \
++ + "<option label=\"mail 3\">" \
++ + "<value>3</value></option>" \
++ + "<option label=\"mail 4\">" \
++ + "<value>4</value></option>" \
++ + "<option label=\"mail 5\">" \
++ + "<value>5</value></option>" \
++ + "<option label=\"mail 6\">" \
++ + "<value>6</value></option>" \
++ + "<option label=\"mail 7\">" \
++ + "<value>7</value></option>" \
++ + "<option label=\"mail 8\">" \
++ + "<value>8</value></option>" \
++ + "<option label=\"mail 9\">" \
++ + "<value>9</value></option>" \
++ + "<option label=\"mail 10\">" \
++ + "<value>10</value></option>",
++ last_page=False):
++ """
++ Check first step result of get-email ad-hoc command
++ """
++ result_iq = result[0].xmlnode
++ result_iq.setNs(None)
++ xml_ref = u"<iq from='account11@" + unicode(self.comp.jid) \
++ + "' to='test1@test.com' type='result'>" \
++ + "<command xmlns='http://jabber.org/protocol/commands'" \
++ + "status='executing'>" \
++ + "<actions execute='complete'><complete/></actions>" \
++ + "<x xmlns='jabber:x:data' type='form'>" \
++ + "<title>" + Lang.en.command_get_email + "</title>" \
++ + "<instructions>" + Lang.en.command_get_email_1_description \
++ + "</instructions>" \
++ + "<field var='emails' type='list-multi' label='" \
++ + Lang.en.field_email_subject + "'>" \
++ + options
++ if not last_page:
++ xml_ref += "</field><field var='fetch_more' type='boolean' label='" \
++ + Lang.en.field_select_more_emails + "'>"
++ xml_ref += "</field></x></command></iq>"
++ self.assertTrue(jcl.tests.is_xml_equal(xml_ref, result_iq, True))
++ session_id = result_iq.children.prop("sessionid")
++ self.assertNotEquals(session_id, None)
++ self.assertTrue(self.account11.has_connected)
++ self.assertFalse(self.account11.connected)
++ self.account11.has_connected = False
++ return session_id
++
++ def check_email_message(self, result_iq, index):
++ """ """
++ self.assertTrue(jcl.tests.is_xml_equal(\
++ u"<message from='account11@" + unicode(self.comp.jid)
++ + "' to='test1@test.com' "
++ + "xmlns='" + PYXMPP_NS + "'>"
++ + "<subject>" + Lang.en.mail_subject \
++ % ("from" + str(index) + "@test.com")
++ + "</subject>"
++ + "<body>mail body " + str(index) + "</body>"
++ + "<addresses xmlns='http://jabber.org/protocol/address'>"
++ + "<address type='replyto' jid='from" + str(index)
++ + "%test.com@jmc.test.com'/>"
++ + "</addresses>"
++ + "</message>",
++ result_iq, True, test_sibling=False))
++
++ def test_execute_get_email(self):
++ """
++ Test single email retrieval
++ """
++ self.info_query.set_from("test1@test.com")
++ self.info_query.set_to("account11@" + unicode(self.comp.jid))
++ result = self.command_manager.apply_command_action(\
++ self.info_query,
++ "jmc#get-email",
++ "execute")
++ session_id = self.check_step_1(result)
++
++ # Second step
++ info_query = jcl.jabber.tests.command.prepare_submit(\
++ node="jmc#get-email",
++ session_id=session_id,
++ from_jid="test1@test.com",
++ to_jid="account11@jmc.test.com",
++ fields=[Field(field_type="list-multi",
++ name="emails",
++ values=["1"]),
++ Field(field_type="boolean",
++ name="fetch_more",
++ value=False)],
++ action="complete")
++ result = self.command_manager.apply_command_action(\
++ info_query,
++ "jmc#get-email",
++ "execute")
++ self.assertTrue(self.account11.has_connected)
++ self.assertFalse(self.account11.connected)
++ self.assertEquals(len(result), 2)
++ result_iq = result[0].xmlnode
++ result_iq.setNs(None)
++ self.assertTrue(jcl.tests.is_xml_equal(\
++ u"<iq from='account11@" + unicode(self.comp.jid)
++ + "' to='test1@test.com' type='result'>"
++ + "<command xmlns='http://jabber.org/protocol/commands' "
++ + "status='completed'>"
++ + "<x xmlns='jabber:x:data' type='form'>"
++ + "<title>" + Lang.en.command_get_email + "</title>"
++ + "<instructions>" + Lang.en.command_get_email_2_description
++ % (1) + "</instructions>"
++ + "</x></command></iq>",
++ result_iq, True, test_sibling=False))
++ result_iq = result[1].xmlnode
++ self.check_email_message(result_iq, 1)
++
++ def test_execute_get_emails(self):
++ """
++ Test multiple emails retrieval
++ """
++ self.info_query.set_from("test1@test.com")
++ self.info_query.set_to("account11@" + unicode(self.comp.jid))
++ result = self.command_manager.apply_command_action(\
++ self.info_query,
++ "jmc#get-email",
++ "execute")
++ session_id = self.check_step_1(result)
++
++ # Second step
++ info_query = jcl.jabber.tests.command.prepare_submit(\
++ node="jmc#get-email",
++ session_id=session_id,
++ from_jid="test1@test.com",
++ to_jid="account11@jmc.test.com",
++ fields=[Field(field_type="list-multi",
++ name="emails",
++ values=["1", "2"]),
++ Field(field_type="boolean",
++ name="fetch_more",
++ value=False)],
++ action="complete")
++ result = self.command_manager.apply_command_action(\
++ info_query,
++ "jmc#get-email",
++ "execute")
++ self.assertTrue(self.account11.has_connected)
++ self.assertFalse(self.account11.connected)
++ self.assertEquals(len(result), 3)
++ result_iq = result[0].xmlnode
++ result_iq.setNs(None)
++ self.assertTrue(jcl.tests.is_xml_equal(\
++ u"<iq from='account11@" + unicode(self.comp.jid)
++ + "' to='test1@test.com' type='result'>"
++ + "<command xmlns='http://jabber.org/protocol/commands' "
++ + "status='completed'>"
++ + "<x xmlns='jabber:x:data' type='form'>"
++ + "<title>" + Lang.en.command_get_email + "</title>"
++ + "<instructions>" + Lang.en.command_get_email_2_description
++ % (2) + "</instructions>"
++ + "</x></command></iq>",
++ result_iq, True, test_sibling=False))
++ result_iq = result[1].xmlnode
++ self.check_email_message(result_iq, 1)
++ result_iq = result[2].xmlnode
++ self.check_email_message(result_iq, 2)
++
++ def test_execute_get_emails_multi_pages(self):
++ """
++ Test multiple emails retrieval
++ """
++ self.info_query.set_from("test1@test.com")
++ self.info_query.set_to("account11@" + unicode(self.comp.jid))
++ result = self.command_manager.apply_command_action(\
++ self.info_query,
++ "jmc#get-email",
++ "execute")
++ session_id = self.check_step_1(result)
++
++ # Second step
++ info_query = jcl.jabber.tests.command.prepare_submit(\
++ node="jmc#get-email",
++ session_id=session_id,
++ from_jid="test1@test.com",
++ to_jid="account11@jmc.test.com",
++ fields=[Field(field_type="list-multi",
++ name="emails",
++ values=["1", "2"]),
++ Field(field_type="boolean",
++ name="fetch_more",
++ value=True)],
++ action="complete")
++ result = self.command_manager.apply_command_action(\
++ info_query,
++ "jmc#get-email",
++ "execute")
++ self.check_step_1(result, options="<option label=\"mail 11\">" \
++ + "<value>11</value></option>" \
++ + "<option label=\"mail 12\">" \
++ + "<value>12</value></option>" \
++ + "<option label=\"mail 13\">" \
++ + "<value>13</value></option>" \
++ + "<option label=\"mail 14\">" \
++ + "<value>14</value></option>" \
++ + "<option label=\"mail 15\">" \
++ + "<value>15</value></option>" \
++ + "<option label=\"mail 16\">" \
++ + "<value>16</value></option>" \
++ + "<option label=\"mail 17\">" \
++ + "<value>17</value></option>" \
++ + "<option label=\"mail 18\">" \
++ + "<value>18</value></option>" \
++ + "<option label=\"mail 19\">" \
++ + "<value>19</value></option>" \
++ + "<option label=\"mail 20\">" \
++ + "<value>20</value></option>")
++
++ # Third step
++ info_query = jcl.jabber.tests.command.prepare_submit(\
++ node="jmc#get-email",
++ session_id=session_id,
++ from_jid="test1@test.com",
++ to_jid="account11@jmc.test.com",
++ fields=[Field(field_type="list-multi",
++ name="emails",
++ values=["13", "14"]),
++ Field(field_type="boolean",
++ name="fetch_more",
++ value=False)],
++ action="complete")
++ result = self.command_manager.apply_command_action(\
++ info_query,
++ "jmc#get-email",
++ "execute")
++ self.assertTrue(self.account11.has_connected)
++ self.assertFalse(self.account11.connected)
++ self.assertEquals(len(result), 5)
++ result_iq = result[0].xmlnode
++ result_iq.setNs(None)
++ self.assertTrue(jcl.tests.is_xml_equal(\
++ u"<iq from='account11@" + unicode(self.comp.jid)
++ + "' to='test1@test.com' type='result'>"
++ + "<command xmlns='http://jabber.org/protocol/commands' "
++ + "status='completed'>"
++ + "<x xmlns='jabber:x:data' type='form'>"
++ + "<title>" + Lang.en.command_get_email + "</title>"
++ + "<instructions>" + Lang.en.command_get_email_2_description
++ % (4) + "</instructions>"
++ + "</x></command></iq>",
++ result_iq, True, test_sibling=False))
++ result_iq = result[1].xmlnode
++ self.check_email_message(result_iq, 1)
++ result_iq = result[2].xmlnode
++ self.check_email_message(result_iq, 2)
++ result_iq = result[3].xmlnode
++ self.check_email_message(result_iq, 13)
++ result_iq = result[4].xmlnode
++ self.check_email_message(result_iq, 14)
++
++ def test_execute_get_emails_last_page(self):
++ """
++ Test that field fetch_more does not exist if number of emails < 10
++ """
++ class MockIMAPAccount2(MockIMAPAccount):
++ """ """
++ def get_mail_list_summary(self, start_index=1, end_index=20):
++ return [("1", "mail 1"),
++ ("2", "mail 2")]
++
++ get_email_func = self.account11.get_mail
++ MockIMAPAccount2.createTable(ifNotExists=True)
++ self.account11.destroySelf()
++ self.account11 = MockIMAPAccount2(user=self.user1,
++ name="account11",
++ jid="account11@" + unicode(self.comp.jid))
++ self.account11.__dict__["get_mail"] = get_email_func
++ self.info_query.set_from("test1@test.com")
++ self.info_query.set_to("account11@" + unicode(self.comp.jid))
++ result = self.command_manager.apply_command_action(\
++ self.info_query,
++ "jmc#get-email",
++ "execute")
++ session_id = self.check_step_1(result, options="<option label=\"mail 1\">" \
++ + "<value>1</value></option>" \
++ + "<option label=\"mail 2\">" \
++ + "<value>2</value></option>",
++ last_page=True)
++ self.assertTrue("fetch_more" in
++ self.command_manager.sessions[session_id][1])
++ self.assertEquals(\
++ self.command_manager.sessions[session_id][1]["fetch_more"][-1],
++ "0")
++
++ # Second step
++ info_query = jcl.jabber.tests.command.prepare_submit(\
++ node="jmc#get-email",
++ session_id=session_id,
++ from_jid="test1@test.com",
++ to_jid="account11@jmc.test.com",
++ fields=[Field(field_type="list-multi",
++ name="emails",
++ values=["1"])],
++ action="complete")
++ result = self.command_manager.apply_command_action(\
++ info_query,
++ "jmc#get-email",
++ "execute")
++ self.assertTrue(self.account11.has_connected)
++ self.assertFalse(self.account11.connected)
++ self.assertEquals(len(result), 2)
++ result_iq = result[0].xmlnode
++ result_iq.setNs(None)
++ self.assertTrue(jcl.tests.is_xml_equal(\
++ u"<iq from='account11@" + unicode(self.comp.jid)
++ + "' to='test1@test.com' type='result'>"
++ + "<command xmlns='http://jabber.org/protocol/commands' "
++ + "status='completed'>"
++ + "<x xmlns='jabber:x:data' type='form'>"
++ + "<title>" + Lang.en.command_get_email + "</title>"
++ + "<instructions>" + Lang.en.command_get_email_2_description
++ % (1) + "</instructions>"
++ + "</x></command></iq>",
++ result_iq, True, test_sibling=False))
++ result_iq = result[1].xmlnode
++ self.check_email_message(result_iq, 1)
++ MockIMAPAccount2.dropTable(ifExists=True)
++
++ def test_execute_get_email_error(self):
++ """
++ Test single email retrieval
++ """
++ self.info_query.set_from("test1@test.com")
++ self.info_query.set_to("unknown@" + unicode(self.comp.jid))
++ result = self.command_manager.apply_command_action(\
++ self.info_query,
++ "jmc#get-email",
++ "execute")
++ result_iq = result[0].xmlnode
++ self.assertTrue(jcl.tests.is_xml_equal(\
++ u"<iq from='unknown@" + unicode(self.comp.jid)
++ + "' to='test1@test.com' type='error' "
++ + "xmlns='" + PYXMPP_NS + "'>"
++ + "<command xmlns='http://jabber.org/protocol/commands' "
++ + "node='jmc#get-email' />"
++ + "<error type='cancel'>"
++ + "<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' />"
++ + "</error></iq>",
++ result_iq, True))
++
++def suite():
++ test_suite = unittest.TestSuite()
++ test_suite.addTest(unittest.makeSuite(MailCommandManagerForceCheckCommand_TestCase, 'test'))
++ test_suite.addTest(unittest.makeSuite(MailCommandManagerGetEmailCommand_TestCase, 'test'))
++ return test_suite
++
++if __name__ == '__main__':
++ if '-v' in sys.argv:
++ logger = logging.getLogger()
++ logger.addHandler(logging.StreamHandler())
++ logger.setLevel(logging.INFO)
++ unittest.main(defaultTest='suite')
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..b7098f6
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1 @@
+debian-changes-0.3b3
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/setup.py b/setup.py
index e7eedd3..735f33f 100644
--- a/setup.py
+++ b/setup.py
@@ -46,7 +46,7 @@ config_dir = root + "/" + prefix_config_dir
full_prefix = root + "/" + prefix
setup(name='jmc',
- version='0.3b2',
+ version='0.3b3',
description='Jabber Mail Component',
long_description="""\
JMC is a jabber service to check email from POP3 and IMAP4 server and retrieve
diff --git a/src/jmc.egg-info/PKG-INFO b/src/jmc.egg-info/PKG-INFO
index ae173ed..b3823a3 100644
--- a/src/jmc.egg-info/PKG-INFO
+++ b/src/jmc.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: jmc
-Version: 0.3b2
+Version: 0.3b3
Summary: Jabber Mail Component
Home-page: http://people.happycoders.org/dax/projects/jmc
Author: David Rousselie