w3mail

program to send a web page by email
git clone https://logand.com/git/w3mail.git/
Log | Files | Refs | README | LICENSE

commit 9fea1d51b528953d0699c9c55a0d08d02ebe7131
parent 45cde57ee73cafe5fa02a84b0553b9011a82d617
Author: Tomas Hlavaty <tom@logand.com>
Date:   Mon, 10 Jan 2011 23:08:00 +0100

w3maild added

Diffstat:
MMakefile | 11++++++-----
Aw3maild.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); + } +}