docomo_web_mailer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.5.1"
12
+ gem "rcov", ">= 0"
13
+ gem "mechanize", ">= 1.0"
14
+ gem "json", ">= 0"
15
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2010 nazoking@gmail.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,64 @@
1
+ = docomo_web_mailer
2
+
3
+ == DESCRIPTION:
4
+
5
+ Docomo Web Mail Scraiper
6
+
7
+ Docomo Web Mail is http://dwmail.jp/
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * フォルダのリストを得ることが出来ます。
12
+ * フォルダ内のメールのリストを得ることが出来ます。
13
+ * メールのヘッダを得ることが出来ます。
14
+ * メールのmimeパートを得ることが出来ます。
15
+ * メールの添付ファイルを得ることが出来ます。
16
+ * 得たメールをsmtp用の文章に変換することが出来ます。
17
+
18
+ * メールを送ったり削除することは出来ません。
19
+
20
+
21
+ == SYNOPSIS:
22
+
23
+ メール転送の例
24
+ login_id , password = dwmail のid,password
25
+ your_smtp_server = smtpサーバ
26
+ forwarding_mail_address = 転送先
27
+
28
+ mailer = DocomoWebMailer.new
29
+ mailer.login( login_id, password )
30
+ maillist = mailer.mail_list_start(mailer.mail_label_list[:inbox],1000)
31
+ #nextmaillist = mailer.mail_list_get(maillist,1001,1000)
32
+ Net::SMTP.start( your_smtp_server, 25 ) {|smtp|
33
+ for mail in maillist
34
+ smtp.send_mail mailer.make_mail_to_smtp( mail ), mail.from, forwarding_mail_address
35
+ end
36
+ }
37
+
38
+ == REQUIREMENTS:
39
+
40
+ * mechanize >= 1.0
41
+ * json
42
+
43
+ == INSTALL:
44
+
45
+ * gem install docomo_web_mailer
46
+
47
+ == Contributing to docomo_web_mailer
48
+
49
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
50
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
51
+ * Fork the project
52
+ * Start a feature/bugfix branch
53
+ * Commit and push until you are happy with your contribution
54
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
55
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
56
+
57
+ == Copyright
58
+
59
+ nazoking@gmail.com
60
+
61
+ (The MIT License)
62
+ Copyright (c) 2010 nazoking. See LICENSE.txt for
63
+ further details.
64
+
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "docomo_web_mailer"
16
+ gem.homepage = "http://github.com/nazoking/docomo_web_mailer"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Docomo Web Mail Client}
19
+ gem.description = %Q{Docomo Web Mail ( http://dwmail.jp/ ) をRubyからいじることの出来るライブラリです。現在は受信のみ対応しており、送信や削除することは出来ません。 }
20
+ gem.email = "nazoking@gmail.com"
21
+ gem.authors = ["nazoking"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ gem.add_runtime_dependency 'mechanize', '> 1.0'
25
+ gem.add_runtime_dependency 'json'
26
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
27
+ end
28
+ Jeweler::RubygemsDotOrgTasks.new
29
+
30
+ require 'rake/testtask'
31
+ Rake::TestTask.new(:test) do |test|
32
+ test.libs << 'lib' << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+
37
+ require 'rcov/rcovtask'
38
+ Rcov::RcovTask.new do |test|
39
+ test.libs << 'test'
40
+ test.pattern = 'test/**/test_*.rb'
41
+ test.verbose = true
42
+ end
43
+
44
+ task :default => :test
45
+
46
+ require 'rake/rdoctask'
47
+ Rake::RDocTask.new do |rdoc|
48
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "docomo_web_mailer #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,76 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{docomo_web_mailer}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["nazoking"]
12
+ s.date = %q{2010-11-19}
13
+ s.description = %q{Docomo Web Mail ( http://dwmail.jp/ ) をRubyからいじることの出来るライブラリです。現在は受信のみ対応しており、送信や削除することは出来ません。 }
14
+ s.email = %q{nazoking@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "LICENSE.txt",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "docomo_web_mailer.gemspec",
27
+ "lib/docomo_web_mailer.rb",
28
+ "lib/docomo_web_mailer/convert_mail.rb",
29
+ "test/helper.rb",
30
+ "test/test_docomo_web_mailer.rb"
31
+ ]
32
+ s.homepage = %q{http://github.com/nazoking/docomo_web_mailer}
33
+ s.licenses = ["MIT"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = %q{1.3.7}
36
+ s.summary = %q{Docomo Web Mail Client}
37
+ s.test_files = [
38
+ "test/helper.rb",
39
+ "test/test_docomo_web_mailer.rb"
40
+ ]
41
+
42
+ if s.respond_to? :specification_version then
43
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
44
+ s.specification_version = 3
45
+
46
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
47
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
48
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
49
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
50
+ s.add_development_dependency(%q<rcov>, [">= 0"])
51
+ s.add_development_dependency(%q<mechanize>, [">= 1.0"])
52
+ s.add_development_dependency(%q<json>, [">= 0"])
53
+ s.add_runtime_dependency(%q<mechanize>, ["> 1.0"])
54
+ s.add_runtime_dependency(%q<json>, [">= 0"])
55
+ else
56
+ s.add_dependency(%q<shoulda>, [">= 0"])
57
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
58
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
59
+ s.add_dependency(%q<rcov>, [">= 0"])
60
+ s.add_dependency(%q<mechanize>, [">= 1.0"])
61
+ s.add_dependency(%q<json>, [">= 0"])
62
+ s.add_dependency(%q<mechanize>, ["> 1.0"])
63
+ s.add_dependency(%q<json>, [">= 0"])
64
+ end
65
+ else
66
+ s.add_dependency(%q<shoulda>, [">= 0"])
67
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
68
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
69
+ s.add_dependency(%q<rcov>, [">= 0"])
70
+ s.add_dependency(%q<mechanize>, [">= 1.0"])
71
+ s.add_dependency(%q<json>, [">= 0"])
72
+ s.add_dependency(%q<mechanize>, ["> 1.0"])
73
+ s.add_dependency(%q<json>, [">= 0"])
74
+ end
75
+ end
76
+
@@ -0,0 +1,478 @@
1
+ #= ドコモWebメールクライアント
2
+ # ドコモWebメール
3
+ # http://dwmail.jp/
4
+ # のメールを読みます。
5
+ #
6
+ #==example
7
+ # メールを forwarding_mail_address へ転送する。
8
+ # mailer = DocomoWebMailer.new
9
+ # mailer.login( login_id, password )
10
+ # maillist = mailer.mail_list_start(mailer.mail_label_list[:inbox],10)
11
+ # #nextmaillist = mailer.mail_list_get(maillist,11,10)
12
+ # Net::SMTP.start( your_smtp_server, 25 ) {|smtp|
13
+ # for mail in maillist
14
+ # puts "#{mail.uid}:#{mail.subject} (#{mail.from})"
15
+ # smtp.send_mail mailer.make_mail_to_smtp( mail ), mail.from[0][1], forwarding_mail_address
16
+ # end
17
+ # }
18
+ #
19
+ require 'rubygems'
20
+ require 'json'
21
+ require 'mechanize'
22
+ require 'cgi'
23
+ require 'base64'
24
+
25
+ class DocomoWebMailer
26
+ # メールボックスの最大値?
27
+ MAX_SIZE=10000
28
+ # コンストラクタ
29
+ def initialize()
30
+ @agent = Mechanize.new
31
+ @id = 0
32
+ @agent.user_agent_alias = 'Mac Safari'
33
+ end
34
+ # ログインする。失敗するとexception
35
+ def login(id,password)
36
+ page = @agent.get("http://dwmail.jp/")
37
+ form = page.form_with(:name => "f1")
38
+ raise "login error: cant find login form" unless form
39
+ form.field_with(:name => "uname").value = id
40
+ form.field_with(:name => "pass").value = password
41
+ res = @agent.submit(form)
42
+ raise "login error (id/pass illegal) " if res.form_with(:name => "f1")
43
+ end
44
+ # MailLabel のメールを得る。uid順。limit個。Maillistを返す。
45
+ # maillabel の値がSymbolならサーバフォルダ、文字列ならユーザフォルダ。
46
+ def mail_list_start(maillabel,limit)
47
+ place = [ A(:server_folder), A(maillabel) ]
48
+ if maillabel.is_a? MailLabel
49
+ place = [ A(maillabel.place), A(maillabel.index) ]
50
+ elsif maillabel.is_a? String
51
+ place[0]['$A']="user_folder"
52
+ end
53
+ Maillist.new( *rcp("mail_list_start",[ 1, T( nil, T(
54
+ # 得たいフォルダの場所
55
+ [ T(*place) ],
56
+ # 不明
57
+ [ ],
58
+ # 不明
59
+ [ T( A(:client_flag), A(:recent) ) ],
60
+ # 得たい付加情報?
61
+ [ A(:server_flag), A(:client_flag), A(:server_folder), A(:user_folder), A(:user_flag) ]
62
+ ) ),
63
+ # 並び順と数?
64
+ T( T( A(:plain), A(:uid) ), A(:descending), nil, limit ),
65
+ # 不明
66
+ nil, MAX_SIZE, MAX_SIZE ]) )
67
+ end
68
+ # Maillistの続きのメールを得る。uid順。startからlimit個。新しいMaillistを返す。
69
+ def mail_list_get(maillist, start,limit )
70
+ Maillist.new( *rcp( "mail_list_get", [ maillist.sign, T( T( A(:plain), A(:uid) ), A(:descending), start, limit ), MAX_SIZE ] ) )
71
+ end
72
+ # uid で指定したメールの全パート情報を得る。Mailpartsを返す。
73
+ # uid は to_uid によって変換される
74
+ def mail_get_parts(uid)
75
+ Mailparts.new *rcp("mail_get_parts", [ to_uid(uid), [ T( A(:bodypref), [ "*/*" ] ), T( A(:bodyparse), A(:off) ) ], MAX_SIZE ])
76
+ end
77
+ # そのパートの添付ファイルを得る。String型のバイナリデータ。
78
+ # mimepart は Mimepart型
79
+ def attachment(mimepart)
80
+ url = "/pc/attachment.php?url=#{u(mimepart.attache_info)}"
81
+ url += "&df=#{u(mimepart.filename.to_s)}" if mimepart.filename
82
+ @agent.get_file(url)
83
+ end
84
+ # ラベル(フォルダ)の一覧 MailLabelList を得る。
85
+ def mail_label_list
86
+ MailLabelList.new( *rcp( "mail_label", [ [
87
+ T( A(:list), [ A(:server_folder) ], A(:ascending) ),
88
+ T( A(:list), [ A(:user_folder) ], A(:ascending) ),
89
+ T( A(:list), [ A(:user_flag) ], A(:ascending) )
90
+ ], 10000 ] ) )
91
+ end
92
+ # uid で指定したメールのヘッダ(AllMailHeaders)を得る。
93
+ # uid は to_uid によって変換される
94
+ def mail_get_headers(maillistitem)
95
+ AllMailHeaders.new *rcp( "mail_get_headers", [ to_uid(maillistitem), A(:infinity) ] )
96
+ end
97
+ # uid で指定したメールのSMTP送信用テキストを作る
98
+ # uid は to_uid によって変換される
99
+ def make_mail_to_smtp(uid)
100
+ Builder.new(self).build( uid )
101
+ end
102
+ # uid で指定したメールにclient_flagをたてる。
103
+ # uid は to_uid によって変換される
104
+ def append_client_flag(uid,flag="flagged")
105
+ rcp( "mail_label", [ [ T( A(:append), T( A(:client_flag), A(flag) ), null, [ to_uid(uid) ] ) ], 10000 ] )
106
+ end
107
+ # uid で指定したメールからclient_flagを外す。
108
+ # uid は to_uid によって変換される
109
+ def remove_client_flag(uid,flag="flagged")
110
+ rcp( "mail_label", [ [ T( A(:remove), T( A(:client_flag), A(flag) ), null, [ to_uid(uid) ] ) ], 10000 ] )
111
+ end
112
+ # maillistitem を uid にする。文字列なら数値化、数値以外ならuidプロパティーの値を返す
113
+ def to_uid( maillistitem )
114
+ maillistitem = maillistitem.to_i if maillistitem.is_a? String
115
+ maillistitem = maillistitem.uid unless maillistitem.is_a? Numeric
116
+ maillistitem
117
+ end
118
+
119
+ def A(str) # :nodoc:
120
+ {'$A'=>str.to_s}
121
+ end
122
+ def T(*array) # :nodoc:
123
+ {'$T'=>array}
124
+ end
125
+
126
+ # SMTPサーバに送信するためのメールテキストを作成する。
127
+ # 他のメールソフト・メールライブラリで扱うための中間形式としても。
128
+ class Builder
129
+ @mailer
130
+ def initialize(mailer)
131
+ @mailer = mailer
132
+ end
133
+ # uid からメールテキストを作成する
134
+ # 引数 uid には to_uid が適用される。
135
+ def build(uid)
136
+ build_from @mailer.mail_get_headers(uid), @mailer.mail_get_parts(uid)
137
+ end
138
+ # header と parts からメールテキストを作成する
139
+ def build_from(headers,parts)
140
+ headers.multipart? ? make_mail_to_smtp_multipart( headers, parts ) : make_mail_to_smtp_singlepart( headers, parts.parts[0] )
141
+ end
142
+
143
+ # AllMailHeaders と Mimepart からメールのSMTP送信用テキストを作る(シングル)
144
+ def make_mail_to_smtp_singlepart(headers,part)
145
+ headers.to_s + "\n\n" + @mailer.attachment( part )
146
+ end
147
+ # AllMailHeaders と Mailparts からメールのSMTP送信用テキストを作る(マルチパート)
148
+ def make_mail_to_smtp_multipart(headers,parts)
149
+ raise "unknown type header #{text}" unless headers.content_type =~ /boundary=(.*)$/
150
+ boundary = $1.dup.strip.gsub(/^"(.*)"$/,'\1').gsub(/^'(.*)'$/,'\1')
151
+
152
+ headers.to_s +
153
+ "\n\n--#{boundary}\n" +
154
+ parts.parts.map{|part| part_to_mail(part).join("\n")}.join("\n--#{boundary}\n") +
155
+ "\n--#{boundary}--\n"
156
+ end
157
+ # Mimepart をsmtp bodyに
158
+ def part_to_mail(part)
159
+ body = @mailer.attachment( part )
160
+ content_type = part.content_type
161
+ is_text = content_type =~ /^text\//
162
+ mail = []
163
+ mail << "Content-Type: #{content_type}"
164
+ mail << "Content-Transfer-Encoding: #{is_text ? '8bit' : 'base64' }"
165
+ mail << "Content-ID: #{part.contentid}" if part.contentid
166
+ mail << "Content-Disposition: #{part.disposition_with_filename}" if part.disposition
167
+ mail << ""
168
+ mail << ( is_text ? body : Base64.encode64(body) )
169
+ mail
170
+ end
171
+ end
172
+ # rcp 1.0 にパラメータを投げる
173
+ def rcp( method,params )
174
+ @id += 1
175
+ result = Parser.rcp_to_ruby(JSON.parse(@agent.post("http://pc.dwmail.jp/api/base/rpc/1.0", {
176
+ :id => @id.to_s,
177
+ :method => method.to_s,
178
+ :params => params,
179
+ :version=>"1.1"
180
+ }.to_json ).body))
181
+ unless result["error"]
182
+ return result["result"]
183
+ else
184
+ require 'pp'
185
+ pp result['error']
186
+ pp params
187
+ raise "error ! #{result['error']}"
188
+ end
189
+ end
190
+ # rcp で返ってきたデータをRubyフレンドリーにする
191
+ class Parser
192
+ # rcp で返ってきたHashデータをRubyフレンドリーにする
193
+ def self.hash_to_ruby(data)
194
+ ret = {}
195
+ for k,v in data
196
+ ret[k]=rcp_to_ruby(v)
197
+ end
198
+ return ret
199
+ end
200
+ # rcp で返ってきたデータをRubyフレンドリーにする
201
+ def self.rcp_to_ruby(data)
202
+ case data
203
+ when Hash
204
+ if data.keys.size==1
205
+ case data.keys[0]
206
+ when '$T'
207
+ if data["$T"].is_a? Array
208
+ return TArray.new(data)
209
+ end
210
+ when '$A'
211
+ if data["$A"].is_a? String
212
+ return data["$A"].to_sym
213
+ end
214
+ end
215
+ end
216
+ if data['$R'] and data['$R'].is_a? String
217
+ # data type is data['$R']
218
+ case data['$R']
219
+ when 'mailheaders'
220
+ return Mailheaders.new( data )
221
+ when 'mailsummary'
222
+ return Mailsummary.new( data )
223
+ when 'mimepartspec'
224
+ return Mimepartspec.new( data )
225
+ end
226
+ end
227
+ return hash_to_ruby(data)
228
+ when Array
229
+ ret = []
230
+ for v in data
231
+ ret << rcp_to_ruby(v)
232
+ end
233
+ return ret
234
+ end
235
+ return data
236
+ end
237
+ end
238
+ # Structの用に扱えるハッシュ。{ '$R'=>クラス名, .... } 形式のハッシュを扱うために用いる
239
+ class RHash
240
+ def initialize(data)
241
+ raise "invalid parameta" unless data.is_a? Hash
242
+ @data = Parser.hash_to_ruby(data)
243
+ @data.delete('$R')
244
+ end
245
+ # ハッシュのキーをメソッドのようにも使える
246
+ def method_missing(sym, *args, &block)
247
+ if @data.has_key? sym.to_s
248
+ @data[sym.to_s]
249
+ else
250
+ @data.send sym, *args, &block
251
+ end
252
+ end
253
+ def inspect #:nodoc:
254
+ "#{self.class.to_s.split('::').last}"+@data.inspect
255
+ end
256
+ end
257
+ # { '$T'=> [ ] } 形式の配列データ
258
+ class TArray < Array
259
+ def initialize(data)
260
+ super(Parser.rcp_to_ruby(data['$T']))
261
+ end
262
+ def inspect #:nodoc:
263
+ "T"+super
264
+ end
265
+ end
266
+ # メールのヘッダ
267
+ # 主なプロパティーに次の値がある
268
+ # cc :: ccの宛先 ( ["ラベル","メールアドレス"]の配列 )
269
+ # from :: 差出人 ( ["ラベル","メールアドレス"]の配列 )
270
+ # bcc :: bccの宛先( ["ラベル","メールアドレス"]の配列 )
271
+ # to :: toの宛先 ( ["ラベル","メールアドレス"]の配列 )
272
+ # date :: 日付(エポック秒)
273
+ # subject :: メールタイトル(デコード済み)
274
+ # othres :: その他のヘッダ( [ "ヘッダ名:値" ] の配列 )
275
+ # in_replay_to :: 用途不明
276
+ # references :: 用途不明
277
+ # message_id :: メッセージID
278
+ class Mailheaders < RHash
279
+ def initialize(data)
280
+ super
281
+ end
282
+ end
283
+ # メールのサマリ。一覧表示などに使う
284
+ # 主なプロパティーに次の値がある
285
+ # bytes :: メールのバイト数
286
+ # mailheaders :: メールのヘッダ(Mailheadersクラス)
287
+ # uid :: ユニークid
288
+ # versionid :: 用途不明
289
+ # attachments :: 添付ファイル名のリスト
290
+ # created :: 受信日(エポック秒)
291
+ class Mailsummary < RHash
292
+ def initialize(data)
293
+ super
294
+ end
295
+ # メールのヘッダ(Mailheadersクラス)
296
+ def mailheaders
297
+ @data["mailheaders"]
298
+ end
299
+ def method_missing(sym, *args, &block)
300
+ if @data.has_key? sym.to_s
301
+ @data[sym.to_s]
302
+ elsif mailheaders.has_key? sym.to_s
303
+ mailheaders[sym.to_s]
304
+ end
305
+ end
306
+ end
307
+ # mimeパートのヘッダ
308
+ # 主なプロパティーに次の値がある
309
+ # conentid :: Content-ID
310
+ # bytes :: 用途不明
311
+ # content_type :: Content-Type
312
+ # disposition :: Content-Disposition
313
+ # filename :: ファイル名
314
+ # first_byte_offset :: 用途不明
315
+ # vertionid :: 用途不明
316
+ class Mimepartspec < RHash
317
+ def initialize(data)
318
+ super
319
+ end
320
+ # ファイル名付きのContent-Dispositionを得る
321
+ def disposition_with_filename
322
+ @data['filename'] ? "#{@data['disposition']}; filename=#{@data['filename']}" : @data['disposition']
323
+ end
324
+ end
325
+ # メールのリストのアイテム
326
+ class MailListItem
327
+ # リスト内での位置( 一番上が1 )
328
+ attr_reader :order
329
+ # メールのサマリ(Mailsummary)
330
+ attr_reader :summary
331
+ # 用途不明
332
+ attr_reader :flag
333
+ def initialize( order, summary, flag )
334
+ @order , @summary, @flag = order, summary, flag
335
+ end
336
+ # summary に委譲
337
+ def method_missing(sym, *args, &block)
338
+ @summary.send sym, *args, &block
339
+ end
340
+ end
341
+ # メールの一つのmimeパート
342
+ class Mimepart
343
+ # Mimepartspec
344
+ attr_reader :spec
345
+ # メール本文(HTML化されている)
346
+ attr_reader :body
347
+ # 用途不明。ヘッダが [ ["content-type", "text/plain"] ] のような形で入るようだ
348
+ attr_reader :inline_head
349
+ # attache を得るためのキー
350
+ attr_reader :attache_info
351
+ def initialize( specs, inline )
352
+ @spec, @attache_info = specs
353
+ @inline_head, @body = inline if inline
354
+ end
355
+ # spec に委譲
356
+ def method_missing(sym, *args, &block)
357
+ @spec.send sym, *args, &block
358
+ end
359
+ # より正しい content-type を得る( inline_head に content-type があればそちらを持ってくる )
360
+ def content_type_more(part)
361
+ for n,v in inline_head
362
+ return v if n == 'content-type'
363
+ end if inline_head
364
+ return @spec.content_type
365
+ end
366
+ end
367
+ # フォルダ内のメールのリスト
368
+ class Maillist < Array
369
+ # mail_list_get 時に使われるキー
370
+ attr_reader :sign
371
+ # :ok なら取得成功
372
+ attr_reader :status
373
+ # おそらくメールボックス内のメールの数。mail_list_get 時は無効
374
+ attr_reader :max_size
375
+ def initialize( status, sign, mails, max_size=nil )
376
+ @status, @sign, @max_size = status, sign, max_size
377
+ for mail in mails
378
+ self << MailListItem.new( *mail )
379
+ end
380
+ end
381
+ end
382
+ # メールの詳細情報。複数のmimeパートを含むデータ
383
+ class Mailparts
384
+ # :ok なら取得成功
385
+ attr_reader :status
386
+ # Mimepart の配列
387
+ attr_reader :parts
388
+ # ヘッダ
389
+ attr_reader :header
390
+ def initialize( status , header, parts )
391
+ @status , @header = status, header
392
+ @parts = parts.map{|data| Mimepart.new( *data )}
393
+ end
394
+ def [](num)
395
+ @parts[num]
396
+ end
397
+ end
398
+ # メールのヘッダ。素の形に近い( Mimepartspec などは利用しやすいが失われている情報が多い)
399
+ class AllMailHeaders
400
+ # :ok なら取得成功
401
+ attr_reader :status
402
+ # ヘッダ。[ ["ヘッダ名","ヘッダ値"] ... ] の形式で格納されている。
403
+ attr_reader :header
404
+ def initialize(status, header)
405
+ @status, @header = status, header
406
+ end
407
+ # メールのヘッダの形にして返す
408
+ def to_s
409
+ @header.map{|k,v| "#{k}: #{v}" }.join("\n")
410
+ end
411
+ # header に委譲
412
+ def method_missing(sym, *args, &block)
413
+ @header.send sym, *args, &block
414
+ end
415
+ # header から 対応する名前のヘッダの値を返す。複数ある場合は最初のものを返す。
416
+ def []( name )
417
+ @header.find{|n,a| n==name }[1]
418
+ end
419
+ # header から content-type の値を得る
420
+ def content_type
421
+ ['content-type']
422
+ end
423
+ # マルチパートか否か
424
+ def multipart?
425
+ content_type =~ /^multipart\//
426
+ end
427
+ end
428
+ # メールのラベル(フォルダ)一つを表す
429
+ class MailLabel
430
+ # 場所。:server_folder, :user_folder, :user_flag がある
431
+ attr_reader :place
432
+ # システム名。place=server_folder の時は名前を表すシンボル、それ以外の時は連番
433
+ # 名前を表すシンボルは :draft, :inbox, :sent, :trash, :upload がある
434
+ attr_reader :index
435
+ # 名前。メルマガフォルダの時は __MM__ が接頭辞としてつく( 例: "__MM__雑誌" )
436
+ attr_reader :name
437
+ # フォルダ内のメールの数
438
+ attr_reader :num
439
+ # 用途不明
440
+ attr_reader :num2
441
+ def initialize(systemname, name, num, num2)
442
+ @name, @num, @num2 = name, num, num2
443
+ @place, @index = systemname
444
+ end
445
+ end
446
+ # メールのラベル(フォルダ)リストを表す
447
+ class MailLabelList
448
+ # サーバフォルダ(既定のフォルダ)のリスト。MailLabel の配列である。
449
+ attr_reader :server_folders
450
+ # 個人フォルダ(およびメルマガフォルダ)のリスト。MailLabel の配列である。
451
+ attr_reader :user_folders
452
+ # ユーザフラグのリスト(用途不明)。MailLabel の配列である。
453
+ attr_reader :user_flags
454
+ # 戻りステータス :ok なら異常なし(詳細不明)
455
+ attr_reader :status
456
+ def initialize(status, data)
457
+ @status = status
458
+ @server_folders,@user_folders,@user_flags = data.map{|a| a.map{|l| MailLabel.new(*l) }}
459
+ end
460
+ # 名前でラベル(フォルダ)を選ぶ
461
+ # nameがシンボルならサーバフォルダから、文字列ならユーザフォルダから選ぶ。
462
+ # 数字ならユーザフォルダのインデックスとして選ぶ。
463
+ def [](name)
464
+ if name.is_a? Symbol
465
+ return @server_folders.find{|a| a.index == name}
466
+ elsif name.is_a? Numeric
467
+ return @user_folders.find{|a| a.index == name}
468
+ else
469
+ return @user_folders.find{|a| a.name == name}
470
+ end
471
+ raise "invalid label key #{name}"
472
+ end
473
+ end
474
+ private
475
+ def u(str) #:nodoc:
476
+ CGI.escape(str)
477
+ end
478
+ end
@@ -0,0 +1,49 @@
1
+ class DocomoWebMailer
2
+ def convert_mail(header)
3
+ text = headers.to_s
4
+ text += "\n\n"
5
+ if parts.parts.size == 1
6
+ data = mail_get_attache( parts.parts[0] )
7
+ text +="#{data}"
8
+ else
9
+ h = nil
10
+ raise "unknown type header #{text}" unless headers.find{|k,v| k == "content-type" and v =~ /boundary=(.*)$/}
11
+ boundary = $1.dup.strip.gsub(/^"(.*)"$/,'\1').gsub(/^'(.*)'$/,'\1')
12
+ for part in parts.parts
13
+ body = mail_get_attache( part )
14
+ header = []
15
+ header << "--#{boundary}"
16
+ content_type = part.content_type
17
+ if part.inline_head and part.inline_head.find{|n,v| n == 'content-type'}
18
+ content_type = part.inline_head.find{|n,v| n == 'content-type'}[1]
19
+ end
20
+ puts "content_type=#{content_type}"
21
+ header << "Content-Type: #{content_type}"
22
+ is_text = content_type =~ /^text\//
23
+ if is_text
24
+ header << "Content-Transfer-Encoding: 8bit"
25
+ else
26
+ header << "Content-Transfer-Encoding: base64"
27
+ end
28
+ header << "Content-ID: #{part.contentid}" if part.contentid
29
+ if part.disposition
30
+ if part.filename
31
+ header << "Content-Disposition: #{part.disposition}; filename=#{part.filename}"
32
+ else
33
+ header << "Content-Disposition: #{part.disposition}"
34
+ end
35
+ end
36
+ header << ""
37
+ if is_text
38
+ header << body
39
+ else
40
+ header << Base64.encode64(body)
41
+ end
42
+ header << ""
43
+ text += header.join("\n")
44
+ end
45
+ text +="--#{boundary}--\n"
46
+ end
47
+ text
48
+ end
49
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'docomo_web_mailer'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,9 @@
1
+ require 'helper'
2
+
3
+ class TestDocomoWebMailer < Test::Unit::TestCase
4
+ should "いつか頑張る" do
5
+ require "docomo_web_mailer"
6
+ require "docomo_web_mailer/convert_mail"
7
+ assert true
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,202 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: docomo_web_mailer
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - nazoking
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-19 00:00:00 +09:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ prerelease: false
23
+ name: shoulda
24
+ version_requirements: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ requirement: *id001
34
+ type: :development
35
+ - !ruby/object:Gem::Dependency
36
+ prerelease: false
37
+ name: bundler
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 23
44
+ segments:
45
+ - 1
46
+ - 0
47
+ - 0
48
+ version: 1.0.0
49
+ requirement: *id002
50
+ type: :development
51
+ - !ruby/object:Gem::Dependency
52
+ prerelease: false
53
+ name: jeweler
54
+ version_requirements: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 1
60
+ segments:
61
+ - 1
62
+ - 5
63
+ - 1
64
+ version: 1.5.1
65
+ requirement: *id003
66
+ type: :development
67
+ - !ruby/object:Gem::Dependency
68
+ prerelease: false
69
+ name: rcov
70
+ version_requirements: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ requirement: *id004
80
+ type: :development
81
+ - !ruby/object:Gem::Dependency
82
+ prerelease: false
83
+ name: mechanize
84
+ version_requirements: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ hash: 15
90
+ segments:
91
+ - 1
92
+ - 0
93
+ version: "1.0"
94
+ requirement: *id005
95
+ type: :development
96
+ - !ruby/object:Gem::Dependency
97
+ prerelease: false
98
+ name: json
99
+ version_requirements: &id006 !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ hash: 3
105
+ segments:
106
+ - 0
107
+ version: "0"
108
+ requirement: *id006
109
+ type: :development
110
+ - !ruby/object:Gem::Dependency
111
+ prerelease: false
112
+ name: mechanize
113
+ version_requirements: &id007 !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">"
117
+ - !ruby/object:Gem::Version
118
+ hash: 15
119
+ segments:
120
+ - 1
121
+ - 0
122
+ version: "1.0"
123
+ requirement: *id007
124
+ type: :runtime
125
+ - !ruby/object:Gem::Dependency
126
+ prerelease: false
127
+ name: json
128
+ version_requirements: &id008 !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ hash: 3
134
+ segments:
135
+ - 0
136
+ version: "0"
137
+ requirement: *id008
138
+ type: :runtime
139
+ description: !binary |
140
+ RG9jb21vIFdlYiBNYWlsICggaHR0cDovL2R3bWFpbC5qcC8gKSDjgpJSdWJ5
141
+ 44GL44KJ44GE44GY44KL44GT44Go44Gu5Ye65p2l44KL44Op44Kk44OW44Op
142
+ 44Oq44Gn44GZ44CC54++5Zyo44Gv5Y+X5L+h44Gu44G/5a++5b+c44GX44Gm
143
+ 44GK44KK44CB6YCB5L+h44KE5YmK6Zmk44GZ44KL44GT44Go44Gv5Ye65p2l
144
+ 44G+44Gb44KT44CCIA==
145
+
146
+ email: nazoking@gmail.com
147
+ executables: []
148
+
149
+ extensions: []
150
+
151
+ extra_rdoc_files:
152
+ - LICENSE.txt
153
+ - README.rdoc
154
+ files:
155
+ - .document
156
+ - Gemfile
157
+ - LICENSE.txt
158
+ - README.rdoc
159
+ - Rakefile
160
+ - VERSION
161
+ - docomo_web_mailer.gemspec
162
+ - lib/docomo_web_mailer.rb
163
+ - lib/docomo_web_mailer/convert_mail.rb
164
+ - test/helper.rb
165
+ - test/test_docomo_web_mailer.rb
166
+ has_rdoc: true
167
+ homepage: http://github.com/nazoking/docomo_web_mailer
168
+ licenses:
169
+ - MIT
170
+ post_install_message:
171
+ rdoc_options: []
172
+
173
+ require_paths:
174
+ - lib
175
+ required_ruby_version: !ruby/object:Gem::Requirement
176
+ none: false
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ hash: 3
181
+ segments:
182
+ - 0
183
+ version: "0"
184
+ required_rubygems_version: !ruby/object:Gem::Requirement
185
+ none: false
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ hash: 3
190
+ segments:
191
+ - 0
192
+ version: "0"
193
+ requirements: []
194
+
195
+ rubyforge_project:
196
+ rubygems_version: 1.3.7
197
+ signing_key:
198
+ specification_version: 3
199
+ summary: Docomo Web Mail Client
200
+ test_files:
201
+ - test/helper.rb
202
+ - test/test_docomo_web_mailer.rb