PKYhJX4jeepney/__init__.py"""Low-level, pure Python DBus protocol wrapper. """ from .low_level import Message, Parser from .bus import find_session_bus, find_system_bus from .wrappers import * __version__ = '0.2' PKcZJVѤKjeepney/auth.pyfrom binascii import hexlify import os def make_auth_external(): hex_uid = hexlify(str(os.getuid()).encode('ascii')) return b'AUTH EXTERNAL %b\r\n' % hex_uid BEGIN = b'BEGIN\r\n' class SASLParser: def __init__(self): self.buffer = b'' self.authenticated = False self.error = None def process_line(self, line): if line.startswith(b'OK '): self.authenticated = True else: self.error = line def feed(self, data): self.buffer += data while (b'\r\n' in data) and not self.authenticated: line, self.buffer = self.buffer.split(b'\r\n', 1) self.process_line(line) PKBZJ*jeepney/bus.pyimport os import re _escape_pat = re.compile(r'%([0-9A-Fa-f]{2})') def unescape(v): def repl(match): n = int(match.group(1), base=16) return chr(n) return _escape_pat.sub(repl, v) def parse_addresses(s): for addr in s.split(';'): transport, info = addr.split(':', 1) kv = {} for x in info.split(','): k, v = x.split('=', 1) kv[k] = unescape(v) yield (transport, kv) SUPPORTED_TRANSPORTS = ('unix',) def get_connectable_addresses(addr): unsupported_transports = set() found = False for transport, kv in parse_addresses(addr): if transport not in SUPPORTED_TRANSPORTS: unsupported_transports.add(transport) elif transport == 'unix': if 'abstract' in kv: yield '\0' + kv['abstract'] found = True elif 'path' in kv: yield kv['path'] found = True if not found: raise RuntimeError("DBus transports ({}) not supported. Supported: {}" .format(unsupported_transports, SUPPORTED_TRANSPORTS)) def find_session_bus(): addr = os.environ['DBUS_SESSION_BUS_ADDRESS'] return next(get_connectable_addresses(addr)) # TODO: fallbacks to X, filesystem def find_system_bus(): addr = os.environ.get('DBUS_SYSTEM_BUS_ADDRESS', '') \ or 'unix:path=/var/run/dbus/system_bus_socket' return next(get_connectable_addresses(addr)) def get_bus(addr): if addr == 'SESSION': return find_session_bus() elif addr == 'SYSTEM': return find_system_bus() else: return next(get_connectable_addresses(addr)) if __name__ == '__main__': print('System bus at:', find_system_bus()) print('Session bus at:', find_session_bus()) PKfJK6/6/jeepney/low_level.pyfrom enum import Enum, IntEnum import struct class Endianness(Enum): little = 1 big = 2 def struct_code(self): return '<' if (self is Endianness.little) else '>' def dbus_code(self): return b'l' if (self is Endianness.little) else b'B' endian_map = {b'l': Endianness.little, b'B': Endianness.big} class MessageType(Enum): method_call = 1 method_return = 2 error = 3 signal = 4 msg_type_map = {t.value: t for t in MessageType} # Flags: NO_REPLY_EXPECTED = 1 NO_AUTO_START = 2 ALLOW_INTERACTIVE_AUTHORIZATION = 4 class HeaderFields(IntEnum): path = 1 interface = 2 member = 3 error_name = 4 reply_serial = 5 destination = 6 sender = 7 signature = 8 unix_fds = 9 header_fields_map = {t.value: t for t in HeaderFields} def padding(pos, step): pad = step - (pos % step) if pad == step: return 0 return pad class FixedType: def __init__(self, size, struct_code): self.size = self.alignment = size self.struct_code = struct_code def parse_data(self, buf, pos, endianness): pos += padding(pos, self.alignment) code = endianness.struct_code() + self.struct_code val = struct.unpack(code, buf[pos:pos + self.size])[0] return val, pos + self.size def serialise(self, data, pos, endianness): pad = b'\0' * padding(pos, self.alignment) code = endianness.struct_code() + self.struct_code return pad + struct.pack(code, data) def __repr__(self): return 'FixedType({!r}, {!r})'.format(self.size, self.struct_code) def __eq__(self, other): return (type(other) is FixedType) and (self.size == other.size) \ and (self.struct_code == other.struct_code) simple_types = { 'y': FixedType(1, 'B'), # unsigned 8 bit 'b': FixedType(4, 'I'), # bool 'n': FixedType(2, 'h'), # signed 16 bit 'q': FixedType(2, 'H'), # unsigned 16 bit 'i': FixedType(4, 'i'), # signed 32-bit 'u': FixedType(4, 'I'), # unsigned 32-bit 'x': FixedType(8, 'q'), # signed 64-bit 't': FixedType(8, 'Q'), # unsigned 64-bit 'd': FixedType(8, 'd'), # double 'h': FixedType(8, 'I'), # file descriptor (32-bit unsigned, index) TODO } class StringType: def __init__(self, length_type): self.length_type = length_type @property def alignment(self): return self.length_type.size def parse_data(self, buf, pos, endianness): length, pos = self.length_type.parse_data(buf, pos, endianness) end = pos + length val = buf[pos:end].decode('utf-8') assert buf[end:end + 1] == b'\0' return val, end + 1 def serialise(self, data, pos, endianness): encoded = data.encode('utf-8') len_data = self.length_type.serialise(len(encoded), pos, endianness) return len_data + encoded + b'\0' def __repr__(self): return 'StringType({!r})'.format(self.length_type) def __eq__(self, other): return (type(other) is StringType) \ and (self.length_type == other.length_type) simple_types.update({ 's': StringType(simple_types['u']), # String 'o': StringType(simple_types['u']), # Object path 'g': StringType(simple_types['y']), # Signature }) class Struct: alignment = 8 def __init__(self, fields): if any(isinstance(f, DictEntry) for f in fields): raise TypeError("Found dict entry outside array") self.fields = fields def parse_data(self, buf, pos, endianness): pos += padding(pos, 8) res = [] for field in self.fields: v, pos = field.parse_data(buf, pos, endianness) res.append(v) return tuple(res), pos def serialise(self, data, pos, endianness): if len(data) != len(self.fields): raise ValueError("{} entries for {} fields".format( len(data), len(self.fields) )) pad = b'\0' * padding(pos, self.alignment) pos += len(pad) res_pieces = [] for item, field in zip(data, self.fields): res_pieces.append(field.serialise(item, pos, endianness)) pos += len(res_pieces[-1]) return pad + b''.join(res_pieces) def __repr__(self): return "{}({!r})".format(type(self).__name__, self.fields) def __eq__(self, other): return (type(other) is type(self)) and (self.fields == other.fields) class DictEntry(Struct): def __init__(self, fields): if len(fields) != 2: raise TypeError( "Dict entry must have 2 fields, not %d" % len(fields)) if not isinstance(fields[0], (FixedType, StringType)): raise TypeError( "First field in dict entry must be simple type, not {}" .format(type(fields[0]))) super().__init__(fields) class Array: alignment = 4 length_type = FixedType(4, 'I') def __init__(self, elt_type): self.elt_type = elt_type def parse_data(self, buf, pos, endianness): # print('Array start', pos) length, pos = self.length_type.parse_data(buf, pos, endianness) pos += padding(pos, self.elt_type.alignment) end = pos + length res = [] while pos < end: # print('Array elem', pos) v, pos = self.elt_type.parse_data(buf, pos, endianness) res.append(v) return res, pos def serialise(self, data, pos, endianness): if isinstance(self.elt_type, DictEntry) and isinstance(data, dict): data = sorted(data.items()) pad1 = padding(pos, self.alignment) pos_after_length = pos + pad1 + 4 pad2 = padding(pos_after_length, self.elt_type.alignment) data_pos = pos_after_length + pad2 chunks = [] for item in data: chunks.append(self.elt_type.serialise(item, data_pos, endianness)) data_pos += len(chunks[-1]) buf = b''.join(chunks) len_data = self.length_type.serialise(len(buf), pos+pad1, endianness) pos += len(len_data) # print('Array ser: pad1={!r}, len_data={!r}, pad2={!r}, buf={!r}'.format( # pad1, len_data, pad2, buf)) return (b'\0' * pad1) + len_data + (b'\0' * pad2) + buf def __repr__(self): return 'Array({!r})'.format(self.elt_type) def __eq__(self, other): return (type(other) is Array) and (self.elt_type == other.elt_type) class Variant: alignment = 1 def parse_data(self, buf, pos, endianness): # print('variant', pos) sig, pos = simple_types['g'].parse_data(buf, pos, endianness) # print('variant sig:', repr(sig), pos) valtype = parse_signature(list(sig)) val, pos = valtype.parse_data(buf, pos, endianness) # print('variant done', (sig, val), pos) return (sig, val), pos def serialise(self, data, pos, endianness): sig, data = data valtype = parse_signature(list(sig)) sig_buf = simple_types['g'].serialise(sig, pos, endianness) return sig_buf + valtype.serialise(data, pos + len(sig_buf), endianness) def __repr__(self): return 'Variant()' def __eq__(self, other): return type(other) is Variant def parse_signature(sig): # Based on http://norvig.com/lispy.html token = sig.pop(0) if token == 'a': return Array(parse_signature(sig)) if token == 'v': return Variant() elif token == '(': fields = [] while sig[0] != ')': fields.append(parse_signature(sig)) sig.pop(0) # ) return Struct(fields) elif token == '{': de = [] while sig[0] != '}': de.append(parse_signature(sig)) sig.pop(0) # } return DictEntry(de) elif token in ')}': raise ValueError('Unexpected end of struct') else: return simple_types[token] def calc_msg_size(buf): endian, = struct.unpack('c', buf[:1]) endian = endian_map[endian] body_length, = struct.unpack(endian.struct_code() + 'I', buf[4:8]) fields_array_len, = struct.unpack(endian.struct_code() + 'I', buf[12:16]) header_len = 16 + fields_array_len return header_len + padding(header_len, 8) + body_length _header_fields_type = Array(Struct([simple_types['y'], Variant()])) def parse_header_fields(buf, endianness): l, pos = _header_fields_type.parse_data(buf, 12, endianness) return {header_fields_map[k]: v[1] for (k, v) in l}, pos header_field_codes = { 1: 'o', 2: 's', 3: 's', 4: 's', 5: 'u', 6: 's', 7: 's', 8: 'g', 9: 'u', } def serialise_header_fields(d, endianness): l = [(i.value, (header_field_codes[i], v)) for (i, v) in sorted(d.items())] return _header_fields_type.serialise(l, 12, endianness) class Header: def __init__(self, endianness, message_type, flags, protocol_version, body_length, serial, fields): self.endianness = endianness self.message_type = message_type self.flags = flags self.protocol_version = protocol_version self.body_length = body_length self.serial = serial self.fields = fields def __repr__(self): return 'Header({!r}, {!r}, {!r}, {!r}, {!r}, {!r}, fields={!r})'.format( self.endianness, self.message_type, self.flags, self.protocol_version, self.body_length, self.serial, self.fields) def serialise(self): s = self.endianness.struct_code() + 'cBBBII' return struct.pack(s, self.endianness.dbus_code(), self.message_type.value, self.flags, self.protocol_version, self.body_length, self.serial) \ + serialise_header_fields(self.fields, self.endianness) @classmethod def from_buffer(cls, buf): endian, msgtype, flags, pv = struct.unpack('cBBB', buf[:4]) endian = endian_map[endian] bodylen, serial = struct.unpack(endian.struct_code() + 'II', buf[4:12]) fields, pos = parse_header_fields(buf, endian) return cls(endian, msg_type_map[msgtype], flags, pv, bodylen, serial, fields), pos class Message: def __init__(self, header, body): self.header = header self.body = body def __repr__(self): return "{}({!r}, {!r})".format(type(self).__name__, self.header, self.body) @classmethod def from_buffer(cls, buf): header, pos = Header.from_buffer(buf) body = () if HeaderFields.signature in header.fields: sig = header.fields[HeaderFields.signature] body_type = parse_signature(list('(%s)' % sig)) body = body_type.parse_data(buf, pos, header.endianness)[0] return cls(header, body) def serialise(self): endian = self.header.endianness if HeaderFields.signature in self.header.fields: sig = self.header.fields[HeaderFields.signature] body_type = parse_signature(list('(%s)' % sig)) body_buf = body_type.serialise(self.body, 0, endian) else: body_buf = b'' self.header.body_length = len(body_buf) header_buf = self.header.serialise() pad = b'\0' * padding(len(header_buf), 8) return header_buf + pad + body_buf class Parser: def __init__(self): self.buf = b'' self.next_msg_size = None def feed(self, data): self.buf += data return list(iter(self._read1, None)) def _read1(self): if self.next_msg_size is None: if len(self.buf) >= 16: self.next_msg_size = calc_msg_size(self.buf) nms = self.next_msg_size if (nms is not None) and len(self.buf) >= nms: raw_msg, self.buf = self.buf[:nms], self.buf[nms:] msg = Message.from_buffer(raw_msg) self.next_msg_size = None return msg PKhJWjeepney/wrappers.pyfrom .low_level import * __all__ = [ 'DBusObject', 'message_bus', 'new_method_call', 'new_method_return', 'new_error', 'new_signal', 'hello_msg', 'Properties', 'DBusErrorResponse', ] class DBusObject: def __init__(self, object_path, bus_name=None, interface=None): self.object_path = object_path self.bus_name = bus_name self.interface = interface def __repr__(self): return '{}({!r}, bus_name={!r}, interface={!r})'.format(type(self).__name__, self.object_path, self.bus_name, self.interface) def with_interface(self, interface): return type(self)(self.object_path, self.bus_name, interface) message_bus = DBusObject('/org/freedesktop/DBus', 'org.freedesktop.DBus', 'org.freedesktop.DBus') def new_header(msg_type): return Header(Endianness.little, msg_type, flags=0, protocol_version=1, body_length=-1, serial=-1, fields={}) def new_method_call(remote_obj, method, signature=None, body=()): header = new_header(MessageType.method_call) header.fields[HeaderFields.path] = remote_obj.object_path if remote_obj.bus_name is None: raise ValueError("remote_obj.bus_name cannot be None for method calls") header.fields[HeaderFields.destination] = remote_obj.bus_name if remote_obj.interface is not None: header.fields[HeaderFields.interface] = remote_obj.interface header.fields[HeaderFields.member] = method if signature is not None: header.fields[HeaderFields.signature] = signature return Message(header, body) def new_method_return(parent_msg, signature=None, body=()): header = new_header(MessageType.method_return) header.fields[HeaderFields.reply_serial] = parent_msg.header.serial if signature is not None: header.fields[HeaderFields.signature] = signature return Message(header, body) def new_error(parent_msg, error_name, signature=None, body=()): header = new_header(MessageType.error) header.fields[HeaderFields.reply_serial] = parent_msg.header.serial header.fields[HeaderFields.error_name] = error_name if signature is not None: header.fields[HeaderFields.signature] = signature return Message(header, body) def new_signal(emitter, signal, signature=None, body=()): header = new_header(MessageType.signal) header.fields[HeaderFields.path] = emitter.object_path if emitter.interface is None: raise ValueError("emitter.interface cannot be None for signals") header.fields[HeaderFields.interface] = emitter.interface header.fields[HeaderFields.member] = signal if signature is not None: header.fields[HeaderFields.signature] = signature return Message(header, body) # We need to say hello to the message bus before doing anythong else, so provide # a prebuilt message for this. def hello_msg(): return new_method_call(message_bus, 'Hello') class Properties: """Build messages for accessing object properties This uses the standard DBus interface org.freedesktop.DBus.Properties """ def __init__(self, obj: DBusObject): self.obj = obj self.props_if = obj.with_interface('org.freedesktop.DBus.Properties') def get(self, name): return new_method_call(self.props_if, 'Get', 'ss', (self.obj.interface, name)) def get_all(self): return new_method_call(self.props_if, 'GetAll', 's', (self.obj.interface,)) def set(self, name, signature, value): return new_method_call(self.props_if, 'Set', 'ssv', (self.obj.interface, name, (signature, value))) class DBusErrorResponse(Exception): pass PK"aZJjeepney/integrate/__init__.pyPKzJc3_"sBtbr/L;`[jNhv4oa97+ڶq 2o'\r:PK!H-jeepney-0.2.dist-info/RECORDӹ@cY,-$@,BBBؾG]r䅧nwM_}?ߚCY@17U(-T Yvd*fmiCM4VQv< }D&gNô.D UCS Fcy\IѽЛzCsNNv(QzHaHѿC|{5`NrmƖ2'M4N_-4W~-7g49;(sh 20 I\~K:D qr)PN1 r"'U;_pM \/ڣַ(\#R՘̤["ߛcԣ܏?ƞlPڄ*+G[i[ZAI*b_VQl)bxr$V#Wtzrf4Db<ͽ_ұs: lYMS͑e[g Z?C0ʼn7-QUR5624]ij>L߰gN3$R)φQuw;RkOsJʹ=Ji)H MOC½{k\v^ef=uwyq¿rl PKYhJX4jeepney/__init__.pyPKcZJVѤKjeepney/auth.pyPKBZJ*jeepney/bus.pyPKfJK6/6/ jeepney/low_level.pyPKhJWt:jeepney/wrappers.pyPK"aZJjIjeepney/integrate/__init__.pyPKzJ