Compare commits

..

1 Commits

Author SHA1 Message Date
'leftie 5e0c4f5d5c add plural-affirmative aliases for `/me` 2019-06-01 11:24:08 -04:00
85 changed files with 24662 additions and 24988 deletions

View File

@ -1,29 +1,3 @@
Gajim 1.1.3 (24 April 2019)
New
* Add a mobile phone indicator to the chat window
* Rework HTTPUpload dialog
* Add a "paste as quote" option to the message input
Bug fixes
* #8822 Fix memory leak when using spell checker
* #9514 Fix jingle filetransfers not working in some circumstances
* #9573 Dont leak DNS query when connecting over proxy
* #9578 Determine Windows version more reliably
* #9622 Fix an error while quitting Gajim
* #9633 Fix an error while sending a file
* #9637 Restore window size correctly on wayland
* #9660 GPG Agent setting is ignored
* #9645 Make zeroconf IPV6 compatible
* Improve dark theme colors
* Fix access to GnuPG keys
* Use UUID4 item ids for pubsub posts
* Dont send invalid show values
* Windows: Dont override format region settings
* Various smaller improvements
Gajim 1.1.2 (15 January 2019)
Bug fixes

View File

@ -32,8 +32,8 @@ build_script:
bash "git clone C:/projects/gajim C:/msys64/home/appveyor/gajim"
bash "C:/msys64/home/appveyor/gajim/win/build.sh $($env:MSYS_ARCH)"
Push-AppveyorArtifact "$($env:BUILDROOT)/Gajim.exe" -FileName "Gajim-1.1.2-$($env:ARCH)-$($env:TIME_STRING).exe"
Push-AppveyorArtifact "$($env:BUILDROOT)/Gajim-Portable.exe" -FileName "Gajim-Portable-1.1.2-$($env:ARCH)-$($env:TIME_STRING).exe"
Push-AppveyorArtifact "$($env:BUILDROOT)/Gajim.exe" -FileName "Gajim-1.1.1-$($env:ARCH)-$($env:TIME_STRING).exe"
Push-AppveyorArtifact "$($env:BUILDROOT)/Gajim-Portable.exe" -FileName "Gajim-Portable-1.1.1-$($env:ARCH)-$($env:TIME_STRING).exe"
# on_finish:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

View File

@ -101,7 +101,6 @@
<content_attribute id="money-gambling">none</content_attribute>
</content_rating>
<releases>
<release version="1.1.3" date="2019-04-23" />
<release version="1.1.2" date="2019-01-15" />
<release version="1.1.1" date="2018-12-23" />
<release version="1.1.0" date="2018-11-06" />

View File

@ -3,6 +3,8 @@ runtime: org.gnome.Platform
runtime-version: 3.30
sdk: org.gnome.Sdk
command: gajim
tags: nightly
desktop-file-name-prefix: '(Nightly) '
finish-args:
- --share=ipc
- --share=network
@ -20,8 +22,6 @@ finish-args:
- --filesystem=~/.config/dconf:ro
- --talk-name=ca.desrt.dconf
- --env=DCONF_USER_CONFIG_DIR=.config/dconf
# GnuPG
- --filesystem=~/.gnupg
# extensions
- --env=PYTHONPATH=/app/plugins/lib/python3.7/site-packages
@ -62,8 +62,8 @@ modules:
- pip3 install --prefix=/app .
sources:
- type: archive
url: https://files.pythonhosted.org/packages/64/7c/27367b38e6cc3e1f49f193deb761fe75cda9f95da37b67b422e62281fcac/cffi-1.12.2.tar.gz
sha256: e113878a446c6228669144ae8a56e268c91b7f1fafae927adc4879d9849e0ea7
url: https://files.pythonhosted.org/packages/e7/a7/4cd50e57cc6f436f1cc3a7e8fa700ff9b8b4d471620629074913e3735fb2/cffi-1.11.5.tar.gz
sha256: e90f17980e6ab0f3c2f3730e56d1fe9bcba1891eeea58966e89d352492cc74f4
- name: python3-asn1crypto
buildsystem: simple
@ -77,11 +77,11 @@ modules:
- name: python3-idna
buildsystem: simple
build-commands:
- pip3 install --prefix=/app idna-2.8-py2.py3-none-any.whl
- pip3 install --prefix=/app idna-2.7-py2.py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/14/2c/cd551d81dbe15200be1cf41cd03869a46fe7226e7450af7a6545bfc474c9/idna-2.8-py2.py3-none-any.whl
sha256: ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c
url: https://files.pythonhosted.org/packages/4b/2a/0276479a4b3caeb8a8c1af2f8e4355746a97fab05a372e4a2c6a6b876165/idna-2.7-py2.py3-none-any.whl
sha256: 156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e
- name: python3-cryptography
buildsystem: simple
@ -89,17 +89,17 @@ modules:
- pip3 install --prefix=/app .
sources:
- type: archive
url: https://files.pythonhosted.org/packages/07/ca/bc827c5e55918ad223d59d299fff92f3563476c3b00d0a9157d9c0217449/cryptography-2.6.1.tar.gz
sha256: 26c821cbeb683facb966045e2064303029d572a87ee69ca5a1bf54bf55f93ca6
url: https://files.pythonhosted.org/packages/22/21/233e38f74188db94e8451ef6385754a98f3cad9b59bedf3a8e8b14988be4/cryptography-2.3.1.tar.gz
sha256: 8d10113ca826a4c29d5b85b2c4e045ffa8bad74fb525ee0eceb1d38d4c70dfd6
- name: python3-pyopenssl
buildsystem: simple
build-commands:
- pip3 install --prefix=/app pyOpenSSL-19.0.0-py2.py3-none-any.whl
- pip3 install --prefix=/app pyOpenSSL-18.0.0-py2.py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/01/c8/ceb170d81bd3941cbeb9940fc6cc2ef2ca4288d0ca8929ea4db5905d904d/pyOpenSSL-19.0.0-py2.py3-none-any.whl
sha256: c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6
url: https://files.pythonhosted.org/packages/96/af/9d29e6bd40823061aea2e0574ccb2fcf72bfd6130ce53d32773ec375458c/pyOpenSSL-18.0.0-py2.py3-none-any.whl
sha256: 26ff56a6b5ecaf3a2a59f132681e2a80afcc76b4f902f612f518f92c2a1bf854
- name: python3-dbus-python
build-options:
@ -122,31 +122,31 @@ modules:
- name: python3-secretstorage
buildsystem: simple
build-commands:
- pip3 install --prefix=/app SecretStorage-3.1.1-py3-none-any.whl
- pip3 install --prefix=/app SecretStorage-3.1.0-py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/82/59/cb226752e20d83598d7fdcabd7819570b0329a61db07cfbdd21b2ef546e3/SecretStorage-3.1.1-py3-none-any.whl
sha256: 7a119fb52a88e398dbb22a4b3eb39b779bfbace7e4153b7bc6e5954d86282a8a
url: https://files.pythonhosted.org/packages/d8/e8/80975fd281764c80b2eb581a7f25d2109786e273b8925e8161bd2d06d10a/SecretStorage-3.1.0-py3-none-any.whl
sha256: 20196abd1a9d1310df7573d58ca6e7ed9292218c98ca3638eea07beb16080343
- name: python3-entrypoints
buildsystem: simple
build-commands:
- pip3 install --prefix=/app entrypoints-0.3-py2.py3-none-any.whl
- pip3 install --prefix=/app entrypoints-0.2.3-py2.py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/ac/c6/44694103f8c221443ee6b0041f69e2740d89a25641e62fb4f2ee568f2f9c/entrypoints-0.3-py2.py3-none-any.whl
sha256: 589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19
url: https://files.pythonhosted.org/packages/cc/8b/4eefa9b47f1910b3d2081da67726b066e379b04ca897acfe9f92bac56147/entrypoints-0.2.3-py2.py3-none-any.whl
sha256: 10ad569bb245e7e2ba425285b9fa3e8178a0dc92fc53b1e1c553805e15a8825b
- name: python3-keyring
buildsystem: simple
build-commands:
- pip3 install --prefix=/app keyring-18.0.0-py2.py3-none-any.whl
- pip3 install --prefix=/app keyring-16.0.2-py2.py3-none-any.whl
cleanup:
- /bin
sources:
- type: file
url: https://files.pythonhosted.org/packages/a1/28/0058032477bfdf2003e605d175629963759220661615443e20711446bfa7/keyring-18.0.0-py2.py3-none-any.whl
sha256: ca33f5ccc542b9ffaa196ee9a33488069e5e7eac77d5b81969f8a3ce74d0230c
url: https://files.pythonhosted.org/packages/5f/cb/dc7b2215cd82b77e7b8b48abd8989c1b09990d4c91a3ccfdc18a61157b36/keyring-16.0.2-py2.py3-none-any.whl
sha256: 2a5cf5e596cbf8b66b98b8df2c214adfe21e6e18baa82006b2c482bd0c4be94c
- name: python3-cssutils
buildsystem: simple
@ -182,8 +182,8 @@ modules:
- pip3 install --prefix=/app .
sources:
- type: archive
url: https://files.pythonhosted.org/packages/d6/01/34b2a441926780f26edd21490158afe0eb76beae4efbb6bc4d3323eae69a/nbxmpp-0.6.10.tar.gz
sha256: cd73417777e4847fdd8d0d96c7cafc606952edbd2b9d52a2a72bb2aaa04d08ef
url: https://files.pythonhosted.org/packages/24/54/23a475a0d7d3664ea21b14ce907245dc390496f31d229a9aac2ae20c7c28/nbxmpp-0.6.8.tar.gz
sha256: 8c2b4b8aac1a8c6d07c1e30af542fde20a70a9b8c7c04017e9cea0db654437c6
- name: gajim
buildsystem: simple
@ -193,6 +193,5 @@ modules:
sources:
- type: git
url: https://dev.gajim.org/gajim/gajim.git
branch: gajim_1.1
post-install:
- install -d /app/plugins

