Author: bdonlan
Date: 2005-12-09 16:42:22 -0500 (Fri, 09 Dec 2005)
New Revision: 946

Added:
   trunk/erlang/server/haver_protocol.erl
   trunk/erlang/server/haver_worker.erl
   trunk/erlang/server/schema.hrl
Removed:
   trunk/erlang/server/line_encode.erl
Modified:
   trunk/erlang/server/server.erl
Log:
Split up the client worker and master server; add BYE and QUIT

Copied: trunk/erlang/server/haver_protocol.erl (from rev 944, 
trunk/erlang/server/line_encode.erl)
===================================================================
--- trunk/erlang/server/line_encode.erl 2005-12-09 20:34:01 UTC (rev 944)
+++ trunk/erlang/server/haver_protocol.erl      2005-12-09 21:42:22 UTC (rev 
946)
@@ -0,0 +1,32 @@
+-module(haver_protocol).
+-export([decode/1, encode/1]).
+
+escape([]) -> [];
+escape([$\t|T]) -> [$\e, $t | escape(T)];
+escape([$\n|T]) -> [$\e, $n | escape(T)];
+escape([$\r|T]) -> [$\e, $r | escape(T)];
+escape([$\e|T]) -> [$\e, $e | escape(T)];
+escape([H|T])    -> [H | escape(T)].
+
+unescape([]) -> [];
+unescape([$\e, $t | T]) -> [$\t | unescape(T)];
+unescape([$\e, $e | T]) -> [$\e | unescape(T)];
+unescape([$\e, $r | T]) -> [$\r | unescape(T)];
+unescape([$\e, $n | T]) -> [$\n | unescape(T)];
+unescape([H|T])           -> [H | unescape(T)].
+
+decode([]) -> [];
+decode(L)  ->
+    { Pre, Post } = lists:splitwith(fun(C) -> C =/= $\t end, L),
+    Word = unescape(Pre),
+    case Post of
+        [] -> [Word];
+        [_|L2]  ->
+            ArgsAfter = decode(L2),
+            [Word|ArgsAfter]
+    end.
+
+encode_([]) -> [];
+encode_([H|T]) -> lists:append(H, [$\t|encode_(T)]).
+
+encode(L) -> encode_(lists:map(fun(W) -> escape(W) end, L)).

Added: trunk/erlang/server/haver_worker.erl
===================================================================
--- trunk/erlang/server/haver_worker.erl        2005-12-09 20:52:40 UTC (rev 
945)
+++ trunk/erlang/server/haver_worker.erl        2005-12-09 21:42:22 UTC (rev 
946)
@@ -0,0 +1,252 @@
+-module(haver_worker).
+-export([entry/2]).
+-include_lib("mnemosyne/include/mnemosyne.hrl").
+-include("schema.hrl").
+
+haver_sendline(Line) ->
+    Socket = get(socket),
+    gen_tcp:send(Socket, haver_protocol:encode(Line)),
+    gen_tcp:send(Socket, "\r\n").
+
+entry(Parent, Socket) ->
+    link(Parent),
+    put(socket, Socket),
+    receive
+        { line, [ "HAVER", Vers | _ ] } ->
+            haver_sendline(["HAVER", "localhost", "Erver/0.0"]),
+            haver_login();
+        { line, _ } ->
+            gen_tcp:close(Socket),
+            exit(rude_peer);
+        Foo -> io:format("haver_entry unknown msg ~p~n", [Foo])
+    end.
+
+handle_ident(Uid) ->
+    F = fun() ->
+        Q = query
+            [ E || E <- table(users), E.name = Uid ]
+            end,
+        R = mnemosyne:eval(Q),
+        io:format("~p~n", [R]),
+        case R of
+            [] -> mnesia:write(#users{name = Uid, pid = self()}),
+                  ok;
+            _  -> collision
+        end
+    end,
+    R = mnesia:transaction(F),
+    case R of
+        { atomic, ok } ->
+            haver_sendline(["HELLO", Uid]),
+            put(uid, Uid),
+            haver_mainloop();
+        { atomic, collision } ->
+            haver_sendline(["FAIL", "IDENT", "exists.user", Uid]),
+            haver_login();
+        Wtf -> io:format("wtf: ~p~n", [Wtf])
+    end.
+
+haver_login() ->
+    receive
+        { line, [ "IDENT", Uid ] } -> handle_ident(Uid);
+        { line, _ } ->
+            haver_sendline(["DIE", "ihateyou"]),
+            gen_tcp:close(get(socket)),
+            exit(rudepeer);
+        M -> exit({unexpected, M})
+    end.    
+
+find_user(Uid) ->
+    T = fun() ->
+        Q = query
+            [ U.pid || U <- table(users), U.name = Uid ]
+            end,
+        mnemosyne:eval(Q)
+        end,
+    R = mnesia:transaction(T),
+    case R of
+        { atomic, [Pid] } -> Pid;
+        { atomic, []    } -> notfound;
+        { atomic, Wtf } ->
+            io:format("find_user wtf: ~p~n", [Wtf]),
+            notfound;
+        _ ->
+            io:format("find_user err: ~p~n", [R]),
+            notfound
+        end.
+
+haver_open(Channel) ->
+    T = fun() ->
+        Q = query
+            [ C || C <- table(channels), C.name = Channel ]
+            end,
+        R = mnemosyne:eval(Q),
+        case R of
+            [] -> mnesia:write(#channels{name = Channel, notused = Channel}),
+                  ok;
+            _  -> collision
+        end end,
+    R = mnesia:transaction(T),
+    case R of
+        { atomic, Result } -> Result
+    end.
+
+chan_broadcast(Channel, Message) ->
+    T = fun() ->
+        Q = query
+            [ U.pid
+            || U <- table(users),
+               J <- table(chanjoin),
+               U.name = J.user,
+               J.channel = Channel
+            ] end,
+        mnemosyne:eval(Q)
+        end,
+    R = mnesia:transaction(T),
+    case R of
+        { atomic, L } -> lists:map(fun(P) -> P ! Message end, L);
+        _ -> io:format("err, bad mnesia txn response ~p~n", [R]),
+             exit({mnesia_fail, R})
+    end.
+
+haver_join(Channel) ->
+    Uid = get(uid),
+    T = fun() ->
+        case mnesia:read({channels, Channel}) of
+            [] -> mnesia:abort(notfound);
+            _  -> ok
+        end,
+        Q = query
+            [ J || J <- table(chanjoin), J.user = Uid, J.channel = Channel ]
+            end,
+        case mnemosyne:eval(Q) of
+            [_]->
+                mnesia:abort(already_joined);
+            [] ->
+                mnesia:write(#chanjoin{channel = Channel, user = Uid}),
+                ok
+        end end,
+    R = mnesia:transaction(T),
+    case R of
+        { aborted, already_joined } -> collision;
+        { aborted, notfound } -> notfound;
+        { atomic, ok } ->
+            chan_broadcast(Channel, { sendline, [ "JOIN", Channel, Uid ] }),
+            ok
+    end.
+
+haver_part(Channel) ->
+    Uid = get(uid),
+    T = fun() ->
+        Q = query
+            [ J || J <- table(chanjoin), J.user = Uid, J.channel = Channel ]
+            end,
+        case mnemosyne:eval(Q) of
+            [] -> notfound;
+            [R]->
+                io:format("R=~p~n", [R]),
+                mnesia:delete_object(R), ok
+        end end,
+    R = mnesia:transaction(T),
+    case R of
+        { atomic, notfound } -> notfound;
+        { atomic, ok } -> 
+            chan_broadcast(Channel, { sendline, [ "PART", Channel, Uid ] }),
+            ok
+    end.
+
+haver_getlist("&lobby", "channel") -> { ok, mnesia:dirty_all_keys(channels) };
+haver_getlist("&lobby", "user")   -> { ok, mnesia:dirty_all_keys(users) };
+haver_getlist(Channel, "user")    ->
+    T = fun() ->
+        case mnesia:read({channels, Channel}) of
+            [] -> mnesia:abort(notfound);
+            _  -> ok
+        end,
+        Records = mnesia:read({chanjoin, Channel}),
+        Uids = lists:map(fun({chanjoin, _, Uid}) -> Uid end, Records),
+        { ok, Uids }
+    end,
+    case mnesia:transaction(T) of
+        { aborted, notfound } -> notfound;
+        { atomic, {ok, Uids} } -> { ok, Uids };
+        Other ->
+            io:format("getlist(~p~n, \"user\") unexpected: ~p~n", [Channel, 
Other]),
+            exit(Other)    
+    end;
+haver_getlist(_, "channel") -> { ok, [] };
+haver_getlist(_, Type) -> {badtype, Type}.
+
+haver_list(C, T) ->
+    R = haver_getlist(C, T),
+    case R of
+        { ok, Members } -> haver_sendline(["LIST", C, T | Members ]);
+        notfound -> haver_sendline(["FAIL", "LIST", "unknown.channel", C]);
+        badtype  -> haver_sendline(["FAIL", "LIST", "unknown.type", C])
+    end.
+
+haver_sendchan(Channel, Message) ->
+    Uid = get(uid),
+    T = fun() ->    
+        Q = query
+            [ J || J <- table(chanjoin),
+                   J.user = Uid,
+                   J.channel = Channel
+            ] end,
+        case mnemosyne:eval(Q) of
+            [] -> notjoined;
+            _  -> ok
+        end end,
+    R = mnesia:transaction(T),
+    case R of
+        { atomic, notjoined } ->
+            haver_sendline(["FAIL", "IN", "not.joined", Channel]);
+        { atomic, ok } ->
+            chan_broadcast(Channel, { sendline, ["IN", Channel, Uid | Message] 
})
+    end.
+
+haver_mainloop() -> 
+    V = receive
+        { line, [ "OPEN", Channel ] } ->
+            case haver_open(Channel) of
+                ok -> haver_sendline(["OPEN", Channel]);
+                collision -> haver_sendline(["FAIL", "OPEN", "exists.channel", 
Channel])
+            end, ok;
+        { line, [ "JOIN", Channel ] } ->
+            case haver_join(Channel) of
+                ok -> ok;
+                notfound -> haver_sendline(["FAIL", "JOIN", "unknown.channel", 
Channel]);
+                collision -> haver_sendline(["FAIL", "JOIN", "already.joined", 
Channel])
+            end, ok;
+        { line, [ "PART", Channel ] } ->
+            case haver_part(Channel) of
+                ok -> haver_sendline(["PART", Channel, get(uid)]);
+                notfound -> haver_sendline(["FAIL", "PART", "not.joined", 
Channel])
+            end, ok;
+        { line, [ "TO", Uid | Message ] } ->
+            Pid = find_user(Uid),
+            case Pid of
+                notfound -> haver_sendline(["FAIL", "TO", "unknown.user", 
Uid]);
+                _        -> Pid ! { privmsg, get(uid), Message }
+            end, ok;
+        { line, [ "IN", Channel | Message ] } ->
+            haver_sendchan(Channel, Message);
+        { line, [ "LIST", Channel, Type ] } -> haver_list(Channel, Type), ok;
+        { line, [ "POKE" | L ] } -> haver_sendline(["OUCH" | L]);
+        { line, [ "BYE", Detail ] } ->
+            haver_sendline(["BYE", Detail]),
+            gen_tcp:close(get(socket)),
+            exit({ quit, "bye", Detail});
+        { line, [ L | T ] } ->
+            io:format("unmatched line: ~p~n", [L|T]),
+            haver_sendline(["FAIL", L, "unknown.cmd"]),
+            ok;
+        { line, L } ->
+            exit({err_line, L});
+        { sendline, L } -> haver_sendline(L), ok;
+        { privmsg, From, Message } ->
+            haver_sendline(["FROM", From | Message]),
+            ok;
+        Other -> io:format("unknown msg: ~p~n", Other), exit(Other)
+        end,
+    haver_mainloop().

Deleted: trunk/erlang/server/line_encode.erl
===================================================================
--- trunk/erlang/server/line_encode.erl 2005-12-09 20:52:40 UTC (rev 945)
+++ trunk/erlang/server/line_encode.erl 2005-12-09 21:42:22 UTC (rev 946)
@@ -1,29 +0,0 @@
--module(line_encode).
--export([decode/1, encode/1]).
-
-escape([]) -> [];
-escape([$\t|T]) -> [$\e, $t | escape(T)];
-escape([$\n|T]) -> [$\e, $n | escape(T)];
-escape([$\r|T]) -> [$\e, $r | escape(T)];
-escape([$\e|T]) -> [$\e, $e | escape(T)];
-escape([H|T])    -> [H | escape(T)].
-
-unescape([]) -> [];
-unescape([$\e, $t | T]) -> [$\t | unescape(T)];
-unescape([$\e, $e | T]) -> [$\e | unescape(T)];
-unescape([$\e, $r | T]) -> [$\r | unescape(T)];
-unescape([$\e, $n | T]) -> [$\n | unescape(T)];
-unescape([H|T])           -> [H | unescape(T)].
-
-decode([]) -> [];
-decode(L)  ->
-    { Pre, Post } = lists:splitwith(fun(C) -> C =/= $\t end, L),
-    case Post of
-        [] -> [Pre];
-        [_|L2]  ->
-            ArgsAfter = decode(L2),
-            [Pre|ArgsAfter]
-    end.
-
-encode([]) -> [];
-encode([H|T]) -> lists:append(H, [$\t|encode(T)]).

Added: trunk/erlang/server/schema.hrl
===================================================================
--- trunk/erlang/server/schema.hrl      2005-12-09 20:52:40 UTC (rev 945)
+++ trunk/erlang/server/schema.hrl      2005-12-09 21:42:22 UTC (rev 946)
@@ -0,0 +1,4 @@
+-record(users, {name,
+                pid}).
+-record(channels, {name, notused}).
+-record(chanjoin, {channel, user}).

Modified: trunk/erlang/server/server.erl
===================================================================
--- trunk/erlang/server/server.erl      2005-12-09 20:52:40 UTC (rev 945)
+++ trunk/erlang/server/server.erl      2005-12-09 21:42:22 UTC (rev 946)
@@ -1,14 +1,11 @@
 -module(server).
--export([cstart/1, start/1, stop/0, worker/2, haver_entry/2, setup_schema/0,
+-export([cstart/1, start/1, stop/0, worker/2, setup_schema/0,
          clear_transients/0]).
+-import(haver_worker, []).
+-import(haver_protocol, [encode/1, decode/1]).
 -include_lib("mnemosyne/include/mnemosyne.hrl").
+-include("schema.hrl").
 
--record(users, {name,
-                pid}).
--record(channels, {name, notused}).
--record(chanjoin, {channel, user}).
-
-
 setup_schema() ->
     mnesia:delete_table(users),
     mnesia:create_table(users, [
@@ -41,7 +38,11 @@
     spawn_loop(LSock).
     
 init_tables() ->
-    mnesia:wait_for_tables([users, chanjoin, channels], 5 * 1000).
+    io:format("Waiting for table init...", []),
+    case mnesia:wait_for_tables([users, chanjoin, channels], 5 * 1000) of
+        ok -> io:format("Table init done.~n", []), ok;
+        R  -> io:format("Table init failed: ~p~n", [R]), R
+    end.
 
 start(Port) ->
     case whereis(haver) of
@@ -58,7 +59,14 @@
     end.
 stop() -> haver ! shutdown.
 
-reap_child(Pid) ->
+match_reason({quit, Type, Detail}) -> {Type, Detail};
+match_reason({socket_closed, _}) -> {"closed", ""};
+match_reason(R) ->
+    io:format("Unknown quit-reason: ~p~n", [R]),
+    { "error", io_lib:format("~w", [R]) }.
+
+reap_child(Pid, Reason) ->
+    {Type, Detail} = match_reason(Reason),
     F = fun() ->
         Q = query
             [ E || E <- table(users), E.pid = Pid ]
@@ -66,24 +74,33 @@
         R = mnemosyne:eval(Q),
         case R of
             [ E ] ->
+                mnesia:delete_object(E),
                 Name = E#users.name,
+                SQ = query
+                    [ U.pid || J <- table(chanjoin), J.user = Name,
+                               J2 <- table(chanjoin), J.channel = J2.channel,
+                               U <- table(users), U.name = J2.user
+                    ] end,
+                SR = mnemosyne:eval(SQ),
+                io:format("SR=~p~n", [SR]),
                 Q2 = query
                      [ J || J <- table(chanjoin), J.user = Name ]
                      end,
                 R2 = mnemosyne:eval(Q2),
                 lists:map(fun(J) -> mnesia:delete_object(J) end, R2),
-                mnesia:delete_object(E),
-                ok;
-            _ -> ok
+                { ok, Name, SR };
+            _ -> { nouser }
         end end,
     R = mnesia:transaction(F),
     case R of
-        { atomic, ok } -> { ok };
+        { atomic, { ok, Name, L } } ->
+            lists:map(fun(P) -> P ! { sendline, [ "QUIT", Name, Type, Detail ] 
} end, L),
+            { ok };
+        { atomic, { nouser } } -> { ok };
         _ -> io:format("Warning: reap failed for pid ~p~n: ~p~n", [Pid,R]),
              { nok, R }
     end.
         
-
 spawn_loop(LSock) ->
     process_flag(trap_exit, true),
     receive
@@ -93,7 +110,7 @@
         shutdown -> ok;
         { 'EXIT', Pid, Reason } ->
             io:format("Child ~p~n died with ~p~n", [Pid, Reason]),
-            reap_child(Pid),
+            reap_child(Pid, Reason),
             spawn_loop(LSock);
         Other ->
             io:format("Unknown message: ~p~n", Other)
@@ -105,7 +122,7 @@
         {ok, Socket} ->
             Parent ! next_worker,
             peer_entry(Parent, Socket),
-            reap_child(self()),
+            reap_child(self(), returned),
             gen_tcp:close(Socket);
         {error, Reason} ->
             Parent ! next_worker,
@@ -113,7 +130,7 @@
     end.
 
 peer_entry(Parent, Socket) ->
-    Pid = spawn_link(?MODULE, haver_entry, [Parent, Socket]),
+    Pid = spawn_link(haver_worker, entry, [Parent, Socket]),
     peer(Socket, "", Pid).
 
 peer(Socket, Buf, Pid) ->
@@ -133,253 +150,8 @@
     case lists:splitwith(fun(C) -> not ((C == $\r) or (C == $\n)) end, Buf) of
         { _, [] } -> Buf;
         { L, Rem} ->
-            Pid ! {line, line_encode:decode(L) },
+            Pid ! {line, haver_protocol:decode(L) },
             Rem2 = lists:dropwhile(fun(C) -> ((C == $\r) or (C == $\n)) end, 
Rem),
             Rem2
     end.
 
-haver_sendline(Line) ->
-    Socket = get(socket),
-    gen_tcp:send(Socket, line_encode:encode(Line)),
-    gen_tcp:send(Socket, "\r\n").
-
-haver_entry(Parent, Socket) ->
-    link(Parent),
-    put(socket, Socket),
-    receive
-        { line, [ "HAVER", Vers | _ ] } ->
-            haver_sendline(["HAVER", "localhost", "Erver/0.0"]),
-            haver_login();
-        { line, _ } ->
-            gen_tcp:close(Socket),
-            exit(rude_peer);
-        Foo -> io:format("haver_entry unknown msg ~p~n", [Foo])
-    end.
-
-handle_ident(Uid) ->
-    F = fun() ->
-        Q = query
-            [ E || E <- table(users), E.name = Uid ]
-            end,
-        R = mnemosyne:eval(Q),
-        io:format("~p~n", [R]),
-        case R of
-            [] -> mnesia:write(#users{name = Uid, pid = self()}),
-                  ok;
-            _  -> collision
-        end
-    end,
-    R = mnesia:transaction(F),
-    case R of
-        { atomic, ok } ->
-            haver_sendline(["HELLO", Uid]),
-            put(uid, Uid),
-            haver_mainloop();
-        { atomic, collision } ->
-            haver_sendline(["FAIL", "IDENT", "exists.user", Uid]),
-            haver_login();
-        Wtf -> io:format("wtf: ~p~n", [Wtf])
-    end.
-
-haver_login() ->
-    receive
-        { line, [ "IDENT", Uid ] } -> handle_ident(Uid);
-        { line, _ } ->
-            haver_sendline(["DIE", "ihateyou"]),
-            gen_tcp:close(get(socket)),
-            exit(rudepeer);
-        M -> exit({unexpected, M})
-    end.    
-
-find_user(Uid) ->
-    T = fun() ->
-        Q = query
-            [ U.pid || U <- table(users), U.name = Uid ]
-            end,
-        mnemosyne:eval(Q)
-        end,
-    R = mnesia:transaction(T),
-    case R of
-        { atomic, [Pid] } -> Pid;
-        { atomic, []    } -> notfound;
-        { atomic, Wtf } ->
-            io:format("find_user wtf: ~p~n", [Wtf]),
-            notfound;
-        _ ->
-            io:format("find_user err: ~p~n", [R]),
-            notfound
-        end.
-
-haver_open(Channel) ->
-    T = fun() ->
-        Q = query
-            [ C || C <- table(channels), C.name = Channel ]
-            end,
-        R = mnemosyne:eval(Q),
-        case R of
-            [] -> mnesia:write(#channels{name = Channel, notused = Channel}),
-                  ok;
-            _  -> collision
-        end end,
-    R = mnesia:transaction(T),
-    case R of
-        { atomic, Result } -> Result
-    end.
-
-chan_broadcast(Channel, Message) ->
-    T = fun() ->
-        Q = query
-            [ U.pid
-            || U <- table(users),
-               J <- table(chanjoin),
-               U.name = J.user,
-               J.channel = Channel
-            ] end,
-        mnemosyne:eval(Q)
-        end,
-    R = mnesia:transaction(T),
-    case R of
-        { atomic, L } -> lists:map(fun(P) -> P ! Message end, L);
-        _ -> io:format("err, bad mnesia txn response ~p~n", [R]),
-             exit({mnesia_fail, R})
-    end.
-
-haver_join(Channel) ->
-    Uid = get(uid),
-    T = fun() ->
-        case mnesia:read({channels, Channel}) of
-            [] -> mnesia:abort(notfound);
-            _  -> ok
-        end,
-        Q = query
-            [ J || J <- table(chanjoin), J.user = Uid, J.channel = Channel ]
-            end,
-        case mnemosyne:eval(Q) of
-            [_]->
-                mnesia:abort(already_joined);
-            [] ->
-                mnesia:write(#chanjoin{channel = Channel, user = Uid}),
-                ok
-        end end,
-    R = mnesia:transaction(T),
-    case R of
-        { aborted, already_joined } -> collision;
-        { aborted, notfound } -> notfound;
-        { atomic, ok } ->
-            chan_broadcast(Channel, { sendline, [ "JOIN", Channel, Uid ] }),
-            ok
-    end.
-
-haver_part(Channel) ->
-    Uid = get(uid),
-    T = fun() ->
-        Q = query
-            [ J || J <- table(chanjoin), J.user = Uid, J.channel = Channel ]
-            end,
-        case mnemosyne:eval(Q) of
-            [] -> notfound;
-            [R]->
-                io:format("R=~p~n", [R]),
-                mnesia:delete_object(R), ok
-        end end,
-    R = mnesia:transaction(T),
-    case R of
-        { atomic, notfound } -> notfound;
-        { atomic, ok } -> 
-            chan_broadcast(Channel, { sendline, [ "PART", Channel, Uid ] }),
-            ok
-    end.
-
-haver_getlist("&lobby", "channel") -> { ok, mnesia:dirty_all_keys(channels) };
-haver_getlist("&lobby", "user")   -> { ok, mnesia:dirty_all_keys(users) };
-haver_getlist(Channel, "user")    ->
-    T = fun() ->
-        case mnesia:read({channels, Channel}) of
-            [] -> mnesia:abort(notfound);
-            _  -> ok
-        end,
-        Records = mnesia:read({chanjoin, Channel}),
-        Uids = lists:map(fun({chanjoin, _, Uid}) -> Uid end, Records),
-        { ok, Uids }
-    end,
-    case mnesia:transaction(T) of
-        { aborted, notfound } -> notfound;
-        { atomic, {ok, Uids} } -> { ok, Uids };
-        Other ->
-            io:format("getlist(~p~n, \"user\") unexpected: ~p~n", [Channel, 
Other]),
-            exit(Other)    
-    end;
-haver_getlist(_, "channel") -> { ok, [] };
-haver_getlist(_, Type) -> {badtype, Type}.
-
-haver_list(C, T) ->
-    R = haver_getlist(C, T),
-    case R of
-        { ok, Members } -> haver_sendline(["LIST", C, T | Members ]);
-        notfound -> haver_sendline(["FAIL", "LIST", "unknown.channel", C]);
-        badtype  -> haver_sendline(["FAIL", "LIST", "unknown.type", C])
-    end.
-
-haver_sendchan(Channel, Message) ->
-    Uid = get(uid),
-    T = fun() ->    
-        Q = query
-            [ J || J <- table(chanjoin),
-                   J.user = Uid,
-                   J.channel = Channel
-            ] end,
-        case mnemosyne:eval(Q) of
-            [] -> notjoined;
-            _  -> ok
-        end end,
-    R = mnesia:transaction(T),
-    case R of
-        { atomic, notjoined } ->
-            haver_sendline(["FAIL", "IN", "not.joined", Channel]);
-        { atomic, ok } ->
-            chan_broadcast(Channel, { sendline, ["IN", Channel, Uid | Message] 
})
-    end.
-
-haver_mainloop() -> 
-    V = receive
-        { line, [ "OPEN", Channel ] } ->
-            case haver_open(Channel) of
-                ok -> haver_sendline(["OPEN", Channel]);
-                collision -> haver_sendline(["FAIL", "OPEN", "exists.channel", 
Channel])
-            end, ok;
-        { line, [ "JOIN", Channel ] } ->
-            case haver_join(Channel) of
-                ok -> ok;
-                notfound -> haver_sendline(["FAIL", "JOIN", "unknown.channel", 
Channel]);
-                collision -> haver_sendline(["FAIL", "JOIN", "already.joined", 
Channel])
-            end, ok;
-        { line, [ "PART", Channel ] } ->
-            case haver_part(Channel) of
-                ok -> haver_sendline(["PART", Channel, get(uid)]);
-                notfound -> haver_sendline(["FAIL", "PART", "not.joined", 
Channel])
-            end, ok;
-        { line, [ "TO", Uid | Message ] } ->
-            Pid = find_user(Uid),
-            case Pid of
-                notfound -> haver_sendline(["FAIL", "TO", "unknown.user", 
Uid]);
-                _        -> Pid ! { privmsg, get(uid), Message }
-            end, ok;
-        { line, [ "IN", Channel | Message ] } ->
-            haver_sendchan(Channel, Message);
-        { line, [ "LIST", Channel, Type ] } -> haver_list(Channel, Type), ok;
-        { line, [ "POKE" | L ] } -> haver_sendline(["OUCH" | L]);
-        { line, ["DIE"]} ->
-            [] = [1]; % XXX
-        { line, [ L | T ] } ->
-            io:format("unmatched line: ~p~n", [L|T]),
-            haver_sendline(["FAIL", L, "unknown.cmd"]),
-            ok;
-        { line, L } ->
-            exit({err_line, L});
-        { sendline, L } -> haver_sendline(L), ok;
-        { privmsg, From, Message } ->
-            haver_sendline(["FROM", From | Message]),
-            ok;
-        Other -> io:format("unknown msg: ~p~n", Other), ok
-        end,
-    haver_mainloop().


Reply via email to