MechanizeでサイボウズOffice6のメールを一括ダウンロード

こんな感じ。

require 'rubygems'
require 'mechanize'
require 'nkf'
require 'pp'
require 'readline'

class Cybozu
  attr_accessor :agent, :page

  def initialize(cgi = nil)
    @cgi = cgi || 'http://cybozu.local/scripts/ag.exe'
    @agent = WWW::Mechanize.new
    @agent.max_history = 1
  end

  def login
    puts "*** login"
    select_group && select_user
  end

  def select_group
    get 'page=LoginGroup'

    groups = @fields.name('Group').options.collect do |o| [o.value, o.text] end
    groups.each do |v, t| printf('%5s %s', v, t) end

    puts
    group = Readline.readline('グループを選択してください(終了=Enter): ')
    return false if group == ''
    @fields.name('Group').value = group.to_i
    submit
  end

  def select_user
    users = @fields.name('_ID').options.collect do |o| [o.value, o.text] end
    users.each do |v, t| printf('%5s %s', v, t) end

    puts
    user = Readline.readline('ユーザを選択してください(終了=Enter): ')
    return false if user == ''
    @fields.name('_ID').value = user.to_i

    puts
    @fields.name('Password').value = Readline.readline('パスワード: ')
    puts "\n" * 50
    submit
  end

  def get(query)
    @page = @agent.get "#{@cgi}?#{query}"
    @form = @page.forms.first
    @fields = @form.fields
    @page
  end

  def submit
    @page = @agent.submit @form
    @form = @page.forms.first
    @fields = @form.fields
    @page
  end

  def get_mbox
    puts "*** get_mbox"
    f = folders
    loop do
      printf("%3d %s\n", 0, "(すべて)")
      f.each_with_index do |a, i| printf("%3d %s\n", i + 1, a[1]) end
      puts
      buf = Readline.readline('フォルダを選択してください(終了=Enter): ')
      break if buf == ''
      if buf == '0'
        f.each do |a| get_folder *a end
        break
      else
        get_folder *f[buf.to_i - 1]
      end
    end
  end

  def folders
    get 'page=MyFolderIndex'
    uri = @page.uri

    @page.links.select do |l|
      l.href.match(/page=MyFolderIndex\&fid=\d+/)
    end.collect do |l|
      [uri + l.uri, l.text]
    end
  end

  def get_folder(folder_uri, save_dir)
    puts "*** get_folder: #{folder_uri}, #{save_dir}"
    mails(folder_uri).each do |m|
      Dir.mkdir(save_dir) rescue nil
      File.unlink("#{save_dir}/_mail_.txt") rescue nil
      get_mail m, save_dir
    end
    puts
  end

  def mails(folder_uri)
    ret = []
    @page = @agent.get(folder_uri)
    while true 
      uri = @page.uri

      ret += @page.links.select do |l|
        l.href.match(/page=(MailView|MailSent)/)
      end.collect do |l|
        uri + l.uri
      end
      if @page.links[-3].text.match(/次の \d+ 件へ >>/)
        @page = @agent.click @page.links[-3]
      else
        break
      end
    end 
    puts "#{ret.size} mails"
    ret
  end

  def get_mail(mail_uri, save_dir)
    puts "*** get_mail: #{mail_uri}, #{save_dir}"
    get_text(mail_uri, save_dir)
    get_attachments(mail_uri, save_dir)
    sleep 3
  end

  def get_text(mail_uri, save_dir)
    puts "*** get_text: #{mail_uri}, #{save_dir}"
    id = mail_uri.to_s.match(/eid=(\d+)/i)[1]
    uri = "#{@cgi}/notitle?page=MailFile&eid=#{id}&ct=1"
    @page = @agent.get(uri)

    file = "#{save_dir}/_mail_.txt"
    mode = File::CREAT | File::APPEND | File::RDWR
    File.open(file, mode) do |f|
      f.write(@page.body)
    end
  end

  def get_attachments(mail_uri, save_dir)
    puts "*** get_attachment: #{mail_uri}, #{save_dir}"
    attachments(mail_uri).each do |file_uri, file_name|
      file = "#{save_dir}/#{file_name}"
      mode = File::CREAT | File::RDWR | File::BINARY
      File.open(file, mode) do |f|
        puts "file: #{file}"
        f.write(@agent.get_file(file_uri))
      end unless File.exist?(file)
    end
  end

  def attachments(mail_uri)
    @page = @agent.get(mail_uri)
    uri = @page.uri
    ret = @page.links.select do |l|
      l.href && l.href.match(/page=(MailContents|PersonalDownload)/)
    end.collect do |l|
      [uri + href2uri(l.href), l.text]
    end
    puts "#{ret.size} attachments"
    ret
  end

  def href2uri(href)
    URI.parse(URI.encode(NKF.nkf('-e', href)))
  end
end

if __FILE__ == $0
  cy = Cybozu.new
  cy.login && cy.get_mbox
end