How do i program a simple IRC bot in python? - python

I need help writing a basic IRC bot that just connects to a channel.. is anyone able to explain me this? I have managed to get it to connect to the IRC server but i am unable to join a channel and log on. The code i have thus far is:
import sockethost = 'irc.freenode.org'
port = 6667
join_sock = socket.socket()
join_sock.connect((host, port))
<code here>
Any help would be greatly appreciated.

To connect to an IRC channel, you must send certain IRC protocol specific commands to the IRC server before you can do it.
When you connect to the server you must wait until the server has sent all data (MOTD and whatnot), then you must send the PASS command.
PASS <some_secret_password>
What follows is the NICK command.
NICK <username>
Then you must send the USER command.
USER <username> <hostname> <servername> :<realname>
Both are mandatory.
Then you're likely to see the PING message from server, you must reply to the server with PONG command every time the server sends PING message to you. The server might ask for PONG between NICK and USER commands too.
PING :12345678
Reply with the exact same text after "PING" with PONG command:
PONG :12345678
What's after PING is unique to every server I believe so make sure you reply with the value that the server sent you.
Now you can join a channel with JOIN command:
JOIN <#channel>
Now you can send messages to channels and users with PRIVMSG command:
PRIVMSG <#channel>|<nick> :<message>
Quit with
QUIT :<optional_quit_msg>
Experiment with Telnet! Start with
telnet irc.example.com 6667
See the IRC RFC for more commands and options.
Hope this helps!

I used this as the MAIN IRC code:
import socket
import sys
server = "server" #settings
channel = "#channel"
botnick = "botname"
irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #defines the socket
print "connecting to:"+server
irc.connect((server, 6667)) #connects to the server
irc.send("USER "+ botnick +" "+ botnick +" "+ botnick +" :This is a fun bot!\n") #user authentication
irc.send("NICK "+ botnick +"\n") #sets nick
irc.send("PRIVMSG nickserv :iNOOPE\r\n") #auth
irc.send("JOIN "+ channel +"\n") #join the chan
while 1: #puts it in a loop
text=irc.recv(2040) #receive the text
print text #print text to console
if text.find('PING') != -1: #check if 'PING' is found
irc.send('PONG ' + text.split() [1] + '\r\n') #returnes 'PONG' back to the server (prevents pinging out!)
Then, you can start setting commands like: !hi <nick>
if text.find(':!hi') !=-1: #you can change !hi to whatever you want
t = text.split(':!hi') #you can change t and to :)
to = t[1].strip() #this code is for getting the first word after !hi
irc.send('PRIVMSG '+channel+' :Hello '+str(to)+'! \r\n')
Note that all irc.send texts must start with PRIVMSG or NOTICE + channel/user and the text should start with a : !

It'd probably be easiest to base it on twisted's implementation of the IRC protocol. Take a look at : http://github.com/brosner/bosnobot for inspiration.

This is an extension of MichaelvdNet's Post, which supports a few additional things:
Uses SSL wrapper for socket
Uses server password authentication
Uses nickserv password authentication
Uses nonblocking sockets, to allow other events to trigger
Logs changes to text files to channel
#!/usr/local/bin/python
import socket
import ssl
import time
## Settings
### IRC
server = "chat.freenode.net"
port = 6697
channel = "#meLon"
botnick = "meLon-Test"
password = "YOURPASSWORD"
### Tail
tail_files = [
'/tmp/file-to-tail.txt'
]
irc_C = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #defines the socket
irc = ssl.wrap_socket(irc_C)
print "Establishing connection to [%s]" % (server)
# Connect
irc.connect((server, port))
irc.setblocking(False)
irc.send("PASS %s\n" % (password))
irc.send("USER "+ botnick +" "+ botnick +" "+ botnick +" :meLon-Test\n")
irc.send("NICK "+ botnick +"\n")
irc.send("PRIVMSG nickserv :identify %s %s\r\n" % (botnick, password))
irc.send("JOIN "+ channel +"\n")
tail_line = []
for i, tail in enumerate(tail_files):
tail_line.append('')
while True:
time.sleep(2)
# Tail Files
for i, tail in enumerate(tail_files):
try:
f = open(tail, 'r')
line = f.readlines()[-1]
f.close()
if tail_line[i] != line:
tail_line[i] = line
irc.send("PRIVMSG %s :%s" % (channel, line))
except Exception as e:
print "Error with file %s" % (tail)
print e
try:
text=irc.recv(2040)
print text
# Prevent Timeout
if text.find('PING') != -1:
irc.send('PONG ' + text.split() [1] + '\r\n')
except Exception:
continue

That will open a socket, but you also need to tell the IRCd who you are. I've done something similar in perl ages ago, and I found the IRC RFCs to be very helpful.
Main RFC: http://irchelp.org/irchelp/rfc/rfc.html
Other RFCs: http://irchelp.org/irchelp/rfc/index.html

Related

I'm trying to create an IRC bot in Python, but it's not working properly

I have installed CentOS on a virtual machine and created an IRC server. I am planning to connect to it using LimeChat2 from my local PC and run a bot there in the #Test channel.
The issue here is that I was able to successfully create a bot in Ruby that joins the #Test channel and responds with "Hello" when prompted in LimeChat2. However, when I created a bot in Python that responds with "pong" when it receives a "ping" message, I am unable to see the bot in the user list in LimeChat.
I am providing my incomplete code below. What could be causing this issue?
import socket, string, time, _thread
SERVER = 'xxx.xx.xxx.xx'
PORT = 6667
NICKNAME = '_bot'
CHANNEL = '#Test'
def main():
global IRC
IRC = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
IRC.connect((SERVER, PORT))
_thread.start_new_thread(Listener(),("Thread No:1",2))
def send_data(command):
IRC.send(bytes(command + '\n', 'UTF-8'))
def Listener():
user_='USER test_bot test_bot test_bot test_bot \n'
nic_='NICK lap_bot \n'
send_data(user_)
send_data(nic_)
while (1):
buffer = IRC.recv(1024)
print(buffer)
print("\n \n")
msg = buffer.decode().split()
# print(msg)
# print('\n')
if msg[0] == "PING":
print ('Pinged!')
pong_=bytes(msg[1] , "utf-8")
IRC.send(bytes("PONG %s" % pong_ , 'UTF-8'))
print("Ponged!!")
main()
Could you please modify the code to respond with "Hi! Nice to meet you" when the Python bot receives a "hello" message?

IRC bot written in Python - join channel function

I'm trying to add to my python IRC bot a function that when I type "join #channel-name" on IRC, the bot will join the channel.
Here's my code:
# IRC bot written by syrius
import socket
server = "irc.freenode.net" # IRC server
channel = "#syrius-test" # Channel
botnick = "syrius-bot" # Nickname of the bot
master = "syrius_" # Nickname of the bot's master
exitcode = "bye " + botnick #Text that we will use to make the bot quit
def ircwrite(message):
global ircsock
ircsock.send(str(message).encode('latin-1', 'ignore'))
def ping():
ircwrite("PONG :pingis\n")
def sendmsg(chan , msg):
ircwrite("PRIVMSG "+ chan +" :"+ msg +"\n")
def joinchan(channel):
ircsock.send(bytes("JOIN "+ channel + "\n"))
def join():
ircsock.send(bytes("JOIN %s"))
def hello():
ircwrite("PRIVMSG "+ channel +" :Hello!\n")
def quitting():
ircwrite("PRIVMSG "+ channel +" :Okay boss, leaving now.\n")
ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ircsock.connect((server, 6667))
ircwrite("USER "+ botnick +" "+ botnick +" "+ botnick +" :IRC bot coded by syrius.\n")
ircwrite("NICK "+ botnick +"\n")
joinchan(channel)
while 1:
ircmsg = ircsock.recv(2048).decode() # receive data from the server
ircmsg = ircmsg.strip('\n\r') # removing any unnecessary linebreaks.
print(ircmsg) # Here we print what's coming from the server
name = ircmsg.split('!',1)[0][1:] # We split out the name
if ircmsg.find(":Hello "+ botnick) != -1: # If we can find "Hello Mybot" it will call the function hello()
hello()
if ircmsg.find("PING :") != -1: # if the server pings us then we've got to respond!
ping()
if name.lower() == master.lower() and ircmsg.find(":quit " + botnick) != -1:
quitting()
ircsock.send(bytes("QUIT \n", "UTF-8"))
if name.lower() == master.lower() and ircmsg.find(":join %s") != -1:
join()
main()
Of course the following code is incorrect :
line23:
def join():
ircsock.send(bytes("JOIN %s"))
line56:
if name.lower() == master.lower() and ircmsg.find(":join %s") != -1:
join()
I would like to know what should I put there so the bot can join the channel.
Any help would be very appreciated.
I see a couple of problems with this solution, my recommendation is you should probably try to use an IRC framework such as Pydle or one of the billion others that already handle protocol.
The first issue I see is using latin-1 for your encoding, generally you should be using utf-8, you could also be using whatever the server advertises in the CHARSET from the RPL_ISUPPORT reply, though that is not common anymore. Along the lines of encoding also, you could decode the IRC lines from utf-8 so you can deal with strings instead of bytes, and just reencode it at the output.
The next IRC issue would be your line ends, IRC messages should always end with CR-LS (Carriage Return-Line Feed) which would be the \r\n characters instead of just the \n.
The last thing I felt like mentioning was your string formatting, you should be using "JOIN {}".format(channel) which is the preferred string formatting method these days, unless you're using python 3.7 then you would use fstrings which are similar.
With the way you are trying to do the formatting now, you are doing it through both concatenation (eg "USER" + channel) but you are also trying to use old style string formatting through %s. If you wanted to use %s formatting the correct way would be "JOIN %s" % (channel), though these days using .format and fstrings are the preferred method.
You are missing argument. ircsock.send(bytes("JOIN %s")).
It should be like this:
ircsock.send(bytes("JOIN %s \r\n") % (channel))

"NO IDENT RESPONSE" error when connecting to an IRC server

Usually I would attempt something like this with the twisted library, but that isn't available for python 3 - so I attempted it using the sockets library. The code does establish a connection, but the server quickly responds with "no ident response". I don't have much network programming experience, so I would appreciate it if someone could point out the error I'm making here. I'm also quite aware that there are functions/other code that aren't used, or that Ive used inconsistently. I just thought I would paste the entirety of my code here in case its relevant.
import socket
server = "irc.freenode.net"
channel = "put channel here"
nickname = "put nickname here"
def encode(text):
return text.encode("ascii")
def ping():
irc_socket.send(encode("PONG :pingis\n"))
def send_message(chan, msg):
irc_socket.send(encode("PRIVMSG " + chan + " :" + msg + "\n"))
def join_channel(chan):
irc_socket.send(encode("JOIN " + chan + "\n"))
def login(username='user', realname='Pythonist', hostname='Helena', servername='Server'):
irc_socket.send(encode("USER %s %s %s %s" % (username, hostname, servername, realname)))
irc_socket.send(encode("NICK " + nickname))
irc_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
irc_socket.connect((server, 6667))
login()
join_channel(channel)
while True:
buffer = irc_socket.recv(1024)
msg = str.split(str(buffer))
if msg[0] == "PING":
irc_socket.send("PONG %s" % msg[1])
print(msg)
The code was originally from: http://wiki.shellium.org/w/Writing_an_IRC_bot_in_Python and Ive made minor changes.
Teensy tiny little problem that’s causing all the trouble: you’re missing newlines in login. "USER %s %s %s %s" should be "USER %s %s %s %s\n" and "NICK " + nickname should be "NICK " + nickname + "\n". The server looks up your ident and doesn’t find it, and the next step after that is for you to register, but you never send it a complete line, so it keeps waiting… and waiting…
Ident is UNIX service which nobody has been using for twenty years or so.
It was used to identify the remote user when doing terminal server to remote server connections in terminal applications. Ident is no way safe for modern internet, so nobody is using it anymore.
So you have hit the ghost of the past. Also, as mentioned in the above answer, if you send correct NICK command the IRC server is happy with your client.

Creating a log for UDP connection

