[Richard Suchenwirth] 2007-01-31 - The code of [picoIRC 0.2] is sweet and short, but a user asked for explanations on how and why things are done. So, here goes: [http://mini.net/files/irc.gif] # We will use the [Tk] GUI toolkit, so best tell it early on package require Tk # Set some parameters (user may want to modify these) set ::server irc.freenode.org set ::chan #tcl set ::me $tcl_platform(user) # The GUI consists mostly of a [text] widget: text .t -height 30 -wrap word -font {Arial 9} # Some tags to make emphasized strings look nicer: .t tag config bold -font [linsert [.t cget -font] end bold] .t tag config italic -font [linsert [.t cget -font] end italic] .t tag config blue -foreground blue # Second UI element is an [entry] widget for typing messages entry .cmd # Brought to screen by [pack] (entry first, so it doesn't disappear on resizing) pack .cmd -side bottom -fill x pack .t -fill both -expand 1 # When is hit in the entry, the command ''post'' is executed bind .cmd post # But first for the receiving proc, which is called when the socket has new content: proc recv {} { gets $::fd line ;#-- read a line from socket # handle PING messages from server if {[lindex [split $line] 0] eq "PING"} { send "PONG [info hostname]" return } #-- Add some markup for messages and actions if {[regexp {:([^!]*)![^ ].* +PRIVMSG ([^ :]+) +:(.*)} $line -> \ nick target msg]} { set tag "" if [regexp {\001ACTION(.+)\001} $msg -> msg] {set tag italic} #-- suppress the names of two well-known bridge bots if [in {azbridge ijchain} $nick] {regexp {<([^>]+)>(.+)} $msg -> nick msg} #-- Display nick in bold, message as tagged above .t insert end $nick\t bold $msg\n $tag } else {.t insert end $line\n italic} #-- make sure the last part is visible .t yview end } # Just a little helper to check list membership proc in {list element} {expr {[lsearch -exact $list $element]>=0}} # This command is called on proc post {} { set msg [.cmd get] ;#-- read what was typed in the entry #-- Lines beginning with /me are marked as actions: if [regexp {^/me (.+)} $msg -> action] {set msg "\001ACTION $action\001"} #-- Multiple lines (as e.g. from pasting) are sent one by one: foreach line [split $msg \n] {send "PRIVMSG $::chan :$line"} .cmd delete 0 end ;#-- clear the entry #-- the sent message is locally reported in the text, with possible markup set tag "" if [regexp {\001ACTION(.+)\001} $msg -> msg] {set tag italic} .t insert end $::me\t {bold blue} $msg\n [list blue $tag] #-- make sure the end of the text widget is visible .t yview end } # A very simple wrapper for sending a string, not forgetting to [flush] proc send str {puts $::fd $str; flush $::fd} # And now, the action begins with "logging in" to the IRC server set ::fd [socket $::server 6667] send "NICK $::me" send "USER $::me 0 * :PicoIRC user" send "JOIN $::chan" # If the [socket] gets readable, ''recv'' will be called fileevent $::fd readable recv # This is just a convenient debugging helper for rapid restart after changes bind . {exec wish $argv0 &; exit} ---- How does this script deal with the ping-pong requirements of an IRC server? Is that handled by the socket itself? [RS]: The script as above worked nicely from home (at work, IRC is blocked). I think I remember timeouts if I wasn't chatting for a while, but I'm not an IRC specialist anyway... Who knows better, please let us know! [MJ] - The handling of the PING request has been added to the script. Regarding that particular segment of code; send "PONG [info hostname]" can someone explain the [info hostname] command to me? [LV] Did you read the wiki page to which you referred? Basically, every computer has some sort of name - info hostname returns that name. No I didn't read that page... posted the question without even looking at it afterwards. Many thanks to you all though! You've been very helpful! ---- Alternatively, some servers send ping requests with a unique key that must be returned. (a rawlog excerpt from xchat on irc.sorcery.net: "<< PING LAG2509966063 >> :nebula.sorcery.net PONG nebula.sorcery.net :LAG2509966063 ") In that case, the following replacement of the server code can suffice (if not, please edit.) if {[lindex [split $line] 0] eq "PING"} { send "PONG [lindex [split $line] 1]" #--sorcery sends a 'key' that must be returned to the server in order to maintain connection# return ---- [Category Example]