Yowsup: Send presence

Created on 15 Jun 2016  路  97Comments  路  Source: tgalal/yowsup

Hello tagal, can I ask you a few examples to send the presence before the answer

taking as example /yowsup/demos/echoclient

receive the message (it's already present)
active presence
responds (it's already present)
deactivates the presence

Thanks for your project, I donated.

from yowsup.layers.interface                           import YowInterfaceLayer, ProtocolEntityCallback

class EchoLayer(YowInterfaceLayer):

    @ProtocolEntityCallback("message")
    def onMessage(self, messageProtocolEntity):

        if messageProtocolEntity.getType() == 'text':
            self.onTextMessage(messageProtocolEntity)
        elif messageProtocolEntity.getType() == 'media':
            self.onMediaMessage(messageProtocolEntity)

        self.toLower(messageProtocolEntity.forward(messageProtocolEntity.getFrom()))
        self.toLower(messageProtocolEntity.ack())
        self.toLower(messageProtocolEntity.ack(True))


    @ProtocolEntityCallback("receipt")
    def onReceipt(self, entity):
        self.toLower(entity.ack())

    def onTextMessage(self,messageProtocolEntity):
        # just print info
        print("Echoing %s to %s" % (messageProtocolEntity.getBody(), messageProtocolEntity.getFrom(False)))

    def onMediaMessage(self, messageProtocolEntity):
        # just print info
        if messageProtocolEntity.getMediaType() == "image":
            print("Echoing image %s to %s" % (messageProtocolEntity.url, messageProtocolEntity.getFrom(False)))

        elif messageProtocolEntity.getMediaType() == "location":
            print("Echoing location (%s, %s) to %s" % (messageProtocolEntity.getLatitude(), messageProtocolEntity.getLongitude(), messageProtocolEntity.getFrom(False)))

        elif messageProtocolEntity.getMediaType() == "vcard":
            print("Echoing vcard (%s, %s) to %s" % (messageProtocolEntity.getName(), messageProtocolEntity.getCardData(), messageProtocolEntity.getFrom(False)))

run.py

from yowsup.stacks                             import YowStackBuilder
from yowsup.layers.protocol_messages           import YowMessagesProtocolLayer
from yowsup.layers.stanzaregulator             import YowStanzaRegulator
from yowsup.layers.protocol_receipts           import YowReceiptProtocolLayer
from yowsup.layers.protocol_acks               import YowAckProtocolLayer
from yowsup.stacks                             import YowStack
from yowsup.common                             import YowConstants
from yowsup.layers                             import YowLayerEvent
from yowsup                                    import env
from layer                                     import EchoLayer
from yowsup.layers.auth                        import YowCryptLayer, YowAuthenticationProtocolLayer, AuthError
from yowsup.layers.coder                       import YowCoderLayer
from yowsup.layers.network                     import YowNetworkLayer
from yowsup.layers.protocol_messages           import YowMessagesProtocolLayer
from yowsup.layers.stanzaregulator             import YowStanzaRegulator
from yowsup.layers.protocol_presence           import YowPresenceProtocolLayer
from yowsup.env                                import YowsupEnv

#Deccomentare per log
#import logging
#logging.basicConfig(level=logging.DEBUG)

CREDENTIALS = ("**************************", "**************************") #replace with your phone and password

if __name__==  "__main__":
    stackBuilder = YowStackBuilder()

    stack = stackBuilder\
        .pushDefaultLayers(True)\
        .push(EchoLayer)\
        .build()

    stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, CREDENTIALS)       #setting credentials
    stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT))          #sending the connect signal
    stack.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[0])           #whatsapp server address
    stack.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN)
    stack.setProp(YowCoderLayer.PROP_RESOURCE, YowsupEnv.getCurrent().getResource())  #info about us as WhatsApp client

    stack.loop( timeout = 0.5, discrete = 0.5 )                                       #this is the program mainloop

Most helpful comment

I clean and perfected the .py

The scripts allow this

Connecting to WhatsApp
WhatsApp listening
Receive a message (case sensitive disable - THANKS @sowerkoku))
Check that the number of the sender is enabled, if it is not enabled sends bad message
If the number is enabled it performs what is asked
You can add functions, now I added a basic:

Hi
Temperature
Restart
On GPIO14
Off GPIO14

I included all the features. (PRESENCE, THANKS @sowerkoku)

Set received (double v)

Set name presence

Set online

Set read (double v blue)

Set is writing

Set no is writing

Send the answer

Set offline

I tried to insert comments to understand what you are doing

v01
Frist release
v02
Corrected Unavailable Presence in the event of a reboot command
v03
Add Name presence (THANKS @sowerkoku)
v04
Added log unauthorized phone number
Is logged: Sender, Number sender, Message text received
v05
Add correction if you receive an audio file and yowsup crashes (THANKS @jlguardi)
Add to send pictures (THANKS @sowerkoku)
Add the management of received images (THANKS @sowerkoku)
Add the image save (beta) (THANKS @sowerkoku)
v06
Add to send geolocation
v07
Little bug fix
v08
Ok the image save (enc) "Now works" (THANKS @sowerkoku)
v09
Add automatic reconnection (THANKS @shekar3110a)
Add the ability to send messages directly from the browser via the address bar, read the readme inside the zip file (THANKS @shekar3110a)
v10
Code optimization
Add the ability to send image directly from the browser via the address bar, read the readme inside the zip file (THANKS @langioletto)
Add the ability to run scripts directly from the browser via the address bar, read the readme inside the zip file (THANKS @langioletto)

#Download HERE v04#

#Download HERE v05#

#Download HERE v06#

#Download HERE v07#

#Download HERE v08#

#Download HERE v09#

#Download HERE v10#

All 97 comments

@langioletto
very easy:
self.toLower(AvailablePresenceProtocolEntity())

example:

self.toLower(messageProtocolEntity.ack())
self.toLower(AvailablePresenceProtocolEntity())
self.toLower(messageProtocolEntity.ack(True))
self.toLower(OutgoingChatstateProtocolEntity(OutgoingChatstateProtocolEntity.STATE_TYPING, Jid.normalize(messageProtocolEntity.getFrom(False)) ))
self.toLower(OutgoingChatstateProtocolEntity(OutgoingChatstateProtocolEntity.STATE_PAUSED, Jid.normalize(messageProtocolEntity.getFrom(False)) ))
self.toLower(messageProtocolEntity.forward(messageProtocolEntity.getFrom()))
self.toLower(UnavailablePresenceProtocolEntity())

Very thanks, perfect!!

You're very kind..

Another question, how can I do to disable the case sensitive in the body of an incoming message?

Example: lower

@langioletto
I do not quite understand the question. my English is not good.

Italiano

Molte grazie, perfetto!!
Tu sei molto gentile

Un'altra domanda, come posso fare per disattivare il case sensitive nel body di un messaggio che mando io e che riceve yowsup?

Esempio: lower

Generalmente uso questo comando: msg.text:lower, ma in py 茅 diverso.

Deutsch:

Viel Dank, perfekt !!
Sie sind sehr freundlich ..
Eine andere Frage, wie kann ich tun, um die Gro脽- und Kleinschreibung in den K枚rper einer Nachricht zu deaktivieren, die ich das Senden und Empfangen yowsup?

Beispiel: Unter

Normalerweise verwenden Sie diesen Befehl: msg.text:lower, aber py ist anders.

sorry, I speak Spanish.
I understand all that. but the question can not understand.

how can I do to disable the case sensitive in the body of an incoming message?

writing this, I begin to understand.
you have problems with case sensitive?

hola != Hola != HOLA !=hOLA

tell me what you need to do and help

cadena = "Hola Mundo"
print cadena.lower()
hola mundo

cadena = "Hola Mundo"
print cadena.upper()
HOLA MUNDO

according to your example:

msg = messageProtocolEntity.getBody().lower()
                if messageProtocolEntity.getFrom(False) in ap:
                        if  'hi' in msg:  #you can type: "hi, how are you?"
                                antwort = 'Hello!'
                        elif 'temperature' == msg:  #only allows "temperature" and not "which is the temperature?"
                                 t=float(subprocess.check_output(["/opt/vc/bin/vcgencmd measure_temp | cut -c6-9"], shell=True)[:-1])
                                 ts=str(t)
                                 antwort = 'My temperature is  '+ts+' 掳C.'
---

or

msg = messageProtocolEntity.getBody()
                if messageProtocolEntity.getFrom(False) in ap:
                        if msg in ["Hi","hi","hI","HI"]:
                                antwort = 'Hello!'
                        elif msg in ["Temperature","temperature","TEMPERATURE","tEMPERATURE"]:
                                 t=float(subprocess.check_output(["/opt/vc/bin/vcgencmd measure_temp | cut -c6-9"], shell=True)[:-1])
                                 ts=str(t)
                                 antwort = 'My temperature is  '+ts+' 掳C.'
---

Yes

line of the layer.py

namemitt = messageProtocolEntity.getNotify()
message = messageProtocolEntity.getBody()
recipient = messageProtocolEntity.getFrom()
textmsg = TextMessageProtocolEntity

        if message == 'Hola':
            answer = "Hola"+namemitt+" " 
            self.toLower(textmsg(answer, to = recipient ))

        else:
            answer = "Sorry"+namemitt+", I do not understand" 
            self.toLower(textmsg(answer, to = recipient))
            print answer

If I write Hola he answers Hola

If I write hola he answers Sorry......

I thought about it, but it does not work

        if message.lower() == 'Hola':
            answer = "Hola"+namemitt+" " 
            self.toLower(textmsg(answer, to = recipient ))

this works perfect:

# -*- coding: iso-8859-15
import sys

msg1 = sys.argv[1].upper()
msg2 = sys.argv[1].lower()

print msg1
print msg2

your mistake here is the string:

hola != Hola

        if message.lower() == 'hola':
            answer = "Hola"+namemitt+" " 
            self.toLower(textmsg(answer, to = recipient ))

Perfect!!!

This work very well

Send HOLA hola Hola, always it works

message = messageProtocolEntity.getBody().lower()

   if message == 'hola':
        answer = "Hola"+namemitt+" " 
        self.toLower(textmsg(answer, to = recipient ))

Very very thanks!!

I clean and perfected the .py

The scripts allow this

Connecting to WhatsApp
WhatsApp listening
Receive a message (case sensitive disable - THANKS @sowerkoku))
Check that the number of the sender is enabled, if it is not enabled sends bad message
If the number is enabled it performs what is asked
You can add functions, now I added a basic:

Hi
Temperature
Restart
On GPIO14
Off GPIO14

I included all the features. (PRESENCE, THANKS @sowerkoku)

Set received (double v)

Set name presence

Set online

Set read (double v blue)

Set is writing

Set no is writing

Send the answer

Set offline

I tried to insert comments to understand what you are doing

v01
Frist release
v02
Corrected Unavailable Presence in the event of a reboot command
v03
Add Name presence (THANKS @sowerkoku)
v04
Added log unauthorized phone number
Is logged: Sender, Number sender, Message text received
v05
Add correction if you receive an audio file and yowsup crashes (THANKS @jlguardi)
Add to send pictures (THANKS @sowerkoku)
Add the management of received images (THANKS @sowerkoku)
Add the image save (beta) (THANKS @sowerkoku)
v06
Add to send geolocation
v07
Little bug fix
v08
Ok the image save (enc) "Now works" (THANKS @sowerkoku)
v09
Add automatic reconnection (THANKS @shekar3110a)
Add the ability to send messages directly from the browser via the address bar, read the readme inside the zip file (THANKS @shekar3110a)
v10
Code optimization
Add the ability to send image directly from the browser via the address bar, read the readme inside the zip file (THANKS @langioletto)
Add the ability to run scripts directly from the browser via the address bar, read the readme inside the zip file (THANKS @langioletto)

#Download HERE v04#

#Download HERE v05#

#Download HERE v06#

#Download HERE v07#

#Download HERE v08#

#Download HERE v09#

#Download HERE v10#

Since you're very good :+1: :100:

if when I send the answer you wanted to send a sound file instead of a text

example

  if message == 'hola':
        answer = "Hola"+namemitt+" " 
        self.toLower(textmsg(answer, to = recipient ))
        /audio         send           <number> <path>               Send audio file

I'd also like to know how to send the presence of the name :)

self.toLower(AvailablePresenceProtocolEntity())
/presence      name           <name>                        Set presence name

@langioletto

the presence is simple, but to send sound files is somewhat more complex.
I do not have a PC near , even within 2hrs .

from yowsup.layers.protocol_presence.protocolentities import PresenceProtocolEntity

/presence      name           <name>

name = "string"
self.toLower(PresenceProtocolEntity(name = name))
or 
self.toLower(PresenceProtocolEntity(name = "string"))

Thanks, do not worry!!

I added the string

驴C贸mo se define el nombre? :)

pasar un buen descanso :+1:

File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/interface/interface.py", line 80, in receive self.entity_callbacks[entityType](entity) File "/root/.yowsup/layer.py", line 43, in onMessage self.toLower(PresenceProtocolEntity(name = name)) NameError: global name 'name' is not defined

send an audio file I can not even.

1656

Ok, @sowerkoku I am reading "layer.py" in
/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/demos/cli/

And I begin to understand, thank you.

You think I should I send other things in a message?

Set received (double v)

Set name presence

Set available presence

Set read (double v blue)

Set is writing

Set no is writing

Send the answer

Set unavailable presence

ib "CleanIqProtocolEntity" ??

Unsubscribe Presence or Subscribe Presence??
This is to hide the presence from contacts "privacy?

Very thanks

set Name presence -> I occupied only once to name

Available #set presence -> I use it after every #set received (double v)

I do not understand the question, but I will answer.

ib "CleanIqProtocolEntity" ??

this should clear the conversation: (I'm not entirely sure)
self.toLower(CleanIqProtocolEntity("groups", YowConstants.DOMAIN))

"Presence Unsubscribe" or "Presence Subscribe" ??
ok:
Unsubscribe Presence: I "available presence" above. I am for all numbers online. then active "Presence Unsubscribe (number)". then only this number see me offline.

Subscribe Presence: this makes contact only see me online

Ok, perfect!! :+1:

@sowerkoku

Do you think that you can send a message from cmd sending also presence of the name?

Changing the py off yowsup but I do not know what to change

python yowsup-cli demos -c /root/.yowsup/config -s 441234567890 "Hola"

It must be added the presence name that now is not sent

Very thanks!!

Done, I have changed the "layer.py" in /usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/demos/sendclient

I add:

from yowsup.layers.protocol_presence.protocolentities import PresenceProtocolEntity #Name presence

name = "MyName"

and modified this by so

@ProtocolEntityCallback("success")
def onSuccess(self, successProtocolEntity):
    self.lock.acquire()
    for target in self.getProp(self.__class__.PROP_MESSAGES, []):
        #getProp() is trying to retreive the list of (jid, message) tuples, if none exist, use the default []
        phone, message = target
        messageEntity = TextMessageProtocolEntity(message, to = Jid.normalize(phone))
        #append the id of message to ackQueue list
        #which the id of message will be deleted when ack is received.
        self.ackQueue.append(messageEntity.getId())
        self.toLower(messageEntity)
    self.lock.release()

To

@ProtocolEntityCallback("success")
def onSuccess(self, successProtocolEntity):
    self.lock.acquire()
    for target in self.getProp(self.__class__.PROP_MESSAGES, []):
        #getProp() is trying to retreive the list of (jid, message) tuples, if none exist, use the default []
        phone, message = target
        messageEntity = TextMessageProtocolEntity(message, to = Jid.normalize(phone))
        self.toLower(PresenceProtocolEntity(name = name))
        #append the id of message to ackQueue list
        #which the id of message will be deleted when ack is received.
        self.ackQueue.append(messageEntity.getId())
        self.toLower(messageEntity)
    self.lock.release()

self.toLower(PresenceProtocolEntity(name = name))

But it would be nice to change yowsup-cli to send the name via command line ex:

python yowsup-cli demos -c /root/.yowsup/config -s 441234567890 "Hola" -n "MyName"

@langioletto
ok, having a time'll see some modification to cli. ;)

I think that send client is ok with current implementation. Nick name is just a "configuration" of the account and shouldn't be modified on each message. Do you agree?

@sowerkoku @jlguardi

My change is too rough, the Nickname is how the subject at first glance when you receive a message

python yowsup-cli demos -c /root/.yowsup/config -s 441234567890 "Hola" -n "My Love"

python yowsup-cli demos -c /root/.yowsup/config -s 441234567890 "Hola" -n "My friend"

python yowsup-cli demos -c /root/.yowsup/config -s 441234567890 "Hola" -n "Happy birthday"

ecc ecc..

It 'very convenient if you use the command line, so the change is much more flexible

But the parameter would not put obligatory

python yowsup-cli demos -c /root/.yowsup/config -s 441234567890 "Hola"
or
python yowsup-cli demos -c /root/.yowsup/config -s 441234567890 "Hola" -n "My Love"

os and you prefer you can add fixed in the config file

cc=44 #if not specified it will be autodetected
name=MyName #if not specified It is not sent
phone=xxxxxxxxxxxxxxxxxxxxxxx
password=xxxxxxxxxxxxxxxxxxxxxxx

Really thank you for your interest :+1: :100:

@jlguardi is true, but what makes @langioletto is a personal script. It does not seek to modify the master of "yowsup".

I think it would be more useful an amendment to cli to send audio or video image. what has already been done in a particular way by a few. but it is not really important.
there are many out here who have created bots, and more than one similar to that of "@langioletto" for its simplicity.

@jlguardi without going too far, I myself have my own modifications to cli or yowsup code. well as you brought your own branch. yowsup helps many people, and that makes me happy ;)

the work of @langioletto directly benefits those who are not able to create their own bot.

@sowerkoku I'm so sorry if didn't explained well.
I wanted to say that I think that it isn't a good feature for send cli in master. Obviously every on can propose improvements/features or fork the project. I was just sa my opinion and also showin th risk of change the nickname too many times.
Anyway, I think this kind of issues helps to users and developers to improve the project.

Another question for you experts

I added a filter to number

allowedPersons=['xxxxxxxxxxxxx','xxxxxxxxxxxxx'] #Filter the senders numbers
ap = set(allowedPersons)

    if messageProtocolEntity.getFrom(False) in ap:

    else:
        answer = "Salve "+namemitt+", mi dispiace, non vorrei essere scortese, ma adesso non posso chattare con te."

If I instead want to do the opposite,

denyPersons=['xxxxxxxxxxxxx','xxxxxxxxxxxxx'] #Filter the senders numbers
denyp = set(denyPersons)

    if messageProtocolEntity.getFrom(False) in denyp:

How do I change the if messageProtocolEntity.getFrom(False) in denyp: , so why not work

Very thanks!!

That should work fine, except for the "," at the end of the list or trupa

@langioletto, one more thing. I'm no expert. I'm here to help if I can.

He apologizes, copy and paste error.

This works with numbers inside allowedPersons

But I want the opposite

Denying the numbers in that list "denyPersons"

if messageProtocolEntity.getFrom(False) in denyp:

This should be changed, so it is not sufficient to deny

you can not deny that a number send a message .
but can a message or other action

if num in denyp:
 send "unautorized"
else:
 all

or

if num not in denyp:
    all
else:
    send "unautorized"

or

if num not in denyp:
    all
else:
    self.toLower(messageProtocolEntity.ack())
    self.toLower(messageProtocolEntity.ack(True))

Hello,

I tried to use your code with a group chat.
But it crash the programm.

But the answer wich the programm wants to send is written in the terminal.
After that message it crashed.

