#!/usr/bin/python
# -*- coding: utf-8 -*-
#
-# Copyright (C) 2011-2012 Sebastien Helleu <flashcode@flashtux.org>
+# protocol.py - decode binary messages received from WeeChat/relay
+#
+# Copyright (C) 2011-2014 Sébastien Helleu <flashcode@flashtux.org>
#
# This file is part of QWeeChat, a Qt remote GUI for WeeChat.
#
#
#
-# Decode binary messages received from WeeChat/relay.
-#
-# For info about protocol and format of messages, please read document "WeeChat Relay Protocol",
-# available at: http://www.weechat.org/doc/
+# For info about protocol and format of messages, please read document
+# "WeeChat Relay Protocol", available at: http://weechat.org/doc/
#
# History:
#
-# 2011-11-23, Sebastien Helleu <flashcode@flashtux.org>:
+# 2011-11-23, Sébastien Helleu <flashcode@flashtux.org>:
# start dev
#
-import struct, zlib
+import collections, struct, zlib
+
+if hasattr(collections, 'OrderedDict'):
+ # python >= 2.7
+ class WeechatDict(collections.OrderedDict):
+ def __str__(self):
+ return '{%s}' % ', '.join(['%s: %s' % (repr(key), repr(self[key])) for key in self])
+else:
+ # python <= 2.6
+ WeechatDict = dict
class WeechatObject:
- def __init__(self, objtype, value):
+ def __init__(self, objtype, value, separator='\n'):
self.objtype = objtype;
self.value = value
+ self.separator = separator
+ self.indent = ' ' if separator == '\n' else ''
+ self.separator1 = '\n%s' % self.indent if separator == '\n' else ''
def _str_value(self, v):
if type(v) is str and not v is None:
return str(v)
def _str_value_hdata(self):
- lines = ['',
- ' keys: %s' % str(self.value['keys']),
- ' path: %s' % str(self.value['path'])]
+ lines = ['%skeys: %s%s%spath: %s' % (self.separator1, str(self.value['keys']), self.separator, self.indent, str(self.value['path']))]
for i, item in enumerate(self.value['items']):
- lines.append(' item %d:' % (i + 1))
- lines.append('\n'.join([' %s: %s' % (key, self._str_value(value)) for key, value in sorted(item.items())]))
+ lines.append(' item %d:%s%s' % ((i + 1), self.separator,
+ self.separator.join(['%s%s: %s' % (self.indent * 2, key, self._str_value(value)) for key, value in item.items()])))
return '\n'.join(lines)
def _str_value_infolist(self):
- lines = ['', ' name: %s' % self.value['name']]
+ lines = ['%sname: %s' % (self.separator1, self.value['name'])]
for i, item in enumerate(self.value['items']):
- lines.append(' item %d:' % (i + 1))
- lines.append('\n'.join([' %s: %s' % (key, self._str_value(value)) for key, value in sorted(item.items())]))
+ lines.append(' item %d:%s%s' % ((i + 1), self.separator,
+ self.separator.join(['%s%s: %s' % (self.indent * 2, key, self._str_value(value)) for key, value in item.items()])))
return '\n'.join(lines)
def _str_value_other(self):
class WeechatObjects(list):
+ def __init__(self, separator='\n'):
+ self.separator = separator
+
def __str__(self):
- return '\n'.join([str(obj) for obj in self])
+ return self.separator.join([str(obj) for obj in self])
class WeechatMessage:
type_keys = self._obj_type()
type_values = self._obj_type()
count = self._obj_int()
- hashtable = {}
+ hashtable = WeechatDict()
for i in range(0, count):
key = self._obj_cb[type_keys]()
value = self._obj_cb[type_values]()
list_path = path.split('/')
list_keys = keys.split(',')
keys_types = []
- dict_keys = {}
+ dict_keys = WeechatDict()
for key in list_keys:
items = key.split(':')
keys_types.append(items)
dict_keys[items[0]] = items[1]
items = []
for i in range(0, count):
- item = {}
+ item = WeechatDict()
+ item['__path'] = []
pointers = []
for p in range(0, len(list_path)):
pointers.append(self._obj_ptr())
items = []
for i in range(0, count_items):
count_vars = self._obj_int()
- variables = {}
+ variables = WeechatDict()
for v in range(0, count_vars):
var_name = self._obj_str()
var_type = self._obj_type()
values.append(self._obj_cb[type_values]())
return values
- def decode(self, data):
+ def decode(self, data, separator='\n'):
"""Decode binary data and return list of objects."""
self.data = data
size = len(self.data)
size_uncompressed = len(uncompressed) + 5
uncompressed = '%s%s%s' % (struct.pack('>i', size_uncompressed), struct.pack('b', 0), uncompressed)
self.data = uncompressed
+ else:
+ uncompressed = self.data[:]
# skip length and compression flag
self.data = self.data[5:]
# read id
if msgid is None:
msgid = ''
# read objects
- objects = WeechatObjects()
+ objects = WeechatObjects(separator=separator)
while len(self.data) > 0:
objtype = self._obj_type()
value = self._obj_cb[objtype]()
- objects.append(WeechatObject(objtype, value))
+ objects.append(WeechatObject(objtype, value, separator=separator))
return WeechatMessage(size, size_uncompressed, compression, uncompressed, msgid, objects)