Philipp Hörist pushed to branch master at gajim / gajim
Commits:
f6739730 by Emmanuel Gil Peyrot at 2017-04-14T16:58:04+01:00
Implement chatstate in MUC, as defined in XEP-0085 §5.5.
- - - - -
a1565040 by Philipp Hörist at 2017-04-14T18:39:08+02:00
Merge branch 'muc-chatstate' into 'master'
Implement chatstate in MUC, as defined in XEP-0085 §5.5
See merge request !11
- - - - -
6 changed files:
- src/chat_control.py
- src/chat_control_base.py
- src/common/connection.py
- src/common/connection_handlers_events.py
- src/groupchat_control.py
- src/roster_window.py
Changes:
=====================================
src/chat_control.py
=====================================
--- a/src/chat_control.py
+++ b/src/chat_control.py
@@ -188,14 +188,7 @@ class ChatControl(ChatControlBase):
self.bigger_avatar_window = None
self.show_avatar()
- # chatstate timers and state
- self.reset_kbd_mouse_timeout_vars()
- self._schedule_activity_timers()
-
# Hook up signals
- id_ = self.parent_win.window.connect('motion-notify-event',
- self._on_window_motion_notify)
- self.handlers[id_] = self.parent_win.window
message_tv_buffer = self.msg_textview.get_buffer()
id_ = message_tv_buffer.connect('changed',
self._on_message_tv_buffer_changed)
@@ -672,21 +665,6 @@ class ChatControl(ChatControlBase):
cursor = gtkgui_helpers.get_cursor('HAND2')
self.parent_win.window.get_window().set_cursor(cursor)
- def _on_window_motion_notify(self, widget, event):
- """
- It gets called no matter if it is the active window or not
- """
- if self.parent_win.get_active_jid() == self.contact.jid:
- # if window is the active one, change vars assisting chatstate
- self.mouse_over_in_last_5_secs = True
- self.mouse_over_in_last_30_secs = True
-
- def _schedule_activity_timers(self):
- self.possible_paused_timeout_id = GLib.timeout_add_seconds(5,
- self.check_for_possible_paused_chatstate, None)
- self.possible_inactive_timeout_id = GLib.timeout_add_seconds(30,
- self.check_for_possible_inactive_chatstate, None)
-
def update_ui(self):
# The name banner is drawn here
ChatControlBase.update_ui(self)
@@ -976,9 +954,6 @@ class ChatControl(ChatControlBase):
if message in ('', None, '\n'):
return None
- # refresh timers
- self.reset_kbd_mouse_timeout_vars()
-
contact = self.contact
encrypted = bool(self.session) and self.session.enable_encryption
@@ -990,10 +965,8 @@ class ChatControl(ChatControlBase):
if not keyID:
keyID = 'UNKNOWN'
- chatstates_on = gajim.config.get('outgoing_chat_state_notifications') != \
- 'disabled'
chatstate_to_send = None
- if chatstates_on and contact is not None:
+ if contact is not None:
if contact.supports(NS_CHATSTATES):
# send active chatstate on every message (as XEP says)
chatstate_to_send = 'active'
@@ -1031,65 +1004,6 @@ class ChatControl(ChatControlBase):
process_commands=process_commands,
attention=attention)
- def check_for_possible_paused_chatstate(self, arg):
- """
- Did we move mouse of that window or write something in message textview
- in the last 5 seconds? If yes - we go active for mouse, composing for
- kbd. If not - we go paused if we were previously composing
- """
- contact = self.contact
- jid = contact.jid
- current_state = contact.our_chatstate
- if current_state is False: # jid doesn't support chatstates
- return False # stop looping
-
- message_buffer = self.msg_textview.get_buffer()
- if (self.kbd_activity_in_last_5_secs and
- message_buffer.get_char_count()):
- # Only composing if the keyboard activity was in text entry
- self.send_chatstate('composing', self.contact)
- elif (self.mouse_over_in_last_5_secs and
- current_state == 'inactive' and
- jid == self.parent_win.get_active_jid()):
- self.send_chatstate('active', self.contact)
- else:
- if current_state == 'composing':
- self.send_chatstate('paused', self.contact) # pause composing
-
- # assume no activity and let the motion-notify or 'insert-text' make them
- # True refresh 30 seconds vars too or else it's 30 - 5 = 25 seconds!
- self.reset_kbd_mouse_timeout_vars()
- return True # loop forever
-
- def check_for_possible_inactive_chatstate(self, arg):
- """
- Did we move mouse over that window or wrote something in message textview
- in the last 30 seconds? if yes - we go active. If no - we go inactive
- """
- contact = self.contact
-
- current_state = contact.our_chatstate
- if current_state is False: # jid doesn't support chatstates
- return False # stop looping
-
- if self.mouse_over_in_last_5_secs or self.kbd_activity_in_last_5_secs:
- return True # loop forever
-
- if not self.mouse_over_in_last_30_secs or \
- self.kbd_activity_in_last_30_secs:
- self.send_chatstate('inactive', contact)
-
- # assume no activity and let the motion-notify or 'insert-text' make them
- # True refresh 30 seconds too or else it's 30 - 5 = 25 seconds!
- self.reset_kbd_mouse_timeout_vars()
- return True # loop forever
-
- def reset_kbd_mouse_timeout_vars(self):
- self.kbd_activity_in_last_5_secs = False
- self.mouse_over_in_last_5_secs = False
- self.mouse_over_in_last_30_secs = False
- self.kbd_activity_in_last_30_secs = False
-
def on_cancel_session_negotiation(self):
msg = _('Session negotiation cancelled')
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
@@ -1391,9 +1305,6 @@ class ChatControl(ChatControlBase):
if self.session:
self.session.control = None
- # Disconnect timer callbacks
- GLib.source_remove(self.possible_paused_timeout_id)
- GLib.source_remove(self.possible_inactive_timeout_id)
# Remove bigger avatar window
if self.bigger_avatar_window:
self.bigger_avatar_window.destroy()
@@ -1482,20 +1393,6 @@ class ChatControl(ChatControlBase):
def set_control_active(self, state):
ChatControlBase.set_control_active(self, state)
- # send chatstate inactive to the one we're leaving
- # and active to the one we visit
- if state:
- message_buffer = self.msg_textview.get_buffer()
- if message_buffer.get_char_count():
- self.send_chatstate('paused', self.contact)
- else:
- self.send_chatstate('active', self.contact)
- self.reset_kbd_mouse_timeout_vars()
- GLib.source_remove(self.possible_paused_timeout_id)
- GLib.source_remove(self.possible_inactive_timeout_id)
- self._schedule_activity_timers()
- else:
- self.send_chatstate('inactive', self.contact)
# Hide bigger avatar window
if self.bigger_avatar_window:
self.bigger_avatar_window.destroy()
@@ -1580,11 +1477,8 @@ class ChatControl(ChatControlBase):
dialogs.TransformChatToMUC(self.account, [c.jid], [dropped_jid])
def _on_message_tv_buffer_changed(self, textbuffer):
- self.kbd_activity_in_last_5_secs = True
- self.kbd_activity_in_last_30_secs = True
+ super()._on_message_tv_buffer_changed(textbuffer)
if textbuffer.get_char_count():
- self.send_chatstate('composing', self.contact)
-
e2e_is_active = self.session and \
self.session.enable_encryption
e2e_pref = gajim.config.get_per('accounts', self.account,
@@ -1600,8 +1494,6 @@ class ChatControl(ChatControlBase):
elif (not self.session or not self.session.status) and \
gajim.connections[self.account].archiving_136_supported:
self.begin_archiving_negotiation()
- else:
- self.send_chatstate('active', self.contact)
def restore_conversation(self):
jid = self.contact.jid
=====================================
src/chat_control_base.py
=====================================
--- a/src/chat_control_base.py
+++ b/src/chat_control_base.py
@@ -383,6 +383,18 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
self.command_hits = []
self.last_key_tabs = False
+ # chatstate timers and state
+ self.reset_kbd_mouse_timeout_vars()
+ self._schedule_activity_timers()
+ message_tv_buffer = self.msg_textview.get_buffer()
+ id_ = message_tv_buffer.connect('changed',
+ self._on_message_tv_buffer_changed)
+ self.handlers[id_] = message_tv_buffer
+ if parent_win is not None:
+ id_ = parent_win.window.connect('motion-notify-event',
+ self._on_window_motion_notify)
+ self.handlers[id_] = parent_win.window
+
# PluginSystem: adding GUI extension point for ChatControlBase
# instance object (also subclasses, eg. ChatControl or GroupchatControl)
gajim.plugin_manager.gui_extension_point('chat_control_base', self)
@@ -448,6 +460,9 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
def shutdown(self):
super(ChatControlBase, self).shutdown()
+ # Disconnect timer callbacks
+ GLib.source_remove(self.possible_paused_timeout_id)
+ GLib.source_remove(self.possible_inactive_timeout_id)
# PluginSystem: removing GUI extension points connected with ChatControlBase
# instance object
gajim.plugin_manager.remove_gui_extension_point('chat_control_base',
@@ -683,6 +698,12 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
if process_commands and self.process_as_command(message):
return
+ # refresh timers
+ self.reset_kbd_mouse_timeout_vars()
+
+ if gajim.config.get('outgoing_chat_state_notifications') == 'disabled':
+ chatstate = None
+
label = self.get_seclabel()
def _cb(obj, msg, cb, *cb_args):
@@ -712,6 +733,88 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
message_buffer = self.msg_textview.get_buffer()
message_buffer.set_text('') # clear message buffer (and tv of course)
+ def check_for_possible_paused_chatstate(self, arg):
+ """
+ Did we move mouse of that window or write something in message textview
+ in the last 5 seconds? If yes - we go active for mouse, composing for
+ kbd. If not - we go paused if we were previously composing
+ """
+ contact = self.contact
+ jid = contact.jid
+ current_state = contact.our_chatstate
+ if current_state is False: # jid doesn't support chatstates
+ return False # stop looping
+
+ message_buffer = self.msg_textview.get_buffer()
+ if (self.kbd_activity_in_last_5_secs and
+ message_buffer.get_char_count()):
+ # Only composing if the keyboard activity was in text entry
+ self.send_chatstate('composing', self.contact)
+ elif (self.mouse_over_in_last_5_secs and
+ current_state == 'inactive' and
+ jid == self.parent_win.get_active_jid()):
+ self.send_chatstate('active', self.contact)
+ else:
+ if current_state == 'composing':
+ self.send_chatstate('paused', self.contact) # pause composing
+
+ # assume no activity and let the motion-notify or 'insert-text' make them
+ # True refresh 30 seconds vars too or else it's 30 - 5 = 25 seconds!
+ self.reset_kbd_mouse_timeout_vars()
+ return True # loop forever
+
+ def check_for_possible_inactive_chatstate(self, arg):
+ """
+ Did we move mouse over that window or wrote something in message textview
+ in the last 30 seconds? if yes - we go active. If no - we go inactive
+ """
+ contact = self.contact
+
+ current_state = contact.our_chatstate
+ if current_state is False: # jid doesn't support chatstates
+ return False # stop looping
+
+ if self.mouse_over_in_last_5_secs or self.kbd_activity_in_last_5_secs:
+ return True # loop forever
+
+ if not self.mouse_over_in_last_30_secs or \
+ self.kbd_activity_in_last_30_secs:
+ self.send_chatstate('inactive', contact)
+
+ # assume no activity and let the motion-notify or 'insert-text' make them
+ # True refresh 30 seconds too or else it's 30 - 5 = 25 seconds!
+ self.reset_kbd_mouse_timeout_vars()
+ return True # loop forever
+
+ def _schedule_activity_timers(self):
+ self.possible_paused_timeout_id = GLib.timeout_add_seconds(5,
+ self.check_for_possible_paused_chatstate, None)
+ self.possible_inactive_timeout_id = GLib.timeout_add_seconds(30,
+ self.check_for_possible_inactive_chatstate, None)
+
+ def reset_kbd_mouse_timeout_vars(self):
+ self.kbd_activity_in_last_5_secs = False
+ self.mouse_over_in_last_5_secs = False
+ self.mouse_over_in_last_30_secs = False
+ self.kbd_activity_in_last_30_secs = False
+
+ def _on_window_motion_notify(self, widget, event):
+ """
+ It gets called no matter if it is the active window or not
+ """
+ if self.parent_win.get_active_jid() == self.contact.jid:
+ # if window is the active one, change vars assisting chatstate
+ self.mouse_over_in_last_5_secs = True
+ self.mouse_over_in_last_30_secs = True
+
+ def _on_message_tv_buffer_changed(self, textbuffer):
+ self.kbd_activity_in_last_5_secs = True
+ self.kbd_activity_in_last_30_secs = True
+ if textbuffer.get_char_count():
+ self.send_chatstate('composing', self.contact)
+ else:
+ self.send_chatstate('active', self.contact)
+
def save_message(self, message, msg_type):
# save the message, so user can scroll though the list with key up/down
if msg_type == 'sent':
@@ -982,6 +1085,19 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
types=type_):
# There were events to remove
self.redraw_after_event_removed(jid)
+ # send chatstate inactive to the one we're leaving
+ # and active to the one we visit
+ message_buffer = self.msg_textview.get_buffer()
+ if message_buffer.get_char_count():
+ self.send_chatstate('paused', self.contact)
+ else:
+ self.send_chatstate('active', self.contact)
+ self.reset_kbd_mouse_timeout_vars()
+ GLib.source_remove(self.possible_paused_timeout_id)
+ GLib.source_remove(self.possible_inactive_timeout_id)
+ self._schedule_activity_timers()
+ else:
+ self.send_chatstate('inactive', self.contact)
def scroll_to_end_iter(self):
self.conv_textview.scroll_to_end_iter()
=====================================
src/common/connection.py
=====================================
--- a/src/common/connection.py
+++ b/src/common/connection.py
@@ -2719,6 +2719,8 @@ class Connection(CommonConnection, ConnectionHandlers):
obj.xhtml = create_xhtml(obj.message)
msg_iq = nbxmpp.Message(obj.jid, obj.message, typ='groupchat',
xhtml=obj.xhtml)
+ if obj.chatstate:
+ msg_iq.setTag(obj.chatstate, namespace=nbxmpp.NS_CHATSTATES)
if obj.label is not None:
msg_iq.addChild(node=obj.label)
gajim.nec.push_incoming_event(GcStanzaMessageOutgoingEvent(
=====================================
src/common/connection_handlers_events.py
=====================================
--- a/src/common/connection_handlers_events.py
+++ b/src/common/connection_handlers_events.py
@@ -2769,6 +2769,7 @@ class GcMessageOutgoingEvent(nec.NetworkOutgoingEvent):
def init(self):
self.additional_data = {}
self.message = ''
+ self.chatstate = None
self.xhtml = None
self.label = None
self.callback = None
=====================================
src/groupchat_control.py
=====================================
--- a/src/groupchat_control.py
+++ b/src/groupchat_control.py
@@ -343,7 +343,7 @@ class GroupchatControl(ChatControlBase):
img.set_from_icon_name('document-open-recent', Gtk.IconSize.MENU)
self.current_tooltip = None
- if parent_win:
+ if parent_win is not None:
# On AutoJoin with minimize Groupchats are created without parent
# Tooltip Window has to be created with parent
self.set_tooltip()
@@ -2035,6 +2035,53 @@ class GroupchatControl(ChatControlBase):
del win._controls[self.account][self.contact.jid]
+ def send_chatstate(self, state, contact):
+ """
+ Send OUR chatstate as STANDLONE chat state message (eg. no body)
+ to contact only if new chatstate is different from the previous one
+ if jid is not specified, send to active tab
+ """
+ # JEP 85 does not allow resending the same chatstate
+ # this function checks for that and just returns so it's safe to call it
+ # with same state.
+
+ # This functions also checks for violation in state transitions
+ # and raises RuntimeException with appropriate message
+ # more on that http://xmpp.org/extensions/xep-0085.html#statechart
+
+ # do not send if we have chat state notifications disabled
+ # that means we won't reply to the <active/> from other peer
+ # so we do not broadcast jep85 capabalities
+ chatstate_setting = gajim.config.get('outgoing_chat_state_notifications')
+ if chatstate_setting == 'disabled':
+ return
+
+ elif chatstate_setting == 'composing_only' and state != 'active' and\
+ state != 'composing':
+ return
+
+ # if the new state we wanna send (state) equals
+ # the current state (contact.our_chatstate) then return
+ if contact.our_chatstate == state:
+ return
+
+ # if wel're inactive prevent composing (XEP violation)
+ if contact.our_chatstate == 'inactive' and state == 'composing':
+ # go active before
+ gajim.nec.push_outgoing_event(GcMessageOutgoingEvent(None,
+ account=self.account, jid=self.contact.jid, chatstate='active',
+ control=self))
+ contact.our_chatstate = 'active'
+ self.reset_kbd_mouse_timeout_vars()
+
+ gajim.nec.push_outgoing_event(GcMessageOutgoingEvent(None,
+ account=self.account, jid=self.contact.jid, chatstate=state,
+ control=self))
+
+ contact.our_chatstate = state
+ if state == 'active':
+ self.reset_kbd_mouse_timeout_vars()
+
def shutdown(self, status='offline'):
# PluginSystem: calling shutdown of super class (ChatControlBase)
# to let it remove it's GUI extension points
=====================================
src/roster_window.py
=====================================
--- a/src/roster_window.py
+++ b/src/roster_window.py
@@ -3215,6 +3215,9 @@ class RosterWindow:
if not mw:
mw = gajim.interface.msg_win_mgr.create_window(ctrl.contact,
ctrl.account, ctrl.type_id)
+ id_ = mw.window.connect('motion-notify-event',
+ ctrl._on_window_motion_notify)
+ ctrl.handlers[id_] = mw.window
ctrl.parent_win = mw
ctrl.set_tooltip()
mw.new_tab(ctrl)
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/78b562f7a53770e2fc895e9e9833d202c…
Philipp Hörist pushed to branch master at gajim / gajim
Commits:
a2785ba3 by Philipp Hörist at 2017-04-12T22:39:55+02:00
Add version check for python-gnupg
- - - - -
78b562f7 by Philipp Hörist at 2017-04-12T22:50:02+02:00
Make PGP encoding configurable
python-gnupg uses latin1 as default encoding because GPG itself uses
latin1 as default.
We should not override this default with getpreferredencoding, because
getpreferredencoding maybe returns something else than what GPG is configured
on that system.
Example: On Windows
GPG is run in default mode with 'latin1'
getpreferredencoding returns 'cp1252'
The approach would be now to default to latin1 as it is GPGs default.
And if the User sets a different ecoding for GPG he has to set it in
Gajim aswell.
- - - - -
3 changed files:
- src/common/config.py
- src/common/gajim.py
- src/common/gpg.py
Changes:
=====================================
src/common/config.py
=====================================
--- a/src/common/config.py
+++ b/src/common/config.py
@@ -315,6 +315,7 @@ class Config:
'positive_184_ack': [ opt_bool, False, _('If enabled, Gajim will show an icon to show that sent message has been received by your contact')],
'show_avatar_in_tabs': [ opt_bool, False, _('Show a mini avatar in chat window tabs and in window icon')],
'use_keyring': [opt_bool, True, _('If True, Gajim will use the Systems Keyring to store account passwords.')],
+ 'pgp_encoding': [ opt_str, '', _('Sets the encoding used by python-gnupg'), True],
}, {})
__options_per_key = {
=====================================
src/common/gajim.py
=====================================
--- a/src/common/gajim.py
+++ b/src/common/gajim.py
@@ -32,6 +32,7 @@ import logging
import locale
import gi
import uuid
+from distutils.version import LooseVersion as V
from common import config
import nbxmpp
@@ -165,7 +166,19 @@ except ImportError:
HAVE_GPG = True
GPG_BINARY = 'gpg'
try:
- __import__('gnupg')
+ import gnupg
+ '''
+ We need https://pypi.python.org/pypi/python-gnupg
+ but https://pypi.python.org/pypi/gnupg shares the same package name.
+ It cannot be used as a drop-in replacement.
+ We test with a version check if python-gnupg is installed as it is
+ on a much lower version number than gnupg
+ Also we need at least python-gnupg 0.3.8
+ '''
+ v_gnupg = gnupg.__version__
+ if V(v_gnupg) < V('0.3.8') or V(v_gnupg) > V('1.0.0'):
+ log.info('Gajim needs python-gnupg >= 0.3.8')
+ HAVE_GPG = False
except ImportError:
HAVE_GPG = False
else:
=====================================
src/common/gpg.py
=====================================
--- a/src/common/gpg.py
+++ b/src/common/gpg.py
@@ -22,9 +22,10 @@
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
##
-from common.gajim import HAVE_GPG, GPG_BINARY
import os
import logging
+from common import gajim
+from common.gajim import HAVE_GPG, GPG_BINARY
if HAVE_GPG:
import gnupg
@@ -33,7 +34,9 @@ if HAVE_GPG:
class GnuPG(gnupg.GPG):
def __init__(self, use_agent=False):
gnupg.GPG.__init__(self, gpgbinary=GPG_BINARY)
- self.encoding = 'utf-8'
+ encoding = gajim.config.get('pgp_encoding')
+ if encoding:
+ self.encoding = encoding
self.decode_errors = 'replace'
self.passphrase = None
self.use_agent = use_agent
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/a51ea32dc63d716d9fb1461cd96159cc8…
Philipp Hörist pushed to branch master at gajim / gajim
Commits:
54eb1cbb by Philipp Hörist at 2017-04-12T22:30:28+02:00
Simplify log_message()
- Pass EventObj instead of variables
- decrease indent level
- check all conditions inside log_message() not before calling
- fixed bug where gc private messages where not logged with the correct jid
- - - - -
a51ea32d by Philipp Hörist at 2017-04-12T22:30:55+02:00
Refactor exception handling for logger
- Handle exceptions inside write() instead of propagating the
exception
- Add error message to exception
- Add dispatch() method in logger
- - - - -
10 changed files:
- src/chat_control.py
- src/common/connection.py
- src/common/connection_handlers.py
- src/common/connection_handlers_events.py
- src/common/exceptions.py
- src/common/logger.py
- src/common/zeroconf/connection_zeroconf.py
- src/gajim.py
- src/gui_interface.py
- src/session.py
Changes:
=====================================
src/chat_control.py
=====================================
--- a/src/chat_control.py
+++ b/src/chat_control.py
@@ -1623,14 +1623,9 @@ class ChatControl(ChatControlBase):
pending_how_many += len(gajim.events.get_events(self.account,
self.contact.get_full_jid(), ['chat', 'pm']))
- try:
- rows = gajim.logger.get_last_conversation_lines(jid, restore_how_many,
- pending_how_many, timeout, self.account)
- except exceptions.DatabaseMalformed:
- dialogs.ErrorDialog(_('Database Error'),
- _('The database file (%s) cannot be read. Try to repair it or '
- 'remove it (all history will be lost).') % logger.LOG_DB_PATH)
- rows = []
+ rows = gajim.logger.get_last_conversation_lines(jid, restore_how_many,
+ pending_how_many, timeout, self.account)
+
local_old_kind = None
self.conv_textview.just_cleared = True
for row in rows: # row[0] time, row[1] has kind, row[2] the message, row[3] subject, row[4] additional_data
=====================================
src/common/connection.py
=====================================
--- a/src/common/connection.py
+++ b/src/common/connection.py
@@ -507,37 +507,32 @@ class CommonConnection:
gajim.nec.push_incoming_event(
StanzaMessageOutgoingEvent(None, **vars(obj)))
- def log_message(self, jid, msg, forward_from, session, original_message,
- subject, type_, xhtml=None, additional_data=None):
- if additional_data is None:
- additional_data = {}
- if not forward_from and session and session.is_loggable():
- ji = gajim.get_jid_without_resource(jid)
- if gajim.config.should_log(self.name, ji):
- log_msg = msg
- if original_message is not None:
- log_msg = original_message
- if log_msg:
- if type_ == 'chat':
- kind = 'chat_msg_sent'
- else:
- kind = 'single_msg_sent'
- try:
- if xhtml and gajim.config.get('log_xhtml_messages'):
- log_msg = '<body xmlns="%s">%s</body>' % (
- nbxmpp.NS_XHTML, xhtml)
- gajim.logger.write(kind, jid, log_msg, subject=subject, additional_data=additional_data)
- except exceptions.PysqliteOperationalError as e:
- self.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).') % \
- common.logger.LOG_DB_PATH
- self.dispatch('DB_ERROR', (pritext, sectext))
+ def log_message(self, obj):
+ if not obj.is_loggable:
+ return
+
+ if obj.forward_from or not obj.session or not obj.session.is_loggable():
+ return
+
+ if not gajim.config.should_log(self.name, obj.jid):
+ return
+
+ if obj.xhtml and gajim.config.get('log_xhtml_messages'):
+ message = '<body xmlns="%s">%s</body>' % (nbxmpp.NS_XHTML,
+ obj.xhtml)
+ else:
+ message = obj.original_message or obj.message
+ if not message:
+ return
+
+ if obj.type_ == 'chat':
+ kind = 'chat_msg_sent'
+ else:
+ kind = 'single_msg_sent'
+
+ gajim.logger.write(
+ kind, obj.jid, message, subject=obj.subject,
+ additional_data=obj.additional_data)
def ack_subscribed(self, jid):
"""
@@ -2136,21 +2131,13 @@ class Connection(CommonConnection, ConnectionHandlers):
if obj.callback:
obj.callback(obj, obj.msg_iq, *obj.callback_args)
- if not obj.is_loggable:
- return
if isinstance(obj.jid, list):
for j in obj.jid:
if obj.session is None:
obj.session = self.get_or_create_session(j, '')
- self.log_message(
- j, obj.message, obj.forward_from, obj.session,
- obj.original_message, obj.subject, obj.type_, obj.xhtml,
- obj.additional_data)
+ self.log_message(obj)
else:
- self.log_message(
- obj.jid, obj.message, obj.forward_from, obj.session,
- obj.original_message, obj.subject, obj.type_, obj.xhtml,
- obj.additional_data)
+ self.log_message(obj)
def send_contacts(self, contacts, fjid, type_='message'):
"""
=====================================
src/common/connection_handlers.py
=====================================
--- a/src/common/connection_handlers.py
+++ b/src/common/connection_handlers.py
@@ -1069,17 +1069,7 @@ class ConnectionHandlersBase:
if gajim.config.get('log_contact_status_changes') and \
gajim.config.should_log(self.name, obj.jid):
- try:
- gajim.logger.write('status', obj.jid, obj.status, obj.show)
- except exceptions.PysqliteOperationalError as e:
- self.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.dispatch('DB_ERROR', (pritext, sectext))
- our_jid = gajim.get_jid_from_account(self.name)
+ gajim.logger.write('status', obj.jid, obj.status, obj.show)
def _nec_gc_presence_received(self, obj):
if obj.conn.name != self.name:
@@ -1244,18 +1234,8 @@ class ConnectionHandlersBase:
subject = msg.getSubject()
if session.is_loggable():
- try:
- gajim.logger.write('error', frm, error_msg, tim=tim,
- subject=subject)
- except exceptions.PysqliteOperationalError as e:
- self.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).') % \
- common.logger.LOG_DB_PATH
- self.dispatch('DB_ERROR', (pritext, sectext))
+ gajim.logger.write('error', frm, error_msg, tim=tim,
+ subject=subject)
gajim.nec.push_incoming_event(MessageErrorEvent(None, conn=self,
fjid=frm, error_code=msg.getErrorCode(), error_msg=error_msg,
msg=msgtxt, time_=tim, session=session, stanza=msg))
=====================================
src/common/connection_handlers_events.py
=====================================
--- a/src/common/connection_handlers_events.py
+++ b/src/common/connection_handlers_events.py
@@ -946,18 +946,7 @@ class GcPresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
if jid:
# we know real jid, save it in db
st += ' (%s)' % jid
- try:
- gajim.logger.write('gcstatus', self.fjid, st, self.show)
- except exceptions.PysqliteOperationalError as 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))
+ gajim.logger.write('gcstatus', self.fjid, st, self.show)
if self.avatar_sha == '':
# contact has no avatar
puny_nick = helpers.sanitize_filename(self.nick)
=====================================
src/common/exceptions.py
=====================================
--- a/src/common/exceptions.py
+++ b/src/common/exceptions.py
@@ -38,11 +38,15 @@ class DatabaseMalformed(Exception):
The databas can't be read
"""
- def __init__(self):
+ def __init__(self, path=''):
Exception.__init__(self)
+ self.path = path
def __str__(self):
- return _('Database cannot be read.')
+ return _('The database file (%s) cannot be read. '
+ 'Try to repair it (see '
+ 'https://dev.gajim.org/gajim/gajim/wikis/help/DatabaseBackup)'
+ ' or remove it (all history will be lost).') % self.path
class ServiceNotAvailable(Exception):
"""
=====================================
src/common/logger.py
=====================================
--- a/src/common/logger.py
+++ b/src/common/logger.py
@@ -121,6 +121,9 @@ class Logger:
gajim.ged.register_event_handler('gc-message-received',
ged.POSTCORE, self._nec_gc_message_received)
+ def dispatch(self, event, error):
+ gajim.ged.raise_event(event, None, str(error))
+
def close_db(self):
if self.con:
self.con.close()
@@ -191,7 +194,7 @@ class Logger:
# list of tuples: [('aaa@bbb',), ('cc@dd',)]
rows = self.cur.fetchall()
except sqlite.DatabaseError:
- raise exceptions.DatabaseMalformed
+ raise exceptions.DatabaseMalformed(LOG_DB_PATH)
self.jids_already_in = []
for row in rows:
# row[0] is first item of row (the only result here, the jid)
@@ -416,7 +419,7 @@ class Logger:
except sqlite.OperationalError as e:
raise exceptions.PysqliteOperationalError(str(e))
except sqlite.DatabaseError:
- raise exceptions.DatabaseMalformed
+ raise exceptions.DatabaseMalformed(LOG_DB_PATH)
message_id = None
if write_unread:
try:
@@ -531,58 +534,53 @@ class Logger:
show)
write_unread = False
-
- # now we may have need to do extra care for some values in columns
- if kind == 'status': # we store (not None) time, jid, show, msg
- # status for roster items
- try:
+ try:
+ # now we may have need to do extra care for some values in columns
+ if kind == 'status': # we store (not None) time, jid, show, msg
+ # status for roster items
jid_id = self.get_jid_id(jid)
- except exceptions.PysqliteOperationalError as e:
- raise exceptions.PysqliteOperationalError(str(e))
- if show is None: # show is None (xmpp), but we say that 'online'
- show_col = ShowConstant.ONLINE
+ if show is None: # show is None (xmpp), but we say that 'online'
+ show_col = ShowConstant.ONLINE
+
+ elif kind == 'gcstatus':
+ # status in ROOM (for pm status see status)
+ if show is None: # show is None (xmpp), but we say that 'online'
+ show_col = ShowConstant.ONLINE
+ jid, nick = jid.split('/', 1)
- elif kind == 'gcstatus':
- # status in ROOM (for pm status see status)
- if show is None: # show is None (xmpp), but we say that 'online'
- show_col = ShowConstant.ONLINE
- jid, nick = jid.split('/', 1)
- try:
# re-get jid_id for the new jid
jid_id = self.get_jid_id(jid, 'ROOM')
- except exceptions.PysqliteOperationalError as e:
- raise exceptions.PysqliteOperationalError(str(e))
- contact_name_col = nick
+ contact_name_col = nick
+
+ elif kind == 'gc_msg':
+ if jid.find('/') != -1: # if it has a /
+ jid, nick = jid.split('/', 1)
+ else:
+ # it's server message f.e. error message
+ # when user tries to ban someone but he's not allowed to
+ nick = None
- elif kind == 'gc_msg':
- if jid.find('/') != -1: # if it has a /
- jid, nick = jid.split('/', 1)
- else:
- # it's server message f.e. error message
- # when user tries to ban someone but he's not allowed to
- nick = None
- try:
# re-get jid_id for the new jid
jid_id = self.get_jid_id(jid, 'ROOM')
- except exceptions.PysqliteOperationalError as e:
- raise exceptions.PysqliteOperationalError(str(e))
- contact_name_col = nick
- else:
- try:
+
+ contact_name_col = nick
+ else:
jid_id = self.get_jid_id(jid)
- except exceptions.PysqliteOperationalError as e:
- raise exceptions.PysqliteOperationalError(str(e))
- if kind == 'chat_msg_recv':
- if not self.jid_is_from_pm(jid) and not mam_query:
- # Save in unread table only if it's not a pm
- write_unread = True
-
- if show_col == 'UNKNOWN': # unknown show, do not log
- return
+ if kind == 'chat_msg_recv':
+ if not self.jid_is_from_pm(jid) and not mam_query:
+ # Save in unread table only if it's not a pm
+ write_unread = True
- values = (jid_id, contact_name_col, time_col, kind_col, show_col,
- message_col, subject_col, additional_data_col)
- return self.commit_to_db(values, write_unread)
+ if show_col == 'UNKNOWN': # unknown show, do not log
+ return
+
+ values = (jid_id, contact_name_col, time_col, kind_col, show_col,
+ message_col, subject_col, additional_data_col)
+ return self.commit_to_db(values, write_unread)
+
+ except (exceptions.DatabaseMalformed,
+ exceptions.PysqliteOperationalError) as error:
+ self.dispatch('DB_ERROR', error)
def get_last_conversation_lines(self, jid, restore_how_many_rows,
pending_how_many, timeout, account):
@@ -621,7 +619,9 @@ class Logger:
parsed_entry = entry[:4] + (additional_data, ) + entry[5:]
messages.append(parsed_entry)
except sqlite.DatabaseError:
- raise exceptions.DatabaseMalformed
+ self.dispatch('DB_ERROR',
+ exceptions.DatabaseMalformed(LOG_DB_PATH))
+ return []
messages.reverse()
return messages
@@ -1186,19 +1186,8 @@ class Logger:
# 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, additional_data=obj.additional_data)
- # 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] = tim_f
-
- except exceptions.PysqliteOperationalError as e:
- obj.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
- obj.conn.dispatch('DB_ERROR', (pritext, sectext))
+ self.write('gc_msg', obj.fjid, obj.msgtxt, tim=obj.timestamp, additional_data=obj.additional_data)
+ # 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] = tim_f
=====================================
src/common/zeroconf/connection_zeroconf.py
=====================================
--- a/src/common/zeroconf/connection_zeroconf.py
+++ b/src/common/zeroconf/connection_zeroconf.py
@@ -342,10 +342,7 @@ class ConnectionZeroconf(CommonConnection, ConnectionHandlersZeroconf):
if obj.callback:
obj.callback(obj.msg_iq, *obj.callback_args)
- if not obj.is_loggable:
- return
- self.log_message(obj.jid, obj.message, obj.forward_from,
- obj.session, obj.original_message, obj.subject, obj.type_)
+ self.log_message(obj)
def on_send_not_ok(reason):
reason += ' ' + _('Your message could not be sent.')
=====================================
src/gajim.py
=====================================
--- a/src/gajim.py
+++ b/src/gajim.py
@@ -142,17 +142,14 @@ class GajimApplication(Gtk.Application):
gajim.logger = logger.Logger()
caps_cache.initialize(gajim.logger)
check_paths.check_and_possibly_create_paths()
- except exceptions.DatabaseMalformed:
+ except exceptions.DatabaseMalformed as error:
dlg = Gtk.MessageDialog(
None,
Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL,
Gtk.MessageType.ERROR,
Gtk.ButtonsType.OK,
_('Database Error'))
- dlg.format_secondary_text(
- _('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).') % gajim.gajimpaths['LOG_DB'])
+ dlg.format_secondary_text(str(error))
dlg.run()
dlg.destroy()
sys.exit()
=====================================
src/gui_interface.py
=====================================
--- a/src/gui_interface.py
+++ b/src/gui_interface.py
@@ -109,11 +109,11 @@ class Interface:
### Methods handling events from connection
################################################################################
- def handle_event_db_error(self, unused, data):
- #('DB_ERROR', account, (title_text, section_text))
+ def handle_event_db_error(self, unused, error):
+ #('DB_ERROR', account, error)
if self.db_error_dialog:
return
- self.db_error_dialog = dialogs.ErrorDialog(data[0], data[1])
+ self.db_error_dialog = dialogs.ErrorDialog(_('Database Error'), error)
def destroyed(win):
self.db_error_dialog = None
self.db_error_dialog.connect('destroy', destroyed)
=====================================
src/session.py
=====================================
--- a/src/session.py
+++ b/src/session.py
@@ -95,26 +95,12 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
log_type += end
if self.is_loggable() and obj.msgtxt:
- try:
- if obj.xhtml and gajim.config.get('log_xhtml_messages'):
- msg_to_log = obj.xhtml
- else:
- msg_to_log = obj.msgtxt
- obj.msg_log_id = gajim.logger.write(log_type, obj.fjid,
- msg_to_log, tim=obj.timestamp, subject=obj.subject, additional_data=obj.additional_data)
- except exceptions.PysqliteOperationalError as e:
- gajim.nec.push_incoming_event(InformationEvent(None,
- conn=self.conn, level='error', pri_txt=_('Disk Write Error'),
- sec_txt=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).') % \
- gajim.logger.LOG_DB_PATH
- gajim.nec.push_incoming_event(InformationEvent(None,
- conn=self.conn, level='error', pri_txt=pritext,
- sec_txt=sectext))
+ if obj.xhtml and gajim.config.get('log_xhtml_messages'):
+ msg_to_log = obj.xhtml
+ else:
+ msg_to_log = obj.msgtxt
+ obj.msg_log_id = gajim.logger.write(log_type, obj.fjid,
+ msg_to_log, tim=obj.timestamp, subject=obj.subject, additional_data=obj.additional_data)
treat_as = gajim.config.get('treat_incoming_messages')
if treat_as:
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/8a789763a27813ae9cb5be70756ee1be1…
Philipp Hörist pushed to branch gajim_0.16 at gajim / gajim
Commits:
beaa82cf by Philipp Hörist at 2017-04-10T23:32:07+02:00
Correctly publish zeroconf txt data
Fixes #8532
- - - - -
1 changed file:
- src/common/zeroconf/zeroconf_bonjour.py
Changes:
=====================================
src/common/zeroconf/zeroconf_bonjour.py
=====================================
--- a/src/common/zeroconf/zeroconf_bonjour.py
+++ b/src/common/zeroconf/zeroconf_bonjour.py
@@ -43,7 +43,7 @@ class Zeroconf:
self.port = port # listening port that gets announced
self.username = name
self.host = host
- self.txt = pybonjour.TXTRecord() # service data
+ self.txt = {} # service data
# XXX these CBs should be set to None when we destroy the object
# (go offline), because they create a circular reference
@@ -245,7 +245,7 @@ class Zeroconf:
txt = {}
#remove empty keys
- for key, val in self.txt:
+ for key, val in self.txt.iteritems():
if val:
txt[key] = val
@@ -259,13 +259,12 @@ class Zeroconf:
else:
txt['status'] = 'avail'
- self.txt = pybonjour.TXTRecord(txt, strict=True)
try:
self.service_sdRef = pybonjour.DNSServiceRegister(
name=self.name,
regtype=self.stype,
port=self.port,
- txtRecord=self.txt,
+ txtRecord=pybonjour.TXTRecord(txt),
callBack=self.service_added_callback)
log.info('Publishing service %s of type %s' % (self.name, self.stype))
View it on GitLab: https://dev.gajim.org/gajim/gajim/commit/beaa82cfd6f2b5d317952bba9dcbec3dcb…
Philipp Hörist pushed to branch gajim_0.16 at gajim / gajim
Commits:
3cd3598b by Philipp Hörist at 2017-04-10T21:27:55+02:00
Always send message delivery receipts requests
- We want to send requests also to offline contacts.
- The XEP is wide spread chances are high that a contact supports it.
- It gets really complicated, when we want to guess if a offline contact supports receipts
- - - - -
42dba38b by Philipp Hörist at 2017-04-10T21:51:55+02:00
Dont show warning on missing 0184 receipt
https://xmpp.org/extensions/xep-0184.html#what tells us that we
SHOULD NOT impute any meaning to the fact that we did not receive an ack message
- - - - -
5 changed files:
- src/chat_control.py
- src/common/caps_cache.py
- src/common/connection.py
- src/common/connection_handlers.py
- src/conversation_textview.py
Changes:
=====================================
src/chat_control.py
=====================================
--- a/src/chat_control.py
+++ b/src/chat_control.py
@@ -53,7 +53,7 @@ from common.stanza_session import EncryptedStanzaSession, ArchivingStanzaSession
from common.contacts import GC_Contact
from common.logger import constants
from nbxmpp.protocol import NS_XHTML, NS_XHTML_IM, NS_FILE, NS_MUC
-from nbxmpp.protocol import NS_RECEIPTS, NS_ESESSION
+from nbxmpp.protocol import NS_ESESSION
from nbxmpp.protocol import NS_JINGLE_RTP_AUDIO, NS_JINGLE_RTP_VIDEO
from nbxmpp.protocol import NS_JINGLE_ICE_UDP, NS_JINGLE_FILE_TRANSFER
from nbxmpp.protocol import NS_CHATSTATES
@@ -937,7 +937,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
displaymarking=displaymarking)
if xep0184_id is not None:
- textview.show_xep0184_warning(xep0184_id)
+ textview.add_xep0184_mark(xep0184_id)
if not count_as_new:
return
@@ -2382,8 +2382,7 @@ class ChatControl(ChatControlBase):
id_ = msg_stanza.getID()
xep0184_id = None
if self.contact.jid != gajim.get_jid_from_account(self.account):
- if self.contact.supports(NS_RECEIPTS) and gajim.config.get_per(
- 'accounts', self.account, 'request_receipt'):
+ if gajim.config.get_per('accounts', self.account, 'request_receipt'):
xep0184_id = id_
if label:
displaymarking = label.getTag('displaymarking')
=====================================
src/common/caps_cache.py
=====================================
--- a/src/common/caps_cache.py
+++ b/src/common/caps_cache.py
@@ -37,11 +37,11 @@ import hashlib
import logging
log = logging.getLogger('gajim.c.caps_cache')
-from nbxmpp import (NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION, NS_CHATSTATES,
+from nbxmpp import (NS_XHTML_IM, NS_ESESSION, NS_CHATSTATES,
NS_JINGLE_ICE_UDP, NS_JINGLE_RTP_AUDIO, NS_JINGLE_RTP_VIDEO,
NS_JINGLE_FILE_TRANSFER)
# Features where we cannot safely assume that the other side supports them
-FEATURE_BLACKLIST = [NS_CHATSTATES, NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION,
+FEATURE_BLACKLIST = [NS_CHATSTATES, NS_XHTML_IM, NS_ESESSION,
NS_JINGLE_ICE_UDP, NS_JINGLE_RTP_AUDIO, NS_JINGLE_RTP_VIDEO,
NS_JINGLE_FILE_TRANSFER]
=====================================
src/common/connection.py
=====================================
--- a/src/common/connection.py
+++ b/src/common/connection.py
@@ -506,8 +506,7 @@ class CommonConnection:
# XEP-0184
if jid != gajim.get_jid_from_account(self.name):
if msgtxt and gajim.config.get_per('accounts', self.name,
- 'request_receipt') and contact and contact.supports(
- nbxmpp.NS_RECEIPTS):
+ 'request_receipt'):
msg_iq.setTag('request', namespace=nbxmpp.NS_RECEIPTS)
if forward_from:
=====================================
src/common/connection_handlers.py
=====================================
--- a/src/common/connection_handlers.py
+++ b/src/common/connection_handlers.py
@@ -1236,7 +1236,7 @@ class ConnectionHandlersBase:
if not id_:
# old XEP implementation
id_ = obj.id_
- ctrl.conv_textview.hide_xep0184_warning(id_)
+ ctrl.conv_textview.show_xep0184_ack(id_)
if obj.mtype == 'error':
if not obj.msgtxt:
=====================================
src/conversation_textview.py
=====================================
--- a/src/conversation_textview.py
+++ b/src/conversation_textview.py
@@ -210,7 +210,6 @@ class ConversationTextview(gobject.GObject):
self.images = []
self.image_cache = {}
self.xep0184_marks = {}
- self.xep0184_shown = {}
self.last_sent_message_marks = [None, None]
# A pair per occupant. Key is '' in normal chat
self.last_received_message_marks = {}
@@ -318,9 +317,6 @@ class ConversationTextview(gobject.GObject):
buffer_.create_tag('focus-out-line', justification = gtk.JUSTIFY_CENTER)
self.displaymarking_tags = {}
- tag = buffer_.create_tag('xep0184-warning')
- tag.set_property('foreground', '#cc0000')
-
tag = buffer_.create_tag('xep0184-received')
tag.set_property('foreground', '#73d216')
@@ -333,8 +329,6 @@ class ConversationTextview(gobject.GObject):
# holds a mark at the end of --- line
self.focus_out_end_mark = None
- self.xep0184_warning_tooltip = tooltips.BaseTooltip()
-
self.line_tooltip = tooltips.BaseTooltip()
self.smooth_id = None
self.just_cleared = False
@@ -507,59 +501,32 @@ class ConversationTextview(gobject.GObject):
self.last_received_message_marks[name][1] = buffer_.create_mark(None, i2,
left_gravity=True)
- def show_xep0184_warning(self, id_):
+ def add_xep0184_mark(self, id_):
if id_ in self.xep0184_marks:
return
buffer_ = self.tv.get_buffer()
buffer_.begin_user_action()
- self.xep0184_marks[id_] = buffer_.create_mark(None,
- buffer_.get_end_iter(), left_gravity=True)
- self.xep0184_shown[id_] = NOT_SHOWN
-
- def show_it():
- if (not id_ in self.xep0184_shown) or \
- self.xep0184_shown[id_] == ALREADY_RECEIVED:
- return False
-
- end_iter = buffer_.get_iter_at_mark(self.xep0184_marks[id_])
- buffer_.insert_with_tags_by_name(end_iter, ' ✖', 'xep0184-warning')
-
- self.xep0184_shown[id_] = SHOWN
- return False
- gobject.timeout_add_seconds(3, show_it)
+ self.xep0184_marks[id_] = buffer_.create_mark(
+ None, buffer_.get_end_iter(), left_gravity=True)
buffer_.end_user_action()
- def hide_xep0184_warning(self, id_):
+ def show_xep0184_ack(self, id_):
if id_ not in self.xep0184_marks:
return
buffer_ = self.tv.get_buffer()
buffer_.begin_user_action()
- if self.xep0184_shown[id_] != NOT_SHOWN:
- begin_iter = buffer_.get_iter_at_mark(self.xep0184_marks[id_])
-
- end_iter = begin_iter.copy()
- # XXX: Is there a nicer way?
- end_iter.forward_char()
- end_iter.forward_char()
-
- buffer_.delete(begin_iter, end_iter)
-
if gajim.config.get('positive_184_ack'):
begin_iter = buffer_.get_iter_at_mark(self.xep0184_marks[id_])
buffer_.insert_with_tags_by_name(begin_iter, ' ✓',
'xep0184-received')
- self.xep0184_shown[id_] = ALREADY_RECEIVED
-
buffer_.end_user_action()
-
del self.xep0184_marks[id_]
- del self.xep0184_shown[id_]
def show_focus_out_line(self, scroll=True):
if not self.allow_focus_out_line:
@@ -623,26 +590,6 @@ class ConversationTextview(gobject.GObject):
# appeared)
gobject.idle_add(self.scroll_to_end)
- def show_xep0184_warning_tooltip(self):
- self.xep0184_warning_tooltip.timeout = 0
- pointer = self.tv.get_pointer()
- x, y = self.tv.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT,
- pointer[0], pointer[1])
- tags = self.tv.get_iter_at_location(x, y).get_tags()
- tag_table = self.tv.get_buffer().get_tag_table()
- xep0184_warning = False
- for tag in tags:
- if tag == tag_table.lookup('xep0184-warning'):
- xep0184_warning = True
- break
- if xep0184_warning and not self.xep0184_warning_tooltip.win:
- # check if the current pointer is still over the line
- position = self.tv.window.get_origin()
- self.xep0184_warning_tooltip.show_tooltip(_('This icon indicates '
- 'that this message has not yet\nbeen received by the remote '
- "end. If this icon stays\nfor a long time, it's likely the "
- 'message got lost.'), 8, position[1] + pointer[1])
-
def show_line_tooltip(self):
self.line_tooltip.timeout = 0
pointer = self.tv.get_pointer()
@@ -702,7 +649,6 @@ class ConversationTextview(gobject.GObject):
self.change_cursor = False
tag_table = self.tv.get_buffer().get_tag_table()
over_line = False
- xep0184_warning = False
for tag in tags:
if tag in (tag_table.lookup('url'), tag_table.lookup('mail'), \
tag_table.lookup('xmpp'), tag_table.lookup('sth_at_sth')):
@@ -711,30 +657,18 @@ class ConversationTextview(gobject.GObject):
self.change_cursor = True
elif tag == tag_table.lookup('focus-out-line'):
over_line = True
- elif tag == tag_table.lookup('xep0184-warning'):
- xep0184_warning = True
if self.line_tooltip.timeout != 0 or self.line_tooltip.shown:
# Check if we should hide the line tooltip
if not over_line:
self.line_tooltip.hide_tooltip()
- if self.xep0184_warning_tooltip.timeout != 0 or \
- self.xep0184_warning_tooltip.shown:
- # Check if we should hide the XEP-184 warning tooltip
- if not xep0184_warning:
- self.xep0184_warning_tooltip.hide_tooltip()
+
if over_line and not self.line_tooltip.win:
self.line_tooltip.timeout = gobject.timeout_add(500,
self.show_line_tooltip)
self.tv.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
self.change_cursor = True
- if xep0184_warning and not self.xep0184_warning_tooltip.win:
- self.xep0184_warning_tooltip.timeout = gobject.timeout_add(500,
- self.show_xep0184_warning_tooltip)
- self.tv.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(
- gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
- self.change_cursor = True
def clear(self, tv = None):
"""
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/f7161b468a281f74d83842dbdc38bc22e…
Philipp Hörist pushed to branch gajim_0.16 at gajim / gajim
Commits:
7554d184 by Philipp Hörist at 2017-03-20T22:57:26+01:00
Extend method to return our own full jid
- - - - -
a34e1704 by Philipp Hörist at 2017-03-20T22:57:39+01:00
Dont send chatstates to own resources
- - - - -
2a2f774d by Philipp Hörist at 2017-03-20T22:57:39+01:00
Use BareJID when sending message to ourself
- - - - -
e17d69b1 by Philipp Hörist at 2017-03-21T20:39:49+01:00
Dont use message receipts in message to ourself
- - - - -
5e56f9c3 by Philipp Hörist at 2017-03-21T20:39:54+01:00
Drop some message from ourself
- 'received'-Carbons from ourself, because we either received
the message directly or got a 'sent'-Carbon about it
- Messages from our own full jid, this can happen when we send
a Message to ourself and no other resource is online.
- - - - -
f7161b46 by Philipp Hörist at 2017-04-10T17:10:50+02:00
Merge branch 'fixselfresource' into 'gajim_0.16'
Improvements for sending messages to ourself
See merge request !69
- - - - -
7 changed files:
- src/chat_control.py
- src/common/connection.py
- src/common/connection_handlers.py
- src/common/connection_handlers_events.py
- src/common/gajim.py
- src/message_control.py
- src/roster_window.py
Changes:
=====================================
src/chat_control.py
=====================================
--- a/src/chat_control.py
+++ b/src/chat_control.py
@@ -2362,7 +2362,10 @@ class ChatControl(ChatControlBase):
if not keyID:
keyID = 'UNKNOWN'
- chatstates_on = gajim.config.get('outgoing_chat_state_notifications') != \
+ if self.contact.jid == gajim.get_jid_from_account(self.account):
+ chatstates_on = False
+ else:
+ chatstates_on = gajim.config.get('outgoing_chat_state_notifications') != \
'disabled'
chatstate_to_send = None
if chatstates_on and contact is not None:
@@ -2377,11 +2380,11 @@ class ChatControl(ChatControlBase):
def _on_sent(msg_stanza, message, encrypted, xhtml, label, old_txt):
id_ = msg_stanza.getID()
- if self.contact.supports(NS_RECEIPTS) and gajim.config.get_per(
- 'accounts', self.account, 'request_receipt'):
- xep0184_id = id_
- else:
- xep0184_id = None
+ xep0184_id = None
+ if self.contact.jid != gajim.get_jid_from_account(self.account):
+ if self.contact.supports(NS_RECEIPTS) and gajim.config.get_per(
+ 'accounts', self.account, 'request_receipt'):
+ xep0184_id = id_
if label:
displaymarking = label.getTag('displaymarking')
else:
@@ -2696,6 +2699,10 @@ class ChatControl(ChatControlBase):
chatstate_setting = gajim.config.get('outgoing_chat_state_notifications')
if chatstate_setting == 'disabled':
return
+
+ if self.contact.jid == gajim.get_jid_from_account(self.account):
+ return
+
elif chatstate_setting == 'composing_only' and state != 'active' and\
state != 'composing':
return
=====================================
src/common/connection.py
=====================================
--- a/src/common/connection.py
+++ b/src/common/connection.py
@@ -298,6 +298,8 @@ class CommonConnection:
'to %s, this JID is not valid.') % j))
return
fjid = new_list
+ elif jid == gajim.get_jid_from_account(self.name):
+ fjid = jid
else:
try:
jid = self.check_jid(jid)
@@ -502,10 +504,11 @@ class CommonConnection:
msg_iq.setTag(chatstate, namespace=nbxmpp.NS_CHATSTATES)
# XEP-0184
- if msgtxt and gajim.config.get_per('accounts', self.name,
- 'request_receipt') and contact and contact.supports(
- nbxmpp.NS_RECEIPTS):
- msg_iq.setTag('request', namespace=nbxmpp.NS_RECEIPTS)
+ if jid != gajim.get_jid_from_account(self.name):
+ if msgtxt and gajim.config.get_per('accounts', self.name,
+ 'request_receipt') and contact and contact.supports(
+ nbxmpp.NS_RECEIPTS):
+ msg_iq.setTag('request', namespace=nbxmpp.NS_RECEIPTS)
if forward_from:
addresses = msg_iq.addChild('addresses',
=====================================
src/common/connection_handlers.py
=====================================
--- a/src/common/connection_handlers.py
+++ b/src/common/connection_handlers.py
@@ -1206,17 +1206,19 @@ class ConnectionHandlersBase:
jid_to = gajim.get_jid_without_resource(fjid_to)
if jid_to == gajim.get_jid_from_account(self.name):
reply = True
- 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' and \
- reply:
- receipt = nbxmpp.Message(to=obj.fjid, typ='chat')
- receipt.setTag('received', namespace='urn:xmpp:receipts',
- attrs={'id': obj.id_})
-
- if obj.thread_id:
- receipt.setThread(obj.thread_id)
- self.connection.send(receipt)
+
+ if obj.jid != gajim.get_jid_from_account(self.name):
+ 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' and \
+ reply:
+ receipt = nbxmpp.Message(to=obj.fjid, typ='chat')
+ receipt.setTag('received', namespace='urn:xmpp:receipts',
+ attrs={'id': obj.id_})
+
+ if obj.thread_id:
+ receipt.setThread(obj.thread_id)
+ self.connection.send(receipt)
# We got our message's receipt
if obj.receipt_received_tag and gajim.config.get_per('accounts',
=====================================
src/common/connection_handlers_events.py
=====================================
--- a/src/common/connection_handlers_events.py
+++ b/src/common/connection_handlers_events.py
@@ -1129,6 +1129,15 @@ class MessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
account = self.conn.name
+ our_full_jid = gajim.get_jid_from_account(account, full=True)
+ if self.stanza.getFrom() == our_full_jid:
+ # Drop messages sent from our own full jid
+ # It can happen that when we sent message to our own bare jid
+ # that the server routes that message back to us
+ log.info('Received message from self: %s, message is dropped'
+ % self.stanza.getFrom())
+ return
+
# check if the message is a roster item exchange (XEP-0144)
if self.stanza.getTag('x', namespace=nbxmpp.NS_ROSTERX):
gajim.nec.push_incoming_event(RosterItemExchangeEvent(None,
@@ -1184,6 +1193,17 @@ class MessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
to = gajim.get_jid_from_account(account)
self.stanza.setFrom(to)
self.sent = True
+ elif carbon_marker.getName() == 'received':
+ full_frm = str(self.stanza.getFrom())
+ frm = gajim.get_jid_without_resource(full_frm)
+ if frm == gajim.get_jid_from_account(account):
+ # Drop 'received' Carbons from ourself, we already
+ # got the message with the 'sent' Carbon or via the
+ # message itself
+ log.info(
+ 'Drop "received"-Carbon from ourself: %s'
+ % full_frm)
+ return
try:
self.get_jid_resource()
except helpers.InvalidFormat:
=====================================
src/common/gajim.py
=====================================
--- a/src/common/gajim.py
+++ b/src/common/gajim.py
@@ -419,13 +419,16 @@ def jid_is_transport(jid):
return True
return False
-def get_jid_from_account(account_name):
+def get_jid_from_account(account_name, full=False):
"""
Return the jid we use in the given account
"""
name = config.get_per('accounts', account_name, 'name')
hostname = config.get_per('accounts', account_name, 'hostname')
jid = name + '@' + hostname
+ if full:
+ resource = connections[account_name].server_resource
+ jid += '/' + resource
return jid
def get_our_jids():
=====================================
src/message_control.py
=====================================
--- a/src/message_control.py
+++ b/src/message_control.py
@@ -234,7 +234,8 @@ class MessageControl(object):
conn = gajim.connections[self.account]
if not self.session:
- if not obj.resource:
+ if (not obj.resource and
+ obj.jid != gajim.get_jid_from_account(self.account)):
if self.resource:
obj.resource = self.resource
else:
=====================================
src/roster_window.py
=====================================
--- a/src/roster_window.py
+++ b/src/roster_window.py
@@ -2759,7 +2759,8 @@ class RosterWindow:
typ = 'error'
if obj.forwarded and obj.sent:
typ = 'out'
- xep0184_id = obj.id_
+ if obj.jid != gajim.get_jid_from_account(obj.conn.name):
+ xep0184_id = obj.id_
obj.session.control.print_conversation(obj.msgtxt, typ,
tim=obj.timestamp, encrypted=obj.encrypted, subject=obj.subject,
@@ -4167,7 +4168,7 @@ class RosterWindow:
contact = gajim.contacts.get_contact_with_highest_priority(account,
jid)
if jid == gajim.get_jid_from_account(account):
- resource = contact.resource
+ resource = None
gajim.interface.on_open_chat_window(None, contact, account, \
resource=resource, session=session)
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/b4bb07a071b5b096ee0bbd44ab12e1b13…
Philipp Hörist pushed to branch gajim_0.16 at gajim / gajim
Commits:
ff8e02c6 by Stephen Paul Weber at 2017-04-06T17:01:38-05:00
Display OOB content, even without <body/>
Also, if the OOB URL is identical to the entire contents of a <body/>,
no reason to show both.
Closes #8521
- - - - -
b4bb07a0 by Philipp Hörist at 2017-04-10T16:59:34+02:00
Merge branch 'improve-oob-display' into 'gajim_0.16'
Display OOB content, even without <body/>
See merge request !79
- - - - -
2 changed files:
- src/common/connection_handlers_events.py
- src/session.py
Changes:
=====================================
src/common/connection_handlers_events.py
=====================================
--- a/src/common/connection_handlers_events.py
+++ b/src/common/connection_handlers_events.py
@@ -1462,12 +1462,15 @@ class DecryptedMessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
self.oob_url = oob_node.getTagData('url')
self.oob_desc = oob_node.getTagData('desc')
if self.oob_url:
- self.msgtxt += '\n'
- if self.oob_desc:
- self.msgtxt += self.oob_desc
+ if self.msgtxt in [None, '', self.oob_url]:
+ self.msgtxt = ''
else:
- self.msgtxt += _('URL:')
- self.msgtxt += ' ' + self.oob_url
+ self.msgtxt += '\n'
+ if self.oob_desc:
+ self.msgtxt += self.oob_desc + ' '
+ elif self.msgtxt != '':
+ self.msgtxt += _('URL:') + ' '
+ self.msgtxt += self.oob_url
replace = self.stanza.getTag('replace', namespace=nbxmpp.NS_CORRECT)
if replace:
=====================================
src/session.py
=====================================
--- a/src/session.py
+++ b/src/session.py
@@ -83,7 +83,7 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
self.control.change_resource(self.resource)
if obj.mtype == 'chat':
- if not obj.stanza.getTag('body') and obj.chatstate is None:
+ if not obj.msgtxt and obj.chatstate is None:
return
log_type = 'chat_msg'
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/b5fabea53e87eeefd309e19e5babb7b9b…