Charles.Forsyth20060303a828770d19 years agoHistory
885 lines · 19.2 KB · Brainfuck
RawDownload
implement WmReadmail; include "sys.m";	sys: Sys; include "draw.m";	draw: Draw;	Context: import draw; include "tk.m";	tk: Tk;	Toplevel: import tk; include "tkclient.m";	tkclient: Tkclient; include "dialog.m";	dialog: Dialog; include "selectfile.m";	selectfile: Selectfile; include "string.m";	str: String; include "keyring.m";	kr: Keyring; WmReadmail: module{	init:	fn(ctxt: ref Draw->Context, args: list of string);}; WmSendmail: module{	init:	fn(ctxt: ref Draw->Context, args: list of string);}; srv: Sys->Connection;main: ref Toplevel;ctxt: ref Context;nmesg: int;cmesg: int;map: array of byte;Ok, Deleted: con iota;username: string; mail_cfg := array[] of {	"frame .top",	"label .top.l -bitmap email.bit",	"frame .top.con",	"frame .top.con.b",	"button .top.con.b.con -bitmap mailcon -command {send msg connect}",	"bind .top.con.b.con <Enter> +{.top.status configure -text {connect/disconnect to mail server}}",	"button .top.con.b.next -bitmap mailnext -command {send msg next}",	"bind .top.con.b.next <Enter> +{.top.status configure -text {next message}}",	"button .top.con.b.prev -bitmap mailprev -command {send msg prev}",	"bind .top.con.b.prev <Enter> +{.top.status configure -text {previous message}}",	"button .top.con.b.del -bitmap maildel -command {send msg dele}",	"bind .top.con.b.del <Enter> +{.top.status configure -text {delete message}}",	"button .top.con.b.reply -bitmap mailreply -command {send msg reply}",	"bind .top.con.b.reply <Enter> +{.top.status configure -text {reply to message}}",	"button .top.con.b.fwd -bitmap mailforward",	"bind .top.con.b.fwd <Enter> +{.top.status configure -text {forward message}}",	"button .top.con.b.hdr -bitmap mailhdr -command {send msg hdrs}",	"bind .top.con.b.hdr <Enter> +{.top.status configure -text {fetch message headers}}",	"button .top.con.b.save -bitmap mailsave -command {send msg save}",	"bind .top.con.b.save <Enter> +{.top.status configure -text {save message}}",	"pack .top.con.b.con .top.con.b.prev .top.con.b.next .top.con.b.del .top.con.b.reply .top.con.b.fwd .top.con.b.hdr .top.con.b.save -padx 2 -side left",	"label .top.status -text {not connected ...} -anchor w",	"pack .top.l -side left",	"pack .top.con -side left -padx 10",	"pack .top.con.b .top.status -in .top.con -fill x -expand 1",	"frame .hdr",	"scrollbar .hdr.scroll -command {.hdr.t yview}",	"text .hdr.t -height 3c -yscrollcommand {.hdr.scroll set} -bg white",	"frame .hdr.pad -width 2c",	"pack .hdr.t -side left -fill x -expand 1",	"pack .hdr.scroll -side left -fill y",	"pack .hdr.pad",	"frame .body",	"scrollbar .body.scroll -command {.body.t yview}",	"text .body.t -width 15c -height 7c -yscrollcommand {.body.scroll set} -bg white",	"pack .body.t -side left -expand 1 -fill both",	"pack .body.scroll -side left -fill y",	"pack .top -anchor w -padx 5",	"pack .hdr -fill x -anchor w -padx 5 -pady 5",	"pack .body -expand 1 -fill both -padx 5 -pady 5",	"pack .b -padx 5 -pady 5 -fill x",	"pack propagate . 0",	"update"}; con_cfg := array[] of {	"frame .b",	"button .b.ok -text {Connect} -command {send cmd ok}",	"button .b.can -text {Cancel} -command {send cmd can}",	"pack .b.ok .b.can -side left -fill x -padx 10 -pady 10 -expand 1",	"frame .l",	"label .l.h -text {Mail Server:} -anchor w",	"label .l.u -text {User Name:} -anchor w",	"label .l.s -text {Secret:} -anchor w",	"pack .l.h .l.u .l.s -fill both -expand 1",	"frame .e",	"entry .e.h",	"entry .e.u",	"entry .e.s -show •",	"pack .e.h .e.u .e.s -fill x",	"frame .f -borderwidth 2 -relief raised",	"pack .l .e -fill both -expand 1 -side left -in .f",	"pack .f",	"pack .b -fill x -expand 1",	"bind .e.h <Key-\n> {send cmd ok}",	"bind .e.u <Key-\n> {send cmd ok}",	"bind .e.s <Key-\n> {send cmd ok}",	"focus .e.s",}; hdr_cfg := array[] of {	"scrollbar .sh -orient horizontal -command {.f.l xview}",	"scrollbar .f.sv -command {.f.l yview}",	"frame .f",	"listbox .f.l -width 80w -height 20h -yscrollcommand { .f.sv set} -xscrollcommand { .sh set}",	"pack .f.l -side left -fill both -expand 1",	"pack .f.sv -side left -fill y",	"pack .f -fill both -expand 1",	"pack .sh -fill x",	"pack propagate . 0",	"bind .f.l <Double-Button> { send tomain [.f.l get [.f.l curselection]] }",	"update",}; init(xctxt: ref Context, argv: list of string){	sys = load Sys Sys->PATH;	if (xctxt == nil) {		sys->fprint(sys->fildes(2), "readmail: no window context\n");		raise "fail:bad context";	}	draw = load Draw Draw->PATH;	tk = load Tk Tk->PATH;	tkclient = load Tkclient Tkclient->PATH;	dialog = load Dialog Dialog->PATH;	selectfile = load Selectfile Selectfile->PATH;	str = load String String->PATH;	kr = load Keyring Keyring->PATH; 	ctxt = xctxt; 	tkclient->init();	dialog->init();	selectfile->init(); 	tkargs := "";	argv = tl argv;	if(argv != nil) {		tkargs = hd argv;		argv = tl argv;	} 	titlectl := chan of string;	(main, titlectl) = tkclient->toplevel(ctxt, tkargs, "Readmail: Reader", Tkclient->Appl); 	msg := chan of string;	tk->namechan(main, msg, "msg");	hdr := chan of string; 	for (c:=0; c<len mail_cfg; c++)		tk->cmd(main, mail_cfg[c]);	tkclient->onscreen(main, nil);	tkclient->startinput(main, "kbd"::"ptr"::nil); 	for(;;) alt {		s := <-main.ctxt.kbd =>			tk->keyboard(main, s);		s := <-main.ctxt.ptr =>			tk->pointer(main, *s);		s := <-main.ctxt.ctl or		s = <-main.wreq or		s = <-titlectl =>			if(s == "exit") {				if(srv.dfd != nil) {					status("Updating mail box...");					pop3cmd("QUIT");				}				return;			}			tkclient->wmctl(main, s);	cmd := <-msg =>		case cmd {		"connect" =>			if(srv.dfd == nil) {				connect(main);				if(srv.dfd != nil)					initialize();				break;			}			disconnect();		"prev" =>			if(cmesg > nmesg) {				status("no more messages.");				break;			}			for(new := cmesg+1; new <= nmesg; new++) {				if(map[new] == byte Ok) {					cmesg = new;					loadmesg();					break;				}			}		"next" =>			for(new := cmesg-1; new >= 1; new--) {				if(map[new] == byte Ok) {					cmesg = new;					loadmesg();					break;				}			}		"dele" =>			delete();			if(cmesg > 0) {				cmesg--;				loadmesg();			}		"hdrs" =>			headers(hdr);		"save" =>			save();		"reply" =>			reply();		}	get := <-hdr =>		new := int get;		if(new < 1 || new > nmesg || map[new] != byte Ok)			break;				cmesg = new;		loadmesg();	}} headers(tomain: chan of string){	(hdr, hdrctl) := tkclient->toplevel(ctxt, nil,				"Readmail: Headers", Tkclient->Appl); 	tk->namechan(hdr, tomain, "tomain"); 	for (c:=0; c<len hdr_cfg; c++)		tk->cmd(hdr, hdr_cfg[c]); 	for(i := 1; i <= nmesg; i++) {		if(map[i] == byte Deleted) {			info := sys->sprint("%4d ...Deleted...\n", i);			tk->cmd(hdr, ".f.l insert 0 '"+info);			continue;		}		if(topit(hdr, i) == 0)			break;		alt {		s := <-hdrctl =>			if(s == "exit")				return;			tkclient->wmctl(hdr, s);		* =>			;		}		if((i%10) == 9)			tk->cmd(hdr, "update");	}	tk->cmd(hdr, "update");	tkclient->onscreen(hdr, nil);	tkclient->startinput(hdr, "kbd"::"ptr"::nil); 	spawn hproc(hdrctl, hdr);} trunc(name: string): string{	for(i := 0; i < len name; i++)		if(name[i] == '<')			break;	i++;	if(i >= len name)		return name;	for(j := i; j < len name; j++)		if(name[j] == '>')			break;	return name[i:j];} topit(hdr: ref Toplevel, msg: int): int{	(err, s) := pop3cmd("TOP "+string msg+" 0");	if(err != nil) {		dialog->prompt(ctxt, hdr.image, "error -fg red", "POP3 Error",				"Ecountered a problem fetching headers\n"+err,				0, "Dismiss"::nil);		return 0;	} 	size := int s;	b := pop3body(size);	if(b == nil)		return 0; 	from := getfield("from", b);	from = trunc(from);	date := getfield("date", b);	subj := getfield("subject", b);	if(len subj > 20)		subj = subj[0:19]; 	if(len subj > 0)		info := sys->sprint("%4d %5d %s \"%s\" %s", msg, size, from, subj, date);	else		info = sys->sprint("%4d %5d %s %s", msg, size, from, date); 	tk->cmd(hdr, ".f.l insert 0 '"+info);	return 1;} mapdown(b: array of byte): string{	lb := len b;	l := array[lb] of byte;	for(i := 0; i < lb; i++) {		c := b[i];		if(c >= byte 'A' && c <= byte 'Z')			c += byte('a' - 'A');		l[i] = c;	}	return string l;	} getfield(key: string, text: array of byte): string{	key[len key] = ':';	lk := len key;	cl := byte key[0];	cu := cl - byte ('a' - 'A'); 	lc: byte;	for(i := 0; i < len text - lk; i++) {		t := text[i];		if(t == byte '\n' && lc == byte '\n')		# end header			break;		lc = t;		if(t != cu && t != cl)			continue;		if(key == mapdown(text[i:i+lk])) {			i += lk+1;			for(j := i+1; j < len text; j++) {				c := text[j];				if(c == byte '\r' || c == byte '\n')					break;			}			return string text[i:j];		}	}	return "";} hproc(wmctl: chan of string, top: ref Toplevel){	for(;;) {		alt {		s := <-top.ctxt.kbd =>			tk->keyboard(top, s);		s := <-top.ctxt.ptr =>			tk->pointer(top, *s);		s := <-top.ctxt.ctl or		s = <-top.wreq or		s = <-wmctl =>			if(s == "exit")				return;			tkclient->wmctl(top, s);		}	}} reply(){	if(cmesg == 0) {		dialog->prompt(ctxt, main.image, "error -fg red", "Reply",					"No message to reply to",					0, "Abort"::nil);		return;	} 	hdr := tk->cmd(main, ".hdr.t get 1.0 end");	if(hdr == "") {		dialog->prompt(ctxt, main.image, "error -fg red", "Reply",					"Mail has no header to reply to",					0, "Abort"::nil);		return;	} 	wmsender := load WmSendmail "/dis/wm/sendmail.dis";	if(wmsender == nil) {		dialog->prompt(ctxt, main.image, "error -fg red", "Reply",				"Failed to load mail sender:\n"+sys->sprint("%r"),				0, "Abort"::nil);		return;	} 	spawn wmsender->init(ctxt, "sendmail" :: hdr :: nil);} save(){	if(cmesg == 0) {		dialog->prompt(ctxt, main.image, "error -fg red", "Save",				"No current message",				0, "Continue"::nil);		return;	}	pat := list of {		"*.let (Saved mail)",		"* (All files)"	}; 	fd: ref Sys->FD;	fname: string;	for(;;) {		fname = selectfile->filename(ctxt, main.image, "Save in Mailbox",					pat, "/usr/"+username+"/mail");		if(fname == nil)			return; 		fd = sys->create(fname, sys->OWRITE, 8r660);		if(fd != nil)			break; 		labs := list of {			"New name",			"Abort"		}; 		r := dialog->prompt(ctxt, main.image, "error -fg red", "Save",				"Failed to create "+sys->sprint("%s\n%r", fname),				0, labs);		if(r == 1)			return;	}	s := tk->cmd(main, ".hdr.t get 1.0 end");	b := array of byte s;	r := sys->write(fd, b, len b);	if(r < 0) {		dialog->prompt(ctxt, main.image, "error -fg red", "Save",				"Error writing file"+sys->sprint("%s\n%r", fname),				0, "Continue (not saved)":: nil);		return;	}	s = tk->cmd(main, ".body.t get 1.0 end");	b = array of byte s;	n := sys->write(fd, b, len b);	if(n < 0) {		dialog->prompt(ctxt, main.image, "error -fg red", "Save",				"Error writing file"+sys->sprint("%s\n%r", fname),				0, "Continue (not saved)":: nil);		return;	}	status("wrote "+string(n+r)+" bytes.");} delete(){	if(srv.dfd == nil) {		dialog->prompt(ctxt, main.image, "warning -fg yellow", "Delete",				"You must be connected to delete messages",				0, "Continue"::nil);		return;	}	(err, s) := pop3cmd("DELE "+string cmesg);	if(err != nil) {		dialog->prompt(ctxt, main.image, "error -fg red", "Delete",				"Encountered POP3 problem during delete\n"+err,				0, "Continue"::nil);		return;	}	map[cmesg] = byte Deleted;	status(s);} status(msg: string){	tk->cmd(main, ".top.status configure -text {"+msg+"}; update");} disconnect(){	(err, s) := pop3cmd("QUIT");	srv.dfd = nil;	tk->cmd(main, ".top.con configure -text Connect");	if(err != nil) {		dialog->prompt(ctxt, main.image, "error -fg red", "Disconnect",				"POP3 protocol problem\n"+err,				0, "Proceed"::nil);		return;	}

Lines 1–500 of 885.