76445a6867
Both for displaying incoming messages, and sending OTR and legacy OpenPGP.
220 lines
8.5 KiB
Python
220 lines
8.5 KiB
Python
# Copyright 2010-2011 Florent Le Coz <louiz@louiz.org>
|
|
#
|
|
# This file is part of Poezio.
|
|
#
|
|
# Poezio is free software: you can redistribute it and/or modify
|
|
# it under the terms of the zlib license. See the COPYING file.
|
|
|
|
"""
|
|
Defines the Connection class
|
|
"""
|
|
|
|
import logging
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
import getpass
|
|
import subprocess
|
|
import sys
|
|
|
|
import slixmpp
|
|
from slixmpp.plugins.xep_0184 import XEP_0184
|
|
|
|
from poezio import common
|
|
from poezio import fixes
|
|
from poezio.common import safeJID
|
|
from poezio.config import config, options
|
|
|
|
class Connection(slixmpp.ClientXMPP):
|
|
"""
|
|
Receives everything from Jabber and emits the
|
|
appropriate signals
|
|
"""
|
|
__init = False
|
|
def __init__(self):
|
|
keyfile = config.get('keyfile')
|
|
certfile = config.get('certfile')
|
|
|
|
if config.get('jid'):
|
|
# Field used to know if we are anonymous or not.
|
|
# many features will be handled differently
|
|
# depending on this setting
|
|
self.anon = False
|
|
jid = '%s' % config.get('jid')
|
|
password = config.get('password')
|
|
eval_password = config.get('eval_password')
|
|
if not password and not eval_password and not (keyfile and certfile):
|
|
password = getpass.getpass()
|
|
elif not password and not (keyfile and certfile):
|
|
sys.stderr.write("No password or certificates provided, using the eval_password command.\n")
|
|
process = subprocess.Popen(['sh', '-c', eval_password], stdin=subprocess.PIPE,
|
|
stdout=subprocess.PIPE, close_fds=True)
|
|
code = process.wait()
|
|
if code != 0:
|
|
sys.stderr.write('The eval_password command (%s) returned a '
|
|
'nonzero status code: %s.\n' % (eval_password, code))
|
|
sys.stderr.write('Poezio will now exit\n')
|
|
sys.exit(code)
|
|
password = process.stdout.readline().decode('utf-8').strip('\n')
|
|
else: # anonymous auth
|
|
self.anon = True
|
|
jid = config.get('server')
|
|
password = None
|
|
jid = safeJID(jid)
|
|
# TODO: use the system language
|
|
slixmpp.ClientXMPP.__init__(self, jid, password,
|
|
lang=config.get('lang'))
|
|
|
|
force_encryption = config.get('force_encryption')
|
|
if force_encryption:
|
|
self['feature_mechanisms'].unencrypted_plain = False
|
|
self['feature_mechanisms'].unencrypted_digest = False
|
|
self['feature_mechanisms'].unencrypted_cram = False
|
|
self['feature_mechanisms'].unencrypted_scram = False
|
|
|
|
self.keyfile = config.get('keyfile')
|
|
self.certfile = config.get('certfile')
|
|
if keyfile and not certfile:
|
|
log.error('keyfile is present in configuration file without certfile')
|
|
elif certfile and not keyfile:
|
|
log.error('certfile is present in configuration file without keyfile')
|
|
|
|
self.core = None
|
|
self.auto_reconnect = config.get('auto_reconnect')
|
|
self.reconnect_max_attempts = 0
|
|
self.auto_authorize = None
|
|
# prosody defaults, lowest is AES128-SHA, it should be a minimum
|
|
# for anything that came out after 2002
|
|
self.ciphers = config.get('ciphers',
|
|
'HIGH+kEDH:HIGH+kEECDH:HIGH:!PSK'
|
|
':!SRP:!3DES:!aNULL')
|
|
self.ca_certs = config.get('ca_cert_path') or None
|
|
interval = config.get('whitespace_interval')
|
|
if int(interval) > 0:
|
|
self.whitespace_keepalive_interval = int(interval)
|
|
else:
|
|
self.whitespace_keepalive = False
|
|
self.register_plugin('xep_0004')
|
|
self.register_plugin('xep_0012')
|
|
self.register_plugin('xep_0030')
|
|
self.register_plugin('xep_0045')
|
|
self.register_plugin('xep_0048')
|
|
self.register_plugin('xep_0050')
|
|
self.register_plugin('xep_0054')
|
|
self.register_plugin('xep_0060')
|
|
self.register_plugin('xep_0066')
|
|
self.register_plugin('xep_0070')
|
|
self.register_plugin('xep_0071')
|
|
self.register_plugin('xep_0077')
|
|
self.plugin['xep_0077'].create_account = False
|
|
self.register_plugin('xep_0085')
|
|
self.register_plugin('xep_0115')
|
|
|
|
# monkey-patch xep_0184 to avoid requesting receipts for messages
|
|
# without a body
|
|
XEP_0184._filter_add_receipt_request = fixes._filter_add_receipt_request
|
|
self.register_plugin('xep_0184')
|
|
self.plugin['xep_0184'].auto_ack = config.get('ack_message_receipts')
|
|
self.plugin['xep_0184'].auto_request = config.get('request_message_receipts')
|
|
|
|
self.register_plugin('xep_0191')
|
|
if config.get('enable_smacks'):
|
|
self.register_plugin('xep_0198')
|
|
self.register_plugin('xep_0199')
|
|
|
|
if config.get('enable_user_tune'):
|
|
self.register_plugin('xep_0118')
|
|
|
|
if config.get('enable_user_nick'):
|
|
self.register_plugin('xep_0172')
|
|
|
|
if config.get('enable_user_mood'):
|
|
self.register_plugin('xep_0107')
|
|
|
|
if config.get('enable_user_activity'):
|
|
self.register_plugin('xep_0108')
|
|
|
|
if config.get('enable_user_gaming'):
|
|
self.register_plugin('xep_0196')
|
|
|
|
if config.get('send_poezio_info'):
|
|
info = {'name':'poezio',
|
|
'version': options.version}
|
|
if config.get('send_os_info'):
|
|
info['os'] = common.get_os_info()
|
|
self.plugin['xep_0030'].set_identities(
|
|
identities={('client', 'console', None, 'Poezio')})
|
|
else:
|
|
info = {'name': '', 'version': ''}
|
|
self.plugin['xep_0030'].set_identities(
|
|
identities={('client', 'console', None, '')})
|
|
self.register_plugin('xep_0092', pconfig=info)
|
|
if config.get('send_time'):
|
|
self.register_plugin('xep_0202')
|
|
self.register_plugin('xep_0224')
|
|
self.register_plugin('xep_0231')
|
|
self.register_plugin('xep_0249')
|
|
self.register_plugin('xep_0257')
|
|
self.register_plugin('xep_0280')
|
|
self.register_plugin('xep_0297')
|
|
self.register_plugin('xep_0308')
|
|
self.register_plugin('xep_0319')
|
|
self.register_plugin('xep_0334')
|
|
self.register_plugin('xep_0352')
|
|
self.register_plugin('xep_0380')
|
|
self.init_plugins()
|
|
|
|
def set_keepalive_values(self, option=None, value=None):
|
|
"""
|
|
Called after the XMPP session has been started, or triggered when one of
|
|
"connection_timeout_delay" and "connection_check_interval" options
|
|
is changed. Unload and reload the ping plugin, with the new values.
|
|
"""
|
|
if not self.is_connected():
|
|
# Happens when we change the value with /set while we are not
|
|
# connected. Do nothing in that case
|
|
return
|
|
ping_interval = config.get('connection_check_interval')
|
|
timeout_delay = config.get('connection_timeout_delay')
|
|
if timeout_delay <= 0:
|
|
# We help the stupid user (with a delay of 0, poezio will try to
|
|
# reconnect immediately because the timeout is immediately
|
|
# passed)
|
|
# 1 second is short, but, well
|
|
timeout_delay = 1
|
|
self.plugin['xep_0199'].disable_keepalive()
|
|
# If the ping_interval is 0 or less, we just disable the keepalive
|
|
if ping_interval > 0:
|
|
self.plugin['xep_0199'].enable_keepalive(ping_interval,
|
|
timeout_delay)
|
|
|
|
def start(self):
|
|
"""
|
|
Connect and process events.
|
|
"""
|
|
custom_host = config.get('custom_host')
|
|
custom_port = config.get('custom_port', 5222)
|
|
if custom_port == -1:
|
|
custom_port = 5222
|
|
if custom_host:
|
|
self.connect((custom_host, custom_port))
|
|
elif custom_port != 5222 and custom_port != -1:
|
|
self.connect((self.boundjid.host, custom_port))
|
|
else:
|
|
self.connect()
|
|
|
|
def send_raw(self, data):
|
|
"""
|
|
Overrides XMLStream.send_raw, with an event added
|
|
"""
|
|
if self.core:
|
|
self.core.handler.outgoing_stanza(data)
|
|
slixmpp.ClientXMPP.send_raw(self, data)
|
|
|
|
class MatchAll(slixmpp.xmlstream.matcher.base.MatcherBase):
|
|
"""
|
|
Callback to retrieve all the stanzas for the XML tab
|
|
"""
|
|
def match(self, xml):
|
|
"match everything"
|
|
return True
|