I have having a problem with one of my university projects. We are doing sockets and UDP at the moment. Anyway so we had to make a very simple program, server, client, password name verification.
He wanted us to make a log of things, and I created a module with methods to write to a log file, this works fine. I have called it from different places and it always works. The only time it does not work is when called from the server.
import datetime
###Appends the message to the server log with the current date and time
def AddToLogServer(message):
f = open('Log_Server', 'a')
time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
f.write(time +" " + message +"\n")
f.close()
###Appends the message to the client log with the current date and time
def AddToLogClient(message):
f = open('Log_Client', 'a')
time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
f.write(time +" " + message +"\n")
f.close()
This is the log creations. Works fine.
import socket
import sys
import Passwords
import getpass
import Log
###Create a connectionless network socket.
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
###Maximum size data.
MAX = 65535
PORT = 1060
if sys.argv[1:] == ['server']:
###Set server ip
ip = '127.0.0.1'
try:
s.bind((ip, PORT))
except:
###If the server fails to start this error message and the server should end.
print "There is an error, perhaps the ip is already being used."
s.close()
sys.exit(1)
###Add to the server log that the server has started.
Log.AddToLogServer("The server is up with the ip " + ip)
print 'Server is up and listening at', s.getsockname()
###Listen for a client to send data to the server.
while True:
data, address = s.recvfrom(MAX)
Passwords.getPasswordsAndUsers()
###Compare the name inputted to the ones in the user list
i = Passwords.findUser(data)
###Update client log
Log.AddToLogServer(address[0] + " Inputted the name " + data)
s.sendto(str(i), address)
data, address = s.recvfrom(MAX)
t = Passwords.checkPassword(data,i)
###if the password matched the user print out the correct message and send a message to the client
if t == 1:
Log.AddToLogServer(address[0] + " Inputted the correct password for that user")
print address[0] + " Has successfully entered the correct User and Password"
s.sendto("The name and password were correct", address)
###if the password did not match the user print out the correct message and send a message to the client
else:
Log.AddToLogServer(address[0] + " Inputted an incorrect password for that user")
print address[0] + " Has failed to provide the correct Password for the inputted User"
s.sendto("The password did not match the name", address)
elif sys.argv[1:] == ['client']:
###Takes in the ip and name as inputs.
serverIp = raw_input("Please enter the server ip : ");
username = raw_input("Enter your first name please: ");
### Attempts to send to the server with the given ip
try:
s.sendto(username, (serverIp, PORT))
except:
###If the send fails then an error is shown and it finishes the execution.
print "There was a problem sending to the server"
s.close()
sys.exit(1)
###Attempt to relieve data from the server, if the client does not then write the appropriate message.
try:
data, address = s.recvfrom(MAX)
except:
print "There was a problem receiving from the server"
s.close()
sys.exit(1)
data = int(data)
###If the data was -1, then the user did not exist and an error should be displayed. Otherwise ask for the
###Password and send it to the server.
if data != -1:
password = getpass.getpass("Enter your password please: ");
try:
s.sendto(password, ('127.0.0.1', PORT))
except:
print "There was a problem sending to the server"
s.close()
sys.exit(1)
else:
print "This first name was not recognised."
sys.exit(1)
###Again try to relieve data from the server and print out the output.
try:
data, address = s.recvfrom(MAX)
print data
s.close()
except:
print "There was a problem receiving to the server"
s.close()
sys.exit(1)
Client server code, the log does not work when called from the server while it is up.
I have tried reproducing the problem, but the script for the server did not execute. On my machine sys.argv[1:] returned [], so i modified this part of your script if sys.argv[1:] == ['server']: to if sys.argv[1:] == []:
Please see the response i got. You should look into that part. if sys.argv[1:] == ['server']:
The server is up with the ip 127.0.0.1
Server is up and listening at ('127.0.0.1', 1060)

Python: Socket doesn't want to shutdown() and setsockopt() is ignored? (Problem debugging)

Edited
Original question was about trouble with reconnecting (close() and shutdown() confusion). The below code is the working code (fixed)
For Googler's, this script is an IRC bot. Feature list:
Keep reconnecting until connection available
If assigned nick is already taken, puts string behind name (repeats until success)
Listens to PING and responds with PONG
Can listen to commands and respond
If connection is lost, the bot will try to reconnect (if no information is received, no PING, in 5 mins, it treats the connection as if it was disconnected)
That is about it :)
Full Code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import socket
import string
import os
import platform
import time
# Variables
HOST = "irc.server.net"
PORT = 6667
NICK = "Nickname"
IDENT = "Nickname"
REALNAME = os.getenv('USER')
CHAN = "##Channel"
readbuffer = ""
# The Connection itself
keep_connecting = True
while keep_connecting:
irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
irc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
irc.settimeout(300)
try:
irc.connect((HOST, PORT))
pass
except socket.gaierror:
print "No connection, attempting to connect again"
time.sleep(5)
continue
print "Sending info..."
irc.send("NICK %s\r\n" % NICK)
irc.send("USER %s %s bla :%s\r\n" % (IDENT, HOST, REALNAME))
irc.send("JOIN :%s\r\n" % CHAN)
# Initial msg to send when bot connects
irc.send("PRIVMSG %s :%s\r\n" % (CHAN, "TehBot: "+ NICK + " Realname: " + REALNAME + " ."))
while True:
try:
data = irc.recv(4096)
print data
# If disconneted from IRC
if len(data) == 0:
print "Length of data == 0 ?..."
break
# If Nick is in use
if data.find (NICK + " :Nickname is already in use") != -1:
NICK = NICK + str(time.time())[5:-3]
break
# Ping Pong so we don't get disconnected
if data[0:4] == "PING":
irc.send ("PONG " + data.split() [ 1 ] + "\r\n")
except socket.timeout:
print "Socket timeout!"
irc.close()
break
This is most probably because you're switching off wi-fi and the interface is removed from system so you get something like Can't assign requested address. You would get such an error while trying to bind to non-existing local address.
The other thing is you won't be able to reconnect on the same socket after calling close as it releases all resources associated to the socket.

Categories

Resources