mirror of https://github.com/nealey/irc-bot
Lots of cleanup; add firebot script
This commit is contained in:
parent
c9b5115c88
commit
d6a497df30
2
Makefile
2
Makefile
|
@ -5,7 +5,7 @@ OCAMLC = ocamlc -g
|
||||||
OCAMLDEP = ocamldep $(INCLUDES)
|
OCAMLDEP = ocamldep $(INCLUDES)
|
||||||
OCAMLLIBS = unix.cma str.cma nums.cma
|
OCAMLLIBS = unix.cma str.cma nums.cma
|
||||||
|
|
||||||
bot: irc.cmo dispatch.cmo process.cmo command.cmo iobuf.cmo cdb.cmo bindings.cmo infobot.cmo bot.cmo infobot.cmo
|
bot: irc.cmo dispatch.cmo process.cmo command.cmo iobuf.cmo bot.cmo
|
||||||
$(OCAMLC) -o $@ $(OCAMLLIBS) $^
|
$(OCAMLC) -o $@ $(OCAMLLIBS) $^
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
40
bindings.ml
40
bindings.ml
|
@ -1,40 +0,0 @@
|
||||||
type callback = Iobuf.t -> Command.t -> unit
|
|
||||||
type t = (string * Str.regexp * callback) list
|
|
||||||
|
|
||||||
let create () = []
|
|
||||||
|
|
||||||
let remove b id =
|
|
||||||
let keep = function
|
|
||||||
| (id', _, _) ->
|
|
||||||
id' <> id
|
|
||||||
in
|
|
||||||
List.filter keep b
|
|
||||||
|
|
||||||
let add b id regex cb =
|
|
||||||
(id, regex, cb) :: (remove b id)
|
|
||||||
|
|
||||||
let lookup b text =
|
|
||||||
let rec groups str i acc =
|
|
||||||
try
|
|
||||||
groups str (i + 1) ((Str.matched_group i str) :: acc)
|
|
||||||
with
|
|
||||||
| Not_found ->
|
|
||||||
groups str (i + 1) ("" :: acc)
|
|
||||||
| Invalid_argument _ ->
|
|
||||||
List.rev acc
|
|
||||||
in
|
|
||||||
let rec loop b acc =
|
|
||||||
match b with
|
|
||||||
| [] ->
|
|
||||||
List.rev acc
|
|
||||||
| (id, regex, cb) :: tl ->
|
|
||||||
try
|
|
||||||
ignore (Str.search_forward regex text 0);
|
|
||||||
loop tl ((id, cb, groups text 0 []) :: acc)
|
|
||||||
with Not_found ->
|
|
||||||
loop tl acc
|
|
||||||
in
|
|
||||||
loop b []
|
|
||||||
|
|
||||||
|
|
||||||
|
|
3
bot.ml
3
bot.ml
|
@ -31,7 +31,7 @@ let extern_callback iobuf sender forum text =
|
||||||
| "" :: tl ->
|
| "" :: tl ->
|
||||||
f tl
|
f tl
|
||||||
| line :: tl ->
|
| line :: tl ->
|
||||||
if line.[0] == ':' then
|
if line.[0] == '\007' then
|
||||||
(* Interpret as raw IRC commands *)
|
(* Interpret as raw IRC commands *)
|
||||||
let ine = Str.string_after line 1 in
|
let ine = Str.string_after line 1 in
|
||||||
let cmd = Command.from_string ine in
|
let cmd = Command.from_string ine in
|
||||||
|
@ -63,6 +63,7 @@ let handle_command outbuf handle_cmd thisbuf cmd =
|
||||||
| (Some suhost, "PART", [forum], _)
|
| (Some suhost, "PART", [forum], _)
|
||||||
| (Some suhost, "JOIN", [forum], _)
|
| (Some suhost, "JOIN", [forum], _)
|
||||||
| (Some suhost, "MODE", forum :: _, _)
|
| (Some suhost, "MODE", forum :: _, _)
|
||||||
|
| (Some suhost, "INVITE", [_; forum], None)
|
||||||
| (Some suhost, "INVITE", _, Some forum)
|
| (Some suhost, "INVITE", _, Some forum)
|
||||||
| (Some suhost, "TOPIC", forum :: _, _)
|
| (Some suhost, "TOPIC", forum :: _, _)
|
||||||
| (Some suhost, "KICK", forum :: _, _) ->
|
| (Some suhost, "KICK", forum :: _, _) ->
|
||||||
|
|
310
cdb.ml
310
cdb.ml
|
@ -1,310 +0,0 @@
|
||||||
(*
|
|
||||||
* Copyright (c) 2003 Dustin Sallings <dustin@spy.net>
|
|
||||||
*
|
|
||||||
* arch-tag: 1E3B7401-2AE1-11D8-A379-000393CB0F1E
|
|
||||||
*)
|
|
||||||
|
|
||||||
(** CDB Implementation.
|
|
||||||
{{:http://cr.yp.to/cdb/cdb.txt} http://cr.yp.to/cdb/cdb.txt}
|
|
||||||
*)
|
|
||||||
|
|
||||||
(* The cdb hash function is ``h = ((h << 5) + h) ^ c'', with a starting
|
|
||||||
hash of 5381.
|
|
||||||
*)
|
|
||||||
|
|
||||||
(** CDB creation handle. *)
|
|
||||||
type cdb_creator = {
|
|
||||||
table_count: int array;
|
|
||||||
(* Hash index pointers *)
|
|
||||||
mutable pointers: (Int32.t * Int32.t) list;
|
|
||||||
out: out_channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
(** Initial hash value *)
|
|
||||||
let hash_init = Int64.of_int 5381
|
|
||||||
|
|
||||||
let ff64 = Int64.of_int 0xff
|
|
||||||
(* I need to do this of_string because it's larger than an ocaml int *)
|
|
||||||
let ffffffff64 = Int64.of_string "0xffffffff"
|
|
||||||
let ff32 = Int32.of_int 0xff
|
|
||||||
|
|
||||||
(** Hash the given string. *)
|
|
||||||
let hash s =
|
|
||||||
let h = ref hash_init in
|
|
||||||
String.iter (fun c -> h := Int64.logand ffffffff64 (Int64.logxor
|
|
||||||
(Int64.add (Int64.shift_left !h 5) !h)
|
|
||||||
(Int64.of_int (int_of_char c)))
|
|
||||||
) s;
|
|
||||||
Int64.to_int32 !h
|
|
||||||
|
|
||||||
let write_le cdc i =
|
|
||||||
output_byte cdc.out (i land 0xff);
|
|
||||||
output_byte cdc.out ((i lsr 8) land 0xff);
|
|
||||||
output_byte cdc.out ((i lsr 16) land 0xff);
|
|
||||||
output_byte cdc.out ((i lsr 24) land 0xff)
|
|
||||||
|
|
||||||
(** Write a little endian integer to the file *)
|
|
||||||
let write_le32 cdc i =
|
|
||||||
output_byte cdc.out (Int32.to_int (Int32.logand ff32 i));
|
|
||||||
output_byte cdc.out (Int32.to_int
|
|
||||||
(Int32.logand ff32 (Int32.shift_right_logical i 8)));
|
|
||||||
output_byte cdc.out (Int32.to_int
|
|
||||||
(Int32.logand ff32 (Int32.shift_right_logical i 16)));
|
|
||||||
output_byte cdc.out (Int32.to_int
|
|
||||||
(Int32.logand ff32 (Int32.shift_right_logical i 24)))
|
|
||||||
|
|
||||||
(**
|
|
||||||
Open a cdb creator for writing.
|
|
||||||
|
|
||||||
@param fn the file to write
|
|
||||||
*)
|
|
||||||
let open_out fn =
|
|
||||||
let s = { table_count=Array.make 256 0;
|
|
||||||
pointers=[];
|
|
||||||
out=open_out_bin fn
|
|
||||||
} in
|
|
||||||
(* Skip over the header *)
|
|
||||||
seek_out s.out 2048;
|
|
||||||
s
|
|
||||||
|
|
||||||
(**
|
|
||||||
Convert out_channel to cdb_creator.
|
|
||||||
|
|
||||||
@param out_channel the out_channel to convert
|
|
||||||
*)
|
|
||||||
let cdb_creator_of_out_channel out_channel =
|
|
||||||
let s = { table_count=Array.make 256 0;
|
|
||||||
pointers=[];
|
|
||||||
out=out_channel
|
|
||||||
} in
|
|
||||||
(* Skip over the header *)
|
|
||||||
seek_out s.out 2048;
|
|
||||||
s
|
|
||||||
|
|
||||||
let hash_to_table h =
|
|
||||||
Int32.to_int (Int32.logand h ff32)
|
|
||||||
|
|
||||||
let hash_to_bucket h len =
|
|
||||||
Int32.to_int (Int32.rem (Int32.shift_right_logical h 8) (Int32.of_int len))
|
|
||||||
|
|
||||||
let pos_out_32 x =
|
|
||||||
Int64.to_int32 (LargeFile.pos_out x)
|
|
||||||
|
|
||||||
(** Add a value to the cdb *)
|
|
||||||
let add cdc k v =
|
|
||||||
(* Add the hash to the list *)
|
|
||||||
let h = hash k in
|
|
||||||
cdc.pointers <- (h, pos_out_32 cdc.out) :: cdc.pointers;
|
|
||||||
let table = hash_to_table h in
|
|
||||||
cdc.table_count.(table) <- cdc.table_count.(table) + 1;
|
|
||||||
|
|
||||||
(* Add the data to the file *)
|
|
||||||
write_le cdc (String.length k);
|
|
||||||
write_le cdc (String.length v);
|
|
||||||
output_string cdc.out k;
|
|
||||||
output_string cdc.out v
|
|
||||||
|
|
||||||
(** Process a hash table *)
|
|
||||||
let process_table cdc table_start slot_table slot_pointers i tc =
|
|
||||||
(* Length of the table *)
|
|
||||||
let len = tc * 2 in
|
|
||||||
(* Store the table position *)
|
|
||||||
slot_table := (pos_out_32 cdc.out, Int32.of_int len) :: !slot_table;
|
|
||||||
(* Build the hash table *)
|
|
||||||
let ht = Array.make len None in
|
|
||||||
let cur_p = ref table_start.(i) in
|
|
||||||
(* Lookup entries by slot number *)
|
|
||||||
let lookupSlot x =
|
|
||||||
try Hashtbl.find slot_pointers x
|
|
||||||
with Not_found -> (Int32.zero,Int32.zero)
|
|
||||||
in
|
|
||||||
(* from 0 to tc-1 because the loop will run an extra time otherwise *)
|
|
||||||
for u = 0 to (tc - 1) do
|
|
||||||
let hp = lookupSlot !cur_p in
|
|
||||||
cur_p := !cur_p + 1;
|
|
||||||
|
|
||||||
(* Find an available hash bucket *)
|
|
||||||
let rec find_where where =
|
|
||||||
match ht.(where) with
|
|
||||||
| None ->
|
|
||||||
where
|
|
||||||
| _ ->
|
|
||||||
if ((where + 1) = len) then (find_where 0)
|
|
||||||
else (find_where (where + 1))
|
|
||||||
in
|
|
||||||
let where = find_where (hash_to_bucket (fst hp) len) in
|
|
||||||
ht.(where) <- Some hp;
|
|
||||||
done;
|
|
||||||
(* Write this hash table *)
|
|
||||||
Array.iter (fun hpp ->
|
|
||||||
let h,t = match hpp with
|
|
||||||
None -> Int32.zero,Int32.zero
|
|
||||||
| Some(h,t) -> h,t;
|
|
||||||
in
|
|
||||||
write_le32 cdc h; write_le32 cdc t
|
|
||||||
) ht
|
|
||||||
|
|
||||||
(** Close and finish the cdb creator. *)
|
|
||||||
let close_cdb_out cdc =
|
|
||||||
let cur_entry = ref 0 in
|
|
||||||
let table_start = Array.make 256 0 in
|
|
||||||
(* Find all the hash starts *)
|
|
||||||
Array.iteri (fun i x ->
|
|
||||||
cur_entry := !cur_entry + x;
|
|
||||||
table_start.(i) <- !cur_entry) cdc.table_count;
|
|
||||||
(* Build out the slot pointers hash *)
|
|
||||||
let slot_pointers = Hashtbl.create (List.length cdc.pointers) in
|
|
||||||
(* Fill in the slot pointers *)
|
|
||||||
List.iter (fun hp ->
|
|
||||||
let h = fst hp in
|
|
||||||
let table = hash_to_table h in
|
|
||||||
table_start.(table) <- table_start.(table) - 1;
|
|
||||||
Hashtbl.replace slot_pointers table_start.(table) hp;
|
|
||||||
) cdc.pointers;
|
|
||||||
(* Write the shit out *)
|
|
||||||
let slot_table = ref [] in
|
|
||||||
(* Write out the hash tables *)
|
|
||||||
Array.iteri (process_table cdc table_start slot_table slot_pointers)
|
|
||||||
cdc.table_count;
|
|
||||||
(* write out the pointer sets *)
|
|
||||||
seek_out cdc.out 0;
|
|
||||||
List.iter (fun x -> write_le32 cdc (fst x); write_le32 cdc (snd x))
|
|
||||||
(List.rev !slot_table);
|
|
||||||
close_out cdc.out
|
|
||||||
|
|
||||||
(** {1 Iterating a cdb file} *)
|
|
||||||
|
|
||||||
(* read a little-endian integer *)
|
|
||||||
let read_le f =
|
|
||||||
let a = (input_byte f) in
|
|
||||||
let b = (input_byte f) in
|
|
||||||
let c = (input_byte f) in
|
|
||||||
let d = (input_byte f) in
|
|
||||||
a lor (b lsl 8) lor (c lsl 16) lor (d lsl 24)
|
|
||||||
|
|
||||||
(* Int32 version of read_le *)
|
|
||||||
let read_le32 f =
|
|
||||||
let a = (input_byte f) in
|
|
||||||
let b = (input_byte f) in
|
|
||||||
let c = (input_byte f) in
|
|
||||||
let d = (input_byte f) in
|
|
||||||
Int32.logor (Int32.of_int (a lor (b lsl 8) lor (c lsl 16)))
|
|
||||||
(Int32.shift_left (Int32.of_int d) 24)
|
|
||||||
|
|
||||||
(**
|
|
||||||
Iterate a CDB.
|
|
||||||
|
|
||||||
@param f the function to call for every key/value pair
|
|
||||||
@param fn the name of the cdb to iterate
|
|
||||||
*)
|
|
||||||
let iter f fn =
|
|
||||||
let fin = open_in_bin fn in
|
|
||||||
try
|
|
||||||
(* Figure out where the end of all data is *)
|
|
||||||
let eod = read_le32 fin in
|
|
||||||
(* Seek to the record section *)
|
|
||||||
seek_in fin 2048;
|
|
||||||
let rec loop() =
|
|
||||||
(* (pos_in fin) < eod *)
|
|
||||||
if (Int32.compare (Int64.to_int32 (LargeFile.pos_in fin)) eod < 0)
|
|
||||||
then (
|
|
||||||
let klen = read_le fin in
|
|
||||||
let dlen = read_le fin in
|
|
||||||
let key = String.create klen in
|
|
||||||
let data = String.create dlen in
|
|
||||||
really_input fin key 0 klen;
|
|
||||||
really_input fin data 0 dlen;
|
|
||||||
f key data;
|
|
||||||
loop()
|
|
||||||
) in
|
|
||||||
loop();
|
|
||||||
close_in fin;
|
|
||||||
with x -> close_in fin; raise x;
|
|
||||||
|
|
||||||
(** {1 Searching } *)
|
|
||||||
|
|
||||||
(** Type type of a cdb_file. *)
|
|
||||||
type cdb_file = {
|
|
||||||
f: in_channel;
|
|
||||||
(* Position * length *)
|
|
||||||
tables: (Int32.t * int) array;
|
|
||||||
}
|
|
||||||
|
|
||||||
(** Open a CDB file for searching.
|
|
||||||
|
|
||||||
@param fn the file to open
|
|
||||||
*)
|
|
||||||
let open_cdb_in fn =
|
|
||||||
let fin = open_in_bin fn in
|
|
||||||
let tables = Array.make 256 (Int32.zero,0) in
|
|
||||||
(* Set the positions and lengths *)
|
|
||||||
Array.iteri (fun i it ->
|
|
||||||
let pos = read_le32 fin in
|
|
||||||
let len = read_le fin in
|
|
||||||
tables.(i) <- (pos,len)
|
|
||||||
) tables;
|
|
||||||
{f=fin; tables=tables}
|
|
||||||
|
|
||||||
(**
|
|
||||||
Close a cdb file.
|
|
||||||
|
|
||||||
@param cdf the cdb file to close
|
|
||||||
*)
|
|
||||||
let close_cdb_in cdf =
|
|
||||||
close_in cdf.f
|
|
||||||
|
|
||||||
(** Get a list of matches.
|
|
||||||
|
|
||||||
@param cdf the cdb file
|
|
||||||
@param key the key to search
|
|
||||||
*)
|
|
||||||
let get_matches cdf key =
|
|
||||||
let kh = hash key in
|
|
||||||
(* Find out where the hash table is *)
|
|
||||||
let hpos, hlen = cdf.tables.(hash_to_table kh) in
|
|
||||||
let rec loop x acc =
|
|
||||||
if (x >= hlen) then
|
|
||||||
acc
|
|
||||||
else
|
|
||||||
let acc' =
|
|
||||||
(* Calculate the slot containing these entries *)
|
|
||||||
let lslot = ((hash_to_bucket kh hlen) + x) mod hlen in
|
|
||||||
let spos = Int32.add (Int32.of_int (lslot * 8)) hpos in
|
|
||||||
let _ = LargeFile.seek_in cdf.f (Int64.of_int32 spos) in
|
|
||||||
let h = read_le32 cdf.f in
|
|
||||||
let pos = read_le32 cdf.f in
|
|
||||||
(* validate that we a real bucket *)
|
|
||||||
if (h = kh) && ((Int32.compare pos Int32.zero) > 0) then
|
|
||||||
let _ = LargeFile.seek_in cdf.f (Int64.of_int32 pos) in
|
|
||||||
let klen = read_le cdf.f in
|
|
||||||
if (klen = String.length key) then
|
|
||||||
let dlen = read_le cdf.f in
|
|
||||||
let rkey = String.create klen in
|
|
||||||
really_input cdf.f rkey 0 klen;
|
|
||||||
if (rkey = key) then
|
|
||||||
let rdata = String.create dlen in
|
|
||||||
really_input cdf.f rdata 0 dlen;
|
|
||||||
rdata :: acc
|
|
||||||
else
|
|
||||||
acc
|
|
||||||
else
|
|
||||||
acc
|
|
||||||
else
|
|
||||||
acc
|
|
||||||
in
|
|
||||||
loop (x + 1) acc'
|
|
||||||
in
|
|
||||||
List.rev (loop 0 [])
|
|
||||||
|
|
||||||
(**
|
|
||||||
Find the first record with the given key.
|
|
||||||
|
|
||||||
@param cdf the cdb_file
|
|
||||||
@param key the key to find
|
|
||||||
*)
|
|
||||||
let find cdf key =
|
|
||||||
match (get_matches cdf key) with
|
|
||||||
| [] ->
|
|
||||||
raise Not_found
|
|
||||||
| r :: _ ->
|
|
||||||
r
|
|
40
cdb.mli
40
cdb.mli
|
@ -1,40 +0,0 @@
|
||||||
|
|
||||||
(** CDB Implementation.
|
|
||||||
{{:http://cr.yp.to/cdb/cdb.txt} http://cr.yp.to/cdb/cdb.txt}
|
|
||||||
*)
|
|
||||||
|
|
||||||
(** {1 Utilities} *)
|
|
||||||
val hash : string -> int32
|
|
||||||
|
|
||||||
(** {1 Building a CDB } *)
|
|
||||||
|
|
||||||
type cdb_creator = {
|
|
||||||
table_count : int array;
|
|
||||||
mutable pointers : (Int32.t * Int32.t) list;
|
|
||||||
out : out_channel;
|
|
||||||
}
|
|
||||||
val open_out : string -> cdb_creator
|
|
||||||
val cdb_creator_of_out_channel : Pervasives.out_channel -> cdb_creator
|
|
||||||
val add : cdb_creator -> string -> string -> unit
|
|
||||||
val close_cdb_out : cdb_creator -> unit
|
|
||||||
|
|
||||||
(** {1 Iterating a CDB } *)
|
|
||||||
|
|
||||||
val iter : (string -> string -> unit) -> string -> unit
|
|
||||||
|
|
||||||
(** {1 Searching } *)
|
|
||||||
|
|
||||||
type cdb_file = {
|
|
||||||
f: in_channel;
|
|
||||||
tables: (Int32.t * int) array;
|
|
||||||
}
|
|
||||||
|
|
||||||
val open_cdb_in : string -> cdb_file
|
|
||||||
val close_cdb_in : cdb_file -> unit
|
|
||||||
|
|
||||||
val get_matches : cdb_file -> string -> string list
|
|
||||||
val find : cdb_file -> string -> string
|
|
||||||
|
|
||||||
(*
|
|
||||||
* arch-tag: 55F4CBF0-2B50-11D8-BEDC-000393CFE6B8
|
|
||||||
*)
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
exec ./bot \
|
||||||
|
-n cobalt \
|
||||||
|
-u cobalt \
|
||||||
|
-a ./cobalt-handler \
|
||||||
|
socat STDIO OPENSSL:woozle.org:994,verify=0
|
|
@ -0,0 +1,24 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
sender=$1; export sender; shift
|
||||||
|
forum=$1; export forum; shift
|
||||||
|
prefix=$1; export prefix; shift
|
||||||
|
command=$1; export command; shift
|
||||||
|
# $* is now args
|
||||||
|
text=$(cat)
|
||||||
|
|
||||||
|
case $command in
|
||||||
|
001)
|
||||||
|
printf '\aJOIN #woozle\n'
|
||||||
|
printf '\aJOIN #foozle\n'
|
||||||
|
printf '\aJOIN #bot\n'
|
||||||
|
;;
|
||||||
|
PRIVMSG)
|
||||||
|
./firebot "$text" || \
|
||||||
|
./infobot woozle.cdb "$text"
|
||||||
|
;;
|
||||||
|
INVITE)
|
||||||
|
printf '\aJOIN %s\n' "$forum"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
firebot () {
|
||||||
|
read cmd args
|
||||||
|
case $cmd in
|
||||||
|
calc)
|
||||||
|
printf "%s = " "$args"
|
||||||
|
echo "$args" | bc -l
|
||||||
|
;;
|
||||||
|
units)
|
||||||
|
src=$(echo "$args" | sed 's/ ->.*//')
|
||||||
|
dst=$(echo "$args" | sed 's/.*-> //')
|
||||||
|
units -1 -v -- "$src" "$dst"
|
||||||
|
;;
|
||||||
|
.note)
|
||||||
|
who=$(echo $args | cut -d\ -f1 | tr -d -c A-Za-z0-9)
|
||||||
|
what=$(echo $args | cut -d\ -f2-)
|
||||||
|
when=$(date)
|
||||||
|
echo "($when) <$sender> $what" > notes/$who
|
||||||
|
echo "I've left $who a note, $sender."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -f notes/$sender ]; then
|
||||||
|
echo "Welcome back, $sender. Your messages:"
|
||||||
|
cat notes/$sender
|
||||||
|
rm notes/$sender
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$1" | firebot
|
||||||
|
|
||||||
|
|
||||||
|
|
40
infobot
40
infobot
|
@ -35,10 +35,9 @@ EOF
|
||||||
cdb -s $db | head -n 1
|
cdb -s $db | head -n 1
|
||||||
;;
|
;;
|
||||||
!l*)
|
!l*)
|
||||||
printf "%s is:" "$args"
|
printf "%s" "$args"
|
||||||
cdb -q -m $db "$args" | while read v; do
|
cdb -q -m $db "$args" | \
|
||||||
printf " \"%s\" |" "$v"
|
awk '{printf(" | \"%s\"", $0);}'
|
||||||
done
|
|
||||||
echo
|
echo
|
||||||
;;
|
;;
|
||||||
!a*)
|
!a*)
|
||||||
|
@ -46,40 +45,35 @@ EOF
|
||||||
val=$(printf "%s" "$args" | sed 's/.*+= //')
|
val=$(printf "%s" "$args" | sed 's/.*+= //')
|
||||||
(printf "+%d,%d:%s->%s\n" ${#key} ${#val} "$key" "$val";
|
(printf "+%d,%d:%s->%s\n" ${#key} ${#val} "$key" "$val";
|
||||||
cdb -d $db) | cdb -c $db
|
cdb -d $db) | cdb -c $db
|
||||||
|
echo "Okay, $sender, I added a factoid to $key"
|
||||||
;;
|
;;
|
||||||
!r*)
|
!r*)
|
||||||
key=$(printf "%s" "$args" | sed 's/ -=.*//')
|
key=$(printf "%s" "$args" | sed 's/ -=.*//')
|
||||||
val=$(printf "%s" "$args" | sed 's/.*-= //')
|
val=$(printf "%s" "$args" | sed 's/.*-= //')
|
||||||
gs=":$key->.*$val"
|
re=":$key->.*$val"
|
||||||
case $(cdb -d $db | grep -c "$gs") in
|
n=$(cdb -d $db | grep -c "$re")
|
||||||
0)
|
if [ $n -gt 0 ]; then
|
||||||
echo 'No matches'
|
cdb -d $db | grep -a -v ":$key->.*$val" | cdb -c $db
|
||||||
;;
|
echo "Okay, $sender, I removed $n factoids from $key"
|
||||||
1)
|
else
|
||||||
cdb -d $db | grep -v "$gs" | cdb -c $db
|
echo "Nothing matched, $sender."
|
||||||
echo "I removed $val from $key"
|
fi
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo 'That maches more than one entry; please refine your request'
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
;;
|
||||||
!f*)
|
!f*)
|
||||||
cdb -d $db | fgrep -v ":$args->" | cdb -c $db
|
cdb -d $db | grep -a -F -v ":$args->" | cdb -c $db
|
||||||
echo "I forgot $args"
|
echo "I removed all factoids from $args"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
resp=$(lookup "$text" | shuf -n 1 | sed "s/\$sender/$sender/")
|
resp=$(lookup "$text" | shuf -n 1 | sed "s/\$sender/$sender/")
|
||||||
case "$resp" in
|
case "$resp" in
|
||||||
"")
|
"")
|
||||||
|
exit 1
|
||||||
;;
|
;;
|
||||||
\\*)
|
\\*)
|
||||||
echo "$resp" | cut -b2-
|
printf "%s" "$resp" | cut -b2-
|
||||||
;;
|
;;
|
||||||
:*)
|
:*)
|
||||||
echo -ne '\001ACTION '
|
printf '\001ACTION %s\001\n' "$(echo "$resp" | cut -b2-)"
|
||||||
echo -n $(echo "$resp" | cut -b2-)
|
|
||||||
echo -e '\001'
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "It's been said that $text is $resp"
|
echo "It's been said that $text is $resp"
|
||||||
|
|
70
infobot.ml
70
infobot.ml
|
@ -1,70 +0,0 @@
|
||||||
type t = {
|
|
||||||
filename: string;
|
|
||||||
mutable db: Cdb.cdb_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = Random.self_init ()
|
|
||||||
|
|
||||||
let create filename =
|
|
||||||
{
|
|
||||||
filename = filename;
|
|
||||||
db = Cdb.open_cdb_in filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
let choice l =
|
|
||||||
let n = Random.int (List.length l) in
|
|
||||||
List.nth l n
|
|
||||||
|
|
||||||
let strip s =
|
|
||||||
let rec lastchar n =
|
|
||||||
match s.[n-1] with
|
|
||||||
| '.'
|
|
||||||
| '!'
|
|
||||||
| '?'
|
|
||||||
| ' ' ->
|
|
||||||
lastchar (n - 1)
|
|
||||||
| _ ->
|
|
||||||
n
|
|
||||||
in
|
|
||||||
let len = lastchar (String.length s) in
|
|
||||||
if (len = String.length s) then
|
|
||||||
None
|
|
||||||
else
|
|
||||||
Some (String.sub s 0 len)
|
|
||||||
|
|
||||||
let choose_one ib key =
|
|
||||||
match (Cdb.get_matches ib.db key) with
|
|
||||||
| [] ->
|
|
||||||
raise Not_found
|
|
||||||
| keys ->
|
|
||||||
choice keys
|
|
||||||
|
|
||||||
let lookup store text =
|
|
||||||
try
|
|
||||||
let text, factoid =
|
|
||||||
try
|
|
||||||
(text, choose_one store text)
|
|
||||||
with Not_found ->
|
|
||||||
match (strip text) with
|
|
||||||
| None ->
|
|
||||||
raise Not_found
|
|
||||||
| Some stext ->
|
|
||||||
(stext, choose_one store stext)
|
|
||||||
in
|
|
||||||
match factoid.[0] with
|
|
||||||
| ':' ->
|
|
||||||
Some ("\001ACTION " ^ (Str.string_after factoid 1) ^ "\001")
|
|
||||||
| '\\' ->
|
|
||||||
Some (Str.string_after factoid 1)
|
|
||||||
| _ ->
|
|
||||||
Some (Printf.sprintf "I overheard that %s is %s" text factoid)
|
|
||||||
with Not_found ->
|
|
||||||
None
|
|
||||||
|
|
||||||
|
|
||||||
let handle_privmsg store msg sender forum text =
|
|
||||||
match (lookup store text) with
|
|
||||||
| Some reply ->
|
|
||||||
msg reply
|
|
||||||
| None ->
|
|
||||||
()
|
|
|
@ -8,7 +8,6 @@ let spawn prog args =
|
||||||
Unix.close fd0_exit;
|
Unix.close fd0_exit;
|
||||||
|
|
||||||
Unix.dup2 fd1_entr Unix.stdout;
|
Unix.dup2 fd1_entr Unix.stdout;
|
||||||
Unix.dup2 fd1_entr Unix.stderr;
|
|
||||||
Unix.close fd1_entr;
|
Unix.close fd1_entr;
|
||||||
Unix.close fd1_exit;
|
Unix.close fd1_exit;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue