From e4ff7c6ced889fd79e3cd9fdc32fa0b31444687c Mon Sep 17 00:00:00 2001 From: Yann Leboulanger Date: Mon, 18 Oct 2010 22:05:41 +0200 Subject: [PATCH] use NEC to handle messages / gc_messages --- plugins/snarl_notifications/plugin.py | 5 +- src/common/connection_handlers.py | 306 +++++------------- src/common/connection_handlers_events.py | 390 ++++++++++++++++++----- src/common/gajim.py | 30 +- src/common/logger.py | 28 ++ src/common/pubsub.py | 2 +- src/config.py | 2 +- src/groupchat_control.py | 34 +- src/gui_interface.py | 60 +--- src/remote_control.py | 7 + 10 files changed, 470 insertions(+), 394 deletions(-) diff --git a/plugins/snarl_notifications/plugin.py b/plugins/snarl_notifications/plugin.py index c01194427..acc41233f 100644 --- a/plugins/snarl_notifications/plugin.py +++ b/plugins/snarl_notifications/plugin.py @@ -65,9 +65,8 @@ class SnarlNotificationsPlugin(GajimPlugin): msg = data[1][1] msg_type = data[1][4] if msg_type == 'chat': - nickname = gajim.get_contact_name_from_jid(account, - jid_without_resource) - elif msg_type == 'pm': + nickname = gajim.get_contact_name_from_jid(account, jid_without_resource) + elif msg_type in ('pm', 'groupchat'): nickname = gajim.get_resource_from_jid(jid) print "Event '%s' occured. Arguments: %s\n\n===\n"%(event_name, pformat(args)) diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py index 79b90ea96..7e1936add 100644 --- a/src/common/connection_handlers.py +++ b/src/common/connection_handlers.py @@ -576,7 +576,7 @@ class ConnectionVcard: id_ = iq_obj.getID() gajim.nec.push_incoming_event(NetworkEvent('raw-iq-received', - conn=con, xmpp_iq=iq_obj)) + conn=self, stanza=iq_obj)) # Check if we were waiting a timeout for this id found_tim = None @@ -910,13 +910,13 @@ class ConnectionHandlersBase: return if obj.id_ in self.last_ids: gajim.nec.push_incoming_event(LastResultReceivedEvent(None, - conn=self, iq_obj=obj.iq_obj)) + conn=self, stanza=obj.stanza)) return True def _LastResultCB(self, con, iq_obj): log.debug('LastResultCB') gajim.nec.push_incoming_event(LastResultReceivedEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) def get_sessions(self, jid): """ @@ -1096,6 +1096,7 @@ ConnectionJingle, ConnectionIBBytestream): gajim.nec.register_incoming_event(RosternotesReceivedEvent) gajim.nec.register_incoming_event(StreamConflictReceivedEvent) gajim.nec.register_incoming_event(PresenceReceivedEvent) + gajim.nec.register_incoming_event(MessageReceivedEvent) gajim.ged.register_event_handler('http-auth-received', ged.CORE, self._nec_http_auth_received) @@ -1133,6 +1134,10 @@ ConnectionJingle, ConnectionIBBytestream): ged.CORE, self._nec_unsubscribed_presence_received) gajim.ged.register_event_handler('unsubscribed-presence-received', ged.POSTGUI, self._nec_unsubscribed_presence_received_end) + gajim.ged.register_event_handler('message-received', ged.CORE, + self._nec_message_received) + gajim.ged.register_event_handler('decrypted-message-received', ged.CORE, + self._nec_decrypted_message_received) def build_http_auth_answer(self, iq_obj, answer): if not self.connection or self.connected < 2: @@ -1152,30 +1157,30 @@ ConnectionJingle, ConnectionIBBytestream): if obj.conn.name != self.name: return if obj.opt in ('yes', 'no'): - obj.conn.build_http_auth_answer(obj.iq_obj, obj.opt) + obj.conn.build_http_auth_answer(obj.stanza, obj.opt) return True def _HttpAuthCB(self, con, iq_obj): log.debug('HttpAuthCB') gajim.nec.push_incoming_event(HttpAuthReceivedEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) raise common.xmpp.NodeProcessed def _ErrorCB(self, con, iq_obj): log.debug('ErrorCB') gajim.nec.push_incoming_event(IqErrorReceivedEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) def _nec_iq_error_received(self, obj): if obj.conn.name != self.name: return if obj.id_ in self.version_ids: gajim.nec.push_incoming_event(VersionResultReceivedEvent(None, - conn=self, iq_obj=obj.iq_obj)) + conn=self, stanza=obj.iq_obj)) return True if obj.id_ in self.entity_time_ids: gajim.nec.push_incoming_event(TimeResultReceivedEvent(None, - conn=self, iq_obj=obj.iq_obj)) + conn=self, stanza=obj.stanza)) return True def _nec_private_storate_bookmarks_received(self, obj): @@ -1203,7 +1208,7 @@ ConnectionJingle, ConnectionIBBytestream): """ log.debug('PrivateCB') gajim.nec.push_incoming_event(PrivateStorageReceivedEvent(None, - conn=self, iq_obj=iq_obj)) + conn=self, stanza=iq_obj)) def _SecLabelCB(self, con, iq_obj): """ @@ -1235,7 +1240,7 @@ ConnectionJingle, ConnectionIBBytestream): def _rosterSetCB(self, con, iq_obj): log.debug('rosterSetCB') gajim.nec.push_incoming_event(RosterSetReceivedEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) raise common.xmpp.NodeProcessed def _nec_roster_set_received(self, obj): @@ -1258,13 +1263,13 @@ ConnectionJingle, ConnectionIBBytestream): if not self.connection or self.connected < 2: return gajim.nec.push_incoming_event(VersionRequestEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) raise common.xmpp.NodeProcessed def _nec_version_request_received(self, obj): if obj.conn.name != self.name: return - iq_obj = obj.iq_obj.buildReply('result') + iq_obj = obj.stanza.buildReply('result') qp = iq_obj.getTag('query') qp.setTagData('name', 'Gajim') qp.setTagData('version', gajim.version) @@ -1278,7 +1283,7 @@ ConnectionJingle, ConnectionIBBytestream): if not self.connection or self.connected < 2: return gajim.nec.push_incoming_event(LastRequestEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) raise common.xmpp.NodeProcessed def _nec_last_request_received(self, obj): @@ -1287,11 +1292,11 @@ ConnectionJingle, ConnectionIBBytestream): return if HAS_IDLE and gajim.config.get_per('accounts', self.name, 'send_idle_time'): - iq_obj = obj.iq_obj.buildReply('result') + iq_obj = obj.stanza.buildReply('result') qp = iq_obj.getTag('query') qp.attrs['seconds'] = int(self.sleeper.getIdleSec()) else: - iq_obj = obj.iq_obj.buildReply('error') + iq_obj = obj.stanza.buildReply('error') err = common.xmpp.ErrorNode(name=common.xmpp.NS_STANZAS + \ ' service-unavailable') iq_obj.addChild(node=err) @@ -1300,20 +1305,20 @@ ConnectionJingle, ConnectionIBBytestream): def _VersionResultCB(self, con, iq_obj): log.debug('VersionResultCB') gajim.nec.push_incoming_event(VersionResultReceivedEvent(None, - conn=self, iq_obj=iq_obj)) + conn=self, stanza=iq_obj)) def _TimeCB(self, con, iq_obj): log.debug('TimeCB') if not self.connection or self.connected < 2: return gajim.nec.push_incoming_event(TimeRequestEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) raise common.xmpp.NodeProcessed def _nec_time_request_received(self, obj): if obj.conn.name != self.name: return - iq_obj = obj.iq_obj.buildReply('result') + iq_obj = obj.stanza.buildReply('result') qp = iq_obj.getTag('query') qp.setTagData('utc', strftime('%Y%m%dT%H:%M:%S', gmtime())) qp.setTagData('tz', helpers.decode_string(tzname[daylight])) @@ -1326,13 +1331,13 @@ ConnectionJingle, ConnectionIBBytestream): if not self.connection or self.connected < 2: return gajim.nec.push_incoming_event(TimeRevisedRequestEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) raise common.xmpp.NodeProcessed def _nec_time_revised_request_received(self, obj): if obj.conn.name != self.name: return - iq_obj = obj.iq_obj.buildReply('result') + iq_obj = obj.stanza.buildReply('result') qp = iq_obj.setTag('time', namespace=common.xmpp.NS_TIME_REVISED) qp.setTagData('utc', strftime('%Y-%m-%dT%H:%M:%SZ', gmtime())) isdst = localtime().tm_isdst @@ -1344,7 +1349,7 @@ ConnectionJingle, ConnectionIBBytestream): def _TimeRevisedResultCB(self, con, iq_obj): log.debug('TimeRevisedResultCB') gajim.nec.push_incoming_event(TimeResultReceivedEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) def _gMailNewMailCB(self, con, iq_obj): """ @@ -1352,7 +1357,7 @@ ConnectionJingle, ConnectionIBBytestream): """ log.debug('gMailNewMailCB') gajim.nec.push_incoming_event(GmailNewMailReceivedEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) raise common.xmpp.NodeProcessed def _nec_gmail_new_mail_received(self, obj): @@ -1381,7 +1386,7 @@ ConnectionJingle, ConnectionIBBytestream): """ log.debug('gMailQueryCB') gajim.nec.push_incoming_event(GMailQueryReceivedEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) raise common.xmpp.NodeProcessed def _rosterItemExchangeCB(self, con, msg): @@ -1390,7 +1395,7 @@ ConnectionJingle, ConnectionIBBytestream): """ log.debug('rosterItemExchangeCB') gajim.nec.push_incoming_event(RosterItemExchangeEvent(None, conn=self, - iq_obj=msg)) + stanza=msg)) raise common.xmpp.NodeProcessed def _messageCB(self, con, msg): @@ -1400,202 +1405,77 @@ ConnectionJingle, ConnectionIBBytestream): log.debug('MessageCB') gajim.nec.push_incoming_event(NetworkEvent('raw-message-received', - conn=con, xmpp_msg=msg, account=self.name)) + conn=self, stanza=msg, account=self.name)) - mtype = msg.getType() - - # check if the message is a roster item exchange (XEP-0144) - if msg.getTag('x', namespace=common.xmpp.NS_ROSTERX): - self._rosterItemExchangeCB(con, msg) + def _nec_message_received(self, obj): + if obj.conn.name != self.name: return - - # check if the message is a XEP-0070 confirmation request - if msg.getTag('confirm', namespace=common.xmpp.NS_HTTP_AUTH): - self._HttpAuthCB(con, msg) - return - - try: - frm = helpers.get_full_jid_from_iq(msg) - jid = helpers.get_jid_from_iq(msg) - except helpers.InvalidFormat: - self.dispatch('ERROR', (_('Invalid Jabber ID'), - _('A message from a non-valid JID arrived, it has been ' - 'ignored.'))) - return - - addressTag = msg.getTag('addresses', namespace=common.xmpp.NS_ADDRESS) - - # Be sure it comes from one of our resource, else ignore address element - if addressTag and jid == gajim.get_jid_from_account(self.name): - address = addressTag.getTag('address', attrs={'type': 'ofrom'}) - if address: - try: - frm = helpers.parse_jid(address.getAttr('jid')) - except common.helpers.InvalidFormat: - log.warn('Invalid JID: %s, ignoring it' % address.getAttr( - 'jid')) - return - jid = gajim.get_jid_without_resource(frm) - - # invitations - invite = None - encTag = msg.getTag('x', namespace=common.xmpp.NS_ENCRYPTED) - - if not encTag: - invite = msg.getTag('x', namespace=common.xmpp.NS_MUC_USER) - if invite and not invite.getTag('invite'): - invite = None - - # FIXME: Msn transport (CMSN1.2.1 and PyMSN0.10) do NOT RECOMMENDED - # invitation - # stanza (MUC XEP) remove in 2007, as we do not do NOT RECOMMENDED - xtags = msg.getTags('x') - for xtag in xtags: - if xtag.getNamespace() == common.xmpp.NS_CONFERENCE and not invite: - try: - room_jid = helpers.parse_jid(xtag.getAttr('jid')) - except common.helpers.InvalidFormat: - log.warn('Invalid JID: %s, ignoring it' % xtag.getAttr( - 'jid')) - continue - is_continued = False - if xtag.getTag('continue'): - is_continued = True - self.dispatch('GC_INVITATION', (room_jid, frm, '', None, - is_continued)) - return - - thread_id = msg.getThread() - - if not mtype or mtype not in ('chat', 'groupchat', 'error'): - mtype = 'normal' - - msgtxt = msg.getBody() - - encrypted = False - xep_200_encrypted = msg.getTag('c', - namespace=common.xmpp.NS_STANZA_CRYPTO) - - session = None - gc_control = gajim.interface.msg_win_mgr.get_gc_control(jid, self.name) - if not gc_control and \ - jid in gajim.interface.minimized_controls[self.name]: - gc_control = gajim.interface.minimized_controls[self.name][jid] - - if gc_control and jid == frm: # message from a gc without a resource - mtype = 'groupchat' - - if mtype != 'groupchat': - session = self.get_or_create_session(frm, thread_id) - - if thread_id and not session.received_thread_id: - session.received_thread_id = True - - session.last_receive = time_time() - - # check if the message is a XEP-0020 feature negotiation request - if msg.getTag('feature', namespace=common.xmpp.NS_FEATURE): - if gajim.HAVE_PYCRYPTO: - feature = msg.getTag(name='feature', - namespace=common.xmpp.NS_FEATURE) - form = common.xmpp.DataForm(node=feature.getTag('x')) - - if form['FORM_TYPE'] == 'urn:xmpp:ssn': - session.handle_negotiation(form) - else: - reply = msg.buildReply() - reply.setType('error') - - reply.addChild(feature) - err = common.xmpp.ErrorNode('service-unavailable', - typ='cancel') - reply.addChild(node=err) - - con.send(reply) - - raise common.xmpp.NodeProcessed - - return - - if msg.getTag('init', namespace=common.xmpp.NS_ESESSION_INIT): - init = msg.getTag(name='init', - namespace=common.xmpp.NS_ESESSION_INIT) - form = common.xmpp.DataForm(node=init.getTag('x')) - - session.handle_negotiation(form) - - raise common.xmpp.NodeProcessed - - tim = msg.getTimestamp() - tim = helpers.datetime_tuple(tim) - tim = localtime(timegm(tim)) - - if xep_200_encrypted: - encrypted = 'xep200' - + if obj.encrypted == 'xep200': try: - msg = session.decrypt_stanza(msg) - msgtxt = msg.getBody() + obj.stanza = self.session.decrypt_stanza(obj.stanza) + obj.msgtxt = obj.stanza.getBody() except Exception: - self.dispatch('FAILED_DECRYPT', (frm, tim, session)) + self.dispatch('FAILED_DECRYPT', (obj.fjid, obj.timestamp, + obj.session)) # Receipt requested # TODO: We shouldn't answer if we're invisible! - contact = gajim.contacts.get_contact(self.name, jid) - nick = gajim.get_room_and_nick_from_fjid(frm)[1] - gc_contact = gajim.contacts.get_gc_contact(self.name, jid, nick) - if msg.getTag('request', namespace=common.xmpp.NS_RECEIPTS) \ - and gajim.config.get_per('accounts', self.name, - 'answer_receipts') and ((contact and contact.sub \ - not in (u'to', u'none')) or gc_contact) and mtype != 'error': - receipt = common.xmpp.Message(to=frm, typ='chat') - receipt.setID(msg.getID()) + contact = gajim.contacts.get_contact(self.name, obj.jid) + nick = obj.resource + gc_contact = gajim.contacts.get_gc_contact(self.name, obj.jid, nick) + if obj.receipt_request_tag and gajim.config.get_per('accounts', + self.name, 'answer_receipts') and ((contact and contact.sub \ + not in (u'to', u'none')) or gc_contact) and obj.mtype != 'error': + receipt = common.xmpp.Message(to=obj.jfid, typ='chat') + receipt.setID(obj.id_) receipt.setTag('received', namespace='urn:xmpp:receipts', - attrs={'id': msg.getID()}) + attrs={'id': obj.id_}) - if thread_id: - receipt.setThread(thread_id) - con.send(receipt) + if obj.thread_id: + receipt.setThread(obj.thread_id) + self.connection.send(receipt) # We got our message's receipt - if msg.getTag('received', namespace=common.xmpp.NS_RECEIPTS) and \ - session.control and gajim.config.get_per('accounts', self.name, - 'request_receipt'): - session.control.conv_textview.hide_xep0184_warning(msg.getID()) + if obj.receipt_received_tag and self.session.control and \ + gajim.config.get_per('accounts', self.name, 'request_receipt'): + self.session.control.conv_textview.hide_xep0184_warning(obj.id_) - if encTag and self.USE_GPG: - encmsg = encTag.getData() + if obj.enc_tag and self.USE_GPG: + encmsg = obj.enc_tag.getData() keyID = gajim.config.get_per('accounts', self.name, 'keyid') if keyID: - def decrypt_thread(encmsg, keyID): + def decrypt_thread(encmsg, keyID, obj): decmsg = self.gpg.decrypt(encmsg, keyID) # \x00 chars are not allowed in C (so in GTK) - msgtxt = helpers.decode_string(decmsg.replace('\x00', '')) - encrypted = 'xep27' - return (msgtxt, encrypted) - gajim.thread_interface(decrypt_thread, [encmsg, keyID], - self._on_message_decrypted, [mtype, msg, session, frm, jid, - invite, tim]) + obj.msgtxt = helpers.decode_string(decmsg.replace('\x00', + '')) + obj.encrypted = 'xep27' + gajim.thread_interface(decrypt_thread, [encmsg, keyID, obj], + self._on_message_decrypted, [obj]) return - self._on_message_decrypted((msgtxt, encrypted), mtype, msg, session, - frm, jid, invite, tim) + self._on_message_decrypted(None, obj) - def _on_message_decrypted(self, output, mtype, msg, session, frm, jid, - invite, tim): - msgtxt, encrypted = output - if mtype == 'error': + def _on_message_decrypted(self, output, obj): + gajim.nec.push_incoming_event(DecryptedMessageReceivedEvent(None, + conn=self, msg_obj=obj)) + + def _nec_decrypted_message_received(self, obj): + if obj.conn.name != self.name: + return + if obj.mtype == 'error': self.dispatch_error_message(msg, msgtxt, session, frm, tim) - elif mtype == 'groupchat': - self.dispatch_gc_message(msg, frm, msgtxt, jid, tim) - elif invite is not None: - self.dispatch_invite_message(invite, frm) + elif obj.mtype == 'groupchat': + gajim.nec.push_incoming_event(GcMessageReceivedEvent(None, + conn=self, msg_obj=obj)) + elif obj.invite_tag is not None: + gajim.nec.push_incoming_event(GcInvitationReceivedEvent(None, + conn=self, msg_obj=obj)) else: if isinstance(session, gajim.default_session_type): session.received(frm, msgtxt, tim, encrypted, msg) else: session.received(msg) - # END messageCB # process and dispatch an error message def dispatch_error_message(self, msg, msgtxt, session, frm, tim): @@ -1623,6 +1503,11 @@ ConnectionJingle, ConnectionIBBytestream): self.dispatch('MSGERROR', (frm, msg.getErrorCode(), error_msg, msgtxt, tim, session)) + def _dispatch_gc_msg_with_captcha(self, stanza, msg_obj): + msg_obj.stanza = stanza + gajim.nec.push_incoming_event(GcMessageReceivedEvent(None, + conn=self, msg_obj=msg_obj)) + def _on_bob_received(self, conn, result, cid): """ Called when we receive BoB data @@ -1747,30 +1632,13 @@ ConnectionJingle, ConnectionIBBytestream): common.logger.LOG_DB_PATH self.dispatch('DB_ERROR', (pritext, sectext)) - def dispatch_invite_message(self, invite, frm): - item = invite.getTag('invite') - try: - jid_from = helpers.parse_jid(item.getAttr('from')) - except common.helpers.InvalidFormat: - log.warn('Invalid JID: %s, ignoring it' % item.getAttr('from')) - return - reason = item.getTagData('reason') - item = invite.getTag('password') - password = invite.getTagData('password') - - is_continued = False - if invite.getTag('invite').getTag('continue'): - is_continued = True - self.dispatch('GC_INVITATION', (frm, jid_from, reason, password, - is_continued)) - def _presenceCB(self, con, prs): """ Called when we receive a presence """ log.debug('PresenceCB') gajim.nec.push_incoming_event(NetworkEvent('raw-pres-received', - conn=self, iq_obj=prs)) + conn=self, stanza=prs)) def _nec_presence_received(self, obj): account = obj.conn.name @@ -2031,17 +1899,17 @@ ConnectionJingle, ConnectionIBBytestream): def _MucOwnerCB(self, con, iq_obj): log.debug('MucOwnerCB') gajim.nec.push_incoming_event(MucOwnerReceivedEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) def _MucAdminCB(self, con, iq_obj): log.debug('MucAdminCB') gajim.nec.push_incoming_event(MucAdminReceivedEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) def _IqPingCB(self, con, iq_obj): log.debug('IqPingCB') gajim.nec.push_incoming_event(PingReceivedEvent(None, conn=self, - iq_obj=iq_obj)) + stanza=iq_obj)) raise common.xmpp.NodeProcessed def _nec_ping_received(self, obj): @@ -2049,7 +1917,7 @@ ConnectionJingle, ConnectionIBBytestream): return if not self.connection or self.connected < 2: return - iq_obj = obj.iq_obj.buildReply('result') + iq_obj = obj.stanza.buildReply('result') self.connection.send(iq_obj) def _PrivacySetCB(self, con, iq_obj): @@ -2207,12 +2075,12 @@ ConnectionJingle, ConnectionIBBytestream): def _SearchCB(self, con, iq_obj): log.debug('SearchCB') gajim.nec.push_incoming_event(SearchFormReceivedEvent(None, - conn=self, iq_obj=iq_obj)) + conn=self, stanza=iq_obj)) def _StreamCB(self, con, iq_obj): log.debug('StreamCB') gajim.nec.push_incoming_event(StreamReceivedEvent(None, - conn=self, iq_obj=iq_obj)) + conn=self, stanza=iq_obj)) def _register_handlers(self, con, con_type): # try to find another way to register handlers in each class diff --git a/src/common/connection_handlers_events.py b/src/common/connection_handlers_events.py index 6200acd9a..af40511a2 100644 --- a/src/common/connection_handlers_events.py +++ b/src/common/connection_handlers_events.py @@ -41,11 +41,26 @@ class HelperEvent: self.fjid = self.conn.groupchat_jids[self.id_] del self.conn.groupchat_jids[self.id_] else: - self.fjid = helpers.get_full_jid_from_iq(self.iq_obj) + self.fjid = helpers.get_full_jid_from_iq(self.stanza) self.jid, self.resource = gajim.get_room_and_nick_from_fjid(self.fjid) def get_id(self): - self.id_ = self.iq_obj.getID() + self.id_ = self.stanza.getID() + + def get_gc_control(self): + self.gc_control = gajim.interface.msg_win_mgr.get_gc_control(self.jid, + self.conn.name) + + # If gc_control is missing - it may be minimized. Try to get it + # from there. If it's not there - then it's missing anyway and + # will remain set to None. + if not self.gc_control: + minimized = gajim.interface.minimized_controls[self.conn.name] + self.gc_control = minimized.get(self.jid) + + def _generate_timestamp(self, tag): + tim = helpers.datetime_tuple(tag) + self.timestamp = localtime(timegm(tim)) class HttpAuthReceivedEvent(nec.NetworkIncomingEvent): name = 'http-auth-received' @@ -53,11 +68,11 @@ class HttpAuthReceivedEvent(nec.NetworkIncomingEvent): def generate(self): self.opt = gajim.config.get_per('accounts', self.conn.name, 'http_auth') - self.iq_id = self.iq_obj.getTagAttr('confirm', 'id') - self.method = self.iq_obj.getTagAttr('confirm', 'method') - self.url = self.iq_obj.getTagAttr('confirm', 'url') + self.iq_id = self.stanza.getTagAttr('confirm', 'id') + self.method = self.stanza.getTagAttr('confirm', 'method') + self.url = self.stanza.getTagAttr('confirm', 'url') # In case it's a message with a body - self.msg = self.iq_obj.getTagData('body') + self.msg = self.stanza.getTagData('body') return True class LastResultReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): @@ -73,10 +88,10 @@ class LastResultReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): self.status = '' self.seconds = -1 - if self.iq_obj.getType() == 'error': + if self.stanza.getType() == 'error': return True - qp = self.iq_obj.getTag('query') + qp = self.stanza.getTag('query') if not qp: return sec = qp.getAttr('seconds') @@ -101,10 +116,10 @@ class VersionResultReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): self.client_info = '' self.os_info = '' - if self.iq_obj.getType() == 'error': + if self.stanza.getType() == 'error': return True - qp = self.iq_obj.getTag('query') + qp = self.stanza.getTag('query') if qp.getTag('name'): self.client_info += qp.getTag('name').getData() if qp.getTag('version'): @@ -126,10 +141,10 @@ class TimeResultReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): self.time_info = '' - if self.iq_obj.getType() == 'error': + if self.stanza.getType() == 'error': return True - qp = self.iq_obj.getTag('time') + qp = self.stanza.getTag('time') if not qp: # wrong answer return @@ -174,9 +189,9 @@ class GMailQueryReceivedEvent(nec.NetworkIncomingEvent): base_network_events = [] def generate(self): - if not self.iq_obj.getTag('mailbox'): + if not self.stanza.getTag('mailbox'): return - mb = self.iq_obj.getTag('mailbox') + mb = self.stanza.getTag('mailbox') if not mb.getAttr('url'): return self.conn.gmail_url = mb.getAttr('url') @@ -234,13 +249,13 @@ class RosterItemExchangeEvent(nec.NetworkIncomingEvent, HelperEvent): self.get_id() self.get_jid_resource() self.exchange_items_list = {} - items_list = self.iq_obj.getTag('x').getChildren() + items_list = self.stanza.getTag('x').getChildren() if not items_list: return self.action = items_list[0].getAttr('action') if self.action is None: self.action = 'add' - for item in self.iq_obj.getTag('x', namespace=xmpp.NS_ROSTERX).\ + for item in self.stanza.getTag('x', namespace=xmpp.NS_ROSTERX).\ getChildren(): try: jid = helpers.parse_jid(item.getAttr('jid')) @@ -320,9 +335,9 @@ class RosterSetReceivedEvent(nec.NetworkIncomingEvent): base_network_events = [] def generate(self): - self.version = self.iq_obj.getTagAttr('query', 'ver') + self.version = self.stanza.getTagAttr('query', 'ver') self.items = {} - for item in self.iq_obj.getTag('query').getChildren(): + for item in self.stanza.getTag('query').getChildren(): try: jid = helpers.parse_jid(item.getAttr('jid')) except helpers.InvalidFormat: @@ -337,8 +352,8 @@ class RosterSetReceivedEvent(nec.NetworkIncomingEvent): self.items[jid] = {'name': name, 'sub': sub, 'ask': ask, 'groups': groups} if self.conn.connection and self.conn.connected > 1: - reply = xmpp.Iq(typ='result', attrs={'id': self.iq_obj.getID()}, - to=self.iq_obj.getFrom(), frm=self.iq_obj.getTo(), xmlns=None) + reply = xmpp.Iq(typ='result', attrs={'id': self.stanza.getID()}, + to=self.stanza.getFrom(), frm=self.stanza.getTo(), xmlns=None) self.conn.connection.send(reply) return True @@ -352,7 +367,7 @@ class MucOwnerReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): def generate(self): self.get_jid_resource() - qp = self.iq_obj.getQueryPayload() + qp = self.stanza.getQueryPayload() self.form_node = None for q in qp: if q.getNamespace() == xmpp.NS_DATA: @@ -366,7 +381,7 @@ class MucAdminReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): def generate(self): self.get_jid_resource() - items = self.iq_obj.getTag('query', + items = self.stanza.getTag('query', namespace=xmpp.NS_MUC_ADMIN).getTags('item') self.users_dict = {} for item in items: @@ -393,7 +408,7 @@ class PrivateStorageReceivedEvent(nec.NetworkIncomingEvent): base_network_events = [] def generate(self): - query = self.iq_obj.getTag('query') + query = self.stanza.getTag('query') self.storage_node = query.getTag('storage') if self.storage_node: self.namespace = self.storage_node.getNamespace() @@ -488,7 +503,7 @@ class PubsubReceivedEvent(nec.NetworkIncomingEvent): base_network_events = [] def generate(self): - self.pubsub_node = self.iq_obj.getTag('pubsub') + self.pubsub_node = self.stanza.getTag('pubsub') if not self.pubsub_node: return self.items_node = self.pubsub_node.getTag('items') @@ -522,7 +537,7 @@ class SearchFormReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): self.get_jid_resource() self.data = None self.is_dataform = False - tag = self.iq_obj.getTag('query', namespace=xmpp.NS_SEARCH) + tag = self.stanza.getTag('query', namespace=xmpp.NS_SEARCH) if not tag: return True self.data = tag.getTag('x', namespace=xmpp.NS_DATA) @@ -530,7 +545,7 @@ class SearchFormReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): self.is_dataform = True return True self.data = {} - for i in self.iq_obj.getQueryPayload(): + for i in self.stanza.getQueryPayload(): self.data[i.getName()] = i.getData() return True @@ -543,7 +558,7 @@ class SearchResultReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): self.get_jid_resource() self.data = None self.is_dataform = False - tag = self.iq_obj.getTag('query', namespace=xmpp.NS_SEARCH) + tag = self.stanza.getTag('query', namespace=xmpp.NS_SEARCH) if not tag: return True self.data = tag.getTag('x', namespace=xmpp.NS_DATA) @@ -566,8 +581,8 @@ class IqErrorReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): def generate(self): self.get_id() self.get_jid_resource() - self.errmsg = self.iq_obj.getErrorMsg() - self.errcode = self.iq_obj.getErrorCode() + self.errmsg = self.stanza.getErrorMsg() + self.errcode = self.stanza.getErrorCode() return True class GmailNewMailReceivedEvent(nec.NetworkIncomingEvent): @@ -575,9 +590,9 @@ class GmailNewMailReceivedEvent(nec.NetworkIncomingEvent): base_network_events = [] def generate(self): - if not self.iq_obj.getTag('new-mail'): + if not self.stanza.getTag('new-mail'): return - if self.iq_obj.getTag('new-mail').getNamespace() != xmpp.NS_GMAILNOTIFY: + if self.stanza.getTag('new-mail').getNamespace() != xmpp.NS_GMAILNOTIFY: return return True @@ -594,7 +609,7 @@ class StreamConflictReceivedEvent(nec.NetworkIncomingEvent): base_network_events = ['stream-received'] def generate(self): - if self.base_event.iq_obj.getTag('conflict'): + if self.base_event.stanza.getTag('conflict'): self.conn = self.base_event.conn return True @@ -612,12 +627,8 @@ class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): self.keyID = helpers.prepare_and_validate_gpg_keyID(self.conn.name, self.jid, self.keyID) - def _generate_timestamp(self, tag): - tim = helpers.datetime_tuple(tag) - self.timestamp = localtime(timegm(tim)) - def _generate_show(self): - self.show = self.iq_obj.getShow() + self.show = self.stanza.getShow() if self.show not in ('chat', 'away', 'xa', 'dnd'): self.show = '' # We ignore unknown show if not self.ptype and not self.show: @@ -626,14 +637,14 @@ class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): self.show = 'offline' def _generate_prio(self): - self.prio = self.iq_obj.getPriority() + self.prio = self.stanza.getPriority() try: self.prio = int(self.prio) except Exception: self.prio = 0 def _generate_ptype(self): - self.ptype = self.iq_obj.getType() + self.ptype = self.stanza.getType() if self.ptype == 'available': self.ptype = None rfc_types = ('unavailable', 'error', 'subscribe', 'subscribed', @@ -643,7 +654,7 @@ class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): def generate(self): self.conn = self.base_event.conn - self.iq_obj = self.base_event.iq_obj + self.stanza = self.base_event.stanza self.need_add_in_roster = False self.need_redraw = False @@ -656,15 +667,6 @@ class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): try: self.get_jid_resource() except Exception: - if self.iq_obj.getTag('error') and self.iq_obj.getTag('error').\ - getTag('jid-malformed'): - # wrong jid, we probably tried to change our nick in a room to a - # non valid one - who = str(self.iq_obj.getFrom()) - jid_stripped, resource = gajim.get_room_and_nick_from_fjid(who) - self.conn.dispatch('GC_MSG', (jid_stripped, - _('Nickname not allowed: %s') % resource, None, False, None, - [])) return jid_list = gajim.contacts.get_jid_list(self.conn.name) self.timestamp = None @@ -673,14 +675,14 @@ class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): sig_tag = None self.avatar_sha = None # XEP-0172 User Nickname - self.user_nick = self.iq_obj.getTagData('nick') or '' + self.user_nick = self.stanza.getTagData('nick') or '' self.contact_nickname = None self.transport_auto_auth = False # XEP-0203 - delay_tag = self.iq_obj.getTag('delay', namespace=xmpp.NS_DELAY2) + delay_tag = self.stanza.getTag('delay', namespace=xmpp.NS_DELAY2) if delay_tag: - self._generate_timestamp(self.iq_obj.getTimestamp2()) - xtags = self.iq_obj.getTags('x') + self._generate_timestamp(self.stanza.getTimestamp2()) + xtags = self.stanza.getTags('x') for x in xtags: namespace = x.getNamespace() if namespace.startswith(xmpp.NS_MUC): @@ -692,7 +694,7 @@ class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): self.contact_nickname = x.getTagData('nickname') elif namespace == xmpp.NS_DELAY and not self.timestamp: # XEP-0091 - self._generate_timestamp(self.iq_obj.getTimestamp()) + self._generate_timestamp(self.stanza.getTimestamp()) elif namespace == 'http://delx.cjb.net/protocol/roster-subsync': # see http://trac.gajim.org/ticket/326 agent = gajim.get_server_from_jid(self.jid) @@ -707,31 +709,31 @@ class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): h = hmac.new(self.conn.secret_hmac, self.jid).hexdigest()[:6] if self.id_.split('_')[-1] == h: self.is_gc = True - self.status = self.iq_obj.getStatus() or '' + self.status = self.stanza.getStatus() or '' self._generate_show() self._generate_prio() self._generate_keyID(sig_tag) - self.errcode = self.iq_obj.getErrorCode() - self.errmsg = self.iq_obj.getErrorMsg() + self.errcode = self.stanza.getErrorCode() + self.errmsg = self.stanza.getErrorMsg() if self.is_gc: gajim.nec.push_incoming_event(GcPresenceReceivedEvent(None, - conn=self.conn, iq_obj=self.iq_obj, presence_obj=self)) + conn=self.conn, stanza=self.stanza, presence_obj=self)) return if self.ptype == 'subscribe': gajim.nec.push_incoming_event(SubscribePresenceReceivedEvent(None, - conn=self.conn, iq_obj=self.iq_obj, presence_obj=self)) + conn=self.conn, stanza=self.stanza, presence_obj=self)) elif self.ptype == 'subscribed': # BE CAREFUL: no con.updateRosterItem() in a callback gajim.nec.push_incoming_event(SubscribedPresenceReceivedEvent(None, - conn=self.conn, iq_obj=self.iq_obj, presence_obj=self)) + conn=self.conn, stanza=self.stanza, presence_obj=self)) elif self.ptype == 'unsubscribe': log.debug(_('unsubscribe request from %s') % self.jid) elif self.ptype == 'unsubscribed': gajim.nec.push_incoming_event(UnsubscribedPresenceReceivedEvent( - None, conn=self.conn, iq_obj=self.iq_obj, presence_obj=self)) + None, conn=self.conn, stanza=self.stanza, presence_obj=self)) elif self.ptype == 'error': if self.errcode != '409': # conflict # See #5120 self.show = 'error' @@ -747,24 +749,14 @@ class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): elif self.jid in jid_list or self.jid == our_jid: return True -class GcPresenceReceivedEvent(nec.NetworkIncomingEvent): +class GcPresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): name = 'gc-presence-received' base_network_events = [] - def get_gc_control(self): - self.gc_control = gajim.interface.msg_win_mgr.get_gc_control( - self.room_jid, self.conn.name) - - # If gc_control is missing - it may be minimized. Try to get it - # from there. If it's not there - then it's missing anyway and - # will remain set to None. - if not self.gc_control: - minimized = gajim.interface.minimized_controls[self.conn.name] - self.gc_control = minimized.get(self.room_jid) - def generate(self): self.ptype = self.presence_obj.ptype self.fjid = self.presence_obj.fjid + self.jid = self.presence_obj.jid self.room_jid = self.presence_obj.jid self.nick = self.presence_obj.resource self.show = self.presence_obj.show @@ -772,7 +764,7 @@ class GcPresenceReceivedEvent(nec.NetworkIncomingEvent): self.avatar_sha = self.presence_obj.avatar_sha self.errcode = self.presence_obj.errcode self.errmsg = self.presence_obj.errmsg - self.errcon = self.iq_obj.getError() + self.errcon = self.stanza.getError() self.get_gc_control() self.gc_contact = gajim.contacts.get_gc_contact(self.conn.name, self.room_jid, self.nick) @@ -787,7 +779,7 @@ class GcPresenceReceivedEvent(nec.NetworkIncomingEvent): if self.gc_contact: jid = self.gc_contact.jid else: - jid = self.iq_obj.getJid() + jid = self.stanza.getJid() st = self.status if jid: # we know real jid, save it in db @@ -813,7 +805,7 @@ class GcPresenceReceivedEvent(nec.NetworkIncomingEvent): # NOTE: if it's a gc presence, don't ask vcard here. # We may ask it to real jid in gui part. self.status_code = [] - ns_muc_user_x = self.iq_obj.getTag('x', namespace=xmpp.NS_MUC_USER) + ns_muc_user_x = self.stanza.getTag('x', namespace=xmpp.NS_MUC_USER) destroy = ns_muc_user_x.getTag('destroy') if ns_muc_user_x and destroy: # Room has been destroyed. see @@ -831,13 +823,13 @@ class GcPresenceReceivedEvent(nec.NetworkIncomingEvent): pass self.status_code = ['destroyed'] else: - self.reason = self.iq_obj.getReason() - self.status_code = self.iq_obj.getStatusCode() - self.role = self.iq_obj.getRole() - self.affiliation = self.iq_obj.getAffiliation() - self.real_jid = self.iq_obj.getJid() - self.actor = self.iq_obj.getActor() - self.new_nick = self.iq_obj.getNewNick() + self.reason = self.stanza.getReason() + self.status_code = self.stanza.getStatusCode() + self.role = self.stanza.getRole() + self.affiliation = self.stanza.getAffiliation() + self.real_jid = self.stanza.getJid() + self.actor = self.stanza.getActor() + self.new_nick = self.stanza.getNewNick() return True class SubscribePresenceReceivedEvent(nec.NetworkIncomingEvent): @@ -868,3 +860,235 @@ class UnsubscribedPresenceReceivedEvent(nec.NetworkIncomingEvent): def generate(self): self.jid = self.presence_obj.jid return True + +class MessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): + name = 'message-received' + base_network_events = ['raw-message-received'] + + def generate(self): + self.conn = self.base_event.conn + self.stanza = self.base_event.stanza + self.get_id() + + account = self.conn.name + + # check if the message is a roster item exchange (XEP-0144) + if self.stanza.getTag('x', namespace=xmpp.NS_ROSTERX): + gajim.nec.push_incoming_event(RosterItemExchangeEvent(None, + conn=self.conn, stanza=self.stanza)) + return + + # check if the message is a XEP-0070 confirmation request + if self.stanza.getTag('confirm', namespace=xmpp.NS_HTTP_AUTH): + gajim.nec.push_incoming_event(HttpAuthReceivedEvent(None, + conn=self.conn, stanza=self.stanza)) + return + + try: + self.get_jid_resource() + except helpers.InvalidFormat: + self.conn.dispatch('ERROR', (_('Invalid Jabber ID'), + _('A message from a non-valid JID arrived, it has been ' + 'ignored.'))) + return + + address_tag = self.stanza.getTag('addresses', namespace=xmpp.NS_ADDRESS) + # Be sure it comes from one of our resource, else ignore address element + if address_tag and self.jid == gajim.get_jid_from_account(account): + address = address_tag.getTag('address', attrs={'type': 'ofrom'}) + if address: + try: + self.fjid = helpers.parse_jid(address.getAttr('jid')) + except helpers.InvalidFormat: + log.warn('Invalid JID: %s, ignoring it' % address.getAttr( + 'jid')) + return + self.jid = gajim.get_jid_without_resource(self.fjid) + + self.enc_tag = self.stanza.getTag('x', namespace=xmpp.NS_ENCRYPTED) + + self.invite_tag = None + if not self.enc_tag: + self.invite_tag = self.stanza.getTag('x', + namespace=xmpp.NS_MUC_USER) + if self.invite_tag and not self.invite_tag.getTag('invite'): + self.invite_tag = None + + self.thread_id = self.stanza.getThread() + self.mtype = self.stanza.getType() + if not self.mtype or self.mtype not in ('chat', 'groupchat', 'error'): + self.mtype = 'normal' + + self.msgtxt = self.stanza.getBody() + + self.get_gc_control() + + if self.gc_control and self.jid == self.fjid: + # message from a gc without a resource + self.mtype = 'groupchat' + + self.session = None + if self.mtype != 'groupchat': + self.session = self.conn.get_or_create_session(self.fjid, + self.thread_id) + + if self.thread_id and not self.session.received_thread_id: + self.session.received_thread_id = True + + self.session.last_receive = time_time() + + # check if the message is a XEP-0020 feature negotiation request + if self.stanza.getTag('feature', namespace=xmpp.NS_FEATURE): + if gajim.HAVE_PYCRYPTO: + feature = self.stanza.getTag(name='feature', + namespace=xmpp.NS_FEATURE) + form = xmpp.DataForm(node=feature.getTag('x')) + + if form['FORM_TYPE'] == 'urn:xmpp:ssn': + self.session.handle_negotiation(form) + else: + reply = self.stanza.buildReply() + reply.setType('error') + reply.addChild(feature) + err = xmpp.ErrorNode('service-unavailable', typ='cancel') + reply.addChild(node=err) + self.conn.connection.send(reply) + return + + if self.stanza.getTag('init', namespace=xmpp.NS_ESESSION_INIT): + init = self.stanza.getTag(name='init', + namespace=xmpp.NS_ESESSION_INIT) + form = xmpp.DataForm(node=init.getTag('x')) + + self.session.handle_negotiation(form) + + return + + self._generate_timestamp(self.stanza.getTimestamp()) + + self.encrypted = False + xep_200_encrypted = self.stanza.getTag('c', + namespace=xmpp.NS_STANZA_CRYPTO) + if xep_200_encrypted: + self.encrypted = 'xep200' + + self.receipt_request_tag = self.stanza.getTag('request', + namespace=xmpp.NS_RECEIPTS) + self.receipt_received_tag = self.stanza.getTag('received', + namespace=xmpp.NS_RECEIPTS) + return True + +class GcInvitationReceivedEvent(nec.NetworkIncomingEvent): + name = 'gc-invitation-received' + base_network_events = [] + + def generate(self): + self.room_jid = self.msg_obj.fjid + + item = self.msg_obj.invite_tag.getTag('invite') + try: + self.jid_from = helpers.parse_jid(item.getAttr('from')) + except helpers.InvalidFormat: + log.warn('Invalid JID: %s, ignoring it' % item.getAttr('from')) + return + self.reason = item.getTagData('reason') + self.password = self.msg_obj.invite_tag.getTagData('password') + + self.is_continued = False + if item.getTag('continue'): + self.is_continued = True + + return True + +class DecryptedMessageReceivedEvent(nec.NetworkIncomingEvent): + name = 'decrypted-message-received' + base_network_events = [] + + def generate(self): + self.stanza = self.msg_obj.stanza + self.jid = self.msg_obj.jid + self.fjid = self.msg_obj.fjid + self.resource = self.msg_obj.resource + self.mtype = self.msg_obj.mtype + self.invite_tag = self.msg_obj.invite_tag + self.thread_id = self.msg_obj.thread_id + self.msgtxt = self.msg_obj.msgtxt + self.gc_control = self.msg_obj.gc_control + self.session = self.msg_obj.session + self.timestamp = self.msg_obj.timestamp + return True + +class GcMessageReceivedEvent(nec.NetworkIncomingEvent): + name = 'gc-message-received' + base_network_events = [] + + def generate(self): + self.stanza = self.msg_obj.stanza + self.fjid = self.msg_obj.fjid + self.msgtxt = self.msg_obj.msgtxt + self.jid = self.msg_obj.jid + self.timestamp = self.msg_obj.timestamp + self.xhtml_msgtxt = self.stanza.getXHTML() + + if gajim.config.get('ignore_incoming_xhtml'): + self.xhtml_msgtxt = None + + if self.msg_obj.resource: + # message from someone + self.nick = self.msg_obj.resource + else: + # message from server + self.nick = '' + + self.has_timestamp = bool(self.stanza.timestamp) + + self.subject = self.stanza.getSubject() + + if self.subject is not None: + self.conn.dispatch('GC_SUBJECT', (self.fjid, self.subject, + self.msgtxt, self.has_timestamp)) + return + + self.status_code = self.stanza.getStatusCode() + + if not self.stanza.getTag('body'): # no + # It could be a config change. See + # http://www.xmpp.org/extensions/xep-0045.html#roomconfig-notify + if self.stanza.getTag('x'): + if self.status_code != []: + self.conn.dispatch('GC_CONFIG_CHANGE', (self.jid, + self.status_code)) + return + + self.displaymarking = None + seclabel = self.stanza.getTag('securitylabel') + if seclabel and seclabel.getNamespace() == xmpp.NS_SECLABEL: + # Ignore message from room in which we are not + self.displaymarking = seclabel.getTag('displaymarking') + + if self.jid not in self.conn.last_history_time: + return + + self.captcha_form = None + captcha_tag = self.stanza.getTag('captcha', namespace=xmpp.NS_CAPTCHA) + if captcha_tag: + self.captcha_form = captcha_tag.getTag('x', namespace=xmpp.NS_DATA) + for field in self.captcha_form.getTags('field'): + for media in field.getTags('media'): + for uri in media.getTags('uri'): + uri_data = uri.getData() + if uri_data.startswith('cid:'): + uri_data = uri_data[4:] + found = False + for data in msg.getTags('data', + namespace=xmpp.NS_BOB): + if data.getAttr('cid') == uri_data: + uri.setData(data.getData()) + found = True + if not found: + self.conn.get_bob_data(uri_data, frm, + self.conn._dispatch_gc_msg_with_captcha, + [self.stanza, self.msg_obj], 0) + return + + return True diff --git a/src/common/gajim.py b/src/common/gajim.py index cfd4419af..7b6ba9049 100644 --- a/src/common/gajim.py +++ b/src/common/gajim.py @@ -33,32 +33,8 @@ import locale import config import xmpp - -try: - import defs -except ImportError: - print >> sys.stderr, '''defs.py is missing! - -If you start gajim from svn: -* Make sure you have GNU autotools installed. -This includes the following packages: -automake >= 1.8 -autoconf >= 2.59 -intltool-0.35 -libtool -* Run -$ sh autogen.sh -* Optionally, install gajim -$ make -$ sudo make install - -**** Note for translators **** -You can get the latest string updates, by running: -$ cd po/ -$ make update-po - -''' - sys.exit(1) +import defs +import common.ged interface = None # The actual interface (the gtk one for the moment) thread_interface = None # Interface to run a thread and then a callback @@ -67,7 +43,7 @@ version = config.get('version') connections = {} # 'account name': 'account (connection.Connection) instance' ipython_window = None -ged = None # Global Events Dispatcher +ged = common.ged.GlobalEventsDispatcher() # Global Events Dispatcher nec = None # Network Events Controller plugin_manager = None # Plugins Manager diff --git a/src/common/logger.py b/src/common/logger.py index 4998eae2a..f3920138d 100644 --- a/src/common/logger.py +++ b/src/common/logger.py @@ -37,6 +37,7 @@ from cStringIO import StringIO import exceptions import gajim +import ged import sqlite3 as sqlite @@ -116,6 +117,8 @@ class Logger: # db will be created in src/common/checks_paths.py return self.attach_cache_database() + gajim.ged.register_event_handler('gc-message-received', + ged.POSTCORE, self._nec_gc_message_received) def close_db(self): if self.con: @@ -1101,3 +1104,28 @@ class Logger: return log.debug('New log received from server archives, storing it') self.write(type_, with_, message=msg, tim=tim) + + def _nec_gc_message_received(self, obj): + tim_int = int(float(time.mktime(obj.timestamp))) + if gajim.config.should_log(obj.conn.name, obj.jid) and not \ + tim_int <= obj.conn.last_history_time[obj.jid] and obj.msgtxt and \ + obj.nick: + # if not obj.nick, it means message comes from room itself + # usually it hold description and can be send at each connection + # so don't store it in logs + try: + self.write('gc_msg', obj.fjid, obj.msgtxt, tim=obj.timestamp) + # store in memory time of last message logged. + # this will also be saved in rooms_last_message_time table + # when we quit this muc + obj.conn.last_history_time[obj.jid] = time.mktime(obj.timestamp) + + except exceptions.PysqliteOperationalError, e: + self.conn.dispatch('DB_ERROR', (_('Disk Write Error'), str(e))) + except exceptions.DatabaseMalformed: + pritext = _('Database Error') + sectext = _('The database file (%s) cannot be read. Try to ' + 'repair it (see http://trac.gajim.org/wiki/DatabaseBackup) ' + 'or remove it (all history will be lost).') % \ + LOG_DB_PATH + self.conn.dispatch('DB_ERROR', (pritext, sectext)) \ No newline at end of file diff --git a/src/common/pubsub.py b/src/common/pubsub.py index a106c7b7d..d0536e40d 100644 --- a/src/common/pubsub.py +++ b/src/common/pubsub.py @@ -181,7 +181,7 @@ class ConnectionPubSub: except Exception: pass gajim.nec.push_incoming_event(PubsubReceivedEvent(None, - conn=self, iq_obj=stanza)) + conn=self, stanza=stanza)) def _nec_pubsub_bookmarks_received(self, obj): bm_jids = [b['jid'] for b in self.bookmarks] diff --git a/src/config.py b/src/config.py index 970d6ab5f..e31bf3cff 100644 --- a/src/config.py +++ b/src/config.py @@ -384,7 +384,7 @@ class PreferencesWindow: # Default Status messages self.default_msg_tree = self.xml.get_object('default_msg_treeview') col2 = self.default_msg_tree.rc_get_style().bg[gtk.STATE_ACTIVE].\ - to_string() + to_string() # (status, translated_status, message, enabled) model = gtk.ListStore(str, str, str, bool) self.default_msg_tree.set_model(model) diff --git a/src/groupchat_control.py b/src/groupchat_control.py index ecb4fc0f4..846ecc2f6 100644 --- a/src/groupchat_control.py +++ b/src/groupchat_control.py @@ -395,6 +395,8 @@ class GroupchatControl(ChatControlBase): gajim.ged.register_event_handler('gc-presence-received', ged.GUI1, self._nec_gc_presence_received) + gajim.ged.register_event_handler('gc-message-received', ged.GUI1, + self._nec_gc_message_received) gajim.gc_connected[self.account][self.room_jid] = False # disable win, we are not connected yet ChatControlBase.got_disconnected(self) @@ -808,14 +810,15 @@ class GroupchatControl(ChatControlBase): # destroy menu menu.destroy() - def on_message(self, nick, msg, tim, has_timestamp=False, xhtml=None, - status_code=[], displaymarking=None, captcha=None): - if captcha: + def _nec_gc_message_received(self, obj): + if obj.jid != self.room_jid: + return + if obj.captcha_form: if self.form_widget: self.form_widget.hide() self.form_widget.destroy() self.btn_box.destroy() - dataform = dataforms.ExtendForm(node=captcha) + dataform = dataforms.ExtendForm(node=obj.captcha_form) self.form_widget = dataforms_widget.DataFormWidget(dataform) self.form_widget.show_all() vbox = self.xml.get_object('gc_textviews_vbox') @@ -826,8 +829,7 @@ class GroupchatControl(ChatControlBase): return form_node = self.form_widget.data_form.get_purged() form_node.type = 'submit' - gajim.connections[self.account].send_captcha(self.room_jid, - form_node) + obj.conn.send_captcha(self.room_jid, form_node) self.form_widget.hide() self.form_widget.destroy() self.btn_box.destroy() @@ -846,20 +848,26 @@ class GroupchatControl(ChatControlBase): else: self.attention_flag = True helpers.play_sound('muc_message_received') - if '100' in status_code: + if '100' in obj.status_code: # Room is not anonymous self.is_anonymous = False - if not nick: + if not obj.nick: # message from server - self.print_conversation(msg, tim=tim, xhtml=xhtml, displaymarking=displaymarking) + self.print_conversation(obj.msgtxt, tim=obj.timestamp, + xhtml=obj.xhtml_msgtxt, displaymarking=obj.displaymarking) else: # message from someone - if has_timestamp: + if obj.has_timestamp: # don't print xhtml if it's an old message. # Like that xhtml messages are grayed too. - self.print_old_conversation(msg, nick, tim, None, displaymarking=displaymarking) + self.print_old_conversation(obj.msgtxt, contact=obj.nick, + tim=obj.timestamp, xhtml=None, + displaymarking=obj.displaymarking) else: - self.print_conversation(msg, nick, tim, xhtml, displaymarking=displaymarking) + self.print_conversation(obj.msgtxt, contact=obj.nick, + tim=obj.timestamp, xhtml=obj.xhtml_msgtxt, + displaymarking=obj.displaymarking) + obj.needs_highlight = self.needs_visual_notification(obj.msgtxt) def on_private_message(self, nick, msg, tim, xhtml, session, msg_id=None, encrypted=False, displaymarking=None): @@ -1706,6 +1714,8 @@ class GroupchatControl(ChatControlBase): gajim.ged.remove_event_handler('gc-presence-received', ged.GUI1, self._nec_gc_presence_received) + gajim.ged.remove_event_handler('gc-message-received', ged.GUI1, + self._nec_gc_message_received) if self.room_jid in gajim.gc_connected[self.account] and \ gajim.gc_connected[self.account][self.room_jid]: diff --git a/src/gui_interface.py b/src/gui_interface.py index 0648c302f..4968fa2b6 100644 --- a/src/gui_interface.py +++ b/src/gui_interface.py @@ -149,7 +149,7 @@ class Interface: def handle_event_http_auth(self, obj): #('HTTP_AUTH', account, (method, url, transaction_id, iq_obj, msg)) def response(account, answer): - obj.conn.build_http_auth_answer(obj.iq_obj, answer) + obj.conn.build_http_auth_answer(obj.stanza, answer) def on_yes(is_checked, obj): response(obj, 'yes') @@ -788,40 +788,6 @@ class Interface: if self.remote_ctrl: self.remote_ctrl.raise_signal('GCPresence', (account, array)) - def handle_event_gc_msg(self, account, array): - # ('GC_MSG', account, (jid, msg, time, has_timestamp, htmlmsg, - # [status_codes], displaymarking, captcha)) - jids = array[0].split('/', 1) - room_jid = jids[0] - - msg = array[1] - - gc_control = self.msg_win_mgr.get_gc_control(room_jid, account) - if not gc_control and \ - room_jid in self.minimized_controls[account]: - gc_control = self.minimized_controls[account][room_jid] - - if not gc_control: - return - xhtml = array[4] - - if gajim.config.get('ignore_incoming_xhtml'): - xhtml = None - if len(jids) == 1: - # message from server - nick = '' - else: - # message from someone - nick = jids[1] - - gc_control.on_message(nick, msg, array[2], array[3], xhtml, array[5], - displaymarking=array[6], captcha=array[7]) - - if self.remote_ctrl: - highlight = gc_control.needs_visual_notification(msg) - array += (highlight,) - self.remote_ctrl.raise_signal('GCMessage', (account, array)) - def handle_event_gc_subject(self, account, array): #('GC_SUBJECT', account, (jid, subject, body, has_timestamp)) jids = array[0].split('/', 1) @@ -943,23 +909,23 @@ class Interface: self.instances[account]['gc_config'][obj.jid].\ affiliation_list_received(obj.users_dict) - def handle_event_gc_invitation(self, account, array): + def handle_event_gc_invitation(self, obj): #('GC_INVITATION', (room_jid, jid_from, reason, password, is_continued)) - jid = gajim.get_jid_without_resource(array[1]) - room_jid = array[0] + jid = gajim.get_jid_without_resource(obj.jid_from) + account = obj.conn.name if helpers.allow_popup_window(account) or not self.systray_enabled: - dialogs.InvitationReceivedDialog(account, room_jid, jid, array[3], - array[2], is_continued=array[4]) + dialogs.InvitationReceivedDialog(account, obj.room_jid, jid, + obj.password, obj.reason, is_continued=obj.is_continued) return - self.add_event(account, jid, 'gc-invitation', (room_jid, array[2], - array[3], array[4])) + self.add_event(account, jid, 'gc-invitation', (obj.room_jid, + obj.reason, obj.password, obj.is_continued)) if helpers.allow_showing_notification(account): path = gtkgui_helpers.get_icon_path('gajim-gc_invitation', 48) event_type = _('Groupchat Invitation') notify.popup(event_type, jid, account, 'gc-invitation', path, - event_type, room_jid) + event_type, obj.room_jid) def forget_gpg_passphrase(self, keyid): if keyid in self.gpg_passphrase: @@ -1908,10 +1874,8 @@ class Interface: 'MYVCARD': [self.handle_event_myvcard], 'VCARD': [self.handle_event_vcard], 'GC_NOTIFY': [self.handle_event_gc_notify], - 'GC_MSG': [self.handle_event_gc_msg], 'GC_SUBJECT': [self.handle_event_gc_subject], 'GC_CONFIG_CHANGE': [self.handle_event_gc_config_change], - 'GC_INVITATION': [self.handle_event_gc_invitation], 'BAD_PASSPHRASE': [self.handle_event_bad_passphrase], 'CON_TYPE': [self.handle_event_con_type], 'CONNECTION_LOST': [self.handle_event_connection_lost], @@ -1959,10 +1923,11 @@ class Interface: 'ARCHIVING_CHANGED': [self.handle_event_archiving_changed], 'ARCHIVING_ERROR': [self.handle_event_archiving_error], 'bookmarks-received': [self.handle_event_bookmarks], - 'iq-error-received': [self.handle_event_iq_error], + 'gc-invitation-received': [self.handle_event_gc_invitation], 'gc-presence-received': [self.handle_event_gc_presence], 'gmail-notify': [self.handle_event_gmail_notify], 'http-auth-received': [self.handle_event_http_auth], + 'iq-error-received': [self.handle_event_iq_error], 'last-result-received': [self.handle_event_last_status_time], 'muc-admin-received': [self.handle_event_gc_affiliation], 'muc-owner-received': [self.handle_event_gc_config], @@ -3204,11 +3169,10 @@ class Interface: gajim.proxy65_manager = proxy65_manager.Proxy65Manager(gajim.idlequeue) gajim.default_session_type = ChatControlSession - # Creating Global Events Dispatcher - gajim.ged = ged.GlobalEventsDispatcher() # Creating Network Events Controller from common import nec gajim.nec = nec.NetworkEventsController() + self.create_core_handlers_list() self.register_core_handlers() diff --git a/src/remote_control.py b/src/remote_control.py index d3b5e7011..9daaefe0b 100644 --- a/src/remote_control.py +++ b/src/remote_control.py @@ -123,6 +123,8 @@ class Remote: ged.POSTGUI, self.on_subscribed_presence_received) gajim.ged.register_event_handler('unsubscribed-presence-received', ged.POSTGUI, self.on_unsubscribed_presence_received) + gajim.ged.register_event_handler('gc-message-received', + ged.POSTGUI, self.on_gc_message_received) def on_last_status_time(self, obj): self.raise_signal('LastStatusTime', (obj.conn.name, [ @@ -168,6 +170,11 @@ class Remote: def on_unsubscribed_presence_received(self, obj): self.raise_signal('Unsubscribed', (obj.conn.name, obj.jid)) + def on_gc_message_received(self, obj): + self.raise_signal('GCMessage', (obj.conn.name, [obj.fjid, obj.msgtxt, + obj.timestamp, obj.has_timestamp, obj.xhtml_msgtxt, obj.status_code, + obj.displaymarking, obj.captcha_form, obj.needs_highlight) + def raise_signal(self, signal, arg): if self.signal_object: try: