decoration_mail 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'mail', '>=2.2.9'
4
+ gem 'hpricot', '>=0.8.3'
5
+
6
+ group :development, :test do
7
+ gem 'rspec', '>=2.0'
8
+ gem 'jeweler'
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.0.3)
5
+ diff-lcs (1.1.2)
6
+ git (1.2.5)
7
+ hpricot (0.8.3)
8
+ i18n (0.5.0)
9
+ jeweler (1.5.2)
10
+ bundler (~> 1.0.0)
11
+ git (>= 1.2.5)
12
+ rake
13
+ mail (2.2.15)
14
+ activesupport (>= 2.3.6)
15
+ i18n (>= 0.4.0)
16
+ mime-types (~> 1.16)
17
+ treetop (~> 1.4.8)
18
+ mime-types (1.16)
19
+ polyglot (0.3.1)
20
+ rake (0.8.7)
21
+ rspec (2.5.0)
22
+ rspec-core (~> 2.5.0)
23
+ rspec-expectations (~> 2.5.0)
24
+ rspec-mocks (~> 2.5.0)
25
+ rspec-core (2.5.0)
26
+ rspec-expectations (2.5.0)
27
+ diff-lcs (~> 1.1.2)
28
+ rspec-mocks (2.5.0)
29
+ treetop (1.4.9)
30
+ polyglot (>= 0.3.1)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ hpricot (>= 0.8.3)
37
+ jeweler
38
+ mail (>= 2.2.9)
39
+ rspec (>= 2.0)
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,44 @@
1
+ = DecorationMail
2
+
3
+ == DecorationMailとは
4
+ 携帯電話で作成されたデコレーションメール(デコメール)をRubyで扱いやすくするためのライブラリです。
5
+
6
+ 今のところ受信したメールをパースするのみでデコメールの新規作成は出来ません。そのうち実装するかもしれません。。。
7
+
8
+ == 使用例
9
+ Rails3でも採用されているMailライブラリのMail::Messageを拡張しています。
10
+
11
+ decorationメソッドで本ライブラリの機能を呼び出す事が出来ます。
12
+
13
+ === 基本的な使い方
14
+
15
+ require 'mail
16
+ require 'decoration_mail'
17
+
18
+ @mail = Mail.read('/path/to')
19
+ @deco = @mail.decoration
20
+
21
+ @html = @deco.save do |image|
22
+ File.open("/path/to/#{image.filename}", "wb") {|f| f.write(image.body)}
23
+ end
24
+
25
+ puts @html # => "<div ...."
26
+
27
+ === 画像のURLを指定する
28
+ image.pathにURIを代入することで、出力されるHTMLの<img src="">を書き換えます。
29
+
30
+ MogileFSなどのストレージを利用する場合に使用すると便利でしょう。
31
+
32
+ @html = @deco.save do |image|
33
+ File.open("/path/to/#{image.filename}", "wb") {|f| f.write(image.body)}
34
+ image.path = "http://xxxxxx/#{image.filename}"
35
+ end
36
+
37
+ === 本文(デコレーション)で使用されていない添付画像をHTMLに追加する
38
+
39
+ # 本文上部に追加
40
+ @html = @deco.save(:other_images => :top) do |image|
41
+ .....
42
+
43
+ # 本文下部に追加
44
+ @html = @deco.save(:other_images => :bottom) do |image|
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the decoration_mail plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the decoration_mail plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'DecorationMail'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
24
+
25
+ begin
26
+ require 'jeweler'
27
+ Jeweler::Tasks.new do |gemspec|
28
+ gemspec.name = "decoration_mail"
29
+ gemspec.summary = "Decoration Mail Parser"
30
+ gemspec.email = "d.akatsuka@gmail.com"
31
+ gemspec.homepage = "https://github.com/dakatsuka/decoration_mail"
32
+ gemspec.description = "Decoration Mail Parser"
33
+ gemspec.authors = ["Dai Akatsuka"]
34
+ end
35
+ rescue LoadError
36
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
37
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,73 @@
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{decoration_mail}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Dai Akatsuka"]
12
+ s.date = %q{2011-02-08}
13
+ s.description = %q{Decoration Mail Parser}
14
+ s.email = %q{d.akatsuka@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ "Gemfile",
20
+ "Gemfile.lock",
21
+ "MIT-LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "init.rb",
26
+ "lib/decoration_mail.rb",
27
+ "lib/decoration_mail/base.rb",
28
+ "lib/decoration_mail/converter.rb",
29
+ "lib/decoration_mail/image.rb",
30
+ "lib/decoration_mail/message.rb",
31
+ "spec/resources/au_decoration.eml",
32
+ "spec/resources/au_decoration_with_attachment.eml",
33
+ "spec/resources/docomo_decoration.eml",
34
+ "spec/resources/docomo_decoration_with_attachment.eml",
35
+ "spec/resources/softbank_decoration.eml",
36
+ "spec/resources/softbank_decoration_with_attachment.eml",
37
+ "spec/spec_helper.rb",
38
+ "spec/unit/base_spec.rb",
39
+ "spec/unit/converter_spec.rb"
40
+ ]
41
+ s.homepage = %q{https://github.com/dakatsuka/decoration_mail}
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = %q{1.3.7}
44
+ s.summary = %q{Decoration Mail Parser}
45
+ s.test_files = [
46
+ "spec/spec_helper.rb",
47
+ "spec/unit/base_spec.rb",
48
+ "spec/unit/converter_spec.rb"
49
+ ]
50
+
51
+ if s.respond_to? :specification_version then
52
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
53
+ s.specification_version = 3
54
+
55
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
+ s.add_runtime_dependency(%q<mail>, [">= 2.2.15"])
57
+ s.add_runtime_dependency(%q<hpricot>, [">= 0.8.3"])
58
+ s.add_development_dependency(%q<rspec>, [">= 2.0"])
59
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
60
+ else
61
+ s.add_dependency(%q<mail>, [">= 2.2.15"])
62
+ s.add_dependency(%q<hpricot>, [">= 0.8.3"])
63
+ s.add_dependency(%q<rspec>, [">= 2.0"])
64
+ s.add_dependency(%q<jeweler>, [">= 0"])
65
+ end
66
+ else
67
+ s.add_dependency(%q<mail>, [">= 2.2.15"])
68
+ s.add_dependency(%q<hpricot>, [">= 0.8.3"])
69
+ s.add_dependency(%q<rspec>, [">= 2.0"])
70
+ s.add_dependency(%q<jeweler>, [">= 0"])
71
+ end
72
+ end
73
+
data/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ # coding: utf-8
2
+
3
+ require File.expand_path("../lib/decoration_mail", __FILE__)
@@ -0,0 +1,82 @@
1
+ # coding: utf-8
2
+
3
+ module DecorationMail
4
+ class Base
5
+ def initialize(mail)
6
+ @attachments = mail.attachments
7
+ @body_text = parse_text(mail.text_part)
8
+ @body_html = parse_html(mail.html_part)
9
+ end
10
+
11
+ def images
12
+ images = []
13
+
14
+ @attachments.each do |attachment|
15
+ content_type = attachment.header['content-type'].to_s
16
+ content_id = "cid:" + attachment.header['content-id'].to_s.sub(/^</, '').sub(/>$/, '')
17
+ file_name = attachment.filename
18
+
19
+ next unless check_content_type(content_type)
20
+ images << DecorationMail::Image.new(content_id, content_type, file_name, attachment)
21
+ end
22
+
23
+ images
24
+ end
25
+
26
+ def save(options = {}, &block)
27
+ images.each do |image|
28
+ image.instance_eval(&block)
29
+
30
+ if image.content_id
31
+ @body_html.search("img").each do |element|
32
+ if element[:src] == image.content_id
33
+ element[:src] = (image.path ? image.path : image.filename)
34
+ end
35
+ end
36
+ else
37
+ case options[:other_images]
38
+ when :top
39
+ @body_html = Hpricot("<div style='text-align:center;'><img src='#{image.path ? image.path : image.filename}' /></div><br />" + @body_html.to_html)
40
+ when :bottom
41
+ @body_html = Hpricot(@body_html.to_html + "<br /><div style='text-align:center;'><img src='#{image.path ? image.path : image.filename}' /></div>")
42
+ end
43
+ end
44
+ end
45
+
46
+ @body_html.to_html
47
+ end
48
+
49
+ private
50
+ def parse_text(text)
51
+ NKF.nkf("-w", text.to_s)
52
+ end
53
+
54
+ def parse_html(html)
55
+ html = NKF.nkf("-w", html.body.to_s)
56
+ html = Hpricot.parse(html)
57
+
58
+ if html.search("body").empty?
59
+ raise ArgumentError, 'invalid HTML'
60
+ else
61
+ html = DecorationMail::Converter.convert_to_xhtml(html).at('div')
62
+ end
63
+
64
+ html
65
+ end
66
+
67
+ def check_content_type(content_type)
68
+ case content_type
69
+ when /^image\/gif/
70
+ true
71
+ when /^image\/jpg/
72
+ true
73
+ when /^image\/jpeg/
74
+ true
75
+ when /^image\/png/
76
+ true
77
+ else
78
+ false
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,101 @@
1
+ # coding: utf-8
2
+
3
+ module DecorationMail
4
+ module Converter
5
+ def self.convert_to_xhtml(html)
6
+ html = convert_body_to_div(html)
7
+ html = convert_font_color_to_css(html)
8
+ html = convert_font_size_to_css(html)
9
+ html = convert_align_to_css(html)
10
+ html = convert_blink_to_css(html)
11
+ html = convert_marquee_to_css(html)
12
+ end
13
+
14
+ private
15
+ def self.convert_body_to_div(html)
16
+ html.search("body").each do |body|
17
+ if body[:bgcolor]
18
+ body.swap('<div style="background-color:' + body[:bgcolor] + ';">' + body.inner_html + '</div>')
19
+ else
20
+ body.swap("<div>#{body.inner_html}</div>")
21
+ end
22
+ end
23
+ html
24
+ end
25
+
26
+ def self.convert_font_color_to_css(html)
27
+ html.search("font").each do |element|
28
+ if element[:color]
29
+ str = "<span>#{element.inner_html}</span>"
30
+ tmp = Hpricot.parse(str).search("span")
31
+ tmp.first[:style] = "color:#{element[:color].downcase};"
32
+ element.swap(tmp.to_html)
33
+ end
34
+ end
35
+ html
36
+ end
37
+
38
+ def self.convert_font_size_to_css(html)
39
+ html.search("font").each do |element|
40
+ if element[:size]
41
+ str = "<span>#{element.inner_html}</span>"
42
+ tmp = Hpricot.parse(str).search("span")
43
+
44
+ case element[:size]
45
+ when "1"
46
+ tmp.first[:style] = "font-size:xx-small;"
47
+ when "2"
48
+ tmp.first[:style] = "font-size:x-small;"
49
+ when "3"
50
+ tmp.first[:style] = "font-size:small;"
51
+ when "4"
52
+ tmp.first[:style] = "font-size:medium;"
53
+ when "5"
54
+ tmp.first[:style] = "font-size:large;"
55
+ when "6"
56
+ tmp.first[:style] = "font-size:x-large;"
57
+ when "7"
58
+ tmp.first[:style] = "font-size:xx-large;"
59
+ else
60
+ tmp.first[:style] = "font-size:x-small;"
61
+ end
62
+ element.swap(tmp.to_html)
63
+ end
64
+ end
65
+ html
66
+ end
67
+
68
+ def self.convert_align_to_css(html)
69
+ html.search("div").each do |element|
70
+ if element[:align]
71
+ str = "<div>#{element.inner_html}</div>"
72
+ tmp = Hpricot.parse(str).search "div"
73
+
74
+ tmp.first[:style] = "text-align:#{element[:align]};"
75
+ element.swap(tmp.to_html)
76
+ end
77
+ end
78
+ html
79
+ end
80
+
81
+ def self.convert_blink_to_css(html)
82
+ html.search("blink").each do |element|
83
+ element.swap('<span style="text-decoration:blink;">' + element.inner_html + '</span>')
84
+ end
85
+ html
86
+ end
87
+
88
+ def self.convert_marquee_to_css(html)
89
+ html.search("marquee").each do |element|
90
+ if element[:behavior] == "scroll"
91
+ element.swap('<div style="display:-wap-marquee;-wap-marquee-loop:infinite;">' + element.inner_html + '</div>')
92
+ elsif element[:behavior] == "alternate"
93
+ element.swap('<div style="display:-wap-marquee;-wap-marquee-style:alternate;-wap-marquee-loop:infinite;">' + element.inner_html + '</div>')
94
+ else
95
+ element.swap('<div style="display:-wap-marquee;-wap-marquee-loop:infinite;">' + element.inner_html + '</div>')
96
+ end
97
+ end
98
+ html
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+
3
+ module DecorationMail
4
+ class Image
5
+ attr_accessor :path
6
+ attr_reader :content_id, :filename
7
+
8
+ def initialize(content_id, content_type, filename, attachment)
9
+ @content_id = (content_id == "cid:" ? nil : content_id)
10
+ @content_type = content_type
11
+ @filename = filename
12
+ @attachment = attachment
13
+ end
14
+
15
+ def body
16
+ @attachment.read
17
+ end
18
+
19
+ def extension
20
+ case @content_type
21
+ when /^image\/gif/
22
+ "gif"
23
+ when /^image\/jpg/
24
+ "jpg"
25
+ when /^image\/jpeg/
26
+ "jpg"
27
+ when /^image\/png/
28
+ "png"
29
+ else
30
+ nil
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,13 @@
1
+ # coding: utf-8
2
+
3
+ module DecorationMail
4
+ module Message
5
+ def decoration
6
+ if html_part
7
+ DecorationMail::Base.new(self)
8
+ else
9
+ nil
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # coding: utf-8
2
+ $:.unshift(File.dirname(__FILE__))
3
+
4
+ require 'mail'
5
+ require 'hpricot'
6
+ require 'nkf'
7
+
8
+ require 'decoration_mail/converter'
9
+ require 'decoration_mail/image'
10
+ require 'decoration_mail/base'
11
+ require 'decoration_mail/message'
12
+
13
+ Mail::Message.send :include, DecorationMail::Message
@@ -0,0 +1,192 @@
1
+ Return-Path: <example@ezweb.ne.jp>
2
+ X-Original-To: d.akatsuka@ist-corp.jp
3
+ Delivered-To: akatsuka@ist-corp.jp
4
+ Received: from ezweb.ne.jp (xxxxx.ezweb.ne.jp [255.255.255.225])
5
+ by ist-corp.jp (Postfix) with ESMTP id DAA9038289
6
+ for <d.akatsuka@ist-corp.jp>; Mon, 7 Feb 2011 18:07:30 +0900 (JST)
7
+ Received: from xxxxx (localhost [127.0.0.1])
8
+ by xxxxx.ezweb.ne.jp (EZweb Mail) with SMTP id C34971C2380BC
9
+ for <d.akatsuka@ist-corp.jp>; Mon, 7 Feb 2011 18:07:30 +0900 (JST)
10
+ From: example@ezweb.ne.jp
11
+ To: d.akatsuka@ist-corp.jp
12
+ Subject: =?iso-2022-jp?B?YXUbJEIlRiU5JUgbKEI=?=
13
+ Message-ID: <2011020718073078334700004bae@nxev03mp01.ezweb.ne.jp>
14
+ Date: Mon, 7 Feb 2011 18:07:30 +0900
15
+ Mime-Version: 1.0
16
+ Content-Type: multipart/mixed; boundary="-----=_NextPart_39580_29716_19852"
17
+
18
+
19
+ -------=_NextPart_39580_29716_19852
20
+ Content-Type: multipart/alternative; boundary="-----=_NextPart_41084_31220_21356"
21
+
22
+
23
+ -------=_NextPart_41084_31220_21356
24
+ Content-Type: text/plain; charset="iso-2022-jp"
25
+ Content-Transfer-Encoding: 7bit
26
+
27
+
28
+ $B"(%3%3$r>C$7$F(B
29
+ $BJ8>O$rF~$l$F$M(B
30
+
31
+
32
+ -------=_NextPart_41084_31220_21356
33
+ Content-Type: text/html; charset="iso-2022-jp"
34
+ Content-Transfer-Encoding: quoted-printable
35
+
36
+ <HTML><HEAD><META http-equiv=3D=22Content-Type=22 content=3D=22text/html;=
37
+ charset=3Diso-2022-jp=22></HEAD><BODY bgcolor=3D=22=23BBF06A=22><DIV align=
38
+ =3D=22center=22><IMG src=3D=22cid:01=40110207.180712=22></DIV><DIV align=3D=
39
+ =22center=22><FONT color=3D=22=23478D00=22><IMG src=3D=22cid:02=40110207.18=
40
+ 0722=22>=1B=24B=22(%3%3=24r>C=247=24F=1B(B</FONT></DIV><DIV align=3D=22cent=
41
+ er=22><FONT color=3D=22=23478D00=22>=1B=24BJ8>O=24rF=7E=24l=24F=24M=1B(B</F=
42
+ ONT></DIV><DIV align=3D=22center=22><IMG src=3D=22cid:03=40110207.180712=22=
43
+ ></DIV></BODY></HTML>
44
+ -------=_NextPart_41084_31220_21356--
45
+
46
+ -------=_NextPart_39580_29716_19852
47
+ Content-Type: image/gif; name="SHmura01_1.gif"
48
+ Content-Transfer-Encoding: base64
49
+ Content-Disposition: attachment; filename="SHmura01_1.gif"
50
+ Content-ID: <01@110207.180712>
51
+
52
+ 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
129
+
130
+ -------=_NextPart_39580_29716_19852
131
+ Content-Type: image/gif; name="0002.gif"
132
+ Content-Transfer-Encoding: base64
133
+ Content-Disposition: attachment; filename="0002.gif"
134
+ Content-ID: <02@110207.180722>
135
+
136
+ R0lGODlhFAAUAPIFAAAAAP8AAP9p//868f/5AAAAAAAAAAAAACH5BAkPAAUAIf8LTkVUU0NBUEUy
137
+ LjADAQAAACwAAAAAFAAUAAADRliwXP7wrQACBTEry6mOVed9UmgtJGSOCvZNV+m6aoO2Dq01oN6/
138
+ N0lK0fNljERSsAZE4moMZ9QGICxTC4L2qqxysd8hLQEAIfkECQ8ABQAsAAAAABQAFAAAAzRYuszw
139
+ r0kHwbxW5Uv15l4IRuAEaSWpjmSHfRQMS3KLmawj0t9Z2D/gL1YpGU3CFGGWSk4SACH5BAkPAAUA
140
+ LAAAAAAUABQAAANHWLrczgC8CeWKtMStcO7WZlGeNmaneX3Q2qSOeMEzzYHyJEZBH9Az3+6zExgl
141
+ QNPRKMg9AMxjhFB6QaUAgrZa4Uy5RDBrlAAAIfkEBQ8ABQAsAAAAABQAFAAAA0tYutzOALwJ5Yq0
142
+ xK1w7tZmUZ42Zqd5fdDapI54wTPNgfIkRkEf0DPf7rMTGGGyyNEoSAEGTwyAeXQOrlATs3TBZk23
143
+ 1xMKfORYhQQAOw==
144
+
145
+ -------=_NextPart_39580_29716_19852
146
+ Content-Type: image/gif; name="SHmura01_2.gif"
147
+ Content-Transfer-Encoding: base64
148
+ Content-Disposition: attachment; filename="SHmura01_2.gif"
149
+ Content-ID: <03@110207.180712>
150
+
151
+ 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
190
+
191
+ -------=_NextPart_39580_29716_19852--
192
+