Python IRC Bot, distinguish from channel messages and private messages - python

I'm coding a simple IRC bot in Python. Actually, It can connect to a specific channel, read messages and send response, but it can't distinguish between channel messages and private messages.
Example:
John, connected to the same channel, send a private message to the Bot's chat, like "!say hello";
Bot have to send "hello" to the same private chat, only to John.
Instead, when bot read "!say hello" in channel's board, have to send "hello" to the channel.
My code:
ircmsg = connection.ircsock.recv(2048)
ircmsg_clean = ircmsg.strip(str.encode('\n\r'))
if ircmsg.find(str.encode("!say")) != -1:
try:
parts = ircmsg_clean.split()
content = parts[4]
connection.sendMsg(channel, content)
except IndexError:
connection.sendMsg(channel, "Invalid syntax")
Connection file:
def sendmsg(channel, msg):
ircsock.send(str.encode("PRIVMSG " + channel +" :" + msg + "\n"))
I know how to send a message to a specific user:
def sendPrivateMsg(username, msg):
ircsock.send(str.encode("PRIVMSG " + username + " :" + msg + "\n"))
But have to know from where the message came, channel or user, and send appropriate response.
Sorry for my bad english.

The source of the message is included in the protocol message, now you are just not using it.
In the part where you do this
parts = ircmsg_clean.split()
you get it in to the list parts.
If I remember correctly, and understand the RFQ right, the irc message you receive from the server looks something like this:
:John!something#something.org PRIVMSG BotName :Are you receiving this message ?
so splitting that would result in this:
[':John!something#something.org', 'PRIVMSG', 'BotName', ':Are', 'you', 'receiving', 'this', 'message', '?']
The sender of the message is that the first element parts, so parts[0]. You would need to strip away the extra ':'.
The target of the message is at parts[2], and that can be your name or the channel name, and you then need to compare the target to your own name to know if it is a message to you or to a channel.
If that is true, you can then do something like this:
source = parts[0].strip(':')
content = ' '.join(parts[3:]).strip(':')
connection.sendMsg(source, content)
Notice that the actual content of the message is also splitted, so you need to rejoin that into a string if you are doing it like that. If you are hitting that IndexError it means that you received a message that had only one word, since the first word is at index 3, not 4.

Related

Botframework send proactive message then string not empty

I have a problem sending proactive messages using the Bot Framework with Python.
First what I need is to get the message body from Outlook, and then the bot must send that as a message to all the chats where it was added.
To do that, first I created a new file and called it Email.py.
To read every incoming message body I simply used while true: and time.sleep()
Here is my code example:
import imaplib, email, getpass
from email import policy
import json
import time
imap_host = 'outlook.office365.com'
imap_user = 'xx#xx.com'
# init imap connection
mail = imaplib.IMAP4_SSL(imap_host, 993)
rc, resp = mail.login(imap_user, 'xxxxxx')
while True:
# select only unread messages from inbox
mail.select('Inbox')
status, data = mail.search(None, '(UNSEEN)')
if not data[0].split():
time.sleep(120)
# Bot message variable
Message_for_bot = ''
# for each e-mail messages
for num in data[0].split():
# get a single message and parse it by policy.SMTP (RFC compliant)
status, data = mail.fetch(num, '(RFC822)')
email_msg = data[0][1]
email_msg = email.message_from_bytes(email_msg, policy=policy.SMTP)
# print only message parts that contain text data
for part in email_msg.walk():
if part.get_content_type() == "text/plain":
for line in part.get_content().splitlines():
Message_for_bot += '\n' + line
print(Message_for_bot)
After I successfully created a program to read and print all incoming messages, I tried to build my bot. I found a proactive message bot on the Internet and used it as an example.
First I thought to just run this file with os in the background, but then my bot wasn't running. So then I tried adding an async function in the bot file but it didn't work. My bot just ignores that function. (Then I found the async functions in activity_handler.py, but I didn't find any that could help me.)
Then I tried adding an on_message_activity function and thought maybe it will start working if I call the bot like "#bot hi" for example in Teams. For that idea I must always run the while cycle and never stop the bot, but then I just get a message, and if there's a new incoming message then the bot doesn't write it anymore, and it's not a solution because if the bot is used for multiple chats then it simply doesn't work this way.
Then I try include my code on on_members_added_activity it seems working on azure test in web chat perfectly, but in teams after 1-2 messages stopping to work.
my code
async def on_members_added_activity(
self, members_added: [ChannelAccount], turn_context: TurnContext
):
imap_host = 'outlook.office365.com'
imap_user = 'xxxxxx#xxxxxx.com'
# init imap connection
mail = imaplib.IMAP4_SSL(imap_host, 993)
rc, resp = mail.login(imap_user, 'xxxxxx')
while True:
# select only unread messages from inbox
mail.select('Inbox')
status, data = mail.search(None, '(UNSEEN)')
if not data[0].split():
time.sleep(5)
# Bot message variable
Message_for_bot = ''
# for each e-mail messages
for num in data[0].split():
# get a single message and parse it by policy.SMTP (RFC compliant)
status, data = mail.fetch(num, '(RFC822)')
email_msg = data[0][1]
email_msg = email.message_from_bytes(email_msg, policy=policy.SMTP)
# print only message parts that contain text data
for part in email_msg.walk():
if part.get_content_type() == "text/plain":
for line in part.get_content().splitlines():
Message_for_bot += '\n' + line
await turn_context.send_activity(f"{Message_for_bot}")
for member in members_added:
if member.id != turn_context.activity.recipient.id:
await turn_context.send_activity(
"bot starting work..."
)
So maybe it's possible to send a message to wherever the bot is added (it needs to get this information somehow, maybe it's kept in the bot memory) whenever Message_for_bot is not empty.
All help will be appreciated.
As we have discussed some logic has to change
Move your code out of the on_members_added_activity function
Use Proactive concept to send the message
-Vinoth

