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. Load more
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; }