egghelp.org community Forum Index
[ egghelp.org home | forum home ]
egghelp.org community
Discussion of eggdrop bots, shell accounts and tcl scripts.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

HELP on eggping.tcl ping-reply modification
Goto page Previous  1, 2, 3  Next
 
Post new topic   Reply to topic    egghelp.org community Forum Index -> Script Requests
View previous topic :: View next topic  
Author Message
arfer
Master


Joined: 26 Nov 2004
Posts: 436
Location: Manchester, UK

PostPosted: Sat Mar 07, 2009 6:48 pm    Post subject: Reply with quote

I guess I was thinking [clock clicks -milliseconds] would always be a huge negative integer and therefore the math would be fine. I see your point.

I have decided to revert to your idea of saving the millisecond granularity timestamp and sending [unixtime] as a dummy ctcp ping argument.

The script is now complete (I hope). I put your nick on it as a joint effort. Hope you don't mind.

Calculates the absolute difference between the ctcp request and the ctcr reply.

Tested and functions well. There are still those that block ctcp requests and I can't say for certain that this works with every single IRC client but I think it's as good as we're going to get.

Code:

# ping.tcl by arfer/nml375
# requires Tcl 8.3 or later
# requires channel to permit embelished text (colour) output
# each #channelname the script is to function in requires (in the partyline) .chanset #channelname +ping
# assuming default trigger "." (period) syntax would be .ping ?target?

##### CONFIGURATION #########

set vPingTrigger "."

##### CODE ##################

proc pPingTrigger {} {
  global vPingTrigger
  return $vPingTrigger
}

set vPingVersion 1.0

setudef flag ping

bind CTCR - PING pPingCtcrReceive
bind PUB - [pPingTrigger]ping pPingPubCommand
bind RAW - 401 pPingRawOffline

proc pPingTimeout {} {
  global vPingOperation
  set schan [lindex $vPingOperation 0]
  set snick [lindex $vPingOperation 1]
  set tnick [lindex $vPingOperation 2]
  putserv "PRIVMSG $schan :\00304Error\003 (\00314$snick\003) operation timed out attempting to ping \00307$tnick\003"
  unset vPingOperation
  return 0
}

proc pPingCtcrReceive {nick uhost hand dest keyword txt} {
  global vPingOperation
  if {[info exists vPingOperation]} {
    set schan [lindex $vPingOperation 0]
    set snick [lindex $vPingOperation 1]
    set tnick [lindex $vPingOperation 2]
    set time1 [lindex $vPingOperation 3]
    if {([string equal -nocase $nick $tnick]) && ([regexp -- {^[0-9]+$} $txt])} {
      set time2 [clock clicks -milliseconds]
      set elapsed [expr {abs($time2 - $time1) / 1000.0}]
      set char [encoding convertto utf-8 \u258C]
      if {[expr {round($elapsed / 0.5)}] > 10} {set red 10} else {set red [expr {round($elapsed / 0.5)}]}
      set green [expr {10 - $red}]
      set output \00303[string repeat $char $green]\003\00304[string repeat $char $red]\003
      putserv "PRIVMSG $schan :\00310Compliance\003 (\00314$snick\003) $output $elapsed seconds from \00307$tnick\003"
      unset vPingOperation
      pPingKillutimer
    }
  }
  return 0
}

proc pPingKillutimer {} {
  foreach item [utimers] {
    if {[string equal pPingTimeout [lindex $item 1]]} {
      killutimer [lindex $item 2]
    }
  }
  return 0
}

