diff --git a/Makefile b/Makefile deleted file mode 100644 index 17e1ed4..0000000 --- a/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -OCAML_PACKAGES := -package equeue -package pcre - -TARGETS = ircd - -OCAMLOPTS = -g -OCAMLC = ocamlfind c $(OCAMLOPTS) - -all: $(TARGETS) - -ircd: connection.cmo ircd.cmo - -.PHONY: test -test: tests - ./tests - -## -## Generic ways to do things -## -%.cmo : %.ml - $(OCAMLC) -c $^ $(OCAML_PACKAGES) - -%: %.cmo - $(OCAMLC) -o $@ $(filter-out $<, $^) $< $(OCAML_PACKAGES) -linkpkg - -## -## -## -include .deps -.deps: *.ml - ocamldep $^ > $@ - -.PHONY: clean -clean: - rm -f $(TARGETS) *.cm? *.o diff --git a/OMakefile b/OMakefile new file mode 100644 index 0000000..6b8f0c4 --- /dev/null +++ b/OMakefile @@ -0,0 +1,22 @@ +USE_OCAMLFIND = true +OCAMLPACKS[] = + equeue + pcre + +.DEFAULT: ircd + +OCamlProgram(pgircd, pgircd ircd connection) + +section + OCAMLPACKS[] += + oUnit + + tests.cmx: + tests.cmi: + tests$(EXT_OBJ): + + OCamlProgram(tests, tests chat ircd connection) + +.PHONY: clean +clean: + rm $(filter-out %.pem tls.c, $(filter-proper-targets $(ls R, .))) diff --git a/OMakeroot b/OMakeroot new file mode 100644 index 0000000..20a8fe6 --- /dev/null +++ b/OMakeroot @@ -0,0 +1,45 @@ +######################################################################## +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this file, to deal in the File without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the File, and to permit persons to whom the +# File is furnished to do so, subject to the following condition: +# +# THE FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE FILE OR +# THE USE OR OTHER DEALINGS IN THE FILE. + +######################################################################## +# The standard OMakeroot file. +# You will not normally need to modify this file. +# By default, your changes should be placed in the +# OMakefile in this directory. +# +# If you decide to modify this file, note that it uses exactly +# the same syntax as the OMakefile. +# + +# +# Include the standard installed configuration files. +# Any of these can be deleted if you are not using them, +# but you probably want to keep the Common file. +# +#open build/C +open build/OCaml +#open build/LaTeX + +# +# The command-line variables are defined *after* the +# standard configuration has been loaded. +# +DefineCommandVars() + +# +# Include the OMakefile in this directory. +# +.SUBDIRS: . diff --git a/irc.ml b/irc.ml deleted file mode 100644 index 040797b..0000000 --- a/irc.ml +++ /dev/null @@ -1,284 +0,0 @@ -open Uq_engines -open Unixqueue - -let newline_re = Pcre.regexp "\n\r?" -let argsep_re = Pcre.regexp " :" -let space_re = Pcre.regexp " " - -let string_map f s = - let l = String.length s in - if l = 0 then - s - else - let r = String.create l in - for i = 0 to l - 1 do - String.unsafe_set r i (f (String.unsafe_get s i)) - done; - r - -let lowercase_char c = - if (c >= 'A' && c <= '^') then - Char.unsafe_chr(Char.code c + 32) - else - c - -let uppercase_char c = - if (c >= 'a' && c <= '~') then - Char.unsafe_chr(Char.code c - 32) - else - c - -let uppercase s = string_map uppercase_char s -let lowercase s = string_map lowercase_char s - - -class irc (ues : unix_event_system) = -object (self) - - val mutable debug = false - val throttle_interval = 1.0 - - (** Group for this bot's events *) - val g = ues#new_group () - - val out_wait_id = ues#new_wait_id () - val mutable check_output = None - val mutable output_pending = "" - val mutable input_pending = "" - val outq_immediate = Queue.create () - val outq_throttled = Queue.create () - val outq_last_sent = Unix.time () - - initializer - ues#add_handler g self#handle_event - - method debug v = - debug <- v - - method log msg = - if debug then - prerr_endline msg - - method handle_event ues' esys e = - assert (ues' = ues); - match e with - | Input_arrived (g, fd) -> - self#handle_input fd - | Output_readiness (g, fd) -> - self#handle_output fd - | Out_of_band (g, fd) -> - self#handle_oob fd - | Timeout (g, op) -> - self#handle_timeout op - | Signal -> - self#handle_signal () - | Extra exn -> - self#handle_extra exn - - method handle_input fd = - let s = 4096 in - let buf = String.create s in - let len = Unix.read fd buf 0 s in - let input = input_pending ^ (String.sub buf 0 len) in - if (input <> "") then - let lines = Pcre.split ~rex:newline_re input in - let rec handle_lines lines = - match lines with - | [] - | [""] -> - input_pending <- ""; - | line :: tl -> - self#handle_line line; - handle_lines tl - in - handle_lines lines - else - begin - Unix.close fd; - ues#clear g; - end - - - method handle_output fd = - let data = ( - if (output_pending <> "") then - output_pending - else if not (Queue.is_empty outq_immediate) then - Queue.pop outq_immediate - else if not (Queue.is_empty outq_throttled) then - begin - (* Stop listening for output events; add a timeout to - start listening again *) - (match check_output with - | None -> () - | Some co -> - let pay_attention () = - ues#add_resource g (co, -.1.0) - in - ues#remove_resource g co; - ues#once g throttle_interval pay_attention - ); - Queue.pop outq_throttled - end - else - match check_output with - | None -> "" - | Some co -> - ues#remove_resource g co; - "" - ) in - let data_len = String.length data in - let n = Unix.single_write fd data 0 data_len in - output_pending <- String.sub data n (data_len - n); - if (data <> "") then - self#log ("--> " ^ (String.escaped data)) - - method handle_oob fd = - self#log "OOB ready!"; - raise Equeue.Reject - - method handle_timeout op = - self#log "Timeout!"; - raise Equeue.Reject - - method handle_signal () = - self#log "Signal!"; - raise Equeue.Reject - - method handle_extra exn = - self#log "Extra!"; - raise Equeue.Reject - - method handle_line line = - let argstr, txt = - match Pcre.split ~max:2 ~rex:argsep_re line with - | [] -> ("", "") - | [a] -> (a, "") - | [a; b] -> (a, b) - | _ -> ("", "") - in - let sender, args = - let args' = Pcre.split ~rex:space_re argstr in - if (debug) then - print_endline ("<-- [" ^ - (String.concat "; " args') ^ - "] " ^ - txt); - if (List.hd args').[0] = ':' then - (List.hd args', List.tl args') - else - ("", args') - in - match args with - | [] -> - () - | "NOTICE" :: args -> - let tlen = String.length txt in - if ((txt.[0] = '\001') && - (txt.[tlen - 1] = '\001')) then - self#handle_ctcp_reply sender args (String.sub txt 1 (tlen - 2)) - else - self#handle_notice sender args txt - | "PRIVMSG" :: args -> - let tlen = String.length txt in - if ((txt.[0] = '\001') && - (txt.[tlen - 1] = '\001')) then - self#handle_ctcp_request sender args (String.sub txt 1 (tlen - 2)) - else - self#handle_privmsg args sender txt - | ["PING"] -> - self#handle_ping txt - | str :: args -> - let numeric = - try - Some (int_of_string str) - with Failure _ -> - None - in - match numeric with - | Some n -> - self#handle_numeric n sender args txt - | None -> - self#handle_unknown sender args txt - - - method handle_privmsg sender args txt = - () - - method handle_notice sender args txt = - () - - method handle_ctcp_request sender args txt = - () - - method handle_ctcp_reply sender args txt = - () - - method handle_numeric n sender args txt = - () - - method handle_unknown sender args txt = - self#log ("Got unknown server message") - - method handle_ping txt = - self#send ["PONG"] txt - - (** Public methods *) - - method set_fd fd nick gecos = - (* XXX: Clear old junk *) - check_output <- Some (Wait_out fd); - ues#add_resource g (Wait_in fd, -.1.0); - self#send ~now:true ["USER"; nick; "+iw"; nick] gecos; - self#send ~now:true ["NICK"; nick] "" - - (** Send a command to the IRC server *) - method send ?(now=false) args txt = - match check_output with - | None -> () - | Some co -> - let q = (if now then outq_immediate else outq_throttled) in - let cmdstr = - (String.concat " " args) ^ - (if txt = "" then "" else " :") ^ - txt ^ - "\n" - in - Queue.push cmdstr q; - ues#add_resource g (co, -.1.0) - - (** Send a private message *) - method privmsg ?(now=false) recipient txt = - self#send ~now ["PRIVMSG"; recipient] txt - - (** Send a notice *) - method notice ?(now=false) recipient txt = - self#send ~now ["NOTICE"; recipient] txt - - (** Send a CTCP request *) - method ctcp_request ?(now=false) recipient command txt = - self#privmsg ~now recipient ("\001" ^ command ^ " " ^ txt ^ "\001") - - (** Send a CTCP reply *) - method ctcp_reply ?(now=false) recipient command txt = - self#notice ~now recipient ("\001" ^ command ^ " " ^ txt ^ "\001") - -end - - -let main() = - let ues = new unix_event_system () in - let c = connector (`Socket(`Sock_inet_byname(Unix.SOCK_STREAM, - "woozle.org", 6667), - default_connect_options - )) ues in - when_state - ~is_done:(fun connstat -> - match connstat with - | `Socket(fd, _) -> - let b = new irc ues in - b#set_fd fd "plasma" "Plasma Bot" - | _ -> assert false - ) - c; - Unixqueue.run ues diff --git a/pgircd.ml b/pgircd.ml new file mode 100644 index 0000000..95b9b3f --- /dev/null +++ b/pgircd.ml @@ -0,0 +1,2 @@ +let _ = + Ircd.main ()