Display DM sender's username (Twitter)

I've got this code, where it basically authenticates to Twitter and streams Direct Messages directly (as soon as I send/receive, the message sent/received gets printed).
from twitter import *
import os
APP_KEY,APP_SECRET = 'appkey123', 'appsecret123'
MY_TWITTER_CREDS = os.path.expanduser('my_app_credentials')
if not os.path.exists(MY_TWITTER_CREDS):
oauth_dance("crypto sentiments", APP_KEY, APP_SECRET,
MY_TWITTER_CREDS)
oauth_token, oauth_secret = read_token_file(MY_TWITTER_CREDS)
auth = OAuth(
consumer_key=APP_KEY,
consumer_secret=APP_SECRET,
token=oauth_token,
token_secret=oauth_secret
)
twitter_userstream = TwitterStream(auth=auth, domain='userstream.twitter.com')
for msg in twitter_userstream.user():
print(msg)
if 'direct_message' in msg:
print (msg['direct_message']['text'])
My question: How can I modify this code so it displays the username of the sender? Like so: #Jack: Hey there!
Simple and dirty way (you could do something far nicer with the string formatting) would be something like
for msg in twitter_userstream.user():
print(msg)
if 'direct_message' in msg:
print ('#' + msg['direct_message']['screen_name'] + ': ' + msg['direct_message']['text'])
It is worth noting that Twitter's user streams will be going away in June, so you should look at the new Account Activity API instead. More details in this announcement.

Can't print a json value

i have this code in python whoose purpose is to send a text file .c .txt (whatever, i've been sending a helloworld.c) through a websocket.
The problem is when i test it, the code doesn't go beyond print("I'm here!")
def onMessage_function(self, client_id, message):
print("Here's the message I received " + message + "\n\n\n")
dumpedMSG = json.dumps(message)
loadedMSG = json.loads(dumpedMSG)
if 'file_name' in loadedMSG:
print("I'm here!")
print(loadedMSG['file_name'])
else:
# do something else here.
Thank you!
It's hard to tell, but does this work?
def onMessage_function(self, client_id, message):
print("Here's the message I received " + message + "\n\n\n")
loadedMSG = json.loads(message)
if 'file_name' in loadedMSG:
print("I'm here!")
print(loadedMSG['file_name'])
else:
# do something else here.
In the original loadedMSG would be the same as message, so 'file_name' in loadedMSG would be a substring check rather than a check for a dictionary key. The print after "I'm here!" would then throw an exception, which you might not see if you're only receiving what is sent over the socket.

SendGrid Sending Multiple Copies

I'm using SendGrid to send emails from my python-based Heroku app.I'm okay with it taking 10 or so minutes to get to my inbox, but I'm receiving three copies of the message and I can't figure out why. Here is the relevant code:
import sendgrid
from sendgrid import SendGridError, SendGridClientError, SendGridServerError
sg = sendgrid.SendGridClient('xxx#heroku.com', 'xxx')
message = sendgrid.Mail()
message.add_to('John Doe <xxx#xxx.com>')
message.set_subject('Example')
message.set_html('Body')
message.set_text('Body')
message.set_from('Dark Knight <xxx#xxx.com>')
message.add_attachment('image.jpg', './image.jpg')
status, msg = sg.send(message)
#app.route('/test2')
def test2():
sg.send(message)
return "sent"
When I go to the relevant route I get 'sent' returned and the email is sent, but again, it send three copies. I'm not sure why. Any help would be great.
Emails one and two:
status, msg = sg.send(message) would send two emails and then set status and msg to the response object.
Email three: after you load the route sg.send(message) sends the next email.
I suggest you to use sendgrid sendmail api to send email. its efficient, fast way to send emails.
You are calling sg.send(message) three times in your code.
It is called twice here: status, msg = sg.send(message) - this will send one mail for status and log it's response to that variable. It will then send again for msg and log it's response to that variable as well.
Then when the user hits the /test2 the function is called again, making it three messages in total.
Here's how you might change it to log responses but just send the one message out:
import sendgrid
from sendgrid import SendGridError, SendGridClientError, SendGridServerError
sg = sendgrid.SendGridClient('xxx#heroku.com', 'xxx')
def sendMessage(options):
message = sendgrid.Mail()
message.add_to('John Doe <xxx#xxx.com>')
message.set_subject('Example')
message.set_html('Body')
message.set_text('Body')
message.set_from('Dark Knight <xxx#xxx.com>')
message.add_attachment('image.jpg', './image.jpg')
// send the message and log the results to status
msg = sg.send(message)
return msg
#app.route('/test2')
def test2():
// send the message, pass any options like email address (not required)
status = sendMessage(options)
return status
I've added a new function above to send out the message and given it an optional options var, so you could use that to pass things to the message, like a different email address, or subject.

Receiving GChat Messages using sleekXMPP or another client in python?

I have sleekXMPP for python and I have used the API to create functions to send messages, although when I researched into receiving them I can't find anything, can someone please help me to work this out, or disprove the possibility. Thanks.
Below is the code I used to send Messages, If its any help.
to = config.get('usermap', to[4:])
gmail_from_user = config.get('auth', 'email')
gmail_from_secret = config.get('auth', 'secret')
sys.stdout = stdouttmp
sys.stderr = stderrtmp
print "Sending chat message to " + to
xmpp = SendMsgBot(gmail_from_user, gmail_from_secret, to, message)
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0199') # XMPP Ping
sys.stdout = stdouttmp
if xmpp.connect(('talk.google.com', 5222)):
xmpp.process(block=True)
else:
sys.stdout = stdouttmp
print("Unable to connect.")
sys.stdout = stdouttmp
sys.stderr = stderrtmp
btw I'm using a .cfg text file for the users email and password, along with some contacts, which is then parsed in
I see that you're using the send_client.py example. The intent of that example is how to reliably log in, send a single message, and then log out. Your use case is to both send and receive messages, so you would be better served looking at the echo_client.py example.
Notably, in order to receive a message you would do:
# in your __init__ method:
def __init__(...):
# ...
self.add_event_handler('message', self.recv_message)
def recv_message(self, msg):
# You'll probably want to ignore error and headline messages.
# If you want to handle group chat messages, add 'groupchat' to the list.
if msg['type'] in ('chat', 'normal'):
print "%s says: %s" % (msg['from'], msg['body'])
Again, you will need to switch from using the SendMsgBot example because it automatically disconnects after sending its message.
Don't forget that there is the sleek#conference.jabber.org chat room if you need any help.
-- Lance

Categories

Resources