Create a gist now

Instantly share code, notes, and snippets.

@grawity /README.md
Last active Aug 21, 2017

What would you like to do?
Eggdrop scripts

Eggdrop 1.8 SASL patch:

  1. For convenience, download this entire gist with git clone https://gist.github.com/4455067.git

  2. Get Eggdrop 1.8 from CVS or from Git (1.6 may work, but I have not tested it. 1.8 is better anyway – with SSL and IPv6 support.)

  3. Apply the patch preinit-server.patch.

    Alternatively, you can use my Git fork and git checkout the branch preinit.

  4. Compile and install the patched Eggdrop.

  5. From your Eggdrop config, source the scripts and set the SASL information.

    source "scripts/4455067/g_base64.tcl"
    source "scripts/4455067/g_cap.tcl"
    
    set sasl-user $username
    set sasl-pass "blahblah"
    
    # Let's turn off all "experimental" crap I added to g_cap
    set caps-wanted "sasl"
  6. Enjoy.

Atheme auto-reop script:

  1. From your Eggdrop config, source the g_atheme_need.tcl script.

  2. Add a user named services to your bot, with ChanServ's hostmask, and give it the +fS flags.

    .+user services *!*@services.example.com
    .chattr services +fS
    

    Otherwise the bot can think it's being notice-flooded by ChanServ and ignore it.

