Saturday, July 21, 2012

Making an IRC Bot

A common question I get from people I know is about making an IRC bot. The problem I run into with people trying to do this is they are usually very new to programming and half the time they are struggling with the basics of simply how to write a program. So before getting into more detail, there are some prerequisites you need to know first.
  • Understanding the programming language syntax you want to use
  • Basic programming
  • Networking knowledge of basic sockets (nothing in depth but more so how network communication should be modeled)
  • Knowledge of the IRC protocol raw (access to an RFC is very useful)

Now f you are still reading, I will assume you at the very least plan on doing the research before actually trying anything. For this, I will be writing it in Python as it is very simple and easy to do. So let us work through this piece by piece.

The first thing we want to do is run our imports so we can have all the modules we need to work with. Rather than using some third party IRC module, we will work with raw sockets because I can and it gives more insight as to what is going on. We need the module for sockets, and regular expressions. We will also import time and I'll get to why later.

import socket
impor re
import time

So now that we have the packages we need, now we need to create a socket object. With a socket object, we can establish a connection over TCP/IP, among other types of socket connections. For our purposes we will use IPv4 and a stream. For this we use the variables AF_INET and SOCK_STREAM. The AF in AF_INET stands for "address family." Now let's create the socket.

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

Now we have the socket object s. In another post I will explain how to put an SSL wrapper on it to use a secure connection. As for now, just a socket will be used. Now we need to connect to a server.

s.connect((HOST, PORT))

Here the connection info is passed as a tuple, so yes the parentheses are on purpose. In this, HOST will be a string of either the IP address or domain and PORT is the port number you will connect to. Now that the connection is established, we need to send identifying information for the IRC. To simplify things we will have the program sleep for a second as some servers do not let you authenticate immediately and instead send a signal for it. However I do not feel like writing out something to check for that signal right away.

time.sleep(1>)
s.send("NICK MyIRCbotNick\r\n")
s.send("USER MyIRCbotNick anarchy46.net PY :Python Bot\r\n")

Okay, so now that we've authenticated, we will sleep again then join a channel because yet again, cannot join right away.

time.sleep(1)
s.send("JOIN #somechannel\r\n")

Now we set up the loop to read the server data. Because this will go on indefinitely, we will use an infinite loop.

while 1:
    data = "" # Reset data each time
    while data.find("\n") == -1:
        data += s.recv(1) # Receives data 1 byte at a time
    data = data.strip() # No need for leading or trailing whitespace
    print data
    # Watch for and respond to server pings
    if re.search(r"^PING", data):
        s.send("PONG" + data[4:])

Now you have all the code needed to connect to an IRC server, join a channel and stay connected. A few things to keep in mind. The socket is blocking, so the bot will wait on the recv() until it gets some data. Without blocking the program would be too CPU intensive without some extra work. Also note that printing data will print raw IRC data, which is a lot different than the messages you see in a client, and will include control characters like char 1 and 3. Furthermore, there is no error handling or autojoining should the bot be kicked. This is simply a small and poorly made IRC bot that is to demonstrate what is needed to connect to an IRC and I do not recommend this design as a base for a larger scale bot that will be used more often. Sometime later I will divulge a more robust bot that has the purpose of logging an IRC channel or channels.

Saturday, July 14, 2012

Flip a web page

I know there are a lot of people out there that like messing with others, so I got bored and decided to make a quick little bit of Javascript to do that. This will only work in browsers that support CSS3 and is a bit lengthy because certain browsers need their own special tags. So if you want to flip a page someone is browsing, or maybe even yourself, just enter this code in the address bar of the browser to flip a site:

javascript:document.body.setAttribute("style", "transform:rotate(180deg);-ms-transform:rotate(180deg);-moz-transform:rotate(180deg);-webkit-transform:rotate(180deg);-o-transform:rotate(180deg);");void(0);

It's as simple as that, the page should be flipped. Also, here's a link to do it, you can set it as a bookmark to make a bookmarklet: flip

Thursday, June 28, 2012

MyBB Registered-only view BBCode

