source: python/wa.py @ 63b017e

Last change on this file since 63b017e was 63b017e, checked in by Wilmer van der Gaast <wilmer@…>, at 2015-05-19T11:39:08Z

Barely functional WhatsApp plugin.

  • Property mode set to 100755
File size: 5.7 KB
Line 
1#!/usr/bin/python
2
3import logging
4import threading
5
6import yowsup
7
8from yowsup.layers.auth                        import YowAuthenticationProtocolLayer
9from yowsup.layers.protocol_messages           import YowMessagesProtocolLayer
10from yowsup.layers.protocol_receipts           import YowReceiptProtocolLayer
11from yowsup.layers.protocol_acks               import YowAckProtocolLayer
12from yowsup.layers.network                     import YowNetworkLayer
13from yowsup.layers.coder                       import YowCoderLayer
14from yowsup.stacks import YowStack
15from yowsup.common import YowConstants
16from yowsup.layers import YowLayerEvent
17from yowsup.stacks import YowStack, YOWSUP_CORE_LAYERS
18from yowsup import env
19
20from yowsup.layers.interface                           import YowInterfaceLayer, ProtocolEntityCallback
21from yowsup.layers.protocol_receipts.protocolentities    import *
22from yowsup.layers.protocol_groups.protocolentities      import *
23from yowsup.layers.protocol_presence.protocolentities    import *
24from yowsup.layers.protocol_messages.protocolentities    import *
25from yowsup.layers.protocol_acks.protocolentities        import *
26from yowsup.layers.protocol_ib.protocolentities          import *
27from yowsup.layers.protocol_iq.protocolentities          import *
28from yowsup.layers.protocol_contacts.protocolentities    import *
29from yowsup.layers.protocol_chatstate.protocolentities   import *
30from yowsup.layers.protocol_privacy.protocolentities     import *
31from yowsup.layers.protocol_media.protocolentities       import *
32from yowsup.layers.protocol_media.mediauploader import MediaUploader
33from yowsup.layers.protocol_profiles.protocolentities    import *
34from yowsup.layers.axolotl.protocolentities.iq_key_get import GetKeysIqProtocolEntity
35from yowsup.layers.axolotl import YowAxolotlLayer
36from yowsup.common.tools import ModuleTools
37
38import implugin
39
40logger = logging.getLogger("yowsup.layers.network.layer")
41logger.setLevel(logging.DEBUG)
42ch = logging.StreamHandler()
43ch.setLevel(logging.DEBUG)
44logger.addHandler(ch)
45
46class BitlBeeLayer(YowInterfaceLayer):
47
48        def __init__(self, *a, **kwa):
49                super(BitlBeeLayer, self).__init__(*a, **kwa)
50
51        def receive(self, entity):
52                print "Received: %s" % entity.getTag()
53                print entity
54                super(BitlBeeLayer, self).receive(entity)
55
56        def Ship(self, entity):
57                """Send an entity into Yowsup, but through the correct thread."""
58                print "Queueing: %s" % entity.getTag()
59                print entity
60                def doit():
61                        self.toLower(entity)
62                self.getStack().execDetached(doit)
63
64        @ProtocolEntityCallback("success")
65        def onSuccess(self, entity):
66                self.b = self.getStack().getProp("org.bitlbee.Bijtje")
67                self.cb = self.b.bee
68                self.b.yow = self
69                self.cb.connected()
70                self.toLower(AvailablePresenceProtocolEntity())
71       
72        @ProtocolEntityCallback("failure")
73        def onFailure(self, entity):
74                self.b = self.getStack().getProp("org.bitlbee.Bijtje")
75                self.cb = self.b.bee
76                self.cb.error(entity.getReason())
77                self.cb.logout(False)
78       
79        @ProtocolEntityCallback("message")
80        def onMessage(self, msg):
81                self.cb.buddy_msg(msg.getFrom(), msg.getBody(), 0, msg.getTimestamp())
82
83                receipt = OutgoingReceiptProtocolEntity(msg.getId(), msg.getFrom())
84                self.toLower(receipt)
85
86        @ProtocolEntityCallback("receipt")
87        def onReceipt(self, entity):
88                ack = OutgoingAckProtocolEntity(entity.getId(), "receipt", "delivery", entity.getFrom())
89                self.toLower(ack)
90
91class YowsupDaemon(threading.Thread):
92        daemon = True
93        stack = None
94
95        class Terminate(Exception):
96                pass
97
98        def run(self):
99                try:
100                        self.stack.loop(timeout=0.2, discrete=0.2, count=1)
101                except YowsupDaemon.Terminate:
102                        print "Exiting loop!"
103                        pass
104       
105        def StopDaemon(self):
106                # Ugly, but yowsup offers no "run single iteration" version
107                # of their event loop :-(
108                raise YowsupDaemon.Terminate
109
110class YowsupIMPlugin(implugin.BitlBeeIMPlugin):
111        NAME = "wa"
112        SETTINGS = {
113                "cc": {
114                        "type": "int",
115                },
116                "name": {
117                        "flags": 0x100, # NULL_OK
118                },
119        }
120        ACCOUNT_FLAGS = 6 # HANDLE_DOMAINS + STATUS_MESSAGE
121        # TODO: LOCAL LIST CAUSES CRASH!
122        # TODO: HANDLE_DOMAIN in right place (add ... ... nick bug)
123       
124        def login(self, account):
125                self.stack = self.build_stack(account)
126                self.daemon = YowsupDaemon(name="yowsup")
127                self.daemon.stack = self.stack
128                self.daemon.start()
129                self.bee.log("Started yowsup thread")
130
131        def keepalive(self):
132                self.yow.Ship(PingIqProtocolEntity(to="s.whatsapp.net"))
133
134        def logout(self):
135                self.stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_DISCONNECT))
136                self.stack.execDetached(self.daemon.StopDaemon)
137
138        def buddy_msg(self, to, text, flags):
139                msg = TextMessageProtocolEntity(text, to=to)
140                self.yow.Ship(msg)
141
142        def add_buddy(self, handle, _group):
143                self.yow.Ship(SubscribePresenceProtocolEntity(handle))
144
145        def remove_buddy(self, handle, _group):
146                self.yow.Ship(UnsubscribePresenceProtocolEntity(handle))
147
148        def set_away(_state, message):
149                # I think state is not supported?
150                print "Trying to set status to %r" % status
151                self.yow.Ship(SetStatusIqProtocolEntity(status))
152
153        def set_set_name(self, _key, value):
154                self.yow.Ship(PresenceProtocolEntity(value))
155
156        def build_stack(self, account):
157                layers = (
158                        BitlBeeLayer,
159                        (YowAuthenticationProtocolLayer, YowMessagesProtocolLayer, YowReceiptProtocolLayer, YowAckProtocolLayer)
160                ) + YOWSUP_CORE_LAYERS
161               
162                creds = (account["user"].split("@")[0], account["pass"])
163
164                stack = YowStack(layers)
165                stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, creds)
166                stack.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[0])
167                stack.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN)
168                stack.setProp(YowCoderLayer.PROP_RESOURCE, env.CURRENT_ENV.getResource())
169                stack.setProp("org.bitlbee.Bijtje", self)
170
171                stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT))
172
173                return stack
174
175implugin.RunPlugin(YowsupIMPlugin, debug=True)
Note: See TracBrowser for help on using the repository browser.