Traceback (most recent call last):
File "run.py", line 30, in
stack.loop( timeout = 0.5, discrete = 0.5 ) #this is the program mainloop
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/stacks/yowstack.py", line 188, in loop
asyncore.loop(_args, *_kwargs)
File "/usr/lib/python2.7/asyncore.py", line 216, in loop
poll_fun(timeout, map)
File "/usr/lib/python2.7/asyncore.py", line 156, in poll
read(obj)
File "/usr/lib/python2.7/asyncore.py", line 87, in read
obj.handle_error()
File "/usr/lib/python2.7/asyncore.py", line 83, in read
obj.handle_read_event()
File "/usr/lib/python2.7/asyncore.py", line 449, in handle_read_event
self.handle_read()
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/network/layer.py", line 102, in handle_read
self.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/network/layer.py", line 110, in receive
self.toUpper(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/init.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/stanzaregulator/layer.py", line 29, in receive
self.processReceived()
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/stanzaregulator/layer.py", line 49, in processReceived
self.toUpper(oneMessageData)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/auth/layer_crypt.py", line 65, in receive
self.toUpper(payload)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/coder/layer.py", line 35, in receive
self.toUpper(node)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/logger/layer.py", line 14, in receive
self.toUpper(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/axolotl/layer_control.py", line 44, in receive
self.toUpper(protocolTreeNode)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 189, in receive
s.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/axolotl/layer_send.py", line 64, in receive
if not self.processIqRegistry(protocolTreeNode):
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/init.py", line 156, in processIqRegistry
successClbk(protocolTreeNode, originalIq)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/axolotl/layer_send.py", line 215, in sendToGroup
jids.remove(ownJid)
ValueError: list.remove(x): x not in list

It worked fine when I used the demo client to send a message to the group.
Did i have to add something?

Hello @Kaoala.

ValueError: list.remove(x): x not in list --> the participant of group fails

if messageProtocolEntity.getFrom(False) in ap: --> this does not work for groups

modifies the line with this:

sender = messageProtocolEntity.getFrom(False) if not messageProtocolEntity.isGroupMessage() else messageProtocolEntity.getParticipant(False)
if sender in ap:
---

and add:
from yowsup.layers.auth import YowAuthenticationProtocolLayer

Hello @sowerkoku
Thank you for your answer.
Is here a formating error?
I modified the code:
if messageProtocolEntity.getFrom(False) in ap:
to the following:
sender = messageProtocolEntity.getFrom(False) if not messageProtocolEntity.isGroupMessage() else messageProtocolEntity.getParticipant(False) (Everything in one row?)
if sender in ap:

But I gote the same error:

Traceback (most recent call last):
File "run.py", line 30, in
stack.loop( timeout = 0.5, discrete = 0.5 ) #this is the program mainloop
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/stacks/yowstack.py", line 188, in loop
asyncore.loop(_args, *_kwargs)
File "/usr/lib/python2.7/asyncore.py", line 216, in loop
poll_fun(timeout, map)
File "/usr/lib/python2.7/asyncore.py", line 156, in poll
read(obj)
File "/usr/lib/python2.7/asyncore.py", line 87, in read
obj.handle_error()
File "/usr/lib/python2.7/asyncore.py", line 83, in read
obj.handle_read_event()
File "/usr/lib/python2.7/asyncore.py", line 449, in handle_read_event
self.handle_read()
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/network/layer.py", line 102, in handle_read
self.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/network/layer.py", line 110, in receive
self.toUpper(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/init.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/stanzaregulator/layer.py", line 29, in receive
self.processReceived()
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/stanzaregulator/layer.py", line 49, in processReceived
self.toUpper(oneMessageData)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/auth/layer_crypt.py", line 65, in receive
self.toUpper(payload)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/coder/layer.py", line 35, in receive
self.toUpper(node)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/logger/layer.py", line 14, in receive
self.toUpper(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/axolotl/layer_control.py", line 44, in receive
self.toUpper(protocolTreeNode)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 189, in receive
s.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/axolotl/layer_send.py", line 64, in receive
if not self.processIqRegistry(protocolTreeNode):
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/init.py", line 156, in processIqRegistry
successClbk(protocolTreeNode, originalIq)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/axolotl/layer_send.py", line 215, in sendToGroup
jids.remove(ownJid)
ValueError: list.remove(x): x not in list

hello @Kaoala

yes, all in a line.
so I see another change is needed in the delivery.

add to layer.py:
from yowsup.layers.auth import YowAuthenticationProtocolLayer

Hello @sowerkoku
thank you for your answer!
I added

from yowsup.layers.auth import YowAuthenticationProtocolLayer

here:

from yowsup.common.tools import Jid #is writing, writing pause
from yowsup.layers.auth import YowAuthenticationProtocolLayer

Log, but only creates the file and writes only if you kill by hand from the console (CTRL + C)

I updated all:

sudo apt-get install python-dateutil
sudo apt-get install python-argparse
sudo apt-get install python-setuptools
sudo apt-get install python-dev
sudo apt-get install libevent-dev
sudo apt-get install ncurses-dev
sudo apt-get install libglib2.0.0
sudo apt-get install libglib2.0-dev
sudo apt-get install libxml2
sudo apt-get install python-pip
sudo pip install protobuf
sudo pip install python-axolotl

but still there is the error :(

Traceback (most recent call last):
File "run.py", line 30, in
stack.loop( timeout = 0.5, discrete = 0.5 ) #this is the program mainloop
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/stacks/yowstack.py", line 188, in loop
asyncore.loop(_args, *_kwargs)
File "/usr/lib/python2.7/asyncore.py", line 216, in loop
poll_fun(timeout, map)
File "/usr/lib/python2.7/asyncore.py", line 156, in poll
read(obj)
File "/usr/lib/python2.7/asyncore.py", line 87, in read
obj.handle_error()
File "/usr/lib/python2.7/asyncore.py", line 83, in read
obj.handle_read_event()
File "/usr/lib/python2.7/asyncore.py", line 449, in handle_read_event
self.handle_read()
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/network/layer.py", line 102, in handle_read
self.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/network/layer.py", line 110, in receive
self.toUpper(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/init.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/stanzaregulator/layer.py", line 29, in receive
self.processReceived()
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/stanzaregulator/layer.py", line 52, in processReceived
self.processReceived()
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/stanzaregulator/layer.py", line 52, in processReceived
self.processReceived()
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/stanzaregulator/layer.py", line 52, in processReceived
self.processReceived()
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/stanzaregulator/layer.py", line 49, in processReceived
self.toUpper(oneMessageData)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/auth/layer_crypt.py", line 65, in receive
self.toUpper(payload)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/coder/layer.py", line 35, in receive
self.toUpper(node)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/logger/layer.py", line 14, in receive
self.toUpper(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/axolotl/layer_control.py", line 44, in receive
self.toUpper(protocolTreeNode)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 76, in toUpper
self.upper.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/__init
.py", line 189, in receive
s.receive(data)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/axolotl/layer_send.py", line 64, in receive
if not self.processIqRegistry(protocolTreeNode):
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/init.py", line 156, in processIqRegistry
successClbk(protocolTreeNode, originalIq)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/axolotl/layer_send.py", line 215, in sendToGroup
jids.remove(ownJid)
ValueError: list.remove(x): x not in list

Men try to move your proyect to /yowsup/demos/echoclient/ in this folder are only two files, layer.py and stack.py, the layer.py change the name momently, and run the code.
the stack.py keep and don t move and don t change.

@Kaoala

true. I use myself that way. as @Messiefee says. if you move the layer.py to the folder yowsup/demos/echoclient you should run your project like this:
./yosup-cli demos -c config.config -e

that's the easiest solution. but if you still want to run it with the run.py, do the following:

you must modify the file "yowsup/layers/auth/layer_authentication.py"

    def getUsername(self, full = False):
        if self._credentials:
            return self._credentials[0] if not full else ("%s@%s" % (self._credentials[0], YowConstants.WHATSAPP_SERVER))
        else:
            #prop = self.getProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS)  #Original line
            prop = self.getProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS)[0] if not full else ("%s@%s" % (
                    self.getProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS)[0], YowConstants.WHATSAPP_SERVER))
            #return prop[0] if prop else None  #Original line
            return prop if prop else None

This can also be fixed by modifying your run.py.
You currently have:
stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, CREDENTIALS) #setting credentials

Change this into:
stack.setCredentials(CREDENTIALS) #setting credentials

when this is done there is no need to patch layer_authentication.py.

Thank you guys,
i will check everything in the next few days.

Hi, Thank you for this script. It is working fine and is able to reply with text message. However, could someone be able to add ability to respond with an image/video file?

possible, with a little work and a couple of extra lines.

Thank you!!! Eagerly waiting.

ok, the promised.

add to head:

from yowsup.layers.protocol_media.protocolentities       import *
from yowsup.layers.protocol_media.mediauploader          import MediaUploader
import sys, logging
logger = logging.getLogger(__name__)

add to tail:

    def image_send(self, number, path, caption = None):
    jid = number
    mediaType = "image"
        entity = RequestUploadIqProtocolEntity(mediaType, filePath = path)
        successFn = lambda successEntity, originalEntity: self.onRequestUploadResult(jid, mediaType, path, successEntity, originalEntity, caption)
        errorFn = lambda errorEntity, originalEntity: self.onRequestUploadError(jid, path, errorEntity, originalEntity)
        self._sendIq(entity, successFn, errorFn)

    def doSendMedia(self, mediaType, filePath, url, to, ip = None, caption = None):
        entity = ImageDownloadableMediaMessageProtocolEntity.fromFilePath(filePath, url, ip, to, caption = caption)
        self.toLower(entity)

    def onRequestUploadResult(self, jid, mediaType, filePath, resultRequestUploadIqProtocolEntity, requestUploadIqProtocolEntity, caption = None):
        if resultRequestUploadIqProtocolEntity.isDuplicate():
            self.doSendMedia(mediaType, filePath, resultRequestUploadIqProtocolEntity.getUrl(), jid,
                             resultRequestUploadIqProtocolEntity.getIp(), caption)
        else:
            successFn = lambda filePath, jid, url: self.doSendMedia(mediaType, filePath, url, jid, resultRequestUploadIqProtocolEntity.getIp(), caption)
            mediaUploader = MediaUploader(jid, self.getOwnJid(), filePath,
                                      resultRequestUploadIqProtocolEntity.getUrl(),
                                      resultRequestUploadIqProtocolEntity.getResumeOffset(),
                                      successFn, self.onUploadError, self.onUploadProgress, async=False)
            mediaUploader.start()

    def onRequestUploadError(self, jid, path, errorRequestUploadIqProtocolEntity, requestUploadIqProtocolEntity):
        logger.error("Request upload for file %s for %s failed" % (path, jid))

    def onUploadError(self, filePath, jid, url):
        logger.error("Upload file %s to %s for %s failed!" % (filePath, url, jid))

    def onUploadProgress(self, filePath, jid, url, progress):
        sys.stdout.write("%s => %s, %d%% \r" % (os.path.basename(filePath), jid, progress))
        sys.stdout.flush()

to call:

            if message == 'hi':
                answer = "Hi "+namemitt+" " 
                self.toLower(textmsg(answer, to = recipient ))
                print answer

            elif message == 'image1':
                path = "image path"
                self.image_send(recipient, path)

This is brilliant!!! Thank you Sowerkoku!!
Now I am able to receive captured picture if asked via whatsapp.
Is there an easy way to trigger a message based on an event? eg I have a python script monitoring push button. Right now it simply flips a GPIO.
How can I send a message if button is pressed without losing echo functionality.
I tried sending message via command line where it was able to send but I have to kill and restart run.py with every push.

Button Script
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(27, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(17, GPIO.OUT)
GPIO.setup(22, GPIO.OUT)
ledState = 1
def toggleState(channel):
global ledState
print("Rising edge detected. Toggling state")

if (ledState%2 == 1):
GPIO.output(17,False)
GPIO.output(22,True)
elif (ledState%2 == 0):
GPIO.output(17,True)
GPIO.output(22,False)
ledState = ledState+1
GPIO.add_event_detect(27, GPIO.RISING, callback=toggleState, bouncetime=300)
try:
while True:
time.sleep(60)
except KeyboardInterrupt:
GPIO.cleanup()

you've tried to integrate the button ?

you can read here.

Hi Sowerkoku,

My apologies, looks like I didn't communicate in clear way.
I am trying to use same setup to send adhoc messages to whatsapp number.
Right now I get echo back. But I have to send a message first.

I'm understanding.
but the purpose of the echo is responding previous message.
Might I happen to generate a new layer.py with:
-def startEcho (self): and
-def startSendClient (self):

or do something like this.

Thanks for quick response. I tired in a way where it kills current instance, execute cli and send required message and then start run.py again. Looks like I'll wait for your new layer.py :)

How is this?
execute cli and send required message

say you run: ./yowsup-cli demos -c config -s PHONE "message"

It does send the message but already running echo (run.py) stops listening/responding. I have to restart after each message send via cli

do something simple first.
a script to stop the echoclient, send the message and run the echoclient

Yepp that's my current solution as i am idiot in programming language.
This is working but it is crude and there must be something we can directly do in layer.py

!/bin/bash

msg=$1
sudo service whatsapp stop
sleep 1
sudo python whatsapp_photo.py $msg
sleep 1
sudo service whatsapp start

run.py is installed as service and whatsapp_photo.py is simple cli call

I do not complicate me, would make it easy.

./yowsup-cli demos -c config -s phone "msg" #this automatically stops the run.py
if message send
run run.py

That is the same solution as mine :( which calls for run.py to stop. Is new sendClient method in layer.py is too difficult to implement and use?

I think it is difficult to understand the purpose :P
send, RECEIVE or interactive.
I see yours interactive. and echoclient is not the option.

it would have to write a script based on the cli.
this will send a message in response to an event. and given the option to respond automatically if the incoming message is a valid command.

I understand that and appreciate your guidance :)
Just noticed that run.py crashes if someone sends video file to it.
What shall I do to to fix this ? or if it can save image/video to folder

File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/axolotl/layer_receive.py", line 88, in handleEncMessage
self.handleWhisperMessage(node)
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/axolotl/layer_receive.py", line 144, in handleWhisperMessage
self.parseAndHandleMessageProto(encMessageProtocolEntity, plaintext[:-padding])
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/axolotl/layer_receive.py", line 204, in parseAndHandleMessageProto
raise ValueError("Unhandled")
ValueError: Unhandled

save a picture if you can

but a video not know, have not tried it :/

How do I atleast make sure that run.py is not killed if someone sends a video?

You need to edit yowsup internal code to ack messages which raise ValueError("Unhandled").

Apply something like this patch:

diff --git a/yowsup/layers/axolotl/layer_receive.py b/yowsup/layers/axolotl/layer_receive.py
index 5ec3293..51f8ddc 100644
--- a/yowsup/layers/axolotl/layer_receive.py
+++ b/yowsup/layers/axolotl/layer_receive.py
@@ -117,6 +117,10 @@ class AxolotlReceivelayer(AxolotlBaseLayer):
             else:
                 logger.error("Ignoring message with untrusted identity")

+        except ValueError as e:
+            logger.warning("Received unrecognized encrypted message. I'll send the delivery receipt myself")
+            self.toLower(OutgoingReceiptProtocolEntity(node["id"], node["from"], participant=node["participant"]).toProtocolTreeNode())
+
     def handlePreKeyWhisperMessage(self, node):
         pkMessageProtocolEntity = EncryptedMessageProtocolEntity.fromProtocolTreeNode(node)
         enc = pkMessageProtocolEntity.getEnc(EncProtocolEntity.TYPE_PKMSG)

Thank you!! Now it is working fine and is not ending up in exception.
What shall I do so that it can save received images to specific path?

See demos/cli/layer.py where image is downloaded. In my branch I've implemented an easier method to get media content.

Hi,
I took an example from
https://github.com/jlguardi/yowsup/tree/master/yowsup/demos/echoclient
I am getting
Echoing image https://mmi670.whatsapp.net/d/pKm4trm2chAENl3N6-zhgleOL9E/AqelPfUPWdAqOjF472m0zYTLbpoYjRBvqax8mlRz7Pmf.enc
Looks like I need to implement some method for downloading encrypted content
def onMediaMessage(self, messageProtocolEntity):
# just print info
if messageProtocolEntity.getMediaType() == "image":
print("Echoing image %s to %s" % (messageProtocolEntity.url, messageProtocolEntity.getFrom(False)))

to download the jlguardi branch is very simple.

       def getMediaMessageBody(self, message):
        if message.getMediaType() in ("image", "audio", "video", "document"):
            return self.getDownloadableMediaMessageBody(message)
        else:
            return "[Media Type: %s] %s" % (message.getMediaType(), message)

    def getDownloadableMediaMessageBody(self, message):
        filename = "%s/%s%s"%('/your home/yowsup/imagenes',message.getId(),message.getExtension())
        with open(filename, 'wb') as f:
            f.write(message.getMediaContent())
        return "[Media Type:{media_type}, Size:{media_size}, URL:{media_url}, FILE:{fname}]".format(
            media_type=message.getMediaType(),
            media_size=message.getMediaSize(),
            media_url=message.getMediaUrl(),
            fname=filename
)

and they call it

    if messageProtocolEntity.getType() == 'media':
       self.getMediaMessageBody(messageProtocolEntity)

HI I tried that but ended up in below exception:
File "/home/pi/layer.py", line 45, in getDownloadableMediaMessageBody
filename = "%s/%s%s"%('/home/pi/imagenes',messageProtocolEntity.getId(),messageProtocolEntity.getExtension())
AttributeError: 'ImageDownloadableMediaMessageProtocolEntity' object has no attribute 'getExtension'

that works for branch jlguardi. but for the branch tgalal you should modify.
read again
not know if that helps. @jlguardi incorporates other changes.

@controller-t
I try this (it is for the branch tgalal) and if it works you comment

    def onMediaMessage(self, messageProtocolEntity):
        if messageProtocolEntity.getMediaType() == "image":
            url = messageProtocolEntity.url
            self.extension = self.getExtension(messageProtocolEntity.getMimeType())
            return self.downloadMedia(url)

    def downloadMedia(self, url):
        print("Downloading %s" % url)
        downloader = MediaDownloader(self.onSuccess, self.onError, self.onProgress)
        downloader.download(url)

    def onError(self):
        logger.error("Error download file")

    def onSuccess(self, path):
        outPath = "/your home/yowsup_tgalal/image/%s%s" % (os.path.basename(path), self.extension)
        shutil.copyfile(path, outPath)
        print("\nPicture downloaded to %s" % outPath)

    def onProgress(self, progress):
        sys.stdout.write("Download progress => %d%% \r" % progress)
        sys.stdout.flush()

    def getExtension(self, mimetype):
        type = mimetypes.guess_extension(mimetype.split(';')[0])
        if type is None:
            raise Exception("Unsupported/unrecognized mimetype: "+mimetype);
        return type

call to:
self.onMediaMessage(messageProtocolEntity)

Hi, I modified it per your recommendation but still getting exception:
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/stacks/yowstack.py", line 188, in loop
File "/home/pi/layer.py", line 12, in onMessage
self.getMediaMessageBody(messageProtocolEntity)
File "/home/pi/layer.py", line 40, in getMediaMessageBody
return self.getDownloadableMediaMessageBody(messageProtocolEntity)
File "/home/pi/layer.py", line 48, in getDownloadableMediaMessageBody
f.write(messageProtocolEntity.getMediaContent())
AttributeError: 'ImageDownloadableMediaMessageProtocolEntity' object has no attribute 'getMediaContent'
Kindly suggest

this error is because these occupy the option to jlguardi branch. and so I understand your use tgalal branch.

I tried the discharge branch jlguardi a while back and it works perfect. but again, if you have the tgalal branch, that option will not work because they process information differently.

try this as I said before. and add this to head:

from yowsup.layers.protocol_media.protocolentities import *
from yowsup.layers.protocol_media.picture         import YowMediaPictureLayer   #descarga imagen
from yowsup.layers.protocol_media.mediadownloader import MediaDownloader        #descarga imagen

import sys, shutil

Hi Sowerkoku,
My humble apologies for this mess.
I tried adding above imports but ended up with additional exception:
File "/home/pi/layer.py", line 3, in
from yowsup.layers.protocol_media.picture import YowMediaPictureLayer #descarga imagen
File "/usr/local/lib/python2.7/dist-packages/yowsup2-2.5.0-py2.7.egg/yowsup/layers/protocol_media/picture.py", line 2, in
from yowsup import ProtocolTreeNode
ImportError: cannot import name ProtocolTreeNode

I modified picture.py and replaced import line with
from yowsup.structs import ProtocolTreeNode
Now it is not throwing any exception during validation but getting an error while recceiving image

pi@retropie:~ $ sudo ./run.py
Downloading https://mmi714.whatsapp.net/d/wh3WGjk_iXivVsf9pkfLeFeTkY0/An_Ip0G1RF5aYDNZ85zB3WVbBwu-ZOknAdBwIY_oHqL3.enc
No handlers could be found for logger "yowsup.layers.protocol_media.mediadownloader"
Error download file

Thanks

I think I am missing something matter. read again

Hi, Below are my layer.py and run.py

layer.py
from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback
import mimetypes
from yowsup.layers.protocol_media.picture import YowMediaPictureLayer #descarga imagen
from yowsup.layers.protocol_media.mediadownloader import MediaDownloader #descarga imagen
from yowsup.layers.protocol_media.protocolentities import *
import sys, shutil, logging
logger = logging.getLogger(name)
class EchoLayer(YowInterfaceLayer):

@ProtocolEntityCallback("message")
def onMessage(self, messageProtocolEntity):

    if messageProtocolEntity.getType() == 'text':
        self.onTextMessage(messageProtocolEntity)
    elif messageProtocolEntity.getType() == 'media':
        self.onMediaMessage(messageProtocolEntity)
    self.toLower(messageProtocolEntity.forward(messageProtocolEntity.getFrom()))
    self.toLower(messageProtocolEntity.ack())
    self.toLower(messageProtocolEntity.ack(True))


@ProtocolEntityCallback("receipt")
def onReceipt(self, entity):
    self.toLower(entity.ack())

def onTextMessage(self,messageProtocolEntity):
    # just print info
    print("Echoing %s to %s" % (messageProtocolEntity.getBody(), messageProtocolEntity.getFrom(False)))

def onMediaMessage(self, messageProtocolEntity):
    if messageProtocolEntity.getMediaType() == "image":
       url = messageProtocolEntity.url
       self.extension = self.getExtension(messageProtocolEntity.getMimeType())
       return self.downloadMedia(url)

def downloadMedia(self, url):
    print("Downloading %s" % url)
    downloader = MediaDownloader(self.onSuccess, self.onError, self.onProgress)
    downloader.download(url)

def onError(self):
    print "Error download file"

def onSuccess(self, path):
    outPath = "/home/pi/test/%s%s" % (os.path.basename(path), self.extension)
    shutil.copyfile(path, outPath)
    print("\nPicture downloaded to %s" % outPath)

def onProgress(self, progress):
    sys.stdout.write("Download progress => %d%% \r" % progress)
    sys.stdout.flush()

def getExtension(self, mimetype):
    type = mimetypes.guess_extension(mimetype.split(';')[0])
    if type is None:
        raise Exception("Unsupported/unrecognized mimetype: "+mimetype);
    return type

run.py

!/usr/bin/python

from yowsup.stacks import YowStackBuilder
from yowsup.common import YowConstants
from yowsup.layers import YowLayerEvent
from layer import EchoLayer
from yowsup.layers.auth import YowAuthenticationProtocolLayer
from yowsup.layers.coder import YowCoderLayer
from yowsup.layers.network import YowNetworkLayer
from yowsup.env import YowsupEnv
CREDENTIALS = ("Phone", "key")

if name== "main":
stackBuilder = YowStackBuilder()

stack = stackBuilder\
    .pushDefaultLayers(True)\
    .push(EchoLayer)\
    .build()

stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, CREDENTIALS)       #setting credentials
stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT))          #sending the connect signal
stack.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[0])           #whatsapp server address
stack.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN)
stack.setProp(YowCoderLayer.PROP_RESOURCE, YowsupEnv.getCurrent().getResource())  #info about us as WhatsApp client
stack.loop( timeout = 0.5, discrete = 0.5 )                                       #this is the program mainloop

