Commit aca509f4 authored by Philipp Hörist's avatar Philipp Hörist
Browse files

Remove modules

parent 50fed1be
[epydoc]
# Information about the project.
name: python-nbxmpp
url: http://python-nbxmpp.gajim.org
verbosity: 3
imports: yes
redundant-details: yes
docformat: restructuredtext
# The list of modules to document. Modules can be named using
# dotted names, module filenames, or package directory names.
# This option may be repeated.
modules: nbxmpp/*
# Write html output to the directory "apidocs"
output: html
target: doc/apidocs/
# Include all automatically generated graphs. These graphs are
# generated using Graphviz dot.
graph: all
dotpath: /usr/bin/dot
graph-font: Sans
graph-font-size: 10
#!/usr/bin/python3
import sys
import os
import logging
import nbxmpp
from nbxmpp.const import Realm
from nbxmpp.const import Event
from gi.repository import GLib
if sys.platform in ('win32', 'darwin'):
import certifi
consoleloghandler = logging.StreamHandler()
log = logging.getLogger('nbxmpp')
log.setLevel('INFO')
log.addHandler(consoleloghandler)
if len(sys.argv) < 2:
print("Syntax: xsend JID text")
sys.exit(0)
to_jid = sys.argv[1]
text = ' '.join(sys.argv[2:])
jidparams = {}
if os.access(os.environ['HOME'] + '/.xsend', os.R_OK):
for ln in open(os.environ['HOME'] + '/.xsend').readlines():
if not ln[0] in ('#', ';'):
key, val = ln.strip().split('=', 1)
jidparams[key.lower()] = val
for mandatory in ['jid', 'password']:
if mandatory not in jidparams.keys():
open(os.environ['HOME']+'/.xsend','w').write('#Uncomment fields before use and type in correct credentials.\n#JID=romeo@montague.net/resource (/resource is optional)\n#PASSWORD=juliet\n')
print('Please point ~/.xsend config file to valid JID for sending messages.')
sys.exit(0)
class Connection:
def __init__(self):
self.jid = nbxmpp.protocol.JID(jidparams['jid'])
self.password = jidparams['password']
self.client_cert = None
self.idle_queue = nbxmpp.idlequeue.get_idlequeue()
self.client = None
def _on_auth_successful(self):
print('authenticated')
self.client.bind()
def _on_connection_active(self):
print('Connection active')
self.client.RegisterHandler('message', self._on_message)
self.send_presence()
def _on_auth_failed(self, reason, text):
log.debug("Couldn't authenticate")
log.error(reason, text)
exit()
def _on_message(self, con, stanza):
print('message received')
print(stanza.getBody())
def _on_connected(self, con, con_type):
print('connected with ' + con_type)
self.client.auth(self.jid.getNode(),
get_password=self._get_password,
resource=self.jid.getResource())
def _get_password(self, mech, password_cb):
password_cb(self.password)
def _on_connection_failed(self):
print('could not connect!')
def _event_dispatcher(self, realm, event, data):
if realm == Realm.CONNECTING:
if event == Event.AUTH_SUCCESSFUL:
log.info(event)
self._on_auth_successful()
elif event == Event.AUTH_FAILED:
log.error(event)
log.error(data)
self._on_auth_failed(*data)
elif event == Event.SESSION_FAILED:
log.error(event)
elif event == Event.BIND_FAILED:
log.error(event)
elif event == Event.CONNECTION_ACTIVE:
log.info(event)
self._on_connection_active()
return
def connect(self):
cacerts = ''
if sys.platform in ('win32', 'darwin'):
cacerts = certifi.where()
self.client = nbxmpp.NonBlockingClient(self.jid.getDomain(),
self.idle_queue,
caller=self)
self.client.connect(self._on_connected,
self._on_connection_failed,
secure_tuple=('tls', cacerts, '', None, None, False))
if sys.platform == 'win32':
timeout, in_seconds = 20, None
else:
timeout, in_seconds = 100, False
if in_seconds:
GLib.timeout_add_seconds(timeout, self.process_connections)
else:
GLib.timeout_add(timeout, self.process_connections)
def send_presence(self):
presence = nbxmpp.Presence()
self.client.send(presence)
def quit(self):
self.disconnect()
ml.quit()
def disconnect(self):
self.client.start_disconnect()
def process_connections(self):
try:
self.idle_queue.process()
except Exception:
# Otherwise, an exception will stop our loop
if sys.platform == 'win32':
# On Windows process() calls select.select(), so we need this
# executed as often as possible.
timeout, in_seconds = 1, None
else:
timeout, in_seconds = 100, False
if in_seconds:
GLib.timeout_add_seconds(timeout, self.process_connections)
else:
GLib.timeout_add(timeout, self.process_connections)
raise
return True # renew timeout (loop for ever)
con = Connection()
con.connect()
ml = GLib.MainLoop()
ml.run()
# Copyright (C) 2003-2005 Alexey "Snake" Nezhdanov
# Copyright (C) Dimitur Kirov <dkirov AT gmail.com>
# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of nbxmpp.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; If not, see <http://www.gnu.org/licenses/>.
import logging
from nbxmpp.plugin import PlugIn
from nbxmpp.protocol import NS_BIND
from nbxmpp.protocol import NS_SESSION
from nbxmpp.protocol import NS_STREAMS
from nbxmpp.protocol import NS_STREAM_MGMT
from nbxmpp.protocol import Node
from nbxmpp.protocol import isResultNode
from nbxmpp.protocol import Protocol
from nbxmpp.const import Realm
from nbxmpp.const import Event
log = logging.getLogger('nbxmpp.bind')
class NonBlockingBind(PlugIn):
"""
Bind some JID to the current connection to allow router know of our
location. Must be plugged after successful SASL auth
"""
def __init__(self):
PlugIn.__init__(self)
self._session_required = False
def plugin(self, _owner):
self._owner.RegisterHandler(
'features', self._on_features, xmlns=NS_STREAMS)
feats = self._owner.Dispatcher.Stream.features
if feats is not None:
if feats.getTag('bind', namespace=NS_BIND) is not None:
# We already received the features
self._on_features(None, feats)
def _on_features(self, _con, feats):
"""
Determine if server supports resource binding and set some internal
attributes accordingly.
"""
if not feats or not feats.getTag('bind', namespace=NS_BIND):
return
session = feats.getTag('session', namespace=NS_SESSION)
if session is not None:
if session.getTag('optional') is None:
self._session_required = True
self._bind()
def plugout(self):
"""
Remove Bind handler from owner's dispatcher. Used internally
"""
self._owner.UnregisterHandler(
'features', self._on_features, xmlns=NS_STREAMS)
def _bind(self):
"""
Perform binding. Use provided resource name or random (if not provided).
"""
log.info('Send bind')
resource = []
if self._owner._Resource:
resource = [Node('resource', payload=[self._owner._Resource])]
payload = Node('bind', attrs={'xmlns': NS_BIND}, payload=resource)
node = Protocol('iq', typ='set', payload=[payload])
self._owner.Dispatcher.SendAndCallForResponse(node, func=self._on_bind)
def _on_bind(self, _client, stanza):
if isResultNode(stanza):
bind = stanza.getTag('bind')
if bind is not None:
jid = bind.getTagData('jid')
log.info('Successfully bound %s', jid)
self._owner.set_bound_jid(jid)
if not self._session_required:
# Server don't want us to initialize a session
log.info('No session required')
self._on_bind_successful()
else:
node = Node('session', attrs={'xmlns':NS_SESSION})
iq = Protocol('iq', typ='set', payload=[node])
self._owner.SendAndCallForResponse(
iq, func=self._on_session)
return
if stanza:
log.error('Binding failed: %s.', stanza.getTag('error'))
else:
log.error('Binding failed: timeout expired')
self._owner.Connection.start_disconnect()
self._owner.Dispatcher.Event(Realm.CONNECTING, Event.BIND_FAILED)
self.PlugOut()
def _on_session(self, _client, stanza):
if isResultNode(stanza):
log.info('Successfully started session')
self._on_bind_successful()
else:
log.error('Session open failed')
self._owner.Connection.start_disconnect()
self._owner.Dispatcher.Event(Realm.CONNECTING, Event.SESSION_FAILED)
self.PlugOut()
def _on_bind_successful(self):
feats = self._owner.Dispatcher.Stream.features
if feats.getTag('sm', namespace=NS_STREAM_MGMT):
self._owner.Smacks.send_enable()
self._owner.Dispatcher.Event(Realm.CONNECTING, Event.CONNECTION_ACTIVE)
self.PlugOut()
This diff is collapsed.
This diff is collapsed.
## features.py
##
## Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov
## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2, or (at your option)
## any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
"""
Different stuff that wasn't worth separating it into modules
(Registration, Privacy Lists, ...)
"""
from .protocol import NS_REGISTER, NS_PRIVACY, NS_DATA, Iq, isResultNode, Node
def _on_default_response(disp, iq, cb):
def _on_response(_client, resp):
if isResultNode(resp):
if cb:
cb(True)
elif cb:
cb(False)
disp.SendAndCallForResponse(iq, _on_response)
###############################################################################
### Registration
###############################################################################
REGISTER_DATA_RECEIVED = 'REGISTER DATA RECEIVED'
def getRegInfo(disp, host, info={}, sync=True):
"""
Get registration form from remote host. Info dict can be prefilled
:param disp: plugged dispatcher instance
:param info: dict, like {'username':'joey'}.
See JEP-0077 for details.
"""
iq=Iq('get', NS_REGISTER, to=host)
for i in info.keys():
iq.setTagData(i, info[i])
if sync:
disp.SendAndCallForResponse(iq, lambda _client, resp:
_ReceivedRegInfo(disp.Dispatcher, resp, host))
else:
disp.SendAndCallForResponse(iq, _ReceivedRegInfo, {'agent': host })
def _ReceivedRegInfo(con, resp, agent):
Iq('get', NS_REGISTER, to=agent)
if not isResultNode(resp):
error_msg = resp.getErrorMsg()
con.Event(NS_REGISTER, REGISTER_DATA_RECEIVED, (agent, None, False, error_msg, ''))
return
tag=resp.getTag('query', namespace=NS_REGISTER)
if not tag:
error_msg = resp.getErrorMsg()
con.Event(NS_REGISTER, REGISTER_DATA_RECEIVED, (agent, None, False, error_msg, ''))
return
df=tag.getTag('x', namespace=NS_DATA)
if df:
con.Event(NS_REGISTER, REGISTER_DATA_RECEIVED, (agent, df, True, '',
tag))
return
df={}
for i in resp.getQueryPayload():
if not isinstance(i, Node):
continue
df[i.getName()] = i.getData()
con.Event(NS_REGISTER, REGISTER_DATA_RECEIVED, (agent, df, False, '', ''))
def register(disp, host, info, cb, args=None):
"""
Perform registration on remote server with provided info
If registration fails you can get additional info from the dispatcher's
owner attributes lastErrNode, lastErr and lastErrCode.
"""
iq=Iq('set', NS_REGISTER, to=host)
if not isinstance(info, dict):
info=info.asDict()
for i in info.keys():
iq.setTag('query').setTagData(i, info[i])
disp.SendAndCallForResponse(iq, cb, args)
def unregister(disp, host, cb):
"""
Unregisters with host (permanently removes account). Returns true on success
"""
iq = Iq('set', NS_REGISTER, to=host, payload=[Node('remove')])
_on_default_response(disp, iq, cb)
def changePasswordTo(disp, newpassword, host=None, cb = None):
"""
Changes password on specified or current (if not specified) server. Returns
true on success.
"""
if not host:
host = disp._owner.Server
iq = Iq('set', NS_REGISTER, to=host, payload=[Node('username',
payload=[disp._owner.Server]), Node('password', payload=[newpassword])])
_on_default_response(disp, iq, cb)
###############################################################################
### Privacy List
###############################################################################
PL_TYPE_JID = 'jid'
PL_TYPE_GROUP = 'group'
PL_TYPE_SUBC = 'subscription'
PL_ACT_ALLOW = 'allow'
PL_ACT_DENY = 'deny'
PRIVACY_LISTS_RECEIVED = 'PRIVACY LISTS RECEIVED'
PRIVACY_LIST_RECEIVED = 'PRIVACY LIST RECEIVED'
PRIVACY_LISTS_ACTIVE_DEFAULT = 'PRIVACY LISTS ACTIVE DEFAULT'
def getPrivacyLists(disp):
"""
Request privacy lists from connected server. Returns dictionary of existing
lists on success.
"""
iq = Iq('get', NS_PRIVACY)
def _on_response(_client, resp):
dict_ = {'lists': []}
if not isResultNode(resp):
disp.Event(NS_PRIVACY, PRIVACY_LISTS_RECEIVED, False)
return
for list_ in resp.getQueryPayload():
if list_.getName()=='list':
dict_['lists'].append(list_.getAttr('name'))
else:
dict_[list_.getName()]=list_.getAttr('name')
disp.Event(NS_PRIVACY, PRIVACY_LISTS_RECEIVED, dict_)
disp.SendAndCallForResponse(iq, _on_response)
def getActiveAndDefaultPrivacyLists(disp):
iq = Iq('get', NS_PRIVACY)
def _on_response(_client, resp):
dict_ = {'active': '', 'default': ''}
if not isResultNode(resp):
disp.Event(NS_PRIVACY, PRIVACY_LISTS_ACTIVE_DEFAULT, False)
return
for list_ in resp.getQueryPayload():
if list_.getName() == 'active':
dict_['active'] = list_.getAttr('name')
elif list_.getName() == 'default':
dict_['default'] = list_.getAttr('name')
disp.Event(NS_PRIVACY, PRIVACY_LISTS_ACTIVE_DEFAULT, dict_)
disp.SendAndCallForResponse(iq, _on_response)
def getPrivacyList(disp, listname):
"""
Request specific privacy list listname. Returns list of XML nodes (rules)
taken from the server responce.
"""
def _on_response(_client, resp):
if not isResultNode(resp):
disp.Event(NS_PRIVACY, PRIVACY_LIST_RECEIVED, False)
return
disp.Event(NS_PRIVACY, PRIVACY_LIST_RECEIVED, resp)
iq = Iq('get', NS_PRIVACY, payload=[Node('list', {'name': listname})])
disp.SendAndCallForResponse(iq, _on_response)
def setActivePrivacyList(disp, listname=None, typ='active', cb=None):
"""
Switch privacy list 'listname' to specified type. By default the type is
'active'. Returns true on success.
"""
if listname:
attrs={'name':listname}
else:
attrs={}
iq = Iq('set', NS_PRIVACY, payload=[Node(typ, attrs)])
_on_default_response(disp, iq, cb)
def setDefaultPrivacyList(disp, listname=None):
"""
Set the default privacy list as 'listname'. Returns true on success
"""
return setActivePrivacyList(disp, listname, 'default')
def setPrivacyList(disp, listname, tags):
"""
Set the ruleset
'list' should be the simpleXML node formatted according to RFC 3921
(XMPP-IM) I.e. Node('list',{'name':listname},payload=[...]).
Returns true on success.
"""
iq = Iq('set', NS_PRIVACY, xmlns = '')
list_query = iq.getTag('query').setTag('list', {'name': listname})
for item in tags:
if 'type' in item and 'value' in item:
item_tag = list_query.setTag('item', {'action': item['action'],
'order': item['order'], 'type': item['type'],
'value': item['value']})
else:
item_tag = list_query.setTag('item', {'action': item['action'],
'order': item['order']})
if 'child' in item:
for child_tag in item['child']:
item_tag.setTag(child_tag)
_on_default_response(disp, iq, None)
def delPrivacyList(disp, listname, cb=None):
""" Deletes privacy list 'listname'. Returns true on success. """
iq = Iq('set', NS_PRIVACY, payload=[Node('list', {'name':listname})])
_on_default_response(disp, iq, cb)
## proxy_connectors.py
##
## Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov
## modified by Dimitur Kirov <dkirov@gmail.com>
## modified by Tomas Karasek <tom.to.the.k@gmail.com>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2, or (at your option)
## any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
"""
Module containing classes for proxy connecting. So far its HTTP CONNECT and
SOCKS5 proxy
Authentication to NTLM (Microsoft implementation) proxies can be next.
"""
import struct
import socket
import logging
from base64 import b64encode
log = logging.getLogger('nbxmpp.proxy_connectors')
class ProxyConnector:
"""
Interface for proxy-connecting object - when tunnneling XMPP over proxies,
some connecting process usually has to be done before opening stream. Proxy
connectors are used right after TCP connection is estabilished
"""
def __init__(self, send_method, onreceive, old_on_receive, on_success,
on_failure, xmpp_server, proxy_creds=(None, None)):
"""
Creates proxy connector, starts connecting immediately and gives control
back to transport afterwards
:param send_method: transport send method
:param onreceive: method to set on_receive callbacks
:param old_on_receive: on_receive callback that should be set when
proxy connection was successful
:param on_success: called after proxy connection was successfully opened
:param on_failure: called when errors occured while connecting
:param xmpp_server: tuple of (hostname, port)
:param proxy_creds: tuple of (proxy_user, proxy_credentials)
"""
self.send = send_method
self.onreceive = onreceive
self.old_on_receive = old_on_receive
self.on_success = on_success
self.on_failure = on_failure
self.xmpp_server = xmpp_server
self.proxy_user, self.proxy_pass = proxy_creds
self.old_on_receive = old_on_receive
self.start_connecting()
@classmethod
def get_instance(cls, *args, **kwargs):
"""
Factory Method for object creation
Use this instead of directly initializing the class in order to make unit
testing much easier.
"""
return cls(*args, **kwargs)