summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/ephraim_account.erl2
-rw-r--r--src/core/ephraim_conn.erl2
-rw-r--r--src/core/ephraim_conv.erl51
-rw-r--r--src/core/ephraim_conv_handler.erl71
-rw-r--r--src/core/ephraim_conv_man.erl12
-rw-r--r--src/core/ephraim_gui.erl2
-rw-r--r--src/core/ephraim_roster.erl2
-rw-r--r--src/gui/Conversation.vala2
-rw-r--r--src/gui/CoreConnector.vala90
-rw-r--r--src/gui/Ephraim.vala22
11 files changed, 194 insertions, 64 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 9baaeee..97c7d4e 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -6,6 +6,8 @@ erl_target(ephraim-core
ephraim_config.erl
ephraim_conn.erl
ephraim_conv.erl
+ ephraim_conv_handler.erl
+ ephraim_conv_man.erl
ephraim_gui.erl
ephraim_roster.erl
ephraim_roster_handler.erl
diff --git a/src/core/ephraim_account.erl b/src/core/ephraim_account.erl
index d79e118..8024d68 100644
--- a/src/core/ephraim_account.erl
+++ b/src/core/ephraim_account.erl
@@ -9,6 +9,8 @@ start_link() ->
{ok, EventManager} = supervisor:start_child(Pid, {event_man, {gen_event, start_link, []}, permanent, 1000, worker, [gen_event]}),
ephraim_account_event_proxy:start(EventManager),
+ {ok, _} = supervisor:start_child(Pid, {conv_man, {ephraim_conv_man, start_link, [EventManager]}, permanent, 1000, supervisor, [ephraim_conv_man]}),
+
{ok, Connection} = supervisor:start_child(Pid, {connection, {ephraim_conn, start_link, [EventManager]}, permanent, 10000, worker, [ephraim_conn]}),
{ok, _} = supervisor:start_child(Pid, {roster, {ephraim_roster, start_link, [EventManager, Connection]}, permanent, 1000, worker, [ephraim_roster]}),
{ok, Pid}.
diff --git a/src/core/ephraim_conn.erl b/src/core/ephraim_conn.erl
index f4e14e0..fa9344d 100644
--- a/src/core/ephraim_conn.erl
+++ b/src/core/ephraim_conn.erl
@@ -37,8 +37,6 @@ session(Session) ->
exmpp_session:login(Session),
io:format("Getting profile...~n"),
exmpp_session:send_packet(Session, exmpp_iq:get('jabber:client', #xmlel{ns='vcard-temp',name='vCard'})),
- io:format("Getting roster...~n"),
- exmpp_session:send_packet(Session, exmpp_client_roster:get_roster("foo")),
io:format("Setting presence...~n"),
exmpp_session:send_packet(Session, exmpp_presence:set_status(exmpp_presence:available(), "Foo/Test\\Bar")),
io:format("Ok.~n").
diff --git a/src/core/ephraim_conv.erl b/src/core/ephraim_conv.erl
index 3342bc9..d9431b2 100644
--- a/src/core/ephraim_conv.erl
+++ b/src/core/ephraim_conv.erl
@@ -1,18 +1,51 @@
-module(ephraim_conv).
--compile([debug_info, export_all]).
+-behaviour(gen_server).
+
+-export([start_link/2]).
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+-export([received_message/4]).
-record(conv_state, {
- my_jid :: binary(),
- jid :: binary()
+ conv_ref :: reference(),
+ event_manager :: pid(),
+ my_jid :: binary(),
+ jid :: binary()
}).
--spec init(binary()) -> ok.
-init(JID) ->
- io:format("Starting a conversation with ~p~n", [JID]),
-
+-spec start_link(pid(), binary()) -> ok.
+start_link(EventManager, JID) ->
+ ConvRef = make_ref(),
+ io:format("Starting conversation ~p with ~p~n", [ConvRef, JID]),
+
+ gen_event:notify(EventManager, {view_update, {conversation, ConvRef, {new, JID}}}),
+
{jid,MyJID} = ephraim_config:get(jid),
- loop(#conv_state{my_jid=list_to_binary(MyJID),jid=JID}),
- io:format("Stopping a conversation with ~p~n", [JID]).
+ gen_server:start_link(?MODULE, #conv_state{conv_ref=ConvRef,event_manager=EventManager,my_jid=list_to_binary(MyJID),jid=JID}, []).
+
+init(State) ->
+ process_flag(trap_exit, true),
+ {ok, State}.
+
+received_message(Conv, From, Type, Body) ->
+ gen_server:cast(Conv, {received_message, From, Type, Body}).
+
+handle_call(_Msg, _From, State) ->
+ {noreply, State}.
+
+handle_cast({received_message, From, Type, Body}, State) ->
+ gen_event:notify(State#conv_state.event_manager, {view_update, {conversation, State#conv_state.conv_ref, {message, From, Type, Body}}}),
+ {noreply, State};
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info(_Msg, State) ->
+ {ok, State}.
+terminate(_Reason, State) ->
+ io:format("Stopping conversation ~p with ~p~n", [State#conv_state.conv_ref, State#conv_state.jid]),
+ ok.
+code_change(_OldVersion, State, _Extra) ->
+ {ok, State}.
+
-spec loop(#conv_state{}) -> ok.
loop(State) ->
diff --git a/src/core/ephraim_conv_handler.erl b/src/core/ephraim_conv_handler.erl
new file mode 100644
index 0000000..e525d99
--- /dev/null
+++ b/src/core/ephraim_conv_handler.erl
@@ -0,0 +1,71 @@
+-module(ephraim_conv_handler).
+-include_lib("exmpp/include/exmpp_client.hrl").
+-behaviour(gen_event).
+-export([start/2]).
+-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]).
+
+-record(conv_handler_state, {
+ supervisor :: pid(),
+ event_manager :: pid(),
+ convs = dict:new() :: dict()
+ }).
+
+start(Supervisor, EventManager) ->
+ gen_event:add_handler(EventManager, ?MODULE, {Supervisor, EventManager}).
+
+init({Supervisor, EventManager}) ->
+ State = #conv_handler_state{supervisor=Supervisor,event_manager=EventManager},
+ {ok, State}.
+
+-spec get_conv(#conv_handler_state{},exmpp_jid:jid()) -> {#conv_handler_state{},pid()|undefined}.
+get_conv(State, JID) ->
+ {Node, Domain, Resource} = exmpp_jid:to_lower(exmpp_jid:parse(JID)),
+
+ case Resource of
+ undefined ->
+ {State, undefined};
+ _ ->
+ Key = list_to_binary([Node, <<"@">>, Domain, <<"/">>, Resource]),
+
+ case dict:find(Key, State#conv_handler_state.convs) of
+ {ok, Conv} ->
+ {State, Conv};
+ error ->
+ {ok, Conv} = supervisor:start_child(State#conv_handler_state.supervisor,
+ {Key, {ephraim_conv, start_link, [State#conv_handler_state.event_manager, JID]}, transient, 1000, worker, [ephraim_conv]}),
+ Dict = dict:store(Key, Conv, State#conv_handler_state.convs),
+ {State#conv_handler_state{convs=Dict}, Conv}
+ end
+ end.
+
+handle_event({received_packet, #received_packet{packet_type=message, raw_packet=Packet}}, State) ->
+ From = exmpp_xml:get_attribute(Packet, from, <<"unknown">>),
+ Type = exmpp_message:get_type(Packet),
+ Body = exmpp_message:get_body(Packet),
+ NewState = if
+ Body =/= undefined ->
+ {State2, Conv} = get_conv(State, From),
+ if
+ Conv =/= undefined ->
+ ephraim_conv:received_message(Conv, From, Type, Body);
+ true ->
+ ok
+ end,
+ State2;
+ true ->
+ io:format("Received strange message from ~p:~n~p~n", [From, Packet]),
+ State
+ end,
+ {ok, NewState};
+
+handle_event(_Event, State) ->
+ {ok, State}.
+
+handle_call(_Msg, State) ->
+ {noreply, State}.
+handle_info(_Msg, State) ->
+ {ok, State}.
+terminate(_Reason, _State) ->
+ ok.
+code_change(_OldVersion, State, _Extra) ->
+ {ok, State}.
diff --git a/src/core/ephraim_conv_man.erl b/src/core/ephraim_conv_man.erl
new file mode 100644
index 0000000..617ccc4
--- /dev/null
+++ b/src/core/ephraim_conv_man.erl
@@ -0,0 +1,12 @@
+-module(ephraim_conv_man).
+-behaviour(supervisor).
+-export([start_link/1]).
+-export([init/1]).
+
+start_link(EventManager) ->
+ {ok, Pid} = supervisor:start_link(?MODULE, []),
+ ephraim_conv_handler:start(Pid, EventManager),
+ {ok, Pid}.
+
+init(_Args) ->
+ {ok, {{one_for_one, 0, 1}, []}}.
diff --git a/src/core/ephraim_gui.erl b/src/core/ephraim_gui.erl
index 92ab521..7bf4b74 100644
--- a/src/core/ephraim_gui.erl
+++ b/src/core/ephraim_gui.erl
@@ -30,7 +30,7 @@ handle_info({Port, {data, Data}}, Port) ->
init:stop(),
remove_handler;
_ ->
- ephraim:notify({view_event, Msg}),
+ ephraim:notify({view_request, Msg}),
{ok, Port}
end;
diff --git a/src/core/ephraim_roster.erl b/src/core/ephraim_roster.erl
index f111f38..605d019 100644
--- a/src/core/ephraim_roster.erl
+++ b/src/core/ephraim_roster.erl
@@ -40,6 +40,8 @@ init({EventManager, Connection}) ->
process_flag(trap_exit, true),
ephraim_roster_handler:start(EventManager, self()),
+ io:format("Getting roster...~n"),
+ ephraim_conn:send_packet(Connection, exmpp_client_roster:get_roster("foo")),
{ok, #roster_state{event_manager=EventManager,connection=Connection,entries=dict:new()}}.
-spec updateResource(#roster_state{}, binary(), integer(), atom(), atom(), binary()) -> #roster_state{}.
diff --git a/src/gui/Conversation.vala b/src/gui/Conversation.vala
index 7c8dc03..926ed3d 100644
--- a/src/gui/Conversation.vala
+++ b/src/gui/Conversation.vala
@@ -62,7 +62,7 @@ public class Conversation {
conversations.remove(widget);
}
- public void chat_message(string type, string from, string message) {
+ public void chat_message(string from, string type, string message) {
if(type != "chat")
return;
diff --git a/src/gui/CoreConnector.vala b/src/gui/CoreConnector.vala
index 4c853ff..46c94f2 100644
--- a/src/gui/CoreConnector.vala
+++ b/src/gui/CoreConnector.vala
@@ -1,25 +1,27 @@
public class CoreConnector {
- static Eva.Term match_gui_init;
+ static Eva.Term match_init_view;
static Eva.Term match_roster_update;
static Eva.Term match_resource_entry;
static Eva.Term match_avatar;
- static Eva.Term match_new_conversation;
- static Eva.Term match_chat_message;
+ static Eva.Term match_conversation;
+ static Eva.Term match_conversation_new;
+ static Eva.Term match_conversation_message;
static construct {
- match_gui_init = Eva.parse("{global,{gui_init,Terms}}");
+ match_init_view = Eva.parse("{global,{init_view,Terms}}");
match_roster_update = Eva.parse("{account,Account,{roster_update,JID,Name,Subscription,Groups,Resources,Avatar}}");
match_resource_entry = Eva.parse("{Name,{resource_entry,Priority,Show,Status}}");
match_avatar = Eva.parse("{avatar,Data}");
- match_new_conversation = Eva.parse("{new_conversation,JID}");
- match_chat_message = Eva.parse("{chat_message,JID,Type,From,Body}");
+ match_conversation = Eva.parse("{account,Account,{conversation,Ref,Message}}");
+ match_conversation_new = Eva.parse("{new,JID}");
+ match_conversation_message = Eva.parse("{message,From,Type,Body}");
}
Eva.PacketHandler con;
public signal void update_contact(Contact contact);
- public signal void new_conversation(string jid);
- public signal void chat_message(string jid, string from, string type, string message);
+ public signal void new_conversation(Eva.Ref conv_ref, string jid);
+ public signal void chat_message(Eva.Ref conv_ref, string from, string type, string message);
public void start() {
con = new Eva.PacketHandler(new UnixInputStream(3, true), new UnixOutputStream(4, true), 4);
@@ -43,7 +45,7 @@ public class CoreConnector {
private void handle_term(Eva.Term term) {
Gee.Map<string, Eva.Term> match;
- if((match = term.match(match_gui_init)) != null) {
+ if((match = term.match(match_init_view)) != null) {
Eva.Cons terms = match["Terms"] as Eva.Cons;
while(terms != null) {
@@ -175,46 +177,56 @@ public class CoreConnector {
}
update_contact(contact);
}
- else if((match = term.match(match_new_conversation)) != null) {
- Eva.Binary jid_term = match["JID"] as Eva.Binary;
- if(jid_term == null) {
+ else if((match = term.match(match_conversation)) != null) {
+ Eva.Ref conv_ref = match["Ref"] as Eva.Ref;
+ if(conv_ref == null) {
warn_if_reached();
return;
}
- string jid = from_utf8(jid_term);
-
- new_conversation(jid);
- }
- else if((match = term.match(match_chat_message)) != null) {
- Eva.Binary jid_term = match["JID"] as Eva.Binary;
- if(jid_term == null) {
+ Eva.Term message_term = match["Message"];
+ if(message_term == null) {
warn_if_reached();
return;
}
- string jid = from_utf8(jid_term);
-
- Eva.Atom type_term = match["Type"] as Eva.Atom;
- if(type_term == null) {
- warn_if_reached();
- return;
+
+ Gee.Map<string, Eva.Term> cmatch;
+ if((cmatch = message_term.match(match_conversation_new)) != null) {
+ Eva.Binary jid_term = cmatch["JID"] as Eva.Binary;
+ if(jid_term == null) {
+ warn_if_reached();
+ return;
+ }
+
+ string jid = from_utf8(jid_term);
+ new_conversation(conv_ref, jid);
}
- string type = type_term.value;
+ else if((cmatch = message_term.match(match_conversation_message)) != null) {
+ Eva.Binary from_term = cmatch["From"] as Eva.Binary;
+ if(from_term == null) {
+ warn_if_reached();
+ return;
+ }
+ string from = from_utf8(from_term);
- Eva.Binary from_term = match["From"] as Eva.Binary;
- if(from_term == null) {
- warn_if_reached();
- return;
- }
- string from = from_utf8(from_term);
+ Eva.Atom type_term = cmatch["Type"] as Eva.Atom;
+ if(type_term == null) {
+ warn_if_reached();
+ return;
+ }
+ string type = type_term.value;
- Eva.Binary body_term = match["Body"] as Eva.Binary;
- if(body_term == null) {
- warn_if_reached();
- return;
- }
- string body = from_utf8(body_term);
+ Eva.Binary body_term = cmatch["Body"] as Eva.Binary;
+ if(body_term == null) {
+ warn_if_reached();
+ return;
+ }
+ string body = from_utf8(body_term);
- chat_message(jid, type, from, body);
+ chat_message(conv_ref, from, type, body);
+ }
+ else {
+ stdout.printf("Received unhandled term: %s\n", term.to_string());
+ }
}
else {
stdout.printf("Received unhandled term: %s\n", term.to_string());
diff --git a/src/gui/Ephraim.vala b/src/gui/Ephraim.vala
index 5801966..fb5e77f 100644
--- a/src/gui/Ephraim.vala
+++ b/src/gui/Ephraim.vala
@@ -17,7 +17,7 @@ public class Ephraim {
unowned Gtk.TreeView rosterView = builder.get_object("Roster") as Gtk.TreeView;
- Gee.TreeMap<string, Conversation> conversations = new Gee.TreeMap<string, Conversation>();
+ Gee.TreeMap<Eva.Ref, Conversation> conversations = new Gee.TreeMap<Eva.Ref, Conversation>();
unowned Gtk.Notebook conversationNotebook = builder.get_object("Conversations") as Gtk.Notebook;
ContactList roster = new ContactList(rosterView);
@@ -28,24 +28,22 @@ public class Ephraim {
coreconn.update_contact.connect(roster.update_contact);
- coreconn.new_conversation.connect((jid) => {
+ coreconn.new_conversation.connect((conv_ref, jid) => {
Contact contact = roster.get_contact(jid);
- if(contact != null) {
- conversations[jid] = new Conversation(conversationNotebook, jid, contact.display_string);
- }
- else {
- conversations[jid] = new Conversation(conversationNotebook, jid, null);
- }
+ Conversation conv = new Conversation(conversationNotebook, jid, contact != null ? contact.display_string : null);
- conversations[jid].send_message.connect((type, message) => coreconn.send_message(jid, type, message));
+ conversations[conv_ref] = conv;
+ conv.send_message.connect((type, message) => coreconn.send_message(jid, type, message));
});
- coreconn.chat_message.connect((jid, type, from, message) => {
- if(!(jid in conversations.keys))
+ coreconn.chat_message.connect((conv_ref, from, type, message) => {
+ if(!(conv_ref in conversations.keys)) {
+ warn_if_reached();
return;
+ }
- conversations[jid].chat_message(type, from, message);
+ conversations[conv_ref].chat_message(from, type, message);
});
//if(!coreconn.start())