source: python/implugin.py @ a852b2b

Last change on this file since a852b2b was b09ce17, checked in by Wilmer van der Gaast <wilmer@…>, at 2015-05-21T03:43:06Z

Improvements: presence and minimal group support.

Presence depends on https://github.com/tgalal/yowsup/pull/796. :-(

  • Property mode set to 100755
File size: 3.5 KB
Line 
1#!/usr/bin/python
2
3import bjsonrpc
4from bjsonrpc.handlers import BaseHandler
5
6import re
7import socket
8
9# List of functions an IM plugin can export. This library will indicate to
10# BitlBee which functions are actually implemented so omitted features
11# will be disabled, but note that some/many functions are simply mandatory.
12# (Currently login/-out, buddy_msg.)
13SUPPORTED_FUNCTIONS = [
14        'login', 'keepalive', 'logout', 'buddy_msg', 'set_away',
15        'send_typing', 'add_buddy', 'remove_buddy', 'add_permit',
16        'add_deny', 'rem_permit', 'rem_deny', 'get_info', 'chat_invite',
17        'chat_kick', 'chat_leave', 'chat_msg', 'chat_with', 'chat_join',
18        'chat_topic'
19]
20
21def make_version_tuple(hex):
22        """Convert the BitlBee binary-encoded version number into something
23        more "Pythonic". Could use distutils.version instead but its main
24        benefit appears to be string parsing which here is not that useful."""
25
26        return (hex >> 16, (hex >> 8) & 0xff, hex & 0xff)
27
28class RpcForwarder(object):
29        """Tiny object that forwards RPCs from local Python code to BitlBee
30        with a marginally nicer syntax. This layer could eventually be
31        used to add basic parameter checking though I don't think that should
32        be done here."""
33       
34        def __init__(self, methods, target):
35                for m in methods:
36                        # imc(b)_ prefix is not useful here, chop it.
37                        # (Maybe do this in BitlBee already as well.)
38                        newname = re.sub("^imcb?_", "", m)
39                        self.__setattr__(newname, target.__getattr__(m))
40
41class BitlBeeIMPlugin(BaseHandler):
42        # Protocol name to be used in the BitlBee CLI, etc.
43        NAME = "rpc-test"
44
45        # See account.h (TODO: Add constants.)
46        ACCOUNT_FLAGS = 0
47       
48        # Supported away states. If your protocol supports a specific set of
49        # away states, put them in a list in this variable.
50        AWAY_STATES = None
51
52        SETTINGS = {
53                "oauth": {
54                        "default": False,
55                        "type": "bool",
56                },
57                "test": {
58                        "default": 123,
59                        "type": "int",
60                },
61                "stringetje": {
62                        "default": "testje",
63                        "flags": 0x04,
64                }
65        }
66        _settings_values = {}
67       
68        # Filled in during initialisation:
69        # Version number as a three-tuple, so 3.2 becomes (3, 2, 0).
70        bitlbee_version = None
71        # Full version string
72        bitlbee_version_str = None
73        # Will become an RpcForwarder object to call into BitlBee
74        bee = None
75       
76        @classmethod
77        def _factory(cls, *args, **kwargs):
78                def handler_factory(connection):
79                        handler = cls(connection, *args, **kwargs)
80                        return handler
81                return handler_factory
82       
83        def init(self, bee):
84                self.bee = RpcForwarder(bee["method_list"], self._conn.call)
85                self.bitlbee_version = make_version_tuple(bee["version"])
86                self.bitlbee_version_str = bee["version_str"]
87
88                return {
89                        "name": self.NAME,
90                        "method_list": list(set(dir(self)) & set(SUPPORTED_FUNCTIONS)),
91                        "account_flags": self.ACCOUNT_FLAGS,
92                        "away_state_list": self.AWAY_STATES,
93                        "settings": self.SETTINGS,
94                }
95
96        def login(self, account):
97                for key, value in account.get("settings", {}).iteritems():
98                        self.set_set(key, value)
99
100        def set_set(self, key, value):
101                self._settings_values[key] = value
102                try:
103                        func = self.__getattribute__("set_set_%s" % key)
104                except AttributeError:
105                        return
106                func(key, value)
107       
108        def setting(self, key):
109                """Throws KeyError if the setting does not exist!"""
110                return self._settings_values[key]
111
112
113def RunPlugin(plugin, debug=False):
114        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
115        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
116        sock.bind("/tmp/rpcplugins/%s.sock" % plugin.NAME)
117        sock.listen(3)
118       
119        srv = bjsonrpc.server.Server(sock, plugin._factory())
120       
121        srv.debug_socket(debug)
122        srv.serve()
Note: See TracBrowser for help on using the repository browser.