Compare commits
35 commits
Author | SHA1 | Date | |
---|---|---|---|
35afbe5d4a | |||
61d467b393 | |||
004422e81e | |||
8ae801cf90 | |||
65faf3766a | |||
![]() |
6e8bf2b616 | ||
269dbdc12d | |||
c359751a44 | |||
acceb3618b | |||
b4f57753c8 | |||
4244920435 | |||
f40102c0c7 | |||
![]() |
42f8c079c3 | ||
![]() |
d88d13d1e3 | ||
![]() |
0c199a8231 | ||
![]() |
02b45a233e | ||
![]() |
2911274ab6 | ||
76fb1b4a6d | |||
![]() |
6563c7282b | ||
![]() |
a51a6b7272 | ||
![]() |
ce70a912dd | ||
fe0ffe7891 | |||
b416990d98 | |||
![]() |
fd477b0eea | ||
![]() |
c96fbbb049 | ||
d85a554e15 | |||
e3ebdae54e | |||
![]() |
13ac8b4d31 | ||
![]() |
c3c76e4cb7 | ||
![]() |
7eb4707397 | ||
![]() |
5caba690cb | ||
085b5a7675 | |||
52ec521ade | |||
9b1e2c1462 | |||
81687c9402 |
12 changed files with 447 additions and 320 deletions
15
INSTALL.rst
15
INSTALL.rst
|
@ -2,7 +2,7 @@ Installation and configuration guide
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
I assume that you have a basic understanding of XMPP and the the concept
|
I assume that you have a basic understanding of XMPP and the the concept
|
||||||
of a XMPP component / transport. If not, please get a book about Jabber
|
of a XMPP component/transport. If not, please get a book about Jabber
|
||||||
or read the standards.
|
or read the standards.
|
||||||
|
|
||||||
transWhat is a XMPP transport. By this means it extends the
|
transWhat is a XMPP transport. By this means it extends the
|
||||||
|
@ -44,14 +44,14 @@ Spectrum 2
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
^^^^^^^^^^^^
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
Manual compile latest version from `Github`_. You can use the following
|
Manual compile latest version from `Github`_. You can use the following
|
||||||
guide:
|
guide:
|
||||||
http://spectrum.im/documentation/installation/from\_source\_code.html.
|
http://spectrum.im/documentation/installation/from\_source\_code.html.
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
^^^^^^^^^^^^^
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
Create a new file ``/etc/spectrum2/transports/whatsapp.cfg`` with the
|
Create a new file ``/etc/spectrum2/transports/whatsapp.cfg`` with the
|
||||||
following content:
|
following content:
|
||||||
|
@ -69,7 +69,7 @@ following content:
|
||||||
port = 5221
|
port = 5221
|
||||||
|
|
||||||
backend_host = localhost
|
backend_host = localhost
|
||||||
backend = /location/to/transwhat/transwhat.py
|
backend = /usr/bin/transwhat
|
||||||
|
|
||||||
users_per_backend = 10
|
users_per_backend = 10
|
||||||
more_resources = 1
|
more_resources = 1
|
||||||
|
@ -106,11 +106,12 @@ Install required dependencies:
|
||||||
|
|
||||||
$ pip install --pre e4u protobuf python-dateutil yowsup2
|
$ pip install --pre e4u protobuf python-dateutil yowsup2
|
||||||
|
|
||||||
- **e4u**: is a simple emoji4unicode python bindings
|
- e4u_: is a simple emoji4unicode python bindings
|
||||||
- `**yowsup**`_: is a python library that enables you build application
|
- yowsup_: is a python library that enables you build application
|
||||||
which use WhatsApp service.
|
which use WhatsApp service.
|
||||||
|
|
||||||
.. _Spectrum 2: http://www.spectrum.im
|
.. _Spectrum 2: http://www.spectrum.im
|
||||||
.. _Yowsup 2: https://github.com/tgalal/yowsup
|
.. _Yowsup 2: https://github.com/tgalal/yowsup
|
||||||
.. _Github: https://github.com/hanzz/libtransport
|
.. _Github: https://github.com/hanzz/libtransport
|
||||||
.. _**yowsup**: https://github.com/tgalal/yowsup
|
.. _yowsup: https://github.com/tgalal/yowsup
|
||||||
|
.. _e4u: https://pypi.python.org/pypi/e4u
|
||||||
|
|
50
README.rst
50
README.rst
|
@ -3,24 +3,10 @@ transWhat
|
||||||
|
|
||||||
transWhat is a WhatsApp XMPP Gateway based on `Spectrum 2`_ and `Yowsup 2`_.
|
transWhat is a WhatsApp XMPP Gateway based on `Spectrum 2`_ and `Yowsup 2`_.
|
||||||
|
|
||||||
Branches
|
Support
|
||||||
^^^^^^^^
|
-------
|
||||||
|
|
||||||
- `yowsup-1`_ My original version which is based on @tgalal first
|
For support and discussions please join the XMPP MUC: **transwhat@conference.0l.de**.
|
||||||
Yowsup version (**deprecated** and broken).
|
|
||||||
- `yowsup-2`_ Major rewrite from @moyamo for @tgalal’s new Yowsup 2
|
|
||||||
(**recommended**).
|
|
||||||
|
|
||||||
For production, please use the ``yowsup-2`` branch.
|
|
||||||
|
|
||||||
`Installation`_
|
|
||||||
---------------
|
|
||||||
|
|
||||||
`Usage`_
|
|
||||||
--------
|
|
||||||
|
|
||||||
`License`_
|
|
||||||
----------
|
|
||||||
|
|
||||||
Features
|
Features
|
||||||
--------
|
--------
|
||||||
|
@ -31,6 +17,24 @@ Features
|
||||||
- Set status message
|
- Set status message
|
||||||
- Groupchats
|
- Groupchats
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
transWhat requires a running and configured XMPP server.
|
||||||
|
Detailed instructions can be found on the `Installation`_ page.
|
||||||
|
|
||||||
|
Users find details on the `Usage`_ page.
|
||||||
|
|
||||||
|
Branches
|
||||||
|
--------
|
||||||
|
|
||||||
|
- `yowsup-1`_ My original version which is based on @tgalal first
|
||||||
|
Yowsup version (**deprecated** and broken).
|
||||||
|
- `yowsup-2`_ Major rewrite from @moyamo for @tgalal’s new Yowsup 2
|
||||||
|
(**recommended**).
|
||||||
|
|
||||||
|
For production, please use the ``yowsup-2`` branch.
|
||||||
|
|
||||||
Contributors
|
Contributors
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -44,12 +48,16 @@ The following persons have contributed major parts of this code:
|
||||||
- @moyamo (Mohammed Yaseen Mowzer): Port to Yowsup 2
|
- @moyamo (Mohammed Yaseen Mowzer): Port to Yowsup 2
|
||||||
- @DaZZZl: Improvements to group chats, media & message receipts
|
- @DaZZZl: Improvements to group chats, media & message receipts
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
transWhat is licensed under the GPLv3_ license.
|
||||||
|
|
||||||
Links
|
Links
|
||||||
-----
|
-----
|
||||||
|
|
||||||
An *outdated* project wiki is available `here`_.
|
- An *outdated* project wiki is available `here`_.
|
||||||
|
- An *outdated* writeup of this project is also availabe at my `blog`_.
|
||||||
An *outdated* writeup of this project is also availabe at my `blog`_.
|
|
||||||
|
|
||||||
.. _Spectrum 2: http://www.spectrum.im
|
.. _Spectrum 2: http://www.spectrum.im
|
||||||
.. _Yowsup 2: https://github.com/tgalal/yowsup
|
.. _Yowsup 2: https://github.com/tgalal/yowsup
|
||||||
|
@ -57,6 +65,6 @@ An *outdated* writeup of this project is also availabe at my `blog`_.
|
||||||
.. _yowsup-2: http://github.com/stv0g/transwhat/tree/yowsup-2
|
.. _yowsup-2: http://github.com/stv0g/transwhat/tree/yowsup-2
|
||||||
.. _Installation: INSTALL.rst
|
.. _Installation: INSTALL.rst
|
||||||
.. _Usage: USAGE.rst
|
.. _Usage: USAGE.rst
|
||||||
.. _License: COPYING.rst
|
.. _GPLv3: COPYING.rst
|
||||||
.. _here: https://dev.0l.de/wiki/projects/transwhat/
|
.. _here: https://dev.0l.de/wiki/projects/transwhat/
|
||||||
.. _blog: http://www.steffenvogel.de/2013/06/29/transwhat/
|
.. _blog: http://www.steffenvogel.de/2013/06/29/transwhat/
|
||||||
|
|
|
@ -89,6 +89,7 @@ message Room {
|
||||||
message RoomList {
|
message RoomList {
|
||||||
repeated string room = 1;
|
repeated string room = 1;
|
||||||
repeated string name = 2;
|
repeated string name = 2;
|
||||||
|
optional string user = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ParticipantFlag {
|
enum ParticipantFlag {
|
||||||
|
@ -111,6 +112,7 @@ message Participant {
|
||||||
optional string statusMessage = 6;
|
optional string statusMessage = 6;
|
||||||
optional string newname = 7;
|
optional string newname = 7;
|
||||||
optional string iconHash = 8;
|
optional string iconHash = 8;
|
||||||
|
optional string alias = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message VCard {
|
message VCard {
|
||||||
|
@ -152,6 +154,10 @@ message BackendConfig {
|
||||||
required string config = 1;
|
required string config = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message APIVersion {
|
||||||
|
required int32 version = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message WrapperMessage {
|
message WrapperMessage {
|
||||||
enum Type {
|
enum Type {
|
||||||
TYPE_CONNECTED = 1;
|
TYPE_CONNECTED = 1;
|
||||||
|
@ -188,8 +194,10 @@ message WrapperMessage {
|
||||||
TYPE_CONV_MESSAGE_ACK = 33;
|
TYPE_CONV_MESSAGE_ACK = 33;
|
||||||
TYPE_RAW_XML = 34;
|
TYPE_RAW_XML = 34;
|
||||||
TYPE_BUDDIES = 35;
|
TYPE_BUDDIES = 35;
|
||||||
|
TYPE_API_VERSION = 36;
|
||||||
}
|
}
|
||||||
required Type type = 1;
|
required Type type = 1;
|
||||||
optional bytes payload = 2;
|
optional bytes payload = 2;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
5
setup.py
Normal file → Executable file
5
setup.py
Normal file → Executable file
|
@ -1,3 +1,5 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import codecs
|
import codecs
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
@ -33,6 +35,9 @@ setup(name='transwhat',
|
||||||
'transWhat',
|
'transWhat',
|
||||||
'Spectrum2'
|
'Spectrum2'
|
||||||
],
|
],
|
||||||
|
scripts=[
|
||||||
|
'transWhat/transwhat.py'
|
||||||
|
],
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'protobuf',
|
'protobuf',
|
||||||
'yowsup2',
|
'yowsup2',
|
||||||
|
|
|
@ -39,7 +39,6 @@ class Bot():
|
||||||
|
|
||||||
self.commands = {
|
self.commands = {
|
||||||
"help": self._help,
|
"help": self._help,
|
||||||
"prune": self._prune,
|
|
||||||
"groups": self._groups,
|
"groups": self._groups,
|
||||||
"getgroups": self._getgroups
|
"getgroups": self._getgroups
|
||||||
}
|
}
|
||||||
|
@ -76,7 +75,6 @@ class Bot():
|
||||||
def _help(self):
|
def _help(self):
|
||||||
self.send("""following bot commands are available:
|
self.send("""following bot commands are available:
|
||||||
\\help show this message
|
\\help show this message
|
||||||
\\prune clear your buddylist
|
|
||||||
|
|
||||||
following user commands are available:
|
following user commands are available:
|
||||||
\\lastseen request last online timestamp from buddy
|
\\lastseen request last online timestamp from buddy
|
||||||
|
@ -86,11 +84,6 @@ following group commands are available
|
||||||
\\groups print all attended groups
|
\\groups print all attended groups
|
||||||
\\getgroups get current groups from WA""")
|
\\getgroups get current groups from WA""")
|
||||||
|
|
||||||
def _prune(self):
|
|
||||||
self.session.buddies.prune()
|
|
||||||
self.session.updateRoster()
|
|
||||||
self.send("buddy list cleared")
|
|
||||||
|
|
||||||
def _groups(self):
|
def _groups(self):
|
||||||
for group in self.session.groups:
|
for group in self.session.groups:
|
||||||
buddy = self.session.groups[group].owner
|
buddy = self.session.groups[group].owner
|
||||||
|
|
|
@ -109,7 +109,6 @@ class BuddyList(dict):
|
||||||
try: del self[number]
|
try: del self[number]
|
||||||
except KeyError: self.logger.warn("non-existing buddy really didn't exist: %s" % number)
|
except KeyError: self.logger.warn("non-existing buddy really didn't exist: %s" % number)
|
||||||
|
|
||||||
|
|
||||||
def onStatus(self, contacts):
|
def onStatus(self, contacts):
|
||||||
self.logger.debug("%s received statuses of: %s" % (self.user, contacts))
|
self.logger.debug("%s received statuses of: %s" % (self.user, contacts))
|
||||||
for number, (status, time) in contacts.iteritems():
|
for number, (status, time) in contacts.iteritems():
|
||||||
|
@ -121,7 +120,6 @@ class BuddyList(dict):
|
||||||
buddy.statusMsg = utils.softToUni(status)
|
buddy.statusMsg = utils.softToUni(status)
|
||||||
self.updateSpectrum(buddy)
|
self.updateSpectrum(buddy)
|
||||||
|
|
||||||
|
|
||||||
def load(self, buddies):
|
def load(self, buddies):
|
||||||
if self.session.loggedIn:
|
if self.session.loggedIn:
|
||||||
self._load(buddies)
|
self._load(buddies)
|
||||||
|
@ -165,7 +163,6 @@ class BuddyList(dict):
|
||||||
self.backend.handleBuddyChanged(self.user, buddy.number, buddy.nick,
|
self.backend.handleBuddyChanged(self.user, buddy.number, buddy.nick,
|
||||||
buddy.groups, status, statusMessage=statusmsg, iconHash=iconHash)
|
buddy.groups, status, statusMessage=statusmsg, iconHash=iconHash)
|
||||||
|
|
||||||
|
|
||||||
def remove(self, number):
|
def remove(self, number):
|
||||||
try:
|
try:
|
||||||
buddy = self[number]
|
buddy = self[number]
|
||||||
|
@ -174,7 +171,7 @@ class BuddyList(dict):
|
||||||
protocol_pb2.STATUS_NONE)
|
protocol_pb2.STATUS_NONE)
|
||||||
self.backend.handleBuddyRemoved(self.user, number)
|
self.backend.handleBuddyRemoved(self.user, number)
|
||||||
self.session.unsubscribePresence(number)
|
self.session.unsubscribePresence(number)
|
||||||
# TODO Sync remove
|
# TODO Sync remove
|
||||||
return buddy
|
return buddy
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -33,6 +33,9 @@ import time
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding("utf-8")
|
||||||
|
|
||||||
from yowsup.layers.protocol_media.mediauploader import MediaUploader
|
from yowsup.layers.protocol_media.mediauploader import MediaUploader
|
||||||
from yowsup.layers.protocol_media.mediadownloader import MediaDownloader
|
from yowsup.layers.protocol_media.mediadownloader import MediaDownloader
|
||||||
|
|
||||||
|
@ -132,39 +135,34 @@ class Session(YowsupApp):
|
||||||
"\n".join(text) + "\nIf you do not join them you will lose messages"
|
"\n".join(text) + "\nIf you do not join them you will lose messages"
|
||||||
#self.bot.send(message)
|
#self.bot.send(message)
|
||||||
|
|
||||||
def _updateGroups(self, response, request):
|
def _updateGroups(self, response, _):
|
||||||
self.logger.debug('Received groups list %s' % response)
|
self.logger.debug('Received groups list %s' % response)
|
||||||
groups = response.getGroups()
|
groups = response.getGroups()
|
||||||
for group in groups:
|
for group in groups:
|
||||||
room = group.getId()
|
room = group.getId()
|
||||||
owner = group.getOwner().split('@')[0]
|
# ensure self.groups[room] exists
|
||||||
subjectOwner = group.getSubjectOwner().split('@')[0]
|
if room not in self.groups:
|
||||||
subject = utils.softToUni(group.getSubject())
|
owner = group.getOwner().split('@')[0]
|
||||||
|
subjectOwner = group.getSubjectOwner().split('@')[0]
|
||||||
if room in self.groups:
|
subject = utils.softToUni(group.getSubject())
|
||||||
oroom = self.groups[room]
|
self.groups[room] = Group(room, owner, subject, subjectOwner,
|
||||||
oroom.owner = owner
|
self.backend, self.user)
|
||||||
oroom.subjectOwner = subjectOwner
|
# add/update room participants
|
||||||
oroom.subject = subject
|
|
||||||
else:
|
|
||||||
self.groups[room] = Group(room, owner, subject, subjectOwner, self.backend, self.user)
|
|
||||||
# self.joinRoom(self._shortenGroupId(room), self.user.split("@")[0])
|
|
||||||
self.groups[room].addParticipants(group.getParticipants().keys(),
|
self.groups[room].addParticipants(group.getParticipants().keys(),
|
||||||
self.buddies, self.legacyName)
|
self.buddies, self.legacyName)
|
||||||
|
|
||||||
#self._addParticipantsToRoom(room, group.getParticipants())
|
|
||||||
|
|
||||||
if room in self.groupOfflineQueue:
|
|
||||||
while self.groupOfflineQueue[room]:
|
|
||||||
msg = self.groupOfflineQueue[room].pop(0)
|
|
||||||
self.backend.handleMessage(self.user, room, msg[1],
|
|
||||||
msg[0], "", msg[2])
|
|
||||||
self.logger.debug("Send queued group message to: %s %s %s" %
|
|
||||||
(msg[0],msg[1], msg[2]))
|
|
||||||
self.gotGroupList = True
|
self.gotGroupList = True
|
||||||
for room, nick in self.joinRoomQueue:
|
# join rooms
|
||||||
self.joinRoom(room, nick)
|
while self.joinRoomQueue:
|
||||||
self.joinRoomQueue = []
|
self.joinRoom(*self.joinRoomQueue.pop(0))
|
||||||
|
# deliver queued offline messages
|
||||||
|
for room in self.groupOfflineQueue:
|
||||||
|
while self.groupOfflineQueue[room]:
|
||||||
|
msg = self.groupOfflineQueue[room].pop(0)
|
||||||
|
self.backend.handleMessage(self.user, room, msg[1], msg[0], "",
|
||||||
|
msg[2])
|
||||||
|
self.logger.debug("Send queued group message to: %s %s %s" %
|
||||||
|
(msg[0], msg[1], msg[2]))
|
||||||
|
# pass update to backend
|
||||||
self.updateRoomList()
|
self.updateRoomList()
|
||||||
|
|
||||||
def joinRoom(self, room, nick):
|
def joinRoom(self, room, nick):
|
||||||
|
@ -302,81 +300,61 @@ class Session(YowsupApp):
|
||||||
|
|
||||||
# Called by superclass
|
# Called by superclass
|
||||||
def onImage(self, image):
|
def onImage(self, image):
|
||||||
self.logger.debug('Received image message: %s' % image)
|
|
||||||
buddy = image._from.split('@')[0]
|
|
||||||
participant = image.participant
|
|
||||||
if image.caption is None:
|
if image.caption is None:
|
||||||
image.caption = ''
|
image.caption = ''
|
||||||
|
|
||||||
if image.isEncrypted():
|
self.onMedia(image, "image")
|
||||||
self.logger.debug('Received encrypted image message')
|
|
||||||
if self.backend.specConf is not None and self.backend.specConf.__getitem__("service.web_directory") is not None and self.backend.specConf.__getitem__("service.web_url") is not None :
|
|
||||||
ipath = "/" + str(image.timestamp) + image.getExtension()
|
|
||||||
|
|
||||||
with open(self.backend.specConf.__getitem__("service.web_directory") + ipath,"wb") as f:
|
|
||||||
f.write(image.getMediaContent())
|
|
||||||
url = self.backend.specConf.__getitem__("service.web_url") + ipath
|
|
||||||
else:
|
|
||||||
self.logger.warn('Received encrypted image: web storage not set in config!')
|
|
||||||
url = image.url
|
|
||||||
|
|
||||||
else:
|
|
||||||
url = image.url
|
|
||||||
|
|
||||||
if participant is not None: # Group message
|
|
||||||
partname = participant.split('@')[0]
|
|
||||||
if image._from.split('@')[1] == 'broadcast': # Broadcast message
|
|
||||||
self.sendMessageToXMPP(partname, self.broadcast_prefix, image.timestamp)
|
|
||||||
self.sendMessageToXMPP(partname, url, image.timestamp)
|
|
||||||
self.sendMessageToXMPP(partname, image.caption, image.timestamp)
|
|
||||||
else: # Group message
|
|
||||||
self.sendGroupMessageToXMPP(buddy, partname, url, image.timestamp)
|
|
||||||
self.sendGroupMessageToXMPP(buddy, partname, image.caption, image.timestamp)
|
|
||||||
else:
|
|
||||||
self.sendMessageToXMPP(buddy, url, image.timestamp)
|
|
||||||
self.sendMessageToXMPP(buddy, image.caption, image.timestamp)
|
|
||||||
self.sendReceipt(image._id, image._from, None, image.participant)
|
|
||||||
self.recvMsgIDs.append((image._id, image._from, image.participant, image.timestamp))
|
|
||||||
|
|
||||||
|
|
||||||
# Called by superclass
|
# Called by superclass
|
||||||
def onAudio(self, audio):
|
def onAudio(self, audio):
|
||||||
self.logger.debug('Received audio message: %s' % audio)
|
self.onMedia(audio, "audio")
|
||||||
buddy = audio._from.split('@')[0]
|
|
||||||
participant = audio.participant
|
|
||||||
message = audio.url
|
|
||||||
if participant is not None: # Group message
|
|
||||||
partname = participant.split('@')[0]
|
|
||||||
if audio._from.split('@')[1] == 'broadcast': # Broadcast message
|
|
||||||
self.sendMessageToXMPP(partname, self.broadcast_prefix, audio.timestamp)
|
|
||||||
self.sendMessageToXMPP(partname, message, audio.timestamp)
|
|
||||||
else: # Group message
|
|
||||||
self.sendGroupMessageToXMPP(buddy, partname, message, audio.timestamp)
|
|
||||||
else:
|
|
||||||
self.sendMessageToXMPP(buddy, message, audio.timestamp)
|
|
||||||
self.sendReceipt(audio._id, audio._from, None, audio.participant)
|
|
||||||
self.recvMsgIDs.append((audio._id, audio._from, audio.participant, audio.timestamp))
|
|
||||||
|
|
||||||
|
|
||||||
# Called by superclass
|
# Called by superclass
|
||||||
def onVideo(self, video):
|
def onVideo(self, video):
|
||||||
self.logger.debug('Received video message: %s' % video)
|
self.onMedia(video, "video")
|
||||||
buddy = video._from.split('@')[0]
|
|
||||||
participant = video.participant
|
|
||||||
|
def onMedia(self, media, type):
|
||||||
|
self.logger.debug('Received %s message: %s' % (type, media))
|
||||||
|
buddy = media._from.split('@')[0]
|
||||||
|
participant = media.participant
|
||||||
|
caption = ''
|
||||||
|
|
||||||
|
if media.isEncrypted():
|
||||||
|
self.logger.debug('Received encrypted media message')
|
||||||
|
if self.backend.specConf is not None and self.backend.specConf.__getitem__("service.web_directory") is not None and self.backend.specConf.__getitem__("service.web_url") is not None :
|
||||||
|
ipath = "/" + str(media.timestamp) + media.getExtension()
|
||||||
|
|
||||||
|
with open(self.backend.specConf.__getitem__("service.web_directory") + ipath,"wb") as f:
|
||||||
|
f.write(media.getMediaContent())
|
||||||
|
url = self.backend.specConf.__getitem__("service.web_url") + ipath
|
||||||
|
else:
|
||||||
|
self.logger.warn('Received encrypted media: web storage not set in config!')
|
||||||
|
url = media.url
|
||||||
|
|
||||||
|
else:
|
||||||
|
url = media.url
|
||||||
|
|
||||||
|
if type == 'image':
|
||||||
|
caption = media.caption
|
||||||
|
|
||||||
message = video.url
|
|
||||||
if participant is not None: # Group message
|
if participant is not None: # Group message
|
||||||
partname = participant.split('@')[0]
|
partname = participant.split('@')[0]
|
||||||
if video._from.split('@')[1] == 'broadcast': # Broadcast message
|
if media._from.split('@')[1] == 'broadcast': # Broadcast message
|
||||||
self.sendMessageToXMPP(partname, self.broadcast_prefix, video.timestamp)
|
self.sendMessageToXMPP(partname, self.broadcast_prefix, media.timestamp)
|
||||||
self.sendMessageToXMPP(partname, message, video.timestamp)
|
self.sendMessageToXMPP(partname, url, media.timestamp)
|
||||||
|
self.sendMessageToXMPP(partname, caption, media.timestamp)
|
||||||
else: # Group message
|
else: # Group message
|
||||||
self.sendGroupMessageToXMPP(buddy, partname, message, video.timestamp)
|
self.sendGroupMessageToXMPP(buddy, partname, url, media.timestamp)
|
||||||
|
self.sendGroupMessageToXMPP(buddy, partname, caption, media.timestamp)
|
||||||
else:
|
else:
|
||||||
self.sendMessageToXMPP(buddy, message, video.timestamp)
|
self.sendMessageToXMPP(buddy, url, media.timestamp)
|
||||||
self.sendReceipt(video._id, video._from, None, video.participant)
|
self.sendMessageToXMPP(buddy, caption, media.timestamp)
|
||||||
self.recvMsgIDs.append((video._id, video._from, video.participant, video.timestamp))
|
|
||||||
|
|
||||||
|
self.sendReceipt(media._id, media._from, None, media.participant)
|
||||||
|
self.recvMsgIDs.append((media._id, media._from, media.participant, media.timestamp))
|
||||||
|
|
||||||
def onLocation(self, location):
|
def onLocation(self, location):
|
||||||
buddy = location._from.split('@')[0]
|
buddy = location._from.split('@')[0]
|
||||||
|
@ -690,7 +668,7 @@ class Session(YowsupApp):
|
||||||
waId = self.sendTextMessage(sender + '@s.whatsapp.net', message)
|
waId = self.sendTextMessage(sender + '@s.whatsapp.net', message)
|
||||||
self.msgIDs[waId] = MsgIDs(ID, waId)
|
self.msgIDs[waId] = MsgIDs(ID, waId)
|
||||||
|
|
||||||
self.logger.info("WA Message send to %s with ID %s", buddy, waId)
|
# self.logger.info("WA Message send to %s with ID %s", buddy, waId)
|
||||||
|
|
||||||
def executeCommand(self, command, room):
|
def executeCommand(self, command, room):
|
||||||
if command == '\\leave':
|
if command == '\\leave':
|
||||||
|
|
|
@ -33,13 +33,13 @@ import asyncore
|
||||||
import sys, os
|
import sys, os
|
||||||
import e4u
|
import e4u
|
||||||
import Queue
|
import Queue
|
||||||
import threadutils
|
import transWhat.threadutils
|
||||||
|
|
||||||
sys.path.insert(0, os.getcwd())
|
sys.path.insert(0, os.getcwd())
|
||||||
|
|
||||||
from Spectrum2.iochannel import IOChannel
|
from Spectrum2.iochannel import IOChannel
|
||||||
from config import SpectrumConfig
|
from Spectrum2.config import SpectrumConfig
|
||||||
from whatsappbackend import WhatsAppBackend
|
from transWhat.whatsappbackend import WhatsAppBackend
|
||||||
from yowsup.common import YowConstants
|
from yowsup.common import YowConstants
|
||||||
from yowsup.stacks import YowStack
|
from yowsup.stacks import YowStack
|
||||||
|
|
||||||
|
@ -58,36 +58,36 @@ args, unknown = parser.parse_known_args()
|
||||||
YowConstants.PATH_STORAGE='/var/lib/spectrum2/' + args.j
|
YowConstants.PATH_STORAGE='/var/lib/spectrum2/' + args.j
|
||||||
|
|
||||||
if args.log is None:
|
if args.log is None:
|
||||||
args.log = '/var/log/spectrum2/' + args.j + '/backends/backend.log'
|
args.log = '/var/log/spectrum2/' + args.j + '/backends/backend.log'
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
filename = args.log,
|
filename = args.log,
|
||||||
format = "%(asctime)-15s %(levelname)s %(name)s: %(message)s",
|
format = "%(asctime)-15s %(levelname)s %(name)s: %(message)s",
|
||||||
level = logging.DEBUG if args.debug else logging.INFO
|
level = logging.DEBUG if args.debug else logging.INFO
|
||||||
)
|
)
|
||||||
|
|
||||||
if args.config is not None:
|
if args.config is not None:
|
||||||
specConf = SpectrumConfig(args.config)
|
specConf = SpectrumConfig(args.config)
|
||||||
else:
|
else:
|
||||||
specConf = None
|
specConf = None
|
||||||
|
|
||||||
# Handler
|
# Handler
|
||||||
def handleTransportData(data):
|
def handleTransportData(data):
|
||||||
try:
|
try:
|
||||||
plugin.handleDataRead(data)
|
plugin.handleDataRead(data)
|
||||||
except SystemExit as e:
|
except SystemExit as e:
|
||||||
raise e
|
raise e
|
||||||
except:
|
except:
|
||||||
logger = logging.getLogger('transwhat')
|
logger = logging.getLogger('transwhat')
|
||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
|
|
||||||
e4u.load()
|
e4u.load()
|
||||||
|
|
||||||
closed = False
|
closed = False
|
||||||
def connectionClosed():
|
def connectionClosed():
|
||||||
global closed
|
global closed
|
||||||
closed = True
|
closed = True
|
||||||
|
|
||||||
# Main
|
# Main
|
||||||
io = IOChannel(args.host, args.port, handleTransportData, connectionClosed)
|
io = IOChannel(args.host, args.port, handleTransportData, connectionClosed)
|
||||||
|
@ -95,34 +95,34 @@ io = IOChannel(args.host, args.port, handleTransportData, connectionClosed)
|
||||||
plugin = WhatsAppBackend(io, args.j, specConf)
|
plugin = WhatsAppBackend(io, args.j, specConf)
|
||||||
|
|
||||||
plugin.handleBackendConfig({
|
plugin.handleBackendConfig({
|
||||||
'features': [
|
'features': [
|
||||||
('send_buddies_on_login', 1),
|
('send_buddies_on_login', 1),
|
||||||
('muc', 'true'),
|
('muc', 'true'),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def main():
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
asyncore.loop(timeout=1.0, count=10, use_poll = True)
|
asyncore.loop(timeout=1.0, count=10, use_poll = True)
|
||||||
try:
|
try:
|
||||||
callback = YowStack._YowStack__detachedQueue.get(False) #doesn't block
|
callback = YowStack._YowStack__detachedQueue.get(False) #doesn't block
|
||||||
callback()
|
callback()
|
||||||
except Queue.Empty:
|
except Queue.Empty:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
if closed:
|
if closed:
|
||||||
break
|
break
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
callback = threadutils.eventQueue.get_nowait()
|
callback = transWhat.threadutils.eventQueue.get_nowait()
|
||||||
except Queue.Empty:
|
except Queue.Empty:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
callback()
|
callback()
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
logger = logging.getLogger('transwhat')
|
logger = logging.getLogger('transwhat')
|
||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
|
|
|
@ -165,7 +165,7 @@ class WhatsAppBackend(SpectrumBackend):
|
||||||
def handleRawXmlRequest(self, xml):
|
def handleRawXmlRequest(self, xml):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def handleMessageAckRequest(self, user, legacyName, ID = 0):
|
def handleMessageAckRequest(self, user, legacyName, ID = 0):
|
||||||
self.logger.info("Meassage ACK request for %s !!" % legacyName)
|
self.logger.info("Meassage ACK request for %s !!" % legacyName)
|
||||||
|
|
||||||
def sendData(self, data):
|
def sendData(self, data):
|
||||||
|
|
|
@ -25,16 +25,14 @@ __email__ = "post@steffenvogel.de"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
from yowsup import env
|
from yowsup import env
|
||||||
from yowsup.env import S40YowsupEnv
|
from yowsup.env import S40YowsupEnv
|
||||||
from yowsup.stacks import YowStack
|
from yowsup.stacks import YowStack, YowStackBuilder
|
||||||
from yowsup.common import YowConstants
|
from yowsup.common import YowConstants
|
||||||
from yowsup.layers import YowLayerEvent, YowParallelLayer
|
from yowsup.layers import YowLayerEvent, YowParallelLayer
|
||||||
from yowsup.layers.auth import AuthError
|
from yowsup.layers.auth import AuthError
|
||||||
from yowsup.stacks import YowStack
|
|
||||||
from yowsup.stacks import YowStackBuilder
|
|
||||||
from yowsup.common import YowConstants
|
|
||||||
|
|
||||||
# Layers
|
# Layers
|
||||||
from yowsup.layers.axolotl import AxolotlSendLayer, AxolotlControlLayer, AxolotlReceivelayer
|
from yowsup.layers.axolotl import AxolotlSendLayer, AxolotlControlLayer, AxolotlReceivelayer
|
||||||
|
@ -56,10 +54,10 @@ from yowsup.layers.protocol_contacts import YowContactsIqProtocolLayer
|
||||||
from yowsup.layers.protocol_chatstate import YowChatstateProtocolLayer
|
from yowsup.layers.protocol_chatstate import YowChatstateProtocolLayer
|
||||||
from yowsup.layers.protocol_privacy import YowPrivacyProtocolLayer
|
from yowsup.layers.protocol_privacy import YowPrivacyProtocolLayer
|
||||||
from yowsup.layers.protocol_profiles import YowProfilesProtocolLayer
|
from yowsup.layers.protocol_profiles import YowProfilesProtocolLayer
|
||||||
from yowsup.layers.protocol_calls import YowCallsProtocolLayer
|
from yowsup.layers.protocol_calls import YowCallsProtocolLayer
|
||||||
|
from yowsup.layers.axolotl.props import PROP_IDENTITY_AUTOTRUST
|
||||||
|
|
||||||
# ProtocolEntities
|
# ProtocolEntities
|
||||||
|
|
||||||
from yowsup.layers.protocol_acks.protocolentities import *
|
from yowsup.layers.protocol_acks.protocolentities import *
|
||||||
from yowsup.layers.protocol_chatstate.protocolentities import *
|
from yowsup.layers.protocol_chatstate.protocolentities import *
|
||||||
from yowsup.layers.protocol_contacts.protocolentities import *
|
from yowsup.layers.protocol_contacts.protocolentities import *
|
||||||
|
@ -75,9 +73,7 @@ from yowsup.layers.protocol_iq.protocolentities import *
|
||||||
from yowsup.layers.protocol_media.mediauploader import MediaUploader
|
from yowsup.layers.protocol_media.mediauploader import MediaUploader
|
||||||
from yowsup.layers.protocol_media.mediadownloader import MediaDownloader
|
from yowsup.layers.protocol_media.mediadownloader import MediaDownloader
|
||||||
|
|
||||||
|
|
||||||
# Registration
|
# Registration
|
||||||
|
|
||||||
from yowsup.registration import WACodeRequest
|
from yowsup.registration import WACodeRequest
|
||||||
from yowsup.registration import WARegRequest
|
from yowsup.registration import WARegRequest
|
||||||
|
|
||||||
|
@ -132,9 +128,10 @@ class YowsupApp(object):
|
||||||
and cellphone number)
|
and cellphone number)
|
||||||
|
|
||||||
- password: (str) base64 encoded password
|
- password: (str) base64 encoded password
|
||||||
"""
|
"""
|
||||||
self.stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS,
|
self.stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS,
|
||||||
(username, password))
|
(username, password))
|
||||||
|
self.stack.setProp(PROP_IDENTITY_AUTOTRUST, True)
|
||||||
# self.stack.setProp(YowIqProtocolLayer.PROP_PING_INTERVAL, 5)
|
# self.stack.setProp(YowIqProtocolLayer.PROP_PING_INTERVAL, 5)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Add table
Reference in a new issue