Commit 7e9c5706 authored by Martin's avatar Martin

Import upstream version 1.1.3

parent 48733993
Pipeline #44369 failed with stages
in 1 minute and 41 seconds
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
......
......@@ -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.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"
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"
# on_finish:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
......
......@@ -3,8 +3,6 @@ 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
......@@ -22,6 +20,8 @@ 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/e7/a7/4cd50e57cc6f436f1cc3a7e8fa700ff9b8b4d471620629074913e3735fb2/cffi-1.11.5.tar.gz
sha256: e90f17980e6ab0f3c2f3730e56d1fe9bcba1891eeea58966e89d352492cc74f4
url: https://files.pythonhosted.org/packages/64/7c/27367b38e6cc3e1f49f193deb761fe75cda9f95da37b67b422e62281fcac/cffi-1.12.2.tar.gz
sha256: e113878a446c6228669144ae8a56e268c91b7f1fafae927adc4879d9849e0ea7
- name: python3-asn1crypto
buildsystem: simple
......@@ -77,11 +77,11 @@ modules:
- name: python3-idna
buildsystem: simple
build-commands:
- pip3 install --prefix=/app idna-2.7-py2.py3-none-any.whl
- pip3 install --prefix=/app idna-2.8-py2.py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/4b/2a/0276479a4b3caeb8a8c1af2f8e4355746a97fab05a372e4a2c6a6b876165/idna-2.7-py2.py3-none-any.whl
sha256: 156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e
url: https://files.pythonhosted.org/packages/14/2c/cd551d81dbe15200be1cf41cd03869a46fe7226e7450af7a6545bfc474c9/idna-2.8-py2.py3-none-any.whl
sha256: ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c
- name: python3-cryptography
buildsystem: simple
......@@ -89,17 +89,17 @@ modules:
- pip3 install --prefix=/app .
sources:
- type: archive
url: https://files.pythonhosted.org/packages/22/21/233e38f74188db94e8451ef6385754a98f3cad9b59bedf3a8e8b14988be4/cryptography-2.3.1.tar.gz
sha256: 8d10113ca826a4c29d5b85b2c4e045ffa8bad74fb525ee0eceb1d38d4c70dfd6
url: https://files.pythonhosted.org/packages/07/ca/bc827c5e55918ad223d59d299fff92f3563476c3b00d0a9157d9c0217449/cryptography-2.6.1.tar.gz
sha256: 26c821cbeb683facb966045e2064303029d572a87ee69ca5a1bf54bf55f93ca6
- name: python3-pyopenssl
buildsystem: simple
build-commands:
- pip3 install --prefix=/app pyOpenSSL-18.0.0-py2.py3-none-any.whl
- pip3 install --prefix=/app pyOpenSSL-19.0.0-py2.py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/96/af/9d29e6bd40823061aea2e0574ccb2fcf72bfd6130ce53d32773ec375458c/pyOpenSSL-18.0.0-py2.py3-none-any.whl
sha256: 26ff56a6b5ecaf3a2a59f132681e2a80afcc76b4f902f612f518f92c2a1bf854
url: https://files.pythonhosted.org/packages/01/c8/ceb170d81bd3941cbeb9940fc6cc2ef2ca4288d0ca8929ea4db5905d904d/pyOpenSSL-19.0.0-py2.py3-none-any.whl
sha256: c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6
- 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.0-py3-none-any.whl
- pip3 install --prefix=/app SecretStorage-3.1.1-py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/d8/e8/80975fd281764c80b2eb581a7f25d2109786e273b8925e8161bd2d06d10a/SecretStorage-3.1.0-py3-none-any.whl
sha256: 20196abd1a9d1310df7573d58ca6e7ed9292218c98ca3638eea07beb16080343
url: https://files.pythonhosted.org/packages/82/59/cb226752e20d83598d7fdcabd7819570b0329a61db07cfbdd21b2ef546e3/SecretStorage-3.1.1-py3-none-any.whl
sha256: 7a119fb52a88e398dbb22a4b3eb39b779bfbace7e4153b7bc6e5954d86282a8a
- name: python3-entrypoints
buildsystem: simple
build-commands:
- pip3 install --prefix=/app entrypoints-0.2.3-py2.py3-none-any.whl
- pip3 install --prefix=/app entrypoints-0.3-py2.py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/cc/8b/4eefa9b47f1910b3d2081da67726b066e379b04ca897acfe9f92bac56147/entrypoints-0.2.3-py2.py3-none-any.whl
sha256: 10ad569bb245e7e2ba425285b9fa3e8178a0dc92fc53b1e1c553805e15a8825b
url: https://files.pythonhosted.org/packages/ac/c6/44694103f8c221443ee6b0041f69e2740d89a25641e62fb4f2ee568f2f9c/entrypoints-0.3-py2.py3-none-any.whl
sha256: 589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19
- name: python3-keyring
buildsystem: simple
build-commands:
- pip3 install --prefix=/app keyring-16.0.2-py2.py3-none-any.whl
- pip3 install --prefix=/app keyring-18.0.0-py2.py3-none-any.whl
cleanup:
- /bin
sources:
- type: file
url: https://files.pythonhosted.org/packages/5f/cb/dc7b2215cd82b77e7b8b48abd8989c1b09990d4c91a3ccfdc18a61157b36/keyring-16.0.2-py2.py3-none-any.whl
sha256: 2a5cf5e596cbf8b66b98b8df2c214adfe21e6e18baa82006b2c482bd0c4be94c
url: https://files.pythonhosted.org/packages/a1/28/0058032477bfdf2003e605d175629963759220661615443e20711446bfa7/keyring-18.0.0-py2.py3-none-any.whl
sha256: ca33f5ccc542b9ffaa196ee9a33488069e5e7eac77d5b81969f8a3ce74d0230c
- name: python3-cssutils
buildsystem: simple
......@@ -182,8 +182,8 @@ modules:
- pip3 install --prefix=/app .
sources:
- type: archive
url: https://files.pythonhosted.org/packages/24/54/23a475a0d7d3664ea21b14ce907245dc390496f31d229a9aac2ae20c7c28/nbxmpp-0.6.8.tar.gz
sha256: 8c2b4b8aac1a8c6d07c1e30af542fde20a70a9b8c7c04017e9cea0db654437c6
url: https://files.pythonhosted.org/packages/d6/01/34b2a441926780f26edd21490158afe0eb76beae4efbb6bc4d3323eae69a/nbxmpp-0.6.10.tar.gz
sha256: cd73417777e4847fdd8d0d96c7cafc606952edbd2b9d52a2a72bb2aaa04d08ef
- name: gajim
buildsystem: simple
......@@ -193,5 +193,6 @@ modules:
sources:
- type: git
url: https://dev.gajim.org/gajim/gajim.git
branch: gajim_1.1
post-install:
- install -d /app/plugins
import os
import subprocess
__version__ = "1.1.2"
__version__ = "1.1.3"
IS_FLATPAK = False
if os.path.exists('/app/share/run-as-flatpak'):
......
......@@ -379,6 +379,7 @@ 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
......
......@@ -225,6 +225,9 @@ 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,
......@@ -435,6 +438,17 @@ 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
......@@ -1063,6 +1077,9 @@ 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)
......
......@@ -323,7 +323,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
self.set_emoticon_popover()
# Attach speller
self.spell_checker = None
self.set_speller()
self.conv_textview.tv.show()
......@@ -474,15 +473,15 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
if gspell_lang is None:
return
self.spell_checker = Gspell.Checker.new(gspell_lang)
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(self.spell_checker)
spell_buffer.set_spell_checker(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)
self.spell_checker.connect('notify::language', self.on_language_changed)
spell_checker.connect('notify::language', self.on_language_changed)
def get_speller_language(self):
per_type = 'contacts'
......@@ -560,14 +559,27 @@ 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 on_quote(self, widget, text):
def insert_as_quote(self, text: str) -> None:
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):
"""
......
......@@ -39,11 +39,13 @@ 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
......@@ -148,6 +150,7 @@ 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',
......@@ -192,6 +195,18 @@ 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
......
......@@ -77,6 +77,14 @@ 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,
......
......@@ -905,10 +905,6 @@ 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 = []
......@@ -918,6 +914,9 @@ 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()
......
......@@ -193,6 +193,13 @@ class SyncThreshold(IntEnum):
return str(self.value)
class Display(Enum):
X11 = 'X11Display'
WAYLAND = 'GdkWaylandDisplay'
WIN32 = 'GdkWin32Display'
QUARTZ = 'GdkQuartzDisplay'
ACTIVITIES = {
'doing_chores': {
'category': _('Doing Chores'),
......
......@@ -116,6 +116,10 @@ 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):
"""
......
......@@ -42,6 +42,7 @@ 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
......@@ -51,11 +52,17 @@ 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')
......@@ -552,12 +559,6 @@ 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
......@@ -1534,3 +1535,14 @@ 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)
......@@ -151,13 +151,18 @@ 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)
print(error, file=sys.stderr)
try:
LANG = get_default_lang()
print('Found default language: %s' % 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
except Exception as error:
print('Failed to determine default language')
print('Failed to determine default language', file=sys.stderr)
import traceback
traceback.print_exc()
......@@ -173,6 +178,6 @@ for dir_ in iter_locale_dirs():
else:
break
else:
print('No translations found')
print('Dirs searched: %s' % get_locale_dirs())
print('No translations found', file=sys.stderr)
print('Dirs searched: %s' % get_locale_dirs(), file=sys.stderr)
_ = _translation.gettext
......@@ -445,6 +445,8 @@ 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,
......
......@@ -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('HIGH:!aNULL:!3DES')
ctx.set_cipher_list(b'HIGH:!aNULL:!3DES')
if fingerprint == 'server': # for testing purposes only
ctx.set_verify(SSL.VERIFY_NONE|SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
......
......@@ -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))
print(_('%s is not a valid loglevel') % repr(arg), file=sys.stderr)
return 0
def parseLogTarget(arg):
......@@ -69,7 +69,8 @@ def parseAndSetLogLevels(arg):
target = parseLogTarget(target.strip())
if target:
logging.getLogger(target).setLevel(level)
print("Logger %s level set to %d" % (target, level))
print("Logger %s level set to %d" % (target, level),
file=sys.stderr)
class colors:
......
......@@ -207,6 +207,11 @@ 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)
......
......@@ -175,6 +175,10 @@ 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)
......
......@@ -92,7 +92,10 @@ class Register:
error = stanza.getErrorMsg()
log.info('Error: %s', error)
if error_cb() is not None:
error_cb()(error)
form = is_form = None
if stanza.getTagAttr('error', 'type') == 'modify':
form, is_form = self._get_register_form(stanza)
error_cb()(error, form, is_form)
return
self._con.get_module('Presence').subscribe(agent, auto_auth=True)
......@@ -116,8 +119,7 @@ class Register:
iq, self._register_info_response, {'success_cb': weak_success_cb,
'error_cb': weak_error_cb})
@staticmethod
def _register_info_response(_con, stanza, success_cb, error_cb):
def _register_info_response(self, _con, stanza, success_cb, error_cb):
if not nbxmpp.isResultNode(stanza):
error = stanza.getErrorMsg()
log.info('Error: %s', error)
......@@ -125,18 +127,28 @@ 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'
......@@ -27,6 +27,7 @@ import os
import sys
import re
import logging
from pathlib import Path
from gajim.common import app
from gajim.common import caps_cache
......@@ -104,25 +105,22 @@ class OptionsParser:
fd.write(s + ' = ' + value + '\n')
def write(self):
(base_dir, filename) = os.path.split(self.__filename)
self.__tempfile = os.path.join(base_dir, '.' + filename)
config_path = Path(self.__filename)
tempfile = 'temp_%s' % config_path.name
temp_filepath = config_path.parent / tempfile
try:
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)
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
try:
os.rename(self.__tempfile, self.__filename)
except IOError as e:
return str(e)
temp_filepath.replace(config_path)
except Exception:
log.exception('Failed to replace config file')
else:
log.info('Successful saved config file')
def update_config(self, old_version, new_version):
old_version_list = old_version.split('.') # convert '0.x.y' to (0, x, y)
......
......@@ -23,7 +23,7 @@ import struct
import hashlib
import os
import time
import platform
import sys
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 self.senders:
for key in list(self.senders):
if idx in key:
sender = self.senders[key]
if sender.file_props.type_ != 's':
......@@ -687,13 +687,11 @@ 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):
# peer stopped reading
self.state = 8 # end connection
self.disconnect()
self.file_props.error = -1
return -1
return self._on_send_exception()
self.size += lenn
current_time = time.time()
self.file_props.elapsed_time += current_time - \
......@@ -719,6 +717,13 @@ 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
......@@ -1431,7 +1436,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 int(platform.win32_ver()[0]) >= 6: # Win Vista +
if sys.getwindowsversion().major >= 6: # Win Vista +
# 47 is socket.IPPROTO_IPV6
# 27 is socket.IPV6_V6ONLY under windows, but not defined ...
self._serv.setsockopt(41, 27, 0)
......
......@@ -26,7 +26,6 @@ from gajim.common.zeroconf import zeroconf
from nbxmpp.protocol import *
import socket
import platform
import ssl
import errno