View File

@ -1,7 +1,7 @@
import os
import subprocess
__version__ = "1.1.3"
__version__ = "1.1.2"
IS_FLATPAK = False
if os.path.exists('/app/share/run-as-flatpak'):

View File

@ -379,7 +379,6 @@ class GajimApplication(Gtk.Application):
act = Gio.SimpleAction.new_stateful(
'agent', None,
GLib.Variant.new_boolean(app.config.get('use_gpg_agent')))
act.connect('change-state', app_actions.on_use_pgp_agent)
self.add_action(act)
# General Actions

View File

@ -225,9 +225,6 @@ class ChatControl(ChatControlBase):
app.ged.register_event_handler('pep-received', ged.GUI1,
self._nec_pep_received)
app.ged.register_event_handler('update-client-info', ged.GUI1,
self._on_update_client_info)
if self.TYPE_ID == message_control.TYPE_CHAT:
# Dont connect this when PrivateChatControl is used
app.ged.register_event_handler('update-roster-avatar', ged.GUI1,
@ -438,17 +435,6 @@ class ChatControl(ChatControlBase):
else:
self.update_pep(obj.pep_type)
def _on_update_client_info(self, event):
if event.account != self.account:
return
if event.jid != self.contact.jid:
return
contact = app.contacts.get_contact(
self.account, event.jid, event.resource)
if contact is None:
return
self.xml.get_object('phone_image').set_visible(contact.uses_phone)
def _update_jingle(self, jingle_type):
if jingle_type not in ('audio', 'video'):
return
@ -1077,9 +1063,6 @@ class ChatControl(ChatControlBase):
app.ged.remove_event_handler('pep-received', ged.GUI1,
self._nec_pep_received)
app.ged.remove_event_handler('update-client-info', ged.GUI1,
self._on_update_client_info)
if self.TYPE_ID == message_control.TYPE_CHAT:
app.ged.remove_event_handler('update-roster-avatar', ged.GUI1,
self._nec_update_avatar)

View File

@ -323,6 +323,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
self.set_emoticon_popover()
# Attach speller
self.spell_checker = None
self.set_speller()
self.conv_textview.tv.show()
@ -473,15 +474,15 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
if gspell_lang is None:
return
spell_checker = Gspell.Checker.new(gspell_lang)
self.spell_checker = Gspell.Checker.new(gspell_lang)
spell_buffer = Gspell.TextBuffer.get_from_gtk_text_buffer(
self.msg_textview.get_buffer())
spell_buffer.set_spell_checker(spell_checker)
spell_buffer.set_spell_checker(self.spell_checker)
spell_view = Gspell.TextView.get_from_gtk_text_view(self.msg_textview)
spell_view.set_inline_spell_checking(False)
spell_view.set_enable_language_menu(True)
spell_checker.connect('notify::language', self.on_language_changed)
self.spell_checker.connect('notify::language', self.on_language_changed)
def get_speller_language(self):
per_type = 'contacts'
@ -559,27 +560,14 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
id_ = item.connect('activate', self.msg_textview.clear)
self.handlers[id_] = item
paste_item = Gtk.MenuItem.new_with_label(_('Paste as quote'))
id_ = paste_item.connect('activate', self.paste_clipboard_as_quote)
self.handlers[id_] = paste_item
menu.append(paste_item)
menu.show_all()
def insert_as_quote(self, text: str) -> None:
def on_quote(self, widget, text):
self.msg_textview.remove_placeholder()
text = '> ' + text.replace('\n', '\n> ') + '\n'
text = '>' + text.replace('\n', '\n>') + '\n'
message_buffer = self.msg_textview.get_buffer()
message_buffer.insert_at_cursor(text)
def paste_clipboard_as_quote(self, _item: Gtk.MenuItem) -> None:
clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
text = clipboard.wait_for_text()
self.insert_as_quote(text)
def on_quote(self, widget, text):
self.insert_as_quote(text)
# moved from ChatControl
def _on_banner_eventbox_button_press_event(self, widget, event):
"""

View File

@ -74,7 +74,7 @@ class StandardCommonCommands(CommandContainer):
def say(self, message):
self.send(message)
@command('we','us',raw=True)
@command('we', 'us', raw=True)
@doc(_("Send action (in the third person) to the current chat"))
def me(self, action):
self.send("/me %s" % action)

View File

@ -39,13 +39,11 @@ from distutils.version import LooseVersion as V
from collections import namedtuple
import nbxmpp
from gi.repository import Gdk
import gajim
from gajim.common import config as c_config
from gajim.common import configpaths
from gajim.common import ged as ged_module
from gajim.common.const import Display
from gajim.common.contacts import LegacyContactsAPI
from gajim.common.events import Events
from gajim.common.types import NetworkEventsControllerT # pylint: disable=unused-import
@ -150,7 +148,6 @@ socks5queue = None
gupnp_igd = None
gajim_identity = {'type': 'pc', 'category': 'client', 'name': 'Gajim'}
gajim_common_features = [nbxmpp.NS_BYTESTREAM, nbxmpp.NS_SI, nbxmpp.NS_FILE,
nbxmpp.NS_MUC, nbxmpp.NS_MUC_USER, nbxmpp.NS_MUC_ADMIN, nbxmpp.NS_MUC_OWNER,
nbxmpp.NS_MUC_CONFIG, nbxmpp.NS_COMMANDS, nbxmpp.NS_DISCO_INFO, 'ipv6',
@ -195,18 +192,6 @@ def is_installed(dependency):
def is_flatpak():
return gajim.IS_FLATPAK
def is_display(display):
# XWayland reports as Display X11, so try with env var
is_wayland = os.environ.get('XDG_SESSION_TYPE') == 'wayland'
if is_wayland and display == Display.WAYLAND:
return True
default = Gdk.Display.get_default()
if default is None:
log('gajim').warning('Could not determine window manager')
return False
return default.__class__.__name__ == display.value
def disable_dependency(dependency):
_dependencies[dependency] = False

View File

@ -77,14 +77,6 @@ def client_supports(client_caps, requested_feature):
return requested_feature not in FEATURE_BLACKLIST
return False
def get_client_identity(client_caps):
lookup_item = client_caps.get_cache_lookup_strategy()
cache_item = lookup_item(capscache)
for identity in cache_item.identities:
if identity.get('category') == 'client':
return identity.get('type')
def create_suitable_client_caps(node, caps_hash, hash_method, fjid=None):
"""
Create and return a suitable ClientCaps object for the given node,

View File

@ -905,6 +905,10 @@ class Connection(CommonConnection, ConnectionHandlers):
]
self._hostname = hostname
if h:
app.resolver.resolve('_xmppconnect.' + helpers.idn_to_ascii(h),
self._on_resolve_txt, type_='txt')
if use_srv and self._proxy is None:
self._srv_hosts = []
@ -914,9 +918,6 @@ class Connection(CommonConnection, ConnectionHandlers):
for service in services:
record_name = '_' + service + '._tcp.' + helpers.idn_to_ascii(h)
app.resolver.resolve(record_name, self._on_resolve_srv)
app.resolver.resolve('_xmppconnect.' + helpers.idn_to_ascii(h),
self._on_resolve_txt, type_='txt')
else:
self._connect_to_next_host()

