[CalendarServer-changes] [9191] CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Thu Apr 26 16:49:56 PDT 2012
Revision: 9191
http://trac.macosforge.org/projects/calendarserver/changeset/9191
Author: gaya at apple.com
Date: 2012-04-26 16:49:56 -0700 (Thu, 26 Apr 2012)
Log Message:
-----------
fix parameter filters. fix <rdar://11312078>
Modified Paths:
--------------
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/opendirectorybacker.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/xmldirectorybacker.py
CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/query/addressbookqueryfilter.py
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/opendirectorybacker.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/opendirectorybacker.py 2012-04-26 23:48:55 UTC (rev 9190)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/opendirectorybacker.py 2012-04-26 23:49:56 UTC (rev 9191)
@@ -48,6 +48,7 @@
from twistedcaldav.config import config
from twistedcaldav.directory.directory import DirectoryService
from twistedcaldav.query import addressbookqueryfilter
+from twistedcaldav.query.addressbookqueryfilter import TextMatch
from twistedcaldav.vcard import Component, Property, vCardProductID
from xmlrpclib import datetime
@@ -625,8 +626,8 @@
addedExpressions=False means no records
addedExpressions=[expressionlist] add to expression list
"""
- #def explen(exp): return len(exp) if isinstance(exp, list) else 0
- # log.debug("propFilterListQuery(): allOf=%s, expressionList=%s (%s), addedExpressions=%s (%s)" % (allOf, expressionList, explen(expressionList), addedExpressions, explen(addedExpressions)))
+ #def explen(exp): return len(exp) if isinstance(exp, list) else 0
+ #log.debug("propFilterListQuery(): allOf=%s, expressionList=%s (%s), addedExpressions=%s (%s)" % (allOf, expressionList, explen(expressionList), addedExpressions, explen(addedExpressions)))
if expressionList is None:
expressionList = addedExpressions
elif addedExpressions is not None:
@@ -688,61 +689,39 @@
#end andOrExpression()
- # short circuit parameter filters
- def supportedParamter( filterName, paramFilters, propFilterAllOf ):
+ def paramFilterElementExpression(propFilterAllOf, paramFilterElement):
+
+ # This is a map of possible params
+ paramFilterMap = {
+ "PHOTO": { "ENCODING": ("B",), "TYPE": ("JPEG",), },
+ "ADR": { "TYPE": ("WORK", "PREF", "POSTAL", "PARCEL",), },
+ "LABEL": { "TYPE": ("POSTAL", "PARCEL",)},
+ "TEL": { "TYPE": None, }, # None mean param can contain can be anything
+ "EMAIL": { "TYPE": None, },
+ "KEY": { "ENCODING": ("B",), "TYPE": ("PGPPUBILICKEY", "USERCERTIFICATE", "USERPKCS12DATA", "USERSMIMECERTIFICATE",) },
+ "PHOTO": { "ENCODING": ("B",), "TYPE": ("JPEG",), },
+ "URL": { "TYPE": ("WEBLOG", "HOMEPAGE",) },
+ "IMPP": { "TYPE": ("PREF",), "X-SERVICE-TYPE": None, },
+ "X-ABRELATEDNAMES" : { "TYPE":None, },
+ "X-AIM": { "TYPE": ("PREF",), },
+ "X-JABBER": { "TYPE": ("PREF",), },
+ "X-MSN": { "TYPE": ("PREF",), },
+ "X-ICQ": { "TYPE": ("PREF",), },
+ }
+ params = paramFilterMap.get(propFilter.filter_name.upper())
- def supported( paramFilterName, paramFilterDefined, params ):
- paramFilterName = paramFilterName.upper()
- if len(params.keys()) and ((paramFilterName in params.keys()) != paramFilterDefined):
+ if bool(params) != paramFilterElement.defined:
+ return False
+
+ if params:
+ paramValues = params.get(paramFilterElement.filter_name.upper())
+ if paramValues and paramFilterElement.filters[0].text.upper() not in paramValues:
return False
- if len(params[paramFilterName]) and str(paramFilter.qualifier).upper() not in params[paramFilterName]:
- return False
- return True
- #end supported()
-
- oneSupported = False
- for paramFilter in paramFilters:
- if filterName == "PHOTO":
- if propFilterAllOf != supported( paramFilter.filter_name, paramFilter.defined, { "ENCODING": ["B",], "TYPE": ["JPEG",], }):
- return not propFilterAllOf
- oneSupported |= propFilterAllOf
- elif filterName == "ADR":
- if propFilterAllOf != supported( paramFilter.filter_name, paramFilter.defined, { "TYPE": ["WORK", "PREF", "POSTAL", "PARCEL",], }):
- return not propFilterAllOf
- oneSupported |= propFilterAllOf
- elif filterName == "LABEL":
- if propFilterAllOf != supported( paramFilter.filter_name, paramFilter.defined, { "TYPE": ["POSTAL", "PARCEL",]}):
- return not propFilterAllOf
- oneSupported |= propFilterAllOf
- elif filterName == "TEL":
- if propFilterAllOf != supported( paramFilter.filter_name, paramFilter.defined, { "TYPE": [], }): # has params derived from ds attributes
- return not propFilterAllOf
- oneSupported |= propFilterAllOf
- elif filterName == "EMAIL":
- if propFilterAllOf != supported( paramFilter.filter_name, paramFilter.defined, { "TYPE": [], }): # has params derived from ds attributes
- return not propFilterAllOf
- oneSupported |= propFilterAllOf
- elif filterName == "URL":
- if propFilterAllOf != supported( paramFilter.filter_name, paramFilter.defined, {}):
- return not propFilterAllOf
- oneSupported |= propFilterAllOf
- elif filterName == "KEY":
- if propFilterAllOf != supported( paramFilter.filter_name, paramFilter.defined, { "ENCODING": ["B",], "TYPE": ["PGPPUBILICKEY", "USERCERTIFICATE", "USERPKCS12DATA", "USERSMIMECERTIFICATE",] }):
- return not propFilterAllOf
- oneSupported |= propFilterAllOf
- elif not filterName.startswith("X-"): #X- IMHandles X-ABRELATEDNAMES excepted, no other params are used
- if propFilterAllOf == paramFilter.defined:
- return not propFilterAllOf
- oneSupported |= propFilterAllOf
-
- if propFilterAllOf:
- return True
- else:
- return oneSupported
- #end supportedParamter()
-
-
+ #perhaps this should return None if not in paramFilterMap
+ return True
+
+
def textMatchElementExpression( propFilterAllOf, textMatchElement ):
# pre process text match strings for ds query
@@ -854,37 +833,37 @@
# return None to try to match all items if this is the only property filter
return None
- if propFilter.qualifier and isinstance(propFilter.qualifier, addressbookqueryfilter.IsNotDefined):
- return definedExpression(False, filterAllOf)
-
paramFilterElements = [paramFilterElement for paramFilterElement in propFilter.filters if isinstance(paramFilterElement, addressbookqueryfilter.ParameterFilter)]
textMatchElements = [textMatchElement for textMatchElement in propFilter.filters if isinstance(textMatchElement, addressbookqueryfilter.TextMatch)]
+ #create a textMatchElement for the IsNotDefined qualifier
+ if isinstance(propFilter.qualifier, addressbookqueryfilter.IsNotDefined):
+ textMatchElement = TextMatch(carddavxml.TextMatch.fromString(""))
+ textMatchElement.negate = True
+ textMatchElements += [textMatchElement,]
+
# if only one propFilter, then use filterAllOf as propFilterAllOf to reduce subexpressions and simplify generated query string
- if len(propFilter.filters) == 1:
+ if len(paramFilterElements)+len(textMatchElements) == 1:
propFilterAllOf = filterAllOf
else:
propFilterAllOf = propFilter.propfilter_test == "allof"
-
- # handle parameter filter elements
- if len(paramFilterElements) > 0:
- if supportedParamter(propFilter.filter_name, paramFilterElements, propFilterAllOf ):
- if len(textMatchElements) == 0:
- return definedExpression(True, filterAllOf)
- else:
- if propFilterAllOf:
- return False
-
- # handle text match elements
+
propFilterExpressions = None
- for textMatchElement in textMatchElements:
+ for paramFilterElement in paramFilterElements:
+ paramFilterExpressions = paramFilterElementExpression(propFilterAllOf, paramFilterElement)
+ propFilterExpressions = combineExpressionLists(propFilterExpressions, propFilterAllOf, paramFilterExpressions)
+ if isinstance(propFilterExpressions, bool) and propFilterAllOf != propFilterExpression:
+ break
+ for textMatchElement in textMatchElements:
textMatchExpressions = textMatchElementExpression(propFilterAllOf, textMatchElement)
propFilterExpressions = combineExpressionLists(propFilterExpressions, propFilterAllOf, textMatchExpressions)
+ if isinstance(propFilterExpressions, bool) and propFilterAllOf != propFilterExpression:
+ break
if isinstance(propFilterExpressions, list):
propFilterExpressions= list(set(propFilterExpressions))
- if (len(propFilterExpressions) > 1) and (filterAllOf != propFilterAllOf):
+ if propFilterExpressions and (filterAllOf != propFilterAllOf):
propFilterExpressions = [dsquery.expression(dsquery.expression.AND if propFilterAllOf else dsquery.expression.OR , propFilterExpressions)]
return propFilterExpressions
@@ -898,15 +877,16 @@
@param propFilters: the C{list} of L{ComponentFilter} elements.
@return: (filterProperyNames, expressions) tuple. expression==True means list all results, expression==False means no results
"""
- properties = []
expressions = None
for propFilter in propFilters:
- properties += [propFilter.filter_name,]
-
propExpressions = propFilterExpression(filterAllOf, propFilter)
expressions = combineExpressionLists(expressions, filterAllOf, propExpressions)
+ # early loop exit
+ if isinstance(expressions, bool) and filterAllOf != expressions:
+ break
+
# convert to needsAllRecords to return
if isinstance(expressions, list):
expressions = list(set(expressions))
@@ -921,6 +901,8 @@
else:
# True or False
expr = expressions
+
+ properties = [propFilter.filter_name for propFilter in propFilters]
return (list(set(properties)), expr)
@@ -1569,10 +1551,10 @@
# Usually found in user records (kDSStdRecordTypeUsers).
# Example: http://example.com/blog/jsmith
for url in self.valuesForAttribute(dsattributes.kDS1AttrWeblogURI):
- addPropertyAndLabel(groupCount, "weblog", "URL", url, parameters = {"TYPE": ["Weblog",]})
+ addPropertyAndLabel(groupCount, "weblog", "URL", url, parameters = {"TYPE": ["WEBLOG",]})
for url in self.valuesForAttribute(dsattributes.kDSNAttrURL):
- addPropertyAndLabel(groupCount, "_$!<HomePage>!$_", "URL", url, parameters = {"TYPE": ["Homepage",]})
+ addPropertyAndLabel(groupCount, "_$!<HomePage>!$_", "URL", url, parameters = {"TYPE": ["HOMEPAGE",]})
# 3.6.9 VERSION Type Definition
@@ -1663,7 +1645,7 @@
managerValue = "%s %s" % (splitManager[0], splitManager[1])
else:
managerValue = manager
- addPropertyAndLabel( groupCount, "_$!<Manager>!$_", "X-ABRELATEDNAMES", managerValue, parameters={ "TYPE": ["Manager",]} )
+ addPropertyAndLabel( groupCount, "_$!<Manager>!$_", "X-ABRELATEDNAMES", managerValue, parameters={ "TYPE": ["MANAGER",]} )
# add apple-defined group vcard properties if record type is group
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/xmldirectorybacker.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/xmldirectorybacker.py 2012-04-26 23:48:55 UTC (rev 9190)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/xmldirectorybacker.py 2012-04-26 23:49:56 UTC (rev 9191)
@@ -288,8 +288,8 @@
traceback.print_exc()
self.log_info("Could not get vcard for %s" % (xmlDirectoryRecord,))
else:
+ self.log_debug("doAddressBookQuery: VCard text =\n%s" % (result.vCard(),))
if addressBookFilter.match(result.vCard()):
- self.log_debug("doAddressBookQuery: VCard text =\n%s" % (result.vCard(),))
results.append(result)
else:
# should also filter for duplicate UIDs
Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/query/addressbookqueryfilter.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/query/addressbookqueryfilter.py 2012-04-26 23:48:55 UTC (rev 9190)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/query/addressbookqueryfilter.py 2012-04-26 23:49:56 UTC (rev 9191)
@@ -73,7 +73,7 @@
return not allof
return allof
else:
- return True
+ return not allof
def valid(self):
"""
@@ -120,9 +120,6 @@
else:
raise ValueError("Unknown child element: %s" % (qname,))
- if qualifier and isinstance(qualifier, IsNotDefined) and (len(filters) != 0):
- raise ValueError("No other tests allowed when CardDAV:is-not-defined is present")
-
if xml_element.qname() == (carddav_namespace, "prop-filter"):
propfilter_test = xml_element.attributes.get("test", "anyof")
if propfilter_test not in ("anyof", "allof"):
@@ -130,13 +127,16 @@
else:
propfilter_test = "anyof"
+ if qualifier and isinstance(qualifier, IsNotDefined) and (len(filters) != 0) and propfilter_test == "allof":
+ raise ValueError("When test is allof, no other tests allowed when CardDAV:is-not-defined is present")
+
self.propfilter_test = propfilter_test
self.qualifier = qualifier
self.filters = filters
self.filter_name = xml_element.attributes["name"]
if isinstance(self.filter_name, unicode):
self.filter_name = self.filter_name.encode("utf-8")
- self.defined = not self.qualifier or not isinstance(qualifier, IsNotDefined)
+ self.defined = not self.qualifier or not isinstance(qualifier, IsNotDefined) or len(filters)
def match(self, item):
"""
@@ -144,20 +144,17 @@
matches this filter, False otherwise.
"""
- # Always return True for the is-not-defined case as the result of this will
- # be negated by the caller
- if not self.defined: return True
+ allof = self.propfilter_test == "allof"
+ if self.qualifier and allof != self.qualifier.match(item):
+ return not allof
- if self.qualifier and not self.qualifier.match(item): return False
-
if len(self.filters) > 0:
- allof = self.propfilter_test == "allof"
for filter in self.filters:
if allof != filter._match(item):
return not allof
return allof
else:
- return True
+ return not allof
class PropertyFilter (FilterChildBase):
"""
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120426/e2458bd3/attachment-0001.html>
More information about the calendarserver-changes
mailing list