This is the new home of the egghelp.org community forum.
All data has been migrated (including user logins/passwords) to a new phpBB version.


For more information, see this announcement post. Click the X in the top right-corner of this box to dismiss this message.

[SOLVED]variable inside the proc

Help for those learning Tcl or writing their own scripts.
Post Reply
g
gasak
Halfop
Posts: 45
Joined: Mon Aug 09, 2010 11:09 pm

[SOLVED]variable inside the proc

Post by gasak »

Hi,

I don't understand yet much about list operation in TCL. I just starting learning TCL tho' :D I have question about calling variable inside the proc.

For example i have this list

Code: Select all

set advert(words) "*http:* *www.* *.com*"
And i want to call that list inside the proc to match the kick reason.

Code: Select all

foreach word $advert(words) {
    	if {[string match -nocase [lindex $advert(words)] $txt] } {return 0}
	}
So i need it for my kick reason

Code: Select all

putserv "KICK $chan $nick :spam match from $word not allowed!
But i got confused on the list operation command. It detects the whole advert(words) list. I still have no idea what list operation to use. Is it an lrange, lindex, or other. Please teach me. My code are so massy :(

Thank you
Last edited by gasak on Wed Jun 06, 2012 9:34 pm, edited 1 time in total.
Learning Knows No Boundaries!!
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

When using foreach-loops to iterate though lists, you specify an iterator-variable (in your code it's word), which will be updated with the next element in the list upon each iteration of the list. Thus, you should not use lindex on the list to extract the item.

Code: Select all

foreach word $advert(words) {
  if {[string match -nocase $word $txt]} {...
NML_375
User avatar
caesar
Mint Rubber
Posts: 3778
Joined: Sun Oct 14, 2001 8:00 pm
Location: Mint Factory

Post by caesar »

Also, in order to go to the next element in the list if a statement is false use continue not return . Example:

Code: Select all

foreach word $advert(words) {
  if {![string match -nocase $word $txt]} continue
that means if the current element that is taken from the $advert(words) doesn't match the $txt then it will continue with the next element. In order to stop the iteration use break instead of continue.
Once the game is over, the king and the pawn go back in the same box.
g
gasak
Halfop
Posts: 45
Joined: Mon Aug 09, 2010 11:09 pm

Post by gasak »

I tried but doesn't work..

Ok here's the full code:

Code: Select all

set advban(time) "30"
set advban(chans) "#chan"
set advban(words) "*http*//* *http:* *www.* *.htm* *ftp*//* *www.*.co* */server*.*.*"
set advban(exempts) ""

bind pubm - "*" advban

proc advban {nick host hand chan txt} {
	global advban
	set advban(chans) [string tolower $advban(chans)]
	set chan [string tolower $chan]
	if {([string length [string trim $advban(chans)]] != 0) && ([lsearch -exact [split $advban(chans)] $chan] == -1)} {return 0}
	foreach exempt $advban(exempts) {
		if {[lsearch $txt $exempt]} {return 0}
	}
	foreach word $advban(words) {
    	if {![string match -nocase $word $txt]} {continue}
	}
	if {![validuser $nick] && ![isop $nick $chan]} {

		set ban *!*@[lindex [split $host @] 1]
		putquick "MODE $chan +b $ban"
		putquick "KICK $chan $nick :Spam match from ($word) is not allowed here"
		timer $advban(time) {putquick "MODE $chan -b $ban"}
	}
}
I got 2 errors there. the $word on kick msg doesnt work and the timer also doesnt work. It says wrong $chan for the timer part.

Please help. Thanks.
Learning Knows No Boundaries!!
User avatar
caesar
Mint Rubber
Posts: 3778
Joined: Sun Oct 14, 2001 8:00 pm
Location: Mint Factory

Post by caesar »

Code: Select all

foreach element $list {
	if {whatever $element check you wish returns true} {
		do this action
	} else {
		do this second action as the if statement returned false
	}
}
In your case you should check each spoken word by the user and compare it with each element you have in the blackilst, but before that check if the word is not in the except list like this:

Code: Select all

set found 0
foreach word [split $txt] {
	if {[lsearch -nocase $advban(exempts) $word] != -1} break
	foreach element [split $advban(words)] {
		if {![string match -nocase $word $element]} continue
		set found 1
		set badword $word
		break
	}
}

if {$found} {
	do whatever you wish as there has been a match with one of the words in the blacklist and that word has been stored in $badword variable
}
Once the game is over, the king and the pawn go back in the same box.
g
gasak
Halfop
Posts: 45
Joined: Mon Aug 09, 2010 11:09 pm

Post by gasak »

ok thanks caesar.. i'll give it a try now..
Learning Knows No Boundaries!!
g
gasak
Halfop
Posts: 45
Joined: Mon Aug 09, 2010 11:09 pm

Post by gasak »

caesar, i got this error:
Tcl error [advban]: bad option "-nocase": must be -all, -ascii, -decreasing, -dictionary, -exact, -glob, -increasing, -inline, -integer, -not, -real, -regexp, -sorted, or -start
Learning Knows No Boundaries!!
User avatar
caesar
Mint Rubber
Posts: 3778
Joined: Sun Oct 14, 2001 8:00 pm
Location: Mint Factory

Post by caesar »

That's cos you have an outdated TCL library version. Anyway, replace:

Code: Select all

   if {[lsearch -nocase $advban(exempts) $word] != -1} break
with:

Code: Select all

   if {[lsearch -equal $advban(exempts) [string tolower $word]] != -1} break
Btw, you should move the:

Code: Select all

if {![validuser $nick] && ![isop $nick $chan]} {
after the global advban as it makes more sense to be there if you wish to skip a user if it's known to the bot AND is a channel operator.
Once the game is over, the king and the pawn go back in the same box.
g
gasak
Halfop
Posts: 45
Joined: Mon Aug 09, 2010 11:09 pm

Post by gasak »

The same error caesar
Tcl error [spamban]: bad option "-equal": must be -all, -ascii, -decreasing, -dictionary, -exact, -glob, -increasing, -inline, -integer, -not, -real, -regexp, -sorted, or -start
Is it correct the placement of my code?

Code: Select all

proc advban {nick host hand chan txt} {
   global advban
   if {![validuser $nick] && ![isop $nick $chan]} {
   set advban(chans) [string tolower $advban(chans)]
   set chan [string tolower $chan]
   if {([string length [string trim $advban(chans)]] != 0) && ([lsearch -exact [split $advban(chans)] $chan] == -1)} {return 0}
   foreach exempt $advban(exempts) {
      if {[lsearch $txt $exempt]} {return 0}
   }
  set found 0
   foreach word [split $txt] {
   if {[lsearch -equal $advban(exempts) [string tolower $word]] != -1} break 
   foreach element [split $advban(words)] {
      if {![string match -nocase $word $element]} continue
      set found 1
      set badword $word
      break
   }
}

      if {$found} { 
      set ban *!*@[lindex [split $host @] 1]
      putquick "MODE $chan +b $ban"
      putquick "KICK $chan $nick :Spam match from ($word) is not allowed here"
      timer $advban(time) {putquick "MODE $chan -b $ban"}
   }
}
anyway, should i remove this code?

Code: Select all

foreach exempt $advban(exempts) {
      if {[lsearch $txt $exempt]} {return 0}
   } 
Since you already called it inside.

Thanks.
Learning Knows No Boundaries!!
User avatar
caesar
Mint Rubber
Posts: 3778
Joined: Sun Oct 14, 2001 8:00 pm
Location: Mint Factory

Post by caesar »

Something like this:

Code: Select all

set advban(time) "30"
set advban(chans) "#chan"
set advban(words) "*http*//* *http:* *www.* *.htm* *ftp*//* *www.*.co* */server*.*.*"
set advban(exempts) ""

bind pubm - "*" advban

proc advban {nick host hand chan txt} {
	global advban
	if !{[string length $advban(chans)]} return
	if {[lsearch -exact $advban(chans) $chan] == -1} return
	if {[validuser $nick] && [isop $nick $chan]} return
	set found 0
	foreach word [split $txt] {
	   set word [string tolower $word]
	   if {[lsearch -equal $advban(exempts) $word] != -1} break
	   foreach element [split $advban(words)] {
		  if {![string match -nocase $word $element]} continue
		  set found 1
		  set badword $word
		  break
	   }
	}
	if {$found} {
		set ban *!*@[lindex [split $host @] 1]
		putquick "MODE $chan +b $ban"
		putquick "KICK $chan $nick :Spam match from ($badword) is not allowed here"
		timer $advban(time) [list "pusmode $chan -b $ban"]
	}
}
Haven't tested so let me know if you get any issues.

Edit: fixed typo.
Last edited by caesar on Wed Jun 06, 2012 10:15 am, edited 1 time in total.
Once the game is over, the king and the pawn go back in the same box.
g
gasak
Halfop
Posts: 45
Joined: Mon Aug 09, 2010 11:09 pm

Post by gasak »

Hi caesar,

I just tested it but it doesn't work at all. Nothings happen when the badwords trigger said on channel.
Learning Knows No Boundaries!!
User avatar
caesar
Mint Rubber
Posts: 3778
Joined: Sun Oct 14, 2001 8:00 pm
Location: Mint Factory

Post by caesar »

Oh sorry, forgot a ! in:

Code: Select all

if {[string length $advban(chans)]} return 
that should be:

Code: Select all

if {![string length $advban(chans)]} return 
Once the game is over, the king and the pawn go back in the same box.
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

I'd suggest something along these lines;
Iterate through each badword-pattern, and get a list of matching words from the spoken text.
Since you'd like to use wildcards in your exempts-list, we'll have to iterate through this list for each match, and see if it should be exempted. If it should be exempted, move on to the next match; else, ban the user and be done with it.

Further, instead of manually adding the ban, kicking the user, and setting up a timer to finally remove it, why not just use the newchanban command with a custom expire-time?

The above converted to code:

Code: Select all

set advban(time) "30"
set advban(chans) [list "#chan"]
set advban(words) [list "*http*//*" "*http:*" "*www.*" "*.htm*" "*ftp*//*" "*www.*.co*" "*/server*.*.*"]
set advban(exempts) [list]

bind pubm - "*" advban

proc advban {nick host hand chan txt} {
  global advban
  set advban(chans) [string tolower $advban(chans)]
  set chan [string tolower $chan]
  set items [split [string tolower $txt]]
  if {[validuser $hand] || [isop $nick $chan] || ([llength $advban(chans)] > 0 && [lsearch -exact $advban(chans) $chan] == -1)} {
    return 0
  }

  foreach pattern $advban(words) {
    foreach match [lsearch -all -inline $items [string tolower $pattern]] {
      set exempt 0
      foreach exception $advban(exempts) {
        if {[string match -nocase $exception $match]} {
          set exempt 1
          break
        }
      }
      if {$exempt} {
        continue
      } else {
        newchanban $chan "*!*@[lindex [split $host "@"] 1]" "advban.tcl" "Spam match from ($match) is not allowed here" $advban(time)
        return 1
      }
    }
  }
}
Or, if we skip the wildcard matching of exempts:

Code: Select all

set advban(time) "30"
set advban(chans) [list "#chan"]
set advban(words) [list "*http*//*" "*http:*" "*www.*" "*.htm*" "*ftp*//*" "*www.*.co*" "*/server*.*.*"]
set advban(exempts) [list "*example.com*"]

bind pubm - "*" advban

proc advban {nick host hand chan txt} {
  global advban
  set advban(chans) [string tolower $advban(chans)]
  set chan [string tolower $chan]
  set items [split [string tolower $txt]]
  if {[validuser $hand] || [isop $nick $chan] || ([llength $advban(chans)] > 0 && [lsearch -exact $advban(chans) $chan] == -1)} {
    return 0
  }

  foreach pattern $advban(words) {
    foreach match [lsearch -all -inline $items $pattern] {
      if {[lsearch -exact $advban(exempts) $match]} {
        continue
      } else {
        newchanban $chan "*!*@[lindex [split $host "@"] 1]" "advban.tcl" "Spam match from ($match) is not allowed here" $advban(time)
        return 1
      }
    }
  }
}
NML_375
g
gasak
Halfop
Posts: 45
Joined: Mon Aug 09, 2010 11:09 pm

Post by gasak »

Thanks a lot nml375. It works great :)
Learning Knows No Boundaries!!
Post Reply