diff options
author | David Rousselie <david.rousselie@happycoders.org> | 2010-06-04 21:59:40 +0400 |
---|---|---|
committer | David Rousselie <david.rousselie@happycoders.org> | 2010-06-04 21:59:40 +0400 |
commit | 6cba8014502d61d22b297dad36ad6b9ea440bfed (patch) | |
tree | 19c241bc37ab3673d9766a4954e9045f4a93461c | |
parent | 74feff9ea9711a7725dd4909fc7a755c95e05311 (diff) |
release JMC 0.3 beta3
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rwxr-xr-x | coverage.py | 952 | ||||
-rw-r--r-- | debian/changelog | 6 | ||||
-rw-r--r-- | debian/control | 2 | ||||
-rw-r--r-- | debian/patches/debian-changes-0.3b3 | 5745 | ||||
-rw-r--r-- | debian/patches/series | 1 | ||||
-rw-r--r-- | debian/source/format | 1 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | src/jmc.egg-info/PKG-INFO | 2 |
10 files changed, 5761 insertions, 959 deletions
@@ -2,3 +2,4 @@ *flymake.py .ropeproject *.pyc +dist @@ -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) @@ -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 |