proc pPingPubCommand {nick uhost hand channel txt} {
  global vPingOperation
  if {[channel get $channel ping]} {
    switch -- [llength [split [string trim $txt]]] {
      0 {set tnick $nick}
      1 {set tnick [string trim $txt]}
      default {
        putserv "PRIVMSG $channel :\00304Error\003 (\00314$nick\003) correct syntax is \00307!ping ?target?\003"
        return 0
      }
    }
    if {![info exists vPingOperation]} {
      if {[regexp -- {^[\x41-\x7D][-\d\x41-\x7D]*$} $tnick]} {
        set time1 [clock clicks -milliseconds]
        putquick "PRIVMSG $tnick :\001PING [unixtime]\001"
        utimer 20 pPingTimeout
        set vPingOperation [list $channel $nick $tnick $time1]
      } else {putserv "PRIVMSG $channel :\00304Error\003 (\00314$nick\003) \00307$tnick\003 is not a valid nick"}
    } else {putserv "PRIVMSG $channel :\00304Error\003 (\00314$nick\003) a ping operation is still pending, please wait"}
  }
  return 0
}

proc pPingRawOffline {from keyword txt} {
  global vPingOperation
  if {[info exists vPingOperation]} {
    set schan [lindex $vPingOperation 0]
    set snick [lindex $vPingOperation 1]
    set tnick [lindex $vPingOperation 2]
    if {[string equal -nocase $tnick [lindex [split $txt] 1]]} {
      putserv "PRIVMSG $schan :\00304Error\003 (\00314$snick\003) \00307$tnick\003 is not online"
      unset vPingOperation
      pPingKillutimer
    }
  }
  return 0
}

putlog "ping.tcl by arfer/nml375 version $vPingVersion loaded"



_________________
I must have had nothing to do
Back to top
View user's profile Send private message
nml375
Revered One


Joined: 04 Aug 2006
Posts: 2857

PostPosted: Sat Mar 07, 2009 7:30 pm    Post subject: Reply with quote

Eeek! Wink
Looks nice now, the remaining abs() is overkill, or could cause a huge delay in the event of a "wraparound", that is, when we reach the end of our 32bit signed integer and we go from 2147483647 to -2147483648 (or in the case of 64bit signed integers, even larger ranges).

The best approach would be to trim the timestamp using the modulus operator (%), and then do the same to the difference. This will give us a limited range, but we'll always have a positive value, and it's bound to be correct within the range.

I'll post a sample below, the value for the modulus operation was chosen to be the number of microseconds in a day:
Code:
set $mod 3600000
#First we start with two arbitrary values that won't cause an overflow:
% set then 1242353145
% set now [expr $then +1342]
1242354487
% set _then [expr $then % $mod]
353145
% set _now [expr $now % $mod]
354487
% expr ($_now - $_then) % $mod
1342
#Yay, we got 1342, which is the differential we started with, works sofar... now lets try a "borderline value"..

% set then [expr $mod - 200]
3599800
% set now [expr $then +1342]
3601142
% set _then [expr $then % $mod]
3599800
% set _now [expr $now % $mod]
1142
% expr $_now - $_then
-3598658
% expr ($_now - $_then) % 3600000
1342
#Once again, we got 1342 in the end. Here you can also see the issue of these "borderline values", as we get a huge negative value. Simply using abs() on this would tell us it took one day for the ping reply to come back...


Oh, and btw, thnx for the credits.
_________________
NML_375, idling at #eggdrop@IrcNET
Back to top
View user's profile Send private message
VinceDalnet
Voice


Joined: 05 Mar 2009
Posts: 17

PostPosted: Sat Mar 07, 2009 7:42 pm    Post subject: Reply with quote

arfer: im getting the following error on your new codes

Tcl error [pingreply]: can't read "chan": no such variable
Back to top
View user's profile Send private message
nml375
Revered One


Joined: 04 Aug 2006
Posts: 2857

PostPosted: Sat Mar 07, 2009 7:46 pm    Post subject: Reply with quote

I can't find a singe proc named "pingreply" in arfer's script. Could it be possible your old script is still loaded?
_________________
NML_375, idling at #eggdrop@IrcNET
Back to top
View user's profile Send private message
VinceDalnet
Voice


Joined: 05 Mar 2009
Posts: 17

PostPosted: Sat Mar 07, 2009 7:56 pm    Post subject: Reply with quote

