Index: gajim.py
===================================================================
--- gajim.py	(revision 9039)
+++ gajim.py	(working copy)
@@ -2166,6 +2166,45 @@
 		instance = data[1]
 		instance.unique_room_id_error(data[0])
 
+	def handle_event_ssl_error(self, account, data):
+		# ('SSL_ERROR', account, (text, cert, sha1_fingerprint))
+		server = gajim.config.get_per('accounts', account, 'hostname')
+		def on_ok(is_checked):
+			if is_checked:
+				f = open(gajim.MY_CACERTS, 'a')
+				f.write(server + '\n')
+				f.write(data[1] + '\n\n')
+				f.close()
+				gajim.config.set_per('accounts', account, 'ssl_fingerprint_sha1',
+					data[2])
+			gajim.connections[account].ssl_certificate_accepted()
+		def on_cancel():
+			gajim.connections[account].disconnect(on_purpose=True)
+			self.handle_event_status(account, 'offline')
+		pritext = _('Error verifying SSL certificate')
+		sectext = _('There was an error verifying the SSL certificate of your jabber server: %(error)s\nDo you still want to connect to this server?') % {'error': data[0]}
+		checktext = _('Add this certificate to the list of trusted certificates.\nSHA1 fingerprint of the certificate:\n%s') % data[2]
+		dialogs.ConfirmationDialogCheck(pritext, sectext, checktext,
+			on_response_ok=on_ok, on_response_cancel=on_cancel)
+
+	def handle_event_fingerprint_error(self, account, data):
+		# ('FINGERPRINT_ERROR', account, (fingerprint,))
+		def on_yes(widget):
+			dialog.destroy()
+			gajim.config.set_per('accounts', account, 'ssl_fingerprint_sha1',
+				data[0])
+			gajim.connections[account].ssl_certificate_accepted()
+		def on_no(widget):
+			dialog.destroy()
+			gajim.connections[account].disconnect(on_purpose=True)
+			self.handle_event_status(account, 'offline')
+		pritext = _('SSL certificate error')
+		sectext = _('It seems SSL certificate has changed or your connection is '
+			'being hacked. Do you still want to connect and update the fingerprint'
+			'of the certificate?')
+		dialog = dialogs.YesNoDialog(pritext, sectext, on_response_yes=on_yes,
+			on_response_no=on_no)
+
 	def read_sleepy(self):
 		'''Check idle status and change that status if needed'''
 		if not self.sleeper.poll():
@@ -2502,6 +2541,8 @@
 			'UNIQUE_ROOM_ID_SUPPORTED': self.handle_event_unique_room_id_supported,
 			'SESSION_NEG': self.handle_session_negotiation,
 			'GPG_PASSWORD_REQUIRED': self.handle_event_gpg_password_required,
+			'SSL_ERROR': self.handle_event_ssl_error,
+			'FINGERPRINT_ERROR': self.handle_event_fingerprint_error,
 		}
 		gajim.handlers = self.handlers
 
Index: common/xmpp/transports_nb.py
===================================================================
--- common/xmpp/transports_nb.py	(revision 9039)
+++ common/xmpp/transports_nb.py	(working copy)
@@ -745,10 +745,34 @@
 		#tcpsock._sslContext = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
 		tcpsock.ssl_errnum = 0
 		tcpsock._sslContext.set_verify(OpenSSL.SSL.VERIFY_PEER, self._ssl_verify_callback)
+		cacerts = os.path.join(gajim.DATA_DIR, 'other', 'cacerts.pem')
 		try:
-			tcpsock._sslContext.load_verify_locations(os.path.join(gajim.DATA_DIR, 'other', 'cacerts.pem'))
+			tcpsock._sslContext.load_verify_locations(cacerts)
 		except:
-			log.warning(_("Unable to load SSL certificats from file %s" % os.path.abspath(os.path.join(gajim.DATA_DIR,'other','ca.crt'))))
+			log.warning('Unable to load SSL certificats from file %s' % \
+				os.path.abspath(cacerts))
+		# load users certs
+		if os.path.isfile(gajim.MY_CACERTS):
+			store = tcpsock._sslContext.get_cert_store()
+			f = open(gajim.MY_CACERTS)
+			lines = f.readlines()
+			i = 0
+			begin = -1
+			for line in lines:
+				if 'BEGIN CERTIFICATE' in line:
+					begin = i
+					continue
+				elif 'END CERTIFICATE' in line and begin > -1:
+					cert = ''.join(lines[begin:i+2])
+					try:
+						X509cert = OpenSSL.crypto.load_certificate(
+							OpenSSL.crypto.FILETYPE_PEM, cert)
+						store.add_cert(X509cert)
+					except:
+						log.warning('Unable to load a certificate from file %s' % \
+							gajim.MY_CACERTS)
+					begin = -1
+				i += 1
 		tcpsock._sslObj = OpenSSL.SSL.Connection(tcpsock._sslContext, tcpsock._sock)
 		tcpsock._sslObj.set_connect_state() # set to client mode
 
