The Eggdrop FAQ
TCL-Scripting


How can I learn the secrets to be an eggdrop TCL scripter?
  1. Learn more about TCL.
    Resource: http://dev.scriptics.com

  2. Learn about what specific commands are added by eggdrop to TCL
    Resource: docs/tcl-commands.doc that comes with every eggdrop distribution

  3. Get other scripts that do something similar than what you intend to do, and learn by following these examples
    Resource: ftp://ftp.eggheads.org/pub/eggdrop/


How do I add mIRC colours/bolds/etc to my scripts output?

These can be added using the following code:

    meaning key in
    mIRC
    TCL
    equivalent
    colour CTRL-K \003
    bold CTRL-B \002
    underline CTRL-U \037
    reverse CTRL-R \022

So you can use:

  putserv "PRIVMSG #chann :\00312,4BLUE ON RED!\003"  

How can I match users in my script with this AND that flag?

Use the userlist flags channel command to get persons with the specified flags. If you use:

  userlist AB  

You will get all users that have flags A or B. If you want it to be A and B, you must use:

  userlist AB&  

The default matching method used in eggdrop is OR, so you must tell it when you want another thing (an AND). '|' and '&' are equivalent seperators, one meaning OR, one meaning AND.


How can I bind an evento to an ACTION (/me text)?
  bind ctcp - "ACTION" action_proc  

This will trigger 'action_proc' when someone does an action to the channel or to the bot in private. You need to pick up what you want inside your proc.

Send to the bot privately:

  proc action_bind { nick uhost hand dest keyword text } {  
     if {[string index $dest 0] == "#"} { return 0 }        
     ...                                                    
  }                                                         

Send to a channel:

  proc action_bind { nick uhost hand dest keyword text } {  
     if {[string index $dest 0] != "#"} { return 0 }        
     ...                                                    
  }                                                         

The ACTION will be triggered if sent to a channel or when sent to the bot privately, that's why you need to check which was the destination right at the beginning of the proc. The $dest will be a channel name or the nickname of your bot.


I miss the addhost command in 1.3.x!

This was replaced with: setuser <nick> HOST <hostmask>


How to bind an event to occur at a specific time of the day?

Use the time binding:

  bind time - <mask> time:proc                  
  proc time:proc { min hour day month year } {  
    ...                                         
  }                                             

The <mask> should be a set of 5 integer numbers, in the form: min hour day month year. Examples:

  • each full hour:

        bind time - "00 * * * *" proc   
  • every day at 5:05am:

        bind time - "05 05 * * *" proc  
  • every 10 minutes at xx:x0:

        bind time - "?0 * * * *" proc  

How to make the bot execute a TCL procedure every XX minutes?
  if {![info exists myproc_running]} {   
    timer 20 myproc                      
    set myproc_running 1                 
  }                                      
                                         
  proc myproc {} {                       
      # your stuff here ...              
      # ...                              
      timer 20 myproc                    
      return 1                           
  }                                      

This will guarantee that your script will not start another timer if the owner rehashs the bot.


The RAW binding does not work after switching from 1.1 to 1.3!

The syntax was changed:

  • In 1.1.x:

        bind raw - "% 372 %" proc  
  • In 1.2.x and 1.3.x:

        bind raw - "372" proc  

The matched mask now just includes the "keyword" of the raw command, and it can be a numeric, or another thing (NOTICE, PRIVMSG, etc).


How can I remove all hosts from an user in one command?
  bind dcc n|- zaphosts dcc:zaphosts                            
                                                                
  proc dcc:zaphosts { idx hand text } {                         
    foreach host [getuser $text hosts] { delhost $text $host }  
    return 1                                                    
  }                                                             

What should I care when I port my scripts from 1.1 to 1.3?

