gmail-afurmanov 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ # -*- ruby -*-
2
+
3
+ $:.unshift(File.expand_path('../lib', __FILE__))
4
+ require 'gmail/version'
5
+
6
+ begin
7
+ Ore::Specification.new do |gemspec|
8
+ gemspec.version = Gmail.version
9
+ end
10
+ rescue NameError
11
+ begin
12
+ require 'ore/specification'
13
+ retry
14
+ rescue LoadError
15
+ STDERR.puts "The '#{__FILE__}' file requires Ore."
16
+ STDERR.puts "Run `gem install ore-core` to install Ore."
17
+ end
18
+ end
@@ -0,0 +1,65 @@
1
+ require 'net/imap'
2
+ require 'net/smtp'
3
+ require 'mail'
4
+ require 'date'
5
+ require 'time'
6
+
7
+ if RUBY_VERSION < "1.8.7"
8
+ require "smtp_tls"
9
+ end
10
+
11
+ class Object
12
+ def to_imap_date
13
+ Date.parse(to_s).strftime("%d-%B-%Y")
14
+ end
15
+ end
16
+
17
+ module Gmail
18
+ autoload :Version, "gmail/version"
19
+ autoload :Client, "gmail/client"
20
+ autoload :Labels, "gmail/labels"
21
+ autoload :Mailbox, "gmail/mailbox"
22
+ autoload :Message, "gmail/message"
23
+
24
+ class << self
25
+ # Creates new Gmail connection using given authorization options.
26
+ #
27
+ # ==== Examples
28
+ #
29
+ # Gmail.new(:plain, "foo@gmail.com", "password")
30
+ # Gmail.new(:xoauth, "foo@gmail.com",
31
+ # :consumer_key => "",
32
+ # :consumer_secret => "",
33
+ # :token => "",
34
+ # :secret => "")
35
+ #
36
+ # To use plain authentication mehod you can also call:
37
+ #
38
+ # Gmail.new("foo@gmail.com", "password")
39
+ #
40
+ # You can also use block-style call:
41
+ #
42
+ # Gmail.new("foo@gmail.com", "password") do |client|
43
+ # # ...
44
+ # end
45
+ #
46
+
47
+ ['', '!'].each { |kind|
48
+ define_method("new#{kind}") do |*args, &block| # def new(*args, &block)
49
+ args.unshift(:plain) unless args.first.is_a?(Symbol) # args.unshift(:plain) unless args.first.is_a?(Symbol)
50
+ client = Gmail::Client.new(*args) # client = Gmail::Client.new(*args)
51
+ client.send("connect#{kind}") and client.send("login#{kind}") # client.connect and client.login
52
+ #
53
+ if block_given? # if block_given?
54
+ yield client # yield client
55
+ client.logout # client.logout
56
+ end # end
57
+ #
58
+ client # client
59
+ end # end
60
+ }
61
+
62
+ alias :connect :new
63
+ alias :connect! :new!
64
+ end # << self
65
+ end # Gmail
@@ -0,0 +1,29 @@
1
+ module Gmail
2
+ module Client
3
+ # Raised when connection with GMail IMAP service couldn't be established.
4
+ class ConnectionError < SocketError; end
5
+ # Raised when given username or password are invalid.
6
+ class AuthorizationError < Net::IMAP::NoResponseError; end
7
+ # Raised when delivered email is invalid.
8
+ class DeliveryError < ArgumentError; end
9
+ # Raised when given client is not registered
10
+ class UnknownClient < ArgumentError; end
11
+
12
+ def self.register(name, klass)
13
+ @clients ||= {}
14
+ @clients[name] = klass
15
+ end
16
+
17
+ def self.new(name, *args)
18
+ if client = @clients[name]
19
+ client.new(*args)
20
+ else
21
+ raise UnknownClient, "No such client: #{name}"
22
+ end
23
+ end
24
+
25
+ require 'gmail/client/base'
26
+ require 'gmail/client/plain'
27
+ require 'gmail/client/xoauth'
28
+ end # Client
29
+ end # Gmail
@@ -0,0 +1,223 @@
1
+ #require 'thread'
2
+
3
+ module Gmail
4
+ module Client
5
+ class Base
6
+ # GMail IMAP defaults
7
+ GMAIL_IMAP_HOST = 'imap.gmail.com'
8
+ GMAIL_IMAP_PORT = 993
9
+
10
+ # GMail SMTP defaults
11
+ GMAIL_SMTP_HOST = "smtp.gmail.com"
12
+ GMAIL_SMTP_PORT = 587
13
+
14
+ attr_reader :username
15
+ attr_reader :options
16
+
17
+ def initialize(username, options={})
18
+ defaults = {}
19
+ @username = fill_username(username)
20
+ @options = defaults.merge(options)
21
+ # @mailbox_mutex = Mutex.new
22
+ end
23
+
24
+ # Connect to gmail service.
25
+ def connect(raise_errors=false)
26
+ @imap = Net::IMAP.new(GMAIL_IMAP_HOST, GMAIL_IMAP_PORT, true, nil, false)
27
+ rescue SocketError
28
+ raise_errors and raise ConnectionError, "Couldn't establish connection with GMail IMAP service"
29
+ end
30
+
31
+ # This version of connect will raise error on failure...
32
+ def connect!
33
+ connect(true)
34
+ end
35
+
36
+ # Return current connection. Log in automaticaly to specified account if
37
+ # it is necessary.
38
+ def connection
39
+ login and at_exit { logout } unless logged_in?
40
+ @imap
41
+ end
42
+ alias :conn :connection
43
+
44
+ # Login to specified account.
45
+ def login(*args)
46
+ raise NotImplementedError, "The `#{self.class.name}#login` method is not implemented."
47
+ end
48
+ alias :sign_in :login
49
+
50
+ # This version of login will raise error on failure...
51
+ def login!
52
+ login(true)
53
+ end
54
+ alias :sign_in! :login!
55
+
56
+ # Returns +true+ when you are logged in to specified account.
57
+ def logged_in?
58
+ !!@logged_in
59
+ end
60
+ alias :signed_in? :logged_in?
61
+
62
+ # Logout from GMail service.
63
+ def logout
64
+ @imap && logged_in? and @imap.logout
65
+ ensure
66
+ @logged_in = false
67
+ end
68
+ alias :sign_out :logout
69
+
70
+ # Return labels object, which helps you with managing your GMail labels.
71
+ # See <tt>Gmail::Labels</tt> for details.
72
+ def labels
73
+ @labels ||= Labels.new(conn)
74
+ end
75
+
76
+ # Compose new e-mail.
77
+ #
78
+ # ==== Examples
79
+ #
80
+ # mail = gmail.compose
81
+ # mail.from "test@gmail.org"
82
+ # mail.to "friend@gmail.com"
83
+ #
84
+ # ... or block style:
85
+ #
86
+ # mail = gmail.compose do
87
+ # from "test@gmail.org"
88
+ # to "friend@gmail.com"
89
+ # subject "Hello!"
90
+ # body "Hello my friend! long time..."
91
+ # end
92
+ #
93
+ # Now you can deliver your mail:
94
+ #
95
+ # gmail.deliver(mail)
96
+ def compose(mail=nil, &block)
97
+ if block_given?
98
+ mail = Mail.new(&block)
99
+ elsif !mail
100
+ mail = Mail.new
101
+ end
102
+
103
+ mail.delivery_method(*smtp_settings)
104
+ mail.from = username unless mail.from
105
+ mail
106
+ end
107
+ alias :message :compose
108
+
109
+ # Compose (optionaly) and send given email.
110
+ #
111
+ # ==== Examples
112
+ #
113
+ # gmail.deliver do
114
+ # to "friend@gmail.com"
115
+ # subject "Hello friend!"
116
+ # body "Hi! How are you?"
117
+ # end
118
+ #
119
+ # ... or with already created message:
120
+ #
121
+ # mail = Mail.new { ... }
122
+ # gmail.deliver(mail)
123
+ #
124
+ # mail = gmail.compose { ... }
125
+ # gmail.deliver(mail)
126
+ def deliver(mail=nil, raise_errors=false, &block)
127
+ mail = compose(mail, &block) if block_given?
128
+ mail.deliver!
129
+ rescue Object => ex
130
+ raise_errors and raise DeliveryError, "Couldn't deliver email: #{ex.to_s}"
131
+ end
132
+
133
+ # This version of deliver will raise error on failure...
134
+ def deliver!(mail=nil, &block)
135
+ deliver(mail, true, &block)
136
+ end
137
+
138
+ # Do something with given mailbox or within it context.
139
+ #
140
+ # ==== Examples
141
+ #
142
+ # mailbox = gmail.mailbox("INBOX")
143
+ # mailbox.emails(:all)
144
+ # mailbox.count(:unread, :before => Time.now-(20*24*3600))
145
+ #
146
+ # ... or block style:
147
+ #
148
+ # gmail.label("Work") do |mailbox|
149
+ # mailbox.emails(:unread)
150
+ # mailbox.count(:all)
151
+ # ...
152
+ # end
153
+ def mailbox(name, &block)
154
+ # @mailbox_mutex.synchronize do
155
+ name = name.to_s
156
+ mailbox = (mailboxes[name] ||= Mailbox.new(self, name))
157
+ switch_to_mailbox(name) if @current_mailbox != name
158
+
159
+ if block_given?
160
+ mailbox_stack << @current_mailbox
161
+ result = block.arity == 1 ? block.call(mailbox) : block.call
162
+ mailbox_stack.pop
163
+ switch_to_mailbox(mailbox_stack.last)
164
+ return result
165
+ end
166
+
167
+ return mailbox
168
+ # end
169
+ end
170
+ alias :in_mailbox :mailbox
171
+ alias :in_label :mailbox
172
+ alias :label :mailbox
173
+
174
+ # Alias for <tt>mailbox("INBOX")</tt>. See <tt>Gmail::Client#mailbox</tt>
175
+ # for details.
176
+ def inbox
177
+ mailbox("INBOX")
178
+ end
179
+
180
+ def mailboxes
181
+ @mailboxes ||= {}
182
+ end
183
+
184
+ def inspect
185
+ "#<Gmail::Client#{'0x%04x' % (object_id << 1)} (#{username}) #{'dis' if !logged_in?}connected>"
186
+ end
187
+
188
+ def fill_username(username)
189
+ username =~ /@/ ? username : "#{username}@gmail.com"
190
+ end
191
+
192
+ def mail_domain
193
+ username.split('@')[0]
194
+ end
195
+
196
+ private
197
+
198
+ def switch_to_mailbox(mailbox)
199
+ if mailbox
200
+ mailbox = Net::IMAP.encode_utf7(mailbox)
201
+ conn.select(mailbox)
202
+ end
203
+ @current_mailbox = mailbox
204
+ end
205
+
206
+ def mailbox_stack
207
+ @mailbox_stack ||= []
208
+ end
209
+
210
+ def smtp_settings
211
+ [:smtp, {
212
+ :address => GMAIL_SMTP_HOST,
213
+ :port => GMAIL_SMTP_PORT,
214
+ :domain => mail_domain,
215
+ :user_name => username,
216
+ :password => password,
217
+ :authentication => 'plain',
218
+ :enable_starttls_auto => true
219
+ }]
220
+ end
221
+ end # Base
222
+ end # Client
223
+ end # Gmail
@@ -0,0 +1,20 @@
1
+ module Gmail
2
+ module Client
3
+ class Plain < Base
4
+ attr_reader :password
5
+
6
+ def initialize(username, password, options={})
7
+ @password = password
8
+ super(username, options)
9
+ end
10
+
11
+ def login(raise_errors=false)
12
+ @imap and @logged_in = (login = @imap.login(username, password)) && login.name == 'OK'
13
+ rescue Net::IMAP::NoResponseError
14
+ raise_errors and raise AuthorizationError, "Couldn't login to given GMail account: #{username}"
15
+ end
16
+ end # Plain
17
+
18
+ register :plain, Plain
19
+ end # Client
20
+ end # Gmail
@@ -0,0 +1,51 @@
1
+ require 'gmail_xoauth'
2
+
3
+ module Gmail
4
+ module Client
5
+ class XOAuth < Base
6
+ attr_reader :token
7
+ attr_reader :secret
8
+ attr_reader :consumer_key
9
+ attr_reader :consumer_secret
10
+
11
+ def initialize(username, options={})
12
+ @token = options.delete(:token)
13
+ @secret = options.delete(:secret)
14
+ @consumer_key = options.delete(:consumer_key)
15
+ @consumer_secret = options.delete(:consumer_secret)
16
+
17
+ super(username, options)
18
+ end
19
+
20
+ def login(raise_errors=false)
21
+ @imap and @logged_in = (login = @imap.authenticate('XOAUTH', username,
22
+ :consumer_key => consumer_key,
23
+ :consumer_secret => consumer_secret,
24
+ :token => token,
25
+ :token_secret => secret
26
+ )) && login.name == 'OK'
27
+ rescue
28
+ raise_errors and raise AuthorizationError, "Couldn't login to given GMail account: #{username}"
29
+ end
30
+
31
+ def smtp_settings
32
+ [:smtp, {
33
+ :address => GMAIL_SMTP_HOST,
34
+ :port => GMAIL_SMTP_PORT,
35
+ :domain => mail_domain,
36
+ :user_name => username,
37
+ :password => {
38
+ :consumer_key => consumer_key,
39
+ :consumer_secret => consumer_secret,
40
+ :token => token,
41
+ :token_secret => secret
42
+ },
43
+ :authentication => :xoauth,
44
+ :enable_starttls_auto => true
45
+ }]
46
+ end
47
+ end # XOAuth
48
+
49
+ register :xoauth, XOAuth
50
+ end # Client
51
+ end # Gmail
@@ -0,0 +1,48 @@
1
+ module Gmail
2
+ class Labels
3
+ include Enumerable
4
+ attr_reader :connection
5
+ alias :conn :connection
6
+
7
+ def initialize(connection)
8
+ @connection = connection
9
+ end
10
+
11
+ # Get list of all defined labels.
12
+ def all
13
+ (conn.list("", "%")+conn.list("[Gmail]/", "%")).inject([]) do |labels,label|
14
+ label[:name].each_line {|l| labels << Net::IMAP.decode_utf7(l) }
15
+ labels
16
+ end
17
+ end
18
+ alias :list :all
19
+ alias :to_a :all
20
+
21
+ def each(*args, &block)
22
+ all.each(*args, &block)
23
+ end
24
+
25
+ # Returns +true+ when given label defined.
26
+ def exists?(label)
27
+ all.include?(label)
28
+ end
29
+ alias :exist? :exists?
30
+
31
+ # Creates given label in your account.
32
+ def create(label)
33
+ !!conn.create(Net::IMAP.encode_utf7(label)) rescue false
34
+ end
35
+ alias :new :create
36
+ alias :add :create
37
+
38
+ # Deletes given label from your account.
39
+ def delete(label)
40
+ !!conn.delete(Net::IMAP.encode_utf7(label)) rescue false
41
+ end
42
+ alias :remove :delete
43
+
44
+ def inspect
45
+ "#<Gmail::Labels#{'0x%04x' % (object_id << 1)}>"
46
+ end
47
+ end # Labels
48
+ end # Gmail