diff --git a/exec/imapservice.js b/exec/imapservice.js index be5397a0104b7d3ae0ee4486a812c549550d346a..2901b334fbff4f228bd94ee048ecc184b816e8b7 100644 --- a/exec/imapservice.js +++ b/exec/imapservice.js @@ -66,10 +66,13 @@ function send_fetch_response(msgnum, format, uid) var m; var re; var tmp; + var sent_flags=false; + var seen_changed=false; function get_header() { - if(hdr == undefined) + if(hdr == undefined) { hdr=base.get_msg_header(msgnum); + } } function get_rfc822_header() { @@ -159,7 +162,52 @@ function send_fetch_response(msgnum, format, uid) rfc822.size=rfc822.header.length+rfc822.text.length; } - resp=idx.offset + " FETCH ("; + function set_seen_flag() { + if(readonly) + return; + if(base.subnum==65535) { + get_header(); + if(!(hdr.attr & MSG_READ)) { + hdr.attr |= MSG_READ; + base.put_msg_header(msgnum); + hdr=base.get_msg_header(msgnum); + if(hdr.attr & MSG_READ) + seen_changed=true; + } + } + } + + if(base.subnum==65535) + resp=inbox_map.offset[msgnum]; + else + resp=idx.offset + resp += " FETCH ("; + + // Moves flags to the end... + function sort_format(a,b) + { + if(typeof(a)=='object') + a=0; + else { + if(a.substr(0,5).toUpperCase()=='FLAGS') + a=100; + else + a=0; + } + if(typeof(b)=='object') + b=0; + else { + if(b.substr(0,5).toUpperCase()=='FLAGS') + b=100; + else + b=0; + } + + return a-b; + } + + format=format.sort(sort_format); + for(i in format) { if(typeof(format[i])=='object') { // We already handled this I hope... @@ -186,7 +234,9 @@ function send_fetch_response(msgnum, format, uid) } switch(format[i].toUpperCase()) { case 'FLAGS': - resp += "FLAGS () "; + get_header(); + resp += "FLAGS ("+calc_msgflags(hdr.attr, hdr.netattr, base.subnum==65535, base.cfg==undefined?null:base.cfg.code, msgnum, readonly)+") "; + sent_flags=true; break; case 'UID': resp += "UID "+idx.number+" "; @@ -194,7 +244,7 @@ function send_fetch_response(msgnum, format, uid) break; case 'INTERNALDATE': get_header(); - resp += 'INTERNALDATE '+strftime('"%d-%a-%C%y %H:%M:%S +0000" ', hdr.when_imported_time); + resp += 'INTERNALDATE '+strftime('"%d-%b-%C%y %H:%M:%S +0000" ', hdr.when_imported_time); break; case 'RFC822.SIZE': get_rfc822_size(); @@ -202,7 +252,7 @@ function send_fetch_response(msgnum, format, uid) break; case 'RFC822.TEXT': case 'BODY[TEXT]': - // Set "Seen" flag + set_seen_flag(); // fall-through case 'BODY.PEEK[TEXT]': get_rfc822_text(); @@ -210,7 +260,7 @@ function send_fetch_response(msgnum, format, uid) break; case 'BODY[HEADER]': case 'RFC822.HEADER': - // Set "Seen" flag + set_seen_flag(); // fall-through case 'BODY.PEEK[HEADER]': get_rfc822_header(); @@ -218,18 +268,23 @@ function send_fetch_response(msgnum, format, uid) break; case 'RFC822': case 'BODY[]': - // Set "Seen" flag + set_seen_flag(); // fall-through case 'BODY.PEEK[]': get_rfc822(); resp += format[i].replace(/\.PEEK/,"").toUpperCase()+" {"+(rfc822.header.length+rfc822.text.length)+"}\r\n"+rfc822.header+rfc822.text+" "; break; case 'BODY[HEADER.FIELDS': + set_seen_flag(); case 'BODY.PEEK[HEADER.FIELDS': objtype=format[i].replace(/\.PEEK/,"").toUpperCase(); break; } } + if(seen_changed && !sent_flags) { + get_header(); + resp += "FLAGS ("+calc_msgflags(hdr.attr, hdr.netattr, base.subnum==65535, base.cfg==undefined?null:base.cfg.code, msgnum, readonly)+") "; + } if(uid && !sent_uid) resp += "UID "+idx.number+" "; resp = resp.substr(0, resp.length-1)+")"; @@ -273,8 +328,12 @@ function parse_seq_set(set, uid) { if(uid) max=base.last_msg; - else - max=base.total_msgs; + else { + if(base.subnum==65535) + max=inbox_map.uid.length; + else + max=base.total_msgs; + } for(chunk in chunks) { range=chunks[chunk].split(/:/); if(range.length == 1) @@ -291,7 +350,13 @@ function parse_seq_set(set, uid) { range[1]=i; } for(i=range[0]; i<=range[1]; i++) { - idx=base.get_msg_index(uid?false:true, parseInt(i,10)); + if(base.subnum==65535) { + idx=base.get_msg_index(uid?parseInt(i,10):inbox_map.uid[parseInt(i,10)]); + if(idx==null || idx.to != user.number) + continue; + } + else + idx=base.get_msg_index(uid?false:true, parseInt(i,10)); if(idx!=null) { response.push(idx.number); } @@ -327,6 +392,8 @@ function parse_command(line) case Selected: if(handle_command(command, args, selected_command_handlers)) return; + if(handle_command(command, args, authenticated_command_handlers)) + return; break; } } @@ -416,6 +483,7 @@ function parse_command(line) return(args); } + send_updates(); return(execute_line(parse_line())); } @@ -425,6 +493,7 @@ const Authenticated=1; const Selected=2; var state=UnAuthenticated; var base; +var inbox_map; // Command handling functions any_state_command_handlers = { @@ -509,15 +578,209 @@ unauthenticated_command_handlers = { function sendflags(perm) { + var flags=""; + var pflags=""; + + if(base.subnum==65535) { + flags=calc_msgflags(0xffff, 0xffff, true, null, null, true); + pflags=calc_msgflags(0xffff, 0xffff, true, null, null, true); + } + else { + flags=calc_msgflags(0xffff, 0xffff, false, null, null, true); + pflags=calc_msgflags(0xffff, 0xffff, false, null, null, true); + } if(perm) - untagged("OK [PERMANENTFLAGS ()] No flags yet... working on 'er"); + untagged("OK [PERMANENTFLAGS ("+pflags+")] Overkill!"); else - untagged("FLAGS () Someday I'll add flags... *sigh*"); + untagged("FLAGS ("+flags+") Overkill!"); +} + +function parse_flags(inflags) +{ + var i; + var flags={attr:0, netattr:0}; + + for(i in inflags) { + switch(inflags[i].toUpperCase()) { + case '\\SEEN': + case 'READ': + flags.attr |= MSG_READ; + break; + case '\\ANSWERED': + case 'REPLIED': + flags.attr |= MSG_REPLIED; + break; + case '\\FLAGGED': + case 'VALIDATED': + flags.attr |= MSG_VALIDATED; + break; + case '\\DELETED': + case 'DELETE': + flags.attr |= MSG_DELETE; + break; + case 'ANONYMOUS': + flags.attr |= MSG_ANONYMOUS; + break; + case 'KILLREAD': + flags.attr |= MSG_KILLREAD; + break; + case 'MODERATED': + flags.attr |= MSG_MODERATED; + break; + case 'NOREPLY': + flags.attr |= MSG_NOREPLY; + break; + + case 'LOCAL': + flags.netattr |= MSG_LOCAL; + break; + case 'INTRANSIT': + flags.netattr |= MSG_INTRANSIT; + break; + case 'SENT': + flags.netattr |= MSG_SENT; + break; + case 'KILLSENT': + flags.netattr |= MSG_KILLSENT; + break; + case 'ARCHIVESENT': + flags.netattr |= MSG_ARCHIVESENT; + break; + case 'HOLD': + flags.netattr |= MSG_HOLD; + break; + case 'CRASH': + flags.netattr |= MSG_CRASH; + break; + case 'IMMEDIATE': + flags.netattr |= MSG_IMMEDIATE; + break; + case 'DIRECT': + flags.netattr |= MSG_DIRECT; + break; + case 'GATE': + flags.netattr |= MSG_GATE; + break; + case 'ORPHAN': + flags.netattr |= MSG_ORPHAN; + break; + case 'FPU': + flags.netattr |= MSG_FPU; + break; + case 'TYPELOCAL': + flags.netattr |= MSG_TYPELOCAL; + break; + case 'TYPEECHO': + flags.netattr |= MSG_TYPECHO; + break; + case 'TYPENET': + flags.netattr |= MSG_TYPENET; + break; + } + } + return(flags); } -function sendexists() +function check_msgflags(attr, netattr, ismail, touser, fromuser, isoperator) { - untagged(base.total_msgs+" EXISTS"); + var flags={attr:attr, netattr:netattr}; + const op_perms=(MSG_DELETE|MSG_VALIDATED); + const to_perms=(MSG_READ); + const from_perms=0; + var perms=0; + + if(user.compare_ars("SYSOP")) + return(flags); // SYSOP has godly powers. + + // Only the sysop can diddle the network flags + flags.netattr=0; + + if(isoperator) + perms |= op_perms; + if(touser) + perms |= to_perms; + if(fromuser) + perms |= from_perms; + + flags.attr &= perms; + return(flags); +} + +function calc_msgflags(attr, netattr, ismail, code, msg, readonly) +{ + var flags=''; + + if(attr & MSG_PRIVATE) + flags += "PRIVATE "; + if(attr & MSG_READ) { + if(base.subnum==65535) + flags += "\\Seen "; + else + flags += "READ "; + } + if(attr & MSG_PERMANENT) + flags += "PERMANENT "; + if(attr & MSG_LOCKED) + flags += "LOCKED "; + if(attr & MSG_DELETE) + flags += "\\Deleted "; + if(attr & MSG_ANONYMOUS) + flags += "ANONYMOUS "; + if(attr & MSG_KILLREAD) + flags += "KILLREAD "; + if(attr & MSG_MODERATED) + flags += "MODERATED "; + if(attr & MSG_VALIDATED) + flags += "\\Flagged "; + if(attr & MSG_REPLIED) { + if(base.subnum==65535) + flags += "\\Answered "; + else + flags += "REPLIED "; + } + if(attr & MSG_NOREPLY) + flags += "NOREPLY "; + + if(netattr & MSG_INTRANSIT) + flags += "INTRANSIT "; + if(netattr & MSG_SENT) + flags += "SENT "; + if(netattr & MSG_KILLSENT) + flags += "KILLSENT "; + if(netattr & MSG_ARCHIVESENT) + flags += "ARCHIVESENT "; + if(netattr & MSG_HOLD) + flags += "HOLD "; + if(netattr & MSG_CRASH) + flags += "CRASH "; + if(netattr & MSG_IMMEDIATE) + flags += "IMMEDIATE "; + if(netattr & MSG_DIRECT) + flags += "DIRECT "; + if(netattr & MSG_GATE) + flags += "GATE "; + if(netattr & MSG_ORPHAN) + flags += "ORPHAN "; + if(netattr & MSG_FPU) + flags += "FPU "; + if(netattr & MSG_TYPELOCAL) + flags += "TYPELOCAL "; + if(netattr & MSG_TYPEECHO) + flags += "TYPEECHO "; + if(netattr & MSG_TYPENET) + flags += "TYPENET "; + + if(msg==null || msg_ptrs[code] < msg) + flags += '\\Recent '; + + if(!readonly) { + if(msg > msg_ptrs[code]) + msg_ptrs[code]=msg; + } + + if(flags.length) + return(flags.substr(0, flags.length-1)); + return(""); } function sublist(group, match, subscribed) @@ -525,21 +788,33 @@ function sublist(group, match, subscribed) var grp; var sub; var ret=[]; + var groups={}; + var wmatch,wgroup; + var fmatch; + + if(match=='') + return([""]); + + wmatch=match.replace(/^\%/, "|*"); + wgroup=group.replace(/\%$/, "*|"); - match=match.replace(/\%/, "*"); - group=group.replace(/\%/, "*"); + if(wgroup == '') + wgroup='*'; + fmatch=(wgroup+wmatch).replace(/\|\|/,"|"); for(grp in msg_area.grp_list) { - if(group=='' || wildmatch(true, msg_area.grp_list[grp].description, group)) { + if(wildmatch(true, msg_area.grp_list[grp].description, fmatch)) { ret.push(msg_area.grp_list[grp].description+sepchar); for(sub in msg_area.grp_list[grp].sub_list) { - if(wildmatch(true, msg_area.grp_list[grp].sub_list[sub].description, match, false)) { + if(wildmatch(true, msg_area.grp_list[grp].sub_list[sub].description, fmatch, false)) { if((!subscribed) || msg_area.grp_list[grp].sub_list[sub].scan_cfg&SCAN_CFG_NEW) ret.push(msg_area.grp_list[grp].description+sepchar+msg_area.grp_list[grp].sub_list[sub].description); } } } } + if(wildmatch(true, "INBOX", fmatch, false)) + ret.push("INBOX"); return(ret); } @@ -548,7 +823,8 @@ function getsub(longname) { var grp; var sub; - longname=longname.replace(/^"(.*)"$/, "$1"); + if(longname=='INBOX') + return("mail"); components=longname.split(sepchar); for(grp in msg_area.grp_list) { if(msg_area.grp_list[grp].description==components[0]) { @@ -562,6 +838,121 @@ function getsub(longname) { return("NONE!!!"); } +function generate_inbox_map() +{ + var i; + var idx; + var count=0; + var unseen=0; + var uid=[]; + var offset={}; + + for(i=base.first_msg; i<=base.last_msg; i++) { + idx=base.get_msg_index(i); + if(idx != null) { + if(idx.to != user.number) + continue; + uid.push(idx.number); + offset[idx.number]=uid.length; + } + } + return({uid:uid,unseen:unseen,offset:offset}); +} + +function count_recent(base) +{ + var i; + var count=0; + var idx; + + if(base.cfg==undefined) + return 0; + for(i=base.first_msg; i<= base.last_msg; i++) { + idx=base.get_msg_index(i); + if(idx==null) + continue; + if(base.subnum==65535 && idx.to != user.number) + continue; + if(i > msg_area.sub[base.cfg.code].scan_ptr) + count++; + } + return(count); +} + +function update_status() +{ + if(base==undefined || !base.is_open) { + curr_status={exists:-1,recent:-1,unseen:-1,uidnext:-1,uidvalidity:-1}; + return; + } + if(base.subnum==65535) { + inbox_map=generate_inbox_map(true); + curr_status.exists=inbox_map.uid.length; + curr_status.recent=count_recent(base); + curr_status.unseen=inbox_map.unseen; + if(inbox_map.uid.length > 0) + curr_status.uidnext=inbox_map.uid[inbox_map.uid.length-1]+1; + else + curr_status.uidnext=1; + curr_status.uidvalidity=0; + } + else { + curr_status.exists=base.total_msgs; + curr_status.recent=count_recent(base); + curr_status.unseen=base.total_msgs; + curr_status.uidnext=base.last_msg+1; + curr_status.uidvalidity=0; + } +} + +function send_updates() +{ + var old_status; + + if(state==Selected) { + old_status=eval(curr_status.toSource()); + update_status(); + if(old_status.exists != curr_status.exists) + untagged(curr_status.exists+" EXISTS"); + if(old_status.recent != curr_status.recent) + untagged(curr_status.recent+" RECENT"); + if(old_status.unseen != curr_status.unseen) + untagged("OK [UNSEEN "+(curr_status.unseen)+"]"); + if(old_status.uidnext != curr_status.uidnext) + untagged("OK [UIDNEXT "+(curr_status.uidnext)+"]"); + if(old_status.uidvalidity != curr_status.uidvalidity) + untagged("OK [UIDVALIDITY "+curr_status.uidvalidity+"]"); + } +} + +function open_sub(sub) +{ + if(base != undefined && base.is_open && base.cfg != undefined) { + if(msg_ptrs[base.cfg.code]!=orig_ptrs[base.cfg.code]) + msg_base.sub[base.cfg.code]=msg_ptrs[base.cfg.code]; + base.close(); + update_status(); + } + base=new MsgBase(sub); + if(base == undefined || (!base.open())) + return false; + if(base.cfg != undefined) { + if(orig_ptrs[base.cfg.code]==undefined) { + orig_ptrs[base.cfg.code]=msg_area.sub[base.cfg.code]; + msg_ptrs[base.cfg.code]=msg_area.sub[base.cfg.code]; + } + } + update_status(); + sendflags(false); + untagged(curr_status.exists+" EXISTS"); + untagged(curr_status.recent+" RECENT"); + untagged("OK [UNSEEN "+(curr_status.unseen)+"]"); + sendflags(true); + untagged("OK [UIDNEXT "+(curr_status.uidnext)+"]"); + untagged("OK [UIDVALIDITY "+curr_status.uidvalidity+"]"); + return true; +} + authenticated_command_handlers = { SELECT:{ arguments:1, @@ -569,19 +960,12 @@ authenticated_command_handlers = { var tag=args[0]; var sub=getsub(args[1]); - base=new MsgBase(sub); - if(base == undefined || (!base.open())) { + if(!open_sub(sub)) { tagged(tag, "NO", "Can't find "+args[1]+" ("+sub+")"); return; } - sendflags(false); - untagged(base.total_msgs+" EXISTS"); - untagged(0+" RECENT"); - untagged("OK [UNSEEN "+(base.total_msgs+1)+"]"); - sendflags(true); - untagged("OK [UIDNEXT "+(base.last_msg+1)+"]"); - untagged("OK [UIDVALIDITY 0]"); - tagged(tag, "OK", "[READ-ONLY] Mailbox "+sub+" has been selected"); + tagged(tag, "OK", "[READ-WRITE] Mailbox "+sub+" has been selected"); + readonly=false; state=Selected; }, }, @@ -591,19 +975,12 @@ authenticated_command_handlers = { var tag=args[0]; var sub=getsub(args[1]); - base=new MsgBase(sub); - if(base == undefined || (!base.open())) { - tagged(tag, "NO", "Can't find your mailbox"); + if(!open_sub(sub)) { + tagged(tag, "NO", "Can't find "+args[1]+" ("+sub+")"); return; } - sendflags(false); - untagged(base.total_msgs+" EXISTS"); - untagged(0+" RECENT"); - untagged("OK [UNSEEN "+(base.total_msgs+1)+"]"); - sendflags(true); - untagged("OK [UIDNEXT "+(base.last_msg+1)+"]"); - untagged("OK [UIDVALIDITY 0]"); - tagged(tag, "OK", "[READ-ONLY] Mailbox "+sub+" has been selected"); + tagged(tag, "OK", "[READ-ONLY] Mailbox "+sub+" has been examined"); + readonly=true; state=Selected; }, }, @@ -672,12 +1049,28 @@ authenticated_command_handlers = { var sub=args[2]; var groups=sublist(group, sub, false); var group; + var base; + var interesting=false; for(group in groups) { if(groups[group].substr(-1)==sepchar) untagged('LIST (\\Noselect) "'+sepchar+'" "'+groups[group].substr(0,groups[group].length-1)+'"'); - else - untagged('LIST () "'+sepchar+'" "'+groups[group]+'"'); + else { + if(groups[group] == '') { + untagged('LIST (\\Noselect) "'+sepchar+'" "'+groups[group]+'"'); + } + else { + base=new MsgBase(getsub(groups[group])); + if(base.cfg != undefined) { + if(base.last_msg > msg_area.sub[base.cfg.code].scan_ptr) + untagged('LIST (\\Noinferiors \\Marked) "'+sepchar+'" "'+groups[group]+'"'); + else + untagged('LIST (\\Noinferiors \\Unmarked) "'+sepchar+'" "'+groups[group]+'"'); + } + else + untagged('LIST (\\Noinferiors) "'+sepchar+'" "'+groups[group]+'"'); + } + } } tagged(tag, "OK", "There you go."); }, @@ -708,6 +1101,9 @@ authenticated_command_handlers = { var items=args[2]; var i; var response=[]; + var base; + var mademap=false; + var inbox_map; if(typeof(items)!="object") items=[items]; @@ -716,15 +1112,25 @@ authenticated_command_handlers = { tagged(tag, "NO", "Can't find your mailbox"); return; } + if(base.cfg != undefined && orig_ptrs[base.cfg.code]==undefined) { + orig_ptrs[base.cfg.code]=msg_area.sub[base.cfg.code]; + msg_ptrs[base.cfg.code]=msg_area.sub[base.cfg.code]; + } for(i in items) { switch(items[i].toUpperCase()) { case 'MESSAGES': response.push("MESSAGES"); - response.push(base.total_msgs); + if(base.subnum==65535) { + if(!mademap) + inbox_map=generate_inbox_map(false); + response.push(inbox_map.length); + } + else + response.push(base.total_msgs); break; case 'RECENT': response.push("RECENT"); - response.push(0); + response.push(count_recent(base)); break; case 'UIDNEXT': response.push("UIDNEXT"); @@ -736,11 +1142,18 @@ authenticated_command_handlers = { break; case 'UNSEEN': response.push("UNSEEN"); - response.push(base.total_msgs); + if(base.subnum==65535) { + if(!mademap) + inbox_map=generate_inbox_map(); + response.push(inbox_map.unseen); + } + else + response.push(base.total_msgs+1); break; } } base.close(); + update_status(); untagged("STATUS {"+(args[1].length)+"}\r\n"+args[1]+" ("+response.join(" ")+")"); tagged(tag, "OK", "And that's the way it is."); }, @@ -759,14 +1172,48 @@ authenticated_command_handlers = { }, }; +function do_store(seq, uid, item, data) +{ + var silent=false; + var i,j; + var flags; + var chflags; + var hdr; + + for(i in seq) { + hdr=base.get_msg_header(seq[i]); + flags=parse_flags(data); + switch(item.toUpperCase()) { + case 'FLAGS.SILENT': + silent=true; + case 'FLAGS': + chflags={attr:hdr.attr^flags.attr, netattr:hdr.netattr^flags.netattr}; + break; + case '+FLAGS.SILENT': + silent=true; + case '+FLAGS': + chflags={attr:hdr.attr^(hdr.attr|flags.attr), netattr:hdr.netattr^(hdr.netattr|flags.netattr)}; + break; + case '-FLAGS.SILENT': + silent=true; + case '-FLAGS': + chflags={attr:hdr.attr^(hdr.attr&~flags.attr), netattr:hdr.netattr^(hdr.netattr&~flags.netattr)}; + break + } + chflags=check_msgflags(chflags.attr, chflags.netattr, base.subnum==65535, hdr.to_net_type==NET_NONE?hdr.to==user.number:false, hdr.from_net_type==NET_NONE?hdr.from==user.number:false,base.is_operator); + if(chflags.attr || chflags.netattr) { + hdr.attr ^= chflags.attr; + hdr.netattr ^= chflags.netattr; + if(!readonly) + base.put_msg_header(seq[i], hdr); + hdr=base.get_msg_header(seq[i]); + } + if(!silent) + send_fetch_response(seq[i], ["FLAGS"], uid); + } +} + selected_command_handlers = { - SELECT:{ // Outlook uses SELECT when selected... - arguments:1, - handler:function(args) { - base.close(); - authenticated_command_handlers.SELECT.handler(args); - }, - }, CHECK:{ arguments:0, handler:function(args) { @@ -780,7 +1227,12 @@ selected_command_handlers = { handler:function(args) { var tag=args[0]; + if(base.cfg != undefined) { + if(msg_ptrs[base.cfg.code]!=orig_ptrs[base.cfg.code]) + msg_base.sub[base.cfg.code]=msg_ptrs[base.cfg.code]; + } base.close(); + update_status(); tagged(tag, "OK", "Closed."); state=Authenticated; }, @@ -815,15 +1267,18 @@ selected_command_handlers = { send_fetch_response(seq[i], data_items, false); } tagged(tag, "OK", "There they are!"); - //tagged(tag, "NO", "Can't fetch... I'm useless."); }, }, STORE:{ arguments:3, handler:function(args) { var tag=args[0]; + var seq=parse_seq_set(args[1], false); + var item=args[2]; + var data=args[3]; - tagged(tag, "NO", "This is read-only."); + do_store(seq, false, item, data); + tagged(tag, "OK", "Stored 'em up"); }, }, COPY:{ @@ -831,16 +1286,21 @@ selected_command_handlers = { handler:function(args) { var tag=args[0]; - tagged(tag, "NO", "Hah! You can't even FETCH yet and you want to COPY?!?!"); + tagged(tag, "NO", "Hah! Not likely!"); }, }, UID:{ - arguments:3, + arguments_valid:function(count) { + if(count==3 || count==4) + return(true); + return(false); + }, handler:function(args) { var tag=args[0]; var cmd=args[1]; var seq; var data_items; + var data; var i; switch(cmd.toUpperCase()) { @@ -856,6 +1316,17 @@ selected_command_handlers = { } tagged(tag, "OK", "There they are (with UIDs)!"); break; + case 'STORE': + if(args.length != 5) { + tagged(args[0], "BAD", "Bad dog, no UID STORE cookie."); + return; + } + seq=parse_seq_set(args[2],true); + data_items=args[3]; + data=args[4]; + do_store(seq, true, data_items, data); + tagged(tag, "OK", "Stored 'em up (with UIDs)!"); + break; default: tagged(tag, "NO", "Help, I'm useless."); } @@ -864,6 +1335,10 @@ selected_command_handlers = { }; var line; +var readonly=true; +var orig_ptrs={}; +var msg_ptrs={}; +var curr_status={exists:0,recent:0,unseen:0,uidnext:0,uidvalidity:0}; client.socket.send("* OK Give 'er\r\n"); while(1) { line=client.socket.recvline(1024, 300);