return [document for document in self.dialog_rules, self.pidf_manipulation, self.pres_rules, self.resource_lists, self.rls_services, self.status_icon, self.server_caps if document.cached]
if wp_prs_blockedcontacts.actions not in [common_policy.Actions([presrules.SubHandling('block')]), common_policy.Actions([presrules.SubHandling('polite-block')])]:
wp_prs_unlisted = [child for child in pres_rules if isinstance(child, common_policy.Rule) and child.id in ('wp_prs_unlisted', 'wp_prs_allow_unlisted')]
if wp_prs_unlisted.id == 'wp_prs_unlisted' and wp_prs_unlisted.actions not in [common_policy.Actions([presrules.SubHandling('confirm')]), common_policy.Actions([presrules.SubHandling('block')]), common_policy.Actions([presrules.SubHandling('polite-block')])]:
if wp_prs_block_anonymous.actions not in [common_policy.Actions([presrules.SubHandling('block')]), common_policy.Actions([presrules.SubHandling('polite-block')])]:
# Make sure the action is one of confirm, block or polite-block
if rule.actions not in [common_policy.Actions([presrules.SubHandling('confirm')]), common_policy.Actions([presrules.SubHandling('block')]), common_policy.Actions([presrules.SubHandling('polite-block')])]:
rule.actions = [presrules.SubHandling('confirm')]
# Make sure there are no transformations
if rule.transformations:
rule.transformations = None
self.resource_lists.dirty = True
self.pres_rules.dirty = True
for rule in (child for child in pres_rules if isinstance(child, common_policy.Rule) and child.id.startswith('wp_prs_onelist_')):
if rule.actions not in [common_policy.Actions([presrules.SubHandling('confirm')]), common_policy.Actions([presrules.SubHandling('block')]), common_policy.Actions([presrules.SubHandling('polite-block')])]:
rule.actions = [presrules.SubHandling('confirm')]
self.pres_rules.dirty = True
if rule.transformations:
rule.transformations = None
self.pres_rules.dirty = True
# Normalize dialog-rules document:
# * create one if it doesn't exist
# * create a rule of each of the four possible actions except 'confirm'
(child for child in dialog_rules if isinstance(child, common_policy.Rule) and any(isinstance(a, dialogrules.SubHandling) and a.value==action for a in (child.actions or []))).next()
except StopIteration:
name = self.unique_name('dialog_%s' % action, (rule.id for rule in dialog_rules)).next()
oma_buddylist = (child for child in resource_lists if isinstance(child, resourcelists.List) and child.name=='oma_buddylist').next()
except StopIteration:
# This should never happen as the document is normalized
return
if operation.contact.presence_policies is None:
operation.contact.presence_policies = []
elif self.oma_compliant:
# Filter out policies we mustn't add contacts to
operation.contact.presence_policies = [policy for policy in operation.contact.presence_policies if policy.id not in ('wp_prs_unlisted', 'wp_prs_allow_unlisted', 'wp_prs_block_anonymous', 'wp_prs_allow_own')]
if operation.contact.dialoginfo_policies is None:
operation.contact.dialoginfo_policies = []
# First see if this contact (uniquely identified by uri) is already a buddy; if it is, don't do anything
notexpanded = deque([oma_buddylist])
visited = set(notexpanded)
while notexpanded:
rlist = notexpanded.popleft()
for child in rlist:
if isinstance(child, resourcelists.List) and child not in visited:
visited.add(child)
notexpanded.append(child)
elif isinstance(child, resourcelists.External):
try:
ref_lists = set(l for l in self._follow_rl_external(resource_lists, child) if l not in visited)
if any(entry.uri == operation.contact.uri for entry in entries):
return
elif isinstance(child, resourcelists.Entry):
if child.uri == operation.contact.uri:
return
# Then find all the lists where we can add this new contact
if operation.contact.group is not None:
# Only add contacts to lists directly referenced from oma_buddylist by an external element.
candidate_lists = []
for child in oma_buddylist:
if isinstance(child, resourcelists.External):
try:
ref_lists = set(l for l in self._follow_rl_external(resource_lists, child))
except ValueError:
ref_lists = set()
if child.display_name is not None:
if child.display_name.value == operation.contact.group:
candidate_lists.extend(ref_lists)
else:
continue
else:
candidate_lists.extend(l for l in ref_lists if l.display_name is not None and l.display_name.value == operation.contact.group)
else:
# Add contacts which are not buddies to top-level lists which are not referenced by oma_buddylist
candidate_lists = [l for l in resource_lists if l not in visited]
# Add a fallback candidate which should never, ever be referenced from anywhere
fallback_candidate = resourcelists.List(name=self.unique_name('group', (l.name for l in resource_lists), skip_preferred_name=True).next(), display_name=operation.contact.group)
candidate_lists.append(fallback_candidate)
# We may need the XPath to this list
resource_lists.append(fallback_candidate)
presence_lists = set() # Lists to which, if added, the rls services document need not be modified for presence subscription
dialoginfo_lists = set() # Lists to which, if added, the rls services document need not be modified for dialoginfo subscription
presrules_lists = set() # Lists to which, if added, the presrules document need not be modified
not_wanted_lists = set() # Lists we don't want to add the contact to because they are referenced from other places
remove_from_lists = set() # Lists we need to remove the contact from
to_remove = [] # (child, parent)
# Filter candidates based on subscribe_to_* flags
if self.rls_services.supported:
# While filtering candidates, also remove any reference to the uri from unwanted services
rls_services = self.rls_services.content
for service in rls_services:
packages = set(package.value for package in (service.packages or []))
# This is one of the rules we want to add the contact to
if rule.conditions is None:
rule.conditions = common_policy.Conditions()
for condition in rule.conditions:
if isinstance(condition, common_policy.Identity):
if not condition.matches(operation.contact.uri):
# First see if there is an exception added for this uri
for identity_condition in condition:
if isinstance(identity_condition, common_policy.IdentityMany):
try:
except_condition = (child for child in identity_condition if isinstance(child, common_policy.IdentityExcept) and child.id==operation.contact.uri).next()
external_lists = [condition for condition in rule.conditions if isinstance(condition, omapolicy.ExternalList)]
if external_lists or len(rlist) > 0 or rule.id in ('wp_prs_grantedcontacts', 'wp_prs_blockedcontacts'):
# We cannot modify the references of wp_prs_grantedcontacts and wp_prs_blockedcontacts
for external_list in external_lists:
try:
container_list = (l for l in self._follow_policy_external_list(resource_lists, external_list) if l not in not_wanted_lists).next()
except (ValueError, StopIteration):
continue
else:
break
else:
if rule.id in ('wp_prs_grantedcontacts', 'wp_prs_blockedcontacts'):
# The user wants to add this contact to one of these rules, but the lists referenced by them are not
# good because they are referenced from other places; create a new rule, similar to this one
container_list = resourcelists.List(name=self.unique_name('presrules_group', (list.name for list in resource_lists), skip_preferred_name=True).next())
resource_lists.append(container_list)
new_policy = deepcopy(policy)
new_policy.id = self.unique_name(('wp_prs_allow_onelist_' if new_policy.action=='allow' else 'wp_prs_onelist_')+container_list.name, (rule.id for rule in pres_rules)).next()
op = AddPresencePolicyOperation(policy=new_policy)
taken_names = [m.group(1) for m in (uri_re.match(service.uri) for service in rls_services) if m]
uri = 'sip:%s@%s' % (self.unique_name('buddies', taken_names, skip_preferred_name=True).next(), self.account.id.domain)
# We'll also make it a dialog service just so that it can also be used as a container for dialog
service = rlsservices.Service(uri=uri, list=rlsservices.ResourceList(path), packages=['presence', 'dialog'] if add_to_dialoginfo_list and rlist not in dialoginfo_lists else ['presence'])
rls_services.append(service)
container_lists.append(service_list)
add_to_dialoginfo_list = False
if add_to_dialoginfo_list:
try:
container_lists.append((l for l in dialoginfo_lists if l not in not_wanted_lists).next())
except StopIteration:
# Too bad, we have to create a new service
service_list = resourcelists.List(name=self.unique_name('subscribe_group', (list.name for list in resource_lists), skip_preferred_name=True).next())
taken_names = [m.group(1) for m in (uri_re.match(service.uri) for service in rls_services) if m]
uri = 'sip:%s@%s' % (self.unique_name('buddies', taken_names, skip_preferred_name=True).next(), self.account.id.domain)
# We'll also make it a presence service just so that it can also be used as a container for presence
service = rlsservices.Service(uri=uri, list=rlsservices.ResourceList(path), packages=['presence', 'dialog'] if operation.contact.subscribe_to_presence and rlist not in presence_lists else ['dialog'])
rls_services.append(service)
container_lists = [service_list] # Don't use the previously determined presence service
entry.attributes = extensions.EntryAttributes((key, value) for key, value in operation.contact.attributes.iteritems() if value is not None)
rlist.append(entry)
self.resource_lists.dirty = True
def _OH_update_contact(self, operation):
if not self.resource_lists.supported:
return
resource_lists = self.resource_lists.content
try:
oma_buddylist = (child for child in resource_lists if isinstance(child, resourcelists.List) and child.name=='oma_buddylist').next()
except StopIteration:
# This should never happen as the document is normalized
return
if not set(['uri', 'group', 'presence_policies', 'dialoginfo_policies', 'subscribe_to_presence', 'subscribe_to_dialoginfo']).intersection(operation.attributes):
# If none of these attributes are specified, then we only need to look at the resource-lists document
# and since we prefer keeping the name and additional attributes in the buddies entry, start with oma_buddylist
# and do a DFS.
notexpanded = deque([oma_buddylist]+[l for l in resource_lists if l is not oma_buddylist])
visited = set(notexpanded)
entries = []
while notexpanded:
rlist = notexpanded.popleft()
for child in rlist:
if isinstance(child, resourcelists.List) and child not in visited:
visited.add(child)
notexpanded.appendleft(child)
elif isinstance(child, resourcelists.External):
try:
ref_lists = set(l for l in self._follow_rl_external(resource_lists, child) if l not in visited)
elif contact.presence_policies is not Null and self.oma_compliant:
# Filter out policies we mustn't add contacts to
contact.presence_policies = set(policy for policy in contact.presence_policies if policy.id not in ('wp_prs_unlisted', 'wp_prs_allow_unlisted', 'wp_prs_block_anonymous', 'wp_prs_allow_own'))
if not self.pres_rules.supported or operation.policy.id in ('wp_prs_unlisted', 'wp_prs_allow_unlisted', 'wp_prs_grantedcontacts', 'wp_prs_blockedcontacts', 'wp_prs_block_anonymous', 'wp_prs_allow_own'):
return
if operation.policy.id is not None and (operation.policy.id.startswith('wp_prs_allow_one_') or operation.policy.id.startswith('wp_prs_one_')):
return
if operation.policy.action is None:
return
pres_rules = self.pres_rules.content
if operation.policy.id is None and self.oma_compliant and not operation.policy.multi_identity_conditions:
operation.policy.id = self.unique_name('wp_prs_allow_onelist_presrules_group' if operation.policy.action=='allow' else 'wp_prs_onelist_presrules_group', (rule.id for rule in pres_rules), skip_preferred_name=True).next()
elif operation.policy.id is None:
operation.policy.id = self.unique_name('rule', (rule.id for rule in pres_rules), skip_preferred_name=True).next()
elif operation.policy.id in pres_rules:
return
elif (operation.policy.id.startswith('wp_prs_allow_onelist_') or operation.policy.id.startswith('wp_prs_onelist_')) and operation.policy.multi_identity_conditions:
operation.policy.id = self.unique_name('rule', (rule.id for rule in pres_rules), skip_preferred_name=True).next()
if not self.pres_rules.supported or operation.policy.id in ('wp_prs_unlisted', 'wp_prs_allow_unlisted', 'wp_prs_grantedcontacts', 'wp_prs_blockedcontacts', 'wp_prs_block_anonymous', 'wp_prs_allow_own'):
return
pres_rules = self.pres_rules.content
if operation.policy.id is None or operation.policy.id not in pres_rules:
elif not (provide_all_attributes is Null and any(isinstance(transformation, presrules.ProvideAllAttributes) for transformation in rule.transformations)):
if provide_all_attributes is False:
for transformation in [t for t in rule.transformations if isinstance(t, presrules.ProvideAllAttributes)]:
if not self.pres_rules.supported or operation.policy.id in (None, 'wp_prs_unlisted', 'wp_prs_allow_unlisted', 'wp_prs_grantedcontacts', 'wp_prs_blockedcontacts', 'wp_prs_block_anonymous', 'wp_prs_allow_own'):
return
pres_rules = self.pres_rules.content
try:
del pres_rules[operation.policy.id]
except KeyError:
return
self.pres_rules.dirty = True
def _OH_add_dialoginfo_policy(self, operation):
if not self.dialog_rules.supported:
return
dialog_rules = self.dialog_rules.content
if operation.policy.id is None:
operation.policy.id = self.unique_name('rule', (rule.id for rule in dialog_rules), skip_preferred_name=True).next()
notexpanded = deque((l, l.display_name.value if l.display_name else None) for l in presence_lists|dialoginfo_lists|set(list_presence_policies)|buddy_lists)
visited = set(notexpanded)
while notexpanded:
rlist, list_name = notexpanded.popleft()
if rlist in buddy_lists and list_name is not None:
groups.add(list_name)
# Some children will need to be revisited so that their descendents are added to appropriate sets
for child in rlist:
if isinstance(child, resourcelists.List):
revisit = False
if rlist in presence_lists:
revisit = (child not in presence_lists) or revisit
presence_lists.add(child)
if rlist in dialoginfo_lists:
revisit = (child not in dialoginfo_lists) or revisit
dialoginfo_lists.add(child)
if rlist in list_presence_policies:
revisit = (child not in list_presence_policies) or not list_presence_policies[child].issuperset(list_presence_policies[rlist]) or revisit
contact.presence_policies = set(policy for policy, identity in presence_policies.iteritems() if identity is not None and identity.matches(contact.uri))
contact.dialoginfo_policies = set(policy for policy, identity in dialoginfo_policies.iteritems() if identity is not None and identity.matches(contact.uri))
contact.subscribe_to_presence = False
contact.subscribe_to_dialoginfo = False
if contact.group is None and rlist in buddy_lists and list_name is not None:
contact.group = list_name
if contact.name is None and rlist in buddy_lists and child.display_name:
contact.name = child.display_name.value
elif contact.name is None and rlist in buddy_lists and entry.display_name:
contact.presence_policies = set(policy for policy, identity in presence_policies.iteritems() if identity is not None and identity.matches(contact.uri))
contact.dialoginfo_policies = set(policy for policy, identity in dialoginfo_policies.iteritems() if identity is not None and identity.matches(contact.uri))
contact.subscribe_to_presence = False
contact.subscribe_to_dialoginfo = False
if contact.group is None and rlist in buddy_lists and list_name is not None:
contact.group = list_name
if contact.name is None and rlist in buddy_lists and child.display_name: