commit 9fea1d51b528953d0699c9c55a0d08d02ebe7131
parent 45cde57ee73cafe5fa02a84b0553b9011a82d617
Author: Tomas Hlavaty <tom@logand.com>
Date: Mon, 10 Jan 2011 23:08:00 +0100
w3maild added
Diffstat:
M | Makefile | | | 11 | ++++++----- |
A | w3maild.vala | | | 258 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 264 insertions(+), 5 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,9 +1,10 @@
-all: w3mail
-
-CFLAGS=-Wall -std=c99 -pedantic -D_XOPEN_SOURCE=600
+all: w3mail w3maild
w3mail: w3mail.c
- $(CC) $(CFLAGS) -o w3mail w3mail.c
+ $(CC) -Wall -std=c99 -pedantic -D_XOPEN_SOURCE=600 -o w3mail w3mail.c
+
+w3maild: w3maild.vala
+ valac -g --pkg gio-2.0 --pkg gee-1.0 w3maild.vala
clean:
- rm -f *~ w3mail
+ rm -f *~ w3mail w3maild
diff --git a/w3maild.vala b/w3maild.vala
@@ -0,0 +1,258 @@
+// w3maild.vala -- Get web pages into your inbox via pop3 server.
+// (c) 2011 Tomas Hlavaty
+
+using Gee;
+
+abstract class Pop3Server {
+ SocketConnection c;
+ DataInputStream i;
+ DataOutputStream o;
+ State s;
+
+ enum State {
+ START,
+ USER,
+ PASS,
+ LIST
+ }
+
+ public Pop3Server(SocketConnection _c) {
+ c = _c;
+ i = new DataInputStream (c.input_stream);
+ o = new DataOutputStream (c.output_stream);
+ s = State.START;
+ }
+
+ protected void prinl (string x) throws GLib.IOError, GLib.Error {
+ o.put_string (x);
+ o.put_string ("\n");
+ o.flush ();
+ }
+
+ protected void ok (string msg) throws GLib.IOError, GLib.Error {
+ o.put_string ("+OK ");
+ prinl (msg);
+ }
+
+ protected void ok2 (string msg1, string msg2) throws GLib.IOError, GLib.Error {
+ o.put_string ("+OK ");
+ o.put_string (msg1);
+ o.put_string (" ");
+ prinl (msg2);
+ }
+
+ public async void process_request () {
+ try {
+ ready ();
+ string line = yield i.read_line_async (Priority.HIGH_IDLE);
+ while (true) {
+ var cmd = parse_line (line);
+ if(!process_command (cmd)) break;
+ line = yield i.read_line_async (Priority.HIGH_IDLE);
+ }
+ } catch (Error e) {
+ stderr.printf ("Error: %s\n", e.message);
+ }
+ }
+
+ protected string[] parse_line (string line) {
+ return line.chomp().split(" ");
+ }
+
+ protected bool process_command (string[] cmd) throws GLib.IOError, GLib.Error {
+ switch(cmd[0]) {
+ case "QUIT":
+ return quit (cmd);
+ case "USER":
+ if(s != State.START) return false;
+ var x = user (cmd);
+ if(x) s = State.USER;
+ return x;
+ case "PASS":
+ if(s != State.USER) return false;
+ var x = pass (cmd);
+ if(x) s = State.PASS;
+ return x;
+ case "STAT":
+ if(s != State.PASS && s != State.LIST) return false;
+ var x = stat (cmd);
+ if(x) s = State.LIST;
+ return x;
+ case "LIST":
+ if(s != State.PASS && s != State.LIST) return false;
+ var x = list (cmd);
+ if(x) s = State.LIST;
+ return x;
+ case "RETR":
+ if(s != State.LIST) return false;
+ return retr (cmd);
+ case "DELE":
+ if(s != State.LIST) return false;
+ return dele (cmd);
+ default: return otherwise (cmd);
+ }
+ }
+
+ protected abstract void ready () throws GLib.IOError, GLib.Error;
+ protected abstract bool quit (string[] cmd) throws GLib.IOError, GLib.Error;
+ protected abstract bool user (string[] cmd) throws GLib.IOError, GLib.Error;
+ protected abstract bool pass (string[] cmd) throws GLib.IOError, GLib.Error;
+ protected abstract bool stat (string[] cmd) throws GLib.IOError, GLib.Error;
+ protected abstract bool list (string[] cmd) throws GLib.IOError, GLib.Error;
+ protected abstract bool retr (string[] cmd) throws GLib.IOError, GLib.Error;
+ protected abstract bool dele (string[] cmd) throws GLib.IOError, GLib.Error;
+ protected abstract bool otherwise (string[] cmd) throws GLib.IOError, GLib.Error;
+}
+
+// ~/.w3maild
+// ~/.w3maild/[tomas]
+// ~/.w3maild/[tomas]/[data]
+
+class W3maildServer : Pop3Server {
+ string usr = "";
+ string pwd = "";
+ HashMap<int, FileInfo> map = new HashMap<int, FileInfo> ();
+
+ public W3maildServer(SocketConnection c) {
+ base (c);
+ }
+
+ protected override void ready () throws GLib.IOError, GLib.Error {
+ ok ("w3maild ready");
+ }
+
+ protected override bool quit (string[] cmd) throws GLib.IOError, GLib.Error {
+ ok2 (usr, "w3maild bye");
+ return false;
+ }
+
+ string data_dirname () {
+ return Environment.get_home_dir () + "/.w3maild/" + usr;
+ }
+
+ File data_dir () {
+ return File.new_for_path (data_dirname ());;
+ }
+
+ bool user_exists () {
+ if(usr.length < 1) return false;
+ return data_dir ().query_file_type (0) == FileType.DIRECTORY;
+ }
+
+ protected override bool user (string[] cmd) throws GLib.IOError, GLib.Error {
+ usr = cmd[1];
+ if(!user_exists ()) return false;
+ ok ("User accepted");
+ return true;
+ }
+
+ protected override bool pass (string[] cmd) throws GLib.IOError, GLib.Error {
+ pwd = cmd[1];
+ ok ("Pass accepted");
+ return true;
+ }
+
+ void update_map () {
+ int cnt = 0;
+ map.clear ();
+ try {
+ File dir = data_dir ();
+ var i = dir.enumerate_children (FILE_ATTRIBUTE_STANDARD_NAME + "," +
+ FILE_ATTRIBUTE_STANDARD_TYPE,
+ FileQueryInfoFlags.NONE,
+ null);
+ FileInfo info;
+ while ((info = i.next_file (null)) != null)
+ if(info.get_file_type () == FileType.REGULAR)
+ map.set (++cnt, info);
+ } catch (Error e) {
+ stderr.printf ("Error: %s\n", e.message);
+ }
+ }
+
+ void collect_stat (out int cnt, out uint64 siz) {
+ cnt = 0;
+ siz = 0;
+ update_map ();
+ foreach (int i in map.keys) {
+ cnt++;
+ siz += map[i].get_size ();
+ }
+ }
+
+ protected override bool stat (string[] cmd) throws GLib.IOError, GLib.Error {
+ int cnt = 0;
+ uint64 siz = 0;
+ collect_stat (out cnt, out siz);
+ ok (cnt.to_string () + " " + siz.to_string ());
+ return true;
+ }
+
+ protected override bool list (string[] cmd) throws GLib.IOError, GLib.Error {
+ int cnt = 0;
+ uint64 siz = 0;
+ collect_stat (out cnt, out siz);
+ ok (cnt.to_string () + " messages (" + siz.to_string () + " octets)");
+ cnt = 0;
+ siz = 0;
+ foreach (int i in map.keys)
+ prinl (i.to_string () + " " + map[i].get_size ().to_string ());
+ prinl (".");
+ return true;
+ }
+
+ string data_filename (string name) {
+ return data_dirname () + "/" + name;
+ }
+
+ File data_file (string name) {
+ return File.new_for_path (data_filename (name));
+ }
+
+ protected override bool retr (string[] cmd) throws GLib.IOError, GLib.Error {
+ var i = cmd[1].to_int ();
+ if (map[i] == null) return false;
+ ok (map[i].get_size ().to_string () + " octets");
+ var file = data_file (map[i].get_name ());
+ try {
+ var dis = new DataInputStream (file.read ());
+ string line;
+ while ((line = dis.read_line (null)) != null)
+ prinl (line == "." ? ".." : line);
+ prinl (".");
+ return true;
+ } catch (Error e) {
+ stderr.printf ("%s\n", e.message);
+ }
+ return false;
+ }
+
+ protected override bool dele (string[] cmd) throws GLib.IOError, GLib.Error {
+ var i = cmd[1].to_int ();
+ data_file (map[i].get_name ()).delete ();
+ ok ("message " + i.to_string () + " deleted");
+ return true;
+ }
+
+ protected override bool otherwise (string[] cmd) throws GLib.IOError, GLib.Error {
+ return false;
+ }
+}
+
+static bool on_incoming_connection (SocketConnection c) {
+ var s = new W3maildServer (c);
+ s.process_request.begin ();
+ return true;
+}
+
+void main () {
+ try {
+ var srv = new SocketService ();
+ srv.add_inet_port (3333, null);
+ srv.incoming.connect (on_incoming_connection);
+ srv.start ();
+ new MainLoop ().run ();
+ } catch (Error e) {
+ stderr.printf ("%s\n", e.message);
+ }
+}