Changeset 9123 for branches/pep/src/common/connection.py
- Timestamp:
- 12/12/07 09:44:46 (12 months ago)
- Files:
-
- 1 modified
-
branches/pep/src/common/connection.py (modified) (49 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/pep/src/common/connection.py
r8487 r9123 3 3 ## 4 4 ## Copyright (C) 2003-2004 Vincent Hanquez <tab@snarc.org> 5 ## Copyright (C) 2003-200 6 Yann Le Boulanger <asterix@lagaule.org>5 ## Copyright (C) 2003-2007 Yann Leboulanger <asterix@lagaule.org> 6 6 ## Copyright (C) 2005-2006 Nikos Kouremenos <kourem@gmail.com> 7 ## Copyright (C) 2005-2006Dimitur Kirov <dkirov@gmail.com>8 ## Copyright (C) 2005-2006Travis Shirk <travis@pobox.com>7 ## Dimitur Kirov <dkirov@gmail.com> 8 ## Travis Shirk <travis@pobox.com> 9 9 ## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com> 10 ## Stephan Erb <steve-e@h3c.de> 10 11 ## 11 ## This program is free software; you can redistribute it and/or modify 12 ## This file is part of Gajim. 13 ## 14 ## Gajim is free software; you can redistribute it and/or modify 12 15 ## it under the terms of the GNU General Public License as published 13 ## by the Free Software Foundation; version 2only.16 ## by the Free Software Foundation; version 3 only. 14 17 ## 15 ## This program is distributed in the hope that it will be useful,18 ## Gajim is distributed in the hope that it will be useful, 16 19 ## but WITHOUT ANY WARRANTY; without even the implied warranty of 17 20 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 21 ## GNU General Public License for more details. 19 22 ## 23 ## You should have received a copy of the GNU General Public License 24 ## along with Gajim. If not, see <http://www.gnu.org/licenses/>. 25 ## 20 26 21 27 import os 22 28 import random 23 29 import socket 30 31 import time 24 32 25 33 try: … … 51 59 import gtkgui_helpers 52 60 53 ssl_error = { 54 2: "Unable to get issuer certificate",55 3: "Unable to get certificate CRL",56 4: "Unable to decrypt certificate's signature",57 5: "Unable to decrypt CRL's signature",58 6: "Unable to decode issuer public key",59 7: "Certificate signature failure",60 8: "CRL signature failure",61 9: "Certificate is not yet valid",62 10: "Certificate has expired",63 11: "CRL is not yet valid",64 12: "CRL has expired",65 13: "Format error in certificate's notBefore field",66 14: "Format error in certificate's notAfter field",67 15: "Format error in CRL's lastUpdate field",68 16: "Format error in CRL's nextUpdate field",69 17: "Out of memory",70 18: "Self signed certificate in certificate chain",71 19: "Unable to get local issuer certificate",72 20: "Unable to verify the first certificate",73 21: "Unable to verify the first certificate",74 22: "Certificate chain too long",75 23: "Certificate revoked",76 24: "Invalid CA certificate",77 25: "Path length constraint exceeded",78 26: "Unsupported certificate purpose",79 27: "Certificate not trusted",80 28: "Certificate rejected",81 29: "Subject issuer mismatch",82 30: "Authority and subject key identifier mismatch",83 31: "Authority and issuer serial number mismatch",84 32: "Key usage does not include certificate signing",85 50: "Application verification failure"61 ssl_error = { 62 2: _("Unable to get issuer certificate"), 63 3: _("Unable to get certificate CRL"), 64 4: _("Unable to decrypt certificate's signature"), 65 5: _("Unable to decrypt CRL's signature"), 66 6: _("Unable to decode issuer public key"), 67 7: _("Certificate signature failure"), 68 8: _("CRL signature failure"), 69 9: _("Certificate is not yet valid"), 70 10: _("Certificate has expired"), 71 11: _("CRL is not yet valid"), 72 12: _("CRL has expired"), 73 13: _("Format error in certificate's notBefore field"), 74 14: _("Format error in certificate's notAfter field"), 75 15: _("Format error in CRL's lastUpdate field"), 76 16: _("Format error in CRL's nextUpdate field"), 77 17: _("Out of memory"), 78 18: _("Self signed certificate in certificate chain"), 79 19: _("Unable to get local issuer certificate"), 80 20: _("Unable to verify the first certificate"), 81 21: _("Unable to verify the first certificate"), 82 22: _("Certificate chain too long"), 83 23: _("Certificate revoked"), 84 24: _("Invalid CA certificate"), 85 25: _("Path length constraint exceeded"), 86 26: _("Unsupported certificate purpose"), 87 27: _("Certificate not trusted"), 88 28: _("Certificate rejected"), 89 29: _("Subject issuer mismatch"), 90 30: _("Authority and subject key identifier mismatch"), 91 31: _("Authority and issuer serial number mismatch"), 92 32: _("Key usage does not include certificate signing"), 93 50: _("Application verification failure") 86 94 } 87 95 class Connection(ConnectionHandlers): … … 100 108 self.is_zeroconf = False 101 109 self.gpg = None 110 if USE_GPG: 111 self.gpg = GnuPG.GnuPG(gajim.config.get('use_gpg_agent')) 102 112 self.status = '' 103 113 self.priority = gajim.get_priority(name, 'offline') … … 110 120 self.last_time_to_reconnect = None 111 121 self.new_account_info = None 122 self.new_account_form = None 112 123 self.bookmarks = [] 113 124 self.annotations = {} … … 118 129 self.password = passwords.get_password(name) 119 130 self.server_resource = gajim.config.get_per('accounts', name, 'resource') 120 # All valid resource substitution strings should be added to this hash. 131 # All valid resource substitution strings should be added to this hash. 121 132 if self.server_resource: 122 133 self.server_resource = Template(self.server_resource).safe_substitute({ … … 132 143 self.blocked_groups = [] 133 144 self.pep_supported = False 134 # Do we continue connection when we get roster (send presence,get vcard.. .)145 # Do we continue connection when we get roster (send presence,get vcard..) 135 146 self.continue_connect_info = None 136 147 # To know the groupchat jid associated with a sranza ID. Useful to … … 138 149 # the fake jid 139 150 self.groupchat_jids = {} # {ID : groupchat_jid} 140 if USE_GPG: 141 self.gpg = GnuPG.GnuPG(gajim.config.get('use_gpg_agent')) 142 gajim.config.set('usegpg', True) 143 else: 144 gajim.config.set('usegpg', False) 145 151 146 152 self.on_connect_success = None 147 153 self.on_connect_failure = None … … 152 158 # server {'icq': ['icq.server.com', 'icq2.server.com'], } 153 159 self.vcard_supported = True 154 self. metacontacts_supported = True160 self.private_storage_supported = True 155 161 # END __init__ 156 162 … … 172 178 self.dispatch('STATUS', 'connecting') 173 179 self.retrycount += 1 174 signed = self.get_signed_msg(self.status)175 180 self.on_connect_auth = self._init_roster 176 self.connect_and_init(self.old_show, self.status, s igned)181 self.connect_and_init(self.old_show, self.status, self.gpg != None) 177 182 else: 178 183 # reconnect succeeded 179 184 self.time_to_reconnect = None 180 185 self.retrycount = 0 181 186 182 187 # We are doing disconnect at so many places, better use one function in all 183 def disconnect(self, on_purpose =False):188 def disconnect(self, on_purpose=False): 184 189 #FIXME: set the Tune to None before disconnection per account 185 190 #gajim.interface.roster._music_track_changed(None, None) … … 194 199 self.last_connection = None 195 200 self.connection = None 196 201 197 202 def _disconnectedReconnCB(self): 198 203 '''Called when we are disconnected''' … … 203 208 self.old_show = STATUS_LIST[self.connected] 204 209 self.connected = 0 205 self.dispatch('STATUS', 'offline')206 210 if not self.on_purpose: 211 self.dispatch('STATUS', 'offline') 207 212 self.disconnect() 208 213 if gajim.config.get_per('accounts', self.name, 'autoreconnect'): … … 236 241 self.on_purpose = False 237 242 # END disconenctedReconnCB 238 243 239 244 def _connection_lost(self): 240 245 self.disconnect(on_purpose = False) … … 258 263 is_form = data[2] 259 264 conf = data[1] 260 self.dispatch('NEW_ACC_CONNECTED', (conf, is_form)) 265 if self.new_account_form: 266 def _on_register_result(result): 267 if not common.xmpp.isResultNode(result): 268 self.dispatch('ACC_NOT_OK', (result.getError())) 269 return 270 if USE_GPG: 271 self.gpg = GnuPG.GnuPG(gajim.config.get( 272 'use_gpg_agent')) 273 self.dispatch('ACC_OK', (self.new_account_info)) 274 self.new_account_info = None 275 self.new_account_form = None 276 if self.connection: 277 self.connection.UnregisterDisconnectHandler( 278 self._on_new_account) 279 self.disconnect(on_purpose=True) 280 # it's the second time we get the form, we have info user 281 # typed, so send them 282 if is_form: 283 #TODO: Check if form has changed 284 iq = common.xmpp.Iq('set', common.xmpp.NS_REGISTER, to=self._hostname) 285 iq.setTag('query').addChild(node=self.new_account_form) 286 self.connection.SendAndCallForResponse(iq, 287 _on_register_result) 288 else: 289 if self.new_account_form.keys().sort() != \ 290 conf.keys().sort(): 291 # requested config has changed since first connection 292 self.dispatch('ACC_NOT_OK', (_( 293 'Server %s provided a different registration form')\ 294 % data[0])) 295 return 296 common.xmpp.features_nb.register(self.connection, 297 self._hostname, self.new_account_form, 298 _on_register_result) 299 return 300 try: 301 errnum = self.connection.Connection.ssl_errnum 302 except AttributeError: 303 errnum = -1 # we don't have an errnum 304 ssl_msg = '' 305 if errnum > 0: 306 if errnum in ssl_error: 307 ssl_msg = ssl_error[errnum] 308 else: 309 ssl_msg = _('Unknown SSL error: %d') % errnum 310 ssl_cert = '' 311 if hasattr(self.connection.Connection, 'ssl_cert_pem'): 312 ssl_cert = self.connection.Connection.ssl_cert_pem 313 ssl_fingerprint = '' 314 if hasattr(self.connection.Connection, 'ssl_fingerprint_sha1'): 315 ssl_fingerprint = \ 316 self.connection.Connection.ssl_fingerprint_sha1 317 self.dispatch('NEW_ACC_CONNECTED', (conf, is_form, ssl_msg, 318 ssl_cert, ssl_fingerprint)) 319 self.connection.UnregisterDisconnectHandler( 320 self._on_new_account) 321 self.disconnect(on_purpose=True) 261 322 return 262 323 if not data[1]: # wrong answer … … 478 539 log.debug(_('Connected to server %s:%s with %s') % (self._current_host['host'], 479 540 self._current_host['port'], con_type)) 480 self._register_handlers(con, con_type)481 541 482 542 name = gajim.config.get_per('accounts', self.name, 'name') … … 488 548 errnum = -1 # we don't have an errnum 489 549 if errnum > 0: 490 # FIXME: tell the user that the certificat is untrusted, and ask him what to do 491 try: 492 log.warning("The authenticity of the "+hostname+" certificate could be unvalid.\nSSL Error: "+ssl_error[errnum]) 493 except KeyError: 494 log.warning("Unknown SSL error: %d" % errnum) 550 text = _('The authenticity of the %s certificate could be invalid.') %\ 551 hostname 552 if errnum in ssl_error: 553 text += _('\nSSL Error: %s') % ssl_error[errnum] 554 else: 555 text += _('\nUnknown SSL error: %d') % errnum 556 self.dispatch('SSL_ERROR', (text, con.Connection.ssl_cert_pem, 557 con.Connection.ssl_fingerprint_sha1)) 558 return True 559 if hasattr(con.Connection, 'ssl_fingerprint_sha1'): 560 saved_fingerprint = gajim.config.get_per('accounts', self.name, 'ssl_fingerprint_sha1') 561 if saved_fingerprint: 562 # Check sha1 fingerprint 563 if con.Connection.ssl_fingerprint_sha1 != saved_fingerprint: 564 self.dispatch('FINGERPRINT_ERROR', 565 (con.Connection.ssl_fingerprint_sha1,)) 566 return True 567 self._register_handlers(con, con_type) 495 568 con.auth(name, self.password, self.server_resource, 1, self.__on_auth) 496 569 497 return True 570 571 def ssl_certificate_accepted(self): 572 name = gajim.config.get_per('accounts', self.name, 'name') 573 self._register_handlers(self.connection, 'ssl') 574 self.connection.auth(name, self.password, self.server_resource, 1, self.__on_auth) 498 575 499 576 def _register_handlers(self, con, con_type): … … 529 606 self.on_connect_auth = None 530 607 else: 531 # Forget password if needed 532 if not gajim.config.get_per('accounts', self.name, 'savepass'): 533 self.password = None 608 # Forget password, it's wrong 609 self.password = None 534 610 gajim.log.debug("Couldn't authenticate to %s" % self._hostname) 535 611 self.disconnect(on_purpose = True) 536 612 self.dispatch('STATUS', 'offline') 537 self.dispatch('ERROR', (_('Authentication failed with "%s"') % self._hostname, 613 self.dispatch('ERROR', (_('Authentication failed with "%s"') % \ 614 self._hostname, 538 615 _('Please check your login and password for correctness.'))) 539 616 if self.on_connect_auth: … … 544 621 def quit(self, kill_core): 545 622 if kill_core and gajim.account_is_connected(self.name): 546 self.disconnect(on_purpose =True)547 623 self.disconnect(on_purpose=True) 624 548 625 def get_privacy_lists(self): 549 626 if not self.connection: … … 571 648 return 572 649 common.xmpp.features_nb.getActiveAndDefaultPrivacyLists(self.connection) 573 650 574 651 def del_privacy_list(self, privacy_list): 575 652 if not self.connection: … … 585 662 common.xmpp.features_nb.delPrivacyList(self.connection, privacy_list, 586 663 _on_del_privacy_list_result) 587 664 588 665 def get_privacy_list(self, title): 589 666 if not self.connection: 590 667 return 591 668 common.xmpp.features_nb.getPrivacyList(self.connection, title) 592 669 593 670 def set_privacy_list(self, listname, tags): 594 671 if not self.connection: 595 672 return 596 673 common.xmpp.features_nb.setPrivacyList(self.connection, listname, tags) 597 674 598 675 def set_active_list(self, listname): 599 676 if not self.connection: … … 605 682 return 606 683 common.xmpp.features_nb.setDefaultPrivacyList(self.connection, listname) 607 684 608 685 def build_privacy_rule(self, name, action): 609 686 '''Build a Privacy rule stanza for invisibility''' … … 658 735 #Get bookmarks from private namespace 659 736 self.get_bookmarks() 660 737 661 738 #Get annotations 662 739 self.get_annotations() … … 666 743 667 744 def test_gpg_passphrase(self, password): 745 if not self.gpg: 746 return False 668 747 self.gpg.passphrase = password 669 748 keyID = gajim.config.get_per('accounts', self.name, 'keyid') … … 672 751 return signed != 'BAD_PASSPHRASE' 673 752 674 def get_signed_msg(self, msg): 753 def get_signed_presence(self, msg, callback = None): 754 if gajim.config.get_per('accounts', self.name, 'gpg_sign_presence'): 755 return self.get_signed_msg(msg, callback) 756 return '' 757 758 def get_signed_msg(self, msg, callback = None): 759 '''returns the signed message if possible 760 or an empty string if gpg is not used 761 or None if waiting for passphrase. 762 callback is the function to call when user give the passphrase''' 675 763 signed = '' 676 764 keyID = gajim.config.get_per('accounts', self.name, 'keyid') 677 if keyID and USE_GPG:765 if keyID and self.gpg: 678 766 use_gpg_agent = gajim.config.get('use_gpg_agent') 679 if self.connected < 2 and self.gpg.passphrase is None and \ 680 not use_gpg_agent: 767 if self.gpg.passphrase is None and not use_gpg_agent: 681 768 # We didn't set a passphrase 682 self.dispatch('ERROR', (_('OpenPGP passphrase was not given'), 683 #%s is the account name here 684 _('You will be connected to %s without OpenPGP.') % self.name)) 685 elif self.gpg.passphrase is not None or use_gpg_agent: 769 return None 770 if self.gpg.passphrase is not None or use_gpg_agent: 686 771 signed = self.gpg.sign(msg, keyID) 687 772 if signed == 'BAD_PASSPHRASE': 773 self.gpg = None 688 774 signed = '' 689 if self.connected < 2: 690 self.dispatch('BAD_PASSPHRASE', ()) 775 self.dispatch('BAD_PASSPHRASE', ()) 691 776 return signed 692 777 … … 696 781 self.connect() 697 782 698 def connect_and_init(self, show, msg, sign ed):699 self.continue_connect_info = [show, msg, sign ed]783 def connect_and_init(self, show, msg, sign_msg): 784 self.continue_connect_info = [show, msg, sign_msg] 700 785 self.on_connect_auth = self._init_roster 701 786 self.connect_and_auth() … … 703 788 def _init_roster(self, con): 704 789 self.connection = con 705 if self.connection: 706 con.set_send_timeout(self.keepalives, self.send_keepalive) 707 self.connection.onreceive(None) 708 iq = common.xmpp.Iq('get', common.xmpp.NS_PRIVACY, xmlns = '') 709 id = self.connection.getAnID() 710 iq.setID(id) 711 self.awaiting_answers[id] = (PRIVACY_ARRIVED, ) 712 self.connection.send(iq) 790 if not self.connection: 791 return 792 self.connection.set_send_timeout(self.keepalives, self.send_keepalive) 793 self.connection.onreceive(None) 794 iq = common.xmpp.Iq('get', common.xmpp.NS_PRIVACY, xmlns = '') 795 id = self.connection.getAnID() 796 iq.setID(id) 797 self.awaiting_answers[id] = (PRIVACY_ARRIVED, ) 798 self.connection.send(iq) 713 799 714 800 def send_custom_status(self, show, msg, jid): … … 727 813 p.setStatus(msg) 728 814 else: 729 signed = self.get_signed_ msg(msg)815 signed = self.get_signed_presence(msg) 730 816 priority = unicode(gajim.get_priority(self.name, sshow)) 731 817 p = common.xmpp.Presence(typ = None, priority = priority, show = sshow, … … 745 831 msg = '' 746 832 keyID = gajim.config.get_per('accounts', self.name, 'keyid') 747 sign ed = ''833 sign_msg = False 748 834 if not auto and not show == 'offline': 749 sign ed = self.get_signed_msg(msg)835 sign_msg = True 750 836 self.status = msg 751 837 if show != 'offline' and not self.connected: … … 753 839 # recconect before we auth to server 754 840 self.old_show = show 755 self.on_purpose = False 841 self.on_purpose = False 756 842 self.server_resource = gajim.config.get_per('accounts', self.name, 757 843 'resource') … … 762 848 'hostname': socket.gethostname() 763 849 }) 764 self.connect_and_init(show, msg, signed) 850 if USE_GPG: 851 self.gpg = GnuPG.GnuPG(gajim.config.get('use_gpg_agent')) 852 self.connect_and_init(show, msg, sign_msg) 765 853 766 854 elif show == 'offline': … … 786 874 self.connected = STATUS_LIST.index(show) 787 875 if show == 'invisible': 876 signed = self.get_signed_presence(msg) 788 877 self.send_invisible_presence(msg, signed) 789 878 return … … 797 886 if msg: 798 887 p.setStatus(msg) 888 signed = self.get_signed_presence(msg) 799 889 if signed: 800 890 p.setTag(common.xmpp.NS_SIGNED + ' x').setData(signed) … … 821 911 self.connection.send(msg_iq) 822 912 823 def send_message(self, jid, msg, keyID, type ='chat', subject='',824 chatstate = None, msg_id = None, composing_xep = None, resource =None,825 user_nick = None, xhtml = None, forward_from =None):913 def send_message(self, jid, msg, keyID, type='chat', subject='', 914 chatstate=None, msg_id=None, composing_xep=None, resource=None, 915 user_nick=None, xhtml=None, session=None, forward_from=None, form_node=None): 826 916 if not self.connection: 827 917 return 1 828 918 if msg and not xhtml and gajim.config.get('rst_formatting_outgoing_messages'): 829 919 xhtml = create_xhtml(msg) 830 if not msg and chatstate is None :920 if not msg and chatstate is None and form_node is None: 831 921 &
