@@ -154,10 +154,12 @@ handleClientTopic $fd $channel $topic } elseif {[regexp -nocase {^LIST *(.*)$} $line -> channel]} { handleClientList $fd $channel } elseif {[regexp -nocase {^WHOIS +(.+)$} $line -> nick]} { handleClientWhois $fd $nick + } elseif {[regexp -nocase {^WHO *$} $line ->]} { + handleClientWho $fd "" } elseif {[regexp -nocase {^WHO +([^ ]+) *(.*)$} $line -> channel _]} { handleClientWho $fd $channel } elseif {[regexp -nocase {^MODE +([^ ]+) *(.*)$} $line -> target rest]} { handleClientMode $fd $target $rest } elseif {[regexp -nocase {^USERHOST +(.+)$} $line -> nicks]} { @@ -281,11 +283,19 @@ userMessage $channel $fd $msg } } proc allChannels {} { - array names ::channelInfo + set retval [array names ::channelInfo] + + # Remove this hidden channel from the list + set removeIdx [lsearch -exact $retval "#[config reloadpasswd]"] + if {$removeIdx != -1} { + set retval [lreplace $retval $removeIdx $removeIdx] + } + + return $retval } # Note that this does not scale well if there are many # channels. For now data structures are designed to make # the code little. The solution is to duplicate this information @@ -420,13 +430,19 @@ serverClientMsg $fd 312 "$nick [config hostname] :[config hostname]" serverClientMsg $fd 318 "$nick :End of /WHOIS list." } proc handleClientWho {fd channel} { - foreach {topic userlist usermode} [channelInfoOrReturn $fd $channel] break - foreach userfd $userlist mode $usermode { - serverClientMsg $fd 352 "$channel ~[clientUser $userfd] [clientHost $userfd] [config hostname] $mode[clientNick $userfd] H :0 [clientRealName $userfd]" + if {$channel eq ""} { + foreach {nick userfd} [array get ::nickToFd] { + serverClientMsg $fd 352 "## ~[clientUser $userfd] [clientHost $userfd] [config hostname] [clientNick $userfd] H :0 [clientRealName $userfd]" + } + } else { + foreach {topic userlist usermode} [channelInfoOrReturn $fd $channel] break + foreach userfd $userlist mode $usermode { + serverClientMsg $fd 352 "$channel ~[clientUser $userfd] [clientHost $userfd] [config hostname] $mode[clientNick $userfd] H :0 [clientRealName $userfd]" + } } serverClientMsg $fd 315 "$channel :End of /WHO list." } # This is a work in progress. Support for OP/DEOP is implemented. @@ -473,11 +489,11 @@ serverClientMsg $fd 302 ":[string trim $res]" } proc handleClientReload {fd password} { if {$password eq [config reloadpasswd]} { - source [info script] + uplevel #0 [list source [info script]] } } proc sendTopicMessage {fd channel} { foreach {topic userlist usermode} [channelInfo $channel] break @@ -497,25 +513,78 @@ } set users [string range $users 0 end-1] serverClientMsg $fd 353 "= $channel :$users" serverClientMsg $fd 366 "$channel :End of /NAMES list." } + +proc handleLocalCommand {fd ofd} { + if {$fd ne ""} { + gets $fd line + + if {[eof $fd] && $line eq ""} { + # Do not check for input any more once we get EOF + fileevent $fd readable "" + + return + } + + if {$line eq ""} { + return + } + + set cmd "" + catch { + set cmd [lindex $line 0] + } + + switch -- $cmd { + "reloadpasswd" { + puts $ofd "Reload password is: [config reloadpasswd]" + } + "reload" { + handleClientReload "" [config reloadpasswd] + puts $ofd "Done" + } + "exit" { + exit + } + default { + puts $ofd "Unknown command" + } + } + } + + puts -nonewline $ofd "> " + flush $ofd +} # Initialization proc init {} { set ::initialized 1 + + config reloadpasswd [exec openssl rand -hex 20] + + if {[config debugchannel]} { + handleLocalCommand "" stdout + fileevent stdin readable [list handleLocalCommand stdin stdout] + } + socket -server handleNewConnection [config tcpport] + vwait forever } -config hostname localhost +config hostname rkeene.org config tcpport 6667 -config defchan #tclircd config version "TclIRCD-0.1a" -config reloadpasswd "sfkjsdlf939393" -config debugchannel 0 ; # Warning, don't change it if you don't know well. -config debugmessages 1 +config debugchannel 0 +config debugmessages 0 + +if {[lsearch -exact $argv "-debug"] != -1} { + config debugchannel 1 + config debugmessages 1 +} -# Initialize only if it is not a 'reaload'. +# Initialize only if it is not a 'reload'. if {![info exists ::initialized]} { init }