summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt6
-rw-r--r--src/core/CMakeLists.txt5
-rw-r--r--src/core/ephraim.erl62
-rw-r--r--src/core/ephraim_conn.erl45
-rw-r--r--src/core/ephraim_conv.erl23
-rw-r--r--src/gui/CMakeLists.txt13
-rw-r--r--src/gui/CoreConnector.vala73
-rw-r--r--src/gui/Ephraim.vala27
-rw-r--r--src/gui/ephraim.glade200
9 files changed, 454 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..859b25d
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_definitions(${GTK_CFLAGS} ${GTK_CFLAGS_OTHER} ${ERL_CFLAGS} ${ERL_CFLAGS_OTHER})
+link_libraries(${GTK_LIBRARIES} ${ERL_LIBRARIES})
+link_directories(${GTK_LIBRARY_DIRS} ${ERL_LIBRARY_DIRS})
+
+add_subdirectory(core ${ephraim_BINARY_DIR}/core)
+add_subdirectory(gui ${ephraim_BINARY_DIR}/gui)
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
new file mode 100644
index 0000000..470e686
--- /dev/null
+++ b/src/core/CMakeLists.txt
@@ -0,0 +1,5 @@
+erl_target(ephraim-core
+ ephraim.erl
+ ephraim_conn.erl
+ ephraim_conv.erl
+)
diff --git a/src/core/ephraim.erl b/src/core/ephraim.erl
new file mode 100644
index 0000000..6a68de0
--- /dev/null
+++ b/src/core/ephraim.erl
@@ -0,0 +1,62 @@
+-module(ephraim).
+-compile([debug_info, export_all]).
+
+-record(state, {
+ conn :: pid(),
+ convs :: dict(),
+ guis :: set()
+ }).
+
+-spec start() -> ok.
+start() ->
+ Pid = spawn(?MODULE, init, []),
+ case register(ephraim, Pid) of
+ true ->
+ ok
+ end.
+
+-spec stop() -> ok.
+stop() ->
+ ephraim ! stop,
+ ok.
+
+-spec init() -> ok.
+init() ->
+ Conn = spawn(ephraim_conn, init, []),
+ loop(#state{conn=Conn,convs=dict:new(),guis=sets:new()}).
+
+-spec get_conv(#state{},exmpp_jid:jid()) -> {#state{},pid()}.
+get_conv(State, JID) ->
+ Key = exmpp_jid:to_lower(exmpp_jid:bare(JID)),
+ case dict:find(Key, State#state.convs) of
+ {ok, Conv} ->
+ {State, Conv};
+ error ->
+ Conv = spawn(ephraim_conv, init, [Key]),
+ Dict = dict:store(Key, Conv, State#state.convs),
+ {State#state{convs=Dict}, Conv}
+ end.
+
+-spec loop(#state{}) -> ok.
+loop(State) ->
+ receive
+ stop ->
+ dict:fold(fun(_,Conv,Msg) -> Conv ! Msg end, stop, State#state.convs),
+ State#state.conn ! stop,
+ ok;
+ {register_gui, Pid} ->
+ GUIs = State#state.guis,
+ State2 = State#state{guis=sets:add_element(Pid,GUIs)},
+ loop(State2);
+ {unregister_gui, Pid} ->
+ GUIs = State#state.guis,
+ State2 = State#state{guis=sets:del_element(Pid,GUIs)},
+ loop(State2);
+ {receive_message, From, Packet} ->
+ {State2, Conv} = get_conv(State, From),
+ Conv ! {receive_message, Packet},
+ loop(State2);
+ Msg ->
+ io:format("ephraim: ~p~n", [Msg]),
+ loop(State)
+ end.
diff --git a/src/core/ephraim_conn.erl b/src/core/ephraim_conn.erl
new file mode 100644
index 0000000..18edd6a
--- /dev/null
+++ b/src/core/ephraim_conn.erl
@@ -0,0 +1,45 @@
+-module(ephraim_conn).
+-include_lib("exmpp/include/exmpp_client.hrl").
+-compile([debug_info, export_all]).
+
+-record(conn_state, {
+ session :: any(),
+ roster :: any()
+ }).
+
+-spec init() -> ok.
+init() ->
+ application:start(exmpp),
+ Session = exmpp_session:start(),
+ JID = exmpp_jid:make("ephraim-test", "jabber.ccc.de", "Bar"),
+ exmpp_session:auth_basic_digest(Session, JID, "foobarbla"),
+ exmpp_session:connect_TCP(Session, "jabber.ccc.de", 5222),
+ session(#conn_state{session=Session}).
+
+-spec session(#conn_state{}) -> ok.
+session(State) ->
+ exmpp_session:login(State#conn_state.session),
+ exmpp_session:send_packet(State#conn_state.session, exmpp_presence:set_status(exmpp_presence:available(), "Foo/Test\\Bar")),
+ loop(State).
+
+-spec loop(#conn_state{}) -> ok.
+loop(State) ->
+ receive
+ stop ->
+ exmpp_session:stop(State#conn_state.session);
+
+ #received_packet{packet_type=presence, raw_packet=Packet} ->
+ From = exmpp_xml:get_attribute(Packet, from, <<"unknown">>),
+ Type = atom_to_list(exmpp_presence:get_type(Packet)),
+ Status = exmpp_presence:get_status(Packet),
+ io:format("~ts is now ~ts: ~ts~n", [From, Type, Status]),
+ loop(State);
+
+ #received_packet{packet_type=message, raw_packet=Packet} ->
+ From = exmpp_xml:get_attribute(Packet, from, <<"unknown">>),
+ ephraim ! {receive_message, From, Packet},
+ loop(State);
+ Msg ->
+ io:format("ephraim_conn: ~p~n", [Msg]),
+ loop(State)
+ end.
diff --git a/src/core/ephraim_conv.erl b/src/core/ephraim_conv.erl
new file mode 100644
index 0000000..99c7668
--- /dev/null
+++ b/src/core/ephraim_conv.erl
@@ -0,0 +1,23 @@
+-module(ephraim_conv).
+-compile([debug_info, export_all]).
+
+-record(conv_state, {
+ jid :: exmpp_jid:jid()
+ }).
+
+-spec init(exmpp_jid:jid()) -> ok.
+init(JID) ->
+ loop(#conv_state{jid=JID}).
+
+-spec loop(#conv_state{}) -> ok.
+loop(State) ->
+ receive
+ stop ->
+ ok;
+ {receive_message, Packet} ->
+ io:format("Received packet from ~p: ~p~n", [State#conv_state.jid, Packet]),
+ loop(State);
+ Msg ->
+ io:format("ephraim_conv (~p): ~p~n", [State#conv_state.jid, Msg]),
+ loop(State)
+ end.
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
new file mode 100644
index 0000000..8839e16
--- /dev/null
+++ b/src/gui/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${ephraim_BINARY_DIR})
+
+vala_precompile(VALA_C
+ "Ephraim.vala"
+ "CoreConnector.vala"
+PACKAGES
+ gtk+-2.0
+ erl_interface
+OPTIONS
+ --thread
+)
+
+add_executable("ephraim-gtk" ${VALA_C})
diff --git a/src/gui/CoreConnector.vala b/src/gui/CoreConnector.vala
new file mode 100644
index 0000000..08ed43f
--- /dev/null
+++ b/src/gui/CoreConnector.vala
@@ -0,0 +1,73 @@
+public class CoreConnector {
+ unowned Thread thread;
+ bool running;
+
+ private class TermStore {
+ public Erl.Term term;
+ }
+
+ static construct {
+ Erl.init();
+ }
+
+ public CoreConnector() {
+ running = false;
+ }
+
+ public bool start() {
+ if(running)
+ return true;
+
+ running = true;
+
+ try {
+ thread = Thread.create(receive, true);
+ return true;
+ } catch(ThreadError e) {
+ return false;
+ }
+ }
+
+ public void stop() {
+ if(!running)
+ return;
+
+ running = false;
+ thread.join();
+ }
+
+ private void* receive() {
+ Erl.Node node = Erl.Node("ephraim-gtk", "magiccookie", 0);
+ Erl.Connection con = node.connect("ephraim-core@avalon.local");
+
+ con.reg_send("ephraim", Erl.mk_self_pid(node));
+
+ while(running) {
+ TermStore response = new TermStore();
+ Erl.ReceiveType ret = con.receive(out response.term, 1000);
+
+ switch(ret) {
+ case Erl.ReceiveType.ERROR:
+ if(Erl.errno == Erl.Error.TIMEDOUT)
+ break;
+
+ running = false;
+ break;
+ case Erl.ReceiveType.TICK:
+ // Do nothing
+ break;
+ case Erl.ReceiveType.MSG:
+ Idle.add(() => {handleTerm(response); return false;});
+ break;
+ }
+ }
+
+ return null;
+ }
+
+ private void handleTerm(TermStore store) {
+ unowned Erl.Term term = store.term;
+ Erl.print_term(stdout, term);
+ stdout.printf("\n");
+ }
+}
diff --git a/src/gui/Ephraim.vala b/src/gui/Ephraim.vala
new file mode 100644
index 0000000..a52c4df
--- /dev/null
+++ b/src/gui/Ephraim.vala
@@ -0,0 +1,27 @@
+public class Ephraim {
+ public static int main(string[] args) {
+ Gtk.init(ref args);
+
+ Gtk.Builder builder = new Gtk.Builder();
+ try {
+ builder.add_from_file("ephraim.glade");
+ } catch(Error e) {
+ return 1;
+ }
+
+ CoreConnector coreconn = new CoreConnector();
+
+ if(!coreconn.start())
+ return 1;
+
+ unowned Gtk.Window window = builder.get_object("MainWindow") as Gtk.Window;
+ window.hide.connect(Gtk.main_quit);
+ window.show();
+
+ Gtk.main();
+
+ coreconn.stop();
+
+ return 0;
+ }
+}
diff --git a/src/gui/ephraim.glade b/src/gui/ephraim.glade
new file mode 100644
index 0000000..b1b3455
--- /dev/null
+++ b/src/gui/ephraim.glade
@@ -0,0 +1,200 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkWindow" id="MainWindow">
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuItem" id="menuitem1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Datei</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem1">
+ <property name="label">gtk-new</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem2">
+ <property name="label">gtk-open</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem3">
+ <property name="label">gtk-save</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem4">
+ <property name="label">gtk-save-as</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="separatormenuitem1">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem5">
+ <property name="label">gtk-quit</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Bearbeiten</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu2">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem6">
+ <property name="label">gtk-cut</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem7">
+ <property name="label">gtk-copy</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem8">
+ <property name="label">gtk-paste</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem9">
+ <property name="label">gtk-delete</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Ansicht</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Hilfe</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu3">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem10">
+ <property name="label">gtk-about</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHPaned" id="RosterPane">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkTreeView" id="Roster">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">RosterStore</property>
+ </object>
+ <packing>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkNotebook" id="Conversations">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="scrollable">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkListStore" id="RosterStore"/>
+</interface>