Haskell AIM Client – a cool proof of concept

Haskell has been my favorite programming language in the past month, and for good reason. Its (purely) functional and has strong, static typing.

The language feels more graceful to me, where design and function are key. It is a joy to program in and I would love to keep exploring it.

On my path to learning a new language, I usually try to implement something to get some real-world experience. In this instance, I have chosen to implement an Open AIM client. AIM operates on the legacy TOC(text based) protocol, or the feature full OSCAR protocol, which is what most AIM clients use. I decided that OSCAR would be more fun to do, especially with the three step login process.

The client that I wrote is very simple — handles login to AIM and just sits there. It can get IM’s though. The bulk of the AIM client that I enjoyed writing was the protocol handlers, and implementing the login process.

It would be very easy to extend this client to be a bot, if you are looking for a practical use for it. For me, the learning experience is enough.

The main function is listed below.

start_aim = do
	putStrLn "Haskell AIM Client - OSCAR Protocol"
	appKey <- getAppKey
	screenName <- getScreenName
	password <- getPassword
	let clientInfo = AIMClientInfo 1 "HaskellClient" appKey
	result <- aim_open_auth clientInfo screenName password
	case result of
		Just info -> do
			boss_result <- aim_boss_session clientInfo info
			case boss_result of
				Just si -> aim_oscar_login si
				Nothing -> putStrLn "Unable to authenticate with BOSS server."
		Nothing -> return ()

If you want to try out this AIM client, you must have an Open AIM Developer key.

The first step is to download the source and use cabal to configure, build, and install it.

# wget http://www.moostrax.com/cmoos/haim.tar.gz
# tar -xzf haim.tar.gz
# cd haim
# cabal configure && cabal build && cabal install

And then run it.

# ~/.cabal/bin/haim

The output will look something like this:

Haskell AIM Client - OSCAR Protocol
An Open AIM Developer key is required: http://developer.aim.com/manageKeys.jsp
Open AIM Key> 
AIM Screen Name> 
AIM Password> 
Connected to AIM server.
Entered OSCAR client loop.
Login accepted by OSCAR server. Setting up rights.
Max Watchers: 2000
Max Buddies: 1000
Max Temp Buddies: 160
Max Denies: 1000

Like I said, the client is very simple, and just sits and waits. When you login you will see some information about your buddy list, and other AIM login data.

Share this post:
  • Digg
  • del.icio.us
  • Facebook
  • Reddit

19 Comments

