]> Pileus Git - ~andy/rhawk/blob - irc.awk
Add authentication tracking on freenode
[~andy/rhawk] / irc.awk
1 # Connect with:
2 #   socat 'TCP:localhost:12345' 'EXEC:awk -f $0'
3 #
4 # Pre-defined variables:
5 #
6 # When connected:
7 #   SERVER:  IRC Server that is connected to
8 #   NICK:    Nickname given by the bot
9 #   CHANNEL: Channel the bot is currently in
10 #
11 # When a messages is recieved:
12 #   CMD:     Message, e.g. PRIVMSG
13 #   SRC:     Source of the message
14 #   DST:     Destination of the message, e.g. the channel
15 #   TO:      Nickname the message was addressed to
16 #   FROM:    Nickname of the user who sent the message
17 #   MSG:     Message sent
18 #   $0:      Message sans TO
19
20 # Debugging
21 function send(msg) {
22         print "  > " msg > "/dev/stderr"
23         print msg
24         fflush()
25 }
26
27 // {
28         #print ""         > "/dev/stderr"
29         print "  < " $0  > "/dev/stderr"
30 }
31
32 function debug(msg) {
33         print "  # " msg > "/dev/stderr"
34         fflush()
35 }
36
37 function set(i) {
38         debug("CMD:  [" CMD  "]")
39         debug("SRC:  [" SRC  "]")
40         debug("DST:  [" DST  "]")
41         debug("FROM: [" FROM "]")
42         debug("TO:   [" TO   "]")
43         debug("MSG:  [" MSG  "]")
44         debug("$0:   [" $0   "]")
45         for (i in ARG)
46                 debug("ARG"i": [" ARG[i] "]")
47 }
48
49 # Functions
50 function connect(server, nick, channel) {
51         SERVER  = server
52         NICK    = nick
53         CHANNEL = channel
54         if (FIRST) {
55                 "whoami"   | getline _name
56                 "hostname" | getline _host
57                 send("USER " _name " " _host " " server " :" nick)
58                 send("NICK " nick)
59                 send("CAP REQ :account-notify")
60                 send("CAP REQ :extended-join")
61                 send("CAP END")
62         } else {
63                 send("WHOIS " nick)
64         }
65 }
66
67 function say(to, msg) {
68         if (msg == "") {
69                 msg = to
70                 if (DST ~ "^#")
71                         to = DST
72                 else if (DST == NICK && FROM)
73                         to = FROM
74                 else
75                         to = CHANNEL
76         }
77         send("PRIVMSG " to " :" msg)
78         if (!DEBUG && NR > 1)
79                 system("sleep 1")
80 }
81
82 function action(to, msg)
83 {
84         if (msg)
85                 say(to, "\001ACTION " msg "\001")
86         else
87                 say("\001ACTION " to "\001")
88 }
89
90 function reply(msg) {
91         say(FROM ": " msg)
92 }
93
94 function join(chan) {
95         send("JOIN " chan)
96         send("TOPIC " chan)
97         send("WHO " chan " %uhnar")
98 }
99
100 function part(chan) {
101         send("PART " chan)
102 }
103
104 function topic(chan, msg) {
105         send("TOPIC " chan " :" msg)
106 }
107
108 # Reloading
109 BEGIN {
110         if (CHILD == "") {
111                 debug("Starting server");
112                 cmd = "awk -f rhawk" \
113                       " -v CHILD=1" \
114                       " -v START=" systime() \
115                       " -v DEBUG=" !!DEBUG
116                 status = system(cmd " -v FIRST=1");
117                 while (status)
118                         status = system(cmd);
119                 exit(0);
120         } else {
121                 debug("Starting child:" \
122                       " DEBUG=" DEBUG   \
123                       " CHILD=" CHILD   \
124                       " START=" START   \
125                       " FIRST=" FIRST);
126         }
127 }
128
129 function quit() {
130         exit(0)
131 }
132
133 function reload() {
134         exit(1)
135 }
136
137 # Input parsing
138 // {
139         gsub(/\s+/,     " ")
140         gsub(/^ | $/,    "")
141         gsub(/\3[0-9]*/, "")
142         match($0, /(:([^ ]+) )?([A-Z0-9]+)(( [^:][^ ]*)*)( :(.*))?/, arr);
143         sub(/^ /, "", arr[4])
144         SRC = arr[2]
145         CMD = arr[3]
146         MSG = arr[7]
147
148         split(arr[4], ARG)
149         DST = ARG[1]
150
151         match(SRC, /([^! ]+)!([^@ ]+)@([^ ]+\/[^ ]+)?/, arr);
152         FROM = arr[1]
153         USER = arr[2]
154         HOST = arr[3]
155
156         match(MSG, /(([^ :,]*)[:,] *)?(.*)/, arr);
157         TO  = arr[2]
158         $0  = TO ? arr[3] : MSG
159
160         if (CMD == "PRIVMSG" && DST == NICK && FROM && !TO)
161                 TO = DST
162
163         if (FROM in USERS)
164                 AUTH = USERS[FROM]["auth"]
165         else
166                 AUTH = ""
167
168         #set()
169 }
170
171 # IRC client
172 CMD == "001" && MSG ~ /Welcome/ {
173         join(CHANNEL)
174 }
175
176 CMD == "PING" {
177         send("PING " MSG)
178 }
179
180 CMD == "332" {
181         CMD = "TOPIC"
182 }
183
184 CMD == "TOPIC" {
185         topics[DST] = MSG
186 }
187
188 # Authentication
189 # todo - netsplits
190 CMD == "319" {
191         gsub(/[@+]/, "")
192         for (i=1; i<=NF; i++)
193                 send("WHO " $i " %uhnar")
194 }
195
196 CMD == "ACCOUNT" {
197         _auth = ARG[1] == "*" ? 0 : ARG[1]
198         USERS[FROM]["auth"] = _auth
199 }
200
201 CMD == "354" {
202         _auth = ARG[5] == "*" ? 0 : ARG[5]
203         USERS[ARG[4]]["user"] = ARG[2]
204         USERS[ARG[4]]["host"] = ARG[3]
205         USERS[ARG[4]]["nick"] = ARG[4]
206         USERS[ARG[4]]["auth"] = _auth
207         USERS[ARG[4]]["real"] = MSG
208 }
209
210 CMD == "JOIN" {
211         _auth = ARG[2] == "*" ? 0 : ARG[2]
212         USERS[FROM]["user"] = USER
213         USERS[FROM]["host"] = HOST
214         USERS[FROM]["nick"] = FROM
215         USERS[FROM]["auth"] = _auth
216         USERS[FROM]["real"] = MSG
217 }
218
219 /^\.auth/ {
220         _who = $2 ? $2 : FROM
221         if (_who in USERS)
222                 say(" nick=" USERS[_who]["nick"] \
223                     " user=" USERS[_who]["user"] \
224                     " auth=" USERS[_who]["auth"] \
225                     " real=" USERS[_who]["real"] \
226                     " host=" USERS[_who]["host"])
227         else
228                 say("no auth info for " _who)
229 }