123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- using Gtk;
- using GLib;
- enum LinkType {
- GOPHE,
- HYPER,
- }
- class Engine : Object {
- Window main_window;
- Entry url_entry;
- TextView text_view;
- Spinner spinner;
- List<string> history;
- List<string> future;
- Regex gopher_url_regex;
- Regex gopher_line_regex;
- public Engine (Window main_window, Entry url_entry, TextView text_view, Spinner spinner) {
- this.main_window = main_window;
- this.url_entry = url_entry;
- this.text_view = text_view;
- this.spinner = spinner;
- history = new List<string> ();
- future = new List<string> ();
-
- fix_cursor ();
- gopher_url_regex = /^(gopher:\/\/)?(?<host>[^\/:]*)(:(?<port>[0-9]+))?(\/((?<gophertype>.))(?<selector>.*))?\/?$/;
- gopher_line_regex = /(?<gopher_type>.)(?<text>[^\t]*)(\t(?<selector>[^\t]*))?(\t(?<host>[^\t]*))?(\t(?<port>[^\t]*))?/;
-
- if(url_entry.text != "") {
- gopher_load (url_entry.text, true);
- }
- }
- public void fix_cursor () {
- var w = text_view.get_window (TextWindowType.TEXT);
- w.set_cursor (new Gdk.Cursor.from_name (Gdk.Display.get_default (), "default"));
- }
- public void visit (string url, bool note) {
- url_entry.set_text (url);
- if (note) {
- history.prepend (url);
- future = new List<string> ();
- }
- }
- public void back () {
- if (history.length () > 1) {
- future.prepend (history.nth_data (0));
- history.remove_link (history.first ());
- string url = history.nth_data (0);
- gopher_load (url, false);
- }
- }
-
- public void forward () {
- if (future.length () > 0) {
- history.prepend (future.nth_data (0));
- string url = future.nth_data (0);
- future.remove_link (future.first ());
- gopher_load (url, false);
- }
- }
-
- public async void gopher_load (string url, bool note) {
- string host;
- int port;
- char gopher_type;
- string selector;
- bool success;
- string text = "";
-
- if (!gopher_parse_url (url, out host, out port, out gopher_type, out selector))
- return;
-
- spinner.start ();
-
- success = yield gopher_request (url, host, port, selector, note, out text);
-
- if(!success) {
- spinner.stop();
- return;
- }
-
- visit (url, note);
- gopher_text_to_buffer (text, gopher_type, text_view);
- fix_cursor ();
-
- spinner.stop();
- }
-
- public bool gopher_parse_url (string url,
- out string host,
- out int port,
- out char gopher_type,
- out string selector) {
- MatchInfo match_info;
- host = "";
- port = 0;
- gopher_type = '0';
- selector = "/";
-
- if (gopher_url_regex.match (url, 0, out match_info)) {
- host = match_info.fetch_named ("host");
-
- string s_port = match_info.fetch_named ("port");
- if (s_port == null) s_port = "70";
- if (s_port == "") s_port = "70";
- port = int.parse(s_port);
-
- string gt = match_info.fetch_named ("gophertype");
- if (gt == null) {
- gopher_type = '1';
- }
- else {
- gopher_type = gt[0];
- }
-
- selector = match_info.fetch_named ("selector");
- if (selector == null) selector = "";
-
- // DBG
- stdout.printf("HOST: %s\n", host);
- stdout.printf("PORT: %d\n", port);
- stdout.printf("TYPE: %c\n", gopher_type);
- stdout.printf("SLCT: %s\n", selector);
-
- return true;
- }
- else {
- stdout.printf ("Invalid URL: %s\n", url);
-
- return false;
- }
- }
-
- public async bool gopher_request (string input_url,
- string host, int port, string selector,
- bool note,
- out string all_lines) {
- try {
- // Resolve hostname to IP address:
- Resolver resolver = Resolver.get_default ();
- List<InetAddress> addresses = resolver.lookup_by_name (host, null);
- InetAddress address = addresses.nth_data (0);
-
- // Connect:
- SocketClient client = new SocketClient ();
- SocketConnection conn = yield client.connect_async (new InetSocketAddress (address, (uint16) port));
-
- // Send HTTP GET request
- string message = "%s\r\n".printf (selector);
- yield conn.output_stream.write_async (message.data);
-
- // Receive response
- conn.socket.set_blocking (true);
- DataInputStream response = new DataInputStream (conn.input_stream);
-
- // response.set_newline_type(DataStreamNewlineType.CR_LF);
-
- size_t my_len;
- all_lines = response.read_upto ("", 0, out my_len);
- } catch (Error e) {
- stdout.printf ("Error: %s\n", e.message);
- return false;
- }
-
- return true;
- }
-
- void gopher_text_to_buffer (string lines, char gopher_type, TextView text_view) {
- TextIter iter;
- TextBuffer buf;
-
- buf = new TextBuffer (null);
- buf.get_start_iter (out iter);
-
- foreach(unowned string line in lines.split("\n")) {
- if (gopher_type == '0') {
- buf.insert(ref iter, line + "\n", -1);
- }
- else if (gopher_type == '1') {
- gopher_page_handle_line (line, buf, ref iter);
- }
- else {
- stdout.printf ("Unhandled gopher type: %c\n", gopher_type);
- return;
- }
- }
-
- text_view.set_buffer (buf);
- }
-
- void gopher_page_handle_line (string line, TextBuffer buf, ref TextIter iter) {
- MatchInfo match_info;
- if (line == "." || line == ".\r") {
- buf.insert(ref iter, line + "\n", -1);
- return;
- }
- if (!gopher_line_regex.match (line, 0, out match_info)) {
- stdout.printf ("Gopher parsing error: %s\n", line);
- return;
- }
- char line_type = match_info.fetch_named ("gopher_type")[0];
- string text = match_info.fetch_named ("text");
- string line_selector = match_info.fetch_named ("selector");
- string line_host = match_info.fetch_named ("host");
- string s_line_port = match_info.fetch_named ("port");
- if (s_line_port == null) s_line_port = "70";
- int line_port = int.parse (s_line_port);
-
- if (line_type == 'i' || line_type == 'I') {
- buf.insert(ref iter, text + "\n", -1);
- }
- else if (line_type == '0' || line_type == '1') {
- string url = "gopher://%s:%d/%c%s".printf (line_host, line_port, line_type, line_selector);
-
- insert_link_to (text, url, LinkType.GOPHE,
- buf, ref iter);
- }
- else if (line_type == 'h' || line_type == 'H') {
- string url = line_selector;
-
- if (url.has_prefix ("URL:")) {
- url = url.substring (4);
- }
-
- insert_link_to (text, url, LinkType.HYPER,
- buf, ref iter);
- }
- else {
- stdout.printf ("Unknown gopher line type: %s\n", line);
- }
- }
- void insert_link_to (string line, string url, LinkType ty,
- TextBuffer buf, ref TextIter iter) {
- string color = "";
- switch (ty) {
- case LinkType.GOPHE:
- color = "blue";
- break;
-
- case LinkType.HYPER:
- color = "red";
- break;
- }
-
- TextTag tag = buf.create_tag (null,
- "foreground", color,
- "underline", Pango.Underline.SINGLE,
- null);
- tag.set_data ("link", url);
-
- tag.event.connect ((event_object, event, iter) => {
- if (event.type == Gdk.EventType.BUTTON_PRESS) {
- string link = tag.get_data ("link");
-
- switch (ty) {
- case LinkType.GOPHE:
- gopher_load (link, true);
- break;
-
- case LinkType.HYPER:
- try {
- if (!Gtk.show_uri (null, link, 0)) {
- stderr.printf ("Couldn't open URL: %s.\n", link);
- }
- }
- catch (Error e) {
- stderr.printf ("Couldn't open URL: %s.\n", link);
- }
- break;
- }
-
- return true;
- }
- else {
- return true;
- }
- });
- buf.insert_with_tags(ref iter, line + "\n", -1, tag, null);
- }
- }
|