19 Comments

  1. s73v3r says:

    Seems kind of cool, but forgive someone who hasn’t studied Haskell for asking a silly question: Is there something about Haskell which would not have made this possible or incredibly difficult compared to another language like Python?

    This comment was originally posted on Reddit

  2. xoclipse says:

    The AIM protocol has been implemented in numerous languages, and here is nothing special about using Haskell for this. I suppose "my own proof of concept" may have been a better title :) , as I wanted to see how implementing AIM in Haskell differed from others.

    This comment was originally posted on Reddit

  3. s73v3r says:

    So same reason someone climbs a mountain: "Because its there." Sounds good.

    This comment was originally posted on Reddit

  4. xoclipse says:

    Beautifully said :)

    This comment was originally posted on Reddit

  5. Paczesiowa says:

    needz more maybe monad

    This comment was originally posted on Reddit

  6. *moar

    This comment was originally posted on Reddit

  7. erg says:

    Just for fun, I’ve implemented the Oscar protocol in C# and Factor .76 (never ported it to the current Factor). For the three step login process, the checksum calculation looks like this in Factor: "m3UPFGcH5hmKSv24" "WeakPassword" sha-256 hmac-bytes >base64 >string . "wEOki901gedaIeJbMAy5k+hv4iJgfvshgM+cWtk+s1g=" There’s a generic protocol so you get HMAC calculations for free on every block checksum. There’s also an interleaved checksum protocol (for when I needed SHA1 interleave) that works the same way.

    This comment was originally posted on Reddit

  8. jfredett says:

    very cool, I’ve always wanted to write my own text-mode, scriptable IM client, but I’ve never really wanted to muck around implementing protocols. Any plans to turn this into a library? Maybe some kind of HAIM monad? Or- perhaps bind to other protocols too, HMSN, HJabber, etc? A general HIM monad (Really just Record (login info(s)) + State (connection state(s)) + IO (networking stuff)) would be very cool.

    This comment was originally posted on Reddit

  9. dhjdhj says:

    Of what concept is it proof?

    This comment was originally posted on Reddit

  10. jfredett says:

    that a AIM protocol implementation is feasable and pretty easy — by the looks of it.

    This comment was originally posted on Reddit

  11. dhjdhj says:

    But that’s true with almost any modern language that has the support libraries. I really "want" to like Haskell and I’m struggling to try and "get" it….but I’m not really seeing anything where I can’t respond with "that could be easily done in (pick your favorite language)" Maybe the concurrency stuff….

    This comment was originally posted on Reddit

  12. geezusfreeek says:

    How about being able to express that big main function from the article: start_aim = do putStrLn "Haskell AIM Client – OSCAR Protocol" appKey <- getAppKey screenName <- getScreenName password <- getPassword let clientInfo = AIMClientInfo 1 "HaskellClient" appKey result <- aim_open_auth clientInfo screenName password case result of Just info -> do boss_result <- aim_boss_session clientInfo info case boss_result of Just si -> aim_oscar_login si Nothing -> putStrLn "Unable to authenticate with BOSS server." Nothing -> return () more concisely like: start_aim = do putStrLn "Haskell AIM Client – OSCAR Protocol" clientInfo <- AIMClientInfo 1 "HaskellClient" <$> getAppKey mapM_ (putStrLn "Unable to authenticate with BOSS server" `maybe` aim_oscar_login <=< aim_boss_session clientInfo) =<< uncurry (aim_open_auth clientInfo) =<< liftM2 (,) getScreenName getPassword . At first glance, this looks like nothing more than golfing, but this version really is a matter of being more expressive! Notice how I was able to hide a lot of the implementation details without masking what’s really happening (although admittedly this would be easier to see with a trained eye).

    This comment was originally posted on Reddit

  13. jerf says:

    Pattern matching does have some nice advantages for implementing protocol support. Instead of a series of nested if or case statements, you get a very nice syntax for matching on things that is very powerful. Obviously this is a convenience more than "radical new power", but it is one that can radically shrink the core of your code when the core is protocol processing, so it can be a nice one. Haskell isn’t the only language with pattern matching, of course. Erlang also ends up with a very nice protocol story, with the language’s support for pattern matching and OTP’s support for state machines.

    This comment was originally posted on Reddit

  14. dhjdhj says:

    I don’t know — I can’t read your version….but consise doesn’t mean better….otherwise we’d all still be using C, very obfuscated. I’m all for the abstraction part (and in theory I’m very strongly in favor of strong typing), but pragmatically, I am sure that the same application (AIM Client) could be implemented with Ruby (say), just as consisely.

    This comment was originally posted on Reddit

  15. vegai says:

    Are you kidding?

    This comment was originally posted on Reddit

  16. Peaker says:

    He didn’t use libraries there, I think. He implemented the protocols in there. Also, the stuff that cannot "easily be done in (pick your favorite language)" is not usually in terms of getting functionality working, but in other terms: A) Reliability * Lack of null references, and use of Maybe instead gets rid of NULL pointer problems * Strong type system: Type errors catch a lot more than other languages * Purity: Effects are quarantined, you get a **lot** of reliability guarantees from library API’s that have pure interfaces, that you just can’t get anywhere else. B) Performance: * Extra information about the code can help the optimizer even [exponentially speed up code](http://www.reddit.com/r/programming/comments/8mmcu/i_tried_to_translate_the_ironpython_code_to/) C) Conciseness * Code is simply far shorter. The types that are being automatically inferred allow getting rid of a lot of the code. D) Power * Others’ languages are Haskell’s libraries. In Python, one needs a new interpreter release to get extra functionality like continuations, or support for better exceptions. In Haskell, anyone can just implement it as a library. Augustusson also demonstrates how you can implement C-like and BASIC-like languages in Haskell as simple libraries. * Just yesterday, I created a little proof-of-concept example showing how Haskell’s ContT library can be used to emulate Python generators very closely (I believe it can be near identical, except with more power, as you have full continuations). E) Documentation * Something like Hoogle is not as possible/practical in any other language * Purity again: This time, it helps the types of functions tell the *whole* story, rather than hiding potential effects everywhere.

    This comment was originally posted on Reddit

  17. Peaker says:

    > but consise doesn’t mean better….otherwise we’d all still be using C, In what way is C concise?

    This comment was originally posted on Reddit

  18. sanity says:

    I don’t see the newsworthyness of these "trivial application X implemented in Haskell", the same thing implemented in any other language certainly wouldn’t be newsworthy. I mean, its good to learn a new language by starting with some simple tasks, but its really not necessary to submit every little scrap of code you write to Reddit.

    This comment was originally posted on Reddit

  19. xoclipse says:

    Definitely. Pattern matching is awesome for protocols, and many other things. For me it is becoming a standard feature I want in any language I use.

    This comment was originally posted on Reddit

Leave a Reply

Additional comments powered by BackType