sorry it was this code that i gotten the errors...

Code:
bind CTCR - PING pPingCtcrReceive
bind PUB - .ping pPingPubCommand
bind RAW - 401 pPingRawOffline

proc pPingTimeout {} {
  global vPingOperation
  set schan [lindex $vPingOperation 0]
  set snick [lindex $vPingOperation 1]
  set tnick [lindex $vPingOperation 2]
  putserv "PRIVMSG $schan :\00304Error\003 (\00314$snick\003) operation timed out attempting to ping \00307$tnick\003"
  unset vPingOperation
  return 0
}

proc pPingCtcrReceive {nick uhost hand dest keyword txt} {
  global vPingOperation
  if {[info exists vPingOperation]} {
    set schan [lindex $vPingOperation 0]
    set snick [lindex $vPingOperation 1]
    set tnick [lindex $vPingOperation 2]
    if {([string equal -nocase $nick $tnick]) && ([regexp -- {^[0-9]+$} $txt])} {
      set seconds [expr {abs((abs([clock clicks -milliseconds]) - $txt) / 1000.0)}]
      set char [encoding convertto utf-8 \u258C]
      if {[expr {round($seconds / 0.5)}] > 10} {set red 10} else {set red [expr {round($seconds / 0.5)}]}
      set green [expr {10 - $red}]
      set output \00303[string repeat $char $green]\003\00304[string repeat $char $red]\003
      putserv "PRIVMSG $schan :\00310Compliance\003 (\00314$snick\003) $output $seconds seconds from \00307$tnick\003"
      unset vPingOperation
      pPingKillutimer
    }
  }
  return 0
}

proc pPingKillutimer {} {
  foreach item [utimers] {
    if {[string equal pPingTimeout [lindex $item 1]]} {
      killutimer [lindex $item 2]
    }
  }
  return 0
}

proc pPingPubCommand {nick uhost hand channel txt} {
  global vPingOperation
  switch -- [llength [split [string trim $txt]]] {
    0 {set tnick $nick}
    1 {set tnick [string trim $txt]}
    default {
      putserv "PRIVMSG $channel :\00304Error\003 (\00314$nick\003) correct syntax is \00307!ping ?target?\003"
      return 0
    }
  }
  if {![info exists vPingOperation]} {
    if {[regexp -- {^[\x41-\x7D][-\d\x41-\x7D]*$} $tnick]} {
      set vPingOperation [list $channel $nick $tnick]
      putserv "PRIVMSG $tnick :\001PING [expr {abs([clock clicks -milliseconds])}]\001"
      utimer 20 pPingTimeout
    } else {putserv "PRIVMSG $channel :\00304Error\003 (\00314$nick\003) \00307$tnick\003 is not a valid nick"}
  } else {putserv "PRIVMSG $channel :\00304Error\003 (\00314$nick\003) a ping operation is still pending, please wait"}
  return 0
}

proc pPingRawOffline {from keyword txt} {
  global vPingOperation
  if {[info exists vPingOperation]} {
    set schan [lindex $vPingOperation 0]
    set snick [lindex $vPingOperation 1]
    set tnick [lindex $vPingOperation 2]
    if {[string equal -nocase $tnick [lindex [split $txt] 1]]} {
      putserv "PRIVMSG $schan :\00304Error\003 (\00314$snick\003) \00307$tnick\003 is not online"
      unset vPingOperation
      pPingKillutimer
    }
  }
  return 0
}




although the latest code still didnt produce any good result,... in fact it doesnt ping anyone... even if i already .chanset #chan +ping Crying or Very sad
Back to top
View user's profile Send private message
nml375
Revered One


Joined: 04 Aug 2006
Posts: 2857

PostPosted: Sat Mar 07, 2009 8:13 pm    Post subject: Reply with quote

Now I'm even more confused...
There still is no proc in there named "pingreply". Further, arfer's script does not test whether the channel is set +ping or not..

