diff --git a/exec/imapservice.js b/exec/imapservice.js index 07d5d798f13b214729ed45b39b4c33d56b212dd4..a9ab7058260aa23a82a7401d452747d59508f6c5 100644 --- a/exec/imapservice.js +++ b/exec/imapservice.js @@ -13,7 +13,7 @@ load("822header.js"); load("mime.js"); var sepchar="|"; -var debug_exceptions = false; +var debug_exceptions = true; var debug=false; var debugRX=false; @@ -27,13 +27,12 @@ var index={offsets:[],idx:{}}; var line; var readonly=true; var curr_status={exists:0,recent:0,unseen:0,uidnext:0,uidvalidity:0}; -var saved_config={'__config_epoch__':0, mail:{scan_ptr:0, subscribed:true}}; -var last_saved_config=JSON.parse(JSON.stringify(saved_config)); -var last_saved_file={}; +var saved_config={mail:{'__config_epoch__':0, scan_ptr:0, subscribed:true, Seen:{}}}; var scan_ptr; var cfgfile; var applied_epoch = -1; var cfg_locked = false; +var locked_code = undefined; /**********************/ /* Encoding functions */ @@ -215,6 +214,8 @@ function untagged(msg) function next_epoch(last_epoch) { + if (last_epoch === undefined) + last_epoch = 0; if (last_epoch >= Number.MAX_SAFE_INTEGER) return 0; return last_epoch + 1; @@ -223,7 +224,7 @@ function next_epoch(last_epoch) function init_seen(code) { if(saved_config[code] == undefined) - saved_config[code] = {subscribed:false}; + saved_config[code] = {subscribed:false, Seen:{}}; if(saved_config[code].Seen == undefined) saved_config[code].Seen = {}; } @@ -946,7 +947,7 @@ var unauthenticated_command_handlers = { tagged(tag, "NO", "No AUTH for you."); return; } - if (!open_cfg(system.matchuser(args[1], false))) + if (!open_cfg(system.matchuser(args[1], false), tag)) return; tagged(tag, "OK", "Howdy."); state=Authenticated; @@ -973,27 +974,36 @@ var unauthenticated_command_handlers = { } // First, try as-stored... if (args[1] === hmac(u.security.password, challenge)) { - if (!open_cfg(u)) + if (!login(u.alias, u.security.password)) { + tagged(tag, "NO", "No AUTH for you."); + return; + } + if (!open_cfg(u, tag)) return; - login(u.alias, u.security.password); tagged(tag, "OK", "Howdy."); state=Authenticated; return; } // Lower-case if (args[1] === hmac(u.security.password.toLowerCase(), challenge)) { - if (!open_cfg(u)) + if (!login(u.alias, u.security.password)) { + tagged(tag, "NO", "No AUTH for you."); + return; + } + if (!open_cfg(u, tag)) return; - login(u.alias, u.security.password); tagged(tag, "OK", "Howdy."); state=Authenticated; return; } // Upper-case if (args[1] === hmac(u.security.password.toUpperCase(), challenge)) { - if (!open_cfg(u)) + if (!login(u.alias, u.security.password)) { + tagged(tag, "NO", "No AUTH for you."); + return; + } + if (!open_cfg(u, tag)) return; - login(u.alias, u.security.password); tagged(tag, "OK", "Howdy."); state=Authenticated; return; @@ -1022,7 +1032,7 @@ var unauthenticated_command_handlers = { return; } u = system.matchuser(usr, false); - if (!open_cfg(u)) + if (!open_cfg(u, tag)) return; tagged(tag, "OK", "Sure, come on in."); state=Authenticated; @@ -1233,34 +1243,32 @@ function sublist(group, match, subscribed) if(re.test("INBOX")) ret.push("INBOX"); - lock_cfg() - try { - read_cfg('mail', true); - for(grp in msg_area.grp_list) { - if(re.test(msg_area.grp_list[grp].description)) - ret.push((msg_area.grp_list[grp].description+sepchar).replace(/&/g,'&-')); + for(grp in msg_area.grp_list) { + if(re.test(msg_area.grp_list[grp].description)) + ret.push((msg_area.grp_list[grp].description+sepchar).replace(/&/g,'&-')); - for(sub in msg_area.grp_list[grp].sub_list) { - code = msg_area.grp_list[grp].sub_list[sub].code - // TODO: Notyet - //read_cfg(code, false); - if(re.test(msg_area.grp_list[grp].description+sepchar+msg_area.grp_list[grp].sub_list[sub].description)) { - if((!subscribed) || (saved_config.hasOwnProperty(code) && saved_config[code].hasOwnProperty('subscribed') && saved_config[code].subscribed)) { - base=new MsgBase(code); - if(base == undefined || sub=="NONE!!!" || (!base.open())) - continue; - base.close(); - ret.push((msg_area.grp_list[grp].description+sepchar+msg_area.grp_list[grp].sub_list[sub].description).replace(/&/g,'&-')); - } + for(sub in msg_area.grp_list[grp].sub_list) { + code = msg_area.grp_list[grp].sub_list[sub].code + lock_cfg(code); + try { + read_cfg(); + } + catch (error) { + unlock_cfg(code); + throw(error); + } + unlock_cfg(code); + if(re.test(msg_area.grp_list[grp].description+sepchar+msg_area.grp_list[grp].sub_list[sub].description)) { + if((!subscribed) || (saved_config.hasOwnProperty(code) && saved_config[code].hasOwnProperty('subscribed') && saved_config[code].subscribed)) { + base=new MsgBase(code); + if(base == undefined || sub=="NONE!!!" || (!base.open())) + continue; + base.close(); + ret.push((msg_area.grp_list[grp].description+sepchar+msg_area.grp_list[grp].sub_list[sub].description).replace(/&/g,'&-')); } } } } - catch (error) { - unlock_cfg(); - throw error; - } - unlock_cfg(); return(ret); } @@ -1385,11 +1393,13 @@ function read_index(base) index.code = get_base_code(base); for(i=0; i<index.total; i++) { idx=base.get_msg_index(true,i); - if(idx==null) + if(idx==null) { continue; + } if(base.subnum==-1) { - if(idx.to != user.number) + if(idx.to != user.number) { continue; + } } else { // Fake \Seen @@ -1425,39 +1435,86 @@ function apply_seen(index) applied_epoch = saved_config.__config_epoch__; } -function open_cfg(usr) +function open_cfg(usr, tag) { - cfgfile=new File(format(system.data_dir+"user/%04d.imap", usr.number)); - if (!cfgfile.open(cfgfile.exists ? 'r+':'w+', true, 0)) { - tagged(tag, "NO", "Can't open imap state file"); - return false; + var path = format(system.data_dir+"user/%04d", usr.number); + if (!file_isdir(path)) { + if (!mkdir(path)) + return false; } - lock_cfg(); - try { - // Check if it's the old INI format... - if (cfgfile.length > 0) { - var ch = cfgfile.read(1); - if (ch != '{') { - // INI file, convert... - read_old_cfg(); - save_cfg(); + + cfgfile=new File(format(system.data_dir+"user/%04d.imap", usr.number)); + if (cfgfile.exists) { + if (!cfgfile.open('r+', true, 0)) { + tagged(tag, "NO", "Can't open imap state file"); + return false; + } + old_lock_cfg(); + try { + // Check if it's the old INI format... + if (cfgfile.length > 0) { + var ch = cfgfile.read(1); + if (ch != '{') { + // INI file, convert... + read_old_cfg(); + } + else { + read_old_cfg2(); + } } } - else { - save_cfg(); + catch (error) { + old_unlock_cfg(); + throw error; } + cfgfile.truncate(); + old_unlock_cfg(); + cfgfile.close(); + file_remove(cfgfile.name); + cfgfile = undefined; + save_cfg(); } - catch (error) { - unlock_cfg(); - throw error; - } - unlock_cfg(); + else + cfgfile = undefined; return true; } -function lock_cfg() +function lock_cfg(sub) { - start = time(); + if (locked_code !== undefined) + throw new Error('Locking ' + sub.toSource() + ' while ' + locked_code.toSource() + ' is locked'); + if (cfgfile != undefined) + throw new Error('Locking ' + sub.toSource() + ' while ' + cfgfile.name + ' is open.'); + var path = format(system.data_dir+"user/%04d", user.number); + if (!file_isdir(path)) { + if (!mkdir(path)) { + throw new Error("Unable to create "+path); + return false; + } + } + + cfgfile=new File(format("%s/%s.imap", path, sub)); + if (!cfgfile.open(cfgfile.exists ? 'r+':'w+', true, 0)) + throw new Error('Unable to open config file'); + + var start = time(); + while(!cfgfile.lock(0, 1)) { + if (!client.socket.is_connected) + exit(0); + if (js.termianted) + exit(0); + if ((time() - start) > 600) { + log(LOG_ERR, "Timed out waiting 600 seconds for IMAP lock."); + exit(0); + } + mswait(10); + } + locked_code = sub; +} + +function old_lock_cfg() +{ + var start = time(); while(!cfgfile.lock(0, 1)) { if (!client.socket.is_connected) exit(0); @@ -1472,7 +1529,18 @@ function lock_cfg() cfg_locked = true; } -function unlock_cfg() +function unlock_cfg(sub) +{ + if (sub != locked_code) + throw new Error('Unlocking ' + sub.toSource() + ' but ' + locked_code.toSource() + ' is locked'); + cfgfile.flush(); + cfgfile.unlock(0, 1); + cfgfile.close(); + cfgfile = undefined; + locked_code = undefined; +} + +function old_unlock_cfg() { cfgfile.unlock(0, 1); cfg_locked = false; @@ -1481,15 +1549,14 @@ function unlock_cfg() function exit_func() { close_sub(); - if (cfgfile !== undefined) { - if (!cfg_locked) - lock_cfg(); - try { - save_cfg(); - } - catch (error) { - } - unlock_cfg(); + if (locked_code !== undefined) { + log("At exit, "+locked_code+" is still locked."); + unlock_cfg(locked_code); + } + try { + save_cfg(); + } + catch (error) { } } @@ -1552,63 +1619,72 @@ function binify(seen) return ret; } -function save_cfg() +function save_cfg(sub) { var cfg; var b; var s; var scpy; var new_cfg = {}; - var forced; var fk; - if (!cfg_locked) - throw new Error('Configuration must be locked to call save_cfg()'); - if(user.number > 0) { - for (sub in saved_config) { - if (sub == '__config_epoch__') { - new_cfg[sub] = next_epoch(saved_config[sub]); - } - else { - // Sanity check to make sure both seen and bseen aren't defined for the same message - forced = false; - if (last_saved_file[sub].bseen != undefined && last_saved_file[sub].seen != undefined) { - fk = Object.keys(last_saved_file[sub].bseen)[0]; - if (last_saved_file[sub].seen[fk]) - delete last_saved_config[sub]; - } + function save_one_cfg(osub) + { + var new_cfg = {}; - if (last_saved_config[sub] == undefined || JSON.stringify(saved_config[sub]) != JSON.stringify(last_saved_config[sub])) { - scpy = undefined; - if (saved_config[sub].Seen !== undefined) { - scpy = JSON.parse(JSON.stringify(saved_config[sub].Seen)); - } - new_cfg[sub] = {}; - if (saved_config[sub].scan_ptr != undefined) - new_cfg[sub].scan_ptr = saved_config[sub].scan_ptr; - if(scpy !== undefined) { - var bin = binify(scpy); - if (bin !== undefined) - new_cfg[sub].bseen = bin; - if (Object.keys(scpy).length > 0) - new_cfg[sub].seen = scpy; - } - if (saved_config[sub].subscribed === undefined || saved_config[sub].subscribed === false) - new_cfg[sub].subscribed = false; - else - new_cfg[sub].subscribed = true; - last_saved_file[sub] = new_cfg[sub]; - last_saved_config[sub] = JSON.parse(JSON.stringify(saved_config[sub])); + if (osub != locked_code) + throw new Error('Unlocking ' + osub.toSource() + ' but ' + locked_code.toSource() + ' is locked'); + + if (saved_config[locked_code]==undefined) { + if (locked_code == 'mail') + saved_config[locked_code]={subscribed:true, __config_epoch__: 0, scan_ptr:0}; + else + saved_config[locked_code]={subscribed:false, __config_epoch__: 0, scan_ptr:0}; + } + + if(user.number > 0) { + // Sanity check to make sure both seen and bseen aren't defined for the same message + new_cfg.__config_epoch__ = next_epoch(saved_config[osub].__config_epoch__); + scpy = undefined; + if (saved_config[osub].Seen !== undefined) { + scpy = JSON.parse(JSON.stringify(saved_config[osub].Seen)); + } + if (saved_config[osub].scan_ptr != undefined) + new_cfg.scan_ptr = saved_config[osub].scan_ptr; + if(scpy !== undefined) { + var bin = binify(scpy); + if (bin !== undefined) + new_cfg.bseen = bin; + if (Object.keys(scpy).length > 0) + new_cfg.seen = scpy; + } + if (saved_config[osub].subscribed === undefined || saved_config[osub].subscribed === false) + new_cfg.subscribed = false; + else + new_cfg.subscribed = true; + cfgfile.rewind(); + cfgfile.truncate(); + cfgfile.write(JSON.stringify(new_cfg)); + } + } + + if (sub != undefined) { + save_one_cfg(sub); + } + else { + for (nsub in saved_config) { + if (nsub != '__config_epoch__') { + lock_cfg(nsub); + try { + save_one_cfg(nsub); } - else { - new_cfg[sub] = last_saved_file[sub]; + catch (error) { + unlock_cfg(nsub); + throw errorl } + unlock_cfg(nsub); } } - cfgfile.rewind(); - cfgfile.truncate(); - cfgfile.write(JSON.stringify(new_cfg)); - cfgfile.flush(); } } @@ -1618,19 +1694,19 @@ function close_sub() if(base != undefined && base.is_open) { code = get_base_code(base); - lock_cfg(); + lock_cfg(get_base_code(base)); try { - read_cfg(get_base_code(base), false); + read_cfg(); if (saved_config[code].scan_ptr < scan_ptr) { saved_config[code].scan_ptr=scan_ptr; - save_cfg(); + save_cfg(get_base_code(base)); } } catch (error) { - unlock_cfg(); + unlock_cfg(get_base_code(base)); throw error; } - unlock_cfg(); + unlock_cfg(get_base_code(base)); base.close(); } } @@ -1639,7 +1715,6 @@ function open_sub(sub) { var i; var idx; - var code; close_sub(); base=new MsgBase(sub); @@ -1647,26 +1722,25 @@ function open_sub(sub) update_status(); return false; } - code = get_base_code(base); if(base.cfg != undefined) { - scan_ptr = msg_area.sub[code].scan_ptr; + scan_ptr = msg_area.sub[sub].scan_ptr; } - lock_cfg(); + lock_cfg(sub); try { - read_cfg(sub, false); + read_cfg(); - if (saved_config[code].scan_ptr > scan_ptr) - scan_ptr = saved_config[code].scan_ptr; + if (saved_config[sub].scan_ptr > scan_ptr) + scan_ptr = saved_config[sub].scan_ptr; if (!readonly) { - saved_config[code].scan_ptr = base.last_msg; - save_cfg(); + saved_config[sub].scan_ptr = base.last_msg; + save_cfg(sub); } } catch (error) { - unlock_cfg(); + unlock_cfg(sub); throw error; } - unlock_cfg(); + unlock_cfg(sub); update_status(); sendflags(false); untagged(curr_status.exists+" EXISTS"); @@ -1682,6 +1756,8 @@ function display_list(cmd, groups) { var group; var base; + var scanptr; + var code; for(group in groups) { if(groups[group].substr(-1)==sepchar) @@ -1693,7 +1769,20 @@ function display_list(cmd, groups) else { base=new MsgBase(getsub(groups[group])); if(base.cfg != undefined) { - if(base.last_msg > msg_area.sub[base.cfg.code].scan_ptr) + code = get_base_code(base); + lock_cfg(code); + try { + read_cfg(); + } + catch (error) { + unlock_cfg(code); + throw(error); + } + unlock_cfg(code); + scanptr = msg_area.sub[base.cfg.code].scan_ptr; + if (saved_config[base.cfg.code].scan_ptr > scanptr) + scanptr = saved_config[base.cfg.code].scan_ptr; + if(base.last_msg > scanptr) untagged(cmd+' (\\Noinferiors \\Marked \\HasNoChildren) '+encode_string(sepchar)+' '+encode_string(groups[group])); else untagged(cmd+' (\\Noinferiors \\UnMarked \\HasNoChildren) '+encode_string(sepchar)+' '+encode_string(groups[group])); @@ -1774,17 +1863,17 @@ var authenticated_command_handlers = { var sub=getsub(args[1]); if(msg_area.sub[sub]!=undefined && msg_area.sub[sub].can_read) { - lock_cfg(); + lock_cfg(sub); try { - read_cfg(sub, false); + read_cfg(); saved_config[sub].subscribed = true; - save_cfg(); + save_cfg(sub); } catch (error) { - unlock_cfg(); + unlock_cfg(sub); throw error; } - unlock_cfg(); + unlock_cfg(sub); tagged(tag, "OK", "Subscribed..."); } else @@ -1798,17 +1887,17 @@ var authenticated_command_handlers = { var sub=getsub(args[1]); if(msg_area.sub[sub]!=undefined && msg_area.sub[sub].can_read) { - lock_cfg(); + lock_cfg(sub); try { - read_cfg(sub, false); + read_cfg(); saved_config[sub].subscribed = false; - save_cfg(); + save_cfg(sub); } catch (error) { - unlock_cfg(); + unlock_cfg(sub); throw error; } - unlock_cfg(); + unlock_cfg(sub); tagged(tag, "OK", "Unsubscribed..."); } else @@ -1863,7 +1952,15 @@ var authenticated_command_handlers = { } base_code = get_base_code(base); - read_cfg(base_code, true); + lock_cfg(base_code); + try { + read_cfg(); + } + catch (error) { + unlock_cfg(base_code); + throw error; + } + unlock_cfg(base_code); index = read_index(base); base.close(); for(i in items) { @@ -1934,9 +2031,9 @@ function do_store(seq, uid, item, data) var changed=false; var uci = item.toUpperCase(); - lock_cfg(); + lock_cfg(index.code); try { - read_cfg(index.code, false); + read_cfg(); flags=parse_flags(data); for(i in seq) { idx=index.idx[seq[i]]; @@ -1988,14 +2085,14 @@ function do_store(seq, uid, item, data) if (!client.socket.is_connected) break; } - js.gc(); - save_cfg(); + save_cfg(index.code); } catch (error) { - unlock_cfg(); + unlock_cfg(index.code); throw error; } - unlock_cfg(); + unlock_cfg(index.code); + js.gc(); if(changed) index=read_index(base); } @@ -2231,7 +2328,7 @@ var search_operators = { return true; } if (arg[0].toUpperCase() == '\\Recent') { - if (msg.idx.offset > scan_ptr) + if (msg.idx.number > scan_ptr) return true; } return false; @@ -2905,21 +3002,21 @@ var selected_command_handlers = { var data_items=parse_data_items(args[2]); var i; - lock_cfg(); + lock_cfg(get_base_code(base)); try { - read_cfg(get_base_code(base), false); + read_cfg(); for(i in seq) { send_fetch_response(seq[i], data_items, false); if (!client.socket.is_connected) break; } - save_cfg(); + save_cfg(get_base_code(base)); } catch (error) { - unlock_cfg(); + unlock_cfg(get_base_code(base)); throw error; } - unlock_cfg(); + unlock_cfg(get_base_code(base)); js.gc(); tagged(tag, "OK", "There they are!"); }, @@ -2966,21 +3063,21 @@ var selected_command_handlers = { } seq=parse_seq_set(args[2],true); data_items=parse_data_items(args[3]); - lock_cfg(); + lock_cfg(get_base_code(base)); try { - read_cfg(get_base_code(base), false); + read_cfg(); for(i in seq) { send_fetch_response(seq[i], data_items, true); if (!client.socket.is_connected) break; } - save_cfg(); + save_cfg(get_base_code(base)); } catch (error) { - unlock_cfg(); + unlock_cfg(get_base_code(base)); throw error; } - unlock_cfg(); + unlock_cfg(get_base_code(base)); js.gc(); tagged(tag, "OK", "There they are (with UIDs)!"); break; @@ -3080,7 +3177,7 @@ function read_old_cfg() } } -function read_cfg(sub, lck) +function read_old_cfg2(sub, lck) { var basemsg; var bstr; @@ -3093,7 +3190,7 @@ function read_cfg(sub, lck) var contents; if (lck) - lock_cfg(); + old_lock_cfg(); try { if(saved_config[sub]==undefined) saved_config[sub]={subscribed:false}; @@ -3112,30 +3209,28 @@ function read_cfg(sub, lck) saved_config.__config_epoch__ = newfile[newsub]; } else { - if (last_saved_file[newsub] == undefined || JSON.stringify(newfile[newsub]) != JSON.stringify(last_saved_file[newsub])) { - saved_config[newsub] = {}; - if (newfile[newsub].hasOwnProperty('scan_ptr')) - saved_config[newsub].scan_ptr = newfile[newsub].scan_ptr; - if (newfile[newsub].hasOwnProperty('seen')) - saved_config[newsub].Seen = newfile[newsub].seen; - else - saved_config[newsub].Seen = {}; - if (newfile[newsub].hasOwnProperty('subscribed')) - saved_config[newsub].subscribed = newfile[newsub].subscribed; - else - saved_config[newsub].subscribed = false; - if (newfile[newsub].hasOwnProperty('bseen')) { - for (i in newfile[newsub].bseen) { - basemsg = parseInt(i, 10); - bstr = base64_decode(newfile[newsub].bseen[i]); - for (byte = 0; byte < bstr.length; byte++) { - asc = ascii(bstr[byte]); - if (asc == 0) - continue; - for (bit=0; bit<8; bit++) { - if (asc & (1<<bit)) - saved_config[newsub].Seen[basemsg+(byte*8+bit)]=1; - } + saved_config[newsub] = {}; + if (newfile[newsub].hasOwnProperty('scan_ptr')) + saved_config[newsub].scan_ptr = newfile[newsub].scan_ptr; + if (newfile[newsub].hasOwnProperty('seen')) + saved_config[newsub].Seen = newfile[newsub].seen; + else + saved_config[newsub].Seen = {}; + if (newfile[newsub].hasOwnProperty('subscribed')) + saved_config[newsub].subscribed = newfile[newsub].subscribed; + else + saved_config[newsub].subscribed = false; + if (newfile[newsub].hasOwnProperty('bseen')) { + for (i in newfile[newsub].bseen) { + basemsg = parseInt(i, 10); + bstr = base64_decode(newfile[newsub].bseen[i]); + for (byte = 0; byte < bstr.length; byte++) { + asc = ascii(bstr[byte]); + if (asc == 0) + continue; + for (bit=0; bit<8; bit++) { + if (asc & (1<<bit)) + saved_config[newsub].Seen[basemsg+(byte*8+bit)]=1; } } } @@ -3146,22 +3241,88 @@ function read_cfg(sub, lck) } catch (error) { if (lck) - unlock_cfg(); + old_unlock_cfg(); throw error; } if (lck) - unlock_cfg(); + old_unlock_cfg(); if(saved_config[sub].Seen==undefined) saved_config[sub].Seen={}; - if (sub != 'mail' && ((saved_config[sub].sub_ptr == undefined) || (msg_area.sub[sub].scan_ptr > saved_config[sub]))) { + if (sub !== undefined && sub != 'mail' && ((saved_config[sub].scan_ptr == undefined) || (msg_area.sub[sub].scan_ptr > saved_config[sub]))) { saved_config[sub].scan_ptr = msg_area.sub[sub].scan_ptr; } apply_seen(index); - last_saved_config = JSON.parse(JSON.stringify(saved_config)); - last_saved_file = newfile; +} + +function read_cfg() +{ + var basemsg; + var bstr; + var newfile; + var i; + var byte; + var asc; + var bit; + var contents; + + if (saved_config[locked_code]==undefined) { + if (locked_code == 'mail') + saved_config[locked_code]={subscribed:true, __config_epoch__: 0, scan_ptr:0}; + else + saved_config[locked_code]={subscribed:false, __config_epoch__: 0, scan_ptr:0}; + } + + cfgfile.rewind(); + contents = cfgfile.read(); + try { + newfile = JSON.parse(contents); + } + catch (error) { + if (locked_code == 'mail') + newfile = {subscribed:true, __config_epoch__: 0, scan_ptr:0}; + else + newfile = {subscribed:false, __config_epoch__: 0, scan_ptr:0}; + } + if (newfile.__config_epoch__ !== saved_config[locked_code].__config_epoch__) { + saved_config.__config_epoch__ = newfile.__config_epoch__; + saved_config[locked_code] = {}; + if (newfile.hasOwnProperty('scan_ptr')) + saved_config[locked_code].scan_ptr = newfile.scan_ptr; + if (newfile.hasOwnProperty('seen')) + saved_config[locked_code].Seen = newfile.seen; + else + saved_config[locked_code].Seen = {}; + if (newfile.hasOwnProperty('subscribed')) + saved_config[locked_code].subscribed = newfile.subscribed; + else + saved_config[locked_code].subscribed = false; + if (newfile.hasOwnProperty('bseen')) { + for (i in newfile.bseen) { + basemsg = parseInt(i, 10); + bstr = base64_decode(newfile.bseen[i]); + for (byte = 0; byte < bstr.length; byte++) { + asc = ascii(bstr[byte]); + if (asc == 0) + continue; + for (bit=0; bit<8; bit++) { + if (asc & (1<<bit)) + saved_config[locked_code].Seen[basemsg+(byte*8+bit)]=1; + } + } + } + } + } + + if(saved_config[locked_code].Seen==undefined) + saved_config[locked_code].Seen={}; + if (locked_code != 'mail' && ((saved_config[locked_code].scan_ptr == undefined) || (msg_area.sub[locked_code].scan_ptr > saved_config[locked_code]))) { + saved_config[locked_code].scan_ptr = msg_area.sub[locked_code].scan_ptr; + } + + apply_seen(index); } js.on_exit("exit_func()");