This will try to make a summary of *all* changes that you must consider when you port a script from an 1.1 bot to a 1.3 bot.

  1. Numeric flags are gone

    Search for the use of the +1 - +9 flags and eventual redefinitions to other names with the set flagX Y command or the newflag procedure.

    If you have something like these, you must now use the new flaging standard:

    • Lowercase flags are for eggdrops own use
    • All uppercase letters are custom flags and can be used by scripts
    • Numerical flags are gone

  2. Userflag matching system

    The way you match for channel flags has changed. All commands now use the same matching method, where you have:

      [globalflags]{&/|}[channelflags]{&/|}[botflags] #channel  

    The '|' means an OR concatenation, the '&' an AND. For example:

      +op|+o #channel  -> global +o OR global +p OR channel +o  
      +n&+o #channel   -> global +n AND channel +o              
      +mn&             -> global +m AND global +n               

    This makes some old commands break, but opens many new possibilities to simplify and shorten pieces of scripts.

    The commands you need to check if they need - or would benefit from - an update:

    • matchattr

      matchchanattr is NOT usable anymore. Change it to the matchattr with the proper syntax for checking for channel flags.

        In 1.1:      matchattr nick +globalflag                     
        In 1.3:      matchattr nick +globalflag                     
                                                                    
        In 1.1:      matchchanattr nick +chanflag #channel          
        In 1.3:      matchattr nick |+chanflag #channel             
                                                                    
        New in 1.3:  matchattr nick +globalflag|+chanflag #channel  
    • userlist

      Was only extended in 1.3, channel matching wasn't possible in 1.1

        In 1.1:  userlist +globalflag                               
        In 1.3:  userlist +globalflag                               
                                                                    
        New in 1.3:  userlist |+chanflag #channel                   
        New in 1.3:  userlist +globalflag|+chanflag #channel        
    • chattr

      Don't forget to add the '|' before the flag you are checking for, if you are changing channel flags. Otherwise it will only change global flags, even if a channel name is given.

        In 1.1:      chattr nick +globalflag                              
        In 1.3:      chattr nick +globalflag                              
                                                                          
        In 1.1:      chattr nick +chanflag #channel                       
        In 1.3:      chattr nick |+chanflag #channel   <- NOTE THE '|'!!  
                                                                          
        New in 1.3:  chattr +globalflag|+chanflag #channel                
        New in 1.3:  botattr +botflags [#channel]                         
    • chanlist

      Was extended in 1.3 to also allow '|' (OR) matches

        In 1.1:      chanlist #channel [+globalflag&+chanflag]      
        In 1.3:      chanlist #channel [+globalflag&+chanflag]      
                                                                    
        New in 1.3:  chanlist #channel +globalflag|+chanflag        
    • bind

      Uppercase flags that were used to match for channel owners, channel masters and channel ops (+N, +M and +O) should be changed to the new matching system! Uppercase flags now are custom flags!!

        In 1.1:      bind type +globalflag command proc                       
        In 1.3:      bind type +globalflag command proc                       
                                                                              
        In 1.1:      bind type +CHANFLAG command proc   (flag in UPPER-case)  
        In 1.3:      bind type |+chanflag command proc  (flag in lower-case)  
                                                                              
        New in 1.3:  bind type +globalflag|+chanflag command proc             
  3. User information

    There used to be dozens of procs to get and set the various information stored with each user. Now there are only two procs to handle this: getuser and setuser.

    PASSWORD:

      In 1.1:  chpass <handle> [pass]        
      In 1.3:  setuser <handle> PASS [pass]  

    INFO LINE:

      In 1.1:  setinfo <handle> <info>                
      In 1.3:  setuser <handle> INFO <info>           
                                                      
      In 1.1:  getinfo <handle>                       
      In 1.3:  getuser <handle> INFO         .        
                                                      
      In 1.1:  setchaninfo <handle> <channel> <info>  
      In 1.3:  setchaninfo <handle> <channel> <info>  
                                                      
      In 1.1:  getchaninfo <handle> <channel>         
      In 1.3:  getchaninfo <handle> <channel>         

    COMMENT:

      In 1.1:  getcomment <handle>                    
      In 1.3:  getuser <handle> COMMENT               
                                                      
      In 1.1:  setcomment <handle> <comment>          
      In 1.3:  setuser <handle> COMMENT <comment>     

    DCCDIR:

      In 1.1:  getdccdir <handle>                     
      In 1.3:  setuser <handle> DCCDIR                
                                                      
      In 1.1:  setdccdir <handle> <dccdir>            
      In 1.3:  setuser <handle> DCCDIR <dccdir>       

    EMAIL:

      In 1.1:  getemail <handle>                      
      In 1.3:  getuser <handle> XTRA EMAIL            
                                                      
      In 1.1:  setemail <handle> <email>              
      In 1.3:  setuser <handle> XTRA EMAIL <email>    

    LASTON:

      In 1.1:  getlaston <handle> <channel>
      In 1.3:  getuser <handle> LASTON <channel>
                                                      
      In 1.1:  getchanlaston <handle>
      In 1.3:  lindex [getuser <handle> LASTON] 1
                                                      
      In 1.1:  getlaston <handle>                  (global laston)
      In 1.3:  lindex [getuser <handle> LASTON] 0
                                                      
      In 1.1:  setlaston <handle> <channel> <unixtime>
      In 1.3:  setuser <handle> LASTON <unixtime> <place>
               (<place> can also be 'partyline' or '@otherbot')
                                                      
      New in 1.3:  setuser <handle> LASTON <unixtime> <place> *
               (only sets laston for specified place, don't set global laston)

    HOSTS:

      In 1.1:  gethosts <handle>
      In 1.3:  getuser <handle> HOSTS
                                                      
      In 1.1:  addhost <handle> <hostmask>
      In 1.3:  setuser <handle> HOSTS <hostmask>
                                                      
      New in 1.3:  setuser <handle> HOSTS
               (clears all hostmasks for that user)
                                                      
      In 1.1:  delhost <handle> <hostmask>
      In 1.3:  delhost <handle> <hostmask> (only command that remained in 1.3)

    BOTADDR:

      In 1.1:  getaddr <handle>
      In 1.3:  getuser <handle> BOTADDR
                                                      
      In 1.1:  setaddr <handle> <addr>
      In 1.3:  setuser <handle> BOTADDR <addr>

    XTRA FIELD:

      In 1.1:  getxtra <handle>
      In 1.1:  setxtra <handle> <xtrastuff>

      The access to the XTRA field was uncoordinated and scripts could do with it whatever they liked. So some standard use was adopted with the following commands from the scripts/toolkit.tcl:

      In 1.1:  user-get <handle> <key>
      In 1.3:  getuser <handle> XTRA <key>
                                                      
      In 1.1:  user-set <handle> <key> <data>
      In 1.3:  setuser <handle> XTRA <key> <data>

    If your script uses getxtra and setxtra directly, you should port it to use this structured access now. If your script used user-get and user-set, then you can just switch over to the new commands.

  4. Bindings

    Some bindings have changed their mask matching and/or the number of arguments of the procs they call:

    • RAW

        In 1.1:  bind raw - "% 372 %" proc
        In 1.3:  bind raw - "372" proc
    • CHPT

      Now the mask is checked agains the text the user used to leave, and the channel is given as a further argument to your proc.

                 bind chpt <flags> <mask> <proc>
        In 1.1:  proc <proc> <bot> <nick> <sock>
        In 1.3:  proc <proc> <bot> <nick> <sock> <chan>
    • TIME

      The first argument was <bot>, this is useless and was removed.

                 bind time - <mask> <proc>
        In 1.1:  proc <proc> <bot> <min> <hour> <day> <month> <year>
        In 1.3:  proc <proc> <min> <hour> <day> <month> <year>
  5. Misc

    • dumpfile

      Now the file should be in the help/text and not in the text directory.

    • putidx <idx> <text>

      Was removed in 1.3, use 'putdcc' instead.


What new features are avaliable with TCL on 1.3 bots that were not found in 1.1?

Some things were already pointed out in the last question, you can recognize them by the 'New in 1.3'. Here are other new things you might want to use:

  1. New commands

    • botattr <handle> [changes [channel]]
      Similar to chattr except for bot attributes rather than normal user attributes, this includes the channel-specific +s share flag

    • addchanrec <handle> <channel>
      Add a channel record for the user

    • delchanrec <handle> <channel>
      Removes a channel record for the user; this includes all associated channel flags

    • unames
      Returns the current operating system the bot is using.

    • storenote <from> <to> <msg> <idx>
      stores a note for later reading, notify idx of any results (use idx == -1 for no notify).

  2. New possibilities

    • whom <chan>
      if you specify a channel of * every user on the botnet is returned with an extra argument indicating the channel the user is on

    • killassoc <chan>
      use 'killassoc &' to kill all assocs.

  3. New global variables

    • numversion
      current numeric bot version (ie: "1031401" = 1.3.14, patch #1); Numerical version is MMNNRRPP where:
      MM = Major release, NN = Minor release, RR = sub-release, PP = patch level

    • server-online
      Unixtime when the bot last connected to an IRC server

    • lastbind
      The last command binding which triggered. This allows you to identify which command triggered a tcl routine.

  4. New bindings

    • AWAY
      triggers when a user goes away or comes back on the botnet (msg == "" when returning)

        bind away - <mask> <proc>
        proc <proc> <bot> <idx> <msg>
    • NKCH
      triggered whenever a local users nick is changed (in the userfile)

        bind nkch - <mask> <proc>
        proc <proc> <oldnick> <newnick>
    • LOAD
      triggers when a module is loaded.

        bind load - <mask> <proc>
        proc <proc> <module>
    • UNLD
      triggers when a module is unloaded.

        bind unld - <mask> <proc>
        proc <proc> <module>

There may be more things, almost all of this was extracted from the documentation changes.


How to bind an event to NOTICEs?
  • Send to the bot:

      bind notc <flags> <mask> <proc>
  • Send to a channel


I have a proc with an parameter called args and I always get '{' and '}' around the text passed to it. Why?

When you use the parameter name args, it has a special meaning to TCL. It means: Accept any number of parameters here (even zero!), and put each argument into a separate list item. If you pass just one argument, it still makes a list of it.

If you are confused, just avoid using args, use arg or something else instead.


How to find out how long time one's bot has been online (connected to a server) in a TCL script?

You can use the (undocummented) TCL global variable "server-online" to find out the timestamp of when your bot connected to the server.

  set time [expr [unixtime] - ${server-online}]

would give you the ammount of seconds your bot is connected.


Why does putserv "PRIVMSG $nick :[OP]" gives an error invalid command name "OP"?

Use a bachslash to "quote" characters that might be misinterpreted by TCL, like "[", "{", "$" or sometimes "(".


I tried the exec TCL command and it tells me couldn't execute "command bla": no such file or directory, but command is a valid command! So what?

Don't quote the whole command, pass each argument separately. So if you want to execute ls -l DEBUG:

  WRONG:  exec "ls -l DEBUG"  -> this will give you an error
  RIGHT:  exec ls -l DEBUG

If you have the whole command you want to execute in a variable, you will need to do a trick with eval like:

          set varname "ls -ls DEBUG"
  WRONG:  exec $varname  -> this will give you an error
  RIGHT:  eval exec $varname


© 1998-2000 by Ernst