@@ -788,9 +812,12 @@
 	def _ssl_verify_callback(self, sslconn, cert, errnum, depth, ok):
 		# Exceptions can't propagate up through this callback, so print them here.
 		try:
+			self._owner.Connection.ssl_fingerprint_sha1 = cert.digest('sha1')
 			if errnum == 0:
 				return True
 			self._owner.Connection.ssl_errnum = errnum
+			self._owner.Connection.ssl_cert_pem = OpenSSL.crypto.dump_certificate(
+				OpenSSL.crypto.FILETYPE_PEM, cert)
 			return True
 		except:
 			log.error("Exception caught in _ssl_info_callback:", exc_info=True)
Index: common/configpaths.py
===================================================================
--- common/configpaths.py	(revision 9039)
+++ common/configpaths.py	(working copy)
@@ -79,9 +79,9 @@
 
 		# LOG is deprecated
 		k = ( 'LOG',   'LOG_DB',   'VCARD',   'AVATAR',   'MY_EMOTS',
-			'MY_ICONSETS' )
+			'MY_ICONSETS', 'MY_CACERTS')
 		v = (u'logs', u'logs.db', u'vcards', u'avatars', u'emoticons',
-			u'iconsets')
+			u'iconsets',  u'cacerts.pem')
 
 		if os.name == 'nt':
 			v = map(lambda x: x.capitalize(), v)
Index: common/config.py
===================================================================
--- common/config.py	(revision 9039)
+++ common/config.py	(working copy)
@@ -276,6 +276,7 @@
 			'keyid': [ opt_str, '', '', True ],
 			'keyname': [ opt_str, '', '', True ],
 			'usessl': [ opt_bool, False, '', True ],
+			'ssl_fingerprint_sha1': [ opt_str, '', '', True ],
 			'use_srv': [ opt_bool, True, '', True ],
 			'use_custom_host': [ opt_bool, False, '', True ],
 			'custom_port': [ opt_int, 5222, '', True ],
Index: common/gajim.py
===================================================================
--- common/gajim.py	(revision 9039)
+++ common/gajim.py	(working copy)
@@ -77,6 +77,7 @@
 AVATAR_PATH = gajimpaths['AVATAR']
 MY_EMOTS_PATH = gajimpaths['MY_EMOTS']
 MY_ICONSETS_PATH = gajimpaths['MY_ICONSETS']
+MY_CACERTS =  gajimpaths['MY_CACERTS']
 TMP = gajimpaths['TMP']
 DATA_DIR = gajimpaths['DATA']
 HOME_DIR = gajimpaths['HOME']
