| Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding:utf-8 -*- 2 ## src/common/contacts.py 3 ## 4 ## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com> 5 ## Travis Shirk <travis AT pobox.com> 6 ## Nikos Kouremenos <kourem AT gmail.com> 7 ## Copyright (C) 2006-2010 Yann Leboulanger <asterix AT lagaule.org> 8 ## Jean-Marie Traissard <jim AT lapin.org> 9 ## Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net> 10 ## Tomasz Melcer <liori AT exroot.org> 11 ## Julien Pivotto <roidelapluie AT gmail.com> 12 ## Copyright (C) 2007-2008 Stephan Erb <steve-e AT h3c.de> 13 ## Copyright (C) 2008 Brendan Taylor <whateley AT gmail.com> 14 ## Jonathan Schleifer <js-gajim AT webkeks.org> 15 ## 16 ## This file is part of Gajim. 17 ## 18 ## Gajim is free software; you can redistribute it and/or modify 19 ## it under the terms of the GNU General Public License as published 20 ## by the Free Software Foundation; version 3 only. 21 ## 22 ## Gajim is distributed in the hope that it will be useful, 23 ## but WITHOUT ANY WARRANTY; without even the implied warranty of 24 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 ## GNU General Public License for more details. 26 ## 27 ## You should have received a copy of the GNU General Public License 28 ## along with Gajim. If not, see <http://www.gnu.org/licenses/>. 29 ## 30 31 32 from common import caps_cache 33 from common.account import Account 34 import common.gajim 35 454793 9448 - def __init__(self, jid, account, resource, show, status, name, 49 our_chatstate, composing_xep, chatstate, client_caps=None):50 51 XMPPEntity.__init__(self, jid, account, resource) 52 53 self.show = show 54 self.status = status 55 self.name = name 56 57 self.client_caps = client_caps or caps_cache.NullClientCaps() 58 59 # please read xep-85 http://www.xmpp.org/extensions/xep-0085.html 60 # we keep track of xep85 support with the peer by three extra states: 61 # None, False and 'ask' 62 # None if no info about peer 63 # False if peer does not support xep85 64 # 'ask' if we sent the first 'active' chatstate and are waiting for reply 65 # this holds what WE SEND to contact (our current chatstate) 66 self.our_chatstate = our_chatstate 67 # tell which XEP we're using for composing state 68 # None = have to ask, XEP-0022 = use this xep, 69 # XEP-0085 = use this xep, False = no composing support 70 self.composing_xep = composing_xep 71 # this is contact's chatstate 72 self.chatstate = chatstate73 76 7981 """ 82 Return True if the contact has advertised to support the feature 83 identified by the given namespace. False otherwise. 84 """ 85 if self.show == 'offline': 86 # Unfortunately, if all resources are offline, the contact 87 # includes the last resource that was online. Check for its 88 # show, so we can be sure it's existant. Otherwise, we still 89 # return caps for a contact that has no resources left. 90 return False 91 else: 92 return caps_cache.client_supports(self.client_caps, requested_feature)96 """ 97 Information concerning a contact 98 """179 18099 - def __init__(self, jid, account, name='', groups=[], show='', status='', 100 sub='', ask='', resource='', priority=0, keyID='', client_caps=None, 101 our_chatstate=None, chatstate=None, last_status_time=None, msg_id= 102 None, composing_xep=None, last_activity_time=None):103 104 CommonContact.__init__(self, jid, account, resource, show, status, name, 105 our_chatstate, composing_xep, chatstate, client_caps=client_caps) 106 107 self.contact_name = '' # nick choosen by contact 108 self.groups = [i for i in set(groups)] # filter duplicate values 109 110 self.sub = sub 111 self.ask = ask 112 113 self.priority = priority 114 self.keyID = keyID 115 self.msg_id = msg_id 116 self.last_status_time = last_status_time 117 self.last_activity_time = last_activity_time 118 119 self.pep = {}120 125127 if self.name: 128 return self.name 129 if self.contact_name: 130 return self.contact_name 131 return self.jid.split('@')[0]132134 if self.is_observer(): 135 return [_('Observers')] 136 elif self.is_groupchat(): 137 return [_('Groupchats')] 138 elif self.is_transport(): 139 return [_('Transports')] 140 elif not self.groups: 141 return [_('General')] 142 else: 143 return self.groups144 161163 # XEP-0162: http://www.xmpp.org/extensions/xep-0162.html 164 is_observer = False 165 if self.sub == 'from' and not self.is_transport()\ 166 and self.is_hidden_from_roster(): 167 is_observer = True 168 return is_observer169171 for account in common.gajim.gc_connected: 172 if self.jid in common.gajim.gc_connected[account]: 173 return True 174 return False175182 """ 183 Information concerning each groupchat contact 184 """ 185210 211186 - def __init__(self, room_jid, account, name='', show='', status='', role='', 187 affiliation='', jid='', resource='', our_chatstate=None, 188 composing_xep=None, chatstate=None):189 190 CommonContact.__init__(self, jid, account, resource, show, status, name, 191 our_chatstate, composing_xep, chatstate) 192 193 self.room_jid = room_jid 194 self.role = role 195 self.affiliation = affiliation196198 return self.room_jid + '/' + self.name199201 return self.name202213 """ 214 This is a GOD class for accessing contact and groupchat information. 215 The API has several flaws: 216 217 * it mixes concerns because it deals with contacts, groupchats, 218 groupchat contacts and metacontacts 219 * some methods like get_contact() may return None. This leads to 220 a lot of duplication all over Gajim because it is not sure 221 if we receive a proper contact or just None. 222 223 It is a long way to cleanup this API. Therefore just stick with it 224 and use it as before. We will try to figure out a migration path. 225 """ 229424 425231 self._accounts[new_name] = self._accounts[old_name] 232 self._accounts[new_name].name = new_name 233 del self._accounts[old_name] 234 235 self._metacontact_manager.change_account_name(old_name, new_name)236238 self._accounts[account_name] = Account(account_name, Contacts(), 239 GC_Contacts()) 240 self._metacontact_manager.add_account(account_name)241243 return self._accounts.keys()244 248249 - def create_contact(self, jid, account, name='', groups=[], show='', 250 status='', sub='', ask='', resource='', priority=0, keyID='', 251 client_caps=None, our_chatstate=None, chatstate=None, last_status_time=None, 252 composing_xep=None, last_activity_time=None):253 # Use Account object if available 254 account = self._accounts.get(account, account) 255 return Contact(jid=jid, account=account, name=name, groups=groups, 256 show=show, status=status, sub=sub, ask=ask, resource=resource, 257 priority=priority, keyID=keyID, client_caps=client_caps, 258 our_chatstate=our_chatstate, chatstate=chatstate, 259 last_status_time=last_status_time, composing_xep=composing_xep, 260 last_activity_time=last_activity_time)261262 - def create_self_contact(self, jid, account, resource, show, status, priority, 263 name='', keyID=''):264 conn = common.gajim.connections[account] 265 nick = name or common.gajim.nicks[account] 266 account = self._accounts.get(account, account) # Use Account object if available 267 self_contact = self.create_contact(jid=jid, account=account, 268 name=nick, groups=['self_contact'], show=show, status=status, 269 sub='both', ask='none', priority=priority, keyID=keyID, 270 resource=resource) 271 self_contact.pep = conn.pep 272 return self_contact273275 account = self._accounts.get(account, account) # Use Account object if available 276 return self.create_contact(jid=jid, account=account, resource=resource, 277 name=name, groups=[_('Not in Roster')], show='not in roster', 278 status='', sub='none', keyID=keyID)279281 return self.create_contact(contact.jid, contact.account, 282 name=contact.name, groups=contact.groups, show=contact.show, 283 status=contact.status, sub=contact.sub, ask=contact.ask, 284 resource=contact.resource, priority=contact.priority, 285 keyID=contact.keyID, client_caps=contact.client_caps, 286 our_chatstate=contact.our_chatstate, chatstate=contact.chatstate, 287 last_status_time=contact.last_status_time, 288 composing_xep=contact.composing_xep, 289 last_activity_time=contact.last_activity_time)290292 if account not in self._accounts: 293 self.add_account(account) 294 return self._accounts[account].contacts.add_contact(contact)295297 if account not in self._accounts: 298 return 299 return self._accounts[account].contacts.remove_contact(contact)300302 self._accounts[account].contacts.remove_jid(jid) 303 if remove_meta: 304 self._metacontact_manager.remove_metacontact(account, jid)305 308 311 315 318 321 324 327 330 333335 if not contacts: 336 return None 337 prim_contact = contacts[0] 338 for contact in contacts[1:]: 339 if int(contact.priority) > int(prim_contact.priority): 340 prim_contact = contact 341 return prim_contact342344 contacts = self.get_contacts(account, jid) 345 if not contacts and '/' in jid: 346 # jid may be a fake jid, try it 347 room, nick = jid.split('/', 1) 348 contact = self.get_gc_contact(account, room, nick) 349 return contact 350 return self.get_highest_prio_contact_from_contacts(contacts)351353 """ 354 Return the number of online contacts and the total number of contacts 355 """ 356 if accounts == []: 357 accounts = self.get_accounts() 358 nbr_online = 0 359 nbr_total = 0 360 for account in accounts: 361 our_jid = common.gajim.get_jid_from_account(account) 362 for jid in self.get_jid_list(account): 363 if jid == our_jid: 364 continue 365 if common.gajim.jid_is_transport(jid) and not \ 366 _('Transports') in groups: 367 # do not count transports 368 continue 369 if self.has_brother(account, jid, accounts) and not \ 370 self.is_big_brother(account, jid, accounts): 371 # count metacontacts only once 372 continue 373 contact = self.get_contact_with_highest_priority(account, jid) 374 if _('Not in roster') in contact.groups: 375 continue 376 in_groups = False 377 if groups == []: 378 in_groups = True 379 else: 380 for group in groups: 381 if group in contact.get_shown_groups(): 382 in_groups = True 383 break 384 385 if in_groups: 386 if contact.show not in ('offline', 'error'): 387 nbr_online += 1 388 nbr_total += 1 389 return nbr_online, nbr_total390392 # Only called if self has no attr_name 393 if hasattr(self._metacontact_manager, attr_name): 394 return getattr(self._metacontact_manager, attr_name) 395 else: 396 raise AttributeError(attr_name)397398 - def create_gc_contact(self, room_jid, account, name='', show='', status='', 399 role='', affiliation='', jid='', resource=''):400 account = self._accounts.get(account, account) # Use Account object if available 401 return GC_Contact(room_jid, account, name, show, status, role, affiliation, jid, 402 resource)403 406 409 412 415 418 421427 """ 428 This is a breakout of the contact related behavior of the old 429 Contacts class (which is not called LegacyContactsAPI) 430 """ 434532 533436 if contact.jid not in self._contacts: 437 self._contacts[contact.jid] = [contact] 438 return 439 contacts = self._contacts[contact.jid] 440 # We had only one that was offline, remove it 441 if len(contacts) == 1 and contacts[0].show == 'offline': 442 # Do not use self.remove_contact: it deteles 443 # self._contacts[account][contact.jid] 444 contacts.remove(contacts[0]) 445 # If same JID with same resource already exists, use the new one 446 for c in contacts: 447 if c.resource == contact.resource: 448 self.remove_contact(c) 449 break 450 contacts.append(contact)451453 if contact.jid not in self._contacts: 454 return 455 if contact in self._contacts[contact.jid]: 456 self._contacts[contact.jid].remove(contact) 457 if len(self._contacts[contact.jid]) == 0: 458 del self._contacts[contact.jid]459461 """ 462 Remove all contacts for a given jid 463 """ 464 if jid in self._contacts: 465 del self._contacts[jid]466468 """ 469 Return the list of contact instances for this jid 470 """ 471 return self._contacts.get(jid, [])472474 ### WARNING ### 475 # This function returns a *RANDOM* resource if resource = None! 476 # Do *NOT* use if you need to get the contact to which you 477 # send a message for example, as a bare JID in Jabber means 478 # highest available resource, which this function ignores! 479 """ 480 Return the contact instance for the given resource if it's given else the 481 first contact is no resource is given or None if there is not 482 """ 483 if jid in self._contacts: 484 if not resource: 485 return self._contacts[jid][0] 486 for c in self._contacts[jid]: 487 if c.resource == resource: 488 return c489 494496 return self._contacts.keys()497499 return [jid for jid, contact in self._contacts.iteritems() if not 500 contact[0].is_groupchat()]501503 """ 504 Get Contact object for specific resource of given jid 505 """ 506 barejid, resource = common.gajim.get_room_and_nick_from_fjid(fjid) 507 return self.get_contact(barejid, resource)508 512514 """ 515 Return all contacts in the given group 516 """ 517 group_contacts = [] 518 for jid in self._contacts: 519 contacts = self.get_contacts(jid) 520 if group in contacts[0].groups: 521 group_contacts += contacts 522 return group_contacts523535 539588 589541 if gc_contact.room_jid not in self._rooms: 542 self._rooms[gc_contact.room_jid] = {gc_contact.name: gc_contact} 543 else: 544 self._rooms[gc_contact.room_jid][gc_contact.name] = gc_contact545547 if gc_contact.room_jid not in self._rooms: 548 return 549 if gc_contact.name not in self._rooms[gc_contact.room_jid]: 550 return 551 del self._rooms[gc_contact.room_jid][gc_contact.name] 552 # It was the last nick in room ? 553 if not len(self._rooms[gc_contact.room_jid]): 554 del self._rooms[gc_contact.room_jid]555 559561 return self._rooms.keys()562564 gc_list = self.get_gc_list() 565 if not room_jid in gc_list: 566 return [] 567 return self._rooms[room_jid].keys()568570 nick_list = self.get_nick_list(room_jid) 571 if not nick in nick_list: 572 return None 573 return self._rooms[room_jid][nick]574576 """ 577 Return the number of group chat contacts for the given role and the total 578 number of group chat contacts 579 """ 580 if room_jid not in self._rooms: 581 return 0, 0 582 nb_role = nb_total = 0 583 for nick in self._rooms[room_jid]: 584 if self._rooms[room_jid][nick].role == role: 585 nb_role += 1 586 nb_total += 1 587 return nb_role, nb_total591 595838597 self._metacontacts_tags[new_name] = self._metacontacts_tags[old_name] 598 del self._metacontacts_tags[old_name]599 603605 del self._metacontacts_tags[account]606608 self._metacontacts_tags[account] = tags_list609611 if not jid in self._metacontacts_tags: 612 return jid 613 #FIXME: can this append ? 614 assert False615617 for tag in self._metacontacts_tags[account]: 618 family = self._get_metacontacts_family_from_tag(account, tag) 619 yield family620622 """ 623 Return the tag of a jid 624 """ 625 if not account in self._metacontacts_tags: 626 return None 627 for tag in self._metacontacts_tags[account]: 628 for data in self._metacontacts_tags[account][tag]: 629 if data['jid'] == jid: 630 return tag 631 return None632634 tag = self._get_metacontacts_tag(brother_account, brother_jid) 635 if not tag: 636 tag = self._get_new_metacontacts_tag(brother_jid) 637 self._metacontacts_tags[brother_account][tag] = [{'jid': brother_jid, 638 'tag': tag}] 639 if brother_account != account: 640 common.gajim.connections[brother_account].store_metacontacts( 641 self._metacontacts_tags[brother_account]) 642 # be sure jid has no other tag 643 old_tag = self._get_metacontacts_tag(account, jid) 644 while old_tag: 645 self.remove_metacontact(account, jid) 646 old_tag = self._get_metacontacts_tag(account, jid) 647 if tag not in self._metacontacts_tags[account]: 648 self._metacontacts_tags[account][tag] = [{'jid': jid, 'tag': tag}] 649 else: 650 if order: 651 self._metacontacts_tags[account][tag].append({'jid': jid, 652 'tag': tag, 'order': order}) 653 else: 654 self._metacontacts_tags[account][tag].append({'jid': jid, 655 'tag': tag}) 656 common.gajim.connections[account].store_metacontacts( 657 self._metacontacts_tags[account])658660 if not account in self._metacontacts_tags: 661 return 662 663 found = None 664 for tag in self._metacontacts_tags[account]: 665 for data in self._metacontacts_tags[account][tag]: 666 if data['jid'] == jid: 667 found = data 668 break 669 if found: 670 self._metacontacts_tags[account][tag].remove(found) 671 common.gajim.connections[account].store_metacontacts( 672 self._metacontacts_tags[account]) 673 break674676 tag = self._get_metacontacts_tag(account, jid) 677 if not tag: 678 return False 679 meta_jids = self._get_metacontacts_jids(tag, accounts) 680 return len(meta_jids) > 1 or len(meta_jids[account]) > 1681683 family = self.get_metacontacts_family(account, jid) 684 if family: 685 nearby_family = [data for data in family 686 if account in accounts] 687 bb_data = self._get_metacontacts_big_brother(nearby_family) 688 if bb_data['jid'] == jid and bb_data['account'] == account: 689 return True 690 return False691693 """ 694 Return all jid for the given tag in the form {acct: [jid1, jid2],.} 695 """ 696 answers = {} 697 for account in self._metacontacts_tags: 698 if tag in self._metacontacts_tags[account]: 699 if account not in accounts: 700 continue 701 answers[account] = [] 702 for data in self._metacontacts_tags[account][tag]: 703 answers[account].append(data['jid']) 704 return answers705707 """ 708 Return the family of the given jid, including jid in the form: 709 [{'account': acct, 'jid': jid, 'order': order}, ] 'order' is optional 710 """ 711 tag = self._get_metacontacts_tag(account, jid) 712 return self._get_metacontacts_family_from_tag(account, tag)713715 if not tag: 716 return [] 717 answers = [] 718 for account in self._metacontacts_tags: 719 if tag in self._metacontacts_tags[account]: 720 for data in self._metacontacts_tags[account][tag]: 721 data['account'] = account 722 answers.append(data) 723 return answers724726 """ 727 Compare 2 metacontacts 728 729 Data is {'jid': jid, 'account': account, 'order': order} order is 730 optional 731 """ 732 jid1 = data1['jid'] 733 jid2 = data2['jid'] 734 account1 = data1['account'] 735 account2 = data2['account'] 736 contact1 = self._contacts.get_contact_with_highest_priority(account1, jid1) 737 contact2 = self._contacts.get_contact_with_highest_priority(account2, jid2) 738 show_list = ['not in roster', 'error', 'offline', 'invisible', 'dnd', 739 'xa', 'away', 'chat', 'online', 'requested', 'message'] 740 # contact can be null when a jid listed in the metacontact data 741 # is not in our roster 742 if not contact1: 743 if contact2: 744 return -1 # prefer the known contact 745 else: 746 show1 = 0 747 priority1 = 0 748 else: 749 show1 = show_list.index(contact1.show) 750 priority1 = contact1.priority 751 if not contact2: 752 if contact1: 753 return 1 # prefer the known contact 754 else: 755 show2 = 0 756 priority2 = 0 757 else: 758 show2 = show_list.index(contact2.show) 759 priority2 = contact2.priority 760 # If only one is offline, it's always second 761 if show1 > 2 and show2 < 3: 762 return 1 763 if show2 > 2 and show1 < 3: 764 return -1 765 if 'order' in data1 and 'order' in data2: 766 if data1['order'] > data2['order']: 767 return 1 768 if data1['order'] < data2['order']: 769 return -1 770 if 'order' in data1: 771 return 1 772 if 'order' in data2: 773 return -1 774 transport1 = common.gajim.get_transport_name_from_jid(jid1) 775 transport2 = common.gajim.get_transport_name_from_jid(jid2) 776 if transport2 and not transport1: 777 return 1 778 if transport1 and not transport2: 779 return -1 780 if show1 > show2: 781 return 1 782 if show2 > show1: 783 return -1 784 if priority1 > priority2: 785 return 1 786 if priority2 > priority1: 787 return -1 788 server1 = common.gajim.get_server_from_jid(jid1) 789 server2 = common.gajim.get_server_from_jid(jid2) 790 myserver1 = common.gajim.config.get_per('accounts', account1, 'hostname') 791 myserver2 = common.gajim.config.get_per('accounts', account2, 'hostname') 792 if server1 == myserver1: 793 if server2 != myserver2: 794 return 1 795 elif server2 == myserver2: 796 return -1 797 if jid1 > jid2: 798 return 1 799 if jid2 > jid1: 800 return -1 801 # If all is the same, compare accounts, they can't be the same 802 if account1 > account2: 803 return 1 804 if account2 > account1: 805 return -1 806 return 0807809 """ 810 Return the nearby family and its Big Brother 811 812 Nearby family is the part of the family that is grouped with the 813 metacontact. A metacontact may be over different accounts. If accounts 814 are not merged then the given family is split account wise. 815 816 (nearby_family, big_brother_jid, big_brother_account) 817 """ 818 if common.gajim.config.get('mergeaccounts'): 819 # group all together 820 nearby_family = family 821 else: 822 # we want one nearby_family per account 823 nearby_family = [data for data in family if account == data['account']] 824 825 big_brother_data = self._get_metacontacts_big_brother(nearby_family) 826 big_brother_jid = big_brother_data['jid'] 827 big_brother_account = big_brother_data['account'] 828 829 return (nearby_family, big_brother_jid, big_brother_account)830832 """ 833 Which of the family will be the big brother under wich all others will be 834 ? 835 """ 836 family.sort(cmp=self._compare_metacontacts) 837 return family[-1]
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Thu Aug 12 02:08:10 2010 | http://epydoc.sourceforge.net |