Do you get any error messages logged, or any other information from your bot?

Be advised that the version you posted still suffers from the issue of negative integers (causing mIRC and other clients to ignore the ping request), and is one of the older ones posted here...

Edit: Reading your post again, and I believe I misunderstood you alittle.
The script you posted is the one you do not use anymore, and you are currently using the last one posted by arfer?
(and yes, I admit that one does care for the +ping channel setting)
_________________
NML_375, idling at #eggdrop@IrcNET
Back to top
View user's profile Send private message
arfer
Master


Joined: 26 Nov 2004
Posts: 436
Location: Manchester, UK

PostPosted: Sat Mar 07, 2009 8:23 pm    Post subject: Reply with quote

My last effort does test if the channel is +ping but it isnt responsible for the errors that VinceDalnet is experiencing.

Code:

if {[channel get $channel ping]} {
# code
}


VinceDalnet repasted a prior version. Check my last post under this thread.

VinceDalnet, unload everything previously loaded, source my last version and restart your bot (not rehash). As nml375 suggested, there is no pingreply proc/command in my script.

Not sure I understand the modulus code. Aren't there way more than 3600000 microseconds in a day?

I get an immediate and correct resonse from a public command tclsh script using the values you suggested might take a long time to evaluate, as follows :-



Unless you are infering that at some point in time the return value from [clock clicks -milliseconds] changes from one of these extremes to the other.
_________________
I must have had nothing to do


Last edited by arfer on Sat Mar 07, 2009 9:03 pm; edited 3 times in total
Back to top
View user's profile Send private message
VinceDalnet
Voice


Joined: 05 Mar 2009
Posts: 17

PostPosted: Sat Mar 07, 2009 8:42 pm    Post subject: Reply with quote

works perfectly now! thanks alot to both of you... Smile Smile Smile


pls add it in egghelp tcl archive so everybody will use it. Cool
Back to top
View user's profile Send private message
arfer
Master


Joined: 26 Nov 2004
Posts: 436
Location: Manchester, UK

PostPosted: Sat Mar 07, 2009 10:30 pm    Post subject: Reply with quote

OK, I see that is exactly what you are infering and will occur at some point in time.

I still don't get the math though. Please bare with me because I'd like to incorporate this if it is the correct thing to do.

Maybe I'm reading it wrong.

Let me suggest an arbitrary scenario and you explain where I'm misunderstanding. I will use your $mod value of 3600000 (milliseconds per hour I assume you meant).

Say, my two [clock clicks -milliseconds] (once for the CTCP and again for the CTCR) cross over this 32 bit boundary and are 5.2 seconds (5200 milliseconds) apart.

Say, the first CTCP [clock clicks -milliseconds] returns 2147483481.

After 167 milliseconds it would cross the boundary and wrap to -2147483648 and after a further 5033 milliseconds (5200 total) the CTCR [clock clicks -milliseconds] would return -2147478615.

2147483481 % 3600000 = 1883481
-2147478615 % 3600000 = 1721385

(1883481 - 1721385) % 3600000 = 162096

I just don't get how this equates to the 5.2 seconds.
_________________
I must have had nothing to do
Back to top
View user's profile Send private message
speechles
Revered One


Joined: 26 Aug 2006
Posts: 1398
Location: emerald triangle, california (coastal redwoods)

PostPosted: Sat Mar 07, 2009 11:10 pm    Post subject: Reply with quote

Code:
<speechles> .tcl set now [clock seconds]
<sp33chy> Tcl: 1236481292
<speechles> .tcl set then [expr {$now - 500000000}]
<sp33chy> Tcl: 736481292
<speechles> .tcl set little_endian [expr {($now - $then) % 3600000}]
<sp33chy> Tcl: 3200000
<speechles> .tcl set big_endian [expr {($now - $then)/3600000}]
<sp33chy> Tcl: 138
<speechles> .tcl set total_ping "${big_endian}.${little_endian} seconds"
<sp33chy> Tcl: 138.3200000 seconds

You can use the endian method to store larger values without losing original signs, both modulus and division can do that. The big endian in this case is your seconds, the little endian is your remainder.
_________________
speechles' eggdrop tcl archive
Back to top
View user's profile Send private message
nml375
Revered One


Joined: 04 Aug 2006
Posts: 2857

PostPosted: Sat Mar 07, 2009 11:11 pm    Post subject: Reply with quote

Hmm.. think I'm forgetting something.

Ah yes, the modulus value has to be of the same power as the base of the timestamp wraparound, in this case, base2. Using a slightly larger value, 2 to the power of 24 (16'777'216), will make this work.
Code:
% set t1 [expr 2147483481 % 16777216]
16777049
% set t2 [expr -2147478615 % 16777216]
5033
%  expr ($t2 - $t1) % 16777216
5200


Basically, the point of this arithmetic is to remove negative numbers by shrinking the numbers to a smaller, unsigned, space. This is best viewed as binary numbers in 2-complement, where the most significant byte (MSB) determines sign (1 = negative, 0 = positive). If we simply cut off the MSB and then 0-pad to the proper length again, we end up with a positive value.
As long as we are dealing with relative values where the difference is lower than the size of our smaller numbers, we will end up with a valid result.

Code:
 011101 #1+4+8+16: 29
+000110 #2+4: 6
=100011 #-32 +1 + 2: -29

#Lets use mod16
011101 => 001101: 13
100011 => 000011: 3

#Lets get the difference, I could do this in binary aswell, but I'm lazy..
3 - 13 => -10: 110110

#Now again, use mod16
110110 => 000110: 2 + 4: 6

_________________
NML_375, idling at #eggdrop@IrcNET
Back to top
View user's profile Send private message
nml375
Revered One


Joined: 04 Aug 2006
Posts: 2857

PostPosted: Sat Mar 07, 2009 11:16 pm    Post subject: Reply with quote

Speech,
Sorry, but I fail to see how that relates to this math issue?
_________________
NML_375, idling at #eggdrop@IrcNET
Back to top
View user's profile Send private message
arfer
Master


Joined: 26 Nov 2004
Posts: 436
Location: Manchester, UK

PostPosted: Sun Mar 08, 2009 7:13 am    Post subject: Reply with quote

Thanks again!

Final version

Code:

# ping.tcl by arfer/nml375
# requires Tcl 8.4 or later
# requires channel to permit embelished text (colour) output
# each #channelname the script is to function in requires (in the partyline) .chanset #channelname +ping
# assuming default trigger "." (period) syntax would be .ping ?target?


##### CHANGELOG #############

# 1.0 07/03/09 beta
# 1.1 08/03/09 changed abs() math to modulus math to interpret integer wraparound

##### CONFIGURATION #########

set vPingTrigger "."

##### CODE ##################

proc pPingTrigger {} {
  global vPingTrigger
  return $vPingTrigger
}

set vPingVersion 1.1

setudef flag ping

bind CTCR - PING pPingCtcrReceive
bind PUB - [pPingTrigger]ping pPingPubCommand
bind RAW - 401 pPingRawOffline

proc pPingTimeout {} {
  global vPingOperation
  set schan [lindex $vPingOperation 0]
  set snick [lindex $vPingOperation 1]
  set tnick [lindex $vPingOperation 2]
  putserv "PRIVMSG $schan :\00304Error\003 (\00314$snick\003) operation timed out attempting to ping \00307$tnick\003"
  unset vPingOperation
  return 0
}

