public class CoreConnector { 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_conversation; static Eva.Term match_conversation_new; static Eva.Term match_conversation_message; static construct { 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_conversation = Eva.parse("{account,Account,{conversation,JID,Message}}"); match_conversation_new = Eva.parse("new"); 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 void start() { con = new Eva.PacketHandler(new UnixInputStream(3, true), new UnixOutputStream(4, true), 4); con.received_term.connect(handle_term); con.start(); } public void stop() { con.send(new Eva.Atom("stop")); } private static string from_utf8(Eva.Binary bin) { if(bin.len == 0) return ""; string ret = ((string)bin.data).ndup(bin.len); warn_if_fail(ret.validate()); return ret; } private void handle_term(Eva.Term term) { Gee.Map match; if((match = term.match(match_init_view)) != null) { Eva.Cons terms = match["Terms"] as Eva.Cons; while(terms != null) { Eva.Tuple tuple = terms.head as Eva.Tuple; if(tuple != null && tuple.size > 0) { Eva.Atom key = tuple[0] as Eva.Atom; /*if(key != null) { switch(key.value) { // None yet } }*/ } terms = terms.tail as Eva.Cons; } } else if((match = term.match(match_roster_update)) != null) { Eva.Binary jid_term = match["JID"] as Eva.Binary; if(jid_term == null) { warn_if_reached(); return; } string jid = from_utf8(jid_term); Eva.Binary name_term = match["Name"] as Eva.Binary; string? name; if (name_term != null) name = from_utf8(name_term); else name = null; Contact contact = new Contact(jid, name); Eva.Atom subscription = match["Subscription"] as Eva.Atom; if(subscription != null) { switch(subscription.value) { case "none": contact.subscription = Contact.Subscription.NONE; break; case "to": contact.subscription = Contact.Subscription.TO; break; case "from": contact.subscription = Contact.Subscription.FROM; break; case "both": contact.subscription = Contact.Subscription.BOTH; break; default: stderr.printf("Unknown subscription: %s\r\n", subscription.value); break; } } Eva.Cons groups = match["Groups"] as Eva.Cons; while(groups != null) { Eva.Binary group_term = groups.head as Eva.Binary; if(group_term != null) { string group = from_utf8(group_term); contact.add_group(group); } groups = groups.tail as Eva.Cons; } Eva.Cons resources = match["Resources"] as Eva.Cons; while(resources != null) { Gee.Map r; if((r = resources.head.match(match_resource_entry)) != null) { Eva.Binary rname_term = r["Name"] as Eva.Binary; Eva.Numeric prio_term = r["Priority"] as Eva.Numeric; Eva.Atom show_term = r["Show"] as Eva.Atom; Eva.Binary status_term = r["Status"] as Eva.Binary; if(rname_term != null && prio_term != null && show_term != null) { string rname = from_utf8(rname_term); int prio = prio_term.int_value; Contact.Show show = Contact.Show.UNDEFINED; switch(show_term.value) { case "online": show = Contact.Show.ONLINE; break; case "away": show = Contact.Show.AWAY; break; case "chat": show = Contact.Show.CHAT; break; case "dnd": show = Contact.Show.DND; break; case "xa": show = Contact.Show.XA; break; } string? status = null; if(status_term != null) { status = from_utf8(status_term); if(status == "") status = null; } contact.update_resource(rname, new Contact.Resource(prio, show, status)); } } resources = resources.tail as Eva.Cons; } Gee.Map avatar = match["Avatar"].match(match_avatar); if(avatar != null) { Eva.Binary avatarData = avatar["Data"] as Eva.Binary; if(avatarData != null) { InputStream avatarStream = new MemoryInputStream.from_data(avatarData.data, avatarData.len, null); try { contact.avatar = new Gdk.Pixbuf.from_stream_at_scale(avatarStream, 32, 32, true, null); avatarStream.close(null); } catch(Error e) { warn_if_reached(); } } } update_contact(contact); } else if((match = term.match(match_conversation)) != null) { Eva.Binary jid_term = match["JID"] as Eva.Binary; if(jid_term == null) { warn_if_reached(); return; } string jid = from_utf8(jid_term); Eva.Term message_term = match["Message"]; if(message_term == null) { warn_if_reached(); return; } Gee.Map cmatch; if((cmatch = message_term.match(match_conversation_new)) != null) { new_conversation(jid); } 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.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 = cmatch["Body"] as Eva.Binary; if(body_term == null) { warn_if_reached(); return; } string body = from_utf8(body_term); chat_message(jid, 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()); } } public void start_conversation(string jid) { char[] jid_utf8 = jid.to_utf8(); con.send(Eva.parse("{account,foo_account,{conversation,~w,new}}", new Eva.Binary(jid_utf8))); } public void send_message(string jid, string type, string message) { char[] jid_utf8 = jid.to_utf8(); char[] message_utf8 = message.to_utf8(); con.send(Eva.parse("{account,foo_account,{conversation,~w,{send_message,~a,~w}}}", new Eva.Binary(jid_utf8), type, new Eva.Binary(message_utf8))); } }