View File

@ -193,13 +193,6 @@ class SyncThreshold(IntEnum):
return str(self.value)
class Display(Enum):
X11 = 'X11Display'
WAYLAND = 'GdkWaylandDisplay'
WIN32 = 'GdkWin32Display'
QUARTZ = 'GdkQuartzDisplay'
ACTIVITIES = {
'doing_chores': {
'category': _('Doing Chores'),

View File

@ -116,10 +116,6 @@ class CommonContact(XMPPEntity):
return False
return caps_cache.client_supports(self.client_caps, requested_feature)
@property
def uses_phone(self):
return caps_cache.get_client_identity(self.client_caps) == 'phone'
class Contact(CommonContact):
"""

View File

@ -42,7 +42,6 @@ import logging
import json
import shutil
import collections
from io import StringIO
from datetime import datetime, timedelta
from distutils.version import LooseVersion as V
from encodings.punycode import punycode_encode
@ -52,17 +51,11 @@ import nbxmpp
from nbxmpp.stringprepare import nameprep
import precis_i18n.codec # pylint: disable=unused-import
from gajim.common import app
from gajim.common import caps_cache
from gajim.common import configpaths
from gajim.common.i18n import Q_
from gajim.common.i18n import _
from gajim.common.i18n import ngettext
from gajim.common.const import Display
if app.is_installed('PYCURL'):
import pycurl
log = logging.getLogger('gajim.c.helpers')
@ -559,6 +552,12 @@ def datetime_tuple(timestamp):
tim = tim.timetuple()
return tim
from gajim.common import app
if app.is_installed('PYCURL'):
import pycurl
from io import StringIO
def convert_bytes(string):
suffix = ''
# IEC standard says KiB = 1024 bytes KB = 1000 bytes
@ -1535,14 +1534,3 @@ class AdditionalDataDict(collections.UserDict):
del _dict[key]
except KeyError:
return
def save_roster_position(window):
if not app.config.get('save-roster-position'):
return
if app.is_display(Display.WAYLAND):
return
x_pos, y_pos = window.get_position()
log.debug('Save roster position: %s %s', x_pos, y_pos)
app.config.set('roster_x-position', x_pos)
app.config.set('roster_y-position', y_pos)

View File

@ -151,18 +151,13 @@ def ngettext(s_sing, s_plural, n, replace_sing=None, replace_plural=None):
try:
locale.setlocale(locale.LC_ALL, '')
except locale.Error as error:
print(error, file=sys.stderr)
print(error)
try:
LANG = get_default_lang()
if os.name == 'nt':
# Set the env var on Windows because gettext.find() uses it to
# find the translation
# Use LANGUAGE instead of LANG, LANG sets LC_ALL and thus
# doesn't retain other region settings like LC_TIME
os.environ['LANGUAGE'] = LANG
print('Found default language: %s' % LANG)
except Exception as error:
print('Failed to determine default language', file=sys.stderr)
print('Failed to determine default language')
import traceback
traceback.print_exc()
@ -178,6 +173,6 @@ for dir_ in iter_locale_dirs():
else:
break
else:
print('No translations found', file=sys.stderr)
print('Dirs searched: %s' % get_locale_dirs(), file=sys.stderr)
print('No translations found')
print('Dirs searched: %s' % get_locale_dirs())
_ = _translation.gettext

View File

@ -445,8 +445,6 @@ class JingleSession:
if child.getName() == 'checksum':
hash_ = child.getTag('file').getTag(name='hash',
namespace=nbxmpp.NS_HASHES_2)
if hash_ is None:
continue
algo = hash_.getAttr('algo')
if algo in nbxmpp.Hashes2.supported:
file_props = FilesProp.getFileProp(self.connection.name,

View File

@ -100,7 +100,7 @@ def get_context(fingerprint, verify_cb=None, remote_jid=None):
flags = (SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3 | SSL.OP_SINGLE_DH_USE \
| SSL.OP_NO_TICKET)
ctx.set_options(flags)
ctx.set_cipher_list(b'HIGH:!aNULL:!3DES')
ctx.set_cipher_list('HIGH:!aNULL:!3DES')
if fingerprint == 'server': # for testing purposes only
ctx.set_verify(SSL.VERIFY_NONE|SSL.VERIFY_FAIL_IF_NO_PEER_CERT,

View File

@ -28,7 +28,7 @@ def parseLogLevel(arg):
return int(arg)
if arg.isupper() and hasattr(logging, arg):
return getattr(logging, arg)
print(_('%s is not a valid loglevel') % repr(arg), file=sys.stderr)
print(_('%s is not a valid loglevel') % repr(arg))
return 0
def parseLogTarget(arg):
@ -69,8 +69,7 @@ def parseAndSetLogLevels(arg):
target = parseLogTarget(target.strip())
if target:
logging.getLogger(target).setLevel(level)
print("Logger %s level set to %d" % (target, level),
file=sys.stderr)
print("Logger %s level set to %d" % (target, level))
class colors:

View File

@ -207,11 +207,6 @@ class Message:
'gc_control': gc_control
}
app.nec.push_incoming_event(NetworkEvent('update-client-info',
account=self._account,
jid=jid,
resource=resource))
event = MessageReceivedEvent(None, **event_attr)
app.nec.push_incoming_event(event)

View File

@ -175,10 +175,6 @@ class Presence:
def get_presence(self, to=None, typ=None, priority=None,
show=None, status=None, nick=None, caps=True,
sign=None, idle_time=None):
if show not in ('chat', 'away', 'xa', 'dnd'):
# Gajim sometimes passes invalid show values here
# until this is fixed this is a workaround
show = None
presence = nbxmpp.Presence(to, typ, priority, show, status)
if nick is not None:
nick_tag = presence.setTag('nick', namespace=nbxmpp.NS_NICK)

View File

@ -92,10 +92,7 @@ class Register:
error = stanza.getErrorMsg()
log.info('Error: %s', error)
if error_cb() is not None:
form = is_form = None
if stanza.getTagAttr('error', 'type') == 'modify':
form, is_form = self._get_register_form(stanza)
error_cb()(error, form, is_form)
error_cb()(error)
return
self._con.get_module('Presence').subscribe(agent, auto_auth=True)
@ -119,7 +116,8 @@ class Register:
iq, self._register_info_response, {'success_cb': weak_success_cb,
'error_cb': weak_error_cb})
def _register_info_response(self, _con, stanza, success_cb, error_cb):
@staticmethod
def _register_info_response(_con, stanza, success_cb, error_cb):
if not nbxmpp.isResultNode(stanza):
error = stanza.getErrorMsg()
log.info('Error: %s', error)
@ -127,28 +125,18 @@ class Register:
error_cb()(error)
else:
log.info('Register form received')
form = stanza.getQuery().getTag('x', namespace=nbxmpp.NS_DATA)
is_form = form is not None
if not is_form:
form = {}
for field in stanza.getQueryPayload():
if not isinstance(field, nbxmpp.Node):
continue
form[field.getName()] = field.getData()
if success_cb() is not None:
form, is_form = self._get_register_form(stanza)
success_cb()(form, is_form)
@staticmethod
def _get_register_form(stanza):
query = stanza.getTag('query')
if not query:
return None, False
form = query.getTag('x', namespace=nbxmpp.NS_DATA)
is_form = form is not None
if not is_form:
form = {}
for field in query.getPayload():
if not isinstance(field, nbxmpp.Node):
continue
form[field.getName()] = field.getData()
return form, is_form
def get_instance(*args, **kwargs):
return Register(*args, **kwargs), 'Register'

View File

@ -27,7 +27,6 @@ import os
import sys
import re
import logging
from pathlib import Path
from gajim.common import app
from gajim.common import caps_cache
@ -105,22 +104,25 @@ class OptionsParser:
fd.write(s + ' = ' + value + '\n')
def write(self):
config_path = Path(self.__filename)
tempfile = 'temp_%s' % config_path.name
temp_filepath = config_path.parent / tempfile
(base_dir, filename) = os.path.split(self.__filename)
self.__tempfile = os.path.join(base_dir, '.' + filename)
try:
with open(str(temp_filepath), 'w', encoding='utf-8') as file:
app.config.foreach(self.write_line, file)
except IOError:
log.exception('Failed to write config file')
return
with open(self.__tempfile, 'w', encoding='utf-8') as f:
app.config.foreach(self.write_line, f)
except IOError as e:
return str(e)
if os.path.exists(self.__filename):
if os.name == 'nt':
# win32 needs this
try:
os.remove(self.__filename)
except Exception as e:
return str(e)
try:
temp_filepath.replace(config_path)
except Exception:
log.exception('Failed to replace config file')
else:
log.info('Successful saved config file')
os.rename(self.__tempfile, self.__filename)
except IOError as e:
return str(e)
def update_config(self, old_version, new_version):
old_version_list = old_version.split('.') # convert '0.x.y' to (0, x, y)

View File

@ -23,7 +23,7 @@ import struct
import hashlib
import os
import time
import sys
import platform
import logging
from errno import EWOULDBLOCK
from errno import ENOBUFS
@ -296,7 +296,7 @@ class SocksQueue:
def activate_proxy(self, idx):
if not self.isHashInSockObjs(self.senders, idx):
return
for key in list(self.senders):
for key in self.senders:
if idx in key:
sender = self.senders[key]
if sender.file_props.type_ != 's':
@ -687,11 +687,13 @@ class Socks5:
OpenSSL.SSL.WantX509LookupError) as e:
log.info('SSL rehandshake request: %s', repr(e))
raise e
except OpenSSL.SSL.SysCallError:
return self._on_send_exception()
except Exception as e:
if e.errno not in (EINTR, ENOBUFS, EWOULDBLOCK):
return self._on_send_exception()
# peer stopped reading
self.state = 8 # end connection
self.disconnect()
self.file_props.error = -1
return -1
self.size += lenn
current_time = time.time()
self.file_props.elapsed_time += current_time - \
@ -717,13 +719,6 @@ class Socks5:
self.disconnect()
return -1
def _on_send_exception(self):
# peer stopped reading
self.state = 8 # end connection
self.disconnect()
self.file_props.error = -1
return -1
def get_file_contents(self, timeout):
"""
Read file contents from socket and write them to file
@ -1436,7 +1431,7 @@ class Socks5Listener(IdleObject):
# Under windows Vista, we need that to listen on ipv6 AND ipv4
# Doesn't work under windows XP
if os.name == 'nt':
if sys.getwindowsversion().major >= 6: # Win Vista +
if int(platform.win32_ver()[0]) >= 6: # Win Vista +
# 47 is socket.IPPROTO_IPV6
# 27 is socket.IPV6_V6ONLY under windows, but not defined ...
self._serv.setsockopt(41, 27, 0)

View File

@ -26,6 +26,7 @@ from gajim.common.zeroconf import zeroconf
from nbxmpp.protocol import *
import socket
import platform
import ssl
import errno
import sys
@ -72,7 +73,7 @@ class ZeroconfListener(IdleObject):
self._serv.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
self._serv.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
if os.name == 'nt':
if sys.getwindowsversion().major >= 6: # Win Vista +
if int(platform.win32_ver()[0]) >= 6: # Win Vista +
# 47 is socket.IPPROTO_IPV6
# 27 is socket.IPV6_V6ONLY under windows, but not defined ...
self._serv.setsockopt(41, 27, 0)

View File

@ -17,6 +17,7 @@
import logging
import select
import socket
import re
from gajim.common.i18n import _
@ -156,16 +157,16 @@ class Zeroconf:
self.queried.append(True)
def getaddrinfo_callback(self, sdRef, flags, interfaceIndex, errorCode,
hosttarget, address, ttl):
def query_record_callback(self, sdRef, flags, interfaceIndex, errorCode,
hosttarget, rrtype, rrclass, rdata, ttl):
if errorCode != pybonjour.kDNSServiceErr_NoError:
log.error('Error in getaddrinfo_callback: %s', str(errorCode))
log.error('Error in query_record_callback: %s', str(errorCode))
return
fullname, port, txtRecord = self.resolved_contacts[hosttarget]
txt = pybonjour.TXTRecord.parse(txtRecord)
ip = address[1]
ip = socket.inet_ntoa(rdata)
name, bare_name, protocol, domain = self._parse_name(fullname)
@ -206,18 +207,20 @@ class Zeroconf:
self.resolved_contacts[hosttarget] = (fullname, port, txtRecord)
try:
getaddrinfo_sdRef = \
pybonjour.DNSServiceGetAddrInfo(
query_sdRef = None
query_sdRef = \
pybonjour.DNSServiceQueryRecord(
interfaceIndex=interfaceIndex,
hostname=hosttarget,
callBack=self.getaddrinfo_callback)
fullname=hosttarget,
rrtype=pybonjour.kDNSServiceType_A,
callBack=self.query_record_callback)
while not self.queried:
ready = select.select([getaddrinfo_sdRef], [], [], resolve_timeout)
if getaddrinfo_sdRef not in ready[0]:
log.warning('GetAddrInfo timed out')
ready = select.select([query_sdRef], [], [], resolve_timeout)
if query_sdRef not in ready[0]:
log.warning('Query record timed out')
break
pybonjour.DNSServiceProcessResult(getaddrinfo_sdRef)
pybonjour.DNSServiceProcessResult(query_sdRef)
else:
self.queried.pop()
@ -228,8 +231,8 @@ class Zeroconf:
self.error_CB(_('Error while adding service. %s') % error)
finally:
if getaddrinfo_sdRef:
getaddrinfo_sdRef.close()
if query_sdRef:
query_sdRef.close()
self.resolved.append(True)

View File

@ -407,13 +407,12 @@
</packing>
</child>
<child>
<object class="GtkGrid">
<object class="GtkBox" id="banner_vbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="margin_left">5</property>
<property name="hexpand">True</property>
<property name="row_spacing">2</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="banner_name_label">
<property name="name">ChatControl-BannerNameLabel</property>
@ -424,9 +423,9 @@
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">2</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
@ -434,7 +433,6 @@
<property name="name">ChatControl-BannerLabel</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="label">label</property>
<property name="use_markup">True</property>
<property name="selectable">True</property>
@ -442,27 +440,14 @@
<signal name="populate-popup" handler="on_banner_label_populate_popup" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkImage" id="phone_image">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="tooltip_text" translatable="yes">The last message was written on a mobile client</property>
<property name="halign">start</property>
<property name="margin_right">4</property>
<property name="icon_name">phone-apple-iphone-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>

View File

@ -311,7 +311,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="label" translatable="yes">Chat</property>
<style>
<class name="dim-label"/>
@ -327,7 +326,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">Record history for this chat</property>
<property name="valign">center</property>
<signal name="notify::active" handler="on_log_history_checkbutton_toggled" swapped="no"/>
</object>
<packing>
@ -339,7 +337,6 @@
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="margin_left">6</property>
<property name="label" translatable="yes">Record History</property>
<style>
@ -356,7 +353,6 @@
<property name="width_request">400</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="model">liststore1</property>
<property name="tearoff_title" translatable="yes">Ttitle</property>

View File

@ -1,20 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<!-- Generated with glade 3.20.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<requires lib="gtk+" version="3.14"/>
<object class="GtkBox" id="box">
<property name="width_request">300</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">18</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkImage">
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">document-send-symbolic</property>
<property name="icon_size">6</property>
<property name="top_padding">8</property>
<property name="bottom_padding">4</property>
<property name="left_padding">8</property>
<property name="right_padding">8</property>
<child>
<object class="GtkLabel" id="label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="variant" value="normal"/>
</attributes>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
@ -23,14 +32,21 @@
</packing>
</child>
<child>
<object class="GtkLabel" id="label">
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">6</property>
<property name="label">&lt;placeholder&gt;</property>
<style>
<class name="bold"/>
</style>
<property name="top_padding">4</property>
<property name="bottom_padding">4</property>
<property name="left_padding">8</property>
<property name="right_padding">8</property>
<child>
<object class="GtkProgressBar" id="progressbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pulse_step">0.10000000149</property>
<property name="show_text">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
@ -38,52 +54,5 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="progress_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label">&lt;progress&gt;</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkProgressBar" id="progressbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">6</property>
<property name="pulse_step">0.10000000149</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cancel_upload_button">
<property name="label" translatable="yes">Cancel Upload</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<property name="margin_top">6</property>
<signal name="clicked" handler="on_cancel_upload_button_clicked" swapped="no"/>
<style>
<class name="destructive-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
</interface>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<!-- Generated with glade 3.22.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkWindow" id="plugins_window">
@ -13,9 +13,6 @@
<property name="type_hint">dialog</property>
<signal name="destroy" handler="on_plugins_window_destroy" swapped="no"/>
<signal name="key-press-event" handler="on_key_press_event" swapped="no"/>
<child type="titlebar">
<placeholder/>
</child>
<child>
<object class="GtkNotebook" id="plugins_notebook">
<property name="visible">True</property>
@ -235,7 +232,6 @@
<property name="wrap">True</property>
<property name="wrap_mode">word-char</property>
<property name="selectable">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
@ -379,6 +375,9 @@
</child>
</object>
</child>
<child type="titlebar">
<placeholder/>
</child>
</object>
<object class="GtkTextBuffer" id="textbuffer1">
<property name="text" translatable="yes">Plug-in decription should be displayed here. This text will be erased during PluginsWindow initialization.</property>

View File

@ -10,8 +10,7 @@
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<property name="min_content_height">260</property>
<property name="overlay_scrolling">False</property>
<property name="min_content_height">200</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>

View File

@ -2,7 +2,6 @@
"servers":[
"0nl1ne.at",
"404.city",
"blabber.im",
"brauchen.info",
"chatme.im",
"comm.unicate.me",

View File

@ -1,11 +1,11 @@
.gajim-incoming-nickname {
color: rgb(207, 49, 47)
color: rgb(164, 0, 0)
}
.gajim-outgoing-nickname {
color: rgb(38, 139, 210)
color: rgb(52, 101, 164)
}
.gajim-url {
color: rgb(53, 132, 228)
color: rgb(117, 80, 123)
}
.gajim-highlight-message {
color: rgb(245, 121, 0)
@ -15,4 +15,4 @@
}
.gajim-status-message {
color: rgb(115, 210, 22)
}
}

View File

@ -55,7 +55,6 @@ from gajim.common.exceptions import GajimGeneralException
# Compat with Gajim 1.0.3 for plugins
from gajim.gtk.dialogs import *
from gajim.gtk.add_contact import AddNewContactWindow
from gajim.gtk.util import get_builder
log = logging.getLogger('gajim.dialogs')
@ -1734,18 +1733,22 @@ class ProgressWindow(Gtk.ApplicationWindow):
self.set_position(Gtk.WindowPosition.CENTER)
self.set_show_menubar(False)
self.set_title(_('File Transfer'))
self.set_default_size(250, -1)
self.event = file.event
self.file = file
self._ui = get_builder('httpupload_progress_dialog.ui')
self.xml = gtkgui_helpers.get_gtk_builder(
'httpupload_progress_dialog.ui')
self.add(self._ui.box)
self.label = self.xml.get_object('label')
self.progressbar = self.xml.get_object('progressbar')
self.add(self.xml.get_object('box'))
self.pulse = GLib.timeout_add(100, self._pulse_progressbar)
self.show_all()
self.connect('destroy', self._on_destroy)
self._ui.connect_signals(self)
app.ged.register_event_handler('httpupload-progress', ged.CORE,
self._on_httpupload_progress)
@ -1753,23 +1756,20 @@ class ProgressWindow(Gtk.ApplicationWindow):
if self.file != obj.file:
return
if obj.status == 'request':
self._ui.label.set_text(_('Requesting HTTP Upload Slot…'))
self.label.set_text(_('Requesting HTTP Upload Slot…'))
elif obj.status == 'close':
self.destroy()
elif obj.status == 'upload':
self._ui.label.set_text(_('Uploading file via HTTP File Upload…'))
self.label.set_text(_('Uploading file via HTTP File Upload…'))
elif obj.status == 'update':
self.update_progress(obj.seen, obj.total)
elif obj.status == 'encrypt':
self._ui.label.set_text(_('Encrypting file…'))
self.label.set_text(_('Encrypting file…'))
def _pulse_progressbar(self):
self._ui.progressbar.pulse()
self.progressbar.pulse()
return True
def on_cancel_upload_button_clicked(self, widget):
self.destroy()
def _on_destroy(self, *args):
self.event.set()
if self.pulse:
@ -1783,9 +1783,6 @@ class ProgressWindow(Gtk.ApplicationWindow):
if self.pulse:
GLib.source_remove(self.pulse)
self.pulse = None
self._ui.progressbar.set_fraction(float(seen) / total)
size_total = round(total / (1024 * 1024), 1)
size_progress = round(seen / (1024 * 1024), 1)
self._ui.progress_label.set_text(
_('%(progress)s of %(total)s MiB sent') % \
{'progress': str(size_progress), 'total': str(size_total)})
pct = (float(seen) / total) * 100.0
self.progressbar.set_fraction(float(seen) / total)
self.progressbar.set_text(str(int(pct)) + "%")

View File

@ -27,7 +27,7 @@ from distutils.version import LooseVersion as V
# Install _() in namespace
from gajim.common import i18n
_MIN_NBXMPP_VER = "0.6.10"
_MIN_NBXMPP_VER = "0.6.9"
_MIN_GTK_VER = "3.22.0"

View File

@ -17,8 +17,6 @@
'''Window to create new post for discussion groups service.'''
import uuid
from gajim.common import app
from nbxmpp import Node
from gajim import gtkgui_helpers
@ -67,7 +65,7 @@ class GroupsPostWindow:
# publish it to node
con = app.connections[self.account]
con.get_module('PubSub').send_pb_publish(
self.servicejid, self.groupid, item, str(uuid.uuid4()))
self.servicejid, self.groupid, item, '0')
# close the window
self.window.destroy()

View File

@ -564,7 +564,6 @@ class AccountCreationWizard:
def create_vars(self, config):
app.config.add_per('accounts', self.account)
config['account_label'] = '%s@%s' % (config['name'], config['hostname'])
if not config['savepass']:
config['password'] = ''

View File

@ -33,9 +33,7 @@ from gajim.common import app
from gajim.common import helpers
from gajim.common import exceptions
from gajim.common.i18n import _
from gajim.common.const import ShowConstant
from gajim.common.const import KindConstant
from gajim.common.const import StyleAttr
from gajim.common.const import ShowConstant, KindConstant
from gajim import conversation_textview
@ -81,9 +79,7 @@ class HistoryWindow:
account, used_in_history_window=True)
scrolledwindow.add(self.history_textview.tv)
self.history_buffer = self.history_textview.tv.get_buffer()
highlight_color = app.css_config.get_value(
'.gajim-highlight-message', StyleAttr.COLOR)
self.history_buffer.create_tag('highlight', background=highlight_color)
self.history_buffer.create_tag('highlight', background='yellow')
self.history_buffer.create_tag('invisible', invisible=True)
self.checkbutton = xml.get_object('log_history_checkbutton')
self.show_status_checkbutton = xml.get_object('show_status_checkbutton')