Do you have a script for sending audio messages?

@Elklund
I have not tried it with audio . but you can read layer.py

@controller-t
what is your question?
only i see bad this it:
logger = logging.getLogger(__name__) #) #in layer.py
and

if __name__== "__main__": #in run.py
change:
stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, CREDENTIALS) by
stack.setCredentials(CREDENTIALS)

The audio problem is fixed. :)

I have this Code using if my bot doesn't understand Things. But I want to put the message (which the bot don't understand) into a link. But there are many Problems how can I fix that?

else:
answer = "I don't understand. Search here for"+messsage+"\nhttps://www.bing.com/search?q="+message
                self.toLower(textmsg(answer, to = recipient))
                print answer

How can I implement the last message from user?

@sowerkoku
I am still unable to receive images with mentioned changes and tagala branch:(

@Elklund
It is ok
answer = "I don't understand. Search here for"+messsage+"\nhttps://www.bing.com/search?q="+message
but
messsage != message
answer = "I don't understand. Search here for \""+message+"\"\nhttps://www.bing.com/search?q="+message

@controller-t
all this ok:

from yowsup.layers.interface                           import YowInterfaceLayer, ProtocolEntityCallback  #Reply to the message
from yowsup.layers.protocol_media.protocolentities     import *                 #sube imagen
from yowsup.layers.protocol_media.picture              import YowMediaPictureLayer   #descarga imagen
from yowsup.layers.protocol_media.mediadownloader      import MediaDownloader        #descarga imagen
import sys, shutil, logging, mimetypes
logger = logging.getLogger(__name__)

add error or debugging here

@Elklund
It is ok
answer = "I don't understand. Search here for"+messsage+"md5-f2810d13b5d726f3baf2be480539d0bcnhttps://www.bing.com/search?q="+message
but
messsage != message
answer = "I don't understand. Search here for ""+message+""md5-f2810d13b5d726f3baf2be480539d0bcnhttps://www.bing.com/search?q="+message

I don't understand!? What means message != message?

3s != 2s
sss != ss
messsage != message
messsage does not exist

ok, the promised.

add to head:

from yowsup.layers.protocol_media.protocolentities import *
from yowsup.layers.protocol_media.mediauploader import MediaUploader
import sys, logging
logger = logging.getLogger(__name__)
add to tail:

def image_send(self, number, path, caption = None):
    jid = number
    mediaType = "image"
    entity = RequestUploadIqProtocolEntity(mediaType, filePath = path)
    successFn = lambda successEntity, originalEntity: self.onRequestUploadResult(jid, mediaType, path, successEntity, originalEntity, caption)
    errorFn = lambda errorEntity, originalEntity: self.onRequestUploadError(jid, path, errorEntity, originalEntity)
    self._sendIq(entity, successFn, errorFn)

def doSendMedia(self, mediaType, filePath, url, to, ip = None, caption = None):
    entity = ImageDownloadableMediaMessageProtocolEntity.fromFilePath(filePath, url, ip, to, caption = caption)
    self.toLower(entity)

def onRequestUploadResult(self, jid, mediaType, filePath, resultRequestUploadIqProtocolEntity, requestUploadIqProtocolEntity, caption = None):
    if resultRequestUploadIqProtocolEntity.isDuplicate():
        self.doSendMedia(mediaType, filePath, resultRequestUploadIqProtocolEntity.getUrl(), jid,
                         resultRequestUploadIqProtocolEntity.getIp(), caption)
    else:
        successFn = lambda filePath, jid, url: self.doSendMedia(mediaType, filePath, url, jid, resultRequestUploadIqProtocolEntity.getIp(), caption)
        mediaUploader = MediaUploader(jid, self.getOwnJid(), filePath,
                                  resultRequestUploadIqProtocolEntity.getUrl(),
                                  resultRequestUploadIqProtocolEntity.getResumeOffset(),
                                  successFn, self.onUploadError, self.onUploadProgress, async=False)
        mediaUploader.start()

def onRequestUploadError(self, jid, path, errorRequestUploadIqProtocolEntity, requestUploadIqProtocolEntity):
    logger.error("Request upload for file %s for %s failed" % (path, jid))

def onUploadError(self, filePath, jid, url):
    logger.error("Upload file %s to %s for %s failed!" % (filePath, url, jid))

def onUploadProgress(self, filePath, jid, url, progress):
    sys.stdout.write("%s => %s, %d%% \r" % (os.path.basename(filePath), jid, progress))
    sys.stdout.flush()

Hi @sowerkoku,

Thanks for this code, i added it and now I can send pictures together with the answer!!!

Now I ask you a favor if I want to send my position along with the answer, how can I do it?

Very thanks!!

I have updated my project layer.py

There are interesting things to do

But there is a problem with downloading the images, Images are downloaded to /root
but these do not open with the image viewer, these appear corrupt

Someone can test the layer.py ?

Thank you very much

@sowerkoku @jlguardi

My project is here

Hi @sowerkoku

In version 06 I added sending geo-localization..

The problem remains with downloading the image

What do you think about it?

hi @langioletto,

I will see your code and comment.

hi @langioletto,
I still do not try your code, but...
Try this,

#############################################
#    def onMediaMessage(self, messageProtocolEntity):
#        if messageProtocolEntity.getMediaType() == "image":
#            url = messageProtocolEntity.url
#            self.extension = self.getExtension(messageProtocolEntity.getMimeType())
#            return self.downloadMedia(url)
#
#    def downloadMedia(self, url):
#        print("Downloading %s" % url)
#        downloader = MediaDownloader(self.onSuccess, self.onError, self.onProgress)
#        downloader.download(url)

############################
#     downloadables
############################
    def getMediaMessage(self, messageProtocolEntity):
        if messageProtocolEntity.getMediaType() in ("image", "audio", "video", "document"):
            return self.getDownloadableMediaMessageBody(messageProtocolEntity)
        else:
            return "[Media Type: %s] %s" % (messageProtocolEntity.getMediaType(), messageProtocolEntity)

    def getDownloadableMediaMessageBody(self, messageProtocolEntity):
    self.extension = self.getExtension(messageProtocolEntity.getMimeType())
    self.url = messageProtocolEntity.getMediaUrl()
    self.mediaKey = messageProtocolEntity.mediaKey
    self.cryptKeys = getcryptKeys(messageProtocolEntity.getMediaType())
        #filename = "%s/%s%s"%(tempfile.gettempdir(),messageProtocolEntity.getId(),messageProtocolEntity.getExtension())
        filename = "%s/%s%s"%('/home/user/yowsup/downloads',messageProtocolEntity.getId(),self.extension)
        with open(filename, 'wb') as f:
            #f.write(messageProtocolEntity.getMediaContent())
            f.write(self.getMediaContent(self.url))
        #return "[Media Type:{media_type}, Size:{media_size}, URL:{media_url}, FILE:{fname}]".format(
        return "{fname}".format(
            media_type=messageProtocolEntity.getMediaType(),
            media_size=messageProtocolEntity.getMediaSize(),
            media_url=messageProtocolEntity.getMediaUrl(),
            fname=filename
        )

    def decrypt(self, encimg, refkey):
        #derivative = HKDFv3().deriveSecrets(refkey, binascii.unhexlify("None"), 112)
        derivative = HKDFv3().deriveSecrets(refkey, binascii.unhexlify(self.cryptKeys), 112)
        parts = ByteUtil.split(derivative, 16, 32)
        iv = parts[0]
        cipherKey = parts[1]
        e_img = encimg[:-10]
        AES.key_size=128
        cr_obj = AES.new(key=cipherKey,mode=AES.MODE_CBC,IV=iv)
        return cr_obj.decrypt(e_img)

    def isEncrypted(self):
        return self.cryptKeys and self.mediaKey

    def getMediaContent(self):
        data = urlopen(self.url).read()
        if self.isEncrypted():
            data = self.decrypt(data, self.mediaKey)
        return bytearray(data)

    def getcryptKeys(self, mediaType):
    if mediaType == "image":
        #self.cryptKeys = '576861747341707020496d616765204b657973'
        return "576861747341707020496d616765204b657973"
    elif mediaType == "audio":
        #self.cryptKeys = '576861747341707020417564696f204b657973'
        return "576861747341707020417564696f204b657973"
    elif mediaType == "video"
        #self.cryptKeys = '576861747341707020566964656f204b657973'
        return "576861747341707020566964656f204b657973"
    elif mediaType == "document"
        #self.cryptKeys = '576861747341707020446f63756d656e74204b657973'
        return "576861747341707020446f63756d656e74204b657973"
    return "None"

###########################

The information you get here

File "/root/.yowsup/layer.py", line 97, in getDownloadableMediaMessageBody filename = "%s/%s%s"%('/home/user/yowsup/downloads',messageProtocolEntity.getId(),messageProtocolEntity.getExtension()) AttributeError: 'ImageDownloadableMediaMessageProtocolEntity' object has no attribute 'getExtension'

Sorry @langioletto, but I have no way to test the code. I just think it will work.

change A x B:
A = messageProtocolEntity.getExtension()
B = self.getExtension(messageProtocolEntity.getMimeType()

read here

f.write(messageProtocolEntity.getMediaContent())

AttributeError: 'ImageDownloadableMediaMessageProtocolEntity' object has no attribute 'getMediaContent'

jajaja ok
self.url = messageProtocolEntity.getMediaUrl()
change messageProtocolEntity.getMediaContent() to self.getMediaContent(self.url)
and def getMediaContent(self): to def getMediaContent(self, url):

update

and remeber change /home/user/yowsup/downloads to your folder_download

File "/root/.yowsup/layer.py", line 118, in getMediaContent
data = urlopen(self.url).read()
NameError: global name 'urlopen' is not defined

from Crypto.Cipher import AES
try:
    from urllib.request import urlopen
except ImportError:
    from urllib2 import urlopen
from axolotl.kdf.hkdfv3 import HKDFv3
from axolotl.util.byteutil import ByteUtil
import binascii
import base64

File "/root/.yowsup/layer.py", line 121, in isEncrypted
return self.mediaKey is not None
AttributeError: 'EchoLayer' object has no attribute 'mediaKey'

or

if sys.version_info >= (3, 0):
    from urllib.request import urlopen
    from urllib.parse import urlencode
else:
    from urllib2 import urlopen
    from urllib import urlencode

File "/root/.yowsup/layer.py", line 128, in isEncrypted
return self.mediaKey is not None
AttributeError: 'EchoLayer' object has no attribute 'mediaKey'

try:

    def getDownloadableMediaMessageBody(self, messageProtocolEntity):
        self.extension = self.getExtension(messageProtocolEntity.getMimeType())
        self.url = messageProtocolEntity.getMediaUrl()
        self.mediaKey = messageProtocolEntity.mediaKey

or add to /yowsup/layers/protocol_media/protocolentities/message_media_downloadable.py
this:

    def getMediaKey(self):
        return self.mediaKey

and change:

    def getDownloadableMediaMessageBody(self, messageProtocolEntity):
        self.extension = self.getExtension(messageProtocolEntity.getMimeType())
        self.url = messageProtocolEntity.getMediaUrl()
        self.mediaKey = messageProtocolEntity.getMediaKey()

Sorry, but I can not try the code.

Now it works, but it works as before (old code)

Download ok

5BED65AD7F988FFA91.jpeg Size: 7098
fanculo.jpg Size: 7075 (original image)

No open "view"

It is not possible to open the file

@langioletto
try:

    def decrypt(self, encimg, refkey):
        #derivative = HKDFv3().deriveSecrets(refkey, binascii.unhexlify(self.cryptKeys), 112)
        derivative = HKDFv3().deriveSecrets(refkey, binascii.unhexlify("576861747341707020496d616765204b657973"), 112)

or view update

@langioletto Hi! Could you upload your layer.py to somewhere else, not in mega.nz? It is heavily blocked in my country *(

Was this page helpful?
0 / 5 - 0 ratings