Decided to make another quick MyBB addon, this adds some BBCode. You can use [paranoid][/paranoid] tags to prevent non-registered and banned members from viewing stuff selectively. I am using it to cover up various resource links. If you are logged in, it will appear like nothing is changed, you can only tell what's covered up by logging out or being banned.

[Download v1.0]

Maintained: https://github.com/anarchywolf46/MyBB-Plugins

Friday, June 22, 2012

Firebug Quick Info (remove)

One of the things that has been annoying me on firebug, is the quick info popup. It's always in the way. So I looked up how to disable it because I didn't have a clue where the options where. In my version of firefox, under Tools > Web Development > Firebug > Options and clicked to uncheck the "Quick Info" option. I think on older versions it was just under the Tools menu. Either way, if you didn't know how to do that, now you know.

Friday, June 15, 2012

Python Lambda Intro (with simple example)

While really a simple thing to do, I wanted to post an example of a very simple program using something a little less common. Instead of the more common way of making a function, I will instead use lambda. In Python, lambda is used for passing an anonymous functions to a method or can be used to have a function generate simple functions. For the latter, decorators can be used for a more complex function generation, however I have yet to fully grasp using it, so I'll save explaining that for when I know how to practically use it.

Now anonymous functions are cool because you can either pass them to a function without creating some permanent function that will only be used in that one particular instance or you can pass it to a variable reference. Passing to variable reference is as simple as defining any variable. The difference in this particular instance is that lambda is limited to very simple functions, and returning variables is not as clear as a return statement. Let's view a quick example.

import sys

ftoc = lambda(f): (f-32.0)*(5.0/9.0)
ctof = lambda(c): (9.0/5.0)*c+32.0

while(1):
    try:
        print """Pick a conversion (EOF to end ctrl+z win/ctrl+c *nix)
1 - Fahrenheit to Celsius
2 - Celsius to Fahrenheit
3 - Exit

>""",
        choice = raw_input()

        if choice == 3:
            break;
        else:
            print "What is the tempurature?",
            temp = raw_input()
            if choice == "1":
                print str(ftoc(float(temp)))+" Celsius"
            elif choice == "2":
                print str(ctof(float(temp)))+" Fahrenheit"
            else:
                print "Unknown option"

    except KeyboardInterrupt:
        break;

    except Exception as e:
        print "An error occured: "+str(e)
print "Goodbye."
exit(0)


The main point to focus on is the 2 lines following the import statements. To break it down, ftoc = lambda(f): (f-32.0)*(5.0/9.0) is actually very simple. It starts out with a normal variable declaration, variable name being ctof. We then assign it to the value of the lambda statement. The word lambda in Python means an anonymous function, then the (x) is the arguments the function accepts. This does not need to be in parenthesis can could just as easily be lambda x:. I use the parentheses to more clearly show that it's not the function name, but arguments being passed to it, I find it to be more clear for myself reading it. The next part is just a formula for converting the temperature. The question may arise, where is the return value? Quite simply, it's whatever the code in the lambda statement evaluates to at the very end.

Now some caveats. Lambda functions cannot span multiple lines, it's only a 1 liner function (with the exception being if a docstring is used). It also supports nested scope, so if it is within a scope where it uses a variable name, it will use that variable, however if the variable is the name of an argument variable, that value will be used instead. Finally, semicolons are ending delimiters and cannot be used to include multiple lines of code, it is only a single statement.

One more little catch I ran into, while I doubt anyone has a need for it, trying to define a list of lambda functions through list comprehension will not work to make different functions. Using something like y = [lambda (x): x+z for z in range(10)] will result in all 10 list items having z as 9 because it will use z as a reference to z and not replace the value, therefore the last value of z is the one that is used. However, if you replace the lambda function with a function that returns lambda functions, it works, and looks like this.

def a(x):
    return lambda(y): x+y

y = [a(z) for z in range(10)]


I was also informed of an alternative way to do this through default values, which looks a little uglier, but can condense things if you really want to. You can do something like y = [(lambda x, z=z: x+z) for z in range(10)], which will place the value of z as the default argument. Note however, that since it is a default argument, it can then be changed, which does not seem like a clean solution.