Anonymous avatar Anonymous committed b268bab

clean a little the tree. remove unused code.

Comments (0)

Files changed (11)

erlang/Makefile

-MODS = \
-	fbot_irc_behaviour \
-	fbot_irc_connection \
-	fbot_irc_protocol \
-	fbot_irc_supervisor \
-	fbot_logger \
-	fbot_socket \
-	fbot_server \
-	test
-
-SRCDIR = src
-BINDIR = ebin
-EFLAGS = -W
-
-OBJS = ${MODS:%=$(BINDIR)/%.beam}
-
-all: $(OBJS)
-
-$(BINDIR)/%.beam: $(SRCDIR)/%.erl
-	erlc -o $(BINDIR) $(EFLAGS) $<
-
-shell:
-	erl -pa $(BINDIR)
-
-clean:
-	rm -f $(OBJS)
-

erlang/src/fbot_irc_behaviour.erl

-%%
-%% fbot_irc_behaviour
-%%
-%% This is a gen_server process that connects to a single fbot_irc_connection
-%% process, and implements all higher-level per-bot behaviours. This includes:
-%%
-%%   - Joining and parting channels
-%%   - Responding to CTCP commands
-%%   - Responding to user messages
-%%   - Nickname policy
-%%
-%% Copyright (C) 2007 Micah Dowty <micah@navi.cx>
-%%
-%%---------------------------------------------------------------------------
-
--module(fbot_irc_behaviour).
--include("fbot_irc_protocol.hrl").
--behaviour(gen_server).
-
-%% Public API
--export([start_link/2]).
-
-%% gen_server callbacks
--export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]).
-
--record(bh_state, {
-	  conn     % Connection Pid
-	 }).
-
-
-%%---------------------------------------------------------------------------
-%% Public API
-%%---------------------------------------------------------------------------
-
-start_link(Parent, Options) ->
-    gen_server:start_link(?MODULE, {Parent, Options}, []).
-
-
-%%---------------------------------------------------------------------------
-%% Sent messages
-%%---------------------------------------------------------------------------
-
-%%
-%% Send an arbitrary message
-%%
-%% FIXME: Bandwidth accounting
-%%
-
-send_message(#message{}=Message, #bh_state{conn=Conn}) ->
-    {ok, Encoded} = fbot_irc_protocol:encode_message(Message),
-    fbot_irc_connection:send_data(Conn, Encoded).
-
-
-%%---------------------------------------------------------------------------
-%% Received message handlers
-%%---------------------------------------------------------------------------
-
-%% The connection process already handles pings. Do nothing.
-received_message(#message{command="PING"}, State) ->
-    State;
-
-%% Log unhandled messages
-received_message(Message, State) ->
-    fbot_logger:log(unhandled_message, Message),
-    State.
-
-
-%%---------------------------------------------------------------------------
-%% Callback interface for gen_server
-%%---------------------------------------------------------------------------
-
-terminate(_Reason, _State) ->
-    ok.
-
-code_change(_OldVsn, State, _Extra) ->
-    State.
-
-%%
-%% We have no synchronous initialization to perform.
-%% Make sure the first message we process is the 'connect' cast.
-%%
-
-init(Args) ->
-    fbot_logger:log(behaviour_state, init),
-    ok = gen_server:cast(self(), {connect, Args}),
-    {ok, not_connected}.
-
-%%
-%% 'connect' cast: Connect to the fbot_irc_connection process.
-%%
-%% We don't want to do this during init/1 for multiple reasons:
-%%
-%%   1. The call to fbot_irc_supervisor:get_child/2 would
-%%      deadlock if we issued it within our synchronous init/1.
-%%
-%%   2. The call to fbot_irc_connection:connect_behaviour/2
-%%      will block until the connection has logged in successfully,
-%%      which could take a while.
-%%
-
-handle_cast({connect, {Parent, _Options}}, not_connected) ->
-    %% This blocks until the supervisor is ready
-    Connection = fbot_irc_supervisor:get_child(Parent, connection),
-
-    %% Now this blocks until the connection is ready:
-    %% which means it blocks until it's logged in.
-    %% connect_behaviour/2 implements the login timeout for us.
-
-    fbot_logger:log(behaviour_state, connecting),
-    fbot_irc_connection:connect_behaviour(Connection, self()),
-    fbot_logger:log(behaviour_state, connected),
-
-    {noreply, #bh_state{conn=Connection}};
-
-%%
-%% 'irc_message' cast: Receive a raw IRC message
-%%                     from the connection process.
-%%
-
-handle_cast({irc_message, Data}, #bh_state{}=State) ->
-    case catch(fbot_irc_protocol:decode_message(Data)) of
-	{ok, Message} ->
-	    {noreply, received_message(Message, State)};
-	Error ->
-	    fbot_logger:log(decode_error, {Error, Data}),
-	    {noreply, State}
-    end;
-
-%%
-%% Log unhandled casts
-%%
-
-handle_cast(Cast, State) ->
-    fbot_logger:log(unhandled_cast, Cast),
-    {noreply, State}.
-
-%%
-%% Log unhandled calls
-%%
-
-handle_call(Call, From, State) ->
-    fbot_logger:log(unhandled_call, {Call, From}),
-    {reply, {error, unhandled_call}, State}.
-
-%%
-%% Log unhandled messages
-%%
-
-handle_info(Info, State) ->
-    fbot_logger:log(unhandled_info, Info),
-    {noreply, State}.

erlang/src/fbot_irc_connection.erl

-%%
-%% fbot_irc_connection
-%%
-%% This is a gen_server process which maintains a single IRC client
-%% connection. This process is responsible for:
-%%
-%%   - Establishing a connection
-%%   - Logging in
-%%   - Responding to PINGs
-%%
-%% It does NOT include any more state than necessary. This process
-%% should be very robust.
-%%
-%% Once the connection is established and the bot is logged in, this
-%% process directs incoming messages to a separate per-bot
-%% fbot_irc_behaviour process, which connects by calling
-%% connect_behaviour/2.
-%%
-%% Copyright (C) 2007 Micah Dowty <micah@navi.cx>
-%%
-%%---------------------------------------------------------------------------
-
--module(fbot_irc_connection).
--include("fbot_irc_protocol.hrl").
--behaviour(gen_server).
-
-%% Public API
--export([start_link/2, send_data/2, connect_behaviour/2, get_login_messages/1]).
-
-%% gen_server callbacks
--export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]).
-
-%% Milliseconds to wait for login to complete. This timeout is
-%% enforced by connect_behaviour.
--define(LOGIN_TIMEOUT, 120000).        
-
-%% Milliseconds to sleep after connect fails, before exiting and
-%% letting the supervisor retry
--define(CONNECT_FAIL_DELAY, 15000).
-
--record(conn_state, {
-	  sock,            % fbot_socket tuple
-	  behaviour,       % Pid of connected behaviour process.
-	  login_messages   % List of messages that came during login
-	 }).
-
-
-%%---------------------------------------------------------------------------
-%% Public API
-%%---------------------------------------------------------------------------
-
-%%
-%% Start a new bot. ConnectInfo is a connection tuple, passed directly
-%% to fbot_socket. Options is a property list with bot login options.
-%%
-%% The process will be creates synchronously, but connection and login
-%% both happen asynchronously. Note that the server will not respond
-%% to any other messages, including connect_behaviour/2, until login
-%% is complete.
-%%
-%% Options: nick, username, hostname, servername, realname,
-%%          temp_nick_prefix
-%%   
-
-start_link(ConnectInfo, Options) ->
-    gen_server:start_link(?MODULE, {ConnectInfo, Options}, []).
-
-%%
-%% Send raw data to this bot's socket. The caller is expected to
-%% encode the data. This improves reliability of this process, and
-%% it's necessary if the caller wishes to do traffic shaping.
-%%
-
-send_data(Pid, Data) ->
-    gen_server:call(Pid, {send_data, Data}).
-
-%%
-%% Connect a new behaviour process. Behaviour processes are notified
-%% of incoming messages via an 'irc_message' cast with the raw message
-%% data.
-%%
-%% NB: This process does have to decode messages, however we choose
-%%     to only provide the raw messages to the behaviour process.
-%%     This requires parsing every message twice, but it insulates
-%%     the interface between this process and the behaviour process
-%%     from changes in the message parsing code.
-%%
-%% We can only have one behaviour process at a time. This call
-%% replaces the existing behaviour process, if there was any.
-%%
-%% Note that all raw lines are delivered to the behaviour process,
-%% even lines from messages that we also handle internally (pings).
-%%
-%% This function implements the login timeout. If the connection
-%% doesn't respond for ?LOGIN_TIMEOUT milliseconds, we kill it and
-%% propagate the connection_timeout error.
-%%
-
-connect_behaviour(Pid, BehaviourPid) ->
-    case catch(gen_server:call(Pid, {connect_behaviour, BehaviourPid},
-			       ?LOGIN_TIMEOUT)) of
-	{'EXIT', {timeout, _}} ->
-	    exit(Pid, connection_timeout),
-	    exit(connection_timeout);
-	{'EXIT', Reason} ->
-	    exit(Reason);
-	Res ->
-	    Res
-    end.
-
-%%
-%% Retrieve a list of the messages processed and stored during login.
-%% This will include the MOTD and the server capabilities.
-%%
-
-get_login_messages(Pid) ->
-    gen_server:call(Pid, get_login_messages).
-
-
-%%---------------------------------------------------------------------------
-%% Local message processing
-%%---------------------------------------------------------------------------
-
-send_data_local(Line, #conn_state{sock=Sock}) ->
-    fbot_logger:log(send_data, Line),
-    fbot_socket:send(Sock, Line).
-
-received_line(Line, #conn_state{behaviour=Behaviour}=State) ->
-    gen_server:cast(Behaviour, {'irc_message', Line}),
-
-    case catch(deliver_local_message(Line, State)) of
-	ok -> ok;
-	Error -> fbot_logger:log(local_delivery_error, Error)
-    end.
-
-send_message(#message{}=Message, State) ->
-    {ok, Encoded} = fbot_irc_protocol:encode_message(Message),
-    send_data_local(Encoded, State).
-
-deliver_local_message(Line, State) ->
-    case fbot_irc_protocol:decode_message(Line) of
-	{ok, #message{command="PING"}=M} ->
-	    handle_local_message(M, State);
-	_ ->
-	    ok
-    end.
-
-%%
-%% Always respond to pings locally: we don't want the connection to
-%% die if the behaviour process is unavailable for a while.
-%%
-handle_local_message(#message{ command="PING", params=Params }, State) ->
-    send_message(#message{ command="PONG", params=Params }, State).
-
-
-%%---------------------------------------------------------------------------
-%% IRC Login
-%%---------------------------------------------------------------------------
-
-%%
-%% Blocking wait for an IRC message. This is for use only during
-%% login, when we want the server to finish before processing
-%% any other messages.
-%%
-%% This function includes a timeout between individual messages,
-%% however we still rely on an external supervisor to enforce an
-%% overall connect/login timeout.
-%%
-
-wait_for_message(#conn_state{sock=Sock}) ->
-    case fbot_socket:recv_blocking() of
-	{data, Sock, Line} ->
-	    {ok, #message{}=Message} = fbot_irc_protocol:decode_message(Line),
-	    Message;
-	Other -> exit(Other)
-    end.
-
-%%
-%% Synchronously log in to the IRC server.
-%%
-
-log_in(Options, State) ->
-    case proplists:get_value(password, Options) of
-	undefined -> ok;
-	Password ->
-	    send_message(#message{ command="PASS", params=[Password] }, State)
-    end,
-
-    %% This is just an initial guess at a nickname.  If there's a
-    %% collision, we'll respond by picking a random nick.  It's the
-    %% behaviour process's job to make sure we got a nick we like, and
-    %% to change it if necessary.
-
-    send_message(#message{command="NICK",
-			  params=[ proplists:get_value(nick, Options, "fpaste") ]},
-		 State),
-
-    {ok, Hostname} = inet:gethostname(),
-    Username = case os:getenv("USER") of
-		   false -> "cia";
-		   User -> User
-	       end,
-
-    send_message(#message{command="USER",
-			  params=[ proplists:get_value(username, Options, Username),
-				   proplists:get_value(hostname, Options, Hostname),
-				   proplists:get_value(servername, Options, "server"),
-				   proplists:get_value(realname, Options, "Friendpaste Bot")]},
-		 State),
-
-    fbot_logger:log(connection_state, wait_for_login),
-    State2 = wait_for_login(Options, State#conn_state{ login_messages=[] }),
-    fbot_logger:log(connection_state, logged_in),
-
-    %% Put the login_messages list back in order
-    State2#conn_state{ login_messages=lists:reverse(State2#conn_state.login_messages) }.
-
-
-%%
-%% Tail-recursive loop to synchronously wait for
-%% login to complete. Parses IRC messages as they
-%% arrive, and adds them to login_messages (in
-%% reverse order)
-%%
-
-wait_for_login(Options, State) ->
-    ok, Message = wait_for_message(State),
-    fbot_logger:log(login_message, Message),
-
-    %% Store every message that came during login.  Other processes
-    %% can query for these messages later, for example to retrieve the
-    %% MOTD or the list of server capabilities.
-
-    State2 = State#conn_state{ login_messages=[Message|State#conn_state.login_messages] },
-
-    case Message of
-
-	%% Always handle pings, even during login
-	#message{command="PING"} ->
-	    handle_local_message(Message, State2),
-	    wait_for_login(Options, State2);
-
-	%% "Nickname is already in use." Pick a random nickname
-	%% so we can finish logging in. Finding an available nick
-	%% might require performing WHOIS queries, which we can't
-	%% do before logging in.
-	#message{command="433"} ->
-	    send_message(#message{command="NICK",
-				  params=[ proplists:get_value(temp_nick_prefix, Options, "CIA-temp")
-					   ++ integer_to_list(100 + random:uniform(999 - 100)) ]},
-			 State2),
-	    wait_for_login(Options, State2);
-	
-	%% "MOTD file is missing." Done with login.
-	#message{command="422"} ->
-	    State2;
-
-	%% "End of MOTD." Done with login.
-	#message{command="376"} ->
-	    State2;
-
-	_ ->
-	    wait_for_login(Options, State2)
-    end.
-
-
-%%---------------------------------------------------------------------------
-%% Callback interface for gen_server
-%%---------------------------------------------------------------------------
-
-terminate(_Reason, _State) ->
-    ok.
-
-code_change(_OldVsn, State, _Extra) ->
-    State.
-
-%%
-%% This is the synchronous initialization function invoked by
-%% gen_server on our server's process, just after it's been spawned
-%% but before it begins its event loop.
-%%
-%% gen_server:start_link will not return until this function finishes,
-%% so we must not wait for the bot to log on before
-%% returning. However, we do want to wait for logon before processing
-%% any outside messages.  To solve this problem, we'll send ourselves
-%% an asynchronous message in order to start the login process.
-%%
-%% The initial state indicates that we're unconnected. This state
-%% will change as soon as we process the asynchronous 'connect' message.
-%%
-
-init({ ConnectInfo, Options }) ->
-    fbot_logger:log(connection_state, started),
-    fbot_server:start([]),
-    ok = gen_server:cast(self(), {connect, ConnectInfo, Options}),
-    {ok, not_connected}.
-
-%%
-%% 'connect' broadcast message.
-%%
-%% This message is only valid in the 'not_connected' state.
-%% It is sent by init(), so it should be the first message we
-%% process. This will synchronously connect and log in.
-%%
-
-handle_cast({connect, ConnectInfo, Options}, not_connected) ->
-    fbot_logger:log(connection_state, connecting),
-    case catch(fbot_socket:connect(ConnectInfo)) of
-	{ok, Sock} ->
-	    fbot_logger:log(connection_state, connected),
-	    {noreply, log_in(Options, #conn_state{sock=Sock})};
-	Error->
-	    fbot_logger:log(connection_state, {failed, Error}),
-	    timer:sleep(?CONNECT_FAIL_DELAY),
-	    exit(Error)
-    end;
-
-%%
-%% Log unhandled broadcast messages
-%%
-
-handle_cast(Cast, State) ->
-    fbot_logger:log(unhandled_cast, Cast),
-    {noreply, State}.
-
-%%
-%% 'send_data' call: Send raw data to our socket.
-%%
-
-handle_call({send_data, Data}, _From, #conn_state{}=State) ->
-    {reply, catch(send_data_local(Data, State)), State};
-
-%%
-%% 'connect_behaviour' call: Change the current behaviour process.
-%%
-
-handle_call({connect_behaviour, Pid}, _From, #conn_state{}=State) ->
-    fbot_logger:log(connect_behaviour, Pid),
-    {reply, ok, State#conn_state{behaviour=Pid}};
-
-%%
-%% 'get_login_messages' call
-%%
-
-handle_call(get_login_messages, _From, #conn_state{login_messages=Messages}=State) ->
-    {reply, Messages, State};
-
-%%
-%% Log unhandled calls
-%%
-
-handle_call(Call, From, State) ->
-    fbot_logger:log(unhandled_call, {Call, From}),
-    {reply, {error, unhandled_call}, State}.
-
-%%
-%% Handle generic Erlang messages: in this case, they should
-%% always be socket messages. Ask fbot_socket to decode them,
-%% then call received_line() to process the incoming data.
-%%
-
-handle_info(M, State) ->
-    case fbot_socket:recv_message(M) of
-	{closed, _Sock} ->
-	    {stop, socket_closed, State};
-	{data, _Sock, Data} ->
-	    received_line(Data, State),
-	    {noreply, State};
-	_ ->
-	    fbot_logger:log(unhandled_info, M),
-	    {noreply, State}
-    end.

erlang/src/fbot_irc_protocol.erl

-%%
-%% fbot_irc_protocol
-%%
-%% Library implementing the IRC protocol, mostly-according to RFC 1459.
-%% This includes message quoting, encoding, and decoding.
-%%
-%% Copyright (C) 2007 Micah Dowty <micah@navi.cx>
-%%
-%%---------------------------------------------------------------------------
-
--module(fbot_irc_protocol).
--include("fbot_irc_protocol.hrl").
-
--export([encode_message/1, decode_message/1]).
-
-
-%%---------------------------------------------------------------------------
-%% IRC Protocol: Low-level quoting
-%%---------------------------------------------------------------------------
-
-%%
-%% Low-level message quoting, as defined by the CTCP spec:
-%%  http://www.irchelp.org/irchelp/rfc/ctcpspec.html
-%%
-
--define(M_QUOTE, 8#020).
--define(SPACE,   32).
-
-%%
-%% Quote a low-level IRC/CTCP message. Operates on deep lists.
-%%
-%% > fbot_irc_conn:low_quote("foo\020\nbar").
-%%   [102,111,111,16,16,16,110,98,97,114]
-%%
-
-low_quote(String) when is_list(String) ->
-    lists:reverse(low_quote(String, [])).
-
-low_quote([H|T], Tail) when is_list(H) ->
-    low_quote(T, low_quote(H, Tail));
-
-low_quote([?M_QUOTE|T], Tail) ->
-    low_quote(T, [?M_QUOTE, ?M_QUOTE|Tail]);
-low_quote([$\0|T], Tail) ->
-    low_quote(T, [$0, ?M_QUOTE|Tail]);
-low_quote([$\n|T], Tail) ->
-    low_quote(T, [$n, ?M_QUOTE|Tail]);
-low_quote([$\r|T], Tail) ->
-    low_quote(T, [$r, ?M_QUOTE|Tail]);
-
-low_quote([H|T], Tail) ->
-    low_quote(T, [H|Tail]);
-low_quote([], Tail) ->
-    Tail.
-
-%%
-%% Dequote a low-level IRC/CTCP message. This is the inverse of
-%% low_quote/1.  Does not operate on deep lists. Strips out
-%% unrecognized escape sequences or partial escape sequences.
-%%
-
-low_dequote(String) when is_list(String) ->
-    lists:reverse(low_dequote(String, [], default)).
-
-low_dequote([?M_QUOTE|T], Tail, default) ->
-    low_dequote(T, Tail, escaped);
-
-low_dequote([?M_QUOTE|T], Tail, escaped) ->    
-    low_dequote(T, [?M_QUOTE|Tail], default);
-low_dequote([$0|T], Tail, escaped) ->    
-    low_dequote(T, [$\0|Tail], default);
-low_dequote([$n|T], Tail, escaped) ->    
-    low_dequote(T, [$\n|Tail], default);
-low_dequote([$r|T], Tail, escaped) ->    
-    low_dequote(T, [$\r|Tail], default);
-
-low_dequote([H|T], Tail, escaped) when is_integer(H) ->
-    %% Ignore unrecognized escape sequence
-    low_dequote(T, Tail, default);
-low_dequote([H|T], Tail, default) when is_integer(H) ->
-    low_dequote(T, [H|Tail], default);
-low_dequote([], Tail, _State) ->
-    Tail.
-
-
-%%---------------------------------------------------------------------------
-%% IRC Protocol: Message codec
-%%---------------------------------------------------------------------------
-
-%%
-%% State machine for quickly parsing a (dequoted) IRC message, as a
-%% string which may include \r and \n termination.
-%%
-%% Returns either {ok, #message} or an error.
-%% Does not accept deep lists.
-%%
-
-decode_message(String) when is_list(String) ->
-    catch(decode_message(default, low_dequote(String),
-			 #message{prefix = [], command = [], params = []})).
-
-%% Finish a parameter (trailing or not) when we encounter end-of-line
-decode_message({params, Cp, _IsTrailing}, [$\n|T], M) ->
-    decode_message(trailing_whitespace, T,
-		   M#message { params = [lists:reverse(Cp)|M#message.params] });
-decode_message({params, Cp, _IsTrailing}, [$\r|T], M) ->
-    decode_message(trailing_whitespace, T,
-		   M#message { params = [lists:reverse(Cp)|M#message.params] });
-
-%% Slurp all extra EOL characters into the 'trailing_whitespace' state
-decode_message(_State, [$\n|T], M) ->
-    decode_message(trailing_whitespace, T, M);
-decode_message(_State, [$\r|T], M) ->
-    decode_message(trailing_whitespace, T, M);
-
-%% Detect the existence of a prefix
-decode_message(default, [$:|T], M) ->
-    decode_message(prefix, T, M);
-decode_message(default, T, M) ->
-    decode_message(command, T, M);
-
-%% Decode the prefix until we hit a SPACE
-decode_message(prefix, [?SPACE|T], M) ->
-    decode_message(command, T, M);
-decode_message(prefix, [H|T], M) ->
-    decode_message(prefix, T, M#message{ prefix = [H|M#message.prefix] });
-
-%% Decode the command until we hit a SPACE. Ignore extra leading spaces.
-decode_message(command, [?SPACE|T], #message{ command = [] }=M) ->
-    decode_message(command, T, M);
-decode_message(command, [?SPACE|T], M) ->
-    decode_message({params, [], false}, T, M);
-decode_message(command, [H|T], M) ->
-    decode_message(command, T, M#message{ command = [H|M#message.command] });
-
-%% Decode parameters. Our state here is a {params, Current, IsTrailing}
-%% tuple, where we keep track of the current parameter and its type.
-%% Trailing parameters begin with a ':', and they may contain spaces.
-
-%% We ignore extra leading whitespace on non-trailing params.
-decode_message({params, [], false}, [?SPACE|T], M) ->
-    decode_message({params, [], false}, T, M);
-
-%% Beginning a trailing parameter?
-decode_message({params, [], false}, [$:|T], M) ->
-    decode_message({params, [], true}, T, M);
-
-%% Finish non-trailing parameters when we encounter a SPACE
-decode_message({params, Cp, false}, [?SPACE|T], M) ->
-    decode_message({params, [], false}, T,
-		   M#message {params = [lists:reverse(Cp)|M#message.params] });
-
-%% Next character in a parameter...
-decode_message({params, Cp, IsTrailing}, [H|T], M) ->
-    decode_message({params, [H|Cp], IsTrailing}, T, M);
-
-%% The one valid end-state: we just finished processing trailing
-%% spaces, and the string is now empty.
-decode_message(trailing_whitespace, [], M) ->
-    {ok, #message{ prefix  = lists:reverse(M#message.prefix),
-		   command = lists:reverse(M#message.command),
-		   params  = lists:reverse(M#message.params) }};
-
-%% Catch-all for bad states.
-decode_message(State, String, _M) ->
-    {bad_message, State, String}.
-
-%%
-%% Encode a message: the inverse of decode_message. Accepts a
-%% #message record, returns a CRLF-terminated deep list.
-%%
-%% Returns either {ok, DeepList} or an error.
-%%
-
-encode_message(Message) ->
-    encode_message(Message, true).
-
-encode_message(#message{}=Message, AllowTrailingParam) ->
-    catch({ok, [ low_quote([ case Message#message.prefix of
-				 [] -> [];
-				 undefined -> [];
-				 Prefix ->
-				     [$:, no_spaces(Prefix), ?SPACE]
-			     end,
-			     no_spaces(Message#message.command),
-			     encode_params(Message#message.params, AllowTrailingParam)
-			    ]),
-		 "\r\n" ]}).
-
-%% Encode a parameter list, optionally supporting "trailing" parameters
-%% which begin with a ':' and may contain whitespace. Each parameter
-%% (including the first!) will begin with ?SPACE.
-encode_params(undefined, _Trailing) ->
-    [];
-encode_params(Params, Trailing) ->
-    lists:reverse(encode_params(Params, Trailing, [])).
-encode_params([H|[]], true, Tail) ->
-    [H, $:, ?SPACE|Tail];
-encode_params([H|T], Trailing, Tail) ->
-    encode_params(T, Trailing, [no_spaces(H), ?SPACE|Tail]);
-encode_params([], _Trailing, Tail) ->
-    Tail.
-
-%% Ensure that a string has no spaces. Returns the
-%% string on success, throws on error.
-no_spaces(String) when is_list(String) ->
-    no_spaces(String, String).
-no_spaces([?SPACE|_], String) ->
-    throw({spaces_not_allowed, String});
-no_spaces([_|T], String) ->
-    no_spaces(T, String);
-no_spaces([], String) ->
-    String.

erlang/src/fbot_irc_protocol.hrl

-%%
-%% fbot_irc_proto Header
-%%
-%% Copyright (C) 2007 Micah Dowty <micah@navi.cx>
-%%
-%%---------------------------------------------------------------------------
-
--record(message, {
-	  prefix,    % String
-	  command,   % String
-	  params     % List of strings
-	  }).

erlang/src/fbot_irc_supervisor.erl

-%%
-%% fbot_irc_supervisor
-%%
-%% This is a supervisor process which manages all processes that belong
-%% to a particular IRC bot. This includes:
-%%
-%%   - fbot_irc_connection, which owns the connection itself
-%%     and handles login
-%%
-%%   - fbot_irc_behaviour, which implements all stateful
-%%     higher-level functionality
-%%
-%% If fbot_irc_conn dies, we've lost the connection so we need to
-%% restart fbot_irc_behaviour in order to re-sync the IRC server with
-%% our desired bot state. If fbot_irc_behaviour dies, it needs to
-%% restart and figure out the server's current state, but the
-%% fbot_irc_conn process keeps on going.
-%%
-%% Thus, we use the 'rest_for_one' restart strategy.
-%%
-%% Copyright (C) 2007 Micah Dowty <micah@navi.cx>
-%%
-%%---------------------------------------------------------------------------
-
--module(fbot_irc_supervisor).
--behaviour(supervisor).
-
-%% Public API
--export([start_link/2, get_child/2]).
-
-%% supervisor callbacks
--export([init/1]).
-
-
-%%---------------------------------------------------------------------------
-%% Public API
-%%---------------------------------------------------------------------------
-
-start_link(ConnectInfo, Options) ->
-    supervisor:start_link(?MODULE, {ConnectInfo, Options}).
-    
-    
-
-%%
-%% Return a child's Pid, or 'undefined'.
-%% The child ID should be 'behaviour' or 'connection'.
-%%
-
-get_child(Pid, ChildId) ->
-    get_child1(supervisor:which_children(Pid), ChildId).
-
-get_child1([], _Id) ->
-    undefined;
-get_child1([{Id, Pid, _Type, _Modules}|_], Id) ->
-    Pid;
-get_child1([_|T], Id) ->
-    get_child1(T, Id).
-
-
-%%---------------------------------------------------------------------------
-%% Callback interface for supervisor
-%%---------------------------------------------------------------------------
-
-init({ConnectInfo, Options}) ->
-    {ok, {
-       %%
-       %% Restart Strategy:
-       %%
-       %% Note that any time the bot loses its connection, it will
-       %% exit. If login fails after LOGIN_TIMEOUT, it will exit.
-       %% If connect() fails, after a timeout or not, we will wait
-       %% CONNECT_FAIL_DELAY and exit.
-       %% 
-       %% Those timeouts combined with the supervisor's restart
-       %% strategy will define our bot's reconnection behaviour.
-       %%
-       %% Please note the amount of time that it takes for a
-       %% connection to time out, when setting the supervisor
-       %% parameters: If CONNECT_FAIL_DELAY is 15000 and
-       %% CONNECT_TIMEOUT is 60000, it would take 750 seconds to
-       %% restart 10 times even if the bot was doing nothing but
-       %% failing to connect and restarting. The parameters must be
-       %% set such to avoid this scenario.
-       %% 
-       { rest_for_one,
-	 10,             %% Max restarts (# of restarts)
-	 60 * 60         %% Max restarts (in X seconds)
-	},
-
-       %% Child processes
-       [
-	{ connection,
-	  {fbot_irc_connection, start_link, [ConnectInfo, Options]},
-	  permanent,     %% Restart mode
-	  5000,          %% Shutdown Timeout
-	  worker,        %% Process type
-	  [gen_server]   %% Modules
-	 },
-	{ behaviour,
-	  {fbot_irc_behaviour, start_link, [self(), Options]},
-	  permanent,     %% Restart mode
-	  5000,          %% Shutdown Timeout
-	  worker,        %% Process type
-	  [gen_server]   %% Modules
-	 }
-       ]
-      }}.

erlang/src/fbot_logger.erl

-%%
-%% fbot_logger
-%%
-%% This is a registered gen_server process which handles log messages
-%% on behalf of all IRC bots.
-%%
-%% Copyright (C) 2007 Micah Dowty <micah@navi.cx>
-%%
-%%---------------------------------------------------------------------------
-
--module(fbot_logger).
--behaviour(gen_server).
-
--export([start_link/0, start/0, log/2]).
--export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]).
-
-
-%%---------------------------------------------------------------------------
-%% Public API
-%%---------------------------------------------------------------------------
-
-start_link() ->
-    gen_server:start_link(?MODULE, undefined, []).
-
-start() ->
-    gen_server:start(?MODULE, undefined, []).
-
-
-%%
-%% Send a log message from the current process.  Should never fail: if
-%% the log server is not running, the message is ignored.
-%%
-
-log(Type, Message) ->
-    gen_server:cast(fbot_logger, {log, self(), Type, Message}).
-
-
-%%---------------------------------------------------------------------------
-%% Callback interface for gen_server
-%%---------------------------------------------------------------------------
-
-terminate(_Reason, _State) ->
-    ok.
-
-code_change(_OldVsn, State, _Extra) ->
-    State.
-
-init(_) ->
-    register(fbot_logger, self()),
-    log(logger, started),
-    {ok, default}.
-
-handle_cast({log, From, Type, Message}, State) ->
-    io:format("[~w ~w] ~p~n", [From, Type, Message]),
-    {noreply, State};
-handle_cast(_, State) ->
-    {noreply, State}.
-
-handle_call(_, _From, State) ->
-    {noreply, State}.
-
-handle_info(_, State) ->
-    {noreply, State}.

erlang/src/fbot_server.erl

-% Copyright 2008 by Benoît Chesneau <benoitc@e-engura.com>
-% 
-% Licensed under the Apache License, Version 2.0 (the "License");
-% you may not use this file except in compliance with the License.
-% You may obtain a copy of the License at
-%
-%     http://www.apache.org/licenses/LICENSE-2.0
-%
-% Unless required by applicable law or agreed to in writing, software
-% distributed under the License is distributed on an "AS IS" BASIS,
-% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-% See the License for the specific language governing permissions and
-% limitations under the License.
-
--module(fbot_server).
--include("fbot_irc_protocol.hrl").qq
--author('benoitc@e-engura.com').
-
--behaviour(gen_server).
-
--export([start/1, stop/0, start_link/1]).
--export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3,
-         handle_info/2]).
--export([acceptor_loop/1]).
-
--define(IDLE_TIMEOUT, 30000).
-
--record(fbot_socket_server,
-        {port=9000,
-         ip=any,
-         max=2048,
-         listen=null,
-         acceptor=null}).
-
-
-         
-start(State=#fbot_socket_server{}) ->
-    start_server(State);
-start(Options) ->
-    start(parse_options(Options)).
-    
-stop() ->
-    gen_server:cast(?MODULE, stop).
-    
-parse_options(Options) ->
-    parse_options(Options, #fbot_socket_server{}).
-        
-parse_options([], State) ->
-    State;
-parse_options([{port, L} | Rest], State) when is_list(L) ->
-    Port = list_to_integer(L),
-    parse_options(Rest, State#fbot_socket_server{port=Port});
-parse_options([{port, Port} | Rest], State) ->
-    parse_options(Rest, State#fbot_socket_server{port=Port});
-parse_options([{ip, Ip} | Rest], State) ->
-    ParsedIp = case Ip of
-                   any ->
-                       any;
-                   Ip when is_tuple(Ip) ->
-                       Ip;
-                   Ip when is_list(Ip) ->
-                       {ok, IpTuple} = inet_parse:address(Ip),
-                       IpTuple
-               end,
-    parse_options(Rest, State#fbot_socket_server{ip=ParsedIp});
-parse_options([{max, Max} | Rest], State) ->
-    MaxInt = case Max of
-                 Max when is_list(Max) ->
-                     list_to_integer(Max);
-                 Max when is_integer(Max) ->
-                     Max
-             end,
-    parse_options(Rest, State#fbot_socket_server{max=MaxInt}).
-    
-ipv6_supported() ->
-    case (catch inet:getaddr("localhost", inet6)) of
-        {ok, _Addr} ->
-            true;
-        {error, _} ->
-            false
-    end.
-
-start_link(Options) ->
-    ?MODULE:start(Options).
-
-start_server(State=#fbot_socket_server{}) ->
-    gen_server:start_link({local, ?MODULE}, ?MODULE, State, []).
-    
-init(State=#fbot_socket_server{port=Port, ip=Ip}) ->
-    process_flag(trap_exit, true),
-    BaseOpts = [binary, 
-            {packet, 0},
-            {reuseaddr, true},
-            {active, false},
-            {nodelay, true}
-    ],
-    Opts = case Ip of
-        any ->
-            case ipv6_supported() of % IPv4, and IPv6 if supported
-                true -> [inet, inet6 | BaseOpts];
-                _ -> BaseOpts
-            end;
-        {_, _, _, _} -> % IPv4
-            [inet, {ip, Ip} | BaseOpts];
-        {_, _, _, _, _, _, _, _} -> % IPv6
-            [inet6, {ip, Ip} | BaseOpts]
-    end,
-    case gen_tcp_listen(Port, Opts, State) of
-        {stop, eacces} ->
-            case Port < 1024 of 
-                true ->
-                    case fdsrv:start() of
-                        {ok, _} ->
-                            case fdsrv:bind_socket(tcp, Port) of
-                                {ok, Fd} ->
-                                    gen_tcp_listen(Port, [{fd, Fd} | Opts], State);
-                                _ ->
-                                    {stop, fdsrv_bind_failed}
-                            end;
-                        _ ->
-                            {stop, fdsrv_start_failed}
-                    end;
-                false ->
-                    {stop, eacces}
-            end;
-        Other ->
-            Other
-    end.
-    
-gen_tcp_listen(Port, Opts, State) ->
-    case gen_tcp:listen(Port, Opts) of
-        {ok, Listen} ->
-            {ok, ListenPort} = inet:port(Listen),
-            {ok, new_acceptor(State#fbot_socket_server{listen=Listen, 
-                                                         port=ListenPort})};
-        {error, Reason} ->
-            {stop, Reason}
-    end.
-
-new_acceptor(State=#fbot_socket_server{max=0}) ->
-    io:format("Not accepting new connections~n"),
-    State#fbot_socket_server{acceptor=null};
-new_acceptor(State=#fbot_socket_server{listen=Listen}) ->
-    Pid = proc_lib:spawn_link(?MODULE, acceptor_loop,
-                              [{self(), Listen}]),
-    State#fbot_socket_server{acceptor=Pid}.
-
-
-acceptor_loop({Server, Listen}) ->
-    case catch gen_tcp:accept(Listen) of
-        {ok, Socket} ->
-            gen_server:cast(Server, {accepted, self()}),
-            %inet:setopts(Socket, [{packet, http}]),
-            loop(Socket);
-        {error, closed} ->
-            exit({error, closed});
-        Other ->
-            io:format("fuck~n"),
-            exit({error, accept_failed})
-    end.
-   
-loop(Socket) ->
-    case gen_tcp:recv(Socket, 0, ?IDLE_TIMEOUT) of
-        {ok, Data} ->
-            io:format("[~w] Received: ~s", [Socket, Data]),
-            handle_line(Socket, string:tokens(binary_to_list(Data), " ")),
-            inet:setopts(Socket, [{packet, 0}]),
-            loop(Socket);
-        {error, closed} ->
-            gen_tcp:close(Socket),
-            exit(stopped)
-    end.
-
-handle_line(Socket, ["PASTE", PasteUrl, Username|_]) ->
-    io:format("Paste: ~s", [PasteUrl]);
-handle_line(Socket, ["MSG"|Msg]) ->
-    Message = lists:concat(Msg),
-    io:format("Message: ~s", [Message]);
-handle_line(Socket, ["JOIN", Channel_]) ->
-    io:format("Join: ~s", [Channel]);
-handle_line(_,_) ->
-    ok.
-
-handle_call(_Message, _From, State) ->
-    Res = error,
-    {reply, Res, State}.
-
-handle_cast({accepted, Pid},
-            State=#fbot_socket_server{acceptor=Pid, max=Max}) ->
-    %io:format("accepted ~p~n", [Pid]),
-    State1 = State#fbot_socket_server{max=Max - 1},
-    {noreply, new_acceptor(State1)};
-handle_cast(stop, State) ->
-    {stop, normal, State}.
-
-
-handle_info({'EXIT', Pid, normal},
-            State=#fbot_socket_server{acceptor=Pid}) ->
-    % io:format("normal acceptor down~n"),
-    {noreply, new_acceptor(State)};
-handle_info({'EXIT', Pid, Reason},
-            State=#fbot_socket_server{acceptor=Pid}) ->
-    timer:sleep(100),
-    {noreply, new_acceptor(State)};
-handle_info({'EXIT', _LoopPid, Reason},
-            State=#fbot_socket_server{acceptor=Pid, max=Max}) ->
-    State1 = State#fbot_socket_server{max=Max + 1},
-    State2 = case Pid of
-                 null ->
-                     new_acceptor(State1);
-                 _ ->
-                     State1
-             end,
-    {noreply, State2};
-handle_info(_Info, State) -> {noreply, State}.
-
-terminate(_Reason, #fbot_socket_server{listen=Listen, port=Port}) -> 
-   gen_tcp:close(Listen),
-   case Port < 1024 of 
-       true ->
-           catch fdsrv:stop(),
-           ok;
-       false ->
-           ok
-   end.
-
-code_change(_OldVsn, State, Extra) -> {ok, State}.

erlang/src/fbot_socket.erl

-%%
-%% fbot_socket
-%%
-%% This is a library for generic socket operations. Using a
-%% type-specific "connection spec", you can open a socket that can
-%% then be used in identical ways regardless of how that socket is
-%% implemented.
-%%
-%% This module gives us transparent support for protocols like SSL and IPv6.
-%%
-%% Copyright (C) 2007 Micah Dowty <micah@navi.cx>
-%%
-%%---------------------------------------------------------------------------
-
--module(fbot_socket).
-
--export([connect/1, connect/3, send/2, recv_message/1, recv_blocking/0]).
-
--define(CONNECT_TIMEOUT, 60000).
--define(RECV_TIMEOUT,    60000).
-
-start_inet_db()->
-    case inet_db:start() of
-        {ok, _} ->
-            ok;
-        {error, {already_started, _}} ->
-            ok;
-        Error ->
-            throw(Error)
-    end.
-
-start_ssl() ->
-    case ssl:start() of
-        ok ->
-            ok;
-        {ok, _} ->
-            ok;
-        {error, {already_started,_}} ->
-            ok;
-        Error ->
-            throw(Error)
-    end.
-
-%%
-%% Connect with default options and timeout
-%%
-connect(ConnectSpec) ->
-    connect(ConnectSpec,
-	    [list,
-	     {packet, line},
-	     {nodelay, true}],
-	    ?CONNECT_TIMEOUT).
-
-connect({ tcp, Host, Port }, Options, Timeout) ->
-    start_inet_db(),
-    case gen_tcp:connect(Host, Port,
-			 Options ++ [inet,
-				     {packet_size, 1024},
-				     {recbuf, 16384},
-				     {sndbuf, 16384}],
-			 Timeout) of
-	{ok, Sock} ->
-	    {ok, {tcp, Sock}};
-	Error ->
-	    Error
-    end;
-
-connect({ ssl, Host, Port }, Options, Timeout) ->
-    start_inet_db(),
-    start_ssl(),
-    case ssl:connect(Host, Port, Options, Timeout) of
-	{ok, Sock} ->
-	    {ok, {ssl, Sock}};
-	Error ->
-	    Error
-    end.
-
-
-send({ tcp, Sock }, Data) ->
-    gen_tcp:send(Sock, Data);
-
-send({ ssl, Sock }, Data) ->
-    ssl:send(Sock, Data).
-
-%%
-%% Handle an incoming message.
-%%
-%%  - If the message does not represent received socket
-%%    data, returns 'undefined'.
-%%
-%%  - If data was received, returns a {recv, Sock, Data} tuple.
-%%
-%%  - If a connection was closed, returns {closed, Sock}.
-%%
-
-recv_message({tcp_closed, Sock}) ->
-    {closed, {tcp, Sock}};
-
-recv_message({tcp, Sock, Data}) ->
-    {data, {tcp, Sock}, Data};
-
-recv_message({ssl_closed, Sock}) ->
-    {closed, {ssl, Sock}};
-
-recv_message({ssl, Sock, Data}) ->
-    {data, {ssl, Sock}, Data};
-
-recv_message(_) ->
-    undefined.
-
-%%
-%% Blocking receive for an incoming message.
-%% Return values are the same as recv_messge(), with
-%% the addition of a 'timeout' atom.
-%%
-%% NB: We list each message type separately here in order
-%%     to avoid dequeueing messages we don't want to process.
-%%
-
-recv_blocking() ->
-    receive
-	{'EXIT', _Parent, Reason} -> exit(Reason);
-	{tcp_closed, _}=M -> recv_message(M);
-	{tcp, _, _}=M -> recv_message(M);
-	{ssl_closed, _}=M -> recv_message(M);
-	{ssl, _, _}=M -> recv_message(M)
-    after ?RECV_TIMEOUT -> timeout
-    end.
-	    
-

erlang/src/test.erl

--module(test).
--export([main/0]).
-
-main() ->
-    catch(fbot_logger:start()),
-    {ok, Sup} = fbot_irc_supervisor:start_link({tcp, "irc.freenode.net", 6667}, [ {nick, "fpaste"}, {password, "as61zx" } ]),
-    register(fbot_sup, Sup).

friendpaste/__init__.py

-# -*- coding: utf-8 -*-
-# Copyright 2008 by Benoît Chesneau <benoitc@e-engura.com>
-# 
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from friendpaste.application import Friendpaste
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.