source: python/wa.py @ 5f8ad281

Last change on this file since 5f8ad281 was 5f8ad281, checked in by Wilmer van der Gaast <wilmer@…>, at 2015-05-20T02:56:41Z

WA improvements: "Handle" all stanzas. Presence now seems to get through.

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