proc pPingCtcrReceive {nick uhost hand dest keyword txt} {
  global vPingOperation
  if {[info exists vPingOperation]} {
    set schan [lindex $vPingOperation 0]
    set snick [lindex $vPingOperation 1]
    set tnick [lindex $vPingOperation 2]
    set time1 [lindex $vPingOperation 3]
    if {([string equal -nocase $nick $tnick]) && ([regexp -- {^[0-9]+$} $txt])} {
      set time2 [expr {[clock clicks -milliseconds] % 16777216}]
      set elapsed [expr {(($time2 - $time1) % 16777216) / 1000.0}]
      set char [encoding convertto utf-8 \u258C]
      if {[expr {round($elapsed / 0.5)}] > 10} {set red 10} else {set red [expr {round($elapsed / 0.5)}]}
      set green [expr {10 - $red}]
      set output \00303[string repeat $char $green]\003\00304[string repeat $char $red]\003
      putserv "PRIVMSG $schan :\00310Compliance\003 (\00314$snick\003) $output $elapsed seconds from \00307$tnick\003"
      unset vPingOperation
      pPingKillutimer
    }
  }
  return 0
}

proc pPingKillutimer {} {
  foreach item [utimers] {
    if {[string equal pPingTimeout [lindex $item 1]]} {
      killutimer [lindex $item 2]
    }
  }
  return 0
}

proc pPingPubCommand {nick uhost hand channel txt} {
  global vPingOperation
  if {[channel get $channel ping]} {
    switch -- [llength [split [string trim $txt]]] {
      0 {set tnick $nick}
      1 {set tnick [string trim $txt]}
      default {
        putserv "PRIVMSG $channel :\00304Error\003 (\00314$nick\003) correct syntax is \00307!ping ?target?\003"
        return 0
      }
    }
    if {![info exists vPingOperation]} {
      if {[regexp -- {^[\x41-\x7D][-\d\x41-\x7D]*$} $tnick]} {
        set time1 [expr {[clock clicks -milliseconds] % 16777216}]
        putquick "PRIVMSG $tnick :\001PING [unixtime]\001"
        utimer 20 pPingTimeout
        set vPingOperation [list $channel $nick $tnick $time1]
      } else {putserv "PRIVMSG $channel :\00304Error\003 (\00314$nick\003) \00307$tnick\003 is not a valid nick"}
    } else {putserv "PRIVMSG $channel :\00304Error\003 (\00314$nick\003) a ping operation is still pending, please wait"}
  }
  return 0
}

proc pPingRawOffline {from keyword txt} {
  global vPingOperation
  if {[info exists vPingOperation]} {
    set schan [lindex $vPingOperation 0]
    set snick [lindex $vPingOperation 1]
    set tnick [lindex $vPingOperation 2]
    if {[string equal -nocase $tnick [lindex [split $txt] 1]]} {
      putserv "PRIVMSG $schan :\00304Error\003 (\00314$snick\003) \00307$tnick\003 is not online"
      unset vPingOperation
      pPingKillutimer
    }
  }
  return 0
}

putlog "ping.tcl by arfer/nml375 version $vPingVersion loaded"



_________________
I must have had nothing to do
Back to top
View user's profile Send private message
nml375
Revered One


Joined: 04 Aug 2006
Posts: 2857

PostPosted: Sun Mar 08, 2009 9:33 am    Post subject: Reply with quote

Your welcome,
always fun with overworked mathematical exercises, especially when one have to explain and motivate the arithmetic Smile
(Yes, I'm a geek, and I'm proud of it Wink

Code/math looks flawless now.
_________________
NML_375, idling at #eggdrop@IrcNET
Back to top
View user's profile Send private message
VinceDalnet
Voice


Joined: 05 Mar 2009
Posts: 17

PostPosted: Sun Mar 08, 2009 3:07 pm    Post subject: Reply with quote

pls do something about this so the script doesnt look silly...


[02:20:22] <+ ASucAL> !ping me
[02:20:24] <@ Voltron> Error(ASucAL) me is not online


thanks in advance Cool
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    egghelp.org community Forum Index -> Script Requests All times are GMT - 4 Hours
Goto page Previous  1, 2, 3  Next
Page 2 of 3

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Forum hosting provided by Reverse.net

Powered by phpBB © 2001, 2005 phpBB Group
subGreen style by ktauber