-require 'gdbm'
+require 'xdbm'
require 'time'
require 'net/pop'
require 'net/smtp'
#===============================================================================
#
-# 連番処理付き GDBM クラス
+# 連番処理付き XDBM クラス
#
-class SqGDBM < GDBM
+class SqXDBM < XDBM
@@start = 100
@@sym = '#last#'
#===============================================================================
#
-# フラグ処理/メール総数管理用 GDBM クラス
+# フラグ処理/メール総数管理用 XDBM クラス
#
-class FlagGDBM < GDBM
+class FlagXDBM < XDBM
@@n_mail_sym = '#n_mail#' # メール総数
@smtp_password = @account[:SMTP_PASSWORD]
@smtp_authtype = @account[:SMTP_AUTHTYPE]
@smtp_over_tls = @account[:SMTP_OVER_TLS]
+ @smtp_tls_certs = @account[:SMTP_TLS_CERTS]
@import_command = @account[:IMPORT_COMMAND]
@hash_id = Digest::MD5.hexdigest(@account[:USER_ADDRESS])[0, 8]
- @pop_uids = GDBM.new(@configs[:ROOT_DIRECTORY] + "/pop_uids_#{name}", 0600)
+ @pop_uids = XDBM.new(@configs[:ROOT_DIRECTORY] + "/pop_uids_#{name}", 0600)
end
#-----------------------------------------------------------
#
def smtp
begin
- Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE) if(@smtp_over_tls)
+ Net::SMTP.enable_tls(@smtp_over_tls, @smtp_tls_certs) if(@smtp_over_tls)
Net::SMTP.start(@smtp_server, @smtp_port, @smtp_helo, @smtp_account, @smtp_password, @smtp_authtype) {|smtp|
yield(_('Connected.'))
yield(smtp)
end
def close
- @pop_uids.reorganize
+ @pop_uids.reorganize; @pop_uids.close
end
end
#-----------------------------------------------------------
#
- # メールアカウントを順に渡す(有効なアカウントのみ)
+ # メールアカウントを順に渡す
#
- def each #### 適切な順序で返すようにする
+ def each(all = false) #### 適切な順序で返すようにする
@accounts.each {|name, account|
- yield(account) if(account.enable)
+ yield(account) if(account.enable or all)
}
end
end
def close
- each {|account| account.close }
+ each(all = true) {|account| account.close }
end
end
}
@cluster_paths << '' if(@cluster_paths.empty?)
- gdbm_flags = params[:CONFIGS][:GDBM_FLAGS]
- @filename_sq = SqGDBM.new(@path + '/filename_sq', 0600, gdbm_flags) # ベースファイル名<-メール連番
+ xdbm_flags = params[:CONFIGS][:XDBM_FLAGS]
+ @filename_sq = SqXDBM.new(@path + '/filename_sq', 0600, xdbm_flags) # ベースファイル名<-メール連番
end
#---------------------------------------- MaveDirectory ----
attr_reader :name # フォルダの名前
attr_reader :flags_sq
+ @@debug_what_scache = false
+
+ #--------------------------------------------- MaveFolder ----
+ #
+ # メールの概要キャッシュ(インクリメンタルサーチ用)表示、切り替え(デバッグ用)
+ #
+ def self.toggle_what_scache
+ @@debug_what_scache = !@@debug_what_scache
+ end
+
def initialize(params)
params[:PATH] = params[:CONFIGS][:ROOT_DIRECTORY] + '/' + params[:NAME]
super
@name = params[:NAME]
- gdbm_flags = params[:CONFIGS][:GDBM_FLAGS]
- @sq_rootsq = SqGDBM.new(@path + '/sq_rootsq', 0600, gdbm_flags) # メール連番<-最新順ルート連番
+ xdbm_flags = params[:CONFIGS][:XDBM_FLAGS]
+ @sq_rootsq = SqXDBM.new(@path + '/sq_rootsq', 0600, xdbm_flags) # メール連番<-最新順ルート連番
- @messageid_sq = GDBM.new(@path + '/messageid_sq', 0600, gdbm_flags) # メッセージID<-メール連番
- @sq_messageid = GDBM.new(@path + '/sq_messageid', 0600, gdbm_flags) # メール連番<-メッセージID
+ @messageid_sq = XDBM.new(@path + '/messageid_sq', 0600, xdbm_flags) # メッセージID<-メール連番
+ @sq_messageid = XDBM.new(@path + '/sq_messageid', 0600, xdbm_flags) # メール連番<-メッセージID
- @rootsq_sq = GDBM.new(@path + '/rootsq_sq', 0600, gdbm_flags) # ルートメール連番<-メール連番
- @parentsq_sq = GDBM.new(@path + '/parentsq_sq', 0600, gdbm_flags) # 親メール連番<-メール連番
- @childsqs_sq = GDBM.new(@path + '/childsqs_sq', 0600, gdbm_flags) # 子メール連番群<-メール連番 #### 統合不可?
+ @rootsq_sq = XDBM.new(@path + '/rootsq_sq', 0600, xdbm_flags) # ルートメール連番<-メール連番
+ @parentsq_sq = XDBM.new(@path + '/parentsq_sq', 0600, xdbm_flags) # 親メール連番<-メール連番
+ @childsqs_sq = XDBM.new(@path + '/childsqs_sq', 0600, xdbm_flags) # 子メール連番群<-メール連番 #### 統合不可?
- @flags_sq = FlagGDBM.new(@path + '/flags_sq', 0600, gdbm_flags) # 各種フラグ群<-メール連番
- [:RED, :FLAG, :NOTICE, :FOLD].each {|flag|
+ @abstract_sq = XDBM.new(@path + '/abstract_sq', 0600, xdbm_flags) # メール概要<-メール連番
+ @flags_sq = FlagXDBM.new(@path + '/flags_sq', 0600, xdbm_flags) # 各種フラグ群<-メール連番
+ [:RED, :FLAG, :NOTICE, :FOLD, :TOYOU].each {|flag|
@flags_sq.alloc_flag(flag)
}
@flags_sq.get_n || @flags_sq.reset_n # メール総数
sq ? MaveMail.new({:CONFIGS => @configs, :FILE => File.new(@path + '/' + @filename_sq[sq]), :FOLDER => self, :SQ => sq}) : nil
end
def get_mail_by_message_id(message_id)
- get_mail(@sq_messageid[message_id])
+ message_id and get_mail(@sq_messageid[message_id])
+ end
+
+ #------------------------------------------- MaveFolder ----
+ #
+ # 関連するメール連番を返す
+ #
+ def get_sq_by_message_id(message_id)
+ @sq_messageid[message_id]
+ end
+ def get_rootsq_by_sq(sq)
+ @rootsq_sq[sq]
end
-
+
#------------------------------------------- MaveFolder ----
#
- # メールの概要を返す
+ # メールの概要を内部コーディング(UTF-8)で返す
#
def abstract_of_mail(sq, mail, marks = {}, padding = '')
+ @@debug_what_scache and @abstract_sq[sq] and return(abstract_of_mail_for_search(sq, nil, marks))
'%s%c%c %3d %-*s %*s %4s %c%s %s%c%s' % [
marks.size == 0 ? '' : (marks[sq] ? 'M ' : '- '),
red?(sq) ? ?. : ?x,
notice?(sq) ? ?# : (flag?(sq) ? ?F : ?.),
(it = last_sq.to_i - sq.to_i) < 1000 ? it : 999,
fw = 16,
- @folder_configs[:SEND_VIEW] ? mail.pseudo_to.snip(fw) : mail.pseudo_from.snip(fw),
+ @folder_configs[:SEND_VIEW] ? mail.pseudo_to.snip(fw, 'UTF-8') : mail.pseudo_from.snip(fw, 'UTF-8'),
dw = Time.mystrftime_len,
mail.date ? mail.date.mystrftime : '-' * dw,
mail.size.to_h,
- ?., #### '.vw'[toyou?],
+ '.vw'[toyou?(sq)],
mail.multipart? ? '@' : '.',
padding,
'#+=-'[(padding == '' ? 0 : 2) + (fold?(sq) ? 0 : 1)],
#------------------------------------------- MaveFolder ----
#
+ # メールの概要キャッシュ(インクリメンタルサーチ用)を返す
+ #
+ def abstract_of_mail_for_search(sq, dummy = nil, marks = {})
+ '%s%c%c %3d %s' % [
+ marks.size == 0 ? '' : (marks[sq] ? 'M ' : '- '),
+ red?(sq) ? ?. : ?x,
+ notice?(sq) ? ?# : (flag?(sq) ? ?F : ?.),
+ (it = last_sq.to_i - sq.to_i) < 1000 ? it : 999,
+ @abstract_sq[sq] || (@abstract_sq[sq] = abstract_of_mail_for_search_cache(sq, get_mail(sq))),
+ ]
+ end
+ def abstract_of_mail_for_search_cache(sq, mail)
+ pseudo = @folder_configs[:SEND_VIEW] ? mail.pseudo_to : mail.pseudo_from
+ '%s %s %c%s %s %s' % [
+ mail.date ? mail.date.mystrftime(false) : '-', #### 日付を数字で持っておく手もある
+ mail.size.to_h,
+ '.vw'[toyou?(sq)],
+ mail.multipart? ? '@' : '.',
+ (it = phoneticize('%s %s' % [pseudo, mail.subject.decode_mh])) ? it : '', # 文字列の読み(ローマ字)表記
+ mail.subject.decode_mh,
+ ]
+ end
+ def delete_abstract(sq)
+ @abstract_sq.delete(sq) # メール概要を消す
+ end
+
+ #------------------------------------------- MaveFolder ----
+ #
# メール DB のリンク構造
#
# (@sq_rootsq)
# #### マークした折り畳み中のスレッドを結合する場合の扱い
#
def join_mail(sq, parent_sq)
+ (pp_sq = parent_sq) == sq and return(false) # 自分や自分の子には結合不可
+ while(pp_sq != @rootsq_sq[pp_sq])
+ (pp_sq = @parentsq_sq[pp_sq]) == sq and return(false)
+ end
+
unjoin_mail(sq) unless(@rootsq_sq[sq] == sq) # 自分がルート以外の場合
# @sq_rootsq.delete(x) == sq # 逆は表示時に消す
@filename_sq[sq = @filename_sq.last_sq] = filename
@messageid_sq[sq] = mail.message_id
@sq_messageid[mail.message_id] = sq
+# @abstract_sq[sq] = abstract_of_mail_for_search_cache(sq, mail) # メール概要登録
# 直近の親を捜す
parent_sqi = 0; it = nil
@flags_sq.dec_n # メール総数カウントダウン
@flags_sq.delete(sq)
+ @abstract_sq.delete(sq) # メール概要を消す
delete(@filename_sq.delete(sq)) # ファイル本体を消す
@dirty += 1
@dirty += 1
end
+ def toyou(sq)
+ @flags_sq.set_flag(sq, :TOYOU, ?T)
+ @dirty += 1
+ end
+ def ccyou(sq)
+ @flags_sq.set_flag(sq, :TOYOU, ?C)
+ @dirty += 1
+ end
+ def toyou?(sq)
+ '-CT'.index(@flags_sq.get_flag(sq, :TOYOU)) || 0
+ end
+
#------------------------------------------- MaveFolder ----
#
# メールの添付ファイルを展開する
fh.write(line + "\n")
}
}
- mail = MavePseudoMail.new({:CONFIGS => @configs, :FILE => File.new(path + '/' + halfname)})
- overwrite_mail(mail, source_mail)
+ mail = MavePseudoMail.new({:CONFIGS => @configs, :FILE => (xmail = File.new(path + '/' + halfname))})
+ overwrite_mail(xmail, source_mail)
delete(halfname) unless(RUBY_PLATFORM =~ /i.86-mswin32/) ####
@dirty += 1 ####
end
@rootsq_sq.reorganize; @rootsq_sq.close
@parentsq_sq.reorganize; @parentsq_sq.close
@childsqs_sq.reorganize; @childsqs_sq.close
+ @abstract_sq.reorganize; @abstract_sq.close
@flags_sq.reorganize; @flags_sq.close
super
end
File.open(folder.config_filename, 'w', 0600) {|fw| fw.write(new_configs.read) }
close_folder(folder.name); open_folder(folder.name)
end
+
+ def close
+ each {|folder| folder.close }
+ end
end
#===============================================================================
@boundary = params[:BOUNDARY]
@folder = params[:FOLDER]
@sq = params[:SQ]
+ @size = 0; size
parse_header
parse_body if(@file.is_a?(File))
# メールのサイズを返す
#
def size
- @file.lstat.size
+ @size = @file.lstat.size rescue @size
end
#--------------------------------------------- MaveMail ----
# メール情報を返す
#
def identify
+ yield([_(' Message-Sq: %s'), sq])
yield([_(' Message-ID: %s'), message_id])
yield([_(' FilePath: %s'), path])
yield([_(' FileSize: %d'), size])
elsif(header == 'bcc')
yield("Bcc: #{ @@address_book.encode(bcc, 'SEND:')}\n")
elsif(header == 'subject')
- yield("Subject: #{subject.encode_mh}\n")
+ subject.encode_mh_multi('Subject') {|mhline| yield(mhline + "\n") }
elsif(header == 'date')
yield("Date: #{Time.now.rfc2822}\n") # Date は現時刻に変更
elsif(header == 'x-mave-extract-targets')
raise("Mail format error '#{line.inspect}'")
end
else
- yield((line + "\n").tojis) #### ボディを仲介(現状は JIS 固定)
+ yield(NKF.nkf('-jWm0', line) + "\n") #### ボディを仲介(現状は JIS 固定)
end
}
end
def initialize(params)
super
- gdbm_flags = params[:CONFIGS][:GDBM_FLAGS]
- @address_db = GDBM.new(@configs[:ROOT_DIRECTORY] + '/mave.address', 0600, gdbm_flags)
+ xdbm_flags = params[:CONFIGS][:XDBM_FLAGS]
+ @address_db = XDBM.new(@configs[:ROOT_DIRECTORY] + '/mave.address', 0600, xdbm_flags)
end
#-------------------------------------- MaveAddressBook ----
}
mailboxes.join(', ')
end
+
+ def close
+ @address_db.reorganize; @address_db.close
+ end
end
#===============================================================================
@text = text
@dirty += 1
end
+
+ #------------------------------------------ MaveTextBox ----
+ #
+ # 文字列を内部エンコーディングで返す
+ #
+ def utf8_text
+ @text.decode_cs('UTF-8', @configs[:TERMINAL_CHARSET])
+ end
end
#===============================================================================