AIM TOC protocol foundation
Posted by Parasite-FT-
Friday, July 23, 2004
Description: a foundation for a full-blown AIM script
A lot of people have decided to give the AOL Instant Messenger protocol a shot, but for understandable reasons quite a few people have had difficulties with it all. I'm not using OSCAR (it changes too often and is quite unneccessary), instead I'm using the TOC protocol which is a level above OSCAR.
You can find an AIM script from ms.org, but it's riddled with bugs and the coding is incomprehensible (and, if you ask me, it's pretty sloppy). My aim is to create a foundation for other people to create a GUI with - that is, this should end up being just a backbone for you to put a nice interface on. We shall see.
Feel free to add on to this or modify it as you like - hopefully I added enough comments (prolly too much in fact), but if you have any questions feel free to ask.
Note: this is using binvars pretty heavily, you should prolly get accustomed to using those first before attempting to edit this.
Changes log:
July 24, 2004 - I just added this so there are still echo's in it for debugging purposes. The login is now complete below, however nothing else has been added yet.
July 25, 2004 - The login bug was fixed. Also added the ability to recieve messages. Decided upon using an 'API'; a series of aliases acting as an interface for people to build upon this without editing it.
July 25, 2004 - Major changes; optimized roaster, added ability to message, format nick, warn people, receive messages, get info from users, change password, set/remove away message. Moved everything that wasn't part of the core protocol out of the file, will make a help file to explain integration with scripts.
July 26,2004 - Added ability to get user profiles and display them in a picwin for a sample GUI. the core itself is near completion.
August 8, 2004 - Changed the interface, and added some features to the protocol foundation. Still looking to finish a picwin scrollbar, then i'll integrate it into the GUI and be ready to finish the damned thing.
This is an example script that should integrate with the core protocol above - under construction
A lot of people have decided to give the AOL Instant Messenger protocol a shot, but for understandable reasons quite a few people have had difficulties with it all. I'm not using OSCAR (it changes too often and is quite unneccessary), instead I'm using the TOC protocol which is a level above OSCAR.
You can find an AIM script from ms.org, but it's riddled with bugs and the coding is incomprehensible (and, if you ask me, it's pretty sloppy). My aim is to create a foundation for other people to create a GUI with - that is, this should end up being just a backbone for you to put a nice interface on. We shall see.
Feel free to add on to this or modify it as you like - hopefully I added enough comments (prolly too much in fact), but if you have any questions feel free to ask.
Note: this is using binvars pretty heavily, you should prolly get accustomed to using those first before attempting to edit this.
Changes log:
July 24, 2004 - I just added this so there are still echo's in it for debugging purposes. The login is now complete below, however nothing else has been added yet.
July 25, 2004 - The login bug was fixed. Also added the ability to recieve messages. Decided upon using an 'API'; a series of aliases acting as an interface for people to build upon this without editing it.
July 25, 2004 - Major changes; optimized roaster, added ability to message, format nick, warn people, receive messages, get info from users, change password, set/remove away message. Moved everything that wasn't part of the core protocol out of the file, will make a help file to explain integration with scripts.
July 26,2004 - Added ability to get user profiles and display them in a picwin for a sample GUI. the core itself is near completion.
August 8, 2004 - Changed the interface, and added some features to the protocol foundation. Still looking to finish a picwin scrollbar, then i'll integrate it into the GUI and be ready to finish the damned thing.
;http://gridley.res.carleton.edu/~straitm/final/howto_signon.html
;http://www-eleves-isia.cma.fr/Doc/packages/kaim/PROTOCOL
;; =========================================================
;; Connection aliases
;; Function: connects to the TOC server
;; Usage: /aim.connect <username> <password>
alias aim.connect {
sockclose aim
;::: toc.oscar.aol.com isn't very stable I find - but this host works great methinks
var %host = 64.12.163.175, %port = 1024
;::: cycle through port numbers until a free one is reached
while (!$portfree(%port)) { inc %port }
sockopen aim %host %port
aim.add username $1
aim.add password $$2
aim.add sequence_number 1
}
;; Function: disconnects from the TOC server
;; Usage: /aim.disconnect
alias aim.disconnect { sockclose aim }
;; Function: parses the server reply
;; Usage: /aim.parse <&binvar>
;; Comments: prolly the messiest alias here, but when was parsing ever clean?
alias -l aim.parse {
;::: loop through the all the FLAP segments provided (multiple data segments often sent in one packet)
while (1) {
var %type = $aim_flap($1).type
var %length = $aim_flap($1).len
var %number = $aim_flap($1).number
;::: make a binvar to hold ONLY the current FLAP segment data (no header)
if (%length > 0) bcopy -c &flap_data 1 $1 7 %length
;::: debug information
if ($isalias(aim.API_debug)) {
aim.API_debug Flap type: %type
aim.API_debug Flap length: %length
aim.API_debug Flap number: %number
aim.API_debug Flap data: $bvar(&flap_data,1,$bvar(&flap_data ,0))
}
;::: send to the redirect alias
aim.redirect %type &flap_data
;::: crop the binvar to remove the segment we just used
if ($bvar($1,0) > $calc(%length + 7)) bcopy -c $1 1 $1 $calc(%length + 7) -1
;::: check to see if we've looped till the end of the data (%length + 7 is amount of bytes in data + header)
else break
}
}
;; Function: redirects data to the proper event handler
;; Usage: /aim.redirect <FLAP type> <&binvar holding data>
alias aim.redirect {
var %type = $1, %data = $2
;::: login data
if (%type == 1) aim.login
;::: handle all other data
elseif (%type == 2) {
;::: find the first colon in the binvar and retrieve the item name for event handling
var %item_end = $calc($bfind(%data,1,58) - 1)
var %item = $bvar(%data,1,%item_end).text
;::: crop out the item name from the data
bcopy -c %data 1 %data $calc(%item_end + 2) -1
;::: redirect to event handlers
if (%item == SIGN_ON) aim.on_login
elseif (%item == NICK) aim.on_nick %data
elseif (%item == CONFIG) aim.on_config %data
elseif (%item == ERROR) aim.on_error %data
elseif (%item == IM_IN) aim.on_message %data
elseif (%item == GOTO_URL) aim.on_getinfo %data
elseif (%item == UPDATE_BUDDY) aim.on_buddy %data
elseif (%item == EVILED) aim.on_warn %data
}
;::: Connection terminated event
elseif (%type == 4) aim.on_terminate
;::: PING-PONG event
elseif (%type == 5) aim.on_ping
}
;; Function: creates/sends the required login information
;; Usage: /aim.login
;; Comments: This is a two part login. First send the SIGNON message, followed by the "toc_signon" message.
;; For the sake of simplicity I'll send both messages from this one alias.
;; Sadly these values must be sent using a binvar so it may look confusing but it's quite straightforward
alias -l aim.login {
var %password = $aim_roast($aim_get(password))
var %username = $aim_normalize($aim_get(username))
var %sequence_number = $aim_get(sequence_number)
;::: send a FLAP SIGNON message
;-----------------------------------------
;::: FLAP version with value of '1' (4 bytes)
bset &login_flap 1 0 0 0 1
;::: TLV tag with value of '1' (2 bytes)
bset &login_flap 5 0 1
;::: username length (2 bytes)
bset &login_flap 7 0 $len(%username)
;::: username value (specified length)
bset -t &login_flap 9 %username
var %login_flap = $aim_buildflap(1,&login_flap)
sockwrite aim %login_flap
;::: send a "toc_signon" message
;----------------------------------------
;::: cycle through port numbers until a free one is reached
var %port = 29999
while (!$portfree(%port)) { inc %port }
;::: toc_signon <authorizer host> <authorizer port> <User Name> <Roasted Password> <language> <version>
bset -t &toc_signon 1 toc_signon login.oscar.aol.com %port %username %password English $+("mIRC,TIC,")
;::: create a FLAP header for &toc_signon (type 2 for some reason)
var %flap = $aim_buildflap(2,&toc_signon).null
;::: send the data
sockwrite aim [ [ %flap ] ]
}
;; Function: sends the specified string to the TOC server
;; Usage: /aim.out <text>
alias aim.out {
bunset &output
bset -t &output 1 $1-
var %output = $aim_buildflap(2,&output).null
if ($sock(aim)) sockwrite aim %output
if ($isalias(aim.API_debug)) {
aim.API_debug Output [byte format]: $bvar(%output,1,$bvar(%output,0))
aim.API_debug Output [text format]: $bvar(%output,7,$bvar(%output,0)).text
}
}
;; =========================================================
;; Connection events
;; Function: establishes an initial connection
on *:sockopen:aim: {
if ($sockerr) return
sockwrite -n $sockname FLAPON
sockwrite -n $sockname
}
on *:sockread:aim: {
sockread &temp
aim.parse &temp
}
;; Function: retrieves the information for a getinfo
on *:sockopen:aim.getinfo.*: {
sockwrite -n $sockname GET / $+ $sock($sockname).mark HTTP/1.1
sockwrite -n $sockname HOST: 64.12.163.175
sockwrite -n $sockname Connection: close
sockwrite -n $sockname
}
on *:sockread:aim.getinfo.*: {
sockread &temp
;::: crop out the header information
bcopy -c &temp 1 &temp $calc($bfind(&temp,1,10 13) + 3) -1
if ($isalias(aim.API_debug)) aim.API_debug Incoming getinfo response: $bvar(%output,1,$bvar(%output,0))
if ($isalias(aim.API_getinfo)) aim.API_getinfo &temp
}
;; =========================================================
;; event handlers
;; Function: handles the CONFIG request by TOC server (buddy list)
;; Usage: /aim.on_config <&binvar>
alias -l aim.on_config {
var %end_byte = 1, %item
;::: loop through all the buddy's in the list (tokens delimited by chr 10)
while ($bfind($1,1,10)) {
%end_byte = $ifmatch
;::: grab the buddy/group name; spans bytes 1 through %end_byte - 1
%item = $bvar($1,1,$calc(%end_byte - 1)).text
;::: parse out the type and name from the item (item looks like: g Group, or, b Buddyname)
var %item_type = $gettok(%item,1,32), %item_name = $gettok(%item,2-,32)
;::: send information to the API
if ($isalias(aim.API_createbuddylist)) aim.API_createbuddylist %item_type %item_name
;::: check to see if user is online or not
if (%item_type == b) aim.out toc_add_buddy %item_name
;::: if the end-of-data has not yet been reached, crop the current information from the binvar
if ($calc(%end_byte + 1) < $bvar($1,0)) bcopy -c $1 1 $1 $calc(%end_byte + 1) -1
;::: once the loop has exceeded all the available data, break from the loop
else break
}
}
;; Function: catches a message from a user
;; Usage: /aim.on_message <&binvar>
alias -l aim.on_message {
;::: the user is between 1 and the first chr 58 found
var %user = $bvar($1,1,$calc($bfind($1,1,58) - 1)).text
;::: the automated response value is 1 char after the length of username + 2; T or F
var %automated_response = $bvar($1,$calc($len(%user) + 2),1).text
;::: crop the message from the original binvar
bcopy -c $1 1 $1 $calc($len(%user) + 4) -1
if ($isalias(aim.API_incomingmessage)) aim.API_incomingmessage $+(%user,:,%automated_response,:,$1)
}
;; Function: catches a response to a getinfo for the user
;; Usage: /aim.on_getinfo <&binvar>
;; Comments: open a new connection to send a basic HTTP request for the URL that is given by the response
alias -l aim.on_getinfo {
;::: format for response is TIC:<relative url> - the response is small enough to use .text prop of $bvar
var %url = $gettok($bvar($1,1,$bvar($1,0)).text,2,58)
var %socket = aim.getinfo. $+ $ticks
sockopen %socket 64.12.163.175 80
sockmark %socket %url
}
;; Function: shows a users updated status/shows a user if online/offline
;; Usage: /aim.on_buddy <&binvar>
alias -l aim.on_buddy {
;::: format: UPDATE_BUDDY:<Buddy User>:<Online? T/F>:<Evil Amount>:<Signon Time>:<IdleTime>:<UC>
var %text = $bvar($1,1,$bvar($1,0)).text, %args = $gettok(%text,-1,58)
;::: check to see if user is on AOL network
var %onAOL = $iif($mid(%args,1,1) == A,$true)
;::: check to see if the user has normal or unconfirmed internet type (admin type is skipped, i'm lazy)
var %connection = $iif($mid(%args,1,1) == O,normal,unconfirmed)
;::: check to see if the user has an away message
var %away = $iif($mid(%args,2,1) == U,$true)
;::: replace the UC param with it's parsed meanings, each delimited by :
var %newparams = $puttok(%text,$+(%onAOL,:,%connection,:,%away),6,58)
if ($isalias(aim.API_debug)) aim.API_debug Update buddy: %newparams
if ($isalias(aim.API_updatebuddy)) aim.API_updatebuddy %text
}
alias -l aim.on_warn {
;::: format: <new evil>:<name of eviler, blank if anonymous>
var %text = $bvar($1,1,$bvar($1,0)).text
tokenize 58 %text
if ($isalias(aim.API_warn)) aim.API_warn $1 $2
}
;; Function: complete the login sequence
;; Usage: /aim.on_login
alias aim.on_login {
;::: required for everyone to see that you're online
aim.out toc_add_buddy ''
;::: completes the login sequence
.timer 1 1 aim.out toc_init_done
}
;; Function: stores what your current nick is formatted like
;; Usage: /aim.on_nick <&binvar holding nick>
alias -l aim.on_nick {
var %nick = $bvar($1,1,$bvar($1,0)).text
aim.add nick %nick
}
;; Function: keep the connection alive
;; Usage: /aim.on_ping
alias -l aim.on_ping { if ($isalias(aim.API_debug)) aim.API_debug PING: PONG! }
;; Function: terminate the connection
;; Usage: /aim.on_terminate
alias -l aim.on_terminate {
if ($isalias(aim.API_debug)) aim.API_debug Connection: terminated
if ($isalias(aim.API_disconnect)) aim.API_disconnect
}
;; Function: when the server throws an error send an error message to the API
;; Usage: /aim.on_error <&binvar>
alias -l aim.on_error {
if (!$isalias(aim.API_error)) return
var %message = $bvar($1,1,$bvar($1,0)).text
tokenize 58 %message
;::: General Errors
if ($1 == 901) aim.API_error $2- not currently available
elseif ($1 == 902) aim.API_error Warning of $2- not currently available
elseif ($1 == 903) aim.API_error A message has been dropped, you are exceeding the server speed limit
;::: Admin Errors
elseif ($1 == 911) aim.API_error Error validating input
elseif ($1 == 912) aim.API_error Invalid account
elseif ($1 == 913) aim.API_error Error encountered while processing request
elseif ($1 == 914) aim.API_error Service unavailable
;::: Chat Errors
elseif ($1 == 950) aim.API_error Chat in $2- is unavailable.
;::: IM & Info Errors
elseif ($1 == 960) aim.API_error You are sending message too fast to $2-
elseif ($1 == 961) aim.API_error You missed an im from $2 because it was too big.
elseif ($1 == 962) aim.API_error You missed an im from $2 because it was sent too fast.
;::: Auth errors
elseif ($1 == 980) aim.API_error Incorrect nickname or password.
elseif ($1 == 981) aim.API_error The service is temporarily unavailable.
elseif ($1 == 982) aim.API_error Your warning level is currently too high to sign on.
elseif ($1 == 983) aim.API_error You have been connecting and disconnecting too frequently. Wait 10 minutes and try again. If you continue to try, you will need to wait even longer.
elseif ($1 == 989) aim.API_error An unknown signon error has occurred $2-
}
;; =========================================================
;; Auxiliary aliases
;; Function: retrieves data about the connection
;; Usage: $aim_get(<query>)
alias aim_get {
if (!$hget(aim)) return
return $hget(aim,$$1)
}
;; Function: adds data about the connection
;; Usage: /aim.add <item> <value>
alias aim.add { hadd -m aim $$1 $2 }
;; Function: parses a binvar for FLAP information
;; Usage: $aim_flap(<&binvar>)[.type|.number|.len]
;; Comments: FLAP header is 6 bytes long, data follows
alias aim_flap {
;::: literal asterisk (*) takes up the first byte (1 byte)
;::: frame type (1 byte)
if ($prop == type) return $bvar($1,2)
;::: sequence number (2 bytes)
elseif ($prop == number) return $aim_fromInt16($bvar($1,3,2))
;::: data length (2 bytes)
elseif ($prop == len) return $aim_fromInt16($bvar($1,5,2))
}
;; Function: creates a flap header based on a supplied binvar's information
;; Usage: $aim_buildflap(<frame type>,<binvar holding data>)[.null]
;; Comments: the .null property will add a null character to terminate string
alias aim_buildflap {
bunset &flap
;::: increase the sequence number for the next transmission
aim.add sequence_number $calc($aim_get(sequence_number) + 1)
;::: FLAP header anatomy: [*] [frame type (1 byte)] [sequence number (2 bytes)] [data length (2 bytes)]
bset -t &flap 1 *
bset &flap 2 $1
bset &flap 3 $aim_toInt16($aim_get(sequence_number))
bset &flap 5 $aim_toInt16($bvar($2,0))
;::: add header to data binvar
bcopy &flap 7 $2 1 -1
;::: null terminate if required - also recompute data length value to account for null terminator
if ($prop == null) {
bset &flap $calc($bvar(&flap,0) + 1) 0
bset &flap 5 $aim_toInt16($calc($bvar($2,0) + 1))
}
return &flap
}
;; Function: 'Roasts' a password for use with AIM
;; Usage: $aim_roast(<password>)
;; Comments: Roasting is simply $xor'ing each character of the password with the corresponding
;; character of the roasting string - the roasting string for AIM TOC is 'Tic/Toc'
alias aim_roast {
;::: initialize variables for loop - roasting pass starts with 0x like any hex representation
var %roast = Tic/Toc, %roast_len = 7, %roasted_pass = 0x, %i = 1
;::: loop through each character of the password supplied
while ($asc($mid($1,%i,1))) {
var %char = $ifmatch
;::: grab the ASCII value of the corresponding char from the roasting string
var %roast_char = $asc($mid(%roast,$iif($calc(%i % %roast_len), $ifmatch, %roast_len),1))
;::: XOR the char from the pass from the char from the roasting string
var %xor_char = $xor(%char,%roast_char)
;::: get the hexadecimal value of the XOR'd char
var %hex_char = $base(%xor_char,10,16,2)
;::: concatenate the roasted password
%roasted_pass = %roasted_pass $+ %hex_char
inc %i
}
;::: return the lowercase of the roasted password when completed
return $lower(%roasted_pass)
}
;; Function: "normalizes" a username - removes the spaces and makes lowercase
;; Usage: $aim_normalize(<username>)
alias aim_normalize {
var %username = $remove($1,$chr(32))
return $lower(%username)
}
;; Function: converts from INT16 (2 bytes to 1 byte)
;; Usage: $aim_fromInt16(1 44)
alias aim_fromInt16 { return $calc($gettok($1,1,32) * 256 + $gettok($1,2,32)) }
;; Function: converts to INT16 (1 byte to 2 bytes)
;; Usage: $aim_toInt16(300)
alias aim_toInt16 { return $int($calc($1 / 256)) $calc($1 % 256) }
;; Function: sends a command to get a users info
;; Usage: /aim.getinfo <nickname>
;; Comments: Used in combination with aim.API_handleinfo, which receives the reply from your request
alias aim.getinfo {
aim.out toc_get_info $1
}
;; Function: sets an away message
;; Usage: /aim.away <message>
alias aim.away {
aim.out toc_set_away $+(",$1-,")
}
;; Function: sets an away message
;; Usage: /aim.away <message>
alias aim.back {
aim.out toc_set_away
}
;; Function: sends a message to a user
;; Usage: /aim.message <username> <message>
alias aim.message {
aim.out toc_send_im $1 $+(",$2-,")
}
;; Function: warns a user
;; Usage: /aim.warn <username> <anonymous? $true|false>
alias aim.warn {
aim.out toc_evil $$1 $iif($2,"anon","norm")
}
;; Function: reset idle time
;; Usage: /aim.idle
alias aim.idle {
aim.out toc_set_idle 0
}
;; Function: change password
;; Usage: /aim.changepassword <old password> <new password>
alias aim.changepassword {
aim.out toc_change_passwd $1 $2
}
;; Function: change nickname formatting
;; Usage: /aim.nick <nickname format>
alias aim.nick {
aim.out toc_format_nickname $1-
}
This is an example script that should integrate with the core protocol above - under construction
alias test {
if (%test) {
echo 2 -s *** Test not ready for reconnect
.timer 1 %test test
return
}
inc -z %test 180
aim.connect <username> <password>
}
;; =========================================================
;; GUI section
;; Function: opens up the aim window if not already open
;; Usage: /aim
alias aim {
if (!$window(@aim)) window -el50 @aim
}
;; Function: handles the response for a getinfo request
;; Usage: /aim.API_getinfo <&binvar holding data>
alias aim.API_getinfo {
;::: find the username for this getinfo data
var %start = $calc($bfind($1,1,<TITLE>User Information for).text + 28)
var %end = $calc($bfind($1,1,</TITLE>).text - %start)
var %username = $bvar($1,%start,%end).text
var %window = $+(@profile-,$aim_normalize(%username))
if (!$window(%window)) {
;::: create the window
window -Cpdf +b %window 0 0 250 300
;::: create the bgcolour
drawfill -nrs %window $rgb(face) $color(0) 1 1
;::: create the titlebar
drawtitle -n %window $rgb(face) $rgb(200,200,200) arial 10 $rgb(255,0,0) %username
}
;::: find where the first segment (the user information) ends - ends at next <HTML> tag oddly enough
var %info_end = $calc($bfind($1,7,<HTML>).text - 1)
;::: create binvar to hold user information
bcopy &info 1 $1 1 %info_end
;::: find where the second segment (the user profile) ends
var %profile_end = $calc($bfind($1,%info_end,</HTML>).text - %info_end + 6)
;::: create binvar to hold profile
bcopy &profile 1 $1 $calc(%info_end + 1) %profile_end
aim.displayhtml %window 5 75 240 220 2 arial 10 &profile
}
;; Function: display the HTML info in a specified block of a specified picwin
;; Usage: /aim.displayhtml <window> <x> <y> <w> <h> <padding> <font name> <font size> <&binvar>
;; Comments: x y w h are dimensions to the block you want it to write the data to, font params are
;; for the default font
alias aim.displayhtml {
;::: assign the parameters to variables
var %i = 1, %params = window x y w h padding fname fsize data
while ($gettok(%params,%i,32)) { set -l % [ $+ [ $ifmatch ] ] $gettok($1-,%i,32) | inc %i }
var %line_spaces
;::: loop until there's no more tags to find
while ($bfind(%data,1,<).text) {
;::: find the start and end position of the next tag (< and >)
var %start = $ifmatch, %end = $bfind(%data,1,>).text
;::: get the next HTML tag
var %tag = $bvar(%data,%start,$calc(%end - %start + 1)).text
;::: get any text preceeding this tag and remove HTML tags from it
var %text = $nohtml($bvar(%data,1,$calc(%start - 1)).text)
;::: display the text
if (%text) {
;::: derive the RGB value from the HEX colour value - if it's a link, change colour accordingly
var %drawColour = $rgb( [ [ $rgbhtml($iif(%colour,%colour,$iif(%linkcolour,%linkcolour,#000000))) ] ] )
;::: get RGB value of the bg colour of the text - if not bg colour specified for text, use body bgcolour
var %drawBGColour = $rgb( [ [ $rgbhtml($iif(%bgcolour,%bgcolour,%bodybgcolour)) ] ] )
;::: adjust font properties or go w/ defaults
var %drawsize = $calc(%fsize + %size * 2), %drawFace = $iif(%face,$+(",%face,"),%fname)
;::: draw the text and wrap it (also center it if neccessary)
drawwrap -nbrp $+ $iif(%center,x) %window %drawColour %drawBGColour %drawFace %drawSize %x $calc(%y + %line_spaces) %w $calc(%h - %line_spaces) %text
;:: if text text needs to wrap, add more $crlf's to correct for wrapping
if ($wrap(%text,%drawFace,%drawSize,%w,1,0) > 1) inc %line_spaces $calc(%drawSize * $ifmatch)
}
if (<BODY BGCOLOR=*> iswm %tag) {
;::: get background colour for profile
var %bodybgcolour = $remove($gettok($gettok(%tag,2,61),1,62),")
;::: draw the display area
drawbox -fn %window $rgb( [ [ $rgbhtml(%bodybgcolour) ] ] ) %x %y %w %h 0
;::: create a padding around the display area
var %x = $calc(%x + %padding), %y = $calc(%y + %padding), %w = $calc(%w - %padding * 2), %h = $calc(%h - %padding * 2)
}
elseif (<FONT *> iswm %tag) {
;::: get font properties for the next text found
var %regex = $regex(colour,%tag,m~COLOR="([^"]+)"~Sig), %colour = $regml(colour,1)
var %regex = $regex(bgcolour,%tag,m~BACK="([^"]+)"~Sig), %bgcolour = $regml(bgcolour,1)
var %regex = $regex(face,%tag,m~FACE="([^"]+)"~Sig), %face = $regml(face,1)
var %regex = $regex(size,%tag,m~SIZE=(\d+)~Sig), %size = $regml(size,1)
echo 2 -s %tag -- %colour - %bgcolour - %bodybgcolour
}
;::: destroy the current font settings
elseif (%tag == </FONT>) var %colour, %bgcolour, %face, %size
;::: increase the vertical space between the last text and the next text
elseif (%tag == <BR>) inc %line_spaces $calc(%fsize + %size * 2)
;::: change the font colour if a link is found
elseif (<A HREF=*> iswm %tag) var %linkcolour = #0000FF
;::: unset the font colour for link once link ends
elseif (%tag == </A>) var %linkcolour
;::: make the text center/uncentered
elseif (%tag == <center>) var %center = $true
elseif (%tag == </center>) var %center = $false
if ($calc(%end + 1) > $bvar(%data,0)) break
;::: crop out the current segment
bcopy -c %data 1 %data $calc(%end + 1) -1
}
;::: finalize the drawing
drawdot %window
}
menu @profile-* {
sclick: {
if ($inrect($mouse.x,$mouse.y,0,0,$window($active).w,17)) movew $active $mouse.x $mouse.y
}
Close: window -c $active
}
;; =========================================================
;; API section
;; Function: creates a buddy list; stores the buddy names
;; Usage: /aim.API_createbuddylist <item type> <item name>
alias aim.API_createbuddylist {
var %item_type = $1, %item_name = $2
;::: if item is a group, make it the current group
if (%item_type == g) aim.add current_group %item_name
;::: if item is a buddy, add it to the buddy list
elseif (%item_type == b) aim.add $+(buddy_,$aim_get(current_group),_,%item_name)
}
;; Function: updates the buddy list with the current user information
;; Usage: /aim.API_updatebuddy <name> <online> <warn> <sign_on> <idle> <unconfirmed> <unavailable> <on AOL> <connection type> <away: $true|$false>
alias -l aim.API_updatebuddy {
tokenize 58 $1-
var %name = $1, %online = $2, %warn = $3, %sign_on = $4, %idle = $5, %away = $6, %internet = $7
}
;; Function: handles an error message
;; Usage: /aim.API_error <message>
alias aim.API_error {
echo 5 -s Error: $1-
}
;; Function: handles an incoming message
;; Usage: /aim.API_incomingmessage <username>:<automated response [T|F]>:<&binvar holding message>
alias aim.API_incomingmessage {
tokenize 58 $1-
echo 4 -s $1 -- $2 -- $bvar($3,1,$bvar($3,0)).text
}
;; Function: handles the event when you get warned by another user
;; Usage: /aim.API_warn <warn level> <username>
alias -l aim.API_warn {
echo 4 -s you have been warned: $1 $+ % warning level
}
;; Function: handles the debug information
;; Usage: /aim.API_debug <description>:<data>
alias aim.API_debug {
tokenize 58 $1-
echo 4 -s $+($chr(2),$1,$chr(2),:) $2-
}
;; =========================================================
;; Auxiliary aliases
alias readbytes {
var %i = 1, %string
while ($gettok($1-,%i,32)) {
%string = %string $+ $chr($ifmatch)
inc %i
}
return %string
}
;; Function: converts RGB to HEX and vica versa
;; Usage: $rgbhtml(<RGB|HEX>)
;; Comments: "rgb <-> html" by cold @ http://mirc.is.dreaming.org
alias rgbhtml {
if (!$1) return
if (#* !iswm $1) {
tokenize 44 $iif($chr(44) isin $1-, $remove($1-, $chr(32)), $replace($1-, $chr(32), $chr(44)))
var %in = $replace($1-, $chr(32), $chr(44)), %out = $+($chr(35), $base($1, 10, 16, 2), $base($2, 10, 16, 2), $base($3, 10, 16, 2))
}
else {
tokenize 32 $mid($1, 2, 2) $mid($1, 4, 2) $mid($1, 6, 2)
var %in = $remove($+($chr(35), $1-), $chr(32)), %out = $+($base($1, 16, 10, 0), $chr(44), $base($2, 16, 10, 0), $chr(44), $base($3, 16, 10, 0))
}
return %out
}
;; =========================================================
;; Picwin construction aliases
;; Function: Draws wrapped text and optionally centers it in a specified block
;; Usage: /drawwrap [-xybrnp] <window> <colour> <bgcolour> <fontname> <fontsize> <x> <y> <w> <h> <text>
;; Comments: -x and -y params are used to center text horizontally and vertically respectively
alias drawwrap {
; parse parameters
var %params = $iif(-* iswm $1,switches) window colour $iif(-*b* iswm $1,bgcolour) fname fsize x y w h
var %regex = $regex(params,$1-,m~("[^"]+")|([^\s]+)~iSxg), %text, %i = 1
while ($gettok(%params,%i,32)) { set -l % [ $+ [ $ifmatch ] ] $regml(params,%i) | inc %i }
; determine which parameters are text input params
while ($regml(params,%i)) { %text = %text $ifmatch | inc %i }
; loop through the wrapped lines
var %i = 1
while ($wrap(%text,%fname,%fsize,%w,1,%i)) {
var %wrappedtext = $ifmatch
var %text_w = $width(%wrappedtext,%fname,%fsize)
var %text_h = $height(%wrappedtext,%fname,%fsize)
; adjust for horizontal centering (if specified with -x switch)
if (x isletter %switches) var %text_x = $int( $calc( (%w - %text_w) / 2 + %x) )
else var %text_x = %x
; find the offset to adjust for Y space in order to center block of textif (w isletter switches)
if (y isletter %switches) var %center_y = $calc((%h - $wrap(%text,%fname,%fsize,%w,1,0) * %text_h) / 2)
; if the offset is > 0 (the block height < specified height) add the centering offset factor
var %text_y = $calc($iif(%center_y > 0,%center_y) + %text_h * (%i - 1) + %y)
; bound the block of text by the specified height
if ($calc(%text_y + %text_h) > $calc(%h + %y)) break
; draw the bloody text
drawtext $+(-,$remove(%switches,-),c) %window %colour %bgcolour %fname %fsize %text_x %text_y %w $height(%wrappedtext,%fname,%fsize) %wrappedtext
inc %i
}
}
;; vertical scroll drawtext
; Usage: /vsdrawtext -porhn @window <color> <color> [fontname fontsize] <x> <y> <w> <h> <text>
; x y w h are all values of the text area
alias vsdrawtext {
var %switches = $iif(-* iswm $1,1), %i = 1
while ($gettok(window colour bgcolour font fontsize x y w h,%i,32)) { set -l % [ $+ [ $ifmatch ] ] $gettok($1-,$calc(%switches + %i),32) | inc %i }
var %text = $iif(%switches,$11-,$10-), %textheight = $height(%text,%font,%fontsize)
if (!$window(%window)) { echo $color(info) -s * /vsdrawtext: invalid window | return }
elseif (!%text) { echo $color(info) -s * /vsdrawtext: invalid parameters | return }
drawscroll $iif(-*n* iswm $1,-n) %window 0 $+(-,%textheight) %x $calc(%y + %textheight) %w %h
drawrect -fr %window %bgcolour 0 %x $calc(%y + %h - %textheight) %w %textheight
drawtext -bc $+ $remove($iif(%window == $2,$1),-) %window %colour %bgcolour %font %fontsize %x $calc(%y + %h - %textheight) %w %textheight %text
}
;; Draws a titlebar onto top of window
; usage: /drawtitle -n <@window> <bgcolour> <title colour> <font name> <font size> <font colour> <text>
; <bgcolour> is the background colour, <title colour> is the colour of the background for the text
alias drawtitle {
var %i = 1, %params = $iif(-* iswm $1,switches) window bgcolour colour fname fsize fcolour
while ($gettok(%params,%i,32)) { set -l % [ $+ [ $ifmatch ] ] $gettok($1-,%i,32) | inc %i }
var %text = $iif(%switches,$8-,$7-)
; colour the background of the titlebar
drawbox -nf %window $rgb(120,120,120) 0 1 $calc($window(%window).w - 3) 16 1
drawbox -n %window 3 2 $calc($window(%window).w - 9) 3 0
drawbox -n %window 3 7 $calc($window(%window).w - 9) 3 0
drawbox -n %window 3 12 $calc($window(%window).w - 9) 3 0
drawbox -nf %window %colour $calc(($window(%window).w / 2) - 50) 3 100 12 0
drawtext -n %window 0 %fname %fsize $calc(($window(%window).w / 2) - 25) 2 %text
if (n !isin %switches) drawdot %window
}
;; draws a box
; usage: /drawbox -nf <window> [colour(RGB)] <x> <y> <w> <h> <1|0>
; the last parameter determines whether box is raised (1) or lowered (0)
alias drawbox {
; parse parameters
var %i = 1, %params = $iif(-* iswm $1,switches) window $iif(-*f* iswm $1,colour) x y w h R
while ($gettok(%params,%i,32)) { set -l % [ $+ [ $ifmatch ] ] $gettok($1-,%i,32) | inc %i }
drawline %switches %window $iif(%R,0,1) 1 %x %y $calc(%x + %w) %y
drawline %switches %window $iif(%R,0,1) 1 %x %y %x $calc(%y + %h)
drawline %switches %window $iif(%R,1,0) 1 $calc(%x + %w) %y $calc(%x + %w) $calc(%y + %h)
drawline %switches %window $iif(%R,1,0) 1 %x $calc(%y + %h) $calc(%x + %w + 1) $calc(%y + %h)
if (%colour) drawrect %switches $+ r %window %colour 0 $calc(%x + 1) $calc(%y + 1) $calc(%w - 1) $calc(%h - 1)
}
;; draws a button
; usage: /drawbutton -n <window> <raised> <colour(RGB)> <x> <y> <w> <h> <font name> <font size> <font colour> <command>:<text>
; <raised>, 1 for up, 0 for down
alias drawbutton {
; parse parameters
var %i = 1, %params = $iif(-* iswm $1,switches) window state colour x y w h fname fsize fcolour
while ($gettok(%params,%i,32)) { set -l % [ $+ [ $ifmatch ] ] $gettok($1-,%i,32) | inc %i }
var %command = $gettok($gettok($1-,$iif(%switches,12-,11-),32),1,58), %text = $gettok($gettok($1-,$iif(%switches,12-,11-),32),2,58)
var %width = $width(%text,%fname,%fsize), %height = $height(%text,%fname,%fsize), %center_x = $calc(%x + (%w - %width) / 2)
; draw button
drawbox -nf %window %colour %x %y %w %h %state
drawtext -cnr %window %fcolour %fname %fsize $iif(%center_x < %x,%x,%center_x) $calc(%y + (%h - %height) / 2) %w %height %text
if (n !isin %switches) drawdot %window
; add button info to hash table
hadd -m %window button. $+ $calc($hfind($active,button.*,0,w) + 1) %x %y %w %h %state %command
}
;; Function: Drags active window
;; Usage: /movew <@window> <x> <y>
;; Comments: from ^Andy at ms.org
alias movew {
if ($mouse.key & 1) && ($window($1)) {
window $1 $calc($mouse.dx - $2) $calc($mouse.dy - $3)
.timermove_ $+ $1 -o 1 0 movew $1-
}
}