class RIMS::Protocol::UserMailboxDecoder::Engine
Attributes
mail_store[R]
unique_user_id[R]
Public Class Methods
new(unique_user_id, mail_store, logger, bulk_response_count: 100, bulk_response_size: 1024**2 * 10, read_lock_timeout_seconds: ReadWriteLock::DEFAULT_TIMEOUT_SECONDS, write_lock_timeout_seconds: ReadWriteLock::DEFAULT_TIMEOUT_SECONDS, cleanup_write_lock_timeout_seconds: 1, charset_aliases: RFC822::DEFAULT_CHARSET_ALIASES, charset_convert_options: nil)
click to toggle source
# File lib/rims/protocol/decoder.rb, line 756 def initialize(unique_user_id, mail_store, logger, bulk_response_count: 100, bulk_response_size: 1024**2 * 10, read_lock_timeout_seconds: ReadWriteLock::DEFAULT_TIMEOUT_SECONDS, write_lock_timeout_seconds: ReadWriteLock::DEFAULT_TIMEOUT_SECONDS, cleanup_write_lock_timeout_seconds: 1, charset_aliases: RFC822::DEFAULT_CHARSET_ALIASES, charset_convert_options: nil) @unique_user_id = unique_user_id @mail_store = mail_store @logger = logger @bulk_response_count = bulk_response_count @bulk_response_size = bulk_response_size @read_lock_timeout_seconds = read_lock_timeout_seconds @write_lock_timeout_seconds = write_lock_timeout_seconds @cleanup_write_lock_timeout_seconds = cleanup_write_lock_timeout_seconds @charset_aliases = charset_aliases @charset_convert_options = charset_convert_options @folders = {} @logger.debug("RIMS::Protocol::UserMailboxDecoder::Engine#initialize at #{self}") if @logger.debug? end
Private Class Methods
imap_command_authenticated(name, **guard_optional)
click to toggle source
# File lib/rims/protocol/decoder.rb, line 905 def imap_command_authenticated(name, **guard_optional) name = name.to_sym orig_name = "_#{name}".to_sym alias_method orig_name, name guard_options_name = "_#{name}_guard_options".to_sym define_method guard_options_name, lambda{ guard_optional } private guard_options_name class_eval(<<-EOF, __FILE__, __LINE__ + 1) def #{name}(token, tag, *args, **kw_args, &block) guard_authenticated(:#{orig_name}, token, tag, *args, **kw_args, **#{guard_options_name}, &block) end EOF name end
imap_command_selected(name, **guard_optional)
click to toggle source
# File lib/rims/protocol/decoder.rb, line 924 def imap_command_selected(name, **guard_optional) name = name.to_sym orig_name = "_#{name}".to_sym alias_method orig_name, name guard_options_name = "_#{name}_guard_options".to_sym define_method guard_options_name, lambda{ guard_optional } private guard_options_name class_eval(<<-EOF, __FILE__, __LINE__ + 1) def #{name}(token, tag, *args, **kw_args, &block) guard_selected(:#{orig_name}, token, tag, *args, **kw_args, **#{guard_options_name}, &block) end EOF name end
Public Instance Methods
append(token, tag, mbox_name, *opt_args, msg_text) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1270 def append(token, tag, mbox_name, *opt_args, msg_text) res = new_bulk_response mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name) if (mbox_id = @mail_store.mbox_id(mbox_name_utf8)) then msg_flags = [] msg_date = Time.now if ((! opt_args.empty?) && (opt_args[0].is_a? Array)) then opt_flags = opt_args.shift if (opt_flags[0] != :group) then raise SyntaxError, 'bad flag list.' end for flag_atom in opt_flags[1..-1] case (flag_atom.upcase) when '\ANSWERED' msg_flags << 'answered' when '\FLAGGED' msg_flags << 'flagged' when '\DELETED' msg_flags << 'deleted' when '\SEEN' msg_flags << 'seen' when '\DRAFT' msg_flags << 'draft' else raise SyntaxError, "invalid flag: #{flag_atom}" end end end if ((! opt_args.empty?) && (opt_args[0].is_a? String)) then begin msg_date = Time.parse(opt_args.shift) rescue ArgumentError raise SyntaxError, $!.message end end unless (opt_args.empty?) then raise SyntaxError, "unknown option: #{opt_args.inspect}" end uid = @mail_store.add_msg(mbox_id, msg_text, msg_date) for flag_name in msg_flags @mail_store.set_msg_flag(mbox_id, uid, flag_name, true) end mailbox_size_server_response_multicast_push(mbox_id) if (token) then folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } end res << "#{tag} OK [APPENDUID #{mbox_id} #{uid}] APPEND completed\r\n" else if (token) then folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } end res << "#{tag} NO [TRYCREATE] not found a mailbox\r\n" end yield(res.flush) end
check(token, tag) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1341 def check(token, tag) res = new_bulk_response if (token) then folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } end @mail_store.sync res << "#{tag} OK CHECK completed\r\n" yield(res.flush) end
cleanup(token)
click to toggle source
# File lib/rims/protocol/decoder.rb, line 834 def cleanup(token) if (token) then begin @mail_store.write_synchronize(@cleanup_write_lock_timeout_seconds) { folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) close_folder(token) do |untagged_response| folder.server_response_multicast_push(untagged_response) end } rescue WriteLockTimeoutError @logger.warn("give up to close folder becaue of write-lock timeout over #{@write_lock_timeout_seconds} seconds") @folders.delete(token) end end nil end
close(token, tag) { |"#{tag} OK CLOSE completed\r\n"| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1368 def close(token, tag) close_no_response(token) yield([ "#{tag} OK CLOSE completed\r\n" ]) end
copy(token, tag, msg_set, mbox_name, uid: false) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1630 def copy(token, tag, msg_set, mbox_name, uid: false) folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.should_be_alive folder.reload if folder.updated? res = new_bulk_response mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name) msg_set = folder.parse_msg_set(msg_set, uid: uid) if (mbox_id = @mail_store.mbox_id(mbox_name_utf8)) then msg_list = folder.msg_find_all(msg_set, uid: uid) src_uids = [] dst_uids = [] for msg in msg_list src_uids << msg.uid dst_uids << @mail_store.copy_msg(msg.uid, folder.mbox_id, mbox_id) end if (msg_list.size > 0) then mailbox_size_server_response_multicast_push(mbox_id) folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } res << "#{tag} OK [COPYUID #{mbox_id} #{src_uids.join(',')} #{dst_uids.join(',')}] COPY completed\r\n" else folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } res << "#{tag} OK COPY completed\r\n" end else folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } res << "#{tag} NO [TRYCREATE] not found a mailbox\r\n" end yield(res.flush) end
create(token, tag, mbox_name) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1032 def create(token, tag, mbox_name) res = new_bulk_response if (token) then folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } end mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name) if (@mail_store.mbox_id(mbox_name_utf8)) then res << "#{tag} NO duplicated mailbox\r\n" else @mail_store.add_mbox(mbox_name_utf8) res << "#{tag} OK CREATE completed\r\n" end yield(res.flush) end
delete(token, tag, mbox_name) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1052 def delete(token, tag, mbox_name) res = new_bulk_response if (token) then folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } end mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name) if (id = @mail_store.mbox_id(mbox_name_utf8)) then if (id != @mail_store.mbox_id('INBOX')) then @mail_store.del_mbox(id) res << "#{tag} OK DELETE completed\r\n" else res << "#{tag} NO not delete inbox\r\n" end else res << "#{tag} NO not found a mailbox\r\n" end yield(res.flush) end
destroy()
click to toggle source
# File lib/rims/protocol/decoder.rb, line 852 def destroy @logger.debug("RIMS::Protocol::UserMailboxDecoder::Engine#destroy at #{self}") if @logger.debug? tmp_mail_store = @mail_store ReadWriteLock.write_lock_timeout_detach(@cleanup_write_lock_timeout_seconds, @write_lock_timeout_seconds, logger: @logger) {|timeout_seconds| tmp_mail_store.write_synchronize(timeout_seconds) { @logger.info("close mail store: #{@unique_user_id}") tmp_mail_store.close } } @mail_store = nil nil end
examine(token, tag, mbox_name) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1007 def examine(token, tag, mbox_name) if (token) then close_no_response(token) end res = new_bulk_response new_token = nil mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name) if (id = @mail_store.mbox_id(mbox_name_utf8)) then new_token = open_folder(id, read_only: true) folder_open_msgs(new_token) {|untagged_response| res << untagged_response yield(res.flush) if res.full? } res << "#{tag} OK [READ-ONLY] EXAMINE completed\r\n" else res << "#{tag} NO not found a mailbox\r\n" end yield(res.flush) new_token end
expunge(token, tag) { |"#{tag} NO cannot expunge in read-only mode\r\n"| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1374 def expunge(token, tag) folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.should_be_alive return yield([ "#{tag} NO cannot expunge in read-only mode\r\n" ]) if folder.read_only? folder.reload if folder.updated? res = new_bulk_response folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } folder.expunge_mbox do |msg_num| untagged_response = "* #{msg_num} EXPUNGE\r\n" res << untagged_response yield(res.flush) if res.full? folder.server_response_multicast_push(untagged_response) end res << "#{tag} OK EXPUNGE completed\r\n" yield(res.flush) end
fetch(token, tag, msg_set, data_item_group, uid: false) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1478 def fetch(token, tag, msg_set, data_item_group, uid: false) folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.should_be_alive folder.reload if folder.updated? msg_set = folder.parse_msg_set(msg_set, uid: uid) msg_list = folder.msg_find_all(msg_set, uid: uid) unless ((data_item_group.is_a? Array) && data_item_group[0] == :group) then data_item_group = [ :group, data_item_group ] end if (uid) then unless (data_item_group.find{|i| (i.is_a? String) && (i.upcase == 'UID') }) then data_item_group = [ :group, 'UID' ] + data_item_group[1..-1] end end parser = FetchParser.new(@mail_store, folder, charset_aliases: @charset_aliases) fetch = parser.parse(data_item_group) res = new_bulk_response folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } for msg in msg_list res << ('* '.b << msg.num.to_s.b << ' FETCH '.b << fetch.call(msg) << "\r\n".b) yield(res.flush) if res.full? end res << "#{tag} OK FETCH completed\r\n" yield(res.flush) end
idle(token, tag, client_input_gets, server_output_write, connection_timer) { |last_res| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1674 def idle(token, tag, client_input_gets, server_output_write, connection_timer) folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.should_be_alive @logger.info('idle start...') server_output_write.call([ "+ continue\r\n" ]) server_response_thread = Thread.new{ res = new_bulk_response @logger.info('idle server response thread start...') folder.server_response_idle_wait{|server_response_list| for untagged_response in server_response_list @logger.debug("idle server response: #{untagged_response}") if @logger.debug? res << untagged_response server_output_write.call(res.flush) if res.full? end server_output_write.call(res.flush) unless res.empty? } @logger.info('idle server response thread terminated.') } begin connection_timer.command_wait or return line = client_input_gets.call ensure folder.server_response_idle_interrupt server_response_thread.join end last_res = [] if (line) then line.chomp!("\n") line.chomp!("\r") if (line.upcase == "DONE") then @logger.info('idle terminated.') last_res << "#{tag} OK IDLE terminated\r\n" else @logger.warn('unexpected client response and idle terminated.') @logger.debug("unexpected client response data: #{line}") if @logger.debug? last_res << "#{tag} BAD unexpected client response\r\n" end else @logger.warn('unexpected client connection close and idle terminated.') last_res << "#{tag} BAD unexpected client connection close\r\n" end yield(last_res) end
list(token, tag, ref_name, mbox_name) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1167 def list(token, tag, ref_name, mbox_name) res = new_bulk_response if (token) then folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } end if (mbox_name.empty?) then res << "* LIST (\\Noselect) NIL \"\"\r\n" else list_mbox(ref_name, mbox_name) {|mbox_entry| res << "* LIST #{mbox_entry}\r\n" yield(res.flush) if res.full? } end res << "#{tag} OK LIST completed\r\n" yield(res.flush) end
lsub(token, tag, ref_name, mbox_name) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1189 def lsub(token, tag, ref_name, mbox_name) res = new_bulk_response if (token) then folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } end if (mbox_name.empty?) then res << "* LSUB (\\Noselect) NIL \"\"\r\n" else list_mbox(ref_name, mbox_name) {|mbox_entry| res << "* LSUB #{mbox_entry}\r\n" yield(res.flush) if res.full? } end res << "#{tag} OK LSUB completed\r\n" yield(res.flush) end
noop(token, tag) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 949 def noop(token, tag) res = new_bulk_response if (token) then folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) begin @mail_store.read_synchronize(@read_lock_timeout_seconds) { folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } } rescue ReadLockTimeoutError @logger.warn("give up to get folder status because of read-lock timeout over #{@read_lock_timeout_seconds} seconds") end end res << "#{tag} OK NOOP completed\r\n" yield(res.flush) end
recovery_if_needed(username) { |"* OK [ALERT] start user data recovery.\r\n"| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 781 def recovery_if_needed(username) @mail_store.write_synchronize(@write_lock_timeout_seconds) { if (@mail_store.abort_transaction?) then @logger.warn("user data recovery start: #{username}") yield("* OK [ALERT] start user data recovery.\r\n") @mail_store.recovery_data(logger: @logger).sync @logger.warn("user data recovery end: #{username}") yield("* OK completed user data recovery.\r\n") self end } end
rename(token, tag, src_name, dst_name) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1076 def rename(token, tag, src_name, dst_name) res = new_bulk_response if (token) then folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } end src_name_utf8 = Net::IMAP.decode_utf7(src_name) dst_name_utf8 = Net::IMAP.decode_utf7(dst_name) unless (id = @mail_store.mbox_id(src_name_utf8)) then res << "#{tag} NO not found a mailbox\r\n" return yield(res.flush) end if (id == @mail_store.mbox_id('INBOX')) then res << "#{tag} NO not rename inbox\r\n" return yield(res.flush) end if (@mail_store.mbox_id(dst_name_utf8)) then res << "#{tag} NO duplicated mailbox\r\n" return yield(res.flush) end @mail_store.rename_mbox(id, dst_name_utf8) res << "#{tag} OK RENAME completed\r\n" yield(res.flush) end
search(token, tag, *cond_args, uid: false) { |"#{tag} NO [BADCHARSET (#{list.reject(&:dummy?).map(&:to_s).join(' ')})] unknown charset\r\n"| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1398 def search(token, tag, *cond_args, uid: false) folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.should_be_alive folder.reload if folder.updated? parser = SearchParser.new(@mail_store, folder, charset_aliases: @charset_aliases, charset_convert_options: @charset_convert_options) if (! cond_args.empty? && cond_args[0].upcase == 'CHARSET') then cond_args.shift charset_string = cond_args.shift or raise SyntaxError, 'need for a charset string of CHARSET' charset_string.is_a? String or raise SyntaxError, "CHARSET charset string expected as <String> but was <#{charset_string.class}>." begin parser.charset = charset_string rescue ArgumentError @logger.warn("unknown charset: #{charset_string}") return yield([ "#{tag} NO [BADCHARSET (#{Encoding.list.reject(&:dummy?).map(&:to_s).join(' ')})] unknown charset\r\n" ]) end end if (cond_args.empty?) then raise SyntaxError, 'required search arguments.' end if (cond_args[0].upcase == 'UID' && cond_args.length >= 2) then begin msg_set = folder.parse_msg_set(cond_args[1], uid: true) msg_list = folder.msg_find_all(msg_set, uid: true) cond_args.shift(2) rescue MessageSetSyntaxError msg_list = folder.each_msg end else begin msg_set = folder.parse_msg_set(cond_args[0], uid: false) msg_list = folder.msg_find_all(msg_set, uid: false) cond_args.shift rescue MessageSetSyntaxError msg_list = folder.each_msg end end cond = parser.parse(cond_args) res = new_bulk_response folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } res << '* SEARCH' begin begin for msg in msg_list begin if (cond.call(msg)) then if (uid) then res << " #{msg.uid}" else res << " #{msg.num}" end yield(res.flush) if res.full? end rescue EncodingError @logger.warn("encoding error at the message: uidvalidity(#{folder.mbox_id}) uid(#{msg.uid})") @logger.warn("#{$!} (#{$!.class})") end end ensure res << "\r\n" end rescue yield(res.flush) raise end res << "#{tag} OK SEARCH completed\r\n" yield(res.flush) end
select(token, tag, mbox_name) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 982 def select(token, tag, mbox_name) if (token) then close_no_response(token) end res = new_bulk_response new_token = nil mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name) if (id = @mail_store.mbox_id(mbox_name_utf8)) then new_token = open_folder(id) folder_open_msgs(new_token) {|untagged_response| res << untagged_response yield(res.flush) if res.full? } res << "#{tag} OK [READ-WRITE] SELECT completed\r\n" else res << "#{tag} NO not found a mailbox\r\n" end yield(res.flush) new_token end
status(token, tag, mbox_name, data_item_group) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1211 def status(token, tag, mbox_name, data_item_group) res = new_bulk_response if (token) then folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } end mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name) if (id = @mail_store.mbox_id(mbox_name_utf8)) then unless ((data_item_group.is_a? Array) && (data_item_group[0] == :group)) then raise SyntaxError, 'second arugment is not a group list.' end values = [] for item in data_item_group[1..-1] case (item.upcase) when 'MESSAGES' values << 'MESSAGES' << @mail_store.mbox_msg_num(id) when 'RECENT' values << 'RECENT' << @mail_store.mbox_flag_num(id, 'recent') when 'UIDNEXT' values << 'UIDNEXT' << @mail_store.uid(id) when 'UIDVALIDITY' values << 'UIDVALIDITY' << id when 'UNSEEN' unseen_flags = @mail_store.mbox_msg_num(id) - @mail_store.mbox_flag_num(id, 'seen') values << 'UNSEEN' << unseen_flags else raise SyntaxError, "unknown status data: #{item}" end end res << "* STATUS #{Protocol.quote(mbox_name)} (#{values.join(' ')})\r\n" res << "#{tag} OK STATUS completed\r\n" else res << "#{tag} NO not found a mailbox\r\n" end yield(res.flush) end
store(token, tag, msg_set, data_item_name, data_item_value, uid: false) { |"#{tag} NO cannot store in read-only mode\r\n"| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1514 def store(token, tag, msg_set, data_item_name, data_item_value, uid: false) folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.should_be_alive return yield([ "#{tag} NO cannot store in read-only mode\r\n" ]) if folder.read_only? folder.reload if folder.updated? msg_set = folder.parse_msg_set(msg_set, uid: uid) name, option = data_item_name.split(/\./, 2) case (name.upcase) when 'FLAGS' action = :flags_replace when '+FLAGS' action = :flags_add when '-FLAGS' action = :flags_del else raise SyntaxError, "unknown store action: #{name}" end case (option && option.upcase) when 'SILENT' is_silent = true when nil is_silent = false else raise SyntaxError, "unknown store option: #{option.inspect}" end if ((data_item_value.is_a? Array) && data_item_value[0] == :group) then flag_list = [] for flag_atom in data_item_value[1..-1] case (flag_atom.upcase) when '\ANSWERED' flag_list << 'answered' when '\FLAGGED' flag_list << 'flagged' when '\DELETED' flag_list << 'deleted' when '\SEEN' flag_list << 'seen' when '\DRAFT' flag_list << 'draft' else raise SyntaxError, "invalid flag: #{flag_atom}" end end rest_flag_list = (MailStore::MSG_FLAG_NAMES - %w[ recent ]) - flag_list else raise SyntaxError, 'third arugment is not a group list.' end msg_list = folder.msg_find_all(msg_set, uid: uid) for msg in msg_list case (action) when :flags_replace for name in flag_list @mail_store.set_msg_flag(folder.mbox_id, msg.uid, name, true) end for name in rest_flag_list @mail_store.set_msg_flag(folder.mbox_id, msg.uid, name, false) end when :flags_add for name in flag_list @mail_store.set_msg_flag(folder.mbox_id, msg.uid, name, true) end when :flags_del for name in flag_list @mail_store.set_msg_flag(folder.mbox_id, msg.uid, name, false) end else raise "internal error: unknown action: #{action}" end end res = new_bulk_response folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } if (is_silent) then res << "#{tag} OK STORE completed\r\n" yield(res.flush) else for msg in msg_list flag_atom_list = nil if (@mail_store.msg_exist? folder.mbox_id, msg.uid) then flag_atom_list = [] for name in MailStore::MSG_FLAG_NAMES if (@mail_store.msg_flag(folder.mbox_id, msg.uid, name)) then flag_atom_list << "\\#{name.capitalize}" end end end if (flag_atom_list) then if (uid) then res << "* #{msg.num} FETCH (UID #{msg.uid} FLAGS (#{flag_atom_list.join(' ')}))\r\n" else res << "* #{msg.num} FETCH (FLAGS (#{flag_atom_list.join(' ')}))\r\n" end yield(res.flush) if res.full? else @logger.warn("not found a message and skipped: uidvalidity(#{folder.mbox_id}) uid(#{msg.uid})") end end res << "#{tag} OK STORE completed\r\n" yield(res.flush) end end
subscribe(token, tag, mbox_name) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1105 def subscribe(token, tag, mbox_name) res = new_bulk_response if (token) then folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } end mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name) if (@mail_store.mbox_id(mbox_name_utf8)) then res << "#{tag} OK SUBSCRIBE completed\r\n" else res << "#{tag} NO not found a mailbox\r\n" end yield(res.flush) end
unsubscribe(token, tag, mbox_name) { |flush| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1124 def unsubscribe(token, tag, mbox_name) res = new_bulk_response if (token) then folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.server_response_fetch{|untagged_response| res << untagged_response yield(res.flush) if res.full? } end mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name) if (@mail_store.mbox_id(mbox_name_utf8)) then res << "#{tag} NO not implemented subscribe/unsbscribe command\r\n" else res << "#{tag} NO not found a mailbox\r\n" end yield(res.flush) end
Private Instance Methods
close_folder(token) { |"* #{msg_num} EXPUNGE\r\n"| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 808 def close_folder(token) @logger.debug("RIMS::Protocol::UserMailboxDecoder::Engine#close_folder: #{token}") if @logger.debug? folder = @folders.delete(token) or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) folder.reload if folder.updated? begin if (block_given?) then saved_recent_msgs = @mail_store.mbox_flag_num(folder.mbox_id, 'recent') folder.close do |msg_num| yield("* #{msg_num} EXPUNGE\r\n") end last_recent_msgs = @mail_store.mbox_flag_num(folder.mbox_id, 'recent') if (last_recent_msgs != saved_recent_msgs) then yield("* #{last_recent_msgs} RECENT\r\n") end else folder.close end ensure folder.detach end @mail_store.sync nil end
close_no_response(token)
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1356 def close_no_response(token) folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) close_folder(token) do |untagged_response| # IMAP CLOSE command may not send untagged EXPUNGE # responses, but notifies other connections of them. folder.server_response_multicast_push(untagged_response) end nil end
folder_open_msgs(token) { |"* #{all_msgs} EXISTS\r\n"| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 968 def folder_open_msgs(token) folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self) all_msgs = @mail_store.mbox_msg_num(folder.mbox_id) recent_msgs = @mail_store.mbox_flag_num(folder.mbox_id, 'recent') unseen_msgs = all_msgs - @mail_store.mbox_flag_num(folder.mbox_id, 'seen') yield("* #{all_msgs} EXISTS\r\n") yield("* #{recent_msgs} RECENT\r\n") yield("* OK [UNSEEN #{unseen_msgs}]\r\n") yield("* OK [UIDVALIDITY #{folder.mbox_id}]\r\n") yield("* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n") nil end
guard_authenticated(imap_command, token, tag, *args, exclusive: false, **kw_args) { |"#{tag} BAD write-lock timeout over #{write_lock_timeout_seconds} seconds"| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 866 def guard_authenticated(imap_command, token, tag, *args, exclusive: false, **kw_args, &block) if (exclusive.nil?) then if (kw_args.empty?) then __send__(imap_command, token, tag, *args, &block) else __send__(imap_command, token, tag, *args, **kw_args, &block) end else begin if (exclusive) then @mail_store.write_synchronize(@write_lock_timeout_seconds) { guard_authenticated(imap_command, token, tag, *args, exclusive: nil, **kw_args, &block) } else @mail_store.read_synchronize(@read_lock_timeout_seconds){ guard_authenticated(imap_command, token, tag, *args, exclusive: nil, **kw_args, &block) } end rescue ReadLockTimeoutError @logger.error("write-lock timeout over #{@write_lock_timeout_seconds} seconds") yield([ "#{tag} BAD write-lock timeout over #{@write_lock_timeout_seconds} seconds" ]) rescue WriteLockTimeoutError @logger.error("read-lock timeout over #{@read_lock_timeout_seconds} seconds") yield([ "#{tag} BAD read-lock timeout over #{@read_lock_timeout_seconds} seconds" ]) end end end
guard_selected(imap_command, token, tag, *args, **kw_args) { |"#{tag} NO not selected\r\n"| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 895 def guard_selected(imap_command, token, tag, *args, **kw_args, &block) if (token) then guard_authenticated(imap_command, token, tag, *args, **kw_args, &block) else yield([ "#{tag} NO not selected\r\n" ]) end end
list_mbox(ref_name, mbox_name) { |"(#{attrs}) NIL #{quote}"| ... }
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1143 def list_mbox(ref_name, mbox_name) ref_name_utf8 = Net::IMAP.decode_utf7(ref_name) mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name) mbox_filter = Protocol.compile_wildcard(mbox_name_utf8) mbox_list = @mail_store.each_mbox_id.map{|id| [ id, @mail_store.mbox_name(id) ] } mbox_list.keep_if{|id, name| name.start_with? ref_name_utf8 } mbox_list.keep_if{|id, name| name[(ref_name_utf8.length)..-1] =~ mbox_filter } for id, name_utf8 in mbox_list name = Net::IMAP.encode_utf7(name_utf8) attrs = '\Noinferiors' if (@mail_store.mbox_flag_num(id, 'recent') > 0) then attrs << ' \Marked' else attrs << ' \Unmarked' end yield("(#{attrs}) NIL #{Protocol.quote(name)}") end nil end
mailbox_size_server_response_multicast_push(mbox_id)
click to toggle source
# File lib/rims/protocol/decoder.rb, line 1254 def mailbox_size_server_response_multicast_push(mbox_id) all_msgs = @mail_store.mbox_msg_num(mbox_id) recent_msgs = @mail_store.mbox_flag_num(mbox_id, 'recent') f = @mail_store.open_folder(mbox_id, read_only: true) begin f.server_response_multicast_push("* #{all_msgs} EXISTS\r\n") f.server_response_multicast_push("* #{recent_msgs} RECENT\r\n") ensure f.close end nil end
new_bulk_response()
click to toggle source
# File lib/rims/protocol/decoder.rb, line 944 def new_bulk_response BulkResponse.new(@bulk_response_count, @bulk_response_size) end
open_folder(mbox_id, read_only: false)
click to toggle source
# File lib/rims/protocol/decoder.rb, line 795 def open_folder(mbox_id, read_only: false) folder = @mail_store.open_folder(mbox_id, read_only: read_only) token = folder.object_id if (@folders.key? token) then raise "internal error: duplicated folder token: #{token}" end @folders[token] = folder @logger.debug("RIMS::Protocol::UserMailboxDecoder::Engine#open_folder: #{token}") if @logger.debug? token end