Hex Artifact Content

Artifact e7c9435743d3529ba481f3dd0e26ac0804185547:


0000: 23 20 4d 69 6e 69 6d 61 6c 20 49 52 43 64 20 73  # Minimal IRCd s
0010: 65 72 76 65 72 20 69 6e 20 54 63 6c 0a 23 20 43  erver in Tcl.# C
0020: 6f 70 79 72 69 67 68 74 20 28 43 29 20 32 30 30  opyright (C) 200
0030: 34 20 53 61 6c 76 61 74 6f 72 65 20 53 61 6e 66  4 Salvatore Sanf
0040: 69 6c 69 70 70 6f 20 3c 61 6e 74 69 72 65 7a 40  ilippo <antirez@
0050: 69 6e 76 65 63 65 2e 6f 72 67 3e 0a 0a 23 20 54  invece.org>..# T
0060: 4f 44 4f 0a 23 0a 23 20 43 61 73 65 20 69 6e 73  ODO.#.# Case ins
0070: 65 6e 73 69 74 69 76 65 20 63 68 61 6e 6e 65 6c  ensitive channel
0080: 73 2f 6e 69 63 6b 73 0a 23 20 2d 20 6d 6f 72 65  s/nicks.# - more
0090: 20 61 62 6f 75 74 20 4d 4f 44 45 0a 23 20 2d 20   about MODE.# - 
00a0: 4b 49 43 4b 0a 23 20 2d 20 42 41 4e 0a 23 20 2d  KICK.# - BAN.# -
00b0: 20 46 4c 4f 4f 44 20 4c 49 4d 49 54 0a 23 0a 23   FLOOD LIMIT.#.#
00c0: 20 57 68 65 6e 20 6f 6e 65 20 63 68 61 6e 67 65   When one change
00d0: 73 20 6e 69 63 6b 20 74 68 65 20 6e 6f 74 69 66  s nick the notif
00e0: 69 63 61 74 69 6f 6e 20 73 68 6f 75 6c 64 20 72  ication should r
00f0: 65 61 63 68 20 65 76 65 72 79 0a 23 20 75 73 65  each every.# use
0100: 72 20 6a 75 73 74 20 6f 6e 65 20 74 69 6d 65 2e  r just one time.
0110: 0a 0a 23 20 50 72 6f 63 65 64 75 72 65 73 20 74  ..# Procedures t
0120: 6f 20 67 65 74 2f 73 65 74 20 73 74 61 74 65 0a  o get/set state.
0130: 66 6f 72 65 61 63 68 20 70 72 6f 63 6e 61 6d 65  foreach procname
0140: 20 7b 20 20 63 6f 6e 66 69 67 20 63 6c 69 65 6e   {  config clien
0150: 74 53 74 61 74 65 20 63 6c 69 65 6e 74 48 6f 73  tState clientHos
0160: 74 20 63 6c 69 65 6e 74 4e 69 63 6b 20 63 6c 69  t clientNick cli
0170: 65 6e 74 50 6f 72 74 0a 09 09 20 20 20 20 63 6c  entPort...    cl
0180: 69 65 6e 74 52 65 61 6c 4e 61 6d 65 20 63 6c 69  ientRealName cli
0190: 65 6e 74 55 73 65 72 20 63 6c 69 65 6e 74 56 69  entUser clientVi
01a0: 72 74 75 61 6c 48 6f 73 74 0a 09 09 20 20 20 20  rtualHost...    
01b0: 6e 69 63 6b 54 6f 46 64 20 63 68 61 6e 6e 65 6c  nickToFd channel
01c0: 49 6e 66 6f 7d 20 5c 0a 7b 0a 20 20 20 20 70 72  Info} \.{.    pr
01d0: 6f 63 20 24 70 72 6f 63 6e 61 6d 65 20 7b 6b 65  oc $procname {ke
01e0: 79 20 61 72 67 73 7d 20 5b 73 74 72 69 6e 67 20  y args} [string 
01f0: 6d 61 70 20 5b 6c 69 73 74 20 25 25 70 72 6f 63  map [list %%proc
0200: 6e 61 6d 65 25 25 20 24 70 72 6f 63 6e 61 6d 65  name%% $procname
0210: 5d 20 7b 0a 09 73 77 69 74 63 68 20 2d 2d 20 5b  ] {..switch -- [
0220: 6c 6c 65 6e 67 74 68 20 24 61 72 67 73 5d 20 7b  llength $args] {
0230: 0a 09 20 20 20 20 30 20 7b 0a 09 09 69 66 20 7b  ..    0 {...if {
0240: 5b 69 6e 66 6f 20 65 78 69 73 74 73 20 3a 3a 25  [info exists ::%
0250: 25 70 72 6f 63 6e 61 6d 65 25 25 28 24 6b 65 79  %procname%%($key
0260: 29 5d 7d 20 7b 0a 09 09 20 20 20 20 73 65 74 20  )]} {...    set 
0270: 3a 3a 25 25 70 72 6f 63 6e 61 6d 65 25 25 28 24  ::%%procname%%($
0280: 6b 65 79 29 0a 09 09 7d 20 65 6c 73 65 20 7b 0a  key)...} else {.
0290: 09 09 20 20 20 20 72 65 74 75 72 6e 20 7b 7d 0a  ..    return {}.
02a0: 09 09 7d 0a 09 20 20 20 20 7d 0a 09 20 20 20 20  ..}..    }..    
02b0: 31 20 7b 0a 09 09 73 65 74 20 6e 65 77 76 61 6c  1 {...set newval
02c0: 20 5b 6c 69 6e 64 65 78 20 24 61 72 67 73 20 30   [lindex $args 0
02d0: 5d 0a 09 09 69 66 20 7b 24 6e 65 77 76 61 6c 20  ]...if {$newval 
02e0: 65 71 20 7b 7d 7d 20 7b 0a 09 09 20 20 20 20 63  eq {}} {...    c
02f0: 61 74 63 68 20 7b 75 6e 73 65 74 20 3a 3a 25 25  atch {unset ::%%
0300: 70 72 6f 63 6e 61 6d 65 25 25 28 24 6b 65 79 29  procname%%($key)
0310: 7d 0a 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 20  }...} else {... 
0320: 20 20 20 73 65 74 20 3a 3a 25 25 70 72 6f 63 6e     set ::%%procn
0330: 61 6d 65 25 25 28 24 6b 65 79 29 20 24 6e 65 77  ame%%($key) $new
0340: 76 61 6c 0a 09 09 7d 0a 09 20 20 20 20 7d 0a 09  val...}..    }..
0350: 20 20 20 20 64 65 66 61 75 6c 74 20 7b 72 65 74      default {ret
0360: 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20  urn -code error 
0370: 22 57 72 6f 6e 67 20 23 20 6f 66 20 61 72 67 73  "Wrong # of args
0380: 20 66 6f 72 20 27 63 6f 6e 66 69 67 27 22 7d 0a   for 'config'"}.
0390: 09 7d 0a 20 20 20 20 7d 5d 0a 7d 0a 0a 23 20 49  .}.    }].}..# I
03a0: 6d 70 6c 65 6d 65 6e 74 61 74 69 6f 6e 0a 70 72  mplementation.pr
03b0: 6f 63 20 64 65 62 75 67 20 6d 73 67 20 7b 0a 20  oc debug msg {. 
03c0: 20 20 20 69 66 20 7b 5b 63 6f 6e 66 69 67 20 64     if {[config d
03d0: 65 62 75 67 6d 65 73 73 61 67 65 73 5d 7d 20 7b  ebugmessages]} {
03e0: 0a 09 70 75 74 73 20 24 6d 73 67 0a 20 20 20 20  ..puts $msg.    
03f0: 7d 0a 7d 0a 0a 70 72 6f 63 20 68 61 6e 64 6c 65  }.}..proc handle
0400: 4e 65 77 43 6f 6e 6e 65 63 74 69 6f 6e 20 7b 66  NewConnection {f
0410: 64 20 68 6f 73 74 20 70 6f 72 74 7d 20 7b 0a 20  d host port} {. 
0420: 20 20 20 64 65 62 75 67 20 22 28 24 66 64 29 20     debug "($fd) 
0430: 4e 65 77 20 63 6f 6e 6e 65 63 74 69 6f 6e 20 66  New connection f
0440: 72 6f 6d 20 24 68 6f 73 74 20 3b 3b 20 70 65 65  rom $host ;; pee
0450: 72 3d 20 5b 66 63 6f 6e 66 69 67 75 72 65 20 24  r= [fconfigure $
0460: 66 64 20 2d 70 65 65 72 6e 61 6d 65 5d 22 0a 0a  fd -peername]"..
0470: 20 20 20 20 63 6c 69 65 6e 74 53 74 61 74 65 20      clientState 
0480: 24 66 64 20 55 4e 52 45 47 49 53 54 45 52 45 44  $fd UNREGISTERED
0490: 0a 20 20 20 20 63 6c 69 65 6e 74 48 6f 73 74 20  .    clientHost 
04a0: 24 66 64 20 5b 6c 69 6e 64 65 78 20 5b 66 63 6f  $fd [lindex [fco
04b0: 6e 66 69 67 75 72 65 20 24 66 64 20 2d 70 65 65  nfigure $fd -pee
04c0: 72 6e 61 6d 65 5d 20 31 5d 0a 20 20 20 20 63 6c  rname] 1].    cl
04d0: 69 65 6e 74 48 6f 73 74 20 24 66 64 20 24 68 6f  ientHost $fd $ho
04e0: 73 74 0a 20 20 20 20 63 6c 69 65 6e 74 50 6f 72  st.    clientPor
04f0: 74 20 24 66 64 20 24 70 6f 72 74 0a 20 20 20 20  t $fd $port.    
0500: 63 6c 69 65 6e 74 4e 69 63 6b 20 24 66 64 20 7b  clientNick $fd {
0510: 7d 0a 20 20 20 20 63 6c 69 65 6e 74 55 73 65 72  }.    clientUser
0520: 20 24 66 64 20 7b 7d 0a 20 20 20 20 63 6c 69 65   $fd {}.    clie
0530: 6e 74 56 69 72 74 75 61 6c 48 6f 73 74 20 24 66  ntVirtualHost $f
0540: 64 20 7b 7d 0a 20 20 20 20 63 6c 69 65 6e 74 52  d {}.    clientR
0550: 65 61 6c 4e 61 6d 65 20 24 66 64 20 7b 7d 0a 20  ealName $fd {}. 
0560: 20 20 20 66 63 6f 6e 66 69 67 75 72 65 20 24 66     fconfigure $f
0570: 64 20 2d 62 6c 6f 63 6b 69 6e 67 20 30 0a 20 20  d -blocking 0.  
0580: 20 20 66 69 6c 65 65 76 65 6e 74 20 24 66 64 20    fileevent $fd 
0590: 72 65 61 64 61 62 6c 65 20 5b 6c 69 73 74 20 68  readable [list h
05a0: 61 6e 64 6c 65 43 6c 69 65 6e 74 49 6e 70 75 74  andleClientInput
05b0: 57 72 61 70 70 65 72 20 24 66 64 5d 0a 20 20 20  Wrapper $fd].   
05c0: 20 72 61 77 4d 73 67 20 24 66 64 20 22 4e 4f 54   rawMsg $fd "NOT
05d0: 49 43 45 20 41 55 54 48 20 3a 5b 63 6f 6e 66 69  ICE AUTH :[confi
05e0: 67 20 76 65 72 73 69 6f 6e 5d 20 69 6e 69 74 69  g version] initi
05f0: 61 6c 69 7a 65 64 2c 20 77 65 6c 63 6f 6d 65 2e  alized, welcome.
0600: 22 0a 7d 0a 0a 70 72 6f 63 20 69 72 63 57 72 69  ".}..proc ircWri
0610: 74 65 20 7b 66 64 20 6d 73 67 7d 20 7b 0a 20 20  te {fd msg} {.  
0620: 20 20 63 61 74 63 68 20 7b 0a 09 70 75 74 73 20    catch {..puts 
0630: 24 66 64 20 24 6d 73 67 0a 09 66 6c 75 73 68 20  $fd $msg..flush 
0640: 24 66 64 0a 20 20 20 20 7d 0a 7d 0a 0a 70 72 6f  $fd.    }.}..pro
0650: 63 20 72 61 77 4d 73 67 20 7b 66 64 20 6d 73 67  c rawMsg {fd msg
0660: 7d 20 7b 0a 20 20 20 20 69 72 63 57 72 69 74 65  } {.    ircWrite
0670: 20 24 66 64 20 22 3a 5b 63 6f 6e 66 69 67 20 68   $fd ":[config h
0680: 6f 73 74 6e 61 6d 65 5d 20 24 6d 73 67 22 0a 7d  ostname] $msg".}
0690: 0a 0a 70 72 6f 63 20 73 65 72 76 65 72 43 6c 69  ..proc serverCli
06a0: 65 6e 74 4d 73 67 20 7b 66 64 20 63 6f 64 65 20  entMsg {fd code 
06b0: 6d 73 67 7d 20 7b 0a 20 20 20 20 69 72 63 57 72  msg} {.    ircWr
06c0: 69 74 65 20 24 66 64 20 22 3a 5b 63 6f 6e 66 69  ite $fd ":[confi
06d0: 67 20 68 6f 73 74 6e 61 6d 65 5d 20 24 63 6f 64  g hostname] $cod
06e0: 65 20 5b 63 6c 69 65 6e 74 4e 69 63 6b 20 24 66  e [clientNick $f
06f0: 64 5d 20 24 6d 73 67 22 0a 7d 0a 0a 23 20 54 68  d] $msg".}..# Th
0700: 69 73 20 6a 75 73 74 20 63 61 6c 6c 73 20 68 61  is just calls ha
0710: 6e 64 6c 65 43 6c 69 65 6e 74 49 6e 70 75 74 2c  ndleClientInput,
0720: 20 62 75 74 20 63 61 74 63 68 20 65 76 65 72 79   but catch every
0730: 20 65 72 72 6f 72 20 72 65 70 6f 72 74 69 6e 67   error reporting
0740: 0a 23 20 69 74 20 74 6f 20 73 74 61 6e 64 61 72  .# it to standar
0750: 64 20 6f 75 74 70 75 74 20 74 6f 20 61 76 6f 69  d output to avoi
0760: 64 20 74 68 61 74 20 74 68 65 20 61 70 70 6c 69  d that the appli
0770: 63 61 74 69 6f 6e 20 63 61 6e 20 66 61 69 6c 0a  cation can fail.
0780: 23 20 65 76 65 6e 20 69 66 20 74 68 65 20 65 72  # even if the er
0790: 72 6f 72 20 69 73 20 6e 6f 6e 20 63 72 69 74 69  ror is non criti
07a0: 63 61 6c 2e 0a 70 72 6f 63 20 68 61 6e 64 6c 65  cal..proc handle
07b0: 43 6c 69 65 6e 74 49 6e 70 75 74 57 72 61 70 70  ClientInputWrapp
07c0: 65 72 20 66 64 20 7b 0a 20 20 20 20 69 66 20 7b  er fd {.    if {
07d0: 5b 63 61 74 63 68 20 7b 68 61 6e 64 6c 65 43 6c  [catch {handleCl
07e0: 69 65 6e 74 49 6e 70 75 74 20 24 66 64 7d 20 72  ientInput $fd} r
07f0: 65 74 76 61 6c 5d 7d 20 7b 0a 09 64 65 62 75 67  etval]} {..debug
0800: 20 22 49 52 43 44 20 72 75 6e 74 69 6d 65 20 65   "IRCD runtime e
0810: 72 72 6f 72 3a 5c 6e 24 3a 3a 65 72 72 6f 72 49  rror:\n$::errorI
0820: 6e 66 6f 22 0a 09 64 65 62 75 67 20 22 2d 2d 2d  nfo"..debug "---
0830: 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 22 0a  --------------".
0840: 09 23 20 42 65 74 74 65 72 20 74 6f 20 77 61 69  .# Better to wai
0850: 74 20 6f 6e 65 20 73 65 63 6f 6e 64 2e 2e 2e 20  t one second... 
0860: 74 68 65 20 65 72 72 6f 72 20 6d 61 79 20 62 65  the error may be
0870: 0a 09 23 20 70 72 65 73 65 6e 74 20 62 65 66 6f  ..# present befo
0880: 72 65 20 74 68 61 6e 20 74 68 65 20 72 65 61 64  re than the read
0890: 20 6f 70 65 72 61 74 69 6f 6e 20 61 6e 64 20 74   operation and t
08a0: 68 65 0a 09 23 20 68 61 6e 64 6c 65 72 20 77 69  he..# handler wi
08b0: 6c 6c 20 62 65 20 66 69 72 65 64 20 61 67 61 69  ll be fired agai
08c0: 6e 2e 20 54 6f 20 61 76 6f 69 64 20 74 6f 20 63  n. To avoid to c
08d0: 6f 6e 73 75 6d 65 20 61 6c 6c 0a 09 23 20 74 68  onsume all..# th
08e0: 65 20 43 50 55 20 69 6e 20 61 20 62 75 73 79 20  e CPU in a busy 
08f0: 69 6e 66 69 6e 69 74 65 20 6c 6f 6f 70 20 77 65  infinite loop we
0900: 20 6e 65 65 64 20 74 6f 20 73 6c 65 65 70 20 6f   need to sleep o
0910: 6e 65 20 73 65 63 6f 6e 64 0a 09 23 20 66 6f 72  ne second..# for
0920: 20 65 76 65 72 79 20 65 72 72 6f 72 2e 0a 09 61   every error...a
0930: 66 74 65 72 20 31 30 30 30 0a 20 20 20 20 7d 0a  fter 1000.    }.
0940: 20 20 20 20 72 65 74 75 72 6e 20 24 72 65 74 76      return $retv
0950: 61 6c 0a 7d 0a 0a 70 72 6f 63 20 68 61 6e 64 6c  al.}..proc handl
0960: 65 43 6c 69 65 6e 74 49 6e 70 75 74 20 66 64 20  eClientInput fd 
0970: 7b 0a 20 20 20 20 69 66 20 7b 5b 63 61 74 63 68  {.    if {[catch
0980: 20 7b 66 63 6f 6e 66 69 67 75 72 65 20 24 66 64   {fconfigure $fd
0990: 7d 5d 7d 20 72 65 74 75 72 6e 0a 20 20 20 20 69  }]} return.    i
09a0: 66 20 7b 5b 65 6f 66 20 24 66 64 5d 7d 20 7b 0a  f {[eof $fd]} {.
09b0: 09 68 61 6e 64 6c 65 43 6c 69 65 6e 74 51 75 69  .handleClientQui
09c0: 74 20 24 66 64 20 22 45 4f 46 20 66 72 6f 6d 20  t $fd "EOF from 
09d0: 63 6c 69 65 6e 74 22 0a 09 72 65 74 75 72 6e 0a  client"..return.
09e0: 20 20 20 20 7d 0a 20 20 20 20 69 66 20 7b 5b 63      }.    if {[c
09f0: 61 74 63 68 20 7b 67 65 74 73 20 24 66 64 20 6c  atch {gets $fd l
0a00: 69 6e 65 7d 20 65 72 72 5d 7d 20 7b 0a 09 68 61  ine} err]} {..ha
0a10: 6e 64 6c 65 43 6c 69 65 6e 74 51 75 69 74 20 24  ndleClientQuit $
0a20: 66 64 20 22 49 2f 4f 20 65 72 72 6f 72 3a 20 24  fd "I/O error: $
0a30: 65 72 72 22 0a 09 72 65 74 75 72 6e 0a 20 20 20  err"..return.   
0a40: 20 7d 0a 20 20 20 20 69 66 20 7b 24 6c 69 6e 65   }.    if {$line
0a50: 20 65 71 20 7b 7d 7d 20 72 65 74 75 72 6e 0a 20   eq {}} return. 
0a60: 20 20 20 73 65 74 20 6c 69 6e 65 20 5b 73 74 72     set line [str
0a70: 69 6e 67 20 74 72 69 6d 20 24 6c 69 6e 65 5d 0a  ing trim $line].
0a80: 20 20 20 20 64 65 62 75 67 20 22 28 5b 63 6c 69      debug "([cli
0a90: 65 6e 74 53 74 61 74 65 20 24 66 64 5d 3a 24 66  entState $fd]:$f
0aa0: 64 29 20 5b 63 6c 69 65 6e 74 4e 69 63 6b 20 24  d) [clientNick $
0ab0: 66 64 5d 20 2d 3e 20 27 24 6c 69 6e 65 27 22 0a  fd] -> '$line'".
0ac0: 20 20 20 20 69 66 20 7b 5b 63 6c 69 65 6e 74 53      if {[clientS
0ad0: 74 61 74 65 20 24 66 64 5d 20 65 71 20 7b 55 4e  tate $fd] eq {UN
0ae0: 52 45 47 49 53 54 45 52 45 44 7d 7d 20 7b 0a 09  REGISTERED}} {..
0af0: 69 66 20 7b 5b 72 65 67 65 78 70 20 2d 6e 6f 63  if {[regexp -noc
0b00: 61 73 65 20 7b 4e 49 43 4b 20 2b 28 5b 5e 20 5d  ase {NICK +([^ ]
0b10: 2b 29 24 7d 20 24 6c 69 6e 65 20 2d 3e 20 6e 69  +)$} $line -> ni
0b20: 63 6b 5d 7d 20 7b 0a 20 20 20 20 20 20 20 20 20  ck]} {.         
0b30: 20 20 20 73 74 72 69 70 43 6f 6c 6f 6e 20 6e 69     stripColon ni
0b40: 63 6b 0a 09 20 20 20 20 69 66 20 7b 5b 6e 69 63  ck..    if {[nic
0b50: 6b 54 6f 46 64 20 24 6e 69 63 6b 5d 20 6e 65 20  kToFd $nick] ne 
0b60: 7b 7d 7d 20 7b 0a 09 09 72 61 77 4d 73 67 20 24  {}} {...rawMsg $
0b70: 66 64 20 22 34 33 33 20 2a 20 24 6e 69 63 6b 20  fd "433 * $nick 
0b80: 3a 4e 69 63 6b 6e 61 6d 65 20 69 73 20 61 6c 72  :Nickname is alr
0b90: 65 61 64 79 20 69 6e 20 75 73 65 2e 22 0a 09 09  eady in use."...
0ba0: 72 65 74 75 72 6e 0a 09 20 20 20 20 7d 0a 09 20  return..    }.. 
0bb0: 20 20 20 63 6c 69 65 6e 74 4e 69 63 6b 20 24 66     clientNick $f
0bc0: 64 20 24 6e 69 63 6b 0a 09 20 20 20 20 6e 69 63  d $nick..    nic
0bd0: 6b 54 6f 46 64 20 24 6e 69 63 6b 20 24 66 64 0a  kToFd $nick $fd.
0be0: 09 20 20 20 20 69 66 20 7b 5b 63 6c 69 65 6e 74  .    if {[client
0bf0: 55 73 65 72 20 24 66 64 5d 20 6e 65 20 7b 7d 7d  User $fd] ne {}}
0c00: 20 7b 0a 09 09 72 65 67 69 73 74 65 72 43 6c 69   {...registerCli
0c10: 65 6e 74 20 24 66 64 0a 09 20 20 20 20 7d 0a 09  ent $fd..    }..
0c20: 7d 20 65 6c 73 65 69 66 20 7b 5b 72 65 67 65 78  } elseif {[regex
0c30: 70 20 2d 6e 6f 63 61 73 65 20 7b 55 53 45 52 20  p -nocase {USER 
0c40: 2b 28 5b 5e 20 5d 2b 29 20 2b 28 5b 5e 20 5d 2b  +([^ ]+) +([^ ]+
0c50: 29 20 2b 28 5b 5e 20 5d 2b 29 20 2b 28 2e 2b 29  ) +([^ ]+) +(.+)
0c60: 24 7d 20 5c 0a 09 09 20 20 20 20 24 6c 69 6e 65  $} \...    $line
0c70: 20 2d 3e 20 75 73 65 72 20 6d 6f 64 65 20 76 69   -> user mode vi
0c80: 72 74 75 61 6c 68 6f 73 74 20 72 65 61 6c 6e 61  rtualhost realna
0c90: 6d 65 5d 7d 20 5c 0a 09 7b 0a 09 20 20 20 20 73  me]} \..{..    s
0ca0: 74 72 69 70 43 6f 6c 6f 6e 20 72 65 61 6c 6e 61  tripColon realna
0cb0: 6d 65 0a 09 20 20 20 20 63 6c 69 65 6e 74 55 73  me..    clientUs
0cc0: 65 72 20 24 66 64 20 24 75 73 65 72 0a 09 20 20  er $fd $user..  
0cd0: 20 20 63 6c 69 65 6e 74 56 69 72 74 75 61 6c 48    clientVirtualH
0ce0: 6f 73 74 20 24 66 64 20 24 76 69 72 74 75 61 6c  ost $fd $virtual
0cf0: 68 6f 73 74 0a 09 20 20 20 20 63 6c 69 65 6e 74  host..    client
0d00: 52 65 61 6c 4e 61 6d 65 20 24 66 64 20 24 72 65  RealName $fd $re
0d10: 61 6c 6e 61 6d 65 0a 09 20 20 20 20 69 66 20 7b  alname..    if {
0d20: 5b 63 6c 69 65 6e 74 4e 69 63 6b 20 24 66 64 5d  [clientNick $fd]
0d30: 20 6e 65 20 7b 7d 7d 20 7b 0a 09 09 72 65 67 69   ne {}} {...regi
0d40: 73 74 65 72 43 6c 69 65 6e 74 20 24 66 64 0a 09  sterClient $fd..
0d50: 20 20 20 20 7d 0a 09 7d 0a 20 20 20 20 7d 20 65      }..}.    } e
0d60: 6c 73 65 69 66 20 7b 5b 63 6c 69 65 6e 74 53 74  lseif {[clientSt
0d70: 61 74 65 20 24 66 64 5d 20 65 71 20 7b 52 45 47  ate $fd] eq {REG
0d80: 49 53 54 45 52 45 44 7d 7d 20 7b 0a 09 23 20 54  ISTERED}} {..# T
0d90: 68 65 20 62 69 67 20 72 65 67 65 78 70 73 20 69  he big regexps i
0da0: 66 2f 65 6c 73 65 2e 20 54 68 69 73 20 61 72 65  f/else. This are
0db0: 20 74 68 65 20 63 6f 6d 6d 61 6e 64 73 20 73 75   the commands su
0dc0: 70 70 6f 72 74 65 64 20 63 75 72 72 65 6e 74 6c  pported currentl
0dd0: 79 2e 0a 09 69 66 20 7b 5b 72 65 67 65 78 70 20  y...if {[regexp 
0de0: 2d 6e 6f 63 61 73 65 20 7b 4a 4f 49 4e 20 2b 28  -nocase {JOIN +(
0df0: 5b 5e 20 5d 2b 29 24 7d 20 24 6c 69 6e 65 20 2d  [^ ]+)$} $line -
0e00: 3e 20 63 68 61 6e 6e 65 6c 5d 7d 20 7b 0a 09 20  > channel]} {.. 
0e10: 20 20 20 68 61 6e 64 6c 65 43 6c 69 65 6e 74 4a     handleClientJ
0e20: 6f 69 6e 20 24 66 64 20 24 63 68 61 6e 6e 65 6c  oin $fd $channel
0e30: 0a 09 7d 20 65 6c 73 65 69 66 20 7b 5b 72 65 67  ..} elseif {[reg
0e40: 65 78 70 20 2d 6e 6f 63 61 73 65 20 7b 5e 50 49  exp -nocase {^PI
0e50: 4e 47 20 2b 28 5b 5e 20 5d 2b 29 20 2a 28 2e 2a  NG +([^ ]+) *(.*
0e60: 29 24 7d 20 24 6c 69 6e 65 20 2d 3e 20 70 69 6e  )$} $line -> pin
0e70: 67 6d 73 67 20 5f 5d 7d 20 7b 0a 09 20 20 20 20  gmsg _]} {..    
0e80: 68 61 6e 64 6c 65 43 6c 69 65 6e 74 50 69 6e 67  handleClientPing
0e90: 20 24 66 64 20 24 70 69 6e 67 6d 73 67 0a 09 7d   $fd $pingmsg..}
0ea0: 20 65 6c 73 65 69 66 20 7b 5b 72 65 67 65 78 70   elseif {[regexp
0eb0: 20 2d 6e 6f 63 61 73 65 20 7b 5e 50 52 49 56 4d   -nocase {^PRIVM
0ec0: 53 47 20 2b 28 5b 5e 20 5d 2b 29 20 2b 28 2e 2a  SG +([^ ]+) +(.*
0ed0: 29 24 7d 20 24 6c 69 6e 65 20 5c 0a 09 09 20 20  )$} $line \...  
0ee0: 20 20 2d 3e 20 74 61 72 67 65 74 20 6d 73 67 5d    -> target msg]
0ef0: 7d 20 5c 0a 09 7b 0a 09 20 20 20 20 68 61 6e 64  } \..{..    hand
0f00: 6c 65 43 6c 69 65 6e 74 50 72 69 76 6d 73 67 20  leClientPrivmsg 
0f10: 50 52 49 56 4d 53 47 20 24 66 64 20 24 74 61 72  PRIVMSG $fd $tar
0f20: 67 65 74 20 24 6d 73 67 0a 09 7d 20 65 6c 73 65  get $msg..} else
0f30: 69 66 20 7b 5b 72 65 67 65 78 70 20 2d 6e 6f 63  if {[regexp -noc
0f40: 61 73 65 20 7b 5e 4e 4f 54 49 43 45 20 2b 28 5b  ase {^NOTICE +([
0f50: 5e 20 5d 2b 29 20 2b 28 2e 2a 29 24 7d 20 24 6c  ^ ]+) +(.*)$} $l
0f60: 69 6e 65 20 5c 0a 09 09 20 20 20 20 2d 3e 20 74  ine \...    -> t
0f70: 61 72 67 65 74 20 6d 73 67 5d 7d 20 5c 0a 09 7b  arget msg]} \..{
0f80: 0a 09 20 20 20 20 68 61 6e 64 6c 65 43 6c 69 65  ..    handleClie
0f90: 6e 74 50 72 69 76 6d 73 67 20 4e 4f 54 49 43 45  ntPrivmsg NOTICE
0fa0: 20 24 66 64 20 24 74 61 72 67 65 74 20 24 6d 73   $fd $target $ms
0fb0: 67 0a 09 7d 20 65 6c 73 65 69 66 20 7b 5b 72 65  g..} elseif {[re
0fc0: 67 65 78 70 20 2d 6e 6f 63 61 73 65 20 7b 5e 50  gexp -nocase {^P
0fd0: 41 52 54 20 2b 28 5b 5e 20 5d 2b 29 20 2a 28 2e  ART +([^ ]+) *(.
0fe0: 2a 29 24 7d 20 24 6c 69 6e 65 20 5c 0a 09 09 20  *)$} $line \... 
0ff0: 20 20 20 2d 3e 20 63 68 61 6e 6e 65 6c 20 6d 73     -> channel ms
1000: 67 5d 7d 20 5c 0a 09 7b 0a 09 20 20 20 20 68 61  g]} \..{..    ha
1010: 6e 64 6c 65 43 6c 69 65 6e 74 50 61 72 74 20 24  ndleClientPart $
1020: 66 64 20 50 41 52 54 20 24 63 68 61 6e 6e 65 6c  fd PART $channel
1030: 20 24 6d 73 67 0a 09 7d 20 65 6c 73 65 69 66 20   $msg..} elseif 
1040: 7b 5b 72 65 67 65 78 70 20 2d 6e 6f 63 61 73 65  {[regexp -nocase
1050: 20 7b 5e 51 55 49 54 20 2a 28 2e 2a 29 24 7d 20   {^QUIT *(.*)$} 
1060: 24 6c 69 6e 65 20 2d 3e 20 6d 73 67 5d 7d 20 7b  $line -> msg]} {
1070: 0a 09 20 20 20 20 68 61 6e 64 6c 65 43 6c 69 65  ..    handleClie
1080: 6e 74 51 75 69 74 20 24 66 64 20 24 6d 73 67 0a  ntQuit $fd $msg.
1090: 09 7d 20 65 6c 73 65 69 66 20 7b 5b 72 65 67 65  .} elseif {[rege
10a0: 78 70 20 2d 6e 6f 63 61 73 65 20 7b 5e 4e 49 43  xp -nocase {^NIC
10b0: 4b 20 2b 28 5b 5e 20 5d 2b 29 24 7d 20 24 6c 69  K +([^ ]+)$} $li
10c0: 6e 65 20 2d 3e 20 6e 69 63 6b 5d 7d 20 7b 0a 09  ne -> nick]} {..
10d0: 20 20 20 20 68 61 6e 64 6c 65 43 6c 69 65 6e 74      handleClient
10e0: 4e 69 63 6b 20 24 66 64 20 24 6e 69 63 6b 0a 09  Nick $fd $nick..
10f0: 7d 20 65 6c 73 65 69 66 20 7b 5b 72 65 67 65 78  } elseif {[regex
1100: 70 20 2d 6e 6f 63 61 73 65 20 7b 5e 54 4f 50 49  p -nocase {^TOPI
1110: 43 20 2b 28 5b 5e 20 5d 2b 29 20 2a 28 2e 2a 29  C +([^ ]+) *(.*)
1120: 24 7d 20 24 6c 69 6e 65 20 5c 0a 09 09 20 20 20  $} $line \...   
1130: 20 2d 3e 20 63 68 61 6e 6e 65 6c 20 74 6f 70 69   -> channel topi
1140: 63 5d 7d 20 5c 0a 09 7b 0a 09 20 20 20 20 68 61  c]} \..{..    ha
1150: 6e 64 6c 65 43 6c 69 65 6e 74 54 6f 70 69 63 20  ndleClientTopic 
1160: 24 66 64 20 24 63 68 61 6e 6e 65 6c 20 24 74 6f  $fd $channel $to
1170: 70 69 63 0a 09 7d 20 65 6c 73 65 69 66 20 7b 5b  pic..} elseif {[
1180: 72 65 67 65 78 70 20 2d 6e 6f 63 61 73 65 20 7b  regexp -nocase {
1190: 5e 4c 49 53 54 20 2a 28 2e 2a 29 24 7d 20 24 6c  ^LIST *(.*)$} $l
11a0: 69 6e 65 20 2d 3e 20 63 68 61 6e 6e 65 6c 5d 7d  ine -> channel]}
11b0: 20 7b 0a 09 20 20 20 20 68 61 6e 64 6c 65 43 6c   {..    handleCl
11c0: 69 65 6e 74 4c 69 73 74 20 24 66 64 20 24 63 68  ientList $fd $ch
11d0: 61 6e 6e 65 6c 0a 09 7d 20 65 6c 73 65 69 66 20  annel..} elseif 
11e0: 7b 5b 72 65 67 65 78 70 20 2d 6e 6f 63 61 73 65  {[regexp -nocase
11f0: 20 7b 5e 57 48 4f 49 53 20 2b 28 2e 2b 29 24 7d   {^WHOIS +(.+)$}
1200: 20 24 6c 69 6e 65 20 2d 3e 20 6e 69 63 6b 5d 7d   $line -> nick]}
1210: 20 7b 0a 09 20 20 20 20 68 61 6e 64 6c 65 43 6c   {..    handleCl
1220: 69 65 6e 74 57 68 6f 69 73 20 24 66 64 20 24 6e  ientWhois $fd $n
1230: 69 63 6b 0a 09 7d 20 65 6c 73 65 69 66 20 7b 5b  ick..} elseif {[
1240: 72 65 67 65 78 70 20 2d 6e 6f 63 61 73 65 20 7b  regexp -nocase {
1250: 5e 57 48 4f 20 2a 24 7d 20 24 6c 69 6e 65 20 2d  ^WHO *$} $line -
1260: 3e 5d 7d 20 7b 0a 09 20 20 20 20 68 61 6e 64 6c  >]} {..    handl
1270: 65 43 6c 69 65 6e 74 57 68 6f 20 24 66 64 20 22  eClientWho $fd "
1280: 22 0a 09 7d 20 65 6c 73 65 69 66 20 7b 5b 72 65  "..} elseif {[re
1290: 67 65 78 70 20 2d 6e 6f 63 61 73 65 20 7b 5e 57  gexp -nocase {^W
12a0: 48 4f 20 2b 28 5b 5e 20 5d 2b 29 20 2a 28 2e 2a  HO +([^ ]+) *(.*
12b0: 29 24 7d 20 24 6c 69 6e 65 20 2d 3e 20 63 68 61  )$} $line -> cha
12c0: 6e 6e 65 6c 20 5f 5d 7d 20 7b 0a 09 20 20 20 20  nnel _]} {..    
12d0: 68 61 6e 64 6c 65 43 6c 69 65 6e 74 57 68 6f 20  handleClientWho 
12e0: 24 66 64 20 24 63 68 61 6e 6e 65 6c 0a 09 7d 20  $fd $channel..} 
12f0: 65 6c 73 65 69 66 20 7b 5b 72 65 67 65 78 70 20  elseif {[regexp 
1300: 2d 6e 6f 63 61 73 65 20 7b 5e 4d 4f 44 45 20 2b  -nocase {^MODE +
1310: 28 5b 5e 20 5d 2b 29 20 2a 28 2e 2a 29 24 7d 20  ([^ ]+) *(.*)$} 
1320: 24 6c 69 6e 65 20 2d 3e 20 74 61 72 67 65 74 20  $line -> target 
1330: 72 65 73 74 5d 7d 20 7b 0a 09 20 20 20 20 68 61  rest]} {..    ha
1340: 6e 64 6c 65 43 6c 69 65 6e 74 4d 6f 64 65 20 24  ndleClientMode $
1350: 66 64 20 24 74 61 72 67 65 74 20 24 72 65 73 74  fd $target $rest
1360: 0a 09 7d 20 65 6c 73 65 69 66 20 7b 5b 72 65 67  ..} elseif {[reg
1370: 65 78 70 20 2d 6e 6f 63 61 73 65 20 7b 5e 55 53  exp -nocase {^US
1380: 45 52 48 4f 53 54 20 2b 28 2e 2b 29 24 7d 20 24  ERHOST +(.+)$} $
1390: 6c 69 6e 65 20 2d 3e 20 6e 69 63 6b 73 5d 7d 20  line -> nicks]} 
13a0: 7b 0a 09 20 20 20 20 68 61 6e 64 6c 65 43 6c 69  {..    handleCli
13b0: 65 6e 74 55 73 65 72 68 6f 73 74 20 24 66 64 20  entUserhost $fd 
13c0: 24 6e 69 63 6b 73 0a 09 7d 20 65 6c 73 65 69 66  $nicks..} elseif
13d0: 20 7b 5b 72 65 67 65 78 70 20 2d 6e 6f 63 61 73   {[regexp -nocas
13e0: 65 20 7b 5e 52 45 4c 4f 41 44 20 2b 28 2e 2b 29  e {^RELOAD +(.+)
13f0: 24 7d 20 24 6c 69 6e 65 20 2d 3e 20 70 61 73 73  $} $line -> pass
1400: 77 6f 72 64 5d 7d 20 7b 0a 09 20 20 20 20 68 61  word]} {..    ha
1410: 6e 64 6c 65 43 6c 69 65 6e 74 52 65 6c 6f 61 64  ndleClientReload
1420: 20 24 66 64 20 24 70 61 73 73 77 6f 72 64 0a 09   $fd $password..
1430: 7d 20 65 6c 73 65 20 7b 0a 09 20 20 20 20 73 65  } else {..    se
1440: 74 20 63 6d 64 20 5b 6c 69 6e 64 65 78 20 5b 73  t cmd [lindex [s
1450: 70 6c 69 74 20 24 6c 69 6e 65 5d 20 30 5d 0a 09  plit $line] 0]..
1460: 20 20 20 20 73 65 72 76 65 72 43 6c 69 65 6e 74      serverClient
1470: 4d 73 67 20 24 66 64 20 34 32 31 20 22 24 63 6d  Msg $fd 421 "$cm
1480: 64 20 3a 55 6e 6b 6e 6f 77 6e 20 63 6f 6d 6d 61  d :Unknown comma
1490: 6e 64 22 0a 09 7d 0a 20 20 20 20 7d 0a 7d 0a 0a  nd"..}.    }.}..
14a0: 70 72 6f 63 20 72 65 67 69 73 74 65 72 43 6c 69  proc registerCli
14b0: 65 6e 74 20 66 64 20 7b 0a 20 20 20 20 63 6c 69  ent fd {.    cli
14c0: 65 6e 74 53 74 61 74 65 20 24 66 64 20 52 45 47  entState $fd REG
14d0: 49 53 54 45 52 45 44 0a 20 20 20 20 73 65 72 76  ISTERED.    serv
14e0: 65 72 43 6c 69 65 6e 74 4d 73 67 20 24 66 64 20  erClientMsg $fd 
14f0: 30 30 31 20 22 3a 57 65 6c 63 6f 6d 65 20 74 6f  001 ":Welcome to
1500: 20 74 68 69 73 20 49 52 43 20 73 65 72 76 65 72   this IRC server
1510: 20 5b 63 6c 69 65 6e 74 4e 69 63 6b 20 24 66 64   [clientNick $fd
1520: 5d 22 0a 20 20 20 20 73 65 72 76 65 72 43 6c 69  ]".    serverCli
1530: 65 6e 74 4d 73 67 20 24 66 64 20 30 30 32 20 22  entMsg $fd 002 "
1540: 3a 59 6f 75 72 20 68 6f 73 74 20 69 73 20 5b 63  :Your host is [c
1550: 6f 6e 66 69 67 20 68 6f 73 74 6e 61 6d 65 5d 2c  onfig hostname],
1560: 20 72 75 6e 6e 69 6e 67 20 76 65 72 73 69 6f 6e   running version
1570: 20 5b 63 6f 6e 66 69 67 20 76 65 72 73 69 6f 6e   [config version
1580: 5d 22 0a 20 20 20 20 73 65 72 76 65 72 43 6c 69  ]".    serverCli
1590: 65 6e 74 4d 73 67 20 24 66 64 20 30 30 33 20 22  entMsg $fd 003 "
15a0: 3a 54 68 69 73 20 73 65 72 76 65 72 20 77 61 73  :This server was
15b0: 20 63 72 65 61 74 65 64 20 2e 2e 2e 20 49 20 64   created ... I d
15c0: 6f 6e 27 74 20 6b 6e 6f 77 22 0a 20 20 20 20 73  on't know".    s
15d0: 65 72 76 65 72 43 6c 69 65 6e 74 4d 73 67 20 24  erverClientMsg $
15e0: 66 64 20 30 30 34 20 22 5b 63 6f 6e 66 69 67 20  fd 004 "[config 
15f0: 68 6f 73 74 6e 61 6d 65 5d 20 5b 63 6f 6e 66 69  hostname] [confi
1600: 67 20 76 65 72 73 69 6f 6e 5d 20 61 41 62 42 63  g version] aAbBc
1610: 43 64 44 65 45 66 46 47 68 48 69 49 6a 6b 4b 6c  CdDeEfFGhHiIjkKl
1620: 4c 6d 4d 6e 4e 6f 70 50 51 72 52 73 53 74 55 76  LmMnNopPQrRsStUv
1630: 56 77 57 78 58 79 59 7a 5a 30 31 32 33 34 35 39  VwWxXyYzZ0123459
1640: 2a 40 20 62 63 64 65 66 46 68 69 49 6b 6c 6d 6e  *@ bcdefFhiIklmn
1650: 6f 50 71 73 74 76 22 0a 7d 0a 0a 70 72 6f 63 20  oPqstv".}..proc 
1660: 66 72 65 65 43 6c 69 65 6e 74 20 66 64 20 7b 0a  freeClient fd {.
1670: 20 20 20 20 63 6c 69 65 6e 74 53 74 61 74 65 20      clientState 
1680: 66 64 20 7b 7d 0a 20 20 20 20 6e 69 63 6b 54 6f  fd {}.    nickTo
1690: 46 64 20 5b 63 6c 69 65 6e 74 4e 69 63 6b 20 24  Fd [clientNick $
16a0: 66 64 5d 20 7b 7d 0a 20 20 20 20 63 6c 6f 73 65  fd] {}.    close
16b0: 20 24 66 64 0a 7d 0a 0a 70 72 6f 63 20 73 74 72   $fd.}..proc str
16c0: 69 70 43 6f 6c 6f 6e 20 76 61 72 6e 61 6d 65 20  ipColon varname 
16d0: 7b 0a 20 20 20 20 75 70 76 61 72 20 31 20 24 76  {.    upvar 1 $v
16e0: 61 72 6e 61 6d 65 20 76 0a 20 20 20 20 69 66 20  arname v.    if 
16f0: 7b 5b 73 74 72 69 6e 67 20 69 6e 64 65 78 20 24  {[string index $
1700: 76 20 30 5d 20 65 71 20 7b 3a 7d 7d 20 7b 0a 09  v 0] eq {:}} {..
1710: 73 65 74 20 76 20 5b 73 74 72 69 6e 67 20 72 61  set v [string ra
1720: 6e 67 65 20 24 76 20 31 20 65 6e 64 5d 0a 20 20  nge $v 1 end].  
1730: 20 20 7d 0a 7d 0a 0a 23 20 52 65 6d 6f 76 65 20    }.}..# Remove 
1740: 65 78 74 72 61 20 73 70 61 63 65 73 20 73 65 70  extra spaces sep
1750: 61 72 61 74 69 6e 67 20 77 6f 72 64 73 2e 0a 23  arating words..#
1760: 20 46 6f 72 20 65 78 61 6d 70 6c 65 20 22 20 20   For example "  
1770: 20 61 20 20 20 62 20 63 20 20 20 20 20 20 20 64   a   b c       d
1780: 20 22 20 69 73 20 74 75 72 6e 65 64 20 69 6e 74   " is turned int
1790: 6f 20 22 61 20 62 20 63 20 64 22 0a 70 72 6f 63  o "a b c d".proc
17a0: 20 73 74 72 69 70 45 78 74 72 61 53 70 61 63 65   stripExtraSpace
17b0: 73 20 76 61 72 6e 61 6d 65 20 7b 0a 20 20 20 20  s varname {.    
17c0: 75 70 76 61 72 20 31 20 24 76 61 72 6e 61 6d 65  upvar 1 $varname
17d0: 20 76 0a 20 20 20 20 73 65 74 20 6f 6c 64 73 74   v.    set oldst
17e0: 72 20 7b 7d 0a 20 20 20 20 77 68 69 6c 65 20 7b  r {}.    while {
17f0: 24 6f 6c 64 73 74 72 20 6e 65 20 24 76 7d 20 7b  $oldstr ne $v} {
1800: 0a 09 73 65 74 20 6f 6c 64 73 74 72 20 24 76 0a  ..set oldstr $v.
1810: 09 73 65 74 20 76 20 5b 73 74 72 69 6e 67 20 6d  .set v [string m
1820: 61 70 20 7b 7b 20 20 7d 20 7b 20 7d 7d 20 24 76  ap {{  } { }} $v
1830: 5d 0a 20 20 20 20 7d 0a 20 20 20 20 73 65 74 20  ].    }.    set 
1840: 76 20 5b 73 74 72 69 6e 67 20 74 72 69 6d 20 24  v [string trim $
1850: 76 5d 0a 7d 0a 0a 70 72 6f 63 20 6e 6f 4e 69 63  v].}..proc noNic
1860: 6b 43 68 61 6e 6e 65 6c 20 7b 66 64 20 74 61 72  kChannel {fd tar
1870: 67 65 74 7d 20 7b 0a 20 20 20 20 73 65 72 76 65  get} {.    serve
1880: 72 43 6c 69 65 6e 74 4d 73 67 20 24 66 64 20 34  rClientMsg $fd 4
1890: 30 31 20 22 24 74 61 72 67 65 74 20 3a 4e 6f 20  01 "$target :No 
18a0: 73 75 63 68 20 6e 69 63 6b 2f 63 68 61 6e 6e 65  such nick/channe
18b0: 6c 22 0a 7d 0a 0a 70 72 6f 63 20 63 68 61 6e 6e  l".}..proc chann
18c0: 65 6c 49 6e 66 6f 4f 72 52 65 74 75 72 6e 20 7b  elInfoOrReturn {
18d0: 66 64 20 63 68 61 6e 6e 65 6c 7d 20 7b 0a 20 20  fd channel} {.  
18e0: 20 20 69 66 20 7b 5b 73 65 74 20 69 6e 66 6f 20    if {[set info 
18f0: 5b 63 68 61 6e 6e 65 6c 49 6e 66 6f 20 24 63 68  [channelInfo $ch
1900: 61 6e 6e 65 6c 5d 5d 20 65 71 20 7b 7d 7d 20 7b  annel]] eq {}} {
1910: 0a 09 6e 6f 4e 69 63 6b 43 68 61 6e 6e 65 6c 20  ..noNickChannel 
1920: 24 66 64 20 24 63 68 61 6e 6e 65 6c 0a 09 72 65  $fd $channel..re
1930: 74 75 72 6e 20 2d 63 6f 64 65 20 72 65 74 75 72  turn -code retur
1940: 6e 0a 20 20 20 20 7d 0a 20 20 20 20 72 65 74 75  n.    }.    retu
1950: 72 6e 20 24 69 6e 66 6f 0a 7d 0a 0a 70 72 6f 63  rn $info.}..proc
1960: 20 6e 69 63 6b 46 64 4f 72 52 65 74 75 72 6e 20   nickFdOrReturn 
1970: 7b 66 64 20 6e 69 63 6b 7d 20 7b 0a 20 20 20 20  {fd nick} {.    
1980: 69 66 20 7b 5b 73 65 74 20 74 61 72 67 65 74 66  if {[set targetf
1990: 64 20 5b 6e 69 63 6b 54 6f 46 64 20 24 6e 69 63  d [nickToFd $nic
19a0: 6b 5d 5d 20 65 71 20 7b 7d 7d 20 7b 0a 09 6e 6f  k]] eq {}} {..no
19b0: 4e 69 63 6b 43 68 61 6e 6e 65 6c 20 24 66 64 20  NickChannel $fd 
19c0: 24 6e 69 63 6b 0a 09 72 65 74 75 72 6e 20 2d 63  $nick..return -c
19d0: 6f 64 65 20 72 65 74 75 72 6e 0a 20 20 20 20 7d  ode return.    }
19e0: 0a 20 20 20 20 72 65 74 75 72 6e 20 24 74 61 72  .    return $tar
19f0: 67 65 74 66 64 0a 7d 0a 0a 70 72 6f 63 20 68 61  getfd.}..proc ha
1a00: 6e 64 6c 65 43 6c 69 65 6e 74 51 75 69 74 20 7b  ndleClientQuit {
1a10: 66 64 20 6d 73 67 7d 20 7b 0a 20 20 20 20 69 66  fd msg} {.    if
1a20: 20 7b 5b 63 61 74 63 68 20 7b 66 63 6f 6e 66 69   {[catch {fconfi
1a30: 67 75 72 65 20 24 66 64 7d 5d 7d 20 72 65 74 75  gure $fd}]} retu
1a40: 72 6e 0a 20 20 20 20 64 65 62 75 67 20 22 2a 2a  rn.    debug "**
1a50: 2a 20 51 75 69 74 74 69 6e 67 20 24 66 64 20 28  * Quitting $fd (
1a60: 5b 63 6c 69 65 6e 74 4e 69 63 6b 20 24 66 64 5d  [clientNick $fd]
1a70: 29 22 0a 20 20 20 20 73 65 74 20 63 68 61 6e 6e  )".    set chann
1a80: 65 6c 73 20 5b 63 6c 69 65 6e 74 43 68 61 6e 6e  els [clientChann
1a90: 65 6c 73 20 24 66 64 5d 0a 20 20 20 20 66 6f 72  els $fd].    for
1aa0: 65 61 63 68 20 63 68 61 6e 6e 65 6c 20 24 63 68  each channel $ch
1ab0: 61 6e 6e 65 6c 73 20 7b 0a 09 68 61 6e 64 6c 65  annels {..handle
1ac0: 43 6c 69 65 6e 74 50 61 72 74 20 24 66 64 20 51  ClientPart $fd Q
1ad0: 55 49 54 20 24 63 68 61 6e 6e 65 6c 20 24 6d 73  UIT $channel $ms
1ae0: 67 0a 20 20 20 20 7d 0a 20 20 20 20 66 72 65 65  g.    }.    free
1af0: 43 6c 69 65 6e 74 20 24 66 64 0a 7d 0a 0a 70 72  Client $fd.}..pr
1b00: 6f 63 20 68 61 6e 64 6c 65 43 6c 69 65 6e 74 4a  oc handleClientJ
1b10: 6f 69 6e 20 7b 66 64 20 63 68 61 6e 6e 65 6c 73  oin {fd channels
1b20: 7d 20 7b 0a 20 20 20 20 66 6f 72 65 61 63 68 20  } {.    foreach 
1b30: 63 68 61 6e 6e 65 6c 20 5b 73 70 6c 69 74 20 24  channel [split $
1b40: 63 68 61 6e 6e 65 6c 73 20 2c 5d 20 7b 0a 09 69  channels ,] {..i
1b50: 66 20 7b 5b 73 74 72 69 6e 67 20 69 6e 64 65 78  f {[string index
1b60: 20 24 63 68 61 6e 6e 65 6c 20 30 5d 20 6e 65 20   $channel 0] ne 
1b70: 7b 23 7d 7d 20 7b 0a 09 20 20 20 20 73 65 72 76  {#}} {..    serv
1b80: 65 72 43 6c 69 65 6e 74 4d 73 67 20 24 66 64 20  erClientMsg $fd 
1b90: 34 30 33 20 22 24 63 68 61 6e 6e 65 6c 20 3a 54  403 "$channel :T
1ba0: 68 61 74 20 63 68 61 6e 6e 65 6c 20 64 6f 65 73  hat channel does
1bb0: 6e 27 74 20 65 78 69 73 22 0a 09 20 20 20 20 63  n't exis"..    c
1bc0: 6f 6e 74 69 6e 75 65 0a 09 7d 0a 09 69 66 20 7b  ontinue..}..if {
1bd0: 5b 63 68 61 6e 6e 65 6c 49 6e 66 6f 20 24 63 68  [channelInfo $ch
1be0: 61 6e 6e 65 6c 5d 20 65 71 20 7b 7d 7d 20 7b 0a  annel] eq {}} {.
1bf0: 09 20 20 20 20 63 68 61 6e 6e 65 6c 49 6e 66 6f  .    channelInfo
1c00: 20 24 63 68 61 6e 6e 65 6c 20 5b 6c 69 73 74 20   $channel [list 
1c10: 7b 7d 20 7b 7d 20 7b 7d 5d 3b 20 23 20 65 6d 70  {} {} {}]; # emp
1c20: 74 79 20 74 6f 70 69 63 2c 20 6e 6f 20 75 73 65  ty topic, no use
1c30: 72 73 2e 0a 09 7d 0a 09 69 66 20 7b 5b 63 6c 69  rs...}..if {[cli
1c40: 65 6e 74 49 6e 43 68 61 6e 6e 65 6c 20 24 66 64  entInChannel $fd
1c50: 20 24 63 68 61 6e 6e 65 6c 5d 7d 20 7b 0a 09 20   $channel]} {.. 
1c60: 20 20 20 63 6f 6e 74 69 6e 75 65 3b 20 23 20 55     continue; # U
1c70: 73 65 72 20 61 6c 72 65 61 64 79 20 69 6e 20 74  ser already in t
1c80: 68 69 73 20 63 68 61 6e 6e 65 6c 0a 09 7d 0a 09  his channel..}..
1c90: 66 6f 72 65 61 63 68 20 7b 74 6f 70 69 63 20 75  foreach {topic u
1ca0: 73 65 72 6c 69 73 74 20 75 73 65 72 6d 6f 64 65  serlist usermode
1cb0: 7d 20 5b 63 68 61 6e 6e 65 6c 49 6e 66 6f 20 24  } [channelInfo $
1cc0: 63 68 61 6e 6e 65 6c 5d 20 62 72 65 61 6b 0a 09  channel] break..
1cd0: 69 66 20 7b 5b 6c 6c 65 6e 67 74 68 20 24 75 73  if {[llength $us
1ce0: 65 72 6c 69 73 74 5d 7d 20 7b 0a 09 20 20 20 20  erlist]} {..    
1cf0: 6c 61 70 70 65 6e 64 20 75 73 65 72 6d 6f 64 65  lappend usermode
1d00: 20 7b 7d 0a 09 7d 20 65 6c 73 65 20 7b 0a 09 20   {}..} else {.. 
1d10: 20 20 20 6c 61 70 70 65 6e 64 20 75 73 65 72 6d     lappend userm
1d20: 6f 64 65 20 7b 40 7d 0a 09 7d 0a 09 6c 61 70 70  ode {@}..}..lapp
1d30: 65 6e 64 20 75 73 65 72 6c 69 73 74 20 24 66 64  end userlist $fd
1d40: 0a 09 63 68 61 6e 6e 65 6c 49 6e 66 6f 20 24 63  ..channelInfo $c
1d50: 68 61 6e 6e 65 6c 20 5b 6c 69 73 74 20 24 74 6f  hannel [list $to
1d60: 70 69 63 20 24 75 73 65 72 6c 69 73 74 20 24 75  pic $userlist $u
1d70: 73 65 72 6d 6f 64 65 5d 0a 09 75 73 65 72 4d 65  sermode]..userMe
1d80: 73 73 61 67 65 20 24 63 68 61 6e 6e 65 6c 20 24  ssage $channel $
1d90: 66 64 20 22 4a 4f 49 4e 20 3a 24 63 68 61 6e 6e  fd "JOIN :$chann
1da0: 65 6c 22 0a 09 73 65 6e 64 54 6f 70 69 63 4d 65  el"..sendTopicMe
1db0: 73 73 61 67 65 20 24 66 64 20 24 63 68 61 6e 6e  ssage $fd $chann
1dc0: 65 6c 0a 09 73 65 6e 64 57 68 6f 4d 65 73 73 61  el..sendWhoMessa
1dd0: 67 65 20 24 66 64 20 24 63 68 61 6e 6e 65 6c 0a  ge $fd $channel.
1de0: 20 20 20 20 7d 0a 7d 0a 0a 70 72 6f 63 20 75 73      }.}..proc us
1df0: 65 72 4d 65 73 73 61 67 65 20 7b 63 68 61 6e 6e  erMessage {chann
1e00: 65 6c 20 75 73 65 72 66 64 20 6d 73 67 20 61 72  el userfd msg ar
1e10: 67 73 7d 20 7b 0a 20 20 20 20 61 72 72 61 79 20  gs} {.    array 
1e20: 73 65 74 20 73 65 6e 74 20 7b 7d 0a 20 20 20 20  set sent {}.    
1e30: 69 66 20 7b 5b 73 74 72 69 6e 67 20 69 6e 64 65  if {[string inde
1e40: 78 20 24 63 68 61 6e 6e 65 6c 20 30 5d 20 65 71  x $channel 0] eq
1e50: 20 7b 23 7d 7d 20 7b 0a 09 63 68 61 6e 6e 65 6c   {#}} {..channel
1e60: 49 6e 66 6f 4f 72 52 65 74 75 72 6e 20 24 75 73  InfoOrReturn $us
1e70: 65 72 66 64 20 24 63 68 61 6e 6e 65 6c 0a 09 66  erfd $channel..f
1e80: 6f 72 65 61 63 68 20 7b 74 6f 70 69 63 20 75 73  oreach {topic us
1e90: 65 72 6c 69 73 74 20 75 73 65 72 6d 6f 64 65 7d  erlist usermode}
1ea0: 20 5b 63 68 61 6e 6e 65 6c 49 6e 66 6f 20 24 63   [channelInfo $c
1eb0: 68 61 6e 6e 65 6c 5d 20 62 72 65 61 6b 0a 20 20  hannel] break.  
1ec0: 20 20 7d 20 65 6c 73 65 20 7b 0a 09 73 65 74 20    } else {..set 
1ed0: 75 73 65 72 6c 69 73 74 20 24 63 68 61 6e 6e 65  userlist $channe
1ee0: 6c 0a 20 20 20 20 7d 0a 20 20 20 20 73 65 74 20  l.    }.    set 
1ef0: 75 73 65 72 20 22 3a 5b 63 6c 69 65 6e 74 4e 69  user ":[clientNi
1f00: 63 6b 20 24 75 73 65 72 66 64 5d 21 7e 5b 63 6c  ck $userfd]!~[cl
1f10: 69 65 6e 74 55 73 65 72 20 24 75 73 65 72 66 64  ientUser $userfd
1f20: 5d 40 5b 63 6c 69 65 6e 74 48 6f 73 74 20 24 75  ]@[clientHost $u
1f30: 73 65 72 66 64 5d 22 0a 20 20 20 20 66 6f 72 65  serfd]".    fore
1f40: 61 63 68 20 66 64 20 24 75 73 65 72 6c 69 73 74  ach fd $userlist
1f50: 20 7b 0a 09 69 66 20 7b 5b 6c 73 65 61 72 63 68   {..if {[lsearch
1f60: 20 24 61 72 67 73 20 2d 6e 6f 73 65 6c 66 5d 20   $args -noself] 
1f70: 21 3d 20 2d 31 20 26 26 20 24 66 64 20 65 71 20  != -1 && $fd eq 
1f80: 24 75 73 65 72 66 64 7d 20 63 6f 6e 74 69 6e 75  $userfd} continu
1f90: 65 0a 09 69 72 63 57 72 69 74 65 20 24 66 64 20  e..ircWrite $fd 
1fa0: 22 24 75 73 65 72 20 24 6d 73 67 22 0a 20 20 20  "$user $msg".   
1fb0: 20 7d 0a 7d 0a 0a 70 72 6f 63 20 75 73 65 72 43   }.}..proc userC
1fc0: 68 61 6e 6e 65 6c 73 4d 65 73 73 61 67 65 20 7b  hannelsMessage {
1fd0: 66 64 20 6d 73 67 7d 20 7b 0a 20 20 20 20 73 65  fd msg} {.    se
1fe0: 74 20 63 68 61 6e 6e 65 6c 73 20 5b 63 6c 69 65  t channels [clie
1ff0: 6e 74 43 68 61 6e 6e 65 6c 73 20 24 66 64 5d 0a  ntChannels $fd].
2000: 20 20 20 20 66 6f 72 65 61 63 68 20 63 68 61 6e      foreach chan
2010: 6e 65 6c 20 24 63 68 61 6e 6e 65 6c 73 20 7b 0a  nel $channels {.
2020: 09 75 73 65 72 4d 65 73 73 61 67 65 20 24 63 68  .userMessage $ch
2030: 61 6e 6e 65 6c 20 24 66 64 20 24 6d 73 67 0a 20  annel $fd $msg. 
2040: 20 20 20 7d 0a 7d 0a 0a 70 72 6f 63 20 61 6c 6c     }.}..proc all
2050: 43 68 61 6e 6e 65 6c 73 20 7b 7d 20 7b 0a 20 20  Channels {} {.  
2060: 20 20 73 65 74 20 72 65 74 76 61 6c 20 5b 61 72    set retval [ar
2070: 72 61 79 20 6e 61 6d 65 73 20 3a 3a 63 68 61 6e  ray names ::chan
2080: 6e 65 6c 49 6e 66 6f 5d 0a 0a 20 20 20 20 23 20  nelInfo]..    # 
2090: 52 65 6d 6f 76 65 20 74 68 69 73 20 68 69 64 64  Remove this hidd
20a0: 65 6e 20 63 68 61 6e 6e 65 6c 20 66 72 6f 6d 20  en channel from 
20b0: 74 68 65 20 6c 69 73 74 0a 20 20 20 20 73 65 74  the list.    set
20c0: 20 72 65 6d 6f 76 65 49 64 78 20 5b 6c 73 65 61   removeIdx [lsea
20d0: 72 63 68 20 2d 65 78 61 63 74 20 24 72 65 74 76  rch -exact $retv
20e0: 61 6c 20 22 23 5b 63 6f 6e 66 69 67 20 72 65 6c  al "#[config rel
20f0: 6f 61 64 70 61 73 73 77 64 5d 22 5d 0a 20 20 20  oadpasswd]"].   
2100: 20 69 66 20 7b 24 72 65 6d 6f 76 65 49 64 78 20   if {$removeIdx 
2110: 21 3d 20 2d 31 7d 20 7b 0a 20 20 20 20 20 20 20  != -1} {.       
2120: 20 73 65 74 20 72 65 74 76 61 6c 20 5b 6c 72 65   set retval [lre
2130: 70 6c 61 63 65 20 24 72 65 74 76 61 6c 20 24 72  place $retval $r
2140: 65 6d 6f 76 65 49 64 78 20 24 72 65 6d 6f 76 65  emoveIdx $remove
2150: 49 64 78 5d 0a 20 20 20 20 7d 0a 0a 20 20 20 20  Idx].    }..    
2160: 72 65 74 75 72 6e 20 24 72 65 74 76 61 6c 0a 7d  return $retval.}
2170: 0a 0a 23 20 4e 6f 74 65 20 74 68 61 74 20 74 68  ..# Note that th
2180: 69 73 20 64 6f 65 73 20 6e 6f 74 20 73 63 61 6c  is does not scal
2190: 65 20 77 65 6c 6c 20 69 66 20 74 68 65 72 65 20  e well if there 
21a0: 61 72 65 20 6d 61 6e 79 0a 23 20 63 68 61 6e 6e  are many.# chann
21b0: 65 6c 73 2e 20 46 6f 72 20 6e 6f 77 20 64 61 74  els. For now dat
21c0: 61 20 73 74 72 75 63 74 75 72 65 73 20 61 72 65  a structures are
21d0: 20 64 65 73 69 67 6e 65 64 20 74 6f 20 6d 61 6b   designed to mak
21e0: 65 0a 23 20 74 68 65 20 63 6f 64 65 20 6c 69 74  e.# the code lit
21f0: 74 6c 65 2e 20 54 68 65 20 73 6f 6c 75 74 69 6f  tle. The solutio
2200: 6e 20 69 73 20 74 6f 20 64 75 70 6c 69 63 61 74  n is to duplicat
2210: 65 20 74 68 69 73 20 69 6e 66 6f 72 6d 61 74 69  e this informati
2220: 6f 6e 0a 23 20 69 6e 74 6f 20 74 68 65 20 63 6c  on.# into the cl
2230: 69 65 6e 74 20 73 74 61 74 65 2c 20 73 6f 20 74  ient state, so t
2240: 68 61 74 20 65 76 65 72 79 20 63 6c 69 65 6e 74  hat every client
2250: 20 68 61 76 65 20 61 6e 20 61 73 73 6f 63 69 61   have an associa
2260: 74 65 64 0a 23 20 6c 69 73 74 20 6f 66 20 63 68  ted.# list of ch
2270: 61 6e 6e 65 6c 73 2e 0a 70 72 6f 63 20 63 6c 69  annels..proc cli
2280: 65 6e 74 43 68 61 6e 6e 65 6c 73 20 66 64 20 7b  entChannels fd {
2290: 0a 20 20 20 20 73 65 74 20 72 65 73 20 7b 7d 0a  .    set res {}.
22a0: 20 20 20 20 66 6f 72 65 61 63 68 20 63 68 61 6e      foreach chan
22b0: 6e 65 6c 20 5b 61 6c 6c 43 68 61 6e 6e 65 6c 73  nel [allChannels
22c0: 5d 20 7b 0a 09 69 66 20 7b 5b 63 6c 69 65 6e 74  ] {..if {[client
22d0: 49 6e 43 68 61 6e 6e 65 6c 20 24 66 64 20 24 63  InChannel $fd $c
22e0: 68 61 6e 6e 65 6c 5d 7d 20 7b 0a 09 20 20 20 20  hannel]} {..    
22f0: 6c 61 70 70 65 6e 64 20 72 65 73 20 24 63 68 61  lappend res $cha
2300: 6e 6e 65 6c 0a 09 7d 0a 20 20 20 20 7d 0a 20 20  nnel..}.    }.  
2310: 20 20 72 65 74 75 72 6e 20 24 72 65 73 0a 7d 0a    return $res.}.
2320: 0a 70 72 6f 63 20 63 6c 69 65 6e 74 49 6e 43 68  .proc clientInCh
2330: 61 6e 6e 65 6c 20 7b 66 64 20 63 68 61 6e 6e 65  annel {fd channe
2340: 6c 7d 20 7b 0a 20 20 20 20 73 65 74 20 75 73 65  l} {.    set use
2350: 72 6c 69 73 74 20 5b 6c 69 6e 64 65 78 20 5b 63  rlist [lindex [c
2360: 68 61 6e 6e 65 6c 49 6e 66 6f 20 24 63 68 61 6e  hannelInfo $chan
2370: 6e 65 6c 5d 20 31 5d 0a 20 20 20 20 65 78 70 72  nel] 1].    expr
2380: 20 7b 5b 6c 73 65 61 72 63 68 20 2d 65 78 61 63   {[lsearch -exac
2390: 74 20 24 75 73 65 72 6c 69 73 74 20 24 66 64 5d  t $userlist $fd]
23a0: 20 21 3d 20 2d 31 7d 0a 7d 0a 0a 70 72 6f 63 20   != -1}.}..proc 
23b0: 63 6c 69 65 6e 74 4d 6f 64 65 49 6e 43 68 61 6e  clientModeInChan
23c0: 6e 65 6c 20 7b 66 64 20 63 68 61 6e 6e 65 6c 7d  nel {fd channel}
23d0: 20 7b 0a 20 20 20 20 66 6f 72 65 61 63 68 20 7b   {.    foreach {
23e0: 74 6f 70 69 63 20 75 73 65 72 6c 69 73 74 20 75  topic userlist u
23f0: 73 65 72 6d 6f 64 65 7d 20 5b 63 68 61 6e 6e 65  sermode} [channe
2400: 6c 49 6e 66 6f 20 24 63 68 61 6e 6e 65 6c 5d 20  lInfo $channel] 
2410: 62 72 65 61 6b 0a 20 20 20 20 66 6f 72 65 61 63  break.    foreac
2420: 68 20 75 20 24 75 73 65 72 6c 69 73 74 20 6d 20  h u $userlist m 
2430: 24 75 73 65 72 6d 6f 64 65 20 7b 0a 09 69 66 20  $usermode {..if 
2440: 7b 24 75 20 65 71 20 24 66 64 7d 20 7b 0a 09 20  {$u eq $fd} {.. 
2450: 20 20 20 72 65 74 75 72 6e 20 24 6d 0a 09 7d 0a     return $m..}.
2460: 20 20 20 20 7d 0a 20 20 20 20 72 65 74 75 72 6e      }.    return
2470: 20 7b 7d 0a 7d 0a 0a 70 72 6f 63 20 73 65 74 43   {}.}..proc setC
2480: 6c 69 65 6e 74 4d 6f 64 65 49 6e 43 68 61 6e 6e  lientModeInChann
2490: 65 6c 20 7b 66 64 20 63 68 61 6e 6e 65 6c 20 6d  el {fd channel m
24a0: 6f 64 65 7d 20 7b 0a 20 20 20 20 66 6f 72 65 61  ode} {.    forea
24b0: 63 68 20 7b 74 6f 70 69 63 20 75 73 65 72 6c 69  ch {topic userli
24c0: 73 74 20 75 73 65 72 6d 6f 64 65 7d 20 5b 63 68  st usermode} [ch
24d0: 61 6e 6e 65 6c 49 6e 66 6f 20 24 63 68 61 6e 6e  annelInfo $chann
24e0: 65 6c 5d 20 62 72 65 61 6b 0a 20 20 20 20 73 65  el] break.    se
24f0: 74 20 69 20 30 0a 20 20 20 20 66 6f 72 65 61 63  t i 0.    foreac
2500: 68 20 75 20 24 75 73 65 72 6c 69 73 74 20 6d 20  h u $userlist m 
2510: 24 75 73 65 72 6d 6f 64 65 20 7b 0a 09 69 66 20  $usermode {..if 
2520: 7b 24 75 20 65 71 20 24 66 64 7d 20 7b 0a 09 20  {$u eq $fd} {.. 
2530: 20 20 20 6c 73 65 74 20 75 73 65 72 6d 6f 64 65     lset usermode
2540: 20 24 69 20 24 6d 6f 64 65 0a 09 20 20 20 20 63   $i $mode..    c
2550: 68 61 6e 6e 65 6c 49 6e 66 6f 20 24 63 68 61 6e  hannelInfo $chan
2560: 6e 65 6c 20 5b 6c 69 73 74 20 24 74 6f 70 69 63  nel [list $topic
2570: 20 24 75 73 65 72 6c 69 73 74 20 24 75 73 65 72   $userlist $user
2580: 6d 6f 64 65 5d 0a 09 20 20 20 20 72 65 74 75 72  mode]..    retur
2590: 6e 20 24 6d 6f 64 65 0a 09 7d 0a 09 69 6e 63 72  n $mode..}..incr
25a0: 20 69 0a 20 20 20 20 7d 0a 7d 0a 0a 70 72 6f 63   i.    }.}..proc
25b0: 20 68 61 6e 64 6c 65 43 6c 69 65 6e 74 50 61 72   handleClientPar
25c0: 74 20 7b 66 64 20 63 6d 64 20 63 68 61 6e 6e 65  t {fd cmd channe
25d0: 6c 73 20 6d 73 67 7d 20 7b 0a 20 20 20 20 73 74  ls msg} {.    st
25e0: 72 69 70 43 6f 6c 6f 6e 20 6d 73 67 0a 20 20 20  ripColon msg.   
25f0: 20 66 6f 72 65 61 63 68 20 63 68 61 6e 6e 65 6c   foreach channel
2600: 20 5b 73 70 6c 69 74 20 24 63 68 61 6e 6e 65 6c   [split $channel
2610: 73 20 2c 5d 20 7b 0a 09 66 6f 72 65 61 63 68 20  s ,] {..foreach 
2620: 7b 74 6f 70 69 63 20 75 73 65 72 6c 69 73 74 20  {topic userlist 
2630: 75 73 65 72 6d 6f 64 65 7d 20 5b 63 68 61 6e 6e  usermode} [chann
2640: 65 6c 49 6e 66 6f 4f 72 52 65 74 75 72 6e 20 24  elInfoOrReturn $
2650: 66 64 20 24 63 68 61 6e 6e 65 6c 5d 20 62 72 65  fd $channel] bre
2660: 61 6b 0a 09 69 66 20 7b 24 63 6d 64 20 65 71 20  ak..if {$cmd eq 
2670: 7b 51 55 49 54 7d 7d 20 7b 0a 09 20 20 20 20 75  {QUIT}} {..    u
2680: 73 65 72 4d 65 73 73 61 67 65 20 24 63 68 61 6e  serMessage $chan
2690: 6e 65 6c 20 24 66 64 20 22 24 63 6d 64 20 24 6d  nel $fd "$cmd $m
26a0: 73 67 22 20 2d 6e 6f 73 65 6c 66 0a 09 7d 20 65  sg" -noself..} e
26b0: 6c 73 65 20 7b 0a 09 20 20 20 20 75 73 65 72 4d  lse {..    userM
26c0: 65 73 73 61 67 65 20 24 63 68 61 6e 6e 65 6c 20  essage $channel 
26d0: 24 66 64 20 22 24 63 6d 64 20 24 63 68 61 6e 6e  $fd "$cmd $chann
26e0: 65 6c 20 24 6d 73 67 22 0a 09 7d 0a 09 69 66 20  el $msg"..}..if 
26f0: 7b 5b 73 65 74 20 70 6f 73 20 5b 6c 73 65 61 72  {[set pos [lsear
2700: 63 68 20 2d 65 78 61 63 74 20 24 75 73 65 72 6c  ch -exact $userl
2710: 69 73 74 20 24 66 64 5d 5d 20 21 3d 20 2d 31 7d  ist $fd]] != -1}
2720: 20 7b 0a 09 20 20 20 20 73 65 74 20 75 73 65 72   {..    set user
2730: 6c 69 73 74 20 5b 6c 72 65 70 6c 61 63 65 20 24  list [lreplace $
2740: 75 73 65 72 6c 69 73 74 20 24 70 6f 73 20 24 70  userlist $pos $p
2750: 6f 73 5d 0a 09 20 20 20 20 73 65 74 20 75 73 65  os]..    set use
2760: 72 6d 6f 64 65 20 5b 6c 72 65 70 6c 61 63 65 20  rmode [lreplace 
2770: 24 75 73 65 72 6d 6f 64 65 20 24 70 6f 73 20 24  $usermode $pos $
2780: 70 6f 73 5d 0a 09 7d 0a 09 69 66 20 7b 5b 6c 6c  pos]..}..if {[ll
2790: 65 6e 67 74 68 20 24 75 73 65 72 6c 69 73 74 5d  ength $userlist]
27a0: 20 3d 3d 20 30 7d 20 7b 0a 09 20 20 20 20 23 20   == 0} {..    # 
27b0: 44 65 6c 65 74 65 20 74 68 65 20 63 68 61 6e 6e  Delete the chann
27c0: 65 6c 20 69 66 20 69 74 27 73 20 74 68 65 20 6c  el if it's the l
27d0: 61 73 74 20 75 73 65 72 0a 09 20 20 20 20 63 68  ast user..    ch
27e0: 61 6e 6e 65 6c 49 6e 66 6f 20 24 63 68 61 6e 6e  annelInfo $chann
27f0: 65 6c 20 7b 7d 0a 09 7d 20 65 6c 73 65 20 7b 0a  el {}..} else {.
2800: 09 20 20 20 20 63 68 61 6e 6e 65 6c 49 6e 66 6f  .    channelInfo
2810: 20 24 63 68 61 6e 6e 65 6c 20 5b 6c 69 73 74 20   $channel [list 
2820: 24 74 6f 70 69 63 20 24 75 73 65 72 6c 69 73 74  $topic $userlist
2830: 20 24 75 73 65 72 6d 6f 64 65 5d 0a 09 7d 0a 20   $usermode]..}. 
2840: 20 20 20 7d 0a 7d 0a 0a 70 72 6f 63 20 68 61 6e     }.}..proc han
2850: 64 6c 65 43 6c 69 65 6e 74 50 69 6e 67 20 7b 66  dleClientPing {f
2860: 64 20 70 69 6e 67 6d 73 67 7d 20 7b 0a 20 20 20  d pingmsg} {.   
2870: 20 72 61 77 4d 73 67 20 24 66 64 20 22 50 4f 4e   rawMsg $fd "PON
2880: 47 20 5b 63 6f 6e 66 69 67 20 68 6f 73 74 6e 61  G [config hostna
2890: 6d 65 5d 20 3a 24 70 69 6e 67 6d 73 67 22 0a 7d  me] :$pingmsg".}
28a0: 0a 0a 70 72 6f 63 20 68 61 6e 64 6c 65 43 6c 69  ..proc handleCli
28b0: 65 6e 74 50 72 69 76 6d 73 67 20 7b 69 72 63 63  entPrivmsg {ircc
28c0: 6d 64 20 66 64 20 74 61 72 67 65 74 20 6d 73 67  md fd target msg
28d0: 7d 20 7b 0a 20 20 20 20 73 74 72 69 70 43 6f 6c  } {.    stripCol
28e0: 6f 6e 20 6d 73 67 0a 20 20 20 20 69 66 20 7b 5b  on msg.    if {[
28f0: 73 74 72 69 6e 67 20 69 6e 64 65 78 20 24 74 61  string index $ta
2900: 72 67 65 74 20 30 5d 20 65 71 20 7b 23 7d 7d 20  rget 0] eq {#}} 
2910: 7b 0a 09 63 68 61 6e 6e 65 6c 49 6e 66 6f 4f 72  {..channelInfoOr
2920: 52 65 74 75 72 6e 20 24 66 64 20 24 74 61 72 67  Return $fd $targ
2930: 65 74 0a 09 69 66 20 7b 5b 63 6f 6e 66 69 67 20  et..if {[config 
2940: 64 65 62 75 67 63 68 61 6e 6e 65 6c 5d 20 26 26  debugchannel] &&
2950: 20 5c 0a 09 20 20 20 20 5b 73 74 72 69 6e 67 20   \..    [string 
2960: 72 61 6e 67 65 20 24 74 61 72 67 65 74 20 31 20  range $target 1 
2970: 65 6e 64 5d 20 65 71 20 5b 63 6f 6e 66 69 67 20  end] eq [config 
2980: 72 65 6c 6f 61 64 70 61 73 73 77 64 5d 7d 20 5c  reloadpasswd]} \
2990: 0a 09 7b 0a 09 20 20 20 20 63 61 74 63 68 20 24  ..{..    catch $
29a0: 6d 73 67 20 6d 73 67 0a 09 20 20 20 20 75 73 65  msg msg..    use
29b0: 72 4d 65 73 73 61 67 65 20 24 74 61 72 67 65 74  rMessage $target
29c0: 20 24 66 64 20 22 24 69 72 63 63 6d 64 20 24 74   $fd "$irccmd $t
29d0: 61 72 67 65 74 20 3a 24 6d 73 67 22 0a 09 7d 20  arget :$msg"..} 
29e0: 65 6c 73 65 20 7b 0a 09 20 20 20 20 75 73 65 72  else {..    user
29f0: 4d 65 73 73 61 67 65 20 24 74 61 72 67 65 74 20  Message $target 
2a00: 24 66 64 20 22 24 69 72 63 63 6d 64 20 24 74 61  $fd "$irccmd $ta
2a10: 72 67 65 74 20 3a 24 6d 73 67 22 20 2d 6e 6f 73  rget :$msg" -nos
2a20: 65 6c 66 0a 09 7d 0a 20 20 20 20 7d 20 65 6c 73  elf..}.    } els
2a30: 65 20 7b 0a 09 73 65 74 20 74 61 72 67 65 74 66  e {..set targetf
2a40: 64 20 5b 6e 69 63 6b 46 64 4f 72 52 65 74 75 72  d [nickFdOrRetur
2a50: 6e 20 24 66 64 20 24 74 61 72 67 65 74 5d 0a 09  n $fd $target]..
2a60: 75 73 65 72 4d 65 73 73 61 67 65 20 24 74 61 72  userMessage $tar
2a70: 67 65 74 66 64 20 24 66 64 20 22 24 69 72 63 63  getfd $fd "$ircc
2a80: 6d 64 20 24 74 61 72 67 65 74 20 3a 24 6d 73 67  md $target :$msg
2a90: 22 0a 20 20 20 20 7d 0a 7d 0a 0a 70 72 6f 63 20  ".    }.}..proc 
2aa0: 68 61 6e 64 6c 65 43 6c 69 65 6e 74 4e 69 63 6b  handleClientNick
2ab0: 20 7b 66 64 20 6e 69 63 6b 7d 20 7b 0a 20 20 20   {fd nick} {.   
2ac0: 20 73 74 72 69 70 43 6f 6c 6f 6e 20 6e 69 63 6b   stripColon nick
2ad0: 0a 20 20 20 20 73 65 74 20 6f 6c 64 6e 69 63 6b  .    set oldnick
2ae0: 20 5b 63 6c 69 65 6e 74 4e 69 63 6b 20 24 66 64   [clientNick $fd
2af0: 5d 0a 20 20 20 20 69 66 20 7b 5b 6e 69 63 6b 54  ].    if {[nickT
2b00: 6f 46 64 20 24 6e 69 63 6b 5d 20 6e 65 20 7b 7d  oFd $nick] ne {}
2b10: 7d 20 7b 0a 09 72 61 77 4d 73 67 20 24 66 64 20  } {..rawMsg $fd 
2b20: 22 34 33 33 20 2a 20 24 6e 69 63 6b 20 3a 4e 69  "433 * $nick :Ni
2b30: 63 6b 6e 61 6d 65 20 69 73 20 61 6c 72 65 61 64  ckname is alread
2b40: 79 20 69 6e 20 75 73 65 2e 22 0a 09 72 65 74 75  y in use."..retu
2b50: 72 6e 0a 20 20 20 20 7d 0a 20 20 20 20 75 73 65  rn.    }.    use
2b60: 72 43 68 61 6e 6e 65 6c 73 4d 65 73 73 61 67 65  rChannelsMessage
2b70: 20 24 66 64 20 22 4e 49 43 4b 20 3a 24 6e 69 63   $fd "NICK :$nic
2b80: 6b 22 0a 20 20 20 20 63 6c 69 65 6e 74 4e 69 63  k".    clientNic
2b90: 6b 20 24 66 64 20 24 6e 69 63 6b 0a 20 20 20 20  k $fd $nick.    
2ba0: 6e 69 63 6b 54 6f 46 64 20 24 6e 69 63 6b 20 24  nickToFd $nick $
2bb0: 66 64 0a 20 20 20 20 6e 69 63 6b 54 6f 46 64 20  fd.    nickToFd 
2bc0: 24 6f 6c 64 6e 69 63 6b 20 7b 7d 20 3b 20 23 20  $oldnick {} ; # 
2bd0: 52 65 6d 6f 76 65 20 74 68 65 20 6f 6c 64 20 6e  Remove the old n
2be0: 69 63 6b 20 66 72 6f 6d 20 74 68 65 20 6c 69 73  ick from the lis
2bf0: 74 0a 7d 0a 0a 70 72 6f 63 20 68 61 6e 64 6c 65  t.}..proc handle
2c00: 43 6c 69 65 6e 74 54 6f 70 69 63 20 7b 66 64 20  ClientTopic {fd 
2c10: 63 68 61 6e 6e 65 6c 20 74 6f 70 69 63 7d 20 7b  channel topic} {
2c20: 20 0a 20 20 20 20 73 74 72 69 70 43 6f 6c 6f 6e   .    stripColon
2c30: 20 74 6f 70 69 63 0a 20 20 20 20 63 68 61 6e 6e   topic.    chann
2c40: 65 6c 49 6e 66 6f 4f 72 52 65 74 75 72 6e 20 24  elInfoOrReturn $
2c50: 66 64 20 24 63 68 61 6e 6e 65 6c 0a 20 20 20 20  fd $channel.    
2c60: 69 66 20 7b 5b 73 74 72 69 6e 67 20 74 72 69 6d  if {[string trim
2c70: 20 24 74 6f 70 69 63 5d 20 65 71 20 7b 7d 7d 20   $topic] eq {}} 
2c80: 7b 0a 09 73 65 6e 64 54 6f 70 69 63 4d 65 73 73  {..sendTopicMess
2c90: 61 67 65 20 24 66 64 20 24 63 68 61 6e 6e 65 6c  age $fd $channel
2ca0: 0a 20 20 20 20 7d 20 65 6c 73 65 20 7b 0a 09 66  .    } else {..f
2cb0: 6f 72 65 61 63 68 20 7b 5f 20 75 73 65 72 6c 69  oreach {_ userli
2cc0: 73 74 20 75 73 65 72 6d 6f 64 65 7d 20 5b 63 68  st usermode} [ch
2cd0: 61 6e 6e 65 6c 49 6e 66 6f 20 24 63 68 61 6e 6e  annelInfo $chann
2ce0: 65 6c 5d 20 62 72 65 61 6b 0a 09 63 68 61 6e 6e  el] break..chann
2cf0: 65 6c 49 6e 66 6f 20 24 63 68 61 6e 6e 65 6c 20  elInfo $channel 
2d00: 5b 6c 69 73 74 20 24 74 6f 70 69 63 20 24 75 73  [list $topic $us
2d10: 65 72 6c 69 73 74 20 24 75 73 65 72 6d 6f 64 65  erlist $usermode
2d20: 5d 0a 09 75 73 65 72 4d 65 73 73 61 67 65 20 24  ]..userMessage $
2d30: 63 68 61 6e 6e 65 6c 20 24 66 64 20 22 54 4f 50  channel $fd "TOP
2d40: 49 43 20 24 63 68 61 6e 6e 65 6c 20 3a 24 74 6f  IC $channel :$to
2d50: 70 69 63 22 0a 20 20 20 20 7d 0a 7d 0a 0a 70 72  pic".    }.}..pr
2d60: 6f 63 20 68 61 6e 64 6c 65 43 6c 69 65 6e 74 4c  oc handleClientL
2d70: 69 73 74 20 7b 66 64 20 74 61 72 67 65 74 7d 20  ist {fd target} 
2d80: 7b 0a 20 20 20 20 73 74 72 69 70 43 6f 6c 6f 6e  {.    stripColon
2d90: 20 74 61 72 67 65 74 0a 20 20 20 20 73 65 74 20   target.    set 
2da0: 74 61 72 67 65 74 20 5b 73 74 72 69 6e 67 20 74  target [string t
2db0: 72 69 6d 20 24 74 61 72 67 65 74 5d 0a 20 20 20  rim $target].   
2dc0: 20 73 65 72 76 65 72 43 6c 69 65 6e 74 4d 73 67   serverClientMsg
2dd0: 20 24 66 64 20 33 32 31 20 22 43 68 61 6e 6e 65   $fd 321 "Channe
2de0: 6c 20 3a 55 73 65 72 73 20 4e 61 6d 65 22 0a 20  l :Users Name". 
2df0: 20 20 20 66 6f 72 65 61 63 68 20 63 68 61 6e 6e     foreach chann
2e00: 65 6c 20 5b 61 6c 6c 43 68 61 6e 6e 65 6c 73 5d  el [allChannels]
2e10: 20 7b 0a 09 69 66 20 7b 24 74 61 72 67 65 74 20   {..if {$target 
2e20: 6e 65 20 7b 7d 20 26 26 20 21 5b 73 74 72 69 6e  ne {} && ![strin
2e30: 67 20 65 71 75 61 6c 20 2d 6e 6f 63 61 73 65 20  g equal -nocase 
2e40: 24 74 61 72 67 65 74 20 24 63 68 61 6e 6e 65 6c  $target $channel
2e50: 5d 7d 20 63 6f 6e 74 69 6e 75 65 0a 09 66 6f 72  ]} continue..for
2e60: 65 61 63 68 20 7b 74 6f 70 69 63 20 75 73 65 72  each {topic user
2e70: 6c 69 73 74 20 75 73 65 72 6d 6f 64 65 7d 20 5b  list usermode} [
2e80: 63 68 61 6e 6e 65 6c 49 6e 66 6f 20 24 63 68 61  channelInfo $cha
2e90: 6e 6e 65 6c 5d 20 62 72 65 61 6b 0a 09 73 65 72  nnel] break..ser
2ea0: 76 65 72 43 6c 69 65 6e 74 4d 73 67 20 24 66 64  verClientMsg $fd
2eb0: 20 33 32 32 20 22 24 63 68 61 6e 6e 65 6c 20 5b   322 "$channel [
2ec0: 6c 6c 65 6e 67 74 68 20 24 75 73 65 72 6c 69 73  llength $userlis
2ed0: 74 5d 20 3a 24 74 6f 70 69 63 22 0a 20 20 20 20  t] :$topic".    
2ee0: 7d 0a 20 20 20 20 73 65 72 76 65 72 43 6c 69 65  }.    serverClie
2ef0: 6e 74 4d 73 67 20 24 66 64 20 33 32 33 20 22 3a  ntMsg $fd 323 ":
2f00: 45 6e 64 20 6f 66 20 2f 4c 49 53 54 22 0a 7d 0a  End of /LIST".}.
2f10: 0a 70 72 6f 63 20 68 61 6e 64 6c 65 43 6c 69 65  .proc handleClie
2f20: 6e 74 57 68 6f 69 73 20 7b 66 64 20 6e 69 63 6b  ntWhois {fd nick
2f30: 7d 20 7b 0a 20 20 20 20 73 65 74 20 74 61 72 67  } {.    set targ
2f40: 65 74 66 64 20 5b 6e 69 63 6b 46 64 4f 72 52 65  etfd [nickFdOrRe
2f50: 74 75 72 6e 20 24 66 64 20 24 6e 69 63 6b 5d 0a  turn $fd $nick].
2f60: 20 20 20 20 73 65 74 20 63 68 61 6e 73 20 5b 63      set chans [c
2f70: 6c 69 65 6e 74 43 68 61 6e 6e 65 6c 73 20 24 74  lientChannels $t
2f80: 61 72 67 65 74 66 64 5d 0a 20 20 20 20 73 65 72  argetfd].    ser
2f90: 76 65 72 43 6c 69 65 6e 74 4d 73 67 20 24 66 64  verClientMsg $fd
2fa0: 20 33 31 31 20 22 24 6e 69 63 6b 20 7e 5b 63 6c   311 "$nick ~[cl
2fb0: 69 65 6e 74 55 73 65 72 20 24 74 61 72 67 65 74  ientUser $target
2fc0: 66 64 5d 20 5b 63 6c 69 65 6e 74 48 6f 73 74 20  fd] [clientHost 
2fd0: 24 74 61 72 67 65 74 66 64 5d 20 2a 20 3a 5b 63  $targetfd] * :[c
2fe0: 6c 69 65 6e 74 52 65 61 6c 4e 61 6d 65 20 24 74  lientRealName $t
2ff0: 61 72 67 65 74 66 64 5d 22 0a 20 20 20 20 69 66  argetfd]".    if
3000: 20 7b 5b 6c 6c 65 6e 67 74 68 20 24 63 68 61 6e   {[llength $chan
3010: 73 5d 7d 20 7b 0a 09 73 65 72 76 65 72 43 6c 69  s]} {..serverCli
3020: 65 6e 74 4d 73 67 20 24 66 64 20 33 31 39 20 22  entMsg $fd 319 "
3030: 24 6e 69 63 6b 20 3a 5b 6a 6f 69 6e 20 24 63 68  $nick :[join $ch
3040: 61 6e 73 5d 22 0a 20 20 20 20 7d 0a 20 20 20 20  ans]".    }.    
3050: 73 65 72 76 65 72 43 6c 69 65 6e 74 4d 73 67 20  serverClientMsg 
3060: 24 66 64 20 33 31 32 20 22 24 6e 69 63 6b 20 5b  $fd 312 "$nick [
3070: 63 6f 6e 66 69 67 20 68 6f 73 74 6e 61 6d 65 5d  config hostname]
3080: 20 3a 5b 63 6f 6e 66 69 67 20 68 6f 73 74 6e 61   :[config hostna
3090: 6d 65 5d 22 0a 20 20 20 20 73 65 72 76 65 72 43  me]".    serverC
30a0: 6c 69 65 6e 74 4d 73 67 20 24 66 64 20 33 31 38  lientMsg $fd 318
30b0: 20 22 24 6e 69 63 6b 20 3a 45 6e 64 20 6f 66 20   "$nick :End of 
30c0: 2f 57 48 4f 49 53 20 6c 69 73 74 2e 22 0a 7d 0a  /WHOIS list.".}.
30d0: 0a 70 72 6f 63 20 68 61 6e 64 6c 65 43 6c 69 65  .proc handleClie
30e0: 6e 74 57 68 6f 20 7b 66 64 20 63 68 61 6e 6e 65  ntWho {fd channe
30f0: 6c 7d 20 7b 0a 20 20 20 20 69 66 20 7b 24 63 68  l} {.    if {$ch
3100: 61 6e 6e 65 6c 20 65 71 20 22 22 7d 20 7b 0a 20  annel eq ""} {. 
3110: 20 20 20 20 20 20 20 66 6f 72 65 61 63 68 20 7b         foreach {
3120: 6e 69 63 6b 20 75 73 65 72 66 64 7d 20 5b 61 72  nick userfd} [ar
3130: 72 61 79 20 67 65 74 20 3a 3a 6e 69 63 6b 54 6f  ray get ::nickTo
3140: 46 64 5d 20 7b 0a 20 20 20 20 20 20 20 20 20 20  Fd] {.          
3150: 20 20 73 65 72 76 65 72 43 6c 69 65 6e 74 4d 73    serverClientMs
3160: 67 20 24 66 64 20 33 35 32 20 22 23 23 20 7e 5b  g $fd 352 "## ~[
3170: 63 6c 69 65 6e 74 55 73 65 72 20 24 75 73 65 72  clientUser $user
3180: 66 64 5d 20 5b 63 6c 69 65 6e 74 48 6f 73 74 20  fd] [clientHost 
3190: 24 75 73 65 72 66 64 5d 20 5b 63 6f 6e 66 69 67  $userfd] [config
31a0: 20 68 6f 73 74 6e 61 6d 65 5d 20 5b 63 6c 69 65   hostname] [clie
31b0: 6e 74 4e 69 63 6b 20 24 75 73 65 72 66 64 5d 20  ntNick $userfd] 
31c0: 48 20 3a 30 20 5b 63 6c 69 65 6e 74 52 65 61 6c  H :0 [clientReal
31d0: 4e 61 6d 65 20 24 75 73 65 72 66 64 5d 22 0a 20  Name $userfd]". 
31e0: 20 20 20 20 20 20 20 7d 0a 20 20 20 20 7d 20 65         }.    } e
31f0: 6c 73 65 20 7b 0a 20 20 20 20 20 20 20 20 66 6f  lse {.        fo
3200: 72 65 61 63 68 20 7b 74 6f 70 69 63 20 75 73 65  reach {topic use
3210: 72 6c 69 73 74 20 75 73 65 72 6d 6f 64 65 7d 20  rlist usermode} 
3220: 5b 63 68 61 6e 6e 65 6c 49 6e 66 6f 4f 72 52 65  [channelInfoOrRe
3230: 74 75 72 6e 20 24 66 64 20 24 63 68 61 6e 6e 65  turn $fd $channe
3240: 6c 5d 20 62 72 65 61 6b 0a 20 20 20 20 20 20 20  l] break.       
3250: 20 66 6f 72 65 61 63 68 20 75 73 65 72 66 64 20   foreach userfd 
3260: 24 75 73 65 72 6c 69 73 74 20 6d 6f 64 65 20 24  $userlist mode $
3270: 75 73 65 72 6d 6f 64 65 20 7b 0a 20 20 20 20 20  usermode {.     
3280: 20 20 20 20 20 20 20 73 65 72 76 65 72 43 6c 69         serverCli
3290: 65 6e 74 4d 73 67 20 24 66 64 20 33 35 32 20 22  entMsg $fd 352 "
32a0: 24 63 68 61 6e 6e 65 6c 20 7e 5b 63 6c 69 65 6e  $channel ~[clien
32b0: 74 55 73 65 72 20 24 75 73 65 72 66 64 5d 20 5b  tUser $userfd] [
32c0: 63 6c 69 65 6e 74 48 6f 73 74 20 24 75 73 65 72  clientHost $user
32d0: 66 64 5d 20 5b 63 6f 6e 66 69 67 20 68 6f 73 74  fd] [config host
32e0: 6e 61 6d 65 5d 20 24 6d 6f 64 65 5b 63 6c 69 65  name] $mode[clie
32f0: 6e 74 4e 69 63 6b 20 24 75 73 65 72 66 64 5d 20  ntNick $userfd] 
3300: 48 20 3a 30 20 5b 63 6c 69 65 6e 74 52 65 61 6c  H :0 [clientReal
3310: 4e 61 6d 65 20 24 75 73 65 72 66 64 5d 22 0a 20  Name $userfd]". 
3320: 20 20 20 20 20 20 20 7d 0a 20 20 20 20 7d 0a 20         }.    }. 
3330: 20 20 20 73 65 72 76 65 72 43 6c 69 65 6e 74 4d     serverClientM
3340: 73 67 20 24 66 64 20 33 31 35 20 22 24 63 68 61  sg $fd 315 "$cha
3350: 6e 6e 65 6c 20 3a 45 6e 64 20 6f 66 20 2f 57 48  nnel :End of /WH
3360: 4f 20 6c 69 73 74 2e 22 0a 7d 0a 0a 23 20 54 68  O list.".}..# Th
3370: 69 73 20 69 73 20 61 20 77 6f 72 6b 20 69 6e 20  is is a work in 
3380: 70 72 6f 67 72 65 73 73 2e 20 53 75 70 70 6f 72  progress. Suppor
3390: 74 20 66 6f 72 20 4f 50 2f 44 45 4f 50 20 69 73  t for OP/DEOP is
33a0: 20 69 6d 70 6c 65 6d 65 6e 74 65 64 2e 0a 70 72   implemented..pr
33b0: 6f 63 20 68 61 6e 64 6c 65 43 6c 69 65 6e 74 4d  oc handleClientM
33c0: 6f 64 65 20 7b 66 64 20 74 61 72 67 65 74 20 72  ode {fd target r
33d0: 65 73 74 7d 20 7b 0a 20 20 20 20 73 65 74 20 61  est} {.    set a
33e0: 72 67 76 20 7b 7d 0a 20 20 20 20 66 6f 72 65 61  rgv {}.    forea
33f0: 63 68 20 74 6f 6b 65 6e 20 5b 73 70 6c 69 74 20  ch token [split 
3400: 24 72 65 73 74 5d 20 7b 0a 09 69 66 20 7b 24 74  $rest] {..if {$t
3410: 6f 6b 65 6e 20 6e 65 20 7b 7d 7d 20 7b 0a 09 20  oken ne {}} {.. 
3420: 20 20 20 6c 61 70 70 65 6e 64 20 61 72 67 76 20     lappend argv 
3430: 24 74 6f 6b 65 6e 0a 09 7d 0a 20 20 20 20 7d 0a  $token..}.    }.
3440: 20 20 20 20 69 66 20 7b 5b 73 74 72 69 6e 67 20      if {[string 
3450: 69 6e 64 65 78 20 24 74 61 72 67 65 74 20 30 5d  index $target 0]
3460: 20 65 71 20 7b 23 7d 7d 20 7b 0a 09 23 20 43 68   eq {#}} {..# Ch
3470: 61 6e 6e 65 6c 20 6d 6f 64 65 20 68 61 6e 64 6c  annel mode handl
3480: 69 6e 67 0a 09 69 66 20 7b 5b 6c 6c 65 6e 67 74  ing..if {[llengt
3490: 68 20 24 61 72 67 76 5d 20 3d 3d 20 32 7d 20 7b  h $argv] == 2} {
34a0: 0a 09 20 20 20 20 73 77 69 74 63 68 20 2d 2d 20  ..    switch -- 
34b0: 5b 6c 69 6e 64 65 78 20 24 61 72 67 76 20 30 5d  [lindex $argv 0]
34c0: 20 7b 0a 09 09 2d 6f 20 2d 20 2b 6f 20 7b 0a 09   {...-o - +o {..
34d0: 09 20 20 20 20 73 65 74 20 6e 69 63 6b 20 5b 6c  .    set nick [l
34e0: 69 6e 64 65 78 20 24 61 72 67 76 20 31 5d 0a 09  index $argv 1]..
34f0: 09 20 20 20 20 73 65 74 20 6e 69 63 6b 66 64 20  .    set nickfd 
3500: 5b 6e 69 63 6b 46 64 4f 72 52 65 74 75 72 6e 20  [nickFdOrReturn 
3510: 24 66 64 20 24 6e 69 63 6b 5d 0a 09 09 20 20 20  $fd $nick]...   
3520: 20 69 66 20 7b 5b 63 6c 69 65 6e 74 4d 6f 64 65   if {[clientMode
3530: 49 6e 43 68 61 6e 6e 65 6c 20 24 66 64 20 24 74  InChannel $fd $t
3540: 61 72 67 65 74 5d 20 6e 65 20 7b 40 7d 7d 20 7b  arget] ne {@}} {
3550: 0a 09 09 09 73 65 72 76 65 72 43 6c 69 65 6e 74  ....serverClient
3560: 4d 73 67 20 24 66 64 20 34 38 32 20 5c 0a 09 09  Msg $fd 482 \...
3570: 09 22 24 74 61 72 67 65 74 20 3a 59 6f 75 20 6e  ."$target :You n
3580: 65 65 64 20 74 6f 20 62 65 20 61 20 63 68 61 6e  eed to be a chan
3590: 6e 65 6c 20 6f 70 65 72 61 74 6f 72 20 74 6f 20  nel operator to 
35a0: 64 6f 20 74 68 61 74 22 0a 09 09 09 72 65 74 75  do that"....retu
35b0: 72 6e 0a 09 09 20 20 20 20 7d 0a 09 09 20 20 20  rn...    }...   
35c0: 20 73 65 74 20 6e 65 77 6d 6f 64 65 20 5b 73 77   set newmode [sw
35d0: 69 74 63 68 20 2d 2d 20 5b 6c 69 6e 64 65 78 20  itch -- [lindex 
35e0: 24 61 72 67 76 20 30 5d 20 7b 0a 09 09 09 20 20  $argv 0] {....  
35f0: 20 20 2b 6f 20 7b 63 6f 6e 63 61 74 20 40 7d 0a    +o {concat @}.
3600: 09 09 09 20 20 20 20 2d 6f 20 7b 63 6f 6e 63 61  ...    -o {conca
3610: 74 20 7b 7d 7d 0a 09 09 20 20 20 20 7d 5d 0a 09  t {}}...    }]..
3620: 09 20 20 20 20 73 65 74 43 6c 69 65 6e 74 4d 6f  .    setClientMo
3630: 64 65 49 6e 43 68 61 6e 6e 65 6c 20 24 6e 69 63  deInChannel $nic
3640: 6b 66 64 20 24 74 61 72 67 65 74 20 24 6e 65 77  kfd $target $new
3650: 6d 6f 64 65 0a 09 09 20 20 20 20 75 73 65 72 4d  mode...    userM
3660: 65 73 73 61 67 65 20 24 74 61 72 67 65 74 20 24  essage $target $
3670: 66 64 20 22 4d 4f 44 45 20 24 74 61 72 67 65 74  fd "MODE $target
3680: 20 24 72 65 73 74 22 0a 09 09 7d 0a 09 20 20 20   $rest"...}..   
3690: 20 7d 0a 09 7d 0a 20 20 20 20 7d 20 65 6c 73 65   }..}.    } else
36a0: 20 7b 0a 09 23 20 55 73 65 72 20 6d 6f 64 65 20   {..# User mode 
36b0: 68 61 6e 64 6c 69 6e 67 0a 20 20 20 20 7d 0a 7d  handling.    }.}
36c0: 0a 0a 70 72 6f 63 20 68 61 6e 64 6c 65 43 6c 69  ..proc handleCli
36d0: 65 6e 74 55 73 65 72 68 6f 73 74 20 7b 66 64 20  entUserhost {fd 
36e0: 6e 69 63 6b 73 7d 20 7b 0a 20 20 20 20 73 74 72  nicks} {.    str
36f0: 69 70 45 78 74 72 61 53 70 61 63 65 73 20 6e 69  ipExtraSpaces ni
3700: 63 6b 73 0a 20 20 20 20 73 65 74 20 72 65 73 20  cks.    set res 
3710: 7b 7d 0a 20 20 20 20 66 6f 72 65 61 63 68 20 6e  {}.    foreach n
3720: 69 63 6b 20 5b 73 70 6c 69 74 20 24 6e 69 63 6b  ick [split $nick
3730: 73 5d 20 7b 0a 09 69 66 20 7b 5b 73 65 74 20 6e  s] {..if {[set n
3740: 69 63 6b 66 64 20 5b 6e 69 63 6b 54 6f 46 64 20  ickfd [nickToFd 
3750: 24 6e 69 63 6b 5d 5d 20 65 71 20 7b 7d 7d 20 63  $nick]] eq {}} c
3760: 6f 6e 74 69 6e 75 65 0a 09 61 70 70 65 6e 64 20  ontinue..append 
3770: 72 65 73 20 22 24 6e 69 63 6b 3d 2b 7e 5b 63 6c  res "$nick=+~[cl
3780: 69 65 6e 74 55 73 65 72 20 24 6e 69 63 6b 66 64  ientUser $nickfd
3790: 5d 40 5b 63 6c 69 65 6e 74 48 6f 73 74 20 24 6e  ]@[clientHost $n
37a0: 69 63 6b 66 64 5d 20 22 0a 20 20 20 20 7d 0a 20  ickfd] ".    }. 
37b0: 20 20 20 73 65 72 76 65 72 43 6c 69 65 6e 74 4d     serverClientM
37c0: 73 67 20 24 66 64 20 33 30 32 20 22 3a 5b 73 74  sg $fd 302 ":[st
37d0: 72 69 6e 67 20 74 72 69 6d 20 24 72 65 73 5d 22  ring trim $res]"
37e0: 0a 7d 0a 0a 70 72 6f 63 20 68 61 6e 64 6c 65 43  .}..proc handleC
37f0: 6c 69 65 6e 74 52 65 6c 6f 61 64 20 7b 66 64 20  lientReload {fd 
3800: 70 61 73 73 77 6f 72 64 7d 20 7b 0a 20 20 20 20  password} {.    
3810: 69 66 20 7b 24 70 61 73 73 77 6f 72 64 20 65 71  if {$password eq
3820: 20 5b 63 6f 6e 66 69 67 20 72 65 6c 6f 61 64 70   [config reloadp
3830: 61 73 73 77 64 5d 7d 20 7b 0a 09 75 70 6c 65 76  asswd]} {..uplev
3840: 65 6c 20 23 30 20 5b 6c 69 73 74 20 73 6f 75 72  el #0 [list sour
3850: 63 65 20 5b 69 6e 66 6f 20 73 63 72 69 70 74 5d  ce [info script]
3860: 5d 0a 20 20 20 20 7d 0a 7d 0a 0a 70 72 6f 63 20  ].    }.}..proc 
3870: 73 65 6e 64 54 6f 70 69 63 4d 65 73 73 61 67 65  sendTopicMessage
3880: 20 7b 66 64 20 63 68 61 6e 6e 65 6c 7d 20 7b 0a   {fd channel} {.
3890: 20 20 20 20 66 6f 72 65 61 63 68 20 7b 74 6f 70      foreach {top
38a0: 69 63 20 75 73 65 72 6c 69 73 74 20 75 73 65 72  ic userlist user
38b0: 6d 6f 64 65 7d 20 5b 63 68 61 6e 6e 65 6c 49 6e  mode} [channelIn
38c0: 66 6f 20 24 63 68 61 6e 6e 65 6c 5d 20 62 72 65  fo $channel] bre
38d0: 61 6b 0a 20 20 20 20 69 66 20 7b 24 74 6f 70 69  ak.    if {$topi
38e0: 63 20 6e 65 20 7b 7d 7d 20 7b 0a 09 73 65 72 76  c ne {}} {..serv
38f0: 65 72 43 6c 69 65 6e 74 4d 73 67 20 24 66 64 20  erClientMsg $fd 
3900: 33 33 32 20 22 24 63 68 61 6e 6e 65 6c 20 3a 24  332 "$channel :$
3910: 74 6f 70 69 63 22 0a 20 20 20 20 7d 20 65 6c 73  topic".    } els
3920: 65 20 7b 0a 09 73 65 72 76 65 72 43 6c 69 65 6e  e {..serverClien
3930: 74 4d 73 67 20 24 66 64 20 33 33 31 20 22 24 63  tMsg $fd 331 "$c
3940: 68 61 6e 6e 65 6c 20 3a 54 68 65 72 65 20 69 73  hannel :There is
3950: 6e 27 74 20 61 20 74 6f 70 69 63 2e 22 0a 20 20  n't a topic.".  
3960: 20 20 7d 0a 7d 0a 0a 70 72 6f 63 20 73 65 6e 64    }.}..proc send
3970: 57 68 6f 4d 65 73 73 61 67 65 20 7b 66 64 20 63  WhoMessage {fd c
3980: 68 61 6e 6e 65 6c 7d 20 7b 0a 20 20 20 20 73 65  hannel} {.    se
3990: 74 20 6e 69 63 6b 20 5b 63 6c 69 65 6e 74 4e 69  t nick [clientNi
39a0: 63 6b 20 24 66 64 5d 0a 20 20 20 20 66 6f 72 65  ck $fd].    fore
39b0: 61 63 68 20 7b 74 6f 70 69 63 20 75 73 65 72 6c  ach {topic userl
39c0: 69 73 74 20 75 73 65 72 6d 6f 64 65 7d 20 5b 63  ist usermode} [c
39d0: 68 61 6e 6e 65 6c 49 6e 66 6f 20 24 63 68 61 6e  hannelInfo $chan
39e0: 6e 65 6c 5d 20 62 72 65 61 6b 0a 20 20 20 20 73  nel] break.    s
39f0: 65 74 20 75 73 65 72 73 20 7b 7d 0a 20 20 20 20  et users {}.    
3a00: 66 6f 72 65 61 63 68 20 66 64 20 24 75 73 65 72  foreach fd $user
3a10: 6c 69 73 74 20 6d 6f 64 65 20 24 75 73 65 72 6d  list mode $userm
3a20: 6f 64 65 20 7b 0a 09 61 70 70 65 6e 64 20 75 73  ode {..append us
3a30: 65 72 73 20 22 24 6d 6f 64 65 5b 63 6c 69 65 6e  ers "$mode[clien
3a40: 74 4e 69 63 6b 20 24 66 64 5d 20 22 0a 20 20 20  tNick $fd] ".   
3a50: 20 7d 0a 20 20 20 20 73 65 74 20 75 73 65 72 73   }.    set users
3a60: 20 5b 73 74 72 69 6e 67 20 72 61 6e 67 65 20 24   [string range $
3a70: 75 73 65 72 73 20 30 20 65 6e 64 2d 31 5d 0a 20  users 0 end-1]. 
3a80: 20 20 20 73 65 72 76 65 72 43 6c 69 65 6e 74 4d     serverClientM
3a90: 73 67 20 24 66 64 20 33 35 33 20 22 3d 20 24 63  sg $fd 353 "= $c
3aa0: 68 61 6e 6e 65 6c 20 3a 24 75 73 65 72 73 22 0a  hannel :$users".
3ab0: 20 20 20 20 73 65 72 76 65 72 43 6c 69 65 6e 74      serverClient
3ac0: 4d 73 67 20 24 66 64 20 33 36 36 20 22 24 63 68  Msg $fd 366 "$ch
3ad0: 61 6e 6e 65 6c 20 3a 45 6e 64 20 6f 66 20 2f 4e  annel :End of /N
3ae0: 41 4d 45 53 20 6c 69 73 74 2e 22 0a 7d 0a 0a 70  AMES list.".}..p
3af0: 72 6f 63 20 68 61 6e 64 6c 65 4c 6f 63 61 6c 43  roc handleLocalC
3b00: 6f 6d 6d 61 6e 64 20 7b 66 64 20 6f 66 64 7d 20  ommand {fd ofd} 
3b10: 7b 0a 09 69 66 20 7b 24 66 64 20 6e 65 20 22 22  {..if {$fd ne ""
3b20: 7d 20 7b 0a 09 09 67 65 74 73 20 24 66 64 20 6c  } {...gets $fd l
3b30: 69 6e 65 0a 0a 09 09 69 66 20 7b 5b 65 6f 66 20  ine....if {[eof 
3b40: 24 66 64 5d 20 26 26 20 24 6c 69 6e 65 20 65 71  $fd] && $line eq
3b50: 20 22 22 7d 20 7b 0a 09 09 09 23 20 44 6f 20 6e   ""} {....# Do n
3b60: 6f 74 20 63 68 65 63 6b 20 66 6f 72 20 69 6e 70  ot check for inp
3b70: 75 74 20 61 6e 79 20 6d 6f 72 65 20 6f 6e 63 65  ut any more once
3b80: 20 77 65 20 67 65 74 20 45 4f 46 0a 09 09 09 66   we get EOF....f
3b90: 69 6c 65 65 76 65 6e 74 20 24 66 64 20 72 65 61  ileevent $fd rea
3ba0: 64 61 62 6c 65 20 22 22 0a 0a 09 09 09 72 65 74  dable "".....ret
3bb0: 75 72 6e 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 24  urn...}....if {$
3bc0: 6c 69 6e 65 20 65 71 20 22 22 7d 20 7b 0a 09 09  line eq ""} {...
3bd0: 09 72 65 74 75 72 6e 0a 09 09 7d 0a 0a 09 09 73  .return...}....s
3be0: 65 74 20 63 6d 64 20 22 22 0a 09 09 63 61 74 63  et cmd ""...catc
3bf0: 68 20 7b 0a 09 09 09 73 65 74 20 63 6d 64 20 5b  h {....set cmd [
3c00: 6c 69 6e 64 65 78 20 24 6c 69 6e 65 20 30 5d 0a  lindex $line 0].
3c10: 09 09 7d 0a 0a 09 09 73 77 69 74 63 68 20 2d 2d  ..}....switch --
3c20: 20 24 63 6d 64 20 7b 0a 09 09 09 22 72 65 6c 6f   $cmd {...."relo
3c30: 61 64 70 61 73 73 77 64 22 20 7b 0a 09 09 09 09  adpasswd" {.....
3c40: 70 75 74 73 20 24 6f 66 64 20 22 52 65 6c 6f 61  puts $ofd "Reloa
3c50: 64 20 70 61 73 73 77 6f 72 64 20 69 73 3a 20 5b  d password is: [
3c60: 63 6f 6e 66 69 67 20 72 65 6c 6f 61 64 70 61 73  config reloadpas
3c70: 73 77 64 5d 22 0a 09 09 09 7d 0a 09 09 09 22 72  swd]"....}...."r
3c80: 65 6c 6f 61 64 22 20 7b 0a 09 09 09 09 68 61 6e  eload" {.....han
3c90: 64 6c 65 43 6c 69 65 6e 74 52 65 6c 6f 61 64 20  dleClientReload 
3ca0: 22 22 20 5b 63 6f 6e 66 69 67 20 72 65 6c 6f 61  "" [config reloa
3cb0: 64 70 61 73 73 77 64 5d 0a 09 09 09 09 70 75 74  dpasswd].....put
3cc0: 73 20 24 6f 66 64 20 22 44 6f 6e 65 22 0a 09 09  s $ofd "Done"...
3cd0: 09 7d 0a 09 09 09 22 65 78 69 74 22 20 7b 0a 09  .}...."exit" {..
3ce0: 09 09 09 65 78 69 74 0a 09 09 09 7d 0a 09 09 09  ...exit....}....
3cf0: 64 65 66 61 75 6c 74 20 7b 0a 09 09 09 09 70 75  default {.....pu
3d00: 74 73 20 24 6f 66 64 20 22 55 6e 6b 6e 6f 77 6e  ts $ofd "Unknown
3d10: 20 63 6f 6d 6d 61 6e 64 22 0a 09 09 09 7d 0a 09   command"....}..
3d20: 09 7d 0a 09 7d 0a 0a 09 70 75 74 73 20 2d 6e 6f  .}..}...puts -no
3d30: 6e 65 77 6c 69 6e 65 20 24 6f 66 64 20 22 3e 20  newline $ofd "> 
3d40: 22 0a 09 66 6c 75 73 68 20 24 6f 66 64 0a 7d 0a  "..flush $ofd.}.
3d50: 0a 23 20 49 6e 69 74 69 61 6c 69 7a 61 74 69 6f  .# Initializatio
3d60: 6e 0a 70 72 6f 63 20 69 6e 69 74 20 7b 7d 20 7b  n.proc init {} {
3d70: 0a 20 20 20 20 73 65 74 20 3a 3a 69 6e 69 74 69  .    set ::initi
3d80: 61 6c 69 7a 65 64 20 31 0a 0a 20 20 20 20 63 6f  alized 1..    co
3d90: 6e 66 69 67 20 72 65 6c 6f 61 64 70 61 73 73 77  nfig reloadpassw
3da0: 64 20 5b 65 78 65 63 20 6f 70 65 6e 73 73 6c 20  d [exec openssl 
3db0: 72 61 6e 64 20 2d 68 65 78 20 32 30 5d 0a 0a 20  rand -hex 20].. 
3dc0: 20 20 20 69 66 20 7b 5b 63 6f 6e 66 69 67 20 64     if {[config d
3dd0: 65 62 75 67 63 68 61 6e 6e 65 6c 5d 7d 20 7b 0a  ebugchannel]} {.
3de0: 09 68 61 6e 64 6c 65 4c 6f 63 61 6c 43 6f 6d 6d  .handleLocalComm
3df0: 61 6e 64 20 22 22 20 73 74 64 6f 75 74 0a 20 20  and "" stdout.  
3e00: 20 20 20 20 20 20 66 69 6c 65 65 76 65 6e 74 20        fileevent 
3e10: 73 74 64 69 6e 20 72 65 61 64 61 62 6c 65 20 5b  stdin readable [
3e20: 6c 69 73 74 20 68 61 6e 64 6c 65 4c 6f 63 61 6c  list handleLocal
3e30: 43 6f 6d 6d 61 6e 64 20 73 74 64 69 6e 20 73 74  Command stdin st
3e40: 64 6f 75 74 5d 0a 20 20 20 20 7d 0a 0a 20 20 20  dout].    }..   
3e50: 20 73 6f 63 6b 65 74 20 2d 73 65 72 76 65 72 20   socket -server 
3e60: 68 61 6e 64 6c 65 4e 65 77 43 6f 6e 6e 65 63 74  handleNewConnect
3e70: 69 6f 6e 20 5b 63 6f 6e 66 69 67 20 74 63 70 70  ion [config tcpp
3e80: 6f 72 74 5d 0a 0a 20 20 20 20 76 77 61 69 74 20  ort]..    vwait 
3e90: 66 6f 72 65 76 65 72 0a 7d 0a 0a 63 6f 6e 66 69  forever.}..confi
3ea0: 67 20 68 6f 73 74 6e 61 6d 65 20 72 6b 65 65 6e  g hostname rkeen
3eb0: 65 2e 6f 72 67 0a 63 6f 6e 66 69 67 20 74 63 70  e.org.config tcp
3ec0: 70 6f 72 74 20 36 36 36 37 0a 63 6f 6e 66 69 67  port 6667.config
3ed0: 20 76 65 72 73 69 6f 6e 20 22 54 63 6c 49 52 43   version "TclIRC
3ee0: 44 2d 30 2e 31 61 22 0a 63 6f 6e 66 69 67 20 64  D-0.1a".config d
3ef0: 65 62 75 67 63 68 61 6e 6e 65 6c 20 30 0a 63 6f  ebugchannel 0.co
3f00: 6e 66 69 67 20 64 65 62 75 67 6d 65 73 73 61 67  nfig debugmessag
3f10: 65 73 20 30 0a 0a 69 66 20 7b 5b 6c 73 65 61 72  es 0..if {[lsear
3f20: 63 68 20 2d 65 78 61 63 74 20 24 61 72 67 76 20  ch -exact $argv 
3f30: 22 2d 64 65 62 75 67 22 5d 20 21 3d 20 2d 31 7d  "-debug"] != -1}
3f40: 20 7b 0a 09 63 6f 6e 66 69 67 20 64 65 62 75 67   {..config debug
3f50: 63 68 61 6e 6e 65 6c 20 31 0a 09 63 6f 6e 66 69  channel 1..confi
3f60: 67 20 64 65 62 75 67 6d 65 73 73 61 67 65 73 20  g debugmessages 
3f70: 31 0a 7d 0a 0a 23 20 49 6e 69 74 69 61 6c 69 7a  1.}..# Initializ
3f80: 65 20 6f 6e 6c 79 20 69 66 20 69 74 20 69 73 20  e only if it is 
3f90: 6e 6f 74 20 61 20 27 72 65 6c 6f 61 64 27 2e 0a  not a 'reload'..
3fa0: 69 66 20 7b 21 5b 69 6e 66 6f 20 65 78 69 73 74  if {![info exist
3fb0: 73 20 3a 3a 69 6e 69 74 69 61 6c 69 7a 65 64 5d  s ::initialized]
3fc0: 7d 20 7b 0a 20 20 20 20 69 6e 69 74 0a 7d 0a     } {.    init.}.