Index: common/connection.py
===================================================================
--- common/connection.py	(revision 9039)
+++ common/connection.py	(working copy)
@@ -59,38 +59,38 @@
 import gtkgui_helpers
 
 ssl_error = { 
-2: "Unable to get issuer certificate",
-3: "Unable to get certificate CRL",
-4: "Unable to decrypt certificate's signature",
-5: "Unable to decrypt CRL's signature",
-6: "Unable to decode issuer public key",
-7: "Certificate signature failure",
-8: "CRL signature failure",
-9: "Certificate is not yet valid",
-10: "Certificate has expired",
-11: "CRL is not yet valid",
-12: "CRL has expired",
-13: "Format error in certificate's notBefore field",
-14: "Format error in certificate's notAfter field",
-15: "Format error in CRL's lastUpdate field",
-16: "Format error in CRL's nextUpdate field",
-17: "Out of memory",
-18: "Self signed certificate in certificate chain",
-19: "Unable to get local issuer certificate",
-20: "Unable to verify the first certificate",
-21: "Unable to verify the first certificate",
-22: "Certificate chain too long",
-23: "Certificate revoked",
-24: "Invalid CA certificate",
-25: "Path length constraint exceeded",
-26: "Unsupported certificate purpose",
-27: "Certificate not trusted",
-28: "Certificate rejected",
-29: "Subject issuer mismatch",
-30: "Authority and subject key identifier mismatch",
-31: "Authority and issuer serial number mismatch",
-32: "Key usage does not include certificate signing",
-50: "Application verification failure"
+2: _("Unable to get issuer certificate"),
+3: _("Unable to get certificate CRL"),
+4: _("Unable to decrypt certificate's signature"),
+5: _("Unable to decrypt CRL's signature"),
+6: _("Unable to decode issuer public key"),
+7: _("Certificate signature failure"),
+8: _("CRL signature failure"),
+9: _("Certificate is not yet valid"),
+10: _("Certificate has expired"),
+11: _("CRL is not yet valid"),
+12: _("CRL has expired"),
+13: _("Format error in certificate's notBefore field"),
+14: _("Format error in certificate's notAfter field"),
+15: _("Format error in CRL's lastUpdate field"),
+16: _("Format error in CRL's nextUpdate field"),
+17: _("Out of memory"),
+18: _("Self signed certificate in certificate chain"),
+19: _("Unable to get local issuer certificate"),
+20: _("Unable to verify the first certificate"),
+21: _("Unable to verify the first certificate"),
+22: _("Certificate chain too long"),
+23: _("Certificate revoked"),
+24: _("Invalid CA certificate"),
+25: _("Path length constraint exceeded"),
+26: _("Unsupported certificate purpose"),
+27: _("Certificate not trusted"),
+28: _("Certificate rejected"),
+29: _("Subject issuer mismatch"),
+30: _("Authority and subject key identifier mismatch"),
+31: _("Authority and issuer serial number mismatch"),
+32: _("Key usage does not include certificate signing"),
+50: _("Application verification failure")
 }
 class Connection(ConnectionHandlers):
 	'''Connection class'''
@@ -182,7 +182,7 @@
 			self.retrycount = 0
 	
 	# We are doing disconnect at so many places, better use one function in all
-	def disconnect(self, on_purpose = False):
+	def disconnect(self, on_purpose=False):
 		self.on_purpose = on_purpose
 		self.connected = 0
 		self.time_to_reconnect = None
@@ -477,7 +477,6 @@
 		con.RegisterDisconnectHandler(self._disconnectedReconnCB)
 		log.debug(_('Connected to server %s:%s with %s') % (self._current_host['host'],
 			self._current_host['port'], con_type))
-		self._register_handlers(con, con_type)
 
 		name = gajim.config.get_per('accounts', self.name, 'name')
 		hostname = gajim.config.get_per('accounts', self.name, 'hostname')
@@ -487,15 +486,32 @@
 		except AttributeError:
 			errnum = -1 # we don't have an errnum
 		if errnum > 0:
-			# FIXME: tell the user that the certificat is untrusted, and ask him what to do
-			try:
-				log.warning("The authenticity of the "+hostname+" certificate could be invalid.\nSSL Error: "+ssl_error[errnum])
-			except KeyError:
-				log.warning("Unknown SSL error: %d" % errnum)
+			text = _('The authenticity of the %s certificate could be invalid.') %\
+				hostname
+			if errnum in ssl_error:
+				text += _('\nSSL Error: %s') % ssl_error[errnum]
+			else:
+				text += _('\nUnknown SSL error: %d') % errnum
+			self.dispatch('SSL_ERROR', (text, con.Connection.ssl_cert_pem,
+				con.Connection.ssl_fingerprint_sha1))
+			return True
+		if hasattr(con.Connection, 'ssl_fingerprint_sha1'):
+			saved_fingerprint = gajim.config.get_per('accounts', self.name, 'ssl_fingerprint_sha1')
+			if saved_fingerprint:
+				# Check sha1 fingerprint
+				if con.Connection.ssl_fingerprint_sha1 != saved_fingerprint:
+					self.dispatch('FINGERPRINT_ERROR',
+						(con.Connection.ssl_fingerprint_sha1,))
+					return True
+		self._register_handlers(con, con_type)
 		con.auth(name, self.password, self.server_resource, 1, self.__on_auth)
 
-		return True
 
+	def ssl_certificate_accepted(self):
+		name = gajim.config.get_per('accounts', self.name, 'name')
+		self._register_handlers(self.connection, 'ssl')
+		self.connection.auth(name, self.password, self.server_resource, 1, self.__on_auth)
+
 	def _register_handlers(self, con, con_type):
 		self.peerhost = con.get_peerhost()
 		# notify the gui about con_type
@@ -543,7 +559,7 @@
 
 	def quit(self, kill_core):
 		if kill_core and gajim.account_is_connected(self.name):
-			self.disconnect(on_purpose = True)
+			self.disconnect(on_purpose=True)
 	
 	def get_privacy_lists(self):
 		if not self.connection:
