transpub/transWhat/yowsupwrapper.py

890 lines
28 KiB
Python

# use unicode encoding for all literals by default (for python2.x)
from __future__ import unicode_literals
__author__ = "Steffen Vogel"
__copyright__ = "Copyright 2015-2017, Steffen Vogel"
__license__ = "GPLv3"
__maintainer__ = "Steffen Vogel"
__email__ = "post@steffenvogel.de"
"""
This file is part of transWhat
transWhat is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
transwhat is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with transWhat. If not, see <http://www.gnu.org/licenses/>.
"""
import logging
from yowsup import env
from yowsup.env import S40YowsupEnv
from yowsup.stacks import YowStack
from yowsup.common import YowConstants
from yowsup.layers import YowLayerEvent, YowParallelLayer
from yowsup.layers.auth import AuthError
from yowsup.stacks import YowStack
from yowsup.stacks import YowStackBuilder
from yowsup.common import YowConstants
# Layers
from yowsup.layers.axolotl import AxolotlSendLayer, AxolotlControlLayer, AxolotlReceivelayer
from yowsup.layers.auth import YowCryptLayer, YowAuthenticationProtocolLayer
from yowsup.layers.coder import YowCoderLayer
from yowsup.layers.logger import YowLoggerLayer
from yowsup.layers.network import YowNetworkLayer
from yowsup.layers.protocol_messages import YowMessagesProtocolLayer
from yowsup.layers.stanzaregulator import YowStanzaRegulator
from yowsup.layers.protocol_media import YowMediaProtocolLayer
from yowsup.layers.protocol_acks import YowAckProtocolLayer
from yowsup.layers.protocol_receipts import YowReceiptProtocolLayer
from yowsup.layers.protocol_groups import YowGroupsProtocolLayer
from yowsup.layers.protocol_presence import YowPresenceProtocolLayer
from yowsup.layers.protocol_ib import YowIbProtocolLayer
from yowsup.layers.protocol_notifications import YowNotificationsProtocolLayer
from yowsup.layers.protocol_iq import YowIqProtocolLayer
from yowsup.layers.protocol_contacts import YowContactsIqProtocolLayer
from yowsup.layers.protocol_chatstate import YowChatstateProtocolLayer
from yowsup.layers.protocol_privacy import YowPrivacyProtocolLayer
from yowsup.layers.protocol_profiles import YowProfilesProtocolLayer
from yowsup.layers.protocol_calls import YowCallsProtocolLayer
# ProtocolEntities
from yowsup.layers.protocol_acks.protocolentities import *
from yowsup.layers.protocol_chatstate.protocolentities import *
from yowsup.layers.protocol_contacts.protocolentities import *
from yowsup.layers.protocol_groups.protocolentities import *
from yowsup.layers.protocol_media.protocolentities import *
from yowsup.layers.protocol_notifications.protocolentities import *
from yowsup.layers.protocol_messages.protocolentities import *
from yowsup.layers.protocol_presence.protocolentities import *
from yowsup.layers.protocol_profiles.protocolentities import *
from yowsup.layers.protocol_privacy.protocolentities import *
from yowsup.layers.protocol_receipts.protocolentities import *
from yowsup.layers.protocol_iq.protocolentities import *
from yowsup.layers.protocol_media.mediauploader import MediaUploader
from yowsup.layers.protocol_media.mediadownloader import MediaDownloader
# Registration
from yowsup.registration import WACodeRequest
from yowsup.registration import WARegRequest
from functools import partial
class YowsupApp(object):
def __init__(self):
env.CURRENT_ENV = env.AndroidYowsupEnv()
layers = (YowsupAppLayer,
YowParallelLayer((YowAuthenticationProtocolLayer,
YowMessagesProtocolLayer,
YowReceiptProtocolLayer,
YowAckProtocolLayer,
YowMediaProtocolLayer,
YowIbProtocolLayer,
YowIqProtocolLayer,
YowNotificationsProtocolLayer,
YowContactsIqProtocolLayer,
YowChatstateProtocolLayer,
YowCallsProtocolLayer,
YowPrivacyProtocolLayer,
YowProfilesProtocolLayer,
YowGroupsProtocolLayer,
YowPresenceProtocolLayer)),
AxolotlControlLayer,
YowParallelLayer((AxolotlSendLayer, AxolotlReceivelayer)),
YowCoderLayer,
YowCryptLayer,
YowStanzaRegulator,
YowNetworkLayer
)
self.logger = logging.getLogger(self.__class__.__name__)
stackBuilder = YowStackBuilder()
self.stack = stackBuilder \
.pushDefaultLayers(True) \
.push(YowsupAppLayer) \
.build()
self.stack.broadcastEvent(
YowLayerEvent(YowsupAppLayer.EVENT_START, caller = self)
)
def login(self, username, password):
"""Login to yowsup
Should result in onAuthSuccess or onAuthFailure to be called.
Args:
- username: (str) username in the form of 1239482382 (country code
and cellphone number)
- password: (str) base64 encoded password
"""
self.stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS,
(username, password))
# self.stack.setProp(YowIqProtocolLayer.PROP_PING_INTERVAL, 5)
try:
self.stack.broadcastEvent(
YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT))
except TypeError as e: # Occurs when password is not correctly formated
self.onAuthFailure('password not base64 encoded')
# try:
# self.stack.loop(timeout=0.5, discrete=0.5)
# except AuthError as e: # For some reason Yowsup throws an exception
# self.onAuthFailure("%s" % e)
def logout(self):
"""
Logout from whatsapp
"""
self.stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_DISCONNECT))
def sendReceipt(self, _id, _from, read, participant):
"""
Send a receipt (delivered: double-tick, read: blue-ticks)
Args:
- _id: id of message received
- _from: jid of person who sent the message
- read: ('read' or None) None is just delivered, 'read' is read
- participant
"""
self.logger.debug(u'Sending receipt to whatsapp: %s', [_id, _from, read, participant])
receipt = OutgoingReceiptProtocolEntity(_id, _from, read, participant)
self.sendEntity(receipt)
def downloadMedia(self, url, onSuccess = None, onFailure = None):
downloader = MediaDownloader(onSuccess, onFailure)
downloader.download(url)
def sendTextMessage(self, to, message):
"""
Sends a text message
Args:
- to: (xxxxxxxxxx@s.whatsapp.net) who to send the message to
- message: (str) the body of the message
"""
messageEntity = TextMessageProtocolEntity(message.encode('utf-8'), to = to)
self.sendEntity(messageEntity)
return messageEntity.getId()
def sendLocation(self, to, latitude, longitude):
messageEntity = LocationMediaMessageProtocolEntity(latitude,longitude, None, None, "raw", to = to)
self.sendEntity(messageEntity)
return messageEntity.getId()
def sendImage(self, jid, path, caption = None, onSuccess = None, onFailure = None):
entity = RequestUploadIqProtocolEntity(RequestUploadIqProtocolEntity.MEDIA_TYPE_IMAGE, filePath=path)
successFn = lambda successEntity, originalEntity: self.onRequestUploadResult(jid, path, successEntity, originalEntity, caption, onSuccess, onFailure)
errorFn = lambda errorEntity, originalEntity: self.onRequestUploadError(jid, path, errorEntity, originalEntity)
self.sendIq(entity, successFn, errorFn)
def onRequestUploadResult(self, jid, filePath, resultRequestUploadIqProtocolEntity, requestUploadIqProtocolEntity, caption = None, onSuccess=None, onFailure=None):
if requestUploadIqProtocolEntity.mediaType == RequestUploadIqProtocolEntity.MEDIA_TYPE_AUDIO:
doSendFn = self.doSendAudio
else:
doSendFn = self.doSendImage
if resultRequestUploadIqProtocolEntity.isDuplicate():
doSendFn(filePath, resultRequestUploadIqProtocolEntity.getUrl(), jid,
resultRequestUploadIqProtocolEntity.getIp(), caption, onSuccess, onFailure)
else:
successFn = lambda filePath, jid, url: doSendFn(filePath, url.encode('ascii','ignore'), jid, resultRequestUploadIqProtocolEntity.getIp(), caption, onSuccess, onFailure)
ownNumber = self.stack.getLayerInterface(YowAuthenticationProtocolLayer).getUsername(full=False)
mediaUploader = MediaUploader(jid, ownNumber, filePath,
resultRequestUploadIqProtocolEntity.getUrl(),
resultRequestUploadIqProtocolEntity.getResumeOffset(),
successFn, self.onUploadError, self.onUploadProgress, async=False)
mediaUploader.start()
def onRequestUploadError(self, jid, path, errorRequestUploadIqProtocolEntity, requestUploadIqProtocolEntity):
self.logger.error("Request upload for file %s for %s failed" % (path, jid))
def onUploadError(self, filePath, jid, url):
self.logger.error("Upload file %s to %s for %s failed!" % (filePath, url, jid))
def onUploadProgress(self, filePath, jid, url, progress):
self.logger.info("%s => %s, %d%% \r" % (os.path.basename(filePath), jid, progress))
pass
def doSendImage(self, filePath, url, to, ip = None, caption = None, onSuccess = None, onFailure = None):
entity = ImageDownloadableMediaMessageProtocolEntity.fromFilePath(filePath, url, ip, to, caption = caption)
self.sendEntity(entity)
#self.msgIDs[entity.getId()] = MsgIDs(self.imgMsgId, entity.getId())
if onSuccess is not None:
onSuccess(entity.getId())
return entity.getId()
def doSendAudio(self, filePath, url, to, ip = None, caption = None, onSuccess = None, onFailure = None):
entity = AudioDownloadableMediaMessageProtocolEntity.fromFilePath(filePath, url, ip, to)
self.sendEntity(entity)
#self.msgIDs[entity.getId()] = MsgIDs(self.imgMsgId, entity.getId())
if onSuccess is not None:
onSuccess(entity.getId())
return entity.getId()
def sendPresence(self, available):
"""
Send presence to whatsapp
Args:
- available: (boolean) True if available false otherwise
"""
if available:
self.sendEntity(AvailablePresenceProtocolEntity())
else:
self.sendEntity(UnavailablePresenceProtocolEntity())
def subscribePresence(self, phone_number):
"""
Subscribe to presence updates from phone_number
Args:
- phone_number: (str) The cellphone number of the person to
subscribe to
"""
self.logger.debug("Subscribing to Presence updates from %s" % phone_number)
jid = phone_number + '@s.whatsapp.net'
entity = SubscribePresenceProtocolEntity(jid)
self.sendEntity(entity)
def unsubscribePresence(self, phone_number):
"""
Unsubscribe to presence updates from phone_number
Args:
- phone_number: (str) The cellphone number of the person to
unsubscribe from
"""
jid = phone_number + '@s.whatsapp.net'
entity = UnsubscribePresenceProtocolEntity(jid)
self.sendEntity(entity)
def leaveGroup(self, group):
"""
Permanently leave a WhatsApp group
Args:
- group: (str) the group id (e.g. 27831788123-144024456)
"""
entity = LeaveGroupsIqProtocolEntity([group + '@g.us'])
self.sendEntity(entity)
def setStatus(self, statusText):
"""
Send status to whatsapp
Args:
- statusTest: (str) Your whatsapp status
"""
iq = SetStatusIqProtocolEntity(statusText)
self.sendIq(iq)
def setProfilePicture(self, previewPicture, fullPicture = None):
"""
Requests profile picture of whatsapp user
Args:
- previewPicture: (bytes) The preview picture
- fullPicture: (bytes) The full profile picture
"""
if fullPicture == None:
fullPicture = previewPicture
ownJid = self.stack.getLayerInterface(YowAuthenticationProtocolLayer).getUsername(full = True)
iq = SetPictureIqProtocolEntity(ownJid, previewPicture, fullPicture)
self.sendIq(iq)
def sendTyping(self, phoneNumber, typing):
"""
Notify buddy using phoneNumber that you are typing to him
Args:
- phoneNumber: (str) cellphone number of the buddy you are typing to.
- typing: (bool) True if you are typing, False if you are not
"""
jid = phoneNumber + '@s.whatsapp.net'
if typing:
state = OutgoingChatstateProtocolEntity(
ChatstateProtocolEntity.STATE_TYPING, jid
)
else:
state = OutgoingChatstateProtocolEntity(
ChatstateProtocolEntity.STATE_PAUSED, jid
)
self.sendEntity(state)
def sendSync(self, contacts, delta = False, interactive = True, success = None, failure = None):
"""
You need to sync new contacts before you interact with
them, failure to do so could result in a temporary ban.
Args:
- contacts: ([str]) a list of phone numbers of the
contacts you wish to sync
- delta: (bool; default: False) If true only send new
contacts to sync, if false you should send your full
contact list.
- interactive: (bool; default: True) Set to false if you are
sure this is the first time registering
- success: (func) - Callback; Takes three arguments: existing numbers,
non-existing numbers, invalid numbers.
"""
mode = GetSyncIqProtocolEntity.MODE_DELTA if delta else GetSyncIqProtocolEntity.MODE_FULL
context = GetSyncIqProtocolEntity.CONTEXT_INTERACTIVE if interactive else GetSyncIqProtocolEntity.CONTEXT_REGISTRATION
# International contacts must be preceded by a plus. Other numbers are
# considered local.
contacts = ['+' + c for c in contacts]
iq = GetSyncIqProtocolEntity(contacts, mode, context)
def onSuccess(response, request):
# Remove leading plus
if success is not None:
existing = [s[1:] for s in response.inNumbers.keys()]
nonexisting = [s[1:] for s in response.outNumbers.keys()]
invalid = [s[1:] for s in response.invalidNumbers]
success(existing, nonexisting, invalid)
self.sendIq(iq, onSuccess = onSuccess, onError = failure)
def requestClientConfig(self, success = None, failure = None):
"""I'm not sure what this does, but it might be required on first login."""
iq = PushIqProtocolEntity()
self.sendIq(iq, onSuccess = success, onError = failure)
def requestPrivacyList(self, success = None, failure = None):
"""I'm not sure what this does, but it might be required on first login."""
iq = PrivacyListIqProtocolEntity()
self.sendIq(iq, onSuccess = success, onError = failure)
def requestServerProperties(self, success = None, failure = None):
"""I'm not sure what this does, but it might be required on first login."""
iq = PropsIqProtocolEntity()
self.sendIq(iq, onSuccess = success, onError = failure)
def requestStatuses(self, contacts, success = None, failure = None):
"""
Request the statuses of a number of users.
Args:
- contacts: ([str]) the phone numbers of users whose statuses you
wish to request
- success: (func) called when request is successful
- failure: (func) called when request has failed
"""
iq = GetStatusesIqProtocolEntity([c + '@s.whatsapp.net' for c in contacts])
def onSuccess(response, request):
if success is not None:
self.logger.debug("Received Statuses %s" % response)
s = {}
for k, v in response.statuses.iteritems():
s[k.split('@')[0]] = v
success(s)
self.sendIq(iq, onSuccess = onSuccess, onError = failure)
def requestLastSeen(self, phoneNumber, success = None, failure = None):
"""
Requests when user was last seen.
Args:
- phone_number: (str) the phone number of the user
- success: (func) called when request is successfully processed.
The first argument is the number, second argument is the seconds
since last seen.
- failure: (func) called when request has failed
"""
iq = LastseenIqProtocolEntity(phoneNumber + '@s.whatsapp.net')
self.sendIq(iq, onSuccess = partial(self._lastSeenSuccess, success),
onError = failure)
def _lastSeenSuccess(self, success, response, request):
success(response._from.split('@')[0], response.seconds)
def requestProfilePicture(self, phoneNumber, onSuccess = None, onFailure = None):
"""
Requests profile picture of whatsapp user
Args:
- phoneNumber: (str) the phone number of the user
- onSuccess: (func) called when request is successfully processed.
- onFailure: (func) called when request has failed
"""
iq = GetPictureIqProtocolEntity(phoneNumber + '@s.whatsapp.net')
self.sendIq(iq, onSuccess = onSuccess, onError = onFailure)
def requestGroupsList(self, onSuccess = None, onFailure = None):
iq = ListGroupsIqProtocolEntity()
self.sendIq(iq, onSuccess = onSuccess, onError = onFailure)
def requestGroupInfo(self, group, onSuccess = None, onFailure = None):
"""
Request info on a specific group (includes participants, subject, owner etc.)
Args:
- group: (str) the group id in the form of xxxxxxxxx-xxxxxxxx
- onSuccess: (func) called when request is successfully processed.
- onFailure: (func) called when request is has failed
"""
iq = InfoGroupsIqProtocolEntity(group + '@g.us')
self.sendIq(iq, onSuccess = onSuccess, onError = onFailure)
def requestSMSCode(self, countryCode, phoneNumber):
"""
Request an sms regitration code. WARNING: this function is blocking
Args:
countryCode: The country code of the phone you wish to register
phoneNumber: phoneNumber of the phone you wish to register without
the country code.
"""
request = WACodeRequest(countryCode, phoneNumber)
return request.send()
def requestPassword(self, countryCode, phoneNumber, smsCode):
"""
Request a password. WARNING: this function is blocking
Args:
countryCode: The country code of the phone you wish to register
phoneNumber: phoneNumber of the phone you wish to register without
the country code.
smsCode: The sms code that you asked for previously
"""
smsCode = smsCode.replace('-', '')
request = WARegRequest(countryCode, phoneNumber, smsCode)
return request.send()
def onAuthSuccess(self, status, kind, creation, expiration, props, nonce, t):
"""
Called when login is successful.
Args:
- status
- kind
- creation
- expiration
- props
- nonce
- t
"""
pass
def onAuthFailure(self, reason):
"""
Called when login is a failure
Args:
- reason: (str) Reason for the login failure
"""
pass
def onReceipt(self, _id, _from, timestamp, type, participant, offline, items):
"""
Called when a receipt is received (double tick or blue tick)
Args
- _id
- _from
- timestamp
- type: Is 'read' for blue ticks and None for double-ticks
- participant: (dxxxxxxxxxx@s.whatsapp.net) delivered to or
read by this participant in group
- offline: (True, False or None)
- items
"""
pass
def onAck(self, _id,_class, _from, timestamp):
"""
Called when Ack is received
Args:
- _id
- _class: ('message', 'receipt' or something else?)
- _from
- timestamp
"""
pass
def onPresenceReceived(self, _type, name, _from, last):
"""
Called when presence (e.g. available, unavailable) is received
from whatsapp
Args:
- _type: (str) 'available' or 'unavailable'
- _name
- _from
- _last
"""
pass
def onDisconnect(self):
"""
Called when disconnected from whatsapp
"""
def onContactTyping(self, number):
"""
Called when contact starts to type
Args:
- number: (str) cellphone number of contact
"""
pass
def onContactPaused(self, number):
"""
Called when contact stops typing
Args:
- number: (str) cellphone number of contact
"""
pass
def onTextMessage(self, _id, _from, to, notify, timestamp, participant, offline, retry, body):
"""
Called when text message is received
Args:
- _id:
- _from: (str) jid of of sender
- to:
- notify: (str) human readable name of _from (e.g. John Smith)
- timestamp:
- participant: (str) jid of user who sent the message in a groupchat
- offline:
- retry:
- body: The content of the message
"""
pass
def onImage(self, entity):
"""
Called when image message is received
Args:
- entity: ImageDownloadableMediaMessageProtocolEntity
"""
pass
def onAudio(self, entity):
"""
Called when audio message is received
Args:
- entity: AudioDownloadableMediaMessageProtocolEntity
"""
pass
def onVideo(self, entity):
"""
Called when video message is received
Args:
- entity: VideoDownloadableMediaMessageProtocolEntity
"""
pass
def onLocation(self, entity):
"""
Called when location message is received
Args:
- entity: LocationMediaMessageProtocolEntity
"""
pass
def onVCard(self, _id, _from, name, card_data, to, notify, timestamp, participant):
"""
Called when VCard message is received
Args:
- _id: (str) id of entity
- _from:
- name:
- card_data:
- to:
- notify:
- timestamp:
- participant:
"""
pass
def onAddedToGroup(self, entity):
"""Called when the user has been added to a new group"""
pass
def onParticipantsAddedToGroup(self, entity):
"""Called when participants have been added to a group"""
pass
def onParticipantsRemovedFromGroup(self, group, participants):
"""Called when participants have been removed from a group
Args:
- group: (str) id of the group (e.g. 27831788123-144024456)
- participants: (list) jids of participants that are removed
"""
pass
def onSubjectChanged(self, group, subject, subjectOwner, timestamp):
"""Called when someone changes the grousp subject
Args:
- group: (str) id of the group (e.g. 27831788123-144024456)
- subject: (str) the new subject
- subjectOwner: (str) the number of the person who changed the subject
- timestamp: (str) time the subject was changed
"""
pass
def onContactStatusChanged(self, number, status):
"""Called when a contacts changes their status
Args:
number: (str) the number of the contact who changed their status
status: (str) the new status
"""
pass
def onContactPictureChanged(self, number):
"""Called when a contact changes their profile picture
Args
number: (str) the number of the contact who changed their picture
"""
pass
def onContactRemoved(self, number):
"""Called when a contact has been removed
Args:
number: (str) the number of the contact who has been removed
"""
pass
def onContactAdded(self, number, nick):
"""Called when a contact has been added
Args:
number: (str) contacts number
nick: (str) contacts nickname
"""
pass
def onContactUpdated(self, oldNumber, newNumber):
"""Called when a contact has changed their number
Args:
oldNumber: (str) the number the contact previously used
newNumber: (str) the new number of the contact
"""
pass
def sendEntity(self, entity):
"""Sends an entity down the stack (as if YowsupAppLayer called toLower)"""
self.stack.broadcastEvent(YowLayerEvent(YowsupAppLayer.TO_LOWER_EVENT,
entity = entity
))
def sendIq(self, iq, onSuccess = None, onError = None):
self.stack.broadcastEvent(
YowLayerEvent(
YowsupAppLayer.SEND_IQ,
iq = iq,
success = onSuccess,
failure = onError,
)
)
from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback
class YowsupAppLayer(YowInterfaceLayer):
EVENT_START = 'transwhat.event.YowsupAppLayer.start'
TO_LOWER_EVENT = 'transwhat.event.YowsupAppLayer.toLower'
SEND_IQ = 'transwhat.event.YowsupAppLayer.sendIq'
def onEvent(self, layerEvent):
# We cannot pass instance varaibles in through init, so we use an event
# instead
# Return False if you want the event to propogate down the stack
# return True otherwise
if layerEvent.getName() == YowsupAppLayer.EVENT_START:
self.caller = layerEvent.getArg('caller')
self.logger = logging.getLogger(self.__class__.__name__)
return True
elif layerEvent.getName() == YowNetworkLayer.EVENT_STATE_DISCONNECTED:
self.caller.onDisconnect()
return True
elif layerEvent.getName() == YowsupAppLayer.TO_LOWER_EVENT:
self.toLower(layerEvent.getArg('entity'))
return True
elif layerEvent.getName() == YowsupAppLayer.SEND_IQ:
iq = layerEvent.getArg('iq')
success = layerEvent.getArg('success')
failure = layerEvent.getArg('failure')
self._sendIq(iq, success, failure)
return True
return False
@ProtocolEntityCallback('success')
def onAuthSuccess(self, entity):
# entity is SuccessProtocolEntity
status = entity.status
kind = entity.kind
creation = entity.creation
expiration = entity.expiration
props = entity.props
nonce = entity.nonce
t = entity.t # I don't know what this is
self.caller.onAuthSuccess(status, kind, creation, expiration, props, nonce, t)
@ProtocolEntityCallback('failure')
def onAuthFailure(self, entity):
# entity is FailureProtocolEntity
reason = entity.reason
self.caller.onAuthFailure(reason)
@ProtocolEntityCallback('receipt')
def onReceipt(self, entity):
"""Sends ack automatically"""
# entity is IncomingReceiptProtocolEntity
#ack = OutgoingAckProtocolEntity(entity.getId(),
# 'receipt', entity.getType(), entity.getFrom())
self.toLower(entity.ack())
_id = entity._id
_from = entity._from
timestamp = entity.timestamp
type = entity.type
participant = entity.participant
offline = entity.offline
items = entity.items
self.caller.onReceipt(_id, _from, timestamp, type, participant, offline, items)
@ProtocolEntityCallback('ack')
def onAck(self, entity):
# entity is IncomingAckProtocolEntity
self.caller.onAck(
entity._id,
entity._class,
entity._from,
entity.timestamp
)
@ProtocolEntityCallback('notification')
def onNotification(self, entity):
"""
Sends ack automatically
"""
self.logger.debug("Received notification (%s): %s" % (type(entity), entity))
self.toLower(entity.ack())
if isinstance(entity, CreateGroupsNotificationProtocolEntity):
self.caller.onAddedToGroup(entity)
elif isinstance(entity, AddGroupsNotificationProtocolEntity):
self.caller.onParticipantsAddedToGroup(entity)
elif isinstance(entity, RemoveGroupsNotificationProtocolEntity):
self.caller.onParticipantsRemovedFromGroup(
entity.getGroupId().split('@')[0],
entity.getParticipants().keys()
)
elif isinstance(entity, SubjectGroupsNotificationProtocolEntity):
self.caller.onSubjectChanged(
entity.getGroupId().split('@')[0],
entity.getSubject(),
entity.getSubjectOwner(full=False),
entity.getSubjectTimestamp()
)
elif isinstance(entity, StatusNotificationProtocolEntity):
self.caller.onContactStatusChanged(
entity._from.split('@')[0],
entity.status
)
elif isinstance(entity, SetPictureNotificationProtocolEntity):
self.caller.onContactPictureChanged(entity.setJid.split('@')[0])
elif isinstance(entity, DeletePictureNotificationProtocolEntity):
self.caller.onContactPictureChanged(entity.deleteJid.split('@')[0])
elif isinstance(entity, RemoveContactNotificationProtocolEntity):
self.caller.onContactRemoved(entity.contactJid.split('@')[0])
elif isinstance(entity, AddContactNotificationProtocolEntity):
self.caller.onContactAdded(
entity.contactJid.split('@')[0],
entity.notify
)
elif isinstance(entity, UpdateContactNotificationProtocolEntity):
self.caller.onContactUpdated(
entity._from.split('@')[0],
entity.contactJid.split('@')[0],
)
@ProtocolEntityCallback('message')
def onMessageReceived(self, entity):
self.logger.debug("Received Message: %s" % unicode(entity))
if entity.getType() == MessageProtocolEntity.MESSAGE_TYPE_TEXT:
self.caller.onTextMessage(
entity._id,
entity._from,
entity.to,
entity.notify,
entity.timestamp,
entity.participant,
entity.offline,
entity.retry,
entity.body
)
elif entity.getType() == MessageProtocolEntity.MESSAGE_TYPE_MEDIA:
if isinstance(entity, ImageDownloadableMediaMessageProtocolEntity):
# There is just way too many fields to pass them into the
# function
self.caller.onImage(entity)
elif isinstance(entity, AudioDownloadableMediaMessageProtocolEntity):
self.caller.onAudio(entity)
elif isinstance(entity, VideoDownloadableMediaMessageProtocolEntity):
self.caller.onVideo(entity)
elif isinstance(entity, VCardMediaMessageProtocolEntity):
self.caller.onVCard(
entity._id,
entity._from,
entity.name,
entity.card_data,
entity.to,
entity.notify,
entity.timestamp,
entity.participant
)
elif isinstance(entity, LocationMediaMessageProtocolEntity):
self.caller.onLocation(entity)
@ProtocolEntityCallback('presence')
def onPresenceReceived(self, presence):
_type = presence.getType()
name = presence.getName()
_from = presence.getFrom()
last = presence.getLast()
self.caller.onPresenceReceived(_type, name, _from, last)
@ProtocolEntityCallback('chatstate')
def onChatstate(self, chatstate):
number = chatstate._from.split('@')[0]
if chatstate.getState() == ChatstateProtocolEntity.STATE_TYPING:
self.caller.onContactTyping(number)
else:
self.caller.onContactPaused(number)