View File

@ -75,14 +75,6 @@ class ServiceRegistration(Gtk.Assistant):
sidebar = main_box.get_children()[0]
main_box.remove(sidebar)
def _build_dataform(self, form, is_form):
if not is_form:
from gajim import config
return config.FakeDataForm(form)
dataform = dataforms.extend_form(node=form)
return DataFormWidget(dataform)
def _on_page_change(self, assistant, page):
if self.get_current_page() == Page.REQUEST:
self._con.get_module('Register').get_register_form(
@ -94,22 +86,23 @@ class ServiceRegistration(Gtk.Assistant):
def _on_get_success(self, form, is_form):
log.info('Show Form page')
self._is_form = is_form
self._data_form_widget = self._build_dataform(form, is_form)
if is_form:
dataform = dataforms.extend_form(node=form)
self._data_form_widget = DataFormWidget(dataform)
else:
from gajim import config
self._data_form_widget = config.FakeDataForm(form)
self.get_nth_page(Page.FORM).set_form(self._data_form_widget)
page = self.get_nth_page(Page.FORM)
page.pack_start(self._data_form_widget, True, True, 0)
self._data_form_widget.show_all()
self.set_current_page(Page.FORM)
def _on_error(self, error_text, form=None, is_form=False):
if form is not None:
log.info('Show Form page')
self._is_form = is_form
self._data_form_widget = self._build_dataform(form, is_form)
self.get_nth_page(Page.FORM).set_form(self._data_form_widget, error_text=error_text)
self.set_current_page(Page.FORM)
else:
log.info('Show Error page')
self.get_nth_page(Page.ERROR).set_text(error_text)
self.set_current_page(Page.ERROR)
def _on_error(self, error_text):
log.info('Show Error page')
page = self.get_nth_page(Page.ERROR)
page.set_text(error_text)
self.set_current_page(Page.ERROR)
def _on_cancel(self, widget):
self.destroy()
@ -166,25 +159,6 @@ class FormPage(Gtk.Box):
def __init__(self):
super().__init__(orientation=Gtk.Orientation.VERTICAL)
self._form = None
self._label = Gtk.Label()
self._label.set_no_show_all(True)
self._label.get_style_context().add_class('error-color')
self.pack_end(self._label, False, False, 0)
def set_form(self, form, error_text=None):
if self._form is not None:
self.remove(self._form)
self._form.destroy()
self._label.hide()
self._form = form
if error_text is not None:
self._label.set_text(error_text)
self._label.show()
self.pack_start(form, True, True, 0)
self._form.show_all()
class SuccessfulPage(Gtk.Box):

View File

@ -30,7 +30,6 @@ from gajim.common import app
from gajim.common import configpaths
from gajim.common import i18n
from gajim.common.i18n import _
from gajim.common.const import Display
_icon_theme = Gtk.IconTheme.get_default()
_icon_theme.append_search_path(configpaths.get('ICONS'))
@ -118,17 +117,11 @@ def get_iconset_name_for(name: str) -> str:
def get_total_screen_geometry() -> Tuple[int, int]:
total_width = 0
total_height = 0
display = Gdk.Display.get_default()
monitors = display.get_n_monitors()
for num in range(0, monitors):
monitor = display.get_monitor(num)
geometry = monitor.get_geometry()
total_width += geometry.width
total_height = max(total_height, geometry.height)
log.debug('Get screen geometry: %s %s', total_width, total_height)
return total_width, total_height
screen = Gdk.Screen.get_default()
window = Gdk.Screen.get_root_window(screen)
width, height = window.get_width(), window.get_height()
log.debug('Get screen geometry: %s %s', width, height)
return width, height
def resize_window(window: Gtk.Window, width: int, height: int) -> None:
@ -162,16 +155,6 @@ def move_window(window: Gtk.Window, pos_x: int, pos_y: int) -> None:
window.move(pos_x, pos_y)
def restore_roster_position(window):
if not app.config.get('save-roster-position'):
return
if app.is_display(Display.WAYLAND):
return
move_window(window,
app.config.get('roster_x-position'),
app.config.get('roster_y-position'))
def get_completion_liststore(entry: Gtk.Entry) -> Gtk.ListStore:
"""
Create a completion model for entry widget completion list consists of

View File

@ -85,7 +85,7 @@ class ExceptionDialog():
traceback.print_exception(type_, value, tb, None, trace)
self.text = self.get_issue_text(trace.getvalue())
buffer_.set_text(self.text)
print(self.text, file=sys.stderr)
print(self.text)
self.exception_view.set_editable(False)
self.dialog.show()
if __name__ == '__main__':

View File

@ -17,6 +17,8 @@
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
import gc
from gi.repository import Gtk
from gi.repository import GLib
from gi.repository import GObject
@ -406,6 +408,9 @@ class MessageTextView(Gtk.TextView):
self.add_child_at_anchor(image, anchor)
buffer_.insert_at_cursor(' ')
def destroy(self):
GLib.idle_add(gc.collect)
def clear(self, widget=None):
"""
Clear text in the textview

View File

@ -75,10 +75,31 @@ class Notification:
Handle notifications
"""
def __init__(self):
self._dbus_available = False
self.daemon_capabilities = ['actions']
self._detect_dbus_caps()
# Detect if actions are supported by the notification daemon
if sys.platform not in ('win32', 'darwin'):
def on_proxy_ready(source, res, data=None):
try:
proxy = Gio.DBusProxy.new_finish(res)
self.daemon_capabilities = proxy.GetCapabilities()
except GLib.Error as e:
if e.domain == 'g-dbus-error-quark':
log.info('Notifications D-Bus connection failed: %s',
e.message)
else:
raise
else:
log.debug('Notifications D-Bus connected')
log.debug('Connecting to Notifications D-Bus')
Gio.DBusProxy.new_for_bus(Gio.BusType.SESSION,
Gio.DBusProxyFlags.DO_NOT_CONNECT_SIGNALS,
None,
'org.freedesktop.Notifications',
'/org/freedesktop/Notifications',
'org.freedesktop.Notifications',
None, on_proxy_ready)
app.ged.register_event_handler(
'notification', ged.GUI2, self._nec_notification)
@ -86,30 +107,6 @@ class Notification:
'our-show', ged.GUI2, self._nec_our_status)
app.events.event_removed_subscribe(self._on_event_removed)
def _detect_dbus_caps(self):
if sys.platform in ('win32', 'darwin'):
return
def on_proxy_ready(_source, res, _data=None):
try:
proxy = Gio.DBusProxy.new_finish(res)
self.daemon_capabilities = proxy.GetCapabilities()
except GLib.Error:
log.exception('Notifications D-Bus connection failed')
else:
self._dbus_available = True
log.info('Notifications D-Bus connected')
log.info('Connecting to Notifications D-Bus')
Gio.DBusProxy.new_for_bus(Gio.BusType.SESSION,
Gio.DBusProxyFlags.DO_NOT_CONNECT_SIGNALS,
None,
'org.freedesktop.Notifications',
'/org/freedesktop/Notifications',
'org.freedesktop.Notifications',
None,
on_proxy_ready)
def _nec_notification(self, obj):
if obj.do_popup:
icon_name = self._get_icon_name(obj)
@ -173,9 +170,6 @@ class Notification:
app.interface.roster.popup_notification_windows.append(instance)
return
if not self._dbus_available:
return
scale = gtkgui_helpers.get_monitor_scale_factor()
icon_pixbuf = gtkgui_helpers.gtk_icon_theme.load_icon_for_scale(
icon_name, 48, scale, 0)
@ -226,9 +220,8 @@ class Notification:
app.app.send_notification(notif_id, notification)
def withdraw(self, *args):
if not self._dbus_available:
return
app.app.withdraw_notification(self._id(*args))
if sys.platform != 'win32':
app.app.withdraw_notification(self._id(*args))
def _id(self, *args):
return ','.join(args)

View File

@ -36,12 +36,10 @@ from gajim.gtk.dialogs import YesNoDialog
from gajim.gtk.filechoosers import ArchiveChooserDialog
from gajim.common import app
from gajim.common import configpaths
from gajim.common.exceptions import PluginsystemError
from gajim.common.helpers import launch_browser_mailer
from gajim.plugins.helpers import log_calls
from gajim.plugins.helpers import GajimPluginActivateException
from gajim.plugins.plugins_i18n import _
from gajim.common.exceptions import PluginsystemError
@unique
@ -65,21 +63,14 @@ class PluginsWindow:
widgets_to_extract = ('plugins_notebook', 'plugin_name_label',
'plugin_version_label', 'plugin_authors_label',
'plugin_homepage_linkbutton', 'install_plugin_button',
'uninstall_plugin_button', 'configure_plugin_button',
'installed_plugins_treeview', 'available_text',
'available_text_label')
'plugin_homepage_linkbutton', 'uninstall_plugin_button',
'configure_plugin_button', 'installed_plugins_treeview',
'available_text', 'available_text_label')
for widget_name in widgets_to_extract:
setattr(self, widget_name, builder.get_object(widget_name))
self.plugin_description_textview = builder.get_object('description')
# Disable 'Install from ZIP' for Flatpak installs
if app.is_flatpak():
self.install_plugin_button.set_tooltip_text(
_('Click to view Gajim\'s wiki page on how to install plugins in Flatpak.'))
self.installed_plugins_model = Gtk.ListStore(object, str, bool, bool,
GdkPixbuf.Pixbuf)
self.installed_plugins_treeview.set_model(self.installed_plugins_model)
@ -246,10 +237,6 @@ class PluginsWindow:
@log_calls('PluginsWindow')
def on_install_plugin_button_clicked(self, widget):
if app.is_flatpak():
launch_browser_mailer('url', 'https://dev.gajim.org/gajim/gajim/wikis/help/flathub')
return
def show_warn_dialog():
text = _('Archive is malformed')
dialog = WarningDialog(text, '', transient_for=self.window)

View File

@ -406,9 +406,9 @@ class PluginManager(metaclass=Singleton):
return
for con in app.connections.values():
for module in plugin.modules:
instance, name = module.get_instance(con)
if not module.zeroconf and con.name == 'Local':
continue
instance, name = module.get_instance(con)
modules.register_single(con, instance, name)
# If handlers have been registered, register the
@ -558,9 +558,9 @@ class PluginManager(metaclass=Singleton):
return
for module in plugin.modules:
instance, name = module.get_instance(con)
if not module.zeroconf and con.name == 'Local':
continue
instance, name = module.get_instance(con)
modules.register_single(con, instance, name)
def _plugin_is_active_in_global_config(self, plugin):

View File

@ -59,7 +59,6 @@ from gajim.common import helpers
from gajim.common import idle
from gajim.common.exceptions import GajimGeneralException
from gajim.common import i18n
from gajim.common.helpers import save_roster_position
from gajim.common.i18n import _
from gajim.common.const import PEPEventType, AvatarSize, StyleAttr
from gajim.common.dbus import location
@ -84,8 +83,6 @@ from gajim.gtk.service_registration import ServiceRegistration
from gajim.gtk.history import HistoryWindow
from gajim.gtk.accounts import AccountsWindow
from gajim.gtk.util import restore_roster_position
log = logging.getLogger('gajim.roster')
@ -2410,7 +2407,11 @@ class RosterWindow:
if not app.config.get('quit_on_roster_x_button') and (
(app.interface.systray_enabled and app.config.get('trayicon') != \
'on_event') or app.config.get('allow_hide_roster')):
save_roster_position(self.window)
if app.config.get('save-roster-position'):
x, y = self.window.get_position()
log.debug('Save roster position (get_position): %s %s', x, y)
app.config.set('roster_x-position', x)
app.config.set('roster_y-position', y)
if os.name == 'nt' or app.config.get('hide_on_roster_x_button'):
self.window.hide()
else:
@ -2435,7 +2436,11 @@ class RosterWindow:
# in case show_roster_on_start is False and roster is never shown
# window.window is None
if self.window.get_window() is not None:
save_roster_position(self.window)
if app.config.get('save-roster-position'):
x, y = self.window.get_window().get_root_origin()
log.debug('Save roster position (get_root_origin): %s %s', x, y)
app.config.set('roster_x-position', x)
app.config.set('roster_y-position', y)
width, height = self.window.get_size()
app.config.set('roster_width', width)
app.config.set('roster_height', height)
@ -2496,11 +2501,8 @@ class RosterWindow:
self.send_pep(acct, pep_dict)
def on_continue2(message, pep_dict):
if 'file_transfers' not in app.interface.instances:
on_continue3(message, pep_dict)
return
# check if there is an active file transfer
from gajim.common.protocol.bytestream import is_transfer_active
from gajim.common.protocol.bytestream import (is_transfer_active)
files_props = app.interface.instances['file_transfers'].\
files_props
transfer_active = False
@ -5701,11 +5703,13 @@ class RosterWindow:
if len(app.connections) < 2:
# Do not merge accounts if only one exists
self.regroup = False
gtkgui_helpers.resize_window(self.window,
app.config.get('roster_width'),
app.config.get('roster_height'))
restore_roster_position(self.window)
if app.config.get('save-roster-position'):
gtkgui_helpers.move_window(self.window,
app.config.get('roster_x-position'),
app.config.get('roster_y-position'))
self.popups_notification_height = 0
self.popup_notification_windows = []

View File

@ -30,8 +30,6 @@ from gajim import gtkgui_helpers
from gajim.common import app
from gajim.common import helpers
from gajim.common.i18n import _
from gajim.common.helpers import save_roster_position
from gajim.gtk.util import restore_roster_position
from gajim.gtk.single_message import SingleMessageWindow
@ -373,11 +371,18 @@ class StatusIcon:
# No pending events, so toggle visible/hidden for roster window
if win.get_property('visible'):
if win.get_property('has-toplevel-focus') or os.name == 'nt':
save_roster_position(win)
if app.config.get('save-roster-position'):
x, y = win.get_position()
app.config.set('roster_x-position', x)
app.config.set('roster_y-position', y)
win.hide() # else we hide it from VD that was visible in
else:
win.show_all()
restore_roster_position(win)
if not win.get_property('visible'):
win.show_all()
if app.config.get('save-roster-position'):
gtkgui_helpers.move_window(win,
app.config.get('roster_x-position'),
app.config.get('roster_y-position'))
if not app.config.get('roster_window_skip_taskbar'):
win.set_property('skip-taskbar-hint', False)
win.present_with_time(Gtk.get_current_event_time())
@ -389,9 +394,11 @@ class StatusIcon:
if not event:
return
win = app.interface.roster.window
if not win.get_property('visible'):
# Needed if we are in one window mode
restore_roster_position(win)
if not win.get_property('visible') and app.config.get(
'save-roster-position'):
gtkgui_helpers.move_window(win,
app.config.get('roster_x-position'),
app.config.get('roster_y-position'))
app.interface.handle_event(account, jid, event.type_)
def on_middle_click(self):

View File

@ -609,7 +609,8 @@ class FileTransfersTooltip():
self.sid = sid
return False, self.widget
def _create_tooltip(self, file_props, _sid):
@staticmethod
def _create_tooltip(file_props, sid):
ft_table = Gtk.Table(2, 1)
ft_table.set_property('column-spacing', 2)
current_row = 1
@ -641,7 +642,26 @@ class FileTransfersTooltip():
if not transfered_len:
transfered_len = 0
properties.append((_('Transferred: '), helpers.convert_bytes(transfered_len)))
status = self._get_current_status(file_props)
status = ''
if file_props.started:
status = _('Not started')
if file_props.stopped:
status = _('Stopped')
elif file_props.completed:
status = _('Completed')
elif not file_props.connected:
if file_props.completed:
status = _('Completed')
else:
if file_props.paused:
status = Q_('?transfer status:Paused')
elif file_props.stalled:
# stalled is not paused. it is like 'frozen' it stopped alone
status = _('Stalled')
else:
status = _('Transferring')
else:
status = _('Not started')
properties.append((_('Status: '), status))
file_desc = file_props.desc or ''
properties.append((_('Description: '), GLib.markup_escape_text(
@ -666,24 +686,6 @@ class FileTransfersTooltip():
ft_table.show_all()
return ft_table
@staticmethod
def _get_current_status(file_props):
if file_props.stopped:
return _('Aborted')
if file_props.completed:
return _('Completed')
if file_props.paused:
return Q_('?transfer status:Paused')
if file_props.stalled:
# stalled is not paused. it is like 'frozen' it stopped alone
return _('Stalled')
if file_props.connected:
if file_props.started:
return _('Transferring')
return _('Not started')
return _('Not started')
def colorize_status(status):
"""

1211
po/be.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1217
po/bg.po

File diff suppressed because it is too large Load Diff

1195
po/br.po

File diff suppressed because it is too large Load Diff

1196
po/ca.po

File diff suppressed because it is too large Load Diff

1217
po/cs.po

File diff suppressed because it is too large Load Diff

1217
po/da.po

File diff suppressed because it is too large Load Diff

1236
po/de.po

File diff suppressed because it is too large Load Diff

1195
po/el.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1211
po/eo.po

File diff suppressed because it is too large Load Diff

3847
po/es.po

File diff suppressed because it is too large Load Diff

1211
po/eu.po

File diff suppressed because it is too large Load Diff

1625
po/fr.po

File diff suppressed because it is too large Load Diff

1211
po/gl.po

File diff suppressed because it is too large Load Diff

1217
po/he.po

File diff suppressed because it is too large Load Diff

1217
po/hr.po

File diff suppressed because it is too large Load Diff

1217
po/hu.po

File diff suppressed because it is too large Load Diff

1217
po/it.po

File diff suppressed because it is too large Load Diff

1217
po/ja.po

File diff suppressed because it is too large Load Diff

1217
po/kk.po

File diff suppressed because it is too large Load Diff

1196
po/lt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1236
po/nl.po

File diff suppressed because it is too large Load Diff

1217
po/pl.po

File diff suppressed because it is too large Load Diff

1613
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1217
po/ru.po

File diff suppressed because it is too large Load Diff

1217
po/sk.po

File diff suppressed because it is too large Load Diff

1217
po/sr.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1217
po/sv.po

File diff suppressed because it is too large Load Diff

1193
po/tr.po

File diff suppressed because it is too large Load Diff

1217
po/uk.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -97,11 +97,10 @@ function install_deps {
mingw-w64-"${ARCH}"-"${PYTHON_ID}"-pyopenssl \
mingw-w64-"${ARCH}"-"${PYTHON_ID}"-docutils \
mingw-w64-"${ARCH}"-"${PYTHON_ID}"-certifi \
mingw-w64-"${ARCH}"-"${PYTHON_ID}"-six \
mingw-w64-"${ARCH}"-"${PYTHON_ID}"-pygments
mingw-w64-"${ARCH}"-"${PYTHON_ID}"-six
PIP_REQUIREMENTS="\
git+https://dev.gajim.org/gajim/python-nbxmpp.git@nbxmpp_0.6
nbxmpp==0.6.9
git+https://dev.gajim.org/lovetox/pybonjour-python3.git
git+https://github.com/enthought/pywin32-ctypes.git
keyring