Projects
Kolab:16
pykolab-python3
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 4
View file
buildtarball.sh
Added
@@ -0,0 +1,22 @@ +#!/bin/bash + +set -e + +VERSION=0.9.0 +GIT_REF=master +NAME=pykolab-$VERSION + +ROOT_DIR=$(pwd) + +rm -Rf /tmp/$NAME +mkdir /tmp/$NAME +cd /tmp/$NAME + +rm -f $NAME.tar.gz + -d "$NAME" && rm -rf "$NAME" + +git clone --branch master ssh://git@git.kolab.org/diffusion/P/pykolab.git $NAME +pushd $NAME +git archive --prefix=$NAME/ -o $ROOT_DIR/$NAME.tar.gz $GIT_REF + +cd "$PWD"
View file
debian.changelog
Changed
@@ -1,6 +1,6 @@ -pykolab (0.9.0-0~kolab1) unstable; urgency=low +pykolab (0.9.0-0~kolab2) unstable; urgency=low - * Release of version 0.8.0 + * Release of version 0.9.0 -- Christian Mollekopf <mollekopf@apheleia-it.ch> Tue, 16 Aug 2022 01:49:00 +0100
View file
pykolab-0.9.0.tar.gz/conf/kolab.conf
Changed
@@ -240,8 +240,7 @@ ; The base DN, scope and filter to use when searching for additional domain ; name spaces in this environment. -domain_base_dn = ou=Domains,%(base_dn)s - +domain_base_dn = cn=kolab,cn=config domain_filter = (&(associatedDomain=*)) domain_name_attribute = associateddomain ; Attribute that holds the root dn for the domain name space. If this attribute
View file
pykolab-0.9.0.tar.gz/cyruslib.py
Changed
@@ -48,6 +48,8 @@ 'ID' : ('AUTH',), # Only one ID allowed in non auth mode 'GETANNOTATION': ('AUTH',), 'SETANNOTATION': ('AUTH',), + 'GETMETADATA': ('AUTH',), + 'SETMETADATA': ('AUTH',), 'XFER' : ('AUTH',) } @@ -87,6 +89,26 @@ elif not isinstance(s, (six.text_type, six.binary_type)): raise TypeError("not expecting type '%s'" % type(s)) return s +def ensure_binary(s, encoding='utf-8', errors='strict'): + """Coerce **s** to six.binary_type. + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + For Python 3: + - `str` -> encoded to `bytes` + - `bytes` -> `bytes` + + Copied from six (not available < 1.12), and extended with list support. + """ + if isinstance(s, list): + + #FIXME pass encoding + return list(map(ensure_binary, s)) + if isinstance(s, six.binary_type): + return s + if isinstance(s, six.text_type): + return s.encode(encoding, errors) + raise TypeError("not expecting type '%s'" % type(s)) def ok(res): return res.upper().startswith('OK') @@ -104,6 +126,63 @@ if len(flag): flags.append(flag) return flags + +def parseToken(data, offset): + i = offset + while i < len(data): + c = datai:i+1 + if c == b' ': + return dataoffset:i, i + 1 + if c == b')': + return dataoffset:i, i + 1 + i += 1 + + +# TODO handle escape sequences? +# TODO handle literal continuations +def parseLiteral(data, offset): + i = offset + while i < len(data): + c = datai:i+1 + if c == b'"': + return dataoffset:i, i + 1 + i += 1 + + +def parse(data, offset): + result = + i = offset + while i < len(data): + c = datai:i + 1 + # print(c) + if c == b'(': + res, newOffset = parse(data, i + 1) + result.append(res) + i = newOffset + continue + if c == b')': + return result, i + 1 + if c == b'"': + res, newOffset = parseLiteral(data, i + 1) + # print("Found literal", res, newOffset) + result.append(res) + i = newOffset + continue + if c != b' ': + res, newOffset = parseToken(data, i) + # print("Found token", res, newOffset) + result.append(res) + i = newOffset + continue + i += 1 + return result, i + + +def tokenize(data): + result, _ = parse(data, 0) + return result + + ### A smart function to return an array of split strings ### and honours quoted strings def splitquote(text): @@ -172,7 +251,7 @@ return ok(res), dat0 def getannotation(self, mailbox, pattern='*', shared=None): - if shared == None: + if shared is None: typ, dat = self._simple_command('GETANNOTATION', mailbox, quote(pattern), quote('*')) elif shared: typ, dat = self._simple_command('GETANNOTATION', mailbox, quote(pattern), quote('value.shared')) @@ -193,6 +272,22 @@ return self._untagged_response(typ, dat, 'ANNOTATION') + + def setmetadata(self, mailbox, desc, value, shared=False): + if value: + value = value.join('"', '"') + else: + value = "NIL" + + if shared: + typ, dat = self._simple_command('SETMETADATA', mailbox, + "(/shared%s %s)" % (desc,value)) + else: + typ, dat = self._simple_command('SETMETADATA', mailbox, + "(/private%s %s)" % (desc,value)) + + return self._untagged_response(typ, dat, 'METADATA') + def setquota(self, mailbox, limit): """Set quota of a mailbox""" if limit == 0: @@ -260,7 +355,7 @@ return ok(res), dat0 def getannotation(self, mailbox, pattern='*', shared=None): - if shared == None: + if shared is None: typ, dat = self._simple_command('GETANNOTATION', mailbox, quote(pattern), quote('*')) elif shared: typ, dat = self._simple_command('GETANNOTATION', mailbox, quote(pattern), quote('value.shared')) @@ -281,6 +376,41 @@ return self._untagged_response(typ, dat, 'ANNOTATION') + def getmetadata(self, mailbox, pattern='*', shared=None): + # If pattern is '*' clean pattern and search all entries under /shared + # and/or /private (depens on the shared parameter value) to emulate the + # ANNOTATEMORE behaviour + if pattern == '*': + pattern = '' + options = '(DEPTH infinity)' + else: + options = '(DEPTH 0)' + if shared == None: + entries = '(/shared%s /private%s)' % (pattern, pattern) + elif shared: + entries = "/shared%s" % pattern + else: + entries = "/private%s" % pattern + + typ, dat = self._simple_command('GETMETADATA', mailbox, options, entries) + + return self._untagged_response(typ, dat, 'METADATA') + + def setmetadata(self, mailbox, desc, value, shared=False): + if value: + value = value.join('"', '"') + else: + value = "NIL" + + if shared: + typ, dat = self._simple_command('SETMETADATA', mailbox, + "(/shared%s %s)" % (desc,value)) + else: + typ, dat = self._simple_command('SETMETADATA', mailbox, + "(/private%s %s)" % (desc,value)) + + return self._untagged_response(typ, dat, 'METADATA') + def setquota(self, mailbox, limit): """Set quota of a mailbox""" if limit == 0: @@ -541,7 +671,7 @@ elif self.ENCODING in self.ENCODING_LIST: return self.__decode(text) - def lm(self, pattern="*"): + def lm(self, pattern=b"*"): """ List mailboxes, returns dict with list of mailboxes @@ -555,8 +685,8 @@ """ self.__prepare('LIST') - if pattern == '': pattern = "*" - if pattern == '%': + if pattern == b'': pattern = b"*" + if pattern == b'%':
View file
pykolab-0.9.0.tar.gz/pykolab/auth/ldap/syncrepl.py
Changed
@@ -2,7 +2,7 @@ try: import anydbm -except: +except ImportError: import dbm.ndbm as anydbm import ldap import ldap.syncrepl @@ -11,11 +11,13 @@ import pykolab from pykolab import utils +from pykolab.translate import _ log = pykolab.getLogger('pykolab.syncrepl') conf = pykolab.getConf() -class DNSync(ldap.ldapobject.LDAPObject,ldap.syncrepl.SyncreplConsumer): + +class DNSync(ldap.ldapobject.LDAPObject, ldap.syncrepl.SyncreplConsumer): callback = None @@ -28,7 +30,7 @@ self.__db = anydbm.open(filename, 'c', 0o640) self.__presentUUIDs = {} - def syncrepl_set_cookie(self,cookie): + def syncrepl_set_cookie(self, cookie): self.__db'cookie' = cookie def syncrepl_get_cookie(self): @@ -36,12 +38,12 @@ return self.__db'cookie' def syncrepl_delete(self, uuids): - log.debug("syncrepl_delete uuids: %r" % (uuids), level=8) + log.debug("syncrepl_delete uuids: %r" % uuids, level=8) # Get the unique_attribute name to issue along with our # callback (if any) unique_attr = conf.get('ldap', 'unique_attribute') - if unique_attr == None: + if unique_attr is None: unique_attr = 'entryuuid' if unique_attr == 'nsuniqueid': @@ -50,14 +52,13 @@ "is very probably not compatible with the use of " + \ "syncrepl.") ) - for uuid in uuids: dn = self.__dbuuid - log.debug("syncrepl_delete dn: %r" % (dn), level=8) + log.debug("syncrepl_delete dn: %r" % dn, level=8) - if not self.callback == None: + if self.callback is not None: self.callback( change_type='delete', previous_dn=None, @@ -90,7 +91,7 @@ if uuid in self.__db: odn = self.__dbuuid if odn != dn: - if not self.callback == None: + if self.callback is not None: self.callback( change_type='moddn', previous_dn=odn, @@ -100,7 +101,7 @@ ) else: - if not self.callback == None: + if self.callback is not None: self.callback( change_type='modify', previous_dn=None, @@ -110,7 +111,7 @@ ) else: - if not self.callback == None: + if self.callback is not None: self.callback( change_type='add', previous_dn=None,
View file
pykolab-0.9.0.tar.gz/pykolab/cli/cmd_sync.py
Changed
@@ -74,20 +74,20 @@ auth = Auth() if conf.domain == "all": - log.debug(_("Listing domains..."), level=5) - start_time = time.time() - domains = auth.list_domains() - end_time = time.time() - log.debug( + log.debug(_("Listing domains..."), level=5) + start_time = time.time() + domains = auth.list_domains() + end_time = time.time() + log.debug( _("Found %d domains in %d seconds") % ( - len(domains), - (end_time-start_time) - ), + len(domains), + (end_time-start_time) + ), level=8 ) else: - domains = {} - domainsconf.domain = conf.domain + domains = {} + domainsconf.domain = conf.domain if version.StrictVersion(sys.version:3) >= version.StrictVersion("2.7"): pool = multiprocessing.Pool(conf.threads, worker_process, (), 1) @@ -125,14 +125,13 @@ entry = utils.normalize(kw) mailbox_attribute = conf.get('cyrus-sasl', 'result_attribute') - if mailbox_attribute == None: + if mailbox_attribute is None: mailbox_attribute = 'mail' - if mailbox_attribute not in entry: return - if not 'kolabinetorgperson' in entry'objectclass': + if 'kolabinetorgperson' not in entry'objectclass': return imap = IMAP()
View file
pykolab-0.9.0.tar.gz/pykolab/imap/__init__.py
Changed
@@ -271,6 +271,7 @@ log.error( _("Could not create folder %r on server %r: %r") % (folder_path, server, excpt) ) + return self.has_folder(folder_path) else: try: @@ -278,7 +279,7 @@ return True except Exception as excpt: log.error(_("Could not create folder %r: %r") % (folder_path, excpt)) - return False + return self.has_folder(folder_path) def __getattr__(self, name): if hasattr(self.imap, name): @@ -310,7 +311,7 @@ """ metadata = {} - _metadata = self.imap.getannotation(self.folder_utf7(folder), '*') + _metadata = self.imap.getmetadata(self.folder_utf7(folder), '*') for (k, v) in _metadata.items(): metadataself.folder_utf8(k) = v @@ -467,7 +468,7 @@ shared = False metadata_path = metadata_path.replace('/private/', '/') - self.imap._setannotation(self.folder_utf7(folder), metadata_path, metadata_value, shared) + self.imap._setmetadata(self.folder_utf7(folder), metadata_path, metadata_value, shared) def shared_folder_create(self, folder_path, server=None): """
View file
pykolab-0.9.0.tar.gz/pykolab/imap/cyrus.py
Changed
@@ -30,6 +30,7 @@ import pykolab +from pykolab import utils from pykolab import constants from pykolab.imap import IMAP from pykolab.translate import _ @@ -208,7 +209,6 @@ _mailfolder'domain') ) - # TODO: Murder capabilities may have been suppressed using Cyrus IMAP # configuration. if not self.murder: @@ -246,7 +246,7 @@ while 1: num_try += 1 - annotations = self._getannotation( + annotations = self._getmetadata( '"%s"' % (mailfolder), ann_path ) @@ -363,12 +363,12 @@ partition ) - def _getannotation(self, *args, **kw): - return self.getannotation(*args, **kw) + def _getmetadata(self, *args, **kw): + return self.getmetadata(*args, **kw) - def _setannotation(self, mailfolder, annotation, value, shared=False): + def _setmetadata(self, mailfolder, metadata, value, shared=False): """ - Login to the actual backend server, then set annotation. + Login to the actual backend server, then set metadata. """ try: server = self.find_mailfolder_server(mailfolder) @@ -376,24 +376,32 @@ server = self.server log.debug( - _("Setting annotation %s on folder %s") % ( - annotation, + _("Setting metadata %s on folder %s") % ( + metadata, mailfolder ), level=8 ) try: - self.setannotation(mailfolder, annotation, value, shared) + self.setmetadata(mailfolder, metadata, value, shared) except cyruslib.CYRUSError as errmsg: log.error( - _("Could not set annotation %r on mail folder %r: %r") % ( - annotation, + _("Could not set metadata %r on mail folder %r: %r") % ( + metadata, mailfolder, errmsg ) ) + # Use metadata instead of annotations + def _getannotation(self, *args, **kw): + return self._getmetadata(*args, **kw) + + # Use metadata instead of annotations + def _setannotation(self, *args, **kw): + return self._setmetadata(*args, **kw) + def _xfer(self, mailfolder, current_server, new_server): self.connect(self.uri.replace(self.server, current_server)) log.debug( @@ -567,13 +575,7 @@ mbox'domain' ) - if ' ' in verify_folder_search: - folders = self.lm( - '"%s"' % self.folder_utf7(verify_folder_search) - ) - - else: - folders = self.lm(self.folder_utf7(verify_folder_search)) + folders = self.lm(utils.ensure_str(self.folder_utf7(verify_folder_search))) # NOTE: Case also covered is valid hexadecimal folders; won't be # the actual check as intended, but doesn't give you anyone else's
View file
pykolab-0.9.0.tar.gz/pykolab/imap/dovecot.py
Changed
@@ -57,128 +57,6 @@ log = pykolab.getLogger('pykolab.imap') conf = pykolab.getConf() -# BEG: Add GETMETADATA and SETMETADATA support to the cyruslib IMAP objects - -Commands = { - 'GETMETADATA': ('AUTH',), - 'SETMETADATA': ('AUTH',), -} - -imaplib.Commands.update(Commands) - -def imap_getmetadata(self, mailbox, pattern='*', shared=None): - # If pattern is '*' clean pattern and search all entries under /shared - # and/or /private (depens on the shared parameter value) to emulate the - # ANNOTATEMORE behaviour - if pattern == '*': - pattern = '' - options = '(DEPTH infinity)' - else: - options = '(DEPTH 0)' - if shared == None: - entries = '( /shared%s /private%s )' % (pattern, pattern) - elif shared: - entries = "/shared%s" % pattern - else: - entries = " /private%s" % pattern - - typ, dat = self._simple_command('GETMETADATA', options, mailbox, entries) - - return self._untagged_response(typ, dat, 'METADATA') - -def imap_setmetadata(self, mailbox, desc, value, shared=False): - if value: - value = value.join('"', '"') - else: - value = "NIL" - - if shared: - typ, dat = self._simple_command('SETMETADATA', mailbox, - "(/shared%s %s)" % (desc,value)) - else: - typ, dat = self._simple_command('SETMETADATA', mailbox, - "(/private%s %s)" % (desc,value)) - - return self._untagged_response(typ, dat, 'METADATA') - -# Bind the new methods to the cyruslib IMAP4 and IMAP4_SSL objects -from types import MethodType -cyruslib.IMAP4.getmetadata = MethodType(imap_getmetadata, None, cyruslib.IMAP4) -cyruslib.IMAP4.setmetadata = MethodType(imap_setmetadata, None, cyruslib.IMAP4) -cyruslib.IMAP4_SSL.getmetadata = MethodType(imap_getmetadata, None, cyruslib.IMAP4_SSL) -cyruslib.IMAP4_SSL.setmetadata = MethodType(imap_setmetadata, None, cyruslib.IMAP4_SSL) - -# END: Add GETMETADATA and SETMETADATA support to the cyruslib IMAP objects - -# Auxiliary functions -def _get_line_entries(lines): - """Function to get metadata entries """ - entries = {} - name = None - value = "" - vlen = 0 - for line in lines: - line_len = len(line) - i = 0 - while i < line_len: - if name == None: - if linei == '/': - j = i - while j < line_len: - if linej == ' ': - break - j += 1 - name = linei:j - i = j - elif vlen != 0: - j = i + vlen - if j > line_len: - value += linei:line_len - vlen -= line_len - i - else: - value += linei:i+vlen - if value in ('', 'NIL'): - entriesname = "" - else: - entriesname = value - name = None - value = "" - vlen = 0 - elif linei == '{': - j = i - while j < line_len: - if linej == '}': - vlen = int(linei+1:j) - break - j += 1 - i = j - elif linei != ' ': - j = i - if linei == '"': - while j < line_len: - # Skip quoted text - if linej == '\\': - j += 2 - continue - elif linej == '"': - break - j += 1 - else: - while j < line_len: - if linej == ' ' or linej == ')': - break - j += 1 - value = linei:j - if value in ('', 'NIL'): - entriesname = "" - else: - entriesname = value - name = None - value = "" - i = j - i += 1 - return entries - class Dovecot(cyruslib.CYRUS): """ Abstraction class for some common actions to do exclusively in @@ -330,126 +208,15 @@ self.m.rename(self.folder_utf7(from_mailfolder), self.folder_utf7(to_mailfolder), '"%s"' % (partition)) -# BEG: METADATA support functions ... quite similar to annotations, really - - def _getmetadata(self, mailbox, pattern='*', shared=None): - """Get Metadata""" - # This test needs to be reviewed - #if not self.metadata: - # return {} - - # Annotations vs. Metadata fix ... we set a pattern that we know is - # good enough for our purposes for now, but the fact is that the - # calling programs should be fixed instead. - - res, data = self.m.getmetadata(self.decode(mailbox), pattern, shared) - - if (len(data) == 1) and data0 is None: - self.__verbose( 'GETMETADATA %s No results' % (mailbox) ) - return {} - - # Get the first response line (it can be a string or a tuple) - if isinstance(data0, tuple): - fline = data00 - else: - fline = data0 - - # Find the folder name - fbeg = 0 - fend = -1 - if fline0 == '"': - # Quoted name - fbeg = 1 - i = 1 - while i < len(fline): - if flinei == '"': - # folder name ended unless the previous char is \ (we - # should test more, this test would fail if we had a \ - # at the end of the folder name, but we leave it at that - # right now - if flinei-1 != '\\': - fend = i - break - i += 1 - else: - # For unquoted names the first word is the folder name - fend = fline.find(' ') - - # No mailbox found - if fend < 0: - self.__verbose( 'GETMETADATA %s Mailbox not found in results' % (mailbox) ) - return {} - - # Folder name - folder = flinefbeg:fend - - # Check mailbox name against the folder name - if folder != mailbox: - quoted_mailbox = "\"%s\"" % (mailbox) - if folder != quoted_mailbox: - self.__verbose( - 'GETMETADATA %s Mailbox \'%s\' is not the same as \'%s\'' \ - % (mailbox, quoted_mailbox, folder) - ) - return {} - - # Process the rest of the first line, the first value will be - # available after the first '(' found - i=fend - ebeg = -1
View file
pykolab-0.9.0.tar.gz/pykolab/imap_utf7.py
Changed
@@ -112,8 +112,10 @@ elif b64_buffer: b64_buffer.append(c) # No buffer initialized yet, should be an ASCII printable char - else: + elif isinstance(c, int): res.append(chr(c)) + else: + res.append(c) # Decode the remaining buffer if any if b64_buffer:
View file
pykolab-0.9.0.tar.gz/pykolab/logger.py
Changed
@@ -73,8 +73,8 @@ # Required for python3 compat because logger adapter now has a native debug function. - def debug(self, msg, level=1, *args, **kw): - return self.logger.debug(msg, level, args, kw) + def debug(self, msg, *args, **kw): + return self.logger.debug(msg, args, kw) class Logger(logging.Logger): @@ -264,14 +264,13 @@ self.console_stdout.close() self.removeHandler(self.console_stdout) - # pylint: disable=arguments-differ - # pylint: disable=keyword-arg-before-vararg - def debug(self, msg, level=1, *args, **kw): + def debug(self, msg, *args, **kw): self.setLevel(self.loglevel) # Work around other applications not using various levels of debugging if not self.name.startswith('pykolab') and self.debuglevel != 9: return + level = kw.get('level', 1) if level <= self.debuglevel: self.log(logging.DEBUG, msg)
View file
pykolab-0.9.0.tar.gz/pykolab/setup/setup_ldap.py
Changed
@@ -447,11 +447,11 @@ ), file=sys.stderr) fp = open('/var/log/kolab/setup.error.log', 'w') - fp.write(stderrdata) + fp.write(utils.ensure_str(stderrdata, 'latin-1')) fp.close() fp = open('/var/log/kolab/setup.out.log', 'w') - fp.write(stdoutdata) + fp.write(utils.ensure_str(stdoutdata, 'latin-1')) fp.close() log.debug(_("Setup DS stdout:"), level=8) @@ -543,11 +543,11 @@ ), file=sys.stderr) fp = open('/var/log/kolab/setup.error.log', 'w') - fp.write(stderrdata) + fp.write(utils.ensure_str(stderrdata, 'latin-1')) fp.close() fp = open('/var/log/kolab/setup.out.log', 'w') - fp.write(stdoutdata) + fp.write(utils.ensure_str(stdoutdata, 'latin-1')) fp.close() log.debug(_("Setup DS stdout:"), level=8)
View file
pykolab-0.9.0.tar.gz/pykolab/wap_client/__init__.py
Changed
@@ -1,15 +1,18 @@ import json +import sys try: import httplib except ImportError: import http.client as httplib -import urllib -import sys try: from urlparse import urlparse except ImportError: from urllib.parse import urlparse +try: + from urllib import urlencode +except ImportError: + from urllib.parse import urlencode import pykolab @@ -447,7 +450,7 @@ conn.set_debuglevel(9) if get is not None: - _get = "?%s" % (urllib.urlencode(get)) + _get = "?%s" % (urlencode(get)) else: _get = ""
View file
pykolab-0.9.0.tar.gz/wallace/__init__.py
Changed
@@ -57,7 +57,12 @@ if 'module' in kwargs: # Cause the previous modules to be skipped - wallace_modules = wallace_modules(wallace_modules.index(kwargs'module') + 1): + # Note that the actual stage in which the message exists may not be a module that + # is loaded, thereby causing an exception of ValueError + try: + wallace_modules = wallace_modules(wallace_modules.index(kwargs'module') + 1): + except ValueError: + return log.debug(_l("Wallace modules: %r") % (wallace_modules), level=8)
View file
pykolab.dsc
Changed
@@ -2,7 +2,7 @@ Source: pykolab Binary: pykolab, kolab-cli, kolab-conf, kolab-saslauthd, kolab-server, kolab-telemetry, kolab-xml, wallace Architecture: all -Version: 0.9.0-0~kolab1 +Version: 0.9.0-0~kolab2 Maintainer: Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> Uploaders: Paul Klos <kolab@klos2day.nl> Homepage: http://www.kolab.org
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.