# g_atheme_need.tcl - handles "need op/unban/invite/key" events with Atheme
# (c) 2011 <grawity@gmail.com>, under WTFPL v2 <http://sam.zoy.org/wtfpl>
# NOTE: You must add a "services" user, then .chattr services +fS
proc need:op {channel type} {
putlog "($channel) requesting reop"
putquick "PRIVMSG ChanServ :op $channel"
}
proc need:unban {channel type} {
putlog "($channel) requesting unban"
putquick "PRIVMSG ChanServ :unban $channel"
}
proc need:invite {channel type} {
putlog "($channel) requesting invite"
putquick "PRIVMSG ChanServ :invite $channel"
}
proc need:key {channel type} {
putlog "($channel) requesting key"
putquick "PRIVMSG ChanServ :getkey $channel"
}
proc chanserv:recvkey {nick addr hand text dest} {
set msg [split [stripcodes bcru $text] " "]
set channel [lindex $msg 1]
set key [lindex $msg 4]
putlog "($channel) received key, joining channel"
putquick "JOIN $channel $key"
return 1
}
bind need - "% op" need:op
bind need - "% unban" need:unban
bind need - "% invite" need:invite
bind need - "% key" need:key
bind notc S "Channel % key is: *" chanserv:recvkey
# g_base64.tcl - Base64 encoding/decoding routines
# (c) 2013 <grawity@gmail.com>, under WTFPL v2 <http://sam.zoy.org/wtfpl>
if {![catch {package require Tcl 8.6}]} {
proc b64:encode {input} {
binary encode base64 $input
}
proc b64:decode {input} {
binary decode base64 $input
}
} elseif {![catch {package require base64}]} {
proc b64:encode {input} {
::base64::encode -wrapchar "" $input
}
proc b64:decode {input} {
::base64::decode $input
}
} else {
set b64map {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
0 1 2 3 4 5 6 7 8 9 + / =}
proc b64:encode {input} {
global b64map
set str {}
set pad 0
binary scan $input c* X
foreach {x y z} $X {
if {$y == {}} {set y 0; incr pad}
if {$z == {}} {set z 0; incr pad}
set n [expr {($x << 16) | ($y << 8) | $z}]
set a [expr {($n >> 18) & 63}]
set b [expr {($n >> 12) & 63}]
set c [expr {($n >> 6) & 63}]
set d [expr {$n & 63}]
append str \
[lindex $b64map $a] \
[lindex $b64map $b] \
[lindex $b64map [expr {$pad >= 2 ? 64 : $c}]] \
[lindex $b64map [expr {$pad >= 1 ? 64 : $d}]]
}
return $str
}
proc b64:decode {input} {
set str {}
set pos 0
set pad 0
set n 0
binary scan $input c* X
foreach x $X {
if {$x >= 65 && $x <= 90} { set x [expr {$x - 65}] }\
elseif {$x >= 97 && $x <= 122} { set x [expr {$x - 71}] }\
elseif {$x >= 48 && $x <= 57} { set x [expr {$x + 4}] }\
elseif {$x == 61} { set x 0; incr pad }\
else { continue }
set o [expr {18 - 6 * ($pos % 4)}]
set n [expr {$n | ($x << $o)}]
if {$o == 0} {
set a [expr {($n >> 16) & 255}]
set b [expr {($n >> 8) & 255}]
set c [expr {$n & 255}]
set n 0
if {$pad == 2} {
append str [binary format c $a]
break
} elseif {$pad == 1} {
append str [binary format cc $a $b]
break
} else {
append str [binary format ccc $a $b $c]
}
}
incr pos
}
return $str
}
}
# g_cap.tcl - Experimental IRCv3 capability support, including SASL
# (c) 2013 <grawity@gmail.com>, under WTFPL v2 <http://sam.zoy.org/wtfpl>
#
# Requires: g_base64.tcl
if {[info procs b64:encode] == ""} {
die "You must load g_base64.tcl first."
}
## Configuration
set caps-wanted "account-notify away-notify extended-join multi-prefix sasl"
#set caps-wanted "sasl"
set sasl-user "$username"
set sasl-pass "hunter2"
## Internal state -- do not change
set caps-enabled {}
set caps-preinit 0
set sasl-state 0
set sasl-mech "*"
## Utility functions
proc rparse {text} {
#putlog "rparse in: $text"
if {[string index $text 0] == ":"} {
set pos [string first " " $text]
set vec [list [string range $text 0 [expr $pos-1]]]
}
set pos [string first " :" $text]
if {$pos < 0} {
set vec [split $text " "]
} else {
set vec [split [string range $text 0 [expr $pos-1]] " "]
lappend vec [string range $text [expr $pos+2] end]
}
#putlog "rparse out: $vec"
return $vec
}
## Raw CAP commands -- required
proc cap:on-connect {ev} {
global caps-preinit
switch $ev {
"preinit-server" {
set caps-preinit 1
putnow "CAP LS"
}
"init-server" {
set caps-preinit 0
}
}
return 0
}
proc raw:cap {from keyword rest} {
global caps-preinit
global caps-wanted
set vec [rparse [string trim $rest]]
set cmd [lindex $vec 1]
set caps [lindex $vec 2]
if {${caps-preinit} == 0} {
return 1
}
switch $cmd {
LS {
set wanted {}
foreach cap $caps {
if {[lsearch -exact ${caps-wanted} $cap] != -1} {
lappend wanted $cap
}
}
if {[llength $wanted]} {
putnow "CAP REQ :[join $wanted " "]"
}
}
ACK {
if {[lsearch -exact $caps "sasl"] != -1} {
sasl:start PLAIN
} else {
putnow "CAP END"
}
}
NAK {
putnow "CAP END"
}
}
return 1
}
## Raw IRCv3 extension commands
proc raw:cap-account {from keyword rest} {
user:account-changed $from $rest
return 1
}
proc raw:cap-extjoin {from keyword rest} {
set nuh [split $from "!"]
set vec [rparse $rest]
if {[llength $vec] > 1} {
set account [lindex $vec 1]
set gecos [lindex $vec 2]
user:account-changed $from $account
user:gecos-changed $from $gecos
}
return 0
}
proc raw:cap-away {from keyword rest} {
set vec [rparse $rest]
user:away-changed $from [lindex $vec 0]
return 0
}
## Raw IRC-SASL commands
proc raw:authenticate {from keyword rest} {
sasl:step $rest
return 1
}
proc numeric:sasl-logged-in {from keyword rest} {
set vec [rparse $rest]
putlog "Authenticated to services as [lindex $vec 2]."
return 1
}
proc numeric:sasl-success {from keyword rest} {
putnow "CAP END"
return 1
}
proc numeric:sasl-failed {from keyword rest} {
putlog "Authentication failed"
# TODO: make this disconnect
putnow "CAP END"
#putnow "QUIT"
return 1
}
## SASL mechanism functions
proc sasl:start {mech} {
global sasl-state
global sasl-mech
set sasl-state 1
set sasl-mech $mech
putlog "Starting SASL $mech authentication."
sasl:step ""
}
proc sasl:step {data} {
global sasl-state
global sasl-mech
if {${sasl-state} == 1} {
putnow "AUTHENTICATE ${sasl-mech}"
} else {
sasl:step:${sasl-mech} $data
}
set sasl-state [expr ${sasl-state} + 1]
}
proc sasl:step:PLAIN {data} {
global sasl-user
global sasl-pass
if {$data == "+"} {
set out [join [list ${sasl-user} ${sasl-user} ${sasl-pass}] "\0"]
putnow "AUTHENTICATE [b64:encode $out]"
}
}
## IRCv3 extension events
#
# Currently these only print log messages. Any ideas on making them useful?
proc user:account-changed {from account} {
set nuh [split $from "!"]
set nick [lindex $nuh 0]
if {$account == "*"} {
putlog "$nick logged out"
set hand [finduser $from]
} else {
putlog "$nick logged in as $account"
set hand [finduser $from]
}
}
proc user:gecos-changed {from gecos} {
set nuh [split $from "!"]
set nick [lindex $nuh 0]
putlog "$nick is actually \"$gecos\""
}
proc user:away-changed {from reason} {
set nuh [split $from "!"]
set nick [lindex $nuh 0]
if {$reason == ""} {
putlog "$nick is back"
} else {
putlog "$nick is away"
}
}
## Event bindings
# Basic CAP commands -- required
bind EVNT - preinit-server cap:on-connect
bind EVNT - init-server cap:on-connect
bind raw - "CAP" raw:cap
# SASL commands
bind raw - "AUTHENTICATE" raw:authenticate
bind raw - "900" numeric:sasl-logged-in
bind raw - "903" numeric:sasl-success
bind raw - "904" numeric:sasl-failed
# IRCv3 extensions -- currently useless
bind raw - "AWAY" raw:cap-away
bind raw - "JOIN" raw:cap-extjoin
bind raw - "ACCOUNT" raw:cap-account
# EOF
Adds a "preinit-server" Tcl event for use with `bind EVNT`.
Index: src/mod/server.mod/servmsg.c
===================================================================
RCS file: /usr/local/cvsroot/eggdrop1.8/src/mod/server.mod/servmsg.c,v
retrieving revision 1.6
diff -u -r1.6 servmsg.c
--- a/src/mod/server.mod/servmsg.c 15 Jun 2012 00:04:59 -0000 1.6
+++ b/src/mod/server.mod/servmsg.c 4 Jan 2013 19:17:15 -0000
@@ -1338,6 +1338,7 @@
strcpy(botname, origbotname);
/* Start alternate nicks from the beginning */
altnick_char = 0;
+ check_tcl_event("preinit-server");
if (pass[0])
dprintf(DP_MODE, "PASS %s\n", pass);
dprintf(DP_MODE, "NICK %s\n", botname);
Index: doc/tcl-commands.doc
===================================================================
RCS file: /usr/local/cvsroot/eggdrop1.8/doc/tcl-commands.doc,v
retrieving revision 1.12
diff -u -r1.12 tcl-commands.doc
--- a/doc/tcl-commands.doc 26 Jun 2012 21:20:49 -0000 1.12
+++ b/doc/tcl-commands.doc 6 Jan 2013 00:30:58 -0000
@@ -2242,6 +2242,7 @@
userfile-loaded - called after userfile has been loaded
connect-server - called just before we connect to an IRC server
+ preinit-server - called immediately when we connect to the server
init-server - called when we actually get on our IRC server
disconnect-server - called when we disconnect from our IRC server
Module: core
Index: doc/html/tcl-commands.html
===================================================================
RCS file: /usr/local/cvsroot/eggdrop1.8/doc/html/tcl-commands.html,v
retrieving revision 1.13
diff -u -r1.13 tcl-commands.html
--- a/doc/html/tcl-commands.html 26 Jun 2012 21:20:49 -0000 1.13
+++ b/doc/html/tcl-commands.html 6 Jan 2013 00:31:00 -0000
@@ -4921,6 +4921,16 @@
<tr valign="top">
<td>
+ <p><strong>preinit-server</strong></p>
+ </td>
+
+ <td>
+ <p>called immediately we connect to the IRC server</p>
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td>
<p><strong>init-server</strong></p>
</td>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment