gmailer 0.1.5 → 0.1.6
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/CHANGES +4 -0
- data/README +40 -0
- data/gmailer-0.1.5.gem +0 -0
- data/gmailer.gempsec +1 -1
- data/gmailer.rb +2165 -1729
- metadata +4 -3
data/CHANGES
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
== 0.1.6 - 16-May-2007
|
2
|
+
- some source code refactoring
|
3
|
+
- add edit_concact, add_contact, delete_contact, add_sender_to_contact method
|
4
|
+
|
1
5
|
== 0.1.5 - 25-Jan-2007
|
2
6
|
- fix bad URI problem connection problem for some accounts
|
3
7
|
- add :ishtml parameter to specify the mail should be sent as text or as HTML
|
data/README
CHANGED
@@ -41,6 +41,46 @@
|
|
41
41
|
g.fetch(:contact=>"freq").each do |item|
|
42
42
|
puts "Name: #{item.name} Email: #{item.email}"
|
43
43
|
end
|
44
|
+
|
45
|
+
puts "Your all contact addresses:"
|
46
|
+
g.fetch(:contact=>"all").each do |item|
|
47
|
+
puts "Name: #{item.name} Email: #{item.email}"
|
48
|
+
end
|
49
|
+
|
50
|
+
puts "Your groups:"
|
51
|
+
g.fetch(:contact=>"group").each do |item|
|
52
|
+
puts "ID: #{item.id} Name: #{item.name} Email: #{item.email}"
|
53
|
+
g.fetch(:contact=>"group_detail",:param=>item.id).each do |detail|
|
54
|
+
puts " Group Name: #{detail.group_names} Group Email: #{detail.group_email}"
|
55
|
+
detail.members.each do |m|
|
56
|
+
puts " Member ID: #{m.id}, Name: #{m.name}, Email: #{m.email}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
puts "Search and Detail Contact:"
|
62
|
+
g.fetch(:contact=>"search",:param=>'phasis').each do |item|
|
63
|
+
puts "Name: #{item.name} Email: #{item.email}"
|
64
|
+
g.fetch(:contact=>"detail",:param=>item.id).each do |detail|
|
65
|
+
puts "ID: #{item.id} Name: #{item.name} Email: #{item.email} Notes: #{item.notes} Details: #{item.details}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
puts "Edit contact info:"
|
70
|
+
contact_id = "7"
|
71
|
+
g.edit_contact(contact_id, "John", "john@company.com", 'Supervisor of project X',[{:phone=>'642-5678',:mobile=>'837-1233',:fax=>'111-1111'}])
|
72
|
+
|
73
|
+
puts "Add contact info:"
|
74
|
+
g.add_contact('Mike', 'mike@company.com', 'Mike',[{:phone=>'642-5678',:mobile=>'837-1233',:fax=>'111-1111'},{:phone=>'1-23-5378',:mobile=>'8-31-1233',:fax=>'122-1321'}])
|
75
|
+
|
76
|
+
puts "Delete Contact:"
|
77
|
+
contact_id = "18"
|
78
|
+
g.delete_contact(contact_id)
|
79
|
+
|
80
|
+
puts "Add sender to Contact:"
|
81
|
+
msg_id = '11276ede68783f04'
|
82
|
+
g.add_sender_to_contact(msg_id)
|
83
|
+
|
44
84
|
end
|
45
85
|
|
46
86
|
=== Get list of labels and get list of messages
|
data/gmailer-0.1.5.gem
ADDED
Binary file
|
data/gmailer.gempsec
CHANGED
data/gmailer.rb
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
# project home page: http://rubyforge.org/projects/gmailutils
|
7
7
|
#
|
8
8
|
|
9
|
-
|
9
|
+
DEBUG = false
|
10
10
|
|
11
11
|
require 'net/https'
|
12
12
|
|
@@ -52,1741 +52,2177 @@ GM_ACT_DELSPAM = 20 # delete spam, forever
|
|
52
52
|
GM_ACT_DELTRASH = 21 # delete trash message, forever
|
53
53
|
|
54
54
|
module GMailer
|
55
|
-
VERSION = "0.1.
|
55
|
+
VERSION = "0.1.6"
|
56
56
|
attr_accessor :connection
|
57
57
|
|
58
58
|
# the main class.
|
59
59
|
class Connection
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
def encode(str)
|
73
|
-
return str if @charset.upcase == 'UTF-8'
|
74
|
-
begin
|
75
|
-
require 'Win32API'
|
76
|
-
str += "\0"
|
77
|
-
ostr = "\0" * str.length*2
|
78
|
-
multiByteToWideChar = Win32API.new('kernel32','MultiByteToWideChar',['L','L','P','L','P','L'],'L')
|
79
|
-
multiByteToWideChar.Call(0,0,str,-1,ostr,str.length*2)
|
80
|
-
(ostr.strip + "\0").unpack("S*").pack("U*")
|
81
|
-
rescue LoadError
|
82
|
-
require 'iconv'
|
83
|
-
Iconv::iconv('UTF-8',@charset,str)[0]
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
#
|
88
|
-
# return GMailer
|
89
|
-
# desc Constructor
|
90
|
-
#
|
91
|
-
def initialize(*param)
|
92
|
-
@login = ''
|
93
|
-
@pwd = ''
|
94
|
-
@raw = {}
|
95
|
-
@proxy_host = nil
|
96
|
-
@proxy_port = 0
|
97
|
-
@proxy_user = nil
|
98
|
-
@proxy_pass = nil
|
99
|
-
@proxy = false
|
100
|
-
@type = 0
|
101
|
-
if param.length==1 && param[0].class==Hash
|
102
|
-
param = param[0]
|
103
|
-
set_login_info(param[:username]||'',param[:password]||'')
|
104
|
-
@proxy_host = param[:proxy_host]
|
105
|
-
@proxy = !@proxy_host.nil?
|
106
|
-
@proxy_port = param[:proxy_port] || 80
|
107
|
-
@proxy_user = param[:proxy_user]
|
108
|
-
@proxy_pass = param[:proxy_pass]
|
109
|
-
@charset = param[:charset] || 'UTF-8'
|
110
|
-
elsif param.length==0
|
111
|
-
@charset = 'UTF-8'
|
112
|
-
elsif param.length==1
|
113
|
-
@charset = param[0]
|
114
|
-
elsif param.length==2
|
115
|
-
@charset = 'UTF-8'
|
116
|
-
set_login_info(param[0],param[1])
|
117
|
-
elsif param.length==3
|
118
|
-
@charset = param[2]
|
119
|
-
set_login_info(param[0],param[1])
|
120
|
-
else
|
121
|
-
raise ArgumentError, 'Invalid argument'
|
122
|
-
end
|
123
|
-
raise 'Not connected, verify the credentials.' unless connect_no_cookie
|
124
|
-
end
|
125
|
-
|
126
|
-
#
|
127
|
-
# return void
|
128
|
-
# param string my_login
|
129
|
-
# param string my_pwd
|
130
|
-
# param int my_tz
|
131
|
-
# desc Set GMail login information.
|
132
|
-
#
|
133
|
-
def set_login_info(my_login, my_pwd, my_tz=0)
|
134
|
-
@login = my_login
|
135
|
-
@pwd = my_pwd
|
136
|
-
@timezone = (my_tz*-60).to_i.to_s
|
137
|
-
end
|
138
|
-
|
139
|
-
#
|
140
|
-
# return bool
|
141
|
-
# desc Connect to GMail without setting any session/cookie.
|
142
|
-
#
|
143
|
-
def connect_no_cookie()
|
144
|
-
|
145
|
-
postdata = "service=mail&Email=" + URI.escape(@login) + "&Passwd=" + URI.escape(@pwd) + "&null=Sign%20in&continue=" +
|
146
|
-
URI.escape('https://mail.google.com/mail/?ui=html&zy=l') + "&rm=false&PersistentCookie=yes"
|
147
|
-
|
148
|
-
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new("www.google.com", 443)
|
149
|
-
np.use_ssl = true
|
150
|
-
np.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
151
|
-
result = ''
|
152
|
-
response = nil
|
153
|
-
# np.set_debug_output($stderr)
|
154
|
-
np.start { |http|
|
155
|
-
response = http.post(GM_LNK_LOGIN, postdata,{'Content-Type' => 'application/x-www-form-urlencoded','User-agent' => GM_USER_AGENT} )
|
156
|
-
result = response.body
|
157
|
-
}
|
158
|
-
|
159
|
-
if result.include?("errormsg")
|
160
|
-
@cookie_str = ''
|
161
|
-
return false
|
162
|
-
end
|
163
|
-
|
164
|
-
cookies = __cookies(response['set-cookie'])
|
165
|
-
arr = URI::split(response["Location"])
|
166
|
-
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 443)
|
167
|
-
np.use_ssl = true
|
168
|
-
np.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
169
|
-
result = ''
|
170
|
-
response = nil
|
171
|
-
# np.set_debug_output($stderr)
|
172
|
-
np.start { |http|
|
173
|
-
response = http.get(arr[5]+'?'+arr[7], {'Cookie' => cookies,'User-agent' => GM_USER_AGENT} )
|
174
|
-
result = response.body
|
175
|
-
}
|
176
|
-
|
177
|
-
if result.include?("Redirecting") && result =~ /url='(.+?)'/
|
178
|
-
url = $1.gsub("&","&")
|
179
|
-
result = ''
|
180
|
-
cookies += ';'+ __cookies(response['set-cookie'])
|
181
|
-
response = nil
|
182
|
-
# np.set_debug_output($stderr)
|
183
|
-
np.start { |http|
|
184
|
-
response = http.get(url, {'Cookie' => cookies,'User-agent'=> GM_USER_AGENT} )
|
185
|
-
result = response.body
|
186
|
-
}
|
187
|
-
end
|
60
|
+
@cookie_str
|
61
|
+
@login
|
62
|
+
@pwd
|
63
|
+
@raw # raw packets
|
64
|
+
@contact_raw # raw packets for address book
|
65
|
+
@timezone
|
66
|
+
@created
|
67
|
+
@proxy_host
|
68
|
+
@proxy_port
|
69
|
+
@proxy_user
|
70
|
+
@proxy_pass
|
188
71
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
result = ''
|
195
|
-
response = nil
|
196
|
-
# np.set_debug_output($stderr)
|
197
|
-
np.start { |http|
|
198
|
-
response = http.get(arr[5]+'?'+arr[7], {'Cookie' => cookies,'User-agent' => GM_USER_AGENT} )
|
199
|
-
result = response.body
|
200
|
-
}
|
201
|
-
end
|
202
|
-
|
203
|
-
@loc = "http://mail.google.com/mail/"
|
204
|
-
cookies += ';' + __cookies(response['set-cookie'])
|
205
|
-
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 443)
|
206
|
-
np.use_ssl = true
|
207
|
-
np.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
208
|
-
# np.set_debug_output($stderr)
|
209
|
-
np.start { |http|
|
210
|
-
response = http.get(@loc, {'Cookie' => cookies,'User-agent' => GM_USER_AGENT} )
|
211
|
-
result = response.body
|
212
|
-
}
|
213
|
-
cookies += ';' + __cookies(response['set-cookie'])
|
214
|
-
|
215
|
-
@cookie_str = cookies + ";TZ=" + @timezone
|
216
|
-
|
217
|
-
return true
|
218
|
-
end
|
219
|
-
|
220
|
-
#
|
221
|
-
# return bool
|
222
|
-
# desc Connect to GMail with default session management settings.
|
223
|
-
#
|
224
|
-
def connect()
|
225
|
-
raise 'Not connected, verify the credentials.' unless connect_no_cookie()
|
226
|
-
end
|
227
|
-
|
228
|
-
|
229
|
-
#
|
230
|
-
# return bool
|
231
|
-
# desc See if it is connected to GMail.
|
232
|
-
#
|
233
|
-
def connected?
|
234
|
-
!@cookie_str.empty?
|
235
|
-
end
|
236
|
-
|
237
|
-
#
|
238
|
-
# return bool
|
239
|
-
# param string query
|
240
|
-
# desc Fetch contents by URL query.
|
241
|
-
#
|
242
|
-
def __fetch(query)
|
243
|
-
if connected?
|
244
|
-
query += "&zv=" + (rand(2000)*2147483.648).to_i.to_s
|
245
|
-
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
246
|
-
# np.set_debug_output($stderr)
|
247
|
-
inbox = ''
|
248
|
-
np.start { |http|
|
249
|
-
response = http.get(GM_LNK_GMAIL + "?" + query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
|
250
|
-
inbox = response.body
|
251
|
-
}
|
252
|
-
if @type == GM_SHOWORIGINAL
|
253
|
-
@raw = inbox
|
254
|
-
else
|
255
|
-
state = 0
|
256
|
-
tmp = ''
|
257
|
-
inbox.each do |l|
|
258
|
-
if /^D\(.*\);$/.match(l)
|
259
|
-
state = 0
|
260
|
-
tmp += l
|
261
|
-
elsif l[0,3]=='D(['
|
262
|
-
state = 1
|
263
|
-
tmp += l.chomp
|
264
|
-
elsif l[0,2]==');'
|
265
|
-
state = 2
|
266
|
-
tmp += ")\n"
|
267
|
-
elsif state == 1
|
268
|
-
tmp += l.chomp
|
269
|
-
end
|
270
|
-
end
|
271
|
-
inbox = tmp
|
272
|
-
matches = inbox.scan(/D\((.*)\)/).flatten
|
273
|
-
packets = {}
|
274
|
-
matches.each {|x|
|
275
|
-
tmp = eval(x.gsub(",,",",'',").gsub(",,",",'',").gsub(",]",",'']").gsub('#{','#\{'))
|
276
|
-
if (packets[tmp[0]] || (tmp[0]=="mi"||tmp[0]=="mb"||tmp[0]=="di"))
|
277
|
-
if (tmp[0]=="t"||tmp[0]=="ts"||tmp[0]=="a"||tmp[0]=="cl")
|
278
|
-
packets[tmp[0]] += tmp[1..-1]
|
279
|
-
end
|
280
|
-
if (tmp[0]=="mi"||tmp[0]=="mb"||tmp[0]=="di")
|
281
|
-
if !packets["mg"].nil?
|
282
|
-
packets["mg"].push(tmp)
|
283
|
-
else
|
284
|
-
packets["mg"] = [tmp]
|
285
|
-
end
|
286
|
-
end
|
287
|
-
else
|
288
|
-
packets[tmp[0]] = tmp
|
289
|
-
end
|
290
|
-
}
|
291
|
-
if packets["cl"] && packets["cl"].length > 1
|
292
|
-
packets["ce"] = []
|
293
|
-
for i in 1 .. packets["cl"].length-1
|
294
|
-
packets["ce"].push(packets["cl"][i])
|
295
|
-
end
|
296
|
-
end
|
297
|
-
@raw = packets
|
298
|
-
end
|
299
|
-
|
300
|
-
true
|
301
|
-
else # not logged in yet
|
302
|
-
false
|
303
|
-
end
|
304
|
-
end
|
305
|
-
private :__fetch
|
306
|
-
|
307
|
-
#
|
308
|
-
# return bool
|
309
|
-
# param constant type
|
310
|
-
# param mixed box
|
311
|
-
# param int pos
|
312
|
-
# desc Fetch contents from GMail by type.
|
313
|
-
#
|
314
|
-
def fetch_box(type, box, pos)
|
315
|
-
@type = type
|
316
|
-
if connected?
|
317
|
-
case type
|
318
|
-
when GM_STANDARD
|
319
|
-
q = "search=" + box.downcase + "&view=tl&start=" + pos.to_s
|
320
|
-
|
321
|
-
when GM_LABEL
|
322
|
-
q = "search=cat&cat=" + box.to_s + "&view=tl&start=" + pos.to_s
|
323
|
-
|
324
|
-
when GM_CONVERSATION
|
325
|
-
q = "search=all&ser=1&view=cv"
|
326
|
-
if (box.class==Array)
|
327
|
-
q += "&th=" + box[0].to_s
|
328
|
-
for i in 1 .. box.length
|
329
|
-
q += "&msgs=" + box[i].to_s
|
330
|
-
end
|
331
|
-
else
|
332
|
-
q += "&th=" + box.to_s
|
333
|
-
end
|
334
|
-
|
335
|
-
when GM_CONV_SPAM
|
336
|
-
q = "search=spam&ser=1&view=cv"
|
337
|
-
if (box.class==Array)
|
338
|
-
q += "&th=" + box[0].to_s
|
339
|
-
for i in 1 .. box.length
|
340
|
-
q += "&msgs=" + box[i].to_s
|
341
|
-
end
|
342
|
-
else
|
343
|
-
q += "&th=" + box.to_s
|
344
|
-
end
|
345
|
-
|
346
|
-
when GM_CONV_TRASH
|
347
|
-
q = "search=trash&ser=1&view=cv"
|
348
|
-
if (box.class==Array)
|
349
|
-
q += "&th=" + box[0].to_s
|
350
|
-
for i in 1 .. box.length
|
351
|
-
q += "&msgs=" + box[i].to_s
|
352
|
-
end
|
353
|
-
else
|
354
|
-
q += "&th=" + box.to_s
|
355
|
-
end
|
356
|
-
|
357
|
-
when GM_SHOWORIGINAL
|
358
|
-
q = "view=om&th=" + box.to_s
|
359
|
-
|
360
|
-
when GM_QUERY
|
361
|
-
q = "search=query&q=" + URI.escape(box.to_s) + "&view=tl&start=" + pos.to_s
|
362
|
-
|
363
|
-
when GM_PREFERENCE
|
364
|
-
q = "view=pr&pnl=g"
|
365
|
-
|
366
|
-
when GM_CONTACT
|
367
|
-
if box.downcase == "all"
|
368
|
-
q = "view=cl&search=contacts&pnl=a"
|
369
|
-
else
|
370
|
-
q = "view=cl&search=contacts&pnl=d"
|
371
|
-
end
|
372
|
-
|
373
|
-
else
|
374
|
-
q = "search=inbox&view=tl&start=0&init=1"
|
375
|
-
end
|
376
|
-
|
377
|
-
__fetch(q)
|
378
|
-
else
|
379
|
-
false
|
380
|
-
end
|
381
|
-
end
|
382
|
-
|
383
|
-
#
|
384
|
-
# return snapshot
|
385
|
-
# param constant type
|
386
|
-
# param mixed box
|
387
|
-
# param int pos
|
388
|
-
# desc Fetch contents from GMail by type.
|
389
|
-
#
|
390
|
-
def fetch(hash_param)
|
391
|
-
type = GM_STANDARD
|
392
|
-
box = "inbox"
|
393
|
-
pos = 0
|
394
|
-
@filter = {}
|
395
|
-
hash_param.keys.each do |k|
|
396
|
-
case k
|
397
|
-
when :label
|
398
|
-
type = GM_LABEL
|
399
|
-
box = hash_param[k]
|
400
|
-
when :standard
|
401
|
-
type = GM_STANDARD
|
402
|
-
box = hash_param[k]
|
403
|
-
when :conversation
|
404
|
-
type = GM_CONVERSATION
|
405
|
-
box = hash_param[k]
|
406
|
-
when :show_original
|
407
|
-
type = GM_SHOWORIGINAL
|
408
|
-
box = hash_param[k]
|
409
|
-
when :preference
|
410
|
-
type = GM_PREFERENCE
|
411
|
-
box = hash_param[k]
|
412
|
-
when :contact
|
413
|
-
type = GM_CONTACT
|
414
|
-
box = hash_param[k]
|
415
|
-
when :query
|
416
|
-
type = GM_QUERY
|
417
|
-
box = hash_param[k]
|
418
|
-
when :pos
|
419
|
-
pos = hash_param[k].to_i
|
420
|
-
when :read
|
421
|
-
@filter[:read] = hash_param[k]
|
422
|
-
when :star
|
423
|
-
@filter[:star] = hash_param[k]
|
424
|
-
else
|
425
|
-
raise ArgumentError, 'Invalid hash argument'
|
426
|
-
end
|
427
|
-
end
|
428
|
-
box = "inbox" unless box
|
429
|
-
fetch_box(type,box,pos)
|
430
|
-
if type == GM_CONVERSATION
|
431
|
-
fetch_box(GM_CONV_SPAM,box,pos) if @raw['mg'].nil?
|
432
|
-
fetch_box(GM_CONV_TRASH,box,pos) if @raw['mg'].nil?
|
433
|
-
end
|
434
|
-
|
435
|
-
if type == GM_SHOWORIGINAL
|
436
|
-
ss = @raw
|
437
|
-
else
|
438
|
-
ss = snapshot(type)
|
439
|
-
end
|
440
|
-
if block_given?
|
441
|
-
yield(ss)
|
442
|
-
elsif type == GM_CONTACT
|
443
|
-
ss.contacts
|
444
|
-
else
|
445
|
-
ss
|
446
|
-
end
|
447
|
-
end
|
448
|
-
|
449
|
-
#
|
450
|
-
# return message
|
451
|
-
# param message id
|
452
|
-
# desc Fetch a message with message id
|
453
|
-
#
|
454
|
-
def msg(msgid)
|
455
|
-
m = fetch(:conversation=>msgid).message
|
456
|
-
if m.nil? then
|
457
|
-
raise ArgumentError, 'Message Not Exist'
|
458
|
-
end
|
459
|
-
m.connection = self
|
460
|
-
if block_given?
|
461
|
-
yield(m)
|
462
|
-
else
|
463
|
-
m
|
464
|
-
end
|
465
|
-
|
466
|
-
end
|
467
|
-
|
468
|
-
#
|
469
|
-
# return string[]
|
470
|
-
# param string[] convs
|
471
|
-
# param string path
|
472
|
-
# desc Save all attaching files of conversations to a path.
|
473
|
-
#
|
474
|
-
def attachments_of(convs, path)
|
475
|
-
|
476
|
-
if connected?
|
477
|
-
if (convs.class != Array)
|
478
|
-
convs = [convs] # array wrapper
|
479
|
-
end
|
480
|
-
final = []
|
481
|
-
convs.each { |v|
|
482
|
-
if v.attachment
|
483
|
-
v.attachment.each { |vv|
|
484
|
-
f = path+"/"+vv.filename
|
485
|
-
f = path+"/"+vv.filename+"."+rand(2000).to_s while (FileTest.exist?(f))
|
486
|
-
if attachment(vv.id,v.id,f,false)
|
487
|
-
final.push(f)
|
488
|
-
end
|
489
|
-
}
|
490
|
-
end
|
491
|
-
}
|
492
|
-
final
|
493
|
-
else
|
494
|
-
nil
|
495
|
-
end
|
496
|
-
end
|
497
|
-
|
498
|
-
#
|
499
|
-
# return string[]
|
500
|
-
# param string[] convs
|
501
|
-
# param string path
|
502
|
-
# desc Save all attaching files of conversations to a path.
|
503
|
-
#
|
504
|
-
def zip_attachments_of(convs, path)
|
505
|
-
|
506
|
-
if connected?
|
507
|
-
if (convs.class != Array)
|
508
|
-
convs = [convs] # array wrapper
|
509
|
-
end
|
510
|
-
final = []
|
511
|
-
convs.each {|v|
|
512
|
-
if v.attachment
|
513
|
-
f = path+"/attachment.zip"
|
514
|
-
f = path+"/attachment."+rand(2000).to_s+".zip" while (FileTest.exist?(f))
|
515
|
-
if attachment(v["attachment"][0]["id"],v["id"],f,true)
|
516
|
-
final.push(f)
|
517
|
-
end
|
518
|
-
end
|
519
|
-
}
|
520
|
-
final
|
521
|
-
else
|
522
|
-
nil
|
523
|
-
end
|
524
|
-
end
|
525
|
-
|
526
|
-
#
|
527
|
-
# return bool
|
528
|
-
# param string attid
|
529
|
-
# param string msgid
|
530
|
-
# param string filename
|
531
|
-
# desc Save attachment with attachment ID attid and message ID msgid to file with name filename.
|
532
|
-
#
|
533
|
-
def attachment(attid, msgid, filename, zipped=false)
|
534
|
-
|
535
|
-
if connected?
|
536
|
-
|
537
|
-
if !zipped
|
538
|
-
query = GM_LNK_ATTACHMENT + "&attid=" + URI.escape(attid) + "&th=" + URI.escape(msgid)
|
539
|
-
else
|
540
|
-
query = GM_LNK_ATTACHMENT_ZIPPED + "&th=" + URI.escape(msgid)
|
541
|
-
end
|
542
|
-
|
543
|
-
File.open(filename,"wb") { |f|
|
544
|
-
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
545
|
-
np.start { |http|
|
546
|
-
response = http.get(query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
|
547
|
-
f.write(response.body)
|
548
|
-
}
|
549
|
-
}
|
550
|
-
true
|
551
|
-
else
|
552
|
-
false
|
553
|
-
end
|
554
|
-
end
|
555
|
-
|
556
|
-
#
|
557
|
-
# return array of labels
|
558
|
-
# desc get label lists
|
559
|
-
#
|
560
|
-
def labels()
|
561
|
-
if connected?
|
562
|
-
fetch(:standard=>"inbox") {|s| s.label_list }
|
563
|
-
else
|
564
|
-
nil
|
565
|
-
end
|
566
|
-
end
|
567
|
-
|
568
|
-
#
|
569
|
-
# return string
|
570
|
-
# param string label
|
571
|
-
# desc validate label
|
572
|
-
#
|
573
|
-
def validate_label(label)
|
574
|
-
label.strip!
|
575
|
-
if label==''
|
576
|
-
raise ArgumentError, 'Error: Labels cannot empty string'
|
577
|
-
end
|
578
|
-
if label.length > 40
|
579
|
-
raise ArgumentError, 'Error: Labels cannot contain more than 40 characters'
|
580
|
-
end
|
581
|
-
if label.include?('^')
|
582
|
-
raise ArgumentError, "Error: Labels cannot contain the character '^'"
|
583
|
-
end
|
584
|
-
label
|
585
|
-
end
|
586
|
-
|
587
|
-
#
|
588
|
-
# return boolean
|
589
|
-
# param string label
|
590
|
-
# desc create label
|
591
|
-
#
|
592
|
-
def create_label(label)
|
593
|
-
if connected?
|
594
|
-
perform_action(GM_ACT_CREATELABEL, '', validate_label(label))
|
595
|
-
else
|
596
|
-
false
|
597
|
-
end
|
598
|
-
end
|
599
|
-
|
600
|
-
#
|
601
|
-
# return boolean
|
602
|
-
# param string label
|
603
|
-
# desc create label
|
604
|
-
#
|
605
|
-
def delete_label(label)
|
606
|
-
if connected?
|
607
|
-
perform_action(GM_ACT_DELETELABEL, '', validate_label(label))
|
608
|
-
else
|
609
|
-
false
|
610
|
-
end
|
611
|
-
end
|
612
|
-
|
613
|
-
#
|
614
|
-
# return boolean
|
615
|
-
# param string old_label
|
616
|
-
# param string new_label
|
617
|
-
# desc create label
|
618
|
-
#
|
619
|
-
def rename_label(old_label,new_label)
|
620
|
-
if connected?
|
621
|
-
perform_action(GM_ACT_RENAMELABEL, '',
|
622
|
-
validate_label(old_label) +'^' + validate_label(new_label))
|
623
|
-
else
|
624
|
-
false
|
625
|
-
end
|
626
|
-
end
|
627
|
-
|
628
|
-
#
|
629
|
-
# return boolean
|
630
|
-
# param string msgid
|
631
|
-
# param string label
|
632
|
-
# desc apply label to message
|
633
|
-
#
|
634
|
-
def apply_label(id,label)
|
635
|
-
if connected?
|
636
|
-
perform_action(GM_ACT_APPLYLABEL, id, validate_label(label))
|
637
|
-
else
|
638
|
-
false
|
639
|
-
end
|
640
|
-
end
|
641
|
-
|
642
|
-
#
|
643
|
-
# return boolean
|
644
|
-
# param string msgid
|
645
|
-
# param string label
|
646
|
-
# desc remove label from message
|
647
|
-
#
|
648
|
-
def remove_label(id,label)
|
649
|
-
if connected?
|
650
|
-
perform_action(GM_ACT_REMOVELABEL, id, validate_label(label))
|
651
|
-
else
|
652
|
-
false
|
653
|
-
end
|
654
|
-
end
|
655
|
-
|
656
|
-
#
|
657
|
-
# return boolean
|
658
|
-
# param string hash_param
|
659
|
-
# desc remove label from message
|
660
|
-
#
|
661
|
-
def update_preference(hash_param)
|
662
|
-
if connected?
|
663
|
-
args = {}
|
664
|
-
hash_param.keys.each do |k|
|
665
|
-
case k
|
666
|
-
when :max_page_size
|
667
|
-
args['p_ix_nt'] = hash_param[k]
|
668
|
-
when :keyboard_shortcuts
|
669
|
-
args['p_bx_hs'] = hash_param[k] ? '1' : '0'
|
670
|
-
when :indicators
|
671
|
-
args['p_bx_sc'] = hash_param[k] ? '1' : '0'
|
672
|
-
when :display_language
|
673
|
-
args['p_sx_dl'] = hash_param[k]
|
674
|
-
when :signature
|
675
|
-
args['p_sx_sg'] = hash_param[k]
|
676
|
-
when :reply_to
|
677
|
-
args['p_sx_rt'] = hash_param[k]
|
678
|
-
when :snippets
|
679
|
-
args['p_bx_ns'] = hash_param[k] ? '0' : '1'
|
680
|
-
when :display_name
|
681
|
-
args['p_sx_dn'] = hash_param[k]
|
682
|
-
end
|
683
|
-
end
|
684
|
-
param = '&' + args.to_a.map {|x| x.join('=')}.join('&')
|
685
|
-
perform_action(GM_ACT_PREFERENCE,'', param)
|
686
|
-
else
|
687
|
-
false
|
688
|
-
end
|
689
|
-
end
|
690
|
-
|
691
|
-
#
|
692
|
-
# return boolean
|
693
|
-
# param string msgid
|
694
|
-
# desc apply star to a message
|
695
|
-
#
|
696
|
-
def apply_star(msgid)
|
697
|
-
if connected?
|
698
|
-
perform_action(GM_ACT_STAR,msgid, '')
|
699
|
-
else
|
700
|
-
false
|
701
|
-
end
|
702
|
-
end
|
703
|
-
|
704
|
-
#
|
705
|
-
# return boolean
|
706
|
-
# param string msgid
|
707
|
-
# desc remove star from a message
|
708
|
-
#
|
709
|
-
def remove_star(msgid)
|
710
|
-
if connected?
|
711
|
-
perform_action(GM_ACT_UNSTAR,msgid, '')
|
712
|
-
else
|
713
|
-
false
|
714
|
-
end
|
715
|
-
end
|
716
|
-
|
717
|
-
#
|
718
|
-
# return boolean
|
719
|
-
# param string msgid
|
720
|
-
# desc report a message as spam
|
721
|
-
#
|
722
|
-
def report_spam(msgid)
|
723
|
-
if connected?
|
724
|
-
perform_action(GM_ACT_SPAM,msgid, '')
|
725
|
-
else
|
726
|
-
false
|
727
|
-
end
|
728
|
-
end
|
729
|
-
|
730
|
-
#
|
731
|
-
# return boolean
|
732
|
-
# param string msgid
|
733
|
-
# desc report a message as not spam
|
734
|
-
#
|
735
|
-
def report_not_spam(msgid)
|
736
|
-
if connected?
|
737
|
-
perform_action(GM_ACT_UNSPAM,msgid, '')
|
738
|
-
else
|
739
|
-
false
|
740
|
-
end
|
741
|
-
end
|
742
|
-
|
743
|
-
#
|
744
|
-
# return boolean
|
745
|
-
# param string msgid
|
746
|
-
# desc delete a spam message forever
|
747
|
-
#
|
748
|
-
def delete_spam(msgid)
|
749
|
-
if connected?
|
750
|
-
perform_action(GM_ACT_DELSPAM,msgid, '')
|
751
|
-
else
|
752
|
-
false
|
753
|
-
end
|
754
|
-
end
|
755
|
-
|
756
|
-
#
|
757
|
-
# return boolean
|
758
|
-
# param string msgid
|
759
|
-
# desc mark a message as read
|
760
|
-
#
|
761
|
-
def mark_read(msgid)
|
762
|
-
if connected?
|
763
|
-
perform_action(GM_ACT_READ,msgid, '')
|
764
|
-
else
|
765
|
-
false
|
766
|
-
end
|
767
|
-
end
|
768
|
-
|
769
|
-
#
|
770
|
-
# return boolean
|
771
|
-
# param string msgid
|
772
|
-
# desc mark a message as unread
|
773
|
-
#
|
774
|
-
def mark_unread(msgid)
|
775
|
-
if connected?
|
776
|
-
perform_action(GM_ACT_UNREAD,msgid, '')
|
777
|
-
else
|
778
|
-
false
|
779
|
-
end
|
780
|
-
end
|
781
|
-
|
782
|
-
#
|
783
|
-
# return original message string
|
784
|
-
# param string msgid
|
785
|
-
# desc show original message format
|
786
|
-
#
|
787
|
-
def show_original(msgid)
|
788
|
-
if connected?
|
789
|
-
fetch(:show_original=>msgid)
|
790
|
-
else
|
791
|
-
false
|
792
|
-
end
|
793
|
-
end
|
794
|
-
|
795
|
-
#
|
796
|
-
# return boolean
|
797
|
-
# param string msgid
|
798
|
-
# desc move a message to trash
|
799
|
-
#
|
800
|
-
def trash(msgid)
|
801
|
-
if connected?
|
802
|
-
perform_action(GM_ACT_TRASH,msgid, '')
|
803
|
-
else
|
804
|
-
false
|
805
|
-
end
|
806
|
-
end
|
807
|
-
|
808
|
-
#
|
809
|
-
# return boolean
|
810
|
-
# param string msgid
|
811
|
-
# desc move a message from trash to inbox
|
812
|
-
#
|
813
|
-
def untrash(msgid)
|
814
|
-
if connected?
|
815
|
-
perform_action(GM_ACT_UNTRASH,msgid, '')
|
816
|
-
else
|
817
|
-
false
|
818
|
-
end
|
819
|
-
end
|
820
|
-
|
821
|
-
#
|
822
|
-
# return boolean
|
823
|
-
# param string msgid
|
824
|
-
# desc delete a trash message forever
|
825
|
-
#
|
826
|
-
def delete_trash(msgid)
|
827
|
-
if connected?
|
828
|
-
perform_action(GM_ACT_DELTRASH,msgid, '')
|
829
|
-
else
|
830
|
-
false
|
831
|
-
end
|
832
|
-
end
|
833
|
-
|
834
|
-
#
|
835
|
-
# return boolean
|
836
|
-
# param string msgid
|
837
|
-
# desc delete a message forever
|
838
|
-
#
|
839
|
-
def delete_message(msgid)
|
840
|
-
if connected?
|
841
|
-
perform_action(GM_ACT_DELFOREVER,msgid, '')
|
842
|
-
else
|
843
|
-
false
|
844
|
-
end
|
845
|
-
end
|
846
|
-
|
847
|
-
#
|
848
|
-
# return boolean
|
849
|
-
# param string msgid
|
850
|
-
# desc archive a message
|
851
|
-
#
|
852
|
-
def archive(msgid)
|
853
|
-
if connected?
|
854
|
-
perform_action(GM_ACT_ARCHIVE,msgid, '')
|
855
|
-
else
|
856
|
-
false
|
857
|
-
end
|
858
|
-
end
|
859
|
-
|
860
|
-
#
|
861
|
-
# return boolean
|
862
|
-
# param string msgid
|
863
|
-
# desc archive a message
|
864
|
-
#
|
865
|
-
def unarchive(msgid)
|
866
|
-
if connected?
|
867
|
-
perform_action(GM_ACT_INBOX,msgid, '')
|
868
|
-
else
|
869
|
-
false
|
870
|
-
end
|
871
|
-
end
|
872
|
-
|
873
|
-
|
874
|
-
#
|
875
|
-
# return hash of preference
|
876
|
-
# desc get preferences
|
877
|
-
#
|
878
|
-
def preference()
|
879
|
-
if connected?
|
880
|
-
fetch(:preference=>"all").preference
|
881
|
-
else
|
882
|
-
nil
|
883
|
-
end
|
884
|
-
end
|
885
|
-
|
886
|
-
#
|
887
|
-
# return array of messages
|
888
|
-
# desc get message lists
|
889
|
-
#
|
890
|
-
def messages(hash_param)
|
891
|
-
if connected?
|
892
|
-
ml = fetch(hash_param).message_list
|
893
|
-
@filter.keys.each do |k|
|
894
|
-
case k
|
895
|
-
when :read
|
896
|
-
ml.box = ml.box.find_all { |x| x.read? == @filter[k] }
|
897
|
-
when :star
|
898
|
-
ml.box = ml.box.find_all { |x| x.star? == @filter[k] }
|
899
|
-
end
|
900
|
-
end
|
901
|
-
ml.connection = self
|
902
|
-
if block_given?
|
903
|
-
yield(ml)
|
904
|
-
else
|
905
|
-
ml
|
906
|
-
end
|
907
|
-
else
|
908
|
-
nil
|
909
|
-
end
|
910
|
-
end
|
911
|
-
|
912
|
-
#
|
913
|
-
# return string
|
914
|
-
# param string query
|
915
|
-
# desc Dump everything to output.
|
916
|
-
#
|
917
|
-
def dump(query)
|
918
|
-
page = ''
|
919
|
-
if connected?
|
920
|
-
query += "&zv=" + (rand(2000)*2147483.648).to_i.to_s
|
921
|
-
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
922
|
-
np.start { |http|
|
923
|
-
response = http.get(GM_LNK_GMAIL + "?"+query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
|
924
|
-
page = response.body
|
925
|
-
}
|
926
|
-
else # not logged in yet
|
927
|
-
|
928
|
-
end
|
929
|
-
page
|
930
|
-
end
|
931
|
-
|
932
|
-
def stripslashes(string)
|
933
|
-
encode(string.gsub("\\\"", "\"").gsub("\\'", "'").gsub("\\\\", "\\"))
|
934
|
-
end
|
935
|
-
|
936
|
-
|
937
|
-
#
|
938
|
-
# return bool
|
939
|
-
# param string to
|
940
|
-
# param string subject
|
941
|
-
# param string body
|
942
|
-
# param string cc
|
943
|
-
# param string bcc
|
944
|
-
# param string msg_id
|
945
|
-
# param string thread_id
|
946
|
-
# param string[] files
|
947
|
-
# desc Send GMail.
|
948
|
-
#
|
949
|
-
def send(*param)
|
950
|
-
if param.length==1 && param[0].class==Hash
|
951
|
-
param = param[0]
|
952
|
-
from = param[:from] || ''
|
953
|
-
to = param[:to] || ''
|
954
|
-
subject = param[:subject] || ''
|
955
|
-
body = param[:body] || ''
|
956
|
-
cc = param[:cc] || ''
|
957
|
-
bcc = param[:bcc] || ''
|
958
|
-
msg_id = param[:msg_id] || ''
|
959
|
-
thread_id = param[:msg_id] || ''
|
960
|
-
files = param[:files] || []
|
961
|
-
draft = param[:draft] || false
|
962
|
-
draft_id = param[:draft_id] || ''
|
963
|
-
elsif param.length==10
|
964
|
-
to, subject, body, cc, bcc, msg_id, thread_id, files, draft, draft_id = param
|
965
|
-
elsif param.length==11
|
966
|
-
from, to, subject, body, cc, bcc, msg_id, thread_id, files, draft, draft_id = param
|
967
|
-
else
|
968
|
-
raise ArgumentError, 'Invalid argument'
|
969
|
-
end
|
970
|
-
|
971
|
-
if connected?
|
972
|
-
other_emails = fetch(:preference=>"all").other_emails
|
973
|
-
if other_emails.length>0
|
974
|
-
other_emails.each {|v|
|
975
|
-
from = v['email'] if from=='' && v['default']
|
976
|
-
}
|
977
|
-
from = @login + '@gmail.com' if from==''
|
978
|
-
else
|
979
|
-
from = nil
|
980
|
-
end
|
981
|
-
|
982
|
-
postdata = {}
|
983
|
-
if draft
|
984
|
-
postdata["view"] = "sd"
|
985
|
-
postdata["draft"] = draft_id
|
986
|
-
postdata["rm"] = msg_id
|
987
|
-
postdata["th"] = thread_id
|
988
|
-
else
|
989
|
-
postdata["view"] = "sm"
|
990
|
-
postdata["draft"] = draft_id
|
991
|
-
postdata["rm"] = msg_id
|
992
|
-
postdata["th"] = thread_id
|
993
|
-
end
|
994
|
-
postdata["msgbody"] = stripslashes(body)
|
995
|
-
postdata["from"] = stripslashes(from) if from
|
996
|
-
postdata["to"] = stripslashes(to)
|
997
|
-
postdata["subject"] = stripslashes(subject)
|
998
|
-
postdata["cc"] = stripslashes(cc)
|
999
|
-
postdata["bcc"] = stripslashes(bcc)
|
1000
|
-
|
1001
|
-
postdata["cmid"] = 1
|
1002
|
-
postdata["ishtml"] = param[:ishtml] || 0
|
1003
|
-
|
1004
|
-
cc = @cookie_str.split(';')
|
1005
|
-
cc.each {|cc_part|
|
1006
|
-
cc_parts = cc_part.split('=')
|
1007
|
-
if(cc_parts[0]=='GMAIL_AT')
|
1008
|
-
postdata["at"] = cc_parts[1]
|
1009
|
-
break
|
1010
|
-
end
|
1011
|
-
}
|
1012
|
-
|
1013
|
-
boundary = "----#{Time.now.to_i}#{(rand(2000)*2147483.648).to_i}"
|
1014
|
-
postdata2 = []
|
1015
|
-
postdata.each {|k,v|
|
1016
|
-
postdata2.push("Content-Disposition: form-data; name=\"#{k}\"\r\n\r\n#{v}\r\n")
|
1017
|
-
}
|
1018
|
-
|
1019
|
-
files.each_with_index {|f,i|
|
1020
|
-
content = File.open(f,'rb') { |c| c.read }
|
1021
|
-
postdata2.push("Content-Disposition: form-data; name=\"file#{i}\"; filename=\"#{File.basename(f)}\"\r\n" +
|
1022
|
-
"Content-Transfer-Encoding: binary\r\n" +
|
1023
|
-
"Content-Type: application/octet-stream\r\n\r\n" + content + "\r\n")
|
1024
|
-
}
|
1025
|
-
|
1026
|
-
postdata = postdata2.collect { |p|
|
1027
|
-
"--" + boundary + "\r\n" + p
|
1028
|
-
}.join('') + "--" + boundary + "--\r\n"
|
1029
|
-
|
1030
|
-
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
1031
|
-
response = nil
|
1032
|
-
# np.set_debug_output($stderr)
|
1033
|
-
np.start { |http|
|
1034
|
-
response = http.post(GM_LNK_GMAIL, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT,'Content-type' => 'multipart/form-data; boundary=' + boundary } )
|
1035
|
-
}
|
1036
|
-
true
|
1037
|
-
else
|
1038
|
-
false
|
1039
|
-
end
|
1040
|
-
|
1041
|
-
end
|
1042
|
-
|
1043
|
-
#
|
1044
|
-
# return bool
|
1045
|
-
# param constant act
|
1046
|
-
# param string[] id
|
1047
|
-
# param string para
|
1048
|
-
# desc Perform action on messages.
|
1049
|
-
#
|
1050
|
-
def perform_action(act, id, para)
|
1051
|
-
|
1052
|
-
if connected?
|
1053
|
-
|
1054
|
-
if (act == GM_ACT_DELFOREVER)
|
1055
|
-
perform_action(GM_ACT_TRASH, id, 0) # trash it before
|
1056
|
-
end
|
1057
|
-
postdata = "act="
|
1058
|
-
|
1059
|
-
action_codes = ["ib", "cc_", "dc_", "nc_", "ac_", "rc_", "prefs", "st", "xst",
|
1060
|
-
"sp", "us", "rd", "ur", "tr", "dl", "rc_^i", "ib", "ib", "dd", "dm", "dl", "dl"]
|
1061
|
-
postdata += action_codes[act] ? action_codes[act] : action_codes[GM_ACT_INBOX]
|
1062
|
-
if act == GM_ACT_RENAMELABEL then
|
1063
|
-
paras = para.split('^')
|
1064
|
-
para = validate_label(paras[0])+'^'+validate_label(paras[1])
|
1065
|
-
elsif ([GM_ACT_APPLYLABEL,GM_ACT_REMOVELABEL,GM_ACT_CREATELABEL,
|
1066
|
-
GM_ACT_DELETELABEL,].include?(act))
|
1067
|
-
para = validate_label(para)
|
1068
|
-
end
|
1069
|
-
if ([GM_ACT_APPLYLABEL,GM_ACT_REMOVELABEL,GM_ACT_CREATELABEL,
|
1070
|
-
GM_ACT_DELETELABEL,GM_ACT_RENAMELABEL,GM_ACT_PREFERENCE].include?(act))
|
1071
|
-
postdata += para.to_s
|
1072
|
-
end
|
1073
|
-
|
1074
|
-
cc = @cookie_str.split(';')
|
1075
|
-
cc.each {|cc_part|
|
1076
|
-
cc_parts = cc_part.split('=')
|
1077
|
-
if(cc_parts[0]=='GMAIL_AT')
|
1078
|
-
postdata += "&at=" + cc_parts[1]
|
1079
|
-
break
|
1080
|
-
end
|
1081
|
-
}
|
1082
|
-
|
1083
|
-
if (act == GM_ACT_TRASHMSG)
|
1084
|
-
postdata += "&m=" + id.to_s
|
1085
|
-
else
|
1086
|
-
if id.class==Array
|
1087
|
-
id.each {|t| postdata += "&t="+t.to_s }
|
1088
|
-
else
|
1089
|
-
postdata += "&t="+id.to_s
|
1090
|
-
end
|
1091
|
-
end
|
1092
|
-
postdata += "&vp="
|
1093
|
-
|
1094
|
-
if [GM_ACT_UNTRASH,GM_ACT_DELFOREVER,GM_ACT_DELTRASH].include?(act)
|
1095
|
-
link = GM_LNK_GMAIL+"?search=trash&view=tl&start=0"
|
1096
|
-
elsif (act == GM_ACT_DELSPAM)
|
1097
|
-
link = GM_LNK_GMAIL+"?search=spam&view=tl&start=0"
|
1098
|
-
else
|
1099
|
-
link = GM_LNK_GMAIL+"?search=query&q=&view=tl&start=0"
|
1100
|
-
end
|
1101
|
-
|
1102
|
-
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
1103
|
-
# np.set_debug_output($stderr)
|
1104
|
-
np.start { |http|
|
1105
|
-
response = http.post(link, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
|
1106
|
-
result = response.body
|
1107
|
-
}
|
1108
|
-
|
1109
|
-
return true
|
1110
|
-
else
|
1111
|
-
return false
|
1112
|
-
end
|
1113
|
-
|
1114
|
-
end
|
1115
|
-
|
1116
|
-
#
|
1117
|
-
# return void
|
1118
|
-
# desc Disconnect from GMail.
|
1119
|
-
#
|
1120
|
-
def disconnect()
|
1121
|
-
|
1122
|
-
response = nil
|
1123
|
-
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
1124
|
-
# np.set_debug_output($stderr)
|
1125
|
-
np.start { |http|
|
1126
|
-
response = http.get(GM_LNK_LOGOUT,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
|
1127
|
-
}
|
1128
|
-
arr = URI::split(response["Location"])
|
1129
|
-
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 80)
|
1130
|
-
# np.set_debug_output($stderr)
|
1131
|
-
np.start { |http|
|
1132
|
-
response = http.get(arr[5]+'?'+arr[7], {'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
|
1133
|
-
}
|
1134
|
-
|
1135
|
-
@cookie_str = ''
|
1136
|
-
end
|
1137
|
-
|
1138
|
-
#
|
1139
|
-
# return GMailSnapshot
|
1140
|
-
# param constant type
|
1141
|
-
# desc Get GMSnapshot by type.
|
1142
|
-
#
|
1143
|
-
def snapshot(type)
|
1144
|
-
if [GM_STANDARD,GM_LABEL,GM_CONVERSATION,GM_QUERY,GM_PREFERENCE,GM_CONTACT].include?(type)
|
1145
|
-
return GMailSnapshot.new(type, @raw, @charset)
|
1146
|
-
else
|
1147
|
-
return GMailSnapshot.new(GM_STANDARD, @raw, @charset) # assuming normal by default
|
1148
|
-
end
|
1149
|
-
end
|
1150
|
-
|
1151
|
-
def snap(type)
|
1152
|
-
action = GM_STANDARD
|
1153
|
-
case type
|
1154
|
-
when :standard
|
1155
|
-
action = GM_STANDARD
|
1156
|
-
when :label
|
1157
|
-
action = GM_LABEL
|
1158
|
-
when :conversation
|
1159
|
-
action = GM_CONVERSATION
|
1160
|
-
when :query
|
1161
|
-
action = GM_QUERY
|
1162
|
-
when :preference
|
1163
|
-
action = GM_PREFERENCE
|
1164
|
-
when :contact
|
1165
|
-
action = GM_CONTACT
|
1166
|
-
else
|
1167
|
-
raise ArgumentError, 'Invalid type'
|
1168
|
-
end
|
1169
|
-
snapshot(action)
|
1170
|
-
end
|
1171
|
-
|
1172
|
-
#
|
1173
|
-
# return bool
|
1174
|
-
# param string email
|
1175
|
-
# desc Send Gmail invite to email
|
1176
|
-
#
|
1177
|
-
def invite(email)
|
1178
|
-
|
1179
|
-
if connected?
|
1180
|
-
|
1181
|
-
postdata = "act=ii&em=" + URI.escape(email)
|
1182
|
-
|
1183
|
-
cc = @cookie_str.split(';')
|
1184
|
-
cc.each {|cc_part|
|
1185
|
-
cc_parts = cc_part.split('=')
|
1186
|
-
if(cc_parts[0]=='GMAIL_AT')
|
1187
|
-
postdata += "&at=" + cc_parts[1]
|
1188
|
-
break
|
1189
|
-
end
|
1190
|
-
}
|
1191
|
-
|
1192
|
-
link = GM_LNK_GMAIL + "?view=ii"
|
1193
|
-
|
1194
|
-
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 443)
|
1195
|
-
np.use_ssl = true
|
1196
|
-
np.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
1197
|
-
# np.set_debug_output($stderr)
|
1198
|
-
np.start { |http|
|
1199
|
-
response = http.post(link, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
|
1200
|
-
}
|
1201
|
-
|
1202
|
-
true
|
1203
|
-
else
|
1204
|
-
false
|
1205
|
-
end
|
1206
|
-
|
1207
|
-
end
|
1208
|
-
|
1209
|
-
#
|
1210
|
-
# return string[]
|
1211
|
-
# desc (Static) Get names of standard boxes.
|
1212
|
-
#
|
1213
|
-
def standard_box()
|
1214
|
-
["Inbox","Starred","Sent","Drafts","All","Spam","Trash"]
|
1215
|
-
end
|
1216
|
-
|
1217
|
-
#
|
1218
|
-
# return string
|
1219
|
-
# param string header
|
1220
|
-
# desc (Static Private) Extract cookies from header.
|
1221
|
-
#
|
1222
|
-
def __cookies(header)
|
1223
|
-
return '' unless header
|
1224
|
-
arr = []
|
1225
|
-
header.split(', ').each { |x|
|
1226
|
-
if x.include?('GMT')
|
1227
|
-
arr[-1] += ", " + x
|
1228
|
-
else
|
1229
|
-
arr.push x
|
1230
|
-
end
|
1231
|
-
}
|
1232
|
-
arr.delete_if {|x| x.include?('LSID=EXPIRED') }
|
1233
|
-
arr.map! {|x| x.split(';')[0]}
|
1234
|
-
arr.join(';')
|
1235
|
-
end
|
1236
|
-
|
1237
|
-
end
|
1238
|
-
|
1239
|
-
|
1240
|
-
class GMailSnapshot
|
1241
|
-
|
1242
|
-
GM_STANDARD = 0x001
|
1243
|
-
GM_LABEL = 0x002
|
1244
|
-
GM_CONVERSATION = 0x004
|
1245
|
-
GM_QUERY = 0x008
|
1246
|
-
GM_CONTACT = 0x010
|
1247
|
-
GM_PREFERENCE = 0x020
|
1248
|
-
|
1249
|
-
def decode(str)
|
1250
|
-
return str if @charset.upcase == 'UTF-8'
|
1251
|
-
begin
|
1252
|
-
require 'Win32API'
|
1253
|
-
str = str.unpack("U*").pack("S*") + "\0"
|
1254
|
-
ostr = "\0" * str.length*2
|
1255
|
-
wideCharToMultiByte = Win32API.new('kernel32','WideCharToMultiByte',['L','L','P','L','P','L','L','L'],'L')
|
1256
|
-
wideCharToMultiByte.Call(0,0,str,-1,ostr,str.length*2,0,0)
|
1257
|
-
ostr.strip
|
1258
|
-
rescue LoadError
|
1259
|
-
require 'iconv'
|
1260
|
-
Iconv::iconv(@charset,'UTF-8',str)[0]
|
1261
|
-
end
|
1262
|
-
end
|
1263
|
-
|
1264
|
-
def strip_tags(str,allowable_tags='')
|
1265
|
-
str.gsub(/<[^>]*>/, '')
|
1266
|
-
end
|
1267
|
-
|
1268
|
-
#
|
1269
|
-
# return GMailSnapshot
|
1270
|
-
# param constant type
|
1271
|
-
# param array raw
|
1272
|
-
# desc Constructor.
|
1273
|
-
#
|
1274
|
-
attr_reader :gmail_ver, :quota_mb, :quota_per, :preference
|
1275
|
-
attr_reader :std_box_new, :have_invit, :label_list, :label_new
|
1276
|
-
attr_reader :message_list
|
1277
|
-
attr_reader :message
|
1278
|
-
attr_reader :contacts, :other_emails
|
1279
|
-
|
1280
|
-
def initialize(type, raw, charset='UTF-8')
|
1281
|
-
@charset = charset
|
1282
|
-
if (raw.class!=Hash)
|
1283
|
-
@created = 0
|
1284
|
-
return nil
|
1285
|
-
elsif (raw.empty?)
|
1286
|
-
@created = 0
|
1287
|
-
return nil
|
1288
|
-
end
|
1289
|
-
if [GM_STANDARD,GM_LABEL,GM_CONVERSATION,GM_QUERY].include?(type)
|
1290
|
-
@gmail_ver = raw["v"][1]
|
1291
|
-
if raw["qu"]
|
1292
|
-
@quota_mb = raw["qu"][1]
|
1293
|
-
@quota_per = raw["qu"][3]
|
1294
|
-
end
|
1295
|
-
if (raw["ds"].class!=Array)
|
1296
|
-
@created = 0
|
1297
|
-
return nil
|
1298
|
-
end
|
1299
|
-
@std_box_new = raw["ds"][1..-1]
|
1300
|
-
#if (isset(raw["p"])) {
|
1301
|
-
# @owner = raw["p"][5][1]
|
1302
|
-
# @owner_email = raw["p"][6][1]
|
1303
|
-
#end
|
1304
|
-
@have_invit = raw["i"][1]
|
1305
|
-
@label_list = []
|
1306
|
-
@label_new = []
|
1307
|
-
raw["ct"][1].each {|v|
|
1308
|
-
@label_list.push(v[0])
|
1309
|
-
@label_new.push(v[1])
|
1310
|
-
}
|
1311
|
-
if raw["ts"]
|
1312
|
-
@view = (GM_STANDARD|GM_LABEL|GM_QUERY)
|
1313
|
-
@message_list = MessageList.new(raw["ts"][5],raw["ts"][3],raw["ts"][1])
|
1314
|
-
end
|
1315
|
-
@box = []
|
1316
|
-
if raw["t"]
|
1317
|
-
raw["t"].each do |t|
|
1318
|
-
if (t != "t")
|
1319
|
-
b = Box.new
|
1320
|
-
b.id = t[0]
|
1321
|
-
b.is_read = (t[1] != 1 ? 1 : 0)
|
1322
|
-
b.is_starred = (t[2] == 1 ? 1 : 0)
|
1323
|
-
b.date = decode(strip_tags(t[3]))
|
1324
|
-
b.sender = decode(strip_tags(t[4]))
|
1325
|
-
b.flag = t[5]
|
1326
|
-
b.subject = decode(strip_tags(t[6]))
|
1327
|
-
b.snippet = decode(t[7].gsub('"','"').gsub('…','...'))
|
1328
|
-
b.labels = t[8].empty? ? [] : t[8].map{|tt|decode(tt)}
|
1329
|
-
b.attachment = t[9].empty? ? []: decode(t[9]).split(",")
|
1330
|
-
b.msgid = t[10]
|
1331
|
-
@box.push(b)
|
1332
|
-
end
|
1333
|
-
end
|
1334
|
-
end
|
1335
|
-
|
1336
|
-
if (!raw["cs"].nil?)
|
1337
|
-
@view = GM_CONVERSATION
|
1338
|
-
@conv_title = raw["cs"][2]
|
1339
|
-
@conv_total = raw["cs"][8]
|
1340
|
-
@conv_id = raw["cs"][1]
|
1341
|
-
@conv_labels = raw["cs"][5].empty? ? '' : raw["cs"][5]
|
1342
|
-
if !@conv_labels.empty?
|
1343
|
-
ij = @conv_labels.index("^i")
|
1344
|
-
if !ij.nil?
|
1345
|
-
@conv_labels[ij] = "Inbox"
|
1346
|
-
end
|
1347
|
-
ij = @conv_labels.index("^s")
|
1348
|
-
if !ij.nil?
|
1349
|
-
@conv_labels[ij] = "Spam"
|
1350
|
-
end
|
1351
|
-
ij = @conv_labels.index("^k")
|
1352
|
-
if !ij.nil?
|
1353
|
-
@conv_labels[ij] = "Trash"
|
1354
|
-
end
|
1355
|
-
ij = @conv_labels.index("^t")
|
1356
|
-
if !ij.nil?
|
1357
|
-
@conv_labels[ij] = '' # Starred
|
1358
|
-
end
|
1359
|
-
ij = @conv_labels.index("^r")
|
1360
|
-
if !ij.nil?
|
1361
|
-
@conv_labels[ij] = "Drafts"
|
1362
|
-
end
|
1363
|
-
end
|
1364
|
-
|
1365
|
-
@conv_starred = false
|
1366
|
-
|
1367
|
-
@conv = []
|
1368
|
-
b = Conversation.new
|
1369
|
-
raw["mg"].each do |r|
|
1370
|
-
if (r[0] == "mb")
|
1371
|
-
b.body = '' if b.body.nil?
|
1372
|
-
b.body += r[1]
|
1373
|
-
if (r[2] == 0)
|
1374
|
-
b.body = decode(b.body)
|
1375
|
-
@conv.push(b)
|
1376
|
-
b = Conversation.new
|
1377
|
-
end
|
1378
|
-
elsif (r[0] == "mi")
|
1379
|
-
if !b.id.nil?
|
1380
|
-
@conv.push(b)
|
1381
|
-
b = Conversation.new
|
1382
|
-
end
|
1383
|
-
b = Conversation.new
|
1384
|
-
b.index = r[2]
|
1385
|
-
b.id = r[3]
|
1386
|
-
b.is_star = r[4]
|
1387
|
-
@conv_starred = (b.is_star == 1)
|
1388
|
-
b.sender = decode(r[6])
|
1389
|
-
b.sender_email = r[8].gsub("\"",'') # remove annoying d-quotes in address
|
1390
|
-
b.recv = r[9]
|
1391
|
-
b.recv_email = r[11].to_s.gsub("\"",'')
|
1392
|
-
b.reply_email = r[14].to_s.gsub("\"",'')
|
1393
|
-
b.dt_easy = r[10]
|
1394
|
-
b.dt = r[15]
|
1395
|
-
b.subject = decode(r[16])
|
1396
|
-
b.snippet = decode(r[17])
|
1397
|
-
b.attachment = []
|
1398
|
-
r[18].each do |bb|
|
1399
|
-
at = Attachment.new
|
1400
|
-
at.id = bb[0]
|
1401
|
-
at.filename = bb[1]
|
1402
|
-
at.type = bb[2]
|
1403
|
-
at.size = bb[3]
|
1404
|
-
b.attachment.push(at)
|
1405
|
-
end
|
1406
|
-
b.is_draft = false
|
1407
|
-
b.body = ''
|
1408
|
-
elsif (r[0] == "di")
|
1409
|
-
if !b.id.nil?
|
1410
|
-
@conv.push(b)
|
1411
|
-
b = Conversation.new
|
1412
|
-
end
|
1413
|
-
b = Conversation.new
|
1414
|
-
b.index = r[2]
|
1415
|
-
b.id = r[3]
|
1416
|
-
b.is_star = r[4]
|
1417
|
-
@conv_starred = (b.is_star == 1)
|
1418
|
-
b.sender = decode(r[6])
|
1419
|
-
b.sender_email = r[8].gsub("\"",'') # remove annoying d-quotes in address
|
1420
|
-
b.recv = r[9]
|
1421
|
-
b.recv_email = r[11].gsub("\"",'')
|
1422
|
-
b.reply_email = r[14].gsub("\"",'')
|
1423
|
-
b.cc_email = r[12].gsub("\"",'')
|
1424
|
-
b.bcc_email = r[13].gsub("\"",'')
|
1425
|
-
b.dt_easy = r[10]
|
1426
|
-
b.dt = r[15]
|
1427
|
-
b.subject = decode(r[16])
|
1428
|
-
b.snippet = decode(r[17])
|
1429
|
-
b.attachment = []
|
1430
|
-
r[18].each do |bb|
|
1431
|
-
at = Attachment.new
|
1432
|
-
at.id = bb[0]
|
1433
|
-
at.filename = bb[1]
|
1434
|
-
at.type = bb[2]
|
1435
|
-
at.size = bb[3]
|
1436
|
-
b.attachment.push(at)
|
1437
|
-
end
|
1438
|
-
b.is_draft = true
|
1439
|
-
b.draft_parent = r[5]
|
1440
|
-
b.body = decode(r[20])
|
1441
|
-
end
|
1442
|
-
end
|
1443
|
-
@conv.push(b) unless !b.id.nil?
|
1444
|
-
@message = Message.new(@conv_tile,@conv_total,@conv_id,@conv_labels,@conv_starred)
|
1445
|
-
@message.conv = @conv
|
1446
|
-
end
|
1447
|
-
elsif type == GM_CONTACT
|
1448
|
-
@contacts = []
|
1449
|
-
if raw["ce"]
|
1450
|
-
raw["ce"].each {|a|
|
1451
|
-
c = Contact.new
|
1452
|
-
c.name = a[2]
|
1453
|
-
c.email = a[4].gsub("\"",'')
|
1454
|
-
c.notes = a[5] if !a[5].empty?
|
1455
|
-
@contacts.push(c)
|
1456
|
-
}
|
1457
|
-
end
|
1458
|
-
@view = GM_CONTACT
|
1459
|
-
elsif type == GM_PREFERENCE
|
1460
|
-
prefs = {}
|
1461
|
-
raw["p"].each_with_index { |v,i|
|
1462
|
-
prefs[v[0]] = v[1] if i>0
|
1463
|
-
}
|
1464
|
-
@preference = Preference.new
|
1465
|
-
prefs.each do |k,v|
|
1466
|
-
case k
|
1467
|
-
when 'ix_nt'
|
1468
|
-
@preference.max_page_size = v
|
1469
|
-
when 'bx_hs'
|
1470
|
-
@preference.keyboard_shortcuts = (v == '1')
|
1471
|
-
when 'bx_sc'
|
1472
|
-
@preference.indicators = (v == '1')
|
1473
|
-
when 'sx_dl'
|
1474
|
-
@preference.display_language = v
|
1475
|
-
when 'sx_sg'
|
1476
|
-
@preference.signature = (v == '0') ? '' : v
|
1477
|
-
when 'sx_rt'
|
1478
|
-
@preference.reply_to = v
|
1479
|
-
when 'bx_ns'
|
1480
|
-
@preference.snippets = (v == '0')
|
1481
|
-
when 'sx_dn'
|
1482
|
-
@preference.display_name = v
|
1483
|
-
end
|
1484
|
-
end
|
1485
|
-
|
1486
|
-
@label_list = []
|
1487
|
-
@label_total = []
|
1488
|
-
raw["cta"][1].each { |v|
|
1489
|
-
@label_list.push(v[0])
|
1490
|
-
@label_total.push(v[1])
|
1491
|
-
}
|
1492
|
-
@other_emails = []
|
1493
|
-
if raw["cfs"]
|
1494
|
-
raw["cfs"][1].each {|v|
|
1495
|
-
@other_emails.push({"name"=>decode(v[0]),"email"=>v[1],"default"=>(v[2]==1)})
|
1496
|
-
}
|
1497
|
-
end
|
1498
|
-
@filter = []
|
1499
|
-
raw["fi"][1].each do |fi|
|
1500
|
-
f = Filter.new
|
1501
|
-
f.id = fi[0]
|
1502
|
-
f.query = fi[1]
|
1503
|
-
f.star = fi[3]
|
1504
|
-
f.label = fi[4]
|
1505
|
-
f.archive = fi[5]
|
1506
|
-
f.trash = fi[6]
|
1507
|
-
f.from = fi[2][0]
|
1508
|
-
f.to = fi[2][1]
|
1509
|
-
f.subject = fi[2][2]
|
1510
|
-
f.has = fi[2][3]
|
1511
|
-
f.hasnot = fi[2][4]
|
1512
|
-
f.attach = fi[2][5]
|
1513
|
-
|
1514
|
-
@filter.push(b)
|
1515
|
-
end
|
1516
|
-
@view = GM_PREFERENCE
|
1517
|
-
else
|
1518
|
-
@created = 0
|
1519
|
-
return nil
|
1520
|
-
end
|
1521
|
-
@message_list.box = @box if @message_list
|
1522
|
-
|
1523
|
-
@created = 1
|
1524
|
-
end
|
1525
|
-
|
1526
|
-
end
|
1527
|
-
|
1528
|
-
# a single filter
|
1529
|
-
class Filter
|
1530
|
-
attr_accessor :id,:query,:star,:label,:archive,:trash
|
1531
|
-
attr_accessor :from,:to,:subject,:has,:hasnot,:attach
|
1532
|
-
end
|
1533
|
-
|
1534
|
-
# a single box
|
1535
|
-
class Box
|
1536
|
-
attr_accessor :id, :is_read, :is_starred, :date, :msgid
|
1537
|
-
attr_accessor :sender, :flag, :subject, :snippet, :labels, :attachment
|
1538
|
-
|
1539
|
-
def read?
|
1540
|
-
is_read == 1
|
1541
|
-
end
|
1542
|
-
|
1543
|
-
def new?
|
1544
|
-
is_read != 1
|
1545
|
-
end
|
1546
|
-
|
1547
|
-
def star?
|
1548
|
-
is_starred == 1
|
1549
|
-
end
|
1550
|
-
|
1551
|
-
end
|
1552
|
-
|
1553
|
-
# a list of messages.
|
1554
|
-
class MessageList
|
1555
|
-
attr_reader :name, :total, :pos
|
1556
|
-
attr_accessor :box, :connection
|
1557
|
-
def initialize(name,total,pos)
|
1558
|
-
@name = name
|
1559
|
-
@total = total
|
1560
|
-
@pos = pos
|
1561
|
-
end
|
1562
|
-
|
1563
|
-
def each(&block)
|
1564
|
-
@box.each do |b|
|
1565
|
-
block.call(b)
|
1566
|
-
end
|
1567
|
-
end
|
1568
|
-
|
1569
|
-
def each_msg(&block)
|
1570
|
-
@box.each do |b|
|
1571
|
-
m = connection.fetch(:conversation=>b.id).message
|
1572
|
-
m.connection = @connection
|
1573
|
-
block.call(m)
|
1574
|
-
end
|
1575
|
-
end
|
1576
|
-
|
1577
|
-
end
|
1578
|
-
|
1579
|
-
# a Preference
|
1580
|
-
class Preference
|
1581
|
-
attr_accessor :max_page_size, :keyboard_shortcuts, :indicators, :display_language
|
1582
|
-
attr_accessor :signature, :reply_to, :snippets, :display_name
|
1583
|
-
def initialize
|
1584
|
-
@max_page_size = '10'
|
1585
|
-
@keyboard_shortcuts = false
|
1586
|
-
@indicators = false
|
1587
|
-
@display_language = 'en'
|
1588
|
-
@signature = ''
|
1589
|
-
@reply_to = ''
|
1590
|
-
@snippets = false
|
1591
|
-
@display_name = ''
|
1592
|
-
end
|
1593
|
-
end
|
1594
|
-
|
1595
|
-
# a Preference
|
1596
|
-
class Contact
|
1597
|
-
attr_accessor :name,:email,:notes
|
1598
|
-
def initialize
|
1599
|
-
@name = ''
|
1600
|
-
@email = ''
|
1601
|
-
@notes = ''
|
1602
|
-
end
|
1603
|
-
end
|
1604
|
-
|
1605
|
-
# a single attachment
|
1606
|
-
class Attachment
|
1607
|
-
attr_accessor :id, :filename, :type, :size
|
1608
|
-
end
|
1609
|
-
|
1610
|
-
# a single conversation
|
1611
|
-
class Conversation
|
1612
|
-
attr_accessor :id, :index, :body, :draft_parent, :is_draft, :attachment
|
1613
|
-
attr_accessor :snippet, :subject, :dt, :dt_easy, :bcc_email, :cc_email
|
1614
|
-
attr_accessor :reply_email, :recv_email, :recv, :sender_email, :sender, :is_star
|
1615
|
-
def read?
|
1616
|
-
is_read == 1
|
1617
|
-
end
|
1618
|
-
|
1619
|
-
def new?
|
1620
|
-
is_read != 1
|
1621
|
-
end
|
1622
|
-
|
1623
|
-
def star?
|
1624
|
-
is_starred == 1
|
1625
|
-
end
|
1626
|
-
|
1627
|
-
end
|
1628
|
-
|
1629
|
-
# a single message
|
1630
|
-
class Message
|
1631
|
-
attr_reader :title, :total, :id, :labels, :starred
|
1632
|
-
attr_accessor :conv, :connection
|
1633
|
-
def initialize(title,total,id,labels,starred)
|
1634
|
-
@title = title
|
1635
|
-
@total = total
|
1636
|
-
@id = id
|
1637
|
-
@labels = labels
|
1638
|
-
@starred = starred
|
1639
|
-
end
|
1640
|
-
|
1641
|
-
def method_missing(methId)
|
1642
|
-
str = methId.id2name
|
1643
|
-
@conv[0].method(str).call
|
1644
|
-
end
|
1645
|
-
|
1646
|
-
#
|
1647
|
-
# return boolean
|
1648
|
-
# param string label
|
1649
|
-
# desc apply label to message
|
1650
|
-
#
|
1651
|
-
def apply_label(label)
|
1652
|
-
@connection.perform_action(GM_ACT_APPLYLABEL, @id, label)
|
1653
|
-
end
|
1654
|
-
|
1655
|
-
#
|
1656
|
-
# return boolean
|
1657
|
-
# param string label
|
1658
|
-
# desc remove label from message
|
1659
|
-
#
|
1660
|
-
def remove_label(label)
|
1661
|
-
@connection.perform_action(GM_ACT_REMOVELABEL, @id, label)
|
1662
|
-
end
|
1663
|
-
|
1664
|
-
#
|
1665
|
-
# return boolean
|
1666
|
-
# desc apply star to a message
|
1667
|
-
#
|
1668
|
-
def apply_star()
|
1669
|
-
@connection.perform_action(GM_ACT_STAR,@id, '')
|
1670
|
-
end
|
1671
|
-
|
1672
|
-
#
|
1673
|
-
# return boolean
|
1674
|
-
# param string msgid
|
1675
|
-
# desc remove star from a message
|
1676
|
-
#
|
1677
|
-
def remove_star()
|
1678
|
-
@connection.perform_action(GM_ACT_UNSTAR,@id, '')
|
1679
|
-
end
|
1680
|
-
|
1681
|
-
#
|
1682
|
-
# return boolean
|
1683
|
-
# desc archive a message
|
1684
|
-
#
|
1685
|
-
def archive()
|
1686
|
-
@connection.perform_action(GM_ACT_ARCHIVE,@id, '')
|
1687
|
-
end
|
1688
|
-
|
1689
|
-
#
|
1690
|
-
# return boolean
|
1691
|
-
# param string msgid
|
1692
|
-
# desc archive a message
|
1693
|
-
#
|
1694
|
-
def unarchive()
|
1695
|
-
@connection.perform_action(GM_ACT_INBOX,@id, '')
|
1696
|
-
end
|
1697
|
-
|
1698
|
-
#
|
1699
|
-
# return boolean
|
1700
|
-
# param string msgid
|
1701
|
-
# desc mark a message as read
|
1702
|
-
#
|
1703
|
-
def mark_read()
|
1704
|
-
@connection.perform_action(GM_ACT_READ,@id, '')
|
1705
|
-
end
|
1706
|
-
|
1707
|
-
#
|
1708
|
-
# return boolean
|
1709
|
-
# param string msgid
|
1710
|
-
# desc mark a message as unread
|
1711
|
-
#
|
1712
|
-
def mark_unread()
|
1713
|
-
@connection.perform_action(GM_ACT_UNREAD,@id, '')
|
1714
|
-
end
|
1715
|
-
|
1716
|
-
def read?()
|
1717
|
-
@conv[0].read?
|
1718
|
-
end
|
1719
|
-
|
1720
|
-
def new?()
|
1721
|
-
@conv[0].new?
|
1722
|
-
end
|
1723
|
-
|
1724
|
-
#
|
1725
|
-
# return boolean
|
1726
|
-
# param string msgid
|
1727
|
-
# desc report a message as spam
|
1728
|
-
#
|
1729
|
-
def report_spam()
|
1730
|
-
@connection.perform_action(GM_ACT_SPAM,@id, '')
|
1731
|
-
end
|
1732
|
-
|
1733
|
-
#
|
1734
|
-
# return boolean
|
1735
|
-
# param string msgid
|
1736
|
-
# desc report a message as not spam
|
1737
|
-
#
|
1738
|
-
def report_not_spam()
|
1739
|
-
@connection.perform_action(GM_ACT_UNSPAM,@id, '')
|
1740
|
-
end
|
1741
|
-
|
1742
|
-
#
|
1743
|
-
# return boolean
|
1744
|
-
# desc move a message to trash
|
1745
|
-
#
|
1746
|
-
def trash()
|
1747
|
-
@connection.perform_action(GM_ACT_TRASH,@id, '')
|
1748
|
-
end
|
1749
|
-
|
1750
|
-
#
|
1751
|
-
# return boolean
|
1752
|
-
# desc move a message from trash to inbox
|
1753
|
-
#
|
1754
|
-
def untrash()
|
1755
|
-
@connection.perform_action(GM_ACT_UNTRASH,@id, '')
|
1756
|
-
end
|
1757
|
-
|
1758
|
-
#
|
1759
|
-
# return boolean
|
1760
|
-
# desc delete a message forever
|
1761
|
-
#
|
1762
|
-
def delete()
|
1763
|
-
if connected?
|
1764
|
-
@connection.perform_action(GM_ACT_DELFOREVER,@id, '')
|
1765
|
-
else
|
1766
|
-
false
|
1767
|
-
end
|
1768
|
-
end
|
1769
|
-
|
1770
|
-
def original()
|
1771
|
-
@connection.fetch(:show_original=>@id)
|
1772
|
-
end
|
1773
|
-
end
|
1774
|
-
|
1775
|
-
# Singleton method
|
1776
|
-
# return bool
|
1777
|
-
# desc Connect to GMail with default session management settings.
|
1778
|
-
#
|
1779
|
-
|
1780
|
-
def GMailer.connect(*param)
|
1781
|
-
g = Connection.new(*param)
|
1782
|
-
@connection = g
|
1783
|
-
if block_given?
|
1784
|
-
yield(g)
|
1785
|
-
g.disconnect()
|
1786
|
-
else
|
1787
|
-
g
|
72
|
+
# Reserved mailbox names
|
73
|
+
def gmail_reserved_names
|
74
|
+
["inbox", "star", "starred", "chat", "chats", "draft", "drafts",
|
75
|
+
"sent", "sentmail", "sent-mail", "sent mail", "all", "allmail", "all-mail", "all mail",
|
76
|
+
"anywhere", "archive", "spam", "trash", "read", "unread"]
|
1788
77
|
end
|
78
|
+
|
79
|
+
def encode(str)
|
80
|
+
return str if @charset.upcase == 'UTF-8'
|
81
|
+
begin
|
82
|
+
require 'Win32API'
|
83
|
+
str += "\0"
|
84
|
+
ostr = "\0" * str.length*2
|
85
|
+
multiByteToWideChar = Win32API.new('kernel32','MultiByteToWideChar',['L','L','P','L','P','L'],'L')
|
86
|
+
multiByteToWideChar.Call(0,0,str,-1,ostr,str.length*2)
|
87
|
+
(ostr.strip + "\0").unpack("S*").pack("U*")
|
88
|
+
rescue LoadError
|
89
|
+
require 'iconv'
|
90
|
+
Iconv::iconv('UTF-8',@charset,str)[0]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# return GMailer
|
96
|
+
# desc Constructor
|
97
|
+
#
|
98
|
+
def initialize(*param)
|
99
|
+
@login = ''
|
100
|
+
@pwd = ''
|
101
|
+
@raw = {}
|
102
|
+
@proxy_host = nil
|
103
|
+
@proxy_port = 0
|
104
|
+
@proxy_user = nil
|
105
|
+
@proxy_pass = nil
|
106
|
+
@proxy = false
|
107
|
+
@type = 0
|
108
|
+
if param.length==1 && param[0].is_a?(Hash)
|
109
|
+
param = param[0]
|
110
|
+
set_login_info(param[:username]||'',param[:password]||'')
|
111
|
+
@proxy_host = param[:proxy_host]
|
112
|
+
@proxy = !@proxy_host.nil?
|
113
|
+
@proxy_port = param[:proxy_port] || 80
|
114
|
+
@proxy_user = param[:proxy_user]
|
115
|
+
@proxy_pass = param[:proxy_pass]
|
116
|
+
@charset = param[:charset] || 'UTF-8'
|
117
|
+
elsif param.length==0
|
118
|
+
@charset = 'UTF-8'
|
119
|
+
elsif param.length==1
|
120
|
+
@charset = param[0]
|
121
|
+
elsif param.length==2
|
122
|
+
@charset = 'UTF-8'
|
123
|
+
set_login_info(param[0],param[1])
|
124
|
+
elsif param.length==3
|
125
|
+
@charset = param[2]
|
126
|
+
set_login_info(param[0],param[1])
|
127
|
+
else
|
128
|
+
raise ArgumentError, 'Invalid argument'
|
129
|
+
end
|
130
|
+
raise 'Not connected, verify the credentials.' unless connect_no_cookie
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# return void
|
135
|
+
# param string my_login
|
136
|
+
# param string my_pwd
|
137
|
+
# param int my_tz
|
138
|
+
# desc Set GMail login information.
|
139
|
+
#
|
140
|
+
def set_login_info(my_login, my_pwd, my_tz=0)
|
141
|
+
@login = my_login
|
142
|
+
@pwd = my_pwd
|
143
|
+
@timezone = (my_tz*-60).to_i.to_s
|
144
|
+
end
|
145
|
+
|
146
|
+
#
|
147
|
+
# return bool
|
148
|
+
# desc Connect to GMail without setting any session/cookie.
|
149
|
+
#
|
150
|
+
def connect_no_cookie()
|
151
|
+
|
152
|
+
postdata = "service=mail&Email=" + URI.escape(@login) + "&Passwd=" + URI.escape(@pwd) + "&null=Sign%20in&continue=" +
|
153
|
+
URI.escape('https://mail.google.com/mail/?ui=html&zy=l') + "&rm=false&PersistentCookie=yes"
|
154
|
+
|
155
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new("www.google.com", 443)
|
156
|
+
np.use_ssl = true
|
157
|
+
np.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
158
|
+
result = ''
|
159
|
+
response = nil
|
160
|
+
np.set_debug_output($stderr) if DEBUG
|
161
|
+
np.start { |http|
|
162
|
+
response = http.post(GM_LNK_LOGIN, postdata,{'Content-Type' => 'application/x-www-form-urlencoded','User-agent' => GM_USER_AGENT} )
|
163
|
+
result = response.body
|
164
|
+
}
|
165
|
+
|
166
|
+
if result.include?("errormsg")
|
167
|
+
@cookie_str = ''
|
168
|
+
return false
|
169
|
+
end
|
170
|
+
|
171
|
+
cookies = __cookies(response['set-cookie'])
|
172
|
+
arr = URI::split(response["Location"])
|
173
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 443)
|
174
|
+
np.use_ssl = true
|
175
|
+
np.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
176
|
+
result = ''
|
177
|
+
response = nil
|
178
|
+
np.set_debug_output($stderr) if DEBUG
|
179
|
+
np.start { |http|
|
180
|
+
response = http.get(arr[5]+'?'+arr[7], {'Cookie' => cookies,'User-agent' => GM_USER_AGENT} )
|
181
|
+
result = response.body
|
182
|
+
}
|
183
|
+
|
184
|
+
if result.include?("Redirecting") && result =~ /url='(.+?)'/
|
185
|
+
url = $1.gsub("&","&")
|
186
|
+
result = ''
|
187
|
+
cookies += ';'+ __cookies(response['set-cookie'])
|
188
|
+
response = nil
|
189
|
+
np.set_debug_output($stderr) if DEBUG
|
190
|
+
np.start { |http|
|
191
|
+
response = http.get(url, {'Cookie' => cookies,'User-agent'=> GM_USER_AGENT} )
|
192
|
+
result = response.body
|
193
|
+
}
|
194
|
+
end
|
195
|
+
|
196
|
+
if response["Location"]!=nil
|
197
|
+
arr = URI::split(response["Location"])
|
198
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 443)
|
199
|
+
np.use_ssl = true
|
200
|
+
np.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
201
|
+
result = ''
|
202
|
+
response = nil
|
203
|
+
np.set_debug_output($stderr) if DEBUG
|
204
|
+
np.start { |http|
|
205
|
+
response = http.get(arr[5]+'?'+arr[7], {'Cookie' => cookies,'User-agent' => GM_USER_AGENT} )
|
206
|
+
result = response.body
|
207
|
+
}
|
208
|
+
end
|
209
|
+
|
210
|
+
@loc = "http://mail.google.com/mail/"
|
211
|
+
cookies += ';' + __cookies(response['set-cookie'])
|
212
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 443)
|
213
|
+
np.use_ssl = true
|
214
|
+
np.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
215
|
+
np.set_debug_output($stderr) if DEBUG
|
216
|
+
np.start { |http|
|
217
|
+
response = http.get(@loc, {'Cookie' => cookies,'User-agent' => GM_USER_AGENT} )
|
218
|
+
result = response.body
|
219
|
+
}
|
220
|
+
cookies += ';' + __cookies(response['set-cookie'])
|
221
|
+
|
222
|
+
@cookie_str = cookies + ";TZ=" + @timezone
|
223
|
+
|
224
|
+
return true
|
225
|
+
end
|
226
|
+
|
227
|
+
#
|
228
|
+
# return bool
|
229
|
+
# desc Connect to GMail with default session management settings.
|
230
|
+
#
|
231
|
+
def connect()
|
232
|
+
raise 'Not connected, verify the credentials.' unless connect_no_cookie()
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
#
|
237
|
+
# return bool
|
238
|
+
# desc See if it is connected to GMail.
|
239
|
+
#
|
240
|
+
def connected?
|
241
|
+
!@cookie_str.empty?
|
242
|
+
end
|
243
|
+
|
244
|
+
#
|
245
|
+
# return bool
|
246
|
+
# param string query
|
247
|
+
# desc Fetch contents by URL query.
|
248
|
+
#
|
249
|
+
def __fetch(query)
|
250
|
+
if connected?
|
251
|
+
query += "&zv=" + (rand(2000)*2147483.648).to_i.to_s
|
252
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
253
|
+
np.set_debug_output($stderr) if DEBUG
|
254
|
+
inbox = ''
|
255
|
+
np.start { |http|
|
256
|
+
response = http.get(GM_LNK_GMAIL + "?" + query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
|
257
|
+
inbox = response.body
|
258
|
+
}
|
259
|
+
if @type == GM_SHOWORIGINAL
|
260
|
+
@raw = inbox
|
261
|
+
else
|
262
|
+
state = 0
|
263
|
+
tmp = ''
|
264
|
+
inbox.each do |l|
|
265
|
+
if /^D\(.*\);$/.match(l)
|
266
|
+
state = 0
|
267
|
+
tmp += l
|
268
|
+
elsif l[0,3]=='D(['
|
269
|
+
state = 1
|
270
|
+
tmp += l.chomp
|
271
|
+
elsif l[0,2]==');'
|
272
|
+
state = 2
|
273
|
+
tmp += ")\n"
|
274
|
+
elsif state == 1
|
275
|
+
tmp += l.chomp
|
276
|
+
end
|
277
|
+
end
|
278
|
+
inbox = tmp
|
279
|
+
matches = inbox.scan(/D\((.*)\)/).flatten
|
280
|
+
packets = {}
|
281
|
+
matches.each do |x|
|
282
|
+
tmp = eval(x.gsub(",,",",'',").gsub(",,",",'',").gsub(",]",",'']").gsub('#{','#\{'))
|
283
|
+
if (packets[tmp[0]] || (tmp[0]=="mi"||tmp[0]=="mb"||tmp[0]=="di"))
|
284
|
+
if (tmp[0]=="t"||tmp[0]=="ts"||tmp[0]=="a"||tmp[0]=="cl")
|
285
|
+
packets[tmp[0]] += tmp[1..-1]
|
286
|
+
end
|
287
|
+
if (tmp[0]=="mi"||tmp[0]=="mb"||tmp[0]=="di")
|
288
|
+
if packets["mg"]
|
289
|
+
packets["mg"].push(tmp)
|
290
|
+
else
|
291
|
+
packets["mg"] = [tmp]
|
292
|
+
end
|
293
|
+
end
|
294
|
+
else
|
295
|
+
packets[tmp[0]] = tmp
|
296
|
+
end
|
297
|
+
end
|
298
|
+
if packets["cl"] && packets["cl"].length > 1
|
299
|
+
packets["ce"] = []
|
300
|
+
for i in 1 .. packets["cl"].length-1
|
301
|
+
packets["ce"].push(packets["cl"][i])
|
302
|
+
end
|
303
|
+
end
|
304
|
+
@raw = packets
|
305
|
+
end
|
306
|
+
|
307
|
+
true
|
308
|
+
else # not logged in yet
|
309
|
+
false
|
310
|
+
end
|
311
|
+
end
|
312
|
+
private :__fetch
|
313
|
+
|
314
|
+
def parse_response(response)
|
315
|
+
inbox = response
|
316
|
+
state = 0
|
317
|
+
tmp = ''
|
318
|
+
inbox.each do |l|
|
319
|
+
if /^D\(.*\);$/.match(l)
|
320
|
+
state = 0
|
321
|
+
tmp += l
|
322
|
+
elsif l[0,3]=='D(['
|
323
|
+
state = 1
|
324
|
+
tmp += l.chomp
|
325
|
+
elsif l[0,2]==');'
|
326
|
+
state = 2
|
327
|
+
tmp += ")\n"
|
328
|
+
elsif state == 1
|
329
|
+
tmp += l.chomp
|
330
|
+
end
|
331
|
+
end
|
332
|
+
inbox = tmp
|
333
|
+
matches = inbox.scan(/D\((.*)\)/).flatten
|
334
|
+
packets = {}
|
335
|
+
matches.each do |x|
|
336
|
+
tmp = eval(x.gsub(",,",",'',").gsub(",,",",'',").gsub(",]",",'']").gsub('#{','#\{'))
|
337
|
+
if (packets[tmp[0]] || (tmp[0]=="mi"||tmp[0]=="mb"||tmp[0]=="di"))
|
338
|
+
if (tmp[0]=="t"||tmp[0]=="ts"||tmp[0]=="a"||tmp[0]=="cl")
|
339
|
+
packets[tmp[0]] += tmp[1..-1]
|
340
|
+
end
|
341
|
+
if (tmp[0]=="mi"||tmp[0]=="mb"||tmp[0]=="di")
|
342
|
+
if packets["mg"]
|
343
|
+
packets["mg"].push(tmp)
|
344
|
+
else
|
345
|
+
packets["mg"] = [tmp]
|
346
|
+
end
|
347
|
+
end
|
348
|
+
else
|
349
|
+
packets[tmp[0]] = tmp
|
350
|
+
end
|
351
|
+
end
|
352
|
+
if packets["cl"] && packets["cl"].length > 1
|
353
|
+
packets["ce"] = []
|
354
|
+
for i in 1 .. packets["cl"].length-1
|
355
|
+
packets["ce"].push(packets["cl"][i])
|
356
|
+
end
|
357
|
+
end
|
358
|
+
@raw = packets
|
359
|
+
end
|
360
|
+
|
361
|
+
#
|
362
|
+
# return bool
|
363
|
+
# param constant type
|
364
|
+
# param mixed box
|
365
|
+
# param int pos
|
366
|
+
# desc Fetch contents from GMail by type.
|
367
|
+
#
|
368
|
+
def fetch_box(type, box, pos)
|
369
|
+
@type = type
|
370
|
+
if connected?
|
371
|
+
case type
|
372
|
+
when GM_STANDARD
|
373
|
+
q = "search=" + box.downcase + "&view=tl&start=" + pos.to_s
|
374
|
+
|
375
|
+
when GM_LABEL
|
376
|
+
q = "search=cat&cat=" + box.to_s + "&view=tl&start=" + pos.to_s
|
377
|
+
|
378
|
+
when GM_CONVERSATION
|
379
|
+
pos = "inbox" if (pos.to_s=='' || pos.to_i == 0)
|
380
|
+
if gmail_reserved_names.include?(pos.downcase)
|
381
|
+
q = "search="+URI.escape(pos)+"&ser=1&view=cv"
|
382
|
+
else
|
383
|
+
q = "search=cat&cat="+URI.escape(pos)+"&ser=1&view=cv"
|
384
|
+
end
|
385
|
+
if (box.is_a?(Array))
|
386
|
+
q += "&th=" + box[0].to_s
|
387
|
+
for i in 1 .. box.length
|
388
|
+
q += "&msgs=" + box[i].to_s
|
389
|
+
end
|
390
|
+
else
|
391
|
+
q += "&th=" + box.to_s
|
392
|
+
end
|
393
|
+
|
394
|
+
when GM_CONV_SPAM
|
395
|
+
q = "search=spam&ser=1&view=cv"
|
396
|
+
if (box.is_a?(Array))
|
397
|
+
q += "&th=" + box[0].to_s
|
398
|
+
for i in 1 .. box.length
|
399
|
+
q += "&msgs=" + box[i].to_s
|
400
|
+
end
|
401
|
+
else
|
402
|
+
q += "&th=" + box.to_s
|
403
|
+
end
|
404
|
+
|
405
|
+
when GM_CONV_TRASH
|
406
|
+
q = "search=trash&ser=1&view=cv"
|
407
|
+
if (box.is_a?(Array))
|
408
|
+
q += "&th=" + box[0].to_s
|
409
|
+
for i in 1 .. box.length
|
410
|
+
q += "&msgs=" + box[i].to_s
|
411
|
+
end
|
412
|
+
else
|
413
|
+
q += "&th=" + box.to_s
|
414
|
+
end
|
415
|
+
|
416
|
+
when GM_SHOWORIGINAL
|
417
|
+
q = "view=om&th=" + box.to_s
|
418
|
+
|
419
|
+
when GM_QUERY
|
420
|
+
q = "search=query&q=" + URI.escape(box.to_s) + "&view=tl&start=" + pos.to_s
|
421
|
+
|
422
|
+
when GM_PREFERENCE
|
423
|
+
q = "view=pr&pnl=g"
|
424
|
+
|
425
|
+
when GM_CONTACT
|
426
|
+
if box.downcase == "all"
|
427
|
+
q = "view=cl&search=contacts&pnl=a"
|
428
|
+
elsif box.downcase == "search"
|
429
|
+
q = "view=cl&search=contacts&pnl=s&q=" + URI.escape(pos.to_s)
|
430
|
+
elsif box.downcase == "detail"
|
431
|
+
q = "search=contacts&ct_id=" + URI.escape(pos.to_s) + "&cvm=2&view=ct"
|
432
|
+
elsif box.downcase == "group_detail"
|
433
|
+
q = "search=contacts&ct_id=" + URI.escape(pos.to_s) + "&cvm=1&view=ctl"
|
434
|
+
elsif box.downcase == "group"
|
435
|
+
q = "view=cl&search=contacts&pnl=l"
|
436
|
+
else # frequently mailed
|
437
|
+
q = "view=cl&search=contacts&pnl=p"
|
438
|
+
end
|
439
|
+
|
440
|
+
else
|
441
|
+
q = "search=inbox&view=tl&start=0&init=1"
|
442
|
+
end
|
443
|
+
|
444
|
+
__fetch(q)
|
445
|
+
else
|
446
|
+
false
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
#
|
451
|
+
# return snapshot
|
452
|
+
# param constant type
|
453
|
+
# param mixed box
|
454
|
+
# param int pos
|
455
|
+
# desc Fetch contents from GMail by type.
|
456
|
+
#
|
457
|
+
def fetch(hash_param)
|
458
|
+
type = GM_STANDARD
|
459
|
+
box = "inbox"
|
460
|
+
pos = 0
|
461
|
+
@filter = {}
|
462
|
+
hash_param.keys.each do |k|
|
463
|
+
case k
|
464
|
+
when :label
|
465
|
+
type = GM_LABEL
|
466
|
+
box = hash_param[k]
|
467
|
+
when :standard
|
468
|
+
type = GM_STANDARD
|
469
|
+
box = hash_param[k]
|
470
|
+
when :conversation
|
471
|
+
type = GM_CONVERSATION
|
472
|
+
box = hash_param[k]
|
473
|
+
when :show_original
|
474
|
+
type = GM_SHOWORIGINAL
|
475
|
+
box = hash_param[k]
|
476
|
+
when :preference
|
477
|
+
type = GM_PREFERENCE
|
478
|
+
box = hash_param[k]
|
479
|
+
when :contact
|
480
|
+
type = GM_CONTACT
|
481
|
+
box = hash_param[k]
|
482
|
+
when :param
|
483
|
+
pos = hash_param[k]
|
484
|
+
when :query
|
485
|
+
type = GM_QUERY
|
486
|
+
box = hash_param[k]
|
487
|
+
when :pos
|
488
|
+
pos = hash_param[k].to_i
|
489
|
+
when :read
|
490
|
+
@filter[:read] = hash_param[k]
|
491
|
+
when :star
|
492
|
+
@filter[:star] = hash_param[k]
|
493
|
+
else
|
494
|
+
raise ArgumentError, 'Invalid hash argument'
|
495
|
+
end
|
496
|
+
end
|
497
|
+
box = "inbox" unless box
|
498
|
+
fetch_box(type,box,pos)
|
499
|
+
if type == GM_CONVERSATION
|
500
|
+
fetch_box(GM_CONV_SPAM,box,pos) if @raw['mg'].nil?
|
501
|
+
fetch_box(GM_CONV_TRASH,box,pos) if @raw['mg'].nil?
|
502
|
+
end
|
503
|
+
|
504
|
+
if type == GM_SHOWORIGINAL
|
505
|
+
ss = @raw
|
506
|
+
else
|
507
|
+
ss = snapshot(type)
|
508
|
+
end
|
509
|
+
if block_given?
|
510
|
+
yield(ss)
|
511
|
+
elsif type == GM_CONTACT
|
512
|
+
ss.contacts
|
513
|
+
else
|
514
|
+
ss
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
#
|
519
|
+
# return message
|
520
|
+
# param message id
|
521
|
+
# desc Fetch a message with message id
|
522
|
+
#
|
523
|
+
def msg(msgid)
|
524
|
+
m = fetch(:conversation=>msgid).message
|
525
|
+
if m.nil? then
|
526
|
+
raise ArgumentError, 'Message Not Exist'
|
527
|
+
end
|
528
|
+
m.connection = self
|
529
|
+
if block_given?
|
530
|
+
yield(m)
|
531
|
+
else
|
532
|
+
m
|
533
|
+
end
|
534
|
+
|
535
|
+
end
|
536
|
+
|
537
|
+
#
|
538
|
+
# return string[]
|
539
|
+
# param string[] convs
|
540
|
+
# param string path
|
541
|
+
# desc Save all attaching files of conversations to a path.
|
542
|
+
#
|
543
|
+
def attachments_of(convs, path)
|
544
|
+
|
545
|
+
if connected?
|
546
|
+
if (!convs.is_a?(Array))
|
547
|
+
convs = [convs] # array wrapper
|
548
|
+
end
|
549
|
+
final = []
|
550
|
+
convs.each do |v|
|
551
|
+
if v.attachment
|
552
|
+
v.attachment.each do |vv|
|
553
|
+
f = path+"/"+vv.filename
|
554
|
+
f = path+"/"+vv.filename+"."+rand(2000).to_s while (FileTest.exist?(f))
|
555
|
+
if attachment(vv.id,v.id,f,false)
|
556
|
+
final.push(f)
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end
|
560
|
+
end
|
561
|
+
final
|
562
|
+
else
|
563
|
+
nil
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
#
|
568
|
+
# return string[]
|
569
|
+
# param string[] convs
|
570
|
+
# param string path
|
571
|
+
# desc Save all attaching files of conversations to a path.
|
572
|
+
#
|
573
|
+
def zip_attachments_of(convs, path)
|
574
|
+
|
575
|
+
if connected?
|
576
|
+
if (!convs.is_a?(Array))
|
577
|
+
convs = [convs] # array wrapper
|
578
|
+
end
|
579
|
+
final = []
|
580
|
+
convs.each do |v|
|
581
|
+
if v.attachment
|
582
|
+
f = path+"/attachment.zip"
|
583
|
+
f = path+"/attachment."+rand(2000).to_s+".zip" while (FileTest.exist?(f))
|
584
|
+
if attachment(v["attachment"][0]["id"],v["id"],f,true)
|
585
|
+
final.push(f)
|
586
|
+
end
|
587
|
+
end
|
588
|
+
end
|
589
|
+
final
|
590
|
+
else
|
591
|
+
nil
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
#
|
596
|
+
# return bool
|
597
|
+
# param string attid
|
598
|
+
# param string msgid
|
599
|
+
# param string filename
|
600
|
+
# desc Save attachment with attachment ID attid and message ID msgid to file with name filename.
|
601
|
+
#
|
602
|
+
def attachment(attid, msgid, filename, zipped=false)
|
603
|
+
|
604
|
+
if connected?
|
605
|
+
|
606
|
+
if !zipped
|
607
|
+
query = GM_LNK_ATTACHMENT + "&attid=" + URI.escape(attid) + "&th=" + URI.escape(msgid)
|
608
|
+
else
|
609
|
+
query = GM_LNK_ATTACHMENT_ZIPPED + "&th=" + URI.escape(msgid)
|
610
|
+
end
|
611
|
+
|
612
|
+
File.open(filename,"wb") do |f|
|
613
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
614
|
+
np.start { |http|
|
615
|
+
response = http.get(query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
|
616
|
+
f.write(response.body)
|
617
|
+
}
|
618
|
+
end
|
619
|
+
true
|
620
|
+
else
|
621
|
+
false
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
#
|
626
|
+
# return array of labels
|
627
|
+
# desc get label lists
|
628
|
+
#
|
629
|
+
def labels()
|
630
|
+
if connected?
|
631
|
+
fetch(:standard=>"inbox") {|s| s.label_list }
|
632
|
+
else
|
633
|
+
nil
|
634
|
+
end
|
635
|
+
end
|
636
|
+
|
637
|
+
#
|
638
|
+
# return string
|
639
|
+
# param string label
|
640
|
+
# desc validate label
|
641
|
+
#
|
642
|
+
def validate_label(label)
|
643
|
+
label.strip!
|
644
|
+
if label==''
|
645
|
+
raise ArgumentError, 'Error: Labels cannot empty string'
|
646
|
+
end
|
647
|
+
if label.length > 40
|
648
|
+
raise ArgumentError, 'Error: Labels cannot contain more than 40 characters'
|
649
|
+
end
|
650
|
+
if label.include?('^')
|
651
|
+
raise ArgumentError, "Error: Labels cannot contain the character '^'"
|
652
|
+
end
|
653
|
+
label
|
654
|
+
end
|
655
|
+
|
656
|
+
#
|
657
|
+
# return boolean
|
658
|
+
# param string label
|
659
|
+
# desc create label
|
660
|
+
#
|
661
|
+
def create_label(label)
|
662
|
+
if connected?
|
663
|
+
perform_action(GM_ACT_CREATELABEL, '', validate_label(label))
|
664
|
+
else
|
665
|
+
false
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
#
|
670
|
+
# return boolean
|
671
|
+
# param string label
|
672
|
+
# desc create label
|
673
|
+
#
|
674
|
+
def delete_label(label)
|
675
|
+
if connected?
|
676
|
+
perform_action(GM_ACT_DELETELABEL, '', validate_label(label))
|
677
|
+
else
|
678
|
+
false
|
679
|
+
end
|
680
|
+
end
|
681
|
+
|
682
|
+
#
|
683
|
+
# return boolean
|
684
|
+
# param string old_label
|
685
|
+
# param string new_label
|
686
|
+
# desc create label
|
687
|
+
#
|
688
|
+
def rename_label(old_label,new_label)
|
689
|
+
if connected?
|
690
|
+
perform_action(GM_ACT_RENAMELABEL, '',
|
691
|
+
validate_label(old_label) +'^' + validate_label(new_label))
|
692
|
+
else
|
693
|
+
false
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
697
|
+
#
|
698
|
+
# return boolean
|
699
|
+
# param string msgid
|
700
|
+
# param string label
|
701
|
+
# desc apply label to message
|
702
|
+
#
|
703
|
+
def apply_label(id,label)
|
704
|
+
if connected?
|
705
|
+
perform_action(GM_ACT_APPLYLABEL, id, validate_label(label))
|
706
|
+
else
|
707
|
+
false
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
#
|
712
|
+
# return boolean
|
713
|
+
# param string msgid
|
714
|
+
# param string label
|
715
|
+
# desc remove label from message
|
716
|
+
#
|
717
|
+
def remove_label(id,label)
|
718
|
+
if connected?
|
719
|
+
perform_action(GM_ACT_REMOVELABEL, id, validate_label(label))
|
720
|
+
else
|
721
|
+
false
|
722
|
+
end
|
723
|
+
end
|
724
|
+
|
725
|
+
#
|
726
|
+
# return boolean
|
727
|
+
# param string hash_param
|
728
|
+
# desc remove label from message
|
729
|
+
#
|
730
|
+
def update_preference(hash_param)
|
731
|
+
if connected?
|
732
|
+
args = {}
|
733
|
+
hash_param.keys.each do |k|
|
734
|
+
case k
|
735
|
+
when :max_page_size
|
736
|
+
args['p_ix_nt'] = hash_param[k]
|
737
|
+
when :keyboard_shortcuts
|
738
|
+
args['p_bx_hs'] = hash_param[k] ? '1' : '0'
|
739
|
+
when :indicators
|
740
|
+
args['p_bx_sc'] = hash_param[k] ? '1' : '0'
|
741
|
+
when :display_language
|
742
|
+
args['p_sx_dl'] = hash_param[k]
|
743
|
+
when :signature
|
744
|
+
args['p_sx_sg'] = hash_param[k]
|
745
|
+
when :reply_to
|
746
|
+
args['p_sx_rt'] = hash_param[k]
|
747
|
+
when :snippets
|
748
|
+
args['p_bx_ns'] = hash_param[k] ? '0' : '1'
|
749
|
+
when :display_name
|
750
|
+
args['p_sx_dn'] = hash_param[k]
|
751
|
+
end
|
752
|
+
end
|
753
|
+
param = '&' + args.to_a.map {|x| x.join('=')}.join('&')
|
754
|
+
perform_action(GM_ACT_PREFERENCE,'', param)
|
755
|
+
else
|
756
|
+
false
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
760
|
+
#
|
761
|
+
# return boolean
|
762
|
+
# param string msgid
|
763
|
+
# desc apply star to a message
|
764
|
+
#
|
765
|
+
def apply_star(msgid)
|
766
|
+
if connected?
|
767
|
+
perform_action(GM_ACT_STAR,msgid, '')
|
768
|
+
else
|
769
|
+
false
|
770
|
+
end
|
771
|
+
end
|
772
|
+
|
773
|
+
#
|
774
|
+
# return boolean
|
775
|
+
# param string msgid
|
776
|
+
# desc remove star from a message
|
777
|
+
#
|
778
|
+
def remove_star(msgid)
|
779
|
+
if connected?
|
780
|
+
perform_action(GM_ACT_UNSTAR,msgid, '')
|
781
|
+
else
|
782
|
+
false
|
783
|
+
end
|
784
|
+
end
|
785
|
+
|
786
|
+
#
|
787
|
+
# return boolean
|
788
|
+
# param string msgid
|
789
|
+
# desc report a message as spam
|
790
|
+
#
|
791
|
+
def report_spam(msgid)
|
792
|
+
if connected?
|
793
|
+
perform_action(GM_ACT_SPAM,msgid, '')
|
794
|
+
else
|
795
|
+
false
|
796
|
+
end
|
797
|
+
end
|
798
|
+
|
799
|
+
#
|
800
|
+
# return boolean
|
801
|
+
# param string msgid
|
802
|
+
# desc report a message as not spam
|
803
|
+
#
|
804
|
+
def report_not_spam(msgid)
|
805
|
+
if connected?
|
806
|
+
perform_action(GM_ACT_UNSPAM,msgid, '')
|
807
|
+
else
|
808
|
+
false
|
809
|
+
end
|
810
|
+
end
|
811
|
+
|
812
|
+
#
|
813
|
+
# return boolean
|
814
|
+
# param string msgid
|
815
|
+
# desc delete a spam message forever
|
816
|
+
#
|
817
|
+
def delete_spam(msgid)
|
818
|
+
if connected?
|
819
|
+
perform_action(GM_ACT_DELSPAM,msgid, '')
|
820
|
+
else
|
821
|
+
false
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
825
|
+
#
|
826
|
+
# return boolean
|
827
|
+
# param string msgid
|
828
|
+
# desc mark a message as read
|
829
|
+
#
|
830
|
+
def mark_read(msgid)
|
831
|
+
if connected?
|
832
|
+
perform_action(GM_ACT_READ,msgid, '')
|
833
|
+
else
|
834
|
+
false
|
835
|
+
end
|
836
|
+
end
|
837
|
+
|
838
|
+
#
|
839
|
+
# return boolean
|
840
|
+
# param string msgid
|
841
|
+
# desc mark a message as unread
|
842
|
+
#
|
843
|
+
def mark_unread(msgid)
|
844
|
+
if connected?
|
845
|
+
perform_action(GM_ACT_UNREAD,msgid, '')
|
846
|
+
else
|
847
|
+
false
|
848
|
+
end
|
849
|
+
end
|
850
|
+
|
851
|
+
#
|
852
|
+
# return original message string
|
853
|
+
# param string msgid
|
854
|
+
# desc show original message format
|
855
|
+
#
|
856
|
+
def show_original(msgid)
|
857
|
+
if connected?
|
858
|
+
fetch(:show_original=>msgid)
|
859
|
+
else
|
860
|
+
false
|
861
|
+
end
|
862
|
+
end
|
863
|
+
|
864
|
+
#
|
865
|
+
# return boolean
|
866
|
+
# param string msgid
|
867
|
+
# desc move a message to trash
|
868
|
+
#
|
869
|
+
def trash(msgid)
|
870
|
+
if connected?
|
871
|
+
perform_action(GM_ACT_TRASH,msgid, '')
|
872
|
+
else
|
873
|
+
false
|
874
|
+
end
|
875
|
+
end
|
876
|
+
|
877
|
+
#
|
878
|
+
# return boolean
|
879
|
+
# param string msgid
|
880
|
+
# desc move a message from trash to inbox
|
881
|
+
#
|
882
|
+
def untrash(msgid)
|
883
|
+
if connected?
|
884
|
+
perform_action(GM_ACT_UNTRASH,msgid, '')
|
885
|
+
else
|
886
|
+
false
|
887
|
+
end
|
888
|
+
end
|
889
|
+
|
890
|
+
#
|
891
|
+
# return boolean
|
892
|
+
# param string msgid
|
893
|
+
# desc delete a trash message forever
|
894
|
+
#
|
895
|
+
def delete_trash(msgid)
|
896
|
+
if connected?
|
897
|
+
perform_action(GM_ACT_DELTRASH,msgid, '')
|
898
|
+
else
|
899
|
+
false
|
900
|
+
end
|
901
|
+
end
|
902
|
+
|
903
|
+
#
|
904
|
+
# return boolean
|
905
|
+
# param string msgid
|
906
|
+
# desc delete a message forever
|
907
|
+
#
|
908
|
+
def delete_message(msgid)
|
909
|
+
if connected?
|
910
|
+
perform_action(GM_ACT_DELFOREVER,msgid, '')
|
911
|
+
else
|
912
|
+
false
|
913
|
+
end
|
914
|
+
end
|
915
|
+
|
916
|
+
#
|
917
|
+
# return boolean
|
918
|
+
# param string msgid
|
919
|
+
# desc archive a message
|
920
|
+
#
|
921
|
+
def archive(msgid)
|
922
|
+
if connected?
|
923
|
+
perform_action(GM_ACT_ARCHIVE,msgid, '')
|
924
|
+
else
|
925
|
+
false
|
926
|
+
end
|
927
|
+
end
|
928
|
+
|
929
|
+
#
|
930
|
+
# return boolean
|
931
|
+
# param string msgid
|
932
|
+
# desc archive a message
|
933
|
+
#
|
934
|
+
def unarchive(msgid)
|
935
|
+
if connected?
|
936
|
+
perform_action(GM_ACT_INBOX,msgid, '')
|
937
|
+
else
|
938
|
+
false
|
939
|
+
end
|
940
|
+
end
|
941
|
+
|
942
|
+
|
943
|
+
#
|
944
|
+
# return hash of preference
|
945
|
+
# desc get preferences
|
946
|
+
#
|
947
|
+
def preference()
|
948
|
+
if connected?
|
949
|
+
fetch(:preference=>"all").preference
|
950
|
+
else
|
951
|
+
nil
|
952
|
+
end
|
953
|
+
end
|
954
|
+
|
955
|
+
#
|
956
|
+
# return array of messages
|
957
|
+
# desc get message lists
|
958
|
+
#
|
959
|
+
def messages(hash_param)
|
960
|
+
if connected?
|
961
|
+
ml = fetch(hash_param).message_list
|
962
|
+
@filter.keys.each do |k|
|
963
|
+
case k
|
964
|
+
when :read
|
965
|
+
ml.box = ml.box.find_all { |x| x.read? == @filter[k] }
|
966
|
+
when :star
|
967
|
+
ml.box = ml.box.find_all { |x| x.star? == @filter[k] }
|
968
|
+
end
|
969
|
+
end
|
970
|
+
ml.connection = self
|
971
|
+
if block_given?
|
972
|
+
yield(ml)
|
973
|
+
else
|
974
|
+
ml
|
975
|
+
end
|
976
|
+
else
|
977
|
+
nil
|
978
|
+
end
|
979
|
+
end
|
980
|
+
|
981
|
+
#
|
982
|
+
# return string
|
983
|
+
# param string query
|
984
|
+
# desc Dump everything to output.
|
985
|
+
#
|
986
|
+
def dump(query)
|
987
|
+
page = ''
|
988
|
+
if connected?
|
989
|
+
query += "&zv=" + (rand(2000)*2147483.648).to_i.to_s
|
990
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
991
|
+
np.start { |http|
|
992
|
+
response = http.get(GM_LNK_GMAIL + "?"+query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
|
993
|
+
page = response.body
|
994
|
+
}
|
995
|
+
else # not logged in yet
|
996
|
+
|
997
|
+
end
|
998
|
+
page
|
999
|
+
end
|
1000
|
+
|
1001
|
+
def stripslashes(string)
|
1002
|
+
encode(string.gsub("\\\"", "\"").gsub("\\'", "'").gsub("\\\\", "\\"))
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
|
1006
|
+
#
|
1007
|
+
# return bool
|
1008
|
+
# param string to
|
1009
|
+
# param string subject
|
1010
|
+
# param string body
|
1011
|
+
# param string cc
|
1012
|
+
# param string bcc
|
1013
|
+
# param string msg_id
|
1014
|
+
# param string thread_id
|
1015
|
+
# param string[] files
|
1016
|
+
# desc Send GMail.
|
1017
|
+
#
|
1018
|
+
def send(*param)
|
1019
|
+
if param.length==1 && param[0].is_a?(Hash)
|
1020
|
+
param = param[0]
|
1021
|
+
from = param[:from] || ''
|
1022
|
+
to = param[:to] || ''
|
1023
|
+
subject = param[:subject] || ''
|
1024
|
+
body = param[:body] || ''
|
1025
|
+
cc = param[:cc] || ''
|
1026
|
+
bcc = param[:bcc] || ''
|
1027
|
+
msg_id = param[:msg_id] || ''
|
1028
|
+
thread_id = param[:msg_id] || ''
|
1029
|
+
files = param[:files] || []
|
1030
|
+
draft = param[:draft] || false
|
1031
|
+
draft_id = param[:draft_id] || ''
|
1032
|
+
elsif param.length==10
|
1033
|
+
to, subject, body, cc, bcc, msg_id, thread_id, files, draft, draft_id = param
|
1034
|
+
elsif param.length==11
|
1035
|
+
from, to, subject, body, cc, bcc, msg_id, thread_id, files, draft, draft_id = param
|
1036
|
+
else
|
1037
|
+
raise ArgumentError, 'Invalid argument'
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
if connected?
|
1041
|
+
other_emails = fetch(:preference=>"all").other_emails
|
1042
|
+
if other_emails.length>0
|
1043
|
+
other_emails.each {|v|
|
1044
|
+
from = v['email'] if from=='' && v['default']
|
1045
|
+
}
|
1046
|
+
from = @login + '@gmail.com' if from==''
|
1047
|
+
else
|
1048
|
+
from = nil
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
postdata = {}
|
1052
|
+
if draft
|
1053
|
+
postdata["view"] = "sd"
|
1054
|
+
postdata["draft"] = draft_id
|
1055
|
+
postdata["rm"] = msg_id
|
1056
|
+
postdata["th"] = thread_id
|
1057
|
+
else
|
1058
|
+
postdata["view"] = "sm"
|
1059
|
+
postdata["draft"] = draft_id
|
1060
|
+
postdata["rm"] = msg_id
|
1061
|
+
postdata["th"] = thread_id
|
1062
|
+
end
|
1063
|
+
postdata["msgbody"] = stripslashes(body)
|
1064
|
+
postdata["from"] = stripslashes(from) if from
|
1065
|
+
postdata["to"] = stripslashes(to)
|
1066
|
+
postdata["subject"] = stripslashes(subject)
|
1067
|
+
postdata["cc"] = stripslashes(cc)
|
1068
|
+
postdata["bcc"] = stripslashes(bcc)
|
1069
|
+
|
1070
|
+
postdata["cmid"] = 1
|
1071
|
+
postdata["ishtml"] = param[:ishtml] || 0
|
1072
|
+
|
1073
|
+
postdata["at"] = at_value
|
1074
|
+
|
1075
|
+
boundary = "----#{Time.now.to_i}#{(rand(2000)*2147483.648).to_i}"
|
1076
|
+
postdata2 = []
|
1077
|
+
postdata.each {|k,v|
|
1078
|
+
postdata2.push("Content-Disposition: form-data; name=\"#{k}\"\r\n\r\n#{v}\r\n")
|
1079
|
+
}
|
1080
|
+
|
1081
|
+
files.each_with_index do |f,i|
|
1082
|
+
content = File.open(f,'rb') { |c| c.read }
|
1083
|
+
postdata2.push("Content-Disposition: form-data; name=\"file#{i}\"; filename=\"#{File.basename(f)}\"\r\n" +
|
1084
|
+
"Content-Transfer-Encoding: binary\r\n" +
|
1085
|
+
"Content-Type: application/octet-stream\r\n\r\n" + content + "\r\n")
|
1086
|
+
end
|
1087
|
+
|
1088
|
+
postdata = postdata2.collect { |p|
|
1089
|
+
"--" + boundary + "\r\n" + p
|
1090
|
+
}.join('') + "--" + boundary + "--\r\n"
|
1091
|
+
|
1092
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
1093
|
+
response = nil
|
1094
|
+
np.set_debug_output($stderr) if DEBUG
|
1095
|
+
np.start { |http|
|
1096
|
+
response = http.post(GM_LNK_GMAIL, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT,'Content-type' => 'multipart/form-data; boundary=' + boundary } )
|
1097
|
+
}
|
1098
|
+
true
|
1099
|
+
else
|
1100
|
+
false
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
end
|
1104
|
+
|
1105
|
+
#
|
1106
|
+
# return bool
|
1107
|
+
# param constant act
|
1108
|
+
# param string[] id
|
1109
|
+
# param string para
|
1110
|
+
# desc Perform action on messages.
|
1111
|
+
#
|
1112
|
+
def perform_action(act, id, para)
|
1113
|
+
|
1114
|
+
if connected?
|
1115
|
+
|
1116
|
+
if (act == GM_ACT_DELFOREVER)
|
1117
|
+
perform_action(GM_ACT_TRASH, id, 0) # trash it before
|
1118
|
+
end
|
1119
|
+
postdata = "act="
|
1120
|
+
|
1121
|
+
action_codes = ["ib", "cc_", "dc_", "nc_", "ac_", "rc_", "prefs", "st", "xst",
|
1122
|
+
"sp", "us", "rd", "ur", "tr", "dl", "rc_^i", "ib", "ib", "dd", "dm", "dl", "dl"]
|
1123
|
+
postdata += action_codes[act] ? action_codes[act] : action_codes[GM_ACT_INBOX]
|
1124
|
+
if act == GM_ACT_RENAMELABEL then
|
1125
|
+
paras = para.split('^')
|
1126
|
+
para = validate_label(paras[0])+'^'+validate_label(paras[1])
|
1127
|
+
elsif ([GM_ACT_APPLYLABEL,GM_ACT_REMOVELABEL,GM_ACT_CREATELABEL,
|
1128
|
+
GM_ACT_DELETELABEL,].include?(act))
|
1129
|
+
para = validate_label(para)
|
1130
|
+
end
|
1131
|
+
if ([GM_ACT_APPLYLABEL,GM_ACT_REMOVELABEL,GM_ACT_CREATELABEL,
|
1132
|
+
GM_ACT_DELETELABEL,GM_ACT_RENAMELABEL,GM_ACT_PREFERENCE].include?(act))
|
1133
|
+
postdata += para.to_s
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
postdata += "&at=" + at_value
|
1137
|
+
|
1138
|
+
if (act == GM_ACT_TRASHMSG)
|
1139
|
+
postdata += "&m=" + id.to_s
|
1140
|
+
else
|
1141
|
+
if id.is_a?(Array)
|
1142
|
+
id.each {|t| postdata += "&t="+t.to_s }
|
1143
|
+
else
|
1144
|
+
postdata += "&t="+id.to_s
|
1145
|
+
end
|
1146
|
+
end
|
1147
|
+
postdata += "&vp="
|
1148
|
+
|
1149
|
+
if [GM_ACT_UNTRASH,GM_ACT_DELFOREVER,GM_ACT_DELTRASH].include?(act)
|
1150
|
+
link = GM_LNK_GMAIL+"?search=trash&view=tl&start=0"
|
1151
|
+
elsif (act == GM_ACT_DELSPAM)
|
1152
|
+
link = GM_LNK_GMAIL+"?search=spam&view=tl&start=0"
|
1153
|
+
else
|
1154
|
+
link = GM_LNK_GMAIL+"?search=query&q=&view=tl&start=0"
|
1155
|
+
end
|
1156
|
+
|
1157
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
1158
|
+
np.set_debug_output($stderr) if DEBUG
|
1159
|
+
np.start { |http|
|
1160
|
+
response = http.post(link, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
|
1161
|
+
result = response.body
|
1162
|
+
}
|
1163
|
+
|
1164
|
+
true
|
1165
|
+
else
|
1166
|
+
false
|
1167
|
+
end
|
1168
|
+
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
#
|
1172
|
+
# return void
|
1173
|
+
# desc Disconnect from GMail.
|
1174
|
+
#
|
1175
|
+
def disconnect()
|
1176
|
+
|
1177
|
+
response = nil
|
1178
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
1179
|
+
np.set_debug_output($stderr) if DEBUG
|
1180
|
+
np.start { |http|
|
1181
|
+
response = http.get(GM_LNK_LOGOUT,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
|
1182
|
+
}
|
1183
|
+
arr = URI::split(response["Location"])
|
1184
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 80)
|
1185
|
+
np.set_debug_output($stderr) if DEBUG
|
1186
|
+
np.start { |http|
|
1187
|
+
response = http.get(arr[5]+'?'+arr[7], {'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
|
1188
|
+
}
|
1189
|
+
|
1190
|
+
@cookie_str = ''
|
1191
|
+
end
|
1192
|
+
|
1193
|
+
#
|
1194
|
+
# return GMailSnapshot
|
1195
|
+
# param constant type
|
1196
|
+
# desc Get GMSnapshot by type.
|
1197
|
+
#
|
1198
|
+
def snapshot(type)
|
1199
|
+
if [GM_STANDARD,GM_LABEL,GM_CONVERSATION,GM_QUERY,GM_PREFERENCE,GM_CONTACT].include?(type)
|
1200
|
+
return GMailSnapshot.new(type, @raw, @charset)
|
1201
|
+
else
|
1202
|
+
return GMailSnapshot.new(GM_STANDARD, @raw, @charset) # assuming normal by default
|
1203
|
+
end
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
def snap(type)
|
1207
|
+
action = GM_STANDARD
|
1208
|
+
case type
|
1209
|
+
when :standard
|
1210
|
+
action = GM_STANDARD
|
1211
|
+
when :label
|
1212
|
+
action = GM_LABEL
|
1213
|
+
when :conversation
|
1214
|
+
action = GM_CONVERSATION
|
1215
|
+
when :query
|
1216
|
+
action = GM_QUERY
|
1217
|
+
when :preference
|
1218
|
+
action = GM_PREFERENCE
|
1219
|
+
when :contact
|
1220
|
+
action = GM_CONTACT
|
1221
|
+
else
|
1222
|
+
raise ArgumentError, 'Invalid type'
|
1223
|
+
end
|
1224
|
+
snapshot(action)
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
#
|
1228
|
+
# return bool
|
1229
|
+
# param string email
|
1230
|
+
# desc Send Gmail invite to email
|
1231
|
+
#
|
1232
|
+
def invite(email)
|
1233
|
+
|
1234
|
+
if connected?
|
1235
|
+
|
1236
|
+
postdata = "act=ii&em=" + URI.escape(email)
|
1237
|
+
|
1238
|
+
postdata += "&at=" + at_value
|
1239
|
+
|
1240
|
+
link = GM_LNK_GMAIL + "?view=ii"
|
1241
|
+
|
1242
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 443)
|
1243
|
+
np.use_ssl = true
|
1244
|
+
np.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
1245
|
+
np.set_debug_output($stderr) if DEBUG
|
1246
|
+
np.start { |http|
|
1247
|
+
response = http.post(link, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
|
1248
|
+
}
|
1249
|
+
|
1250
|
+
true
|
1251
|
+
else
|
1252
|
+
false
|
1253
|
+
end
|
1254
|
+
|
1255
|
+
end
|
1256
|
+
|
1257
|
+
|
1258
|
+
def at_value
|
1259
|
+
val = ''
|
1260
|
+
cc = @cookie_str.split(';')
|
1261
|
+
cc.each do |cc_part|
|
1262
|
+
cc_parts = cc_part.split('=')
|
1263
|
+
if(cc_parts[0]=='GMAIL_AT')
|
1264
|
+
val = cc_parts[1]
|
1265
|
+
break
|
1266
|
+
end
|
1267
|
+
end
|
1268
|
+
val
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
#
|
1272
|
+
# return string[]
|
1273
|
+
# desc (Static) Get names of standard boxes.
|
1274
|
+
#
|
1275
|
+
def standard_box
|
1276
|
+
["Inbox","Starred","Sent","Drafts","All","Spam","Trash"]
|
1277
|
+
end
|
1278
|
+
|
1279
|
+
#
|
1280
|
+
# return string
|
1281
|
+
# param string header
|
1282
|
+
# desc (Static Private) Extract cookies from header.
|
1283
|
+
#
|
1284
|
+
def __cookies(header)
|
1285
|
+
return '' unless header
|
1286
|
+
arr = []
|
1287
|
+
header.split(', ').each { |x|
|
1288
|
+
if x.include?('GMT')
|
1289
|
+
arr[-1] += ", " + x
|
1290
|
+
else
|
1291
|
+
arr.push x
|
1292
|
+
end
|
1293
|
+
}
|
1294
|
+
arr.delete_if {|x| x.include?('LSID=EXPIRED') }
|
1295
|
+
arr.map! {|x| x.split(';')[0]}
|
1296
|
+
arr.join(';')
|
1297
|
+
end
|
1298
|
+
|
1299
|
+
def edit_contact(contact_id, name, email, notes, details=[])
|
1300
|
+
if connected?
|
1301
|
+
postdata = {}
|
1302
|
+
postdata["act"] = "ec"
|
1303
|
+
postdata["ct_id"] = contact_id.to_s
|
1304
|
+
postdata["ct_nm"] = name
|
1305
|
+
postdata["ct_em"] = email
|
1306
|
+
postdata["ctf_n"] = notes
|
1307
|
+
|
1308
|
+
if (details.length > 0)
|
1309
|
+
i = 0 # the detail number
|
1310
|
+
det_num = '00' # detail number padded to 2 numbers for gmail
|
1311
|
+
details.each do |detail1|
|
1312
|
+
postdata["ctsn_#{det_num}"] = "Unnamed" # default name if none defined later
|
1313
|
+
address = '' # default address if none defined later
|
1314
|
+
k = 0 # the field number supplied to Gmail
|
1315
|
+
field_num = '00' # must be padded to 2 numbers for gmail
|
1316
|
+
detail1.each do |key,value|
|
1317
|
+
field_type = ''
|
1318
|
+
case key
|
1319
|
+
when :phone
|
1320
|
+
field_type = "p"
|
1321
|
+
when :email
|
1322
|
+
field_type = "e"
|
1323
|
+
when :mobile
|
1324
|
+
field_type = "m"
|
1325
|
+
when :fax
|
1326
|
+
field_type = "f"
|
1327
|
+
when :pager
|
1328
|
+
field_type = "b"
|
1329
|
+
when :im
|
1330
|
+
field_type = "i"
|
1331
|
+
when :company
|
1332
|
+
field_type = "d"
|
1333
|
+
when :position
|
1334
|
+
field_type = "t" # t = title
|
1335
|
+
when :other
|
1336
|
+
field_type = "o"
|
1337
|
+
when :address
|
1338
|
+
field_type = "a"
|
1339
|
+
when :detail_name
|
1340
|
+
field_type = "xyz"
|
1341
|
+
else
|
1342
|
+
field_type = "o"
|
1343
|
+
end
|
1344
|
+
if (field_type == "xyz")
|
1345
|
+
postdata["ctsn_#{det_num}"] = value
|
1346
|
+
elsif (field_type == "a")
|
1347
|
+
address = value
|
1348
|
+
else
|
1349
|
+
# e.g. ctsf_00_00_p for phone
|
1350
|
+
postdata["ctsf_#{det_num}_#{field_num}_#{field_type}"] = value
|
1351
|
+
# increments the field number and pads it
|
1352
|
+
k = k + 1
|
1353
|
+
field_num = "%02d" % k
|
1354
|
+
end
|
1355
|
+
end
|
1356
|
+
# Address field needs to be last
|
1357
|
+
# if more than one address was given, the last one found will be used
|
1358
|
+
if (address != '')
|
1359
|
+
postdata["ctsf_#{det_num}_#{field_num}_a"] = address
|
1360
|
+
end
|
1361
|
+
|
1362
|
+
# increment detail number
|
1363
|
+
i = i + 1
|
1364
|
+
det_num = "%02d" % i
|
1365
|
+
end
|
1366
|
+
end
|
1367
|
+
|
1368
|
+
postdata["at"] = at_value
|
1369
|
+
|
1370
|
+
postdata2 = []
|
1371
|
+
postdata.each {|k,v|
|
1372
|
+
postdata2.push("#{k}=#{v}")
|
1373
|
+
}
|
1374
|
+
postdata = postdata2.join('&')
|
1375
|
+
|
1376
|
+
link = GM_LNK_GMAIL + "?view=up"
|
1377
|
+
|
1378
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
1379
|
+
np.set_debug_output($stderr) if DEBUG
|
1380
|
+
np.start { |http|
|
1381
|
+
response = http.post(link, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
|
1382
|
+
parse_response(response.body)
|
1383
|
+
}
|
1384
|
+
|
1385
|
+
orig_contact_id = contact_id.to_i
|
1386
|
+
if (orig_contact_id == "-1" && @raw["ar"][1])
|
1387
|
+
if (@raw["cov"][1][1])
|
1388
|
+
contact_id = @raw["cov"][1][1]
|
1389
|
+
elsif (@raw["a"][1][1])
|
1390
|
+
contact_id = @raw["a"][1][1]
|
1391
|
+
elsif (@raw["cl"][1][1])
|
1392
|
+
contact_id = @raw["cl"][1][1]
|
1393
|
+
end
|
1394
|
+
end
|
1395
|
+
|
1396
|
+
status = @raw["ar"][1]==1
|
1397
|
+
message = @raw["ar"][2]
|
1398
|
+
raise message unless status
|
1399
|
+
|
1400
|
+
return status
|
1401
|
+
else
|
1402
|
+
raise "Not connected"
|
1403
|
+
return false
|
1404
|
+
end
|
1405
|
+
end
|
1406
|
+
|
1407
|
+
def add_contact(name, email, notes, details=[])
|
1408
|
+
edit_contact(-1,name, email, notes, details)
|
1409
|
+
end
|
1410
|
+
|
1411
|
+
def add_sender_to_contact(message_id)
|
1412
|
+
if connected?
|
1413
|
+
query = ''
|
1414
|
+
query += "&search=inbox"
|
1415
|
+
query += "&view=up"
|
1416
|
+
query += "&act=astc"
|
1417
|
+
query += "&at="+at_value
|
1418
|
+
query += "&m="+message_id.to_s
|
1419
|
+
|
1420
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
1421
|
+
np.set_debug_output($stderr) if DEBUG
|
1422
|
+
np.start { |http|
|
1423
|
+
response = http.get(GM_LNK_GMAIL + "?" + query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
|
1424
|
+
}
|
1425
|
+
|
1426
|
+
return true
|
1427
|
+
else
|
1428
|
+
return false
|
1429
|
+
end
|
1430
|
+
end
|
1431
|
+
|
1432
|
+
def delete_contact(id)
|
1433
|
+
if connected?
|
1434
|
+
query = ''
|
1435
|
+
|
1436
|
+
if id.is_a?(Array)
|
1437
|
+
#Post: act=dc&at=xxxxx-xxxx&cl_nw=&cl_id=&cl_nm=&c=0&c=3d
|
1438
|
+
$query += "&act=dc&cl_nw=&cl_id=&cl_nm="
|
1439
|
+
id.each { |contact_id|
|
1440
|
+
query += "&c="+contact_id
|
1441
|
+
}
|
1442
|
+
else
|
1443
|
+
query += "search=contacts"
|
1444
|
+
query += "&ct_id="+id.to_s
|
1445
|
+
query += "&cvm=2"
|
1446
|
+
query += "&view=up"
|
1447
|
+
query += "&act=dc"
|
1448
|
+
end
|
1449
|
+
|
1450
|
+
query += "&at="+at_value
|
1451
|
+
if !(id.is_a?(Array))
|
1452
|
+
query += "&c="+id.to_s
|
1453
|
+
end
|
1454
|
+
|
1455
|
+
np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
|
1456
|
+
response = nil
|
1457
|
+
np.set_debug_output($stderr) if DEBUG
|
1458
|
+
if (id.is_a?(Array))
|
1459
|
+
np.start { |http|
|
1460
|
+
response = http.post(GM_LNK_GMAIL+"?view=up", query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
|
1461
|
+
parse_response(response.body)
|
1462
|
+
}
|
1463
|
+
else
|
1464
|
+
np.start { |http|
|
1465
|
+
response = http.get(GM_LNK_GMAIL + "?" + query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
|
1466
|
+
parse_response(response.body)
|
1467
|
+
}
|
1468
|
+
end
|
1469
|
+
|
1470
|
+
status = @raw["ar"][1]==1
|
1471
|
+
message = @raw["ar"][2]
|
1472
|
+
raise message unless message
|
1473
|
+
return status
|
1474
|
+
else
|
1475
|
+
return false
|
1476
|
+
end
|
1477
|
+
end
|
1478
|
+
|
1479
|
+
end
|
1480
|
+
|
1481
|
+
class GMailSnapshot
|
1482
|
+
|
1483
|
+
GM_STANDARD = 0x001
|
1484
|
+
GM_LABEL = 0x002
|
1485
|
+
GM_CONVERSATION = 0x004
|
1486
|
+
GM_QUERY = 0x008
|
1487
|
+
GM_CONTACT = 0x010
|
1488
|
+
GM_PREFERENCE = 0x020
|
1489
|
+
|
1490
|
+
def decode(str)
|
1491
|
+
return str if @charset.upcase == 'UTF-8'
|
1492
|
+
begin
|
1493
|
+
require 'Win32API'
|
1494
|
+
str = str.unpack("U*").pack("S*") + "\0"
|
1495
|
+
ostr = "\0" * str.length*2
|
1496
|
+
wideCharToMultiByte = Win32API.new('kernel32','WideCharToMultiByte',['L','L','P','L','P','L','L','L'],'L')
|
1497
|
+
wideCharToMultiByte.Call(0,0,str,-1,ostr,str.length*2,0,0)
|
1498
|
+
ostr.strip
|
1499
|
+
rescue LoadError
|
1500
|
+
require 'iconv'
|
1501
|
+
Iconv::iconv(@charset,'UTF-8',str)[0]
|
1502
|
+
end
|
1503
|
+
end
|
1504
|
+
|
1505
|
+
def strip_tags(str,allowable_tags='')
|
1506
|
+
str.gsub(/<[^>]*>/, '')
|
1507
|
+
end
|
1508
|
+
|
1509
|
+
#
|
1510
|
+
# return GMailSnapshot
|
1511
|
+
# param constant type
|
1512
|
+
# param array raw
|
1513
|
+
# desc Constructor.
|
1514
|
+
#
|
1515
|
+
attr_reader :gmail_ver, :quota_mb, :quota_per, :preference
|
1516
|
+
attr_reader :std_box_new, :have_invit, :label_list, :label_new
|
1517
|
+
attr_reader :message_list
|
1518
|
+
attr_reader :message
|
1519
|
+
attr_reader :contacts, :other_emails
|
1520
|
+
|
1521
|
+
def initialize(type, raw, charset='UTF-8')
|
1522
|
+
@charset = charset
|
1523
|
+
if (!raw.is_a?(Hash))
|
1524
|
+
@created = 0
|
1525
|
+
return nil
|
1526
|
+
elsif (raw.empty?)
|
1527
|
+
@created = 0
|
1528
|
+
return nil
|
1529
|
+
end
|
1530
|
+
if [GM_STANDARD,GM_LABEL,GM_CONVERSATION,GM_QUERY].include?(type)
|
1531
|
+
@gmail_ver = raw["v"][1]
|
1532
|
+
if raw["qu"]
|
1533
|
+
@quota_mb = raw["qu"][1]
|
1534
|
+
@quota_per = raw["qu"][3]
|
1535
|
+
end
|
1536
|
+
if (!raw["ds"].is_a?(Array))
|
1537
|
+
@created = 0
|
1538
|
+
return nil
|
1539
|
+
end
|
1540
|
+
@std_box_new = raw["ds"][1..-1]
|
1541
|
+
|
1542
|
+
@have_invit = raw["i"][1]
|
1543
|
+
@label_list = []
|
1544
|
+
@label_new = []
|
1545
|
+
raw["ct"][1].each {|v|
|
1546
|
+
@label_list.push(v[0])
|
1547
|
+
@label_new.push(v[1])
|
1548
|
+
}
|
1549
|
+
if raw["ts"]
|
1550
|
+
@view = (GM_STANDARD|GM_LABEL|GM_QUERY)
|
1551
|
+
@message_list = MessageList.new(raw["ts"][5],raw["ts"][3],raw["ts"][1])
|
1552
|
+
end
|
1553
|
+
@box = []
|
1554
|
+
if raw["t"]
|
1555
|
+
raw["t"].each do |t|
|
1556
|
+
if (t != "t")
|
1557
|
+
b = Box.new
|
1558
|
+
b.id = t[0]
|
1559
|
+
b.is_read = (t[1] != 1 ? 1 : 0)
|
1560
|
+
b.is_starred = (t[2] == 1 ? 1 : 0)
|
1561
|
+
b.date = decode(strip_tags(t[3]))
|
1562
|
+
b.sender = decode(strip_tags(t[4]))
|
1563
|
+
b.flag = t[5]
|
1564
|
+
b.subject = decode(strip_tags(t[6]))
|
1565
|
+
b.snippet = decode(t[7].gsub('"','"').gsub('…','...'))
|
1566
|
+
b.labels = t[8].empty? ? [] : t[8].map{|tt|decode(tt)}
|
1567
|
+
b.attachment = t[9].empty? ? []: decode(t[9]).split(",")
|
1568
|
+
b.msgid = t[10]
|
1569
|
+
@box.push(b)
|
1570
|
+
end
|
1571
|
+
end
|
1572
|
+
end
|
1573
|
+
|
1574
|
+
if raw["cs"]
|
1575
|
+
@view = GM_CONVERSATION
|
1576
|
+
@conv_title = raw["cs"][2]
|
1577
|
+
@conv_total = raw["cs"][8]
|
1578
|
+
@conv_id = raw["cs"][1]
|
1579
|
+
@conv_labels = raw["cs"][5].empty? ? '' : raw["cs"][5]
|
1580
|
+
if !@conv_labels.empty?
|
1581
|
+
ij = @conv_labels.index("^i")
|
1582
|
+
if !ij.nil?
|
1583
|
+
@conv_labels[ij] = "Inbox"
|
1584
|
+
end
|
1585
|
+
ij = @conv_labels.index("^s")
|
1586
|
+
if !ij.nil?
|
1587
|
+
@conv_labels[ij] = "Spam"
|
1588
|
+
end
|
1589
|
+
ij = @conv_labels.index("^k")
|
1590
|
+
if !ij.nil?
|
1591
|
+
@conv_labels[ij] = "Trash"
|
1592
|
+
end
|
1593
|
+
ij = @conv_labels.index("^t")
|
1594
|
+
if !ij.nil?
|
1595
|
+
@conv_labels[ij] = '' # Starred
|
1596
|
+
end
|
1597
|
+
ij = @conv_labels.index("^r")
|
1598
|
+
if !ij.nil?
|
1599
|
+
@conv_labels[ij] = "Drafts"
|
1600
|
+
end
|
1601
|
+
end
|
1602
|
+
|
1603
|
+
@conv_starred = false
|
1604
|
+
|
1605
|
+
@conv = []
|
1606
|
+
b = Conversation.new
|
1607
|
+
raw["mg"].each do |r|
|
1608
|
+
if (r[0] == "mb")
|
1609
|
+
b.body = '' if b.body.nil?
|
1610
|
+
b.body += r[1]
|
1611
|
+
if (r[2] == 0)
|
1612
|
+
b.body = decode(b.body)
|
1613
|
+
@conv.push(b)
|
1614
|
+
b = Conversation.new
|
1615
|
+
end
|
1616
|
+
elsif (r[0] == "mi")
|
1617
|
+
if b.id
|
1618
|
+
@conv.push(b)
|
1619
|
+
b = Conversation.new
|
1620
|
+
end
|
1621
|
+
b = Conversation.new
|
1622
|
+
b.index = r[2]
|
1623
|
+
b.id = r[3]
|
1624
|
+
b.is_star = r[4]
|
1625
|
+
@conv_starred = (b.is_star == 1)
|
1626
|
+
b.sender = decode(r[6])
|
1627
|
+
b.sender_email = r[8].gsub("\"",'') # remove annoying d-quotes in address
|
1628
|
+
b.recv = r[9]
|
1629
|
+
b.recv_email = r[11].to_s.gsub("\"",'')
|
1630
|
+
b.reply_email = r[14].to_s.gsub("\"",'')
|
1631
|
+
b.dt_easy = r[10]
|
1632
|
+
b.dt = r[15]
|
1633
|
+
b.subject = decode(r[16])
|
1634
|
+
b.snippet = decode(r[17])
|
1635
|
+
b.attachment = []
|
1636
|
+
r[18].each do |bb|
|
1637
|
+
at = Attachment.new
|
1638
|
+
at.id = bb[0]
|
1639
|
+
at.filename = bb[1]
|
1640
|
+
at.type = bb[2]
|
1641
|
+
at.size = bb[3]
|
1642
|
+
b.attachment.push(at)
|
1643
|
+
end
|
1644
|
+
b.is_draft = false
|
1645
|
+
b.body = ''
|
1646
|
+
elsif (r[0] == "di")
|
1647
|
+
if b.id
|
1648
|
+
@conv.push(b)
|
1649
|
+
b = Conversation.new
|
1650
|
+
end
|
1651
|
+
b = Conversation.new
|
1652
|
+
b.index = r[2]
|
1653
|
+
b.id = r[3]
|
1654
|
+
b.is_star = r[4]
|
1655
|
+
@conv_starred = (b.is_star == 1)
|
1656
|
+
b.sender = decode(r[6])
|
1657
|
+
b.sender_email = r[8].gsub("\"",'') # remove annoying d-quotes in address
|
1658
|
+
b.recv = r[9]
|
1659
|
+
b.recv_email = r[11].gsub("\"",'')
|
1660
|
+
b.reply_email = r[14].gsub("\"",'')
|
1661
|
+
b.cc_email = r[12].gsub("\"",'')
|
1662
|
+
b.bcc_email = r[13].gsub("\"",'')
|
1663
|
+
b.dt_easy = r[10]
|
1664
|
+
b.dt = r[15]
|
1665
|
+
b.subject = decode(r[16])
|
1666
|
+
b.snippet = decode(r[17])
|
1667
|
+
b.attachment = []
|
1668
|
+
r[18].each do |bb|
|
1669
|
+
at = Attachment.new
|
1670
|
+
at.id = bb[0]
|
1671
|
+
at.filename = bb[1]
|
1672
|
+
at.type = bb[2]
|
1673
|
+
at.size = bb[3]
|
1674
|
+
b.attachment.push(at)
|
1675
|
+
end
|
1676
|
+
b.is_draft = true
|
1677
|
+
b.draft_parent = r[5]
|
1678
|
+
b.body = decode(r[20])
|
1679
|
+
end
|
1680
|
+
end
|
1681
|
+
@conv.push(b) unless !b.id.nil?
|
1682
|
+
@message = Message.new(@conv_tile,@conv_total,@conv_id,@conv_labels,@conv_starred)
|
1683
|
+
@message.conv = @conv
|
1684
|
+
end
|
1685
|
+
elsif type == GM_CONTACT
|
1686
|
+
@contacts = []
|
1687
|
+
@contact_groups = []
|
1688
|
+
@contacts_total = 0
|
1689
|
+
|
1690
|
+
if raw["cls"]
|
1691
|
+
@contacts_toal = (raw["cls"][1]).to_i
|
1692
|
+
@contacts_shown = (raw["cls"][3]).to_i
|
1693
|
+
end
|
1694
|
+
|
1695
|
+
type = ''
|
1696
|
+
c_grp_det = ''
|
1697
|
+
if raw["a"]
|
1698
|
+
c_array = "a"
|
1699
|
+
# determine is this is a list or contact detail
|
1700
|
+
if ((raw["a"]).length == 2 && raw["a"][1][6])
|
1701
|
+
type = "detail"
|
1702
|
+
c_id = 0
|
1703
|
+
c_name = 1
|
1704
|
+
c_email = 3
|
1705
|
+
c_groups = 4
|
1706
|
+
c_notes = 5
|
1707
|
+
c_detail = 6
|
1708
|
+
else
|
1709
|
+
c_email = 3
|
1710
|
+
c_notes = 4
|
1711
|
+
type = "list"
|
1712
|
+
end
|
1713
|
+
elsif raw["cl"] # list
|
1714
|
+
c_array = "cl"
|
1715
|
+
c_email = 4
|
1716
|
+
c_notes = 5
|
1717
|
+
c_addresses = 6
|
1718
|
+
type = "list"
|
1719
|
+
elsif raw["cov"] # contact detail in accounts using "cl"
|
1720
|
+
c_array = "cov"
|
1721
|
+
type = "detail"
|
1722
|
+
c_id = 1
|
1723
|
+
c_name = 2
|
1724
|
+
c_email = 4
|
1725
|
+
c_groups = 6
|
1726
|
+
c_notes = 7
|
1727
|
+
c_detail = 8
|
1728
|
+
elsif raw["clv"] # group detail in accounts using "cl"
|
1729
|
+
c_array = "clv"
|
1730
|
+
type = "detail"
|
1731
|
+
c_id = 1
|
1732
|
+
c_name = 2
|
1733
|
+
c_email = 6
|
1734
|
+
c_total = 3
|
1735
|
+
c_detail = 5
|
1736
|
+
c_members = 4
|
1737
|
+
c_notes = 0
|
1738
|
+
else
|
1739
|
+
c = Contact.new
|
1740
|
+
c.id = 'error'
|
1741
|
+
c.name = 'gmailer Error'
|
1742
|
+
@contacts.push(c)
|
1743
|
+
end
|
1744
|
+
|
1745
|
+
if type == "list"
|
1746
|
+
# An ordinary list of contacts
|
1747
|
+
for i in (1 ... raw[c_array].length)
|
1748
|
+
a = raw[c_array][i]
|
1749
|
+
b = Contact.new
|
1750
|
+
b.id = a[1] # contact id
|
1751
|
+
b.name = a[2] ? a[2] : ''
|
1752
|
+
b.email = a[c_email]
|
1753
|
+
|
1754
|
+
if a[c_notes]
|
1755
|
+
if (a[c_notes]).is_a?(Array)
|
1756
|
+
b.notes = ''
|
1757
|
+
b.is_group = true
|
1758
|
+
# email addresses for groups are in a different location and format
|
1759
|
+
# "Name" <email@address.net>, "Name2" <email2@address.net>, etc
|
1760
|
+
# and needs to be "simply" re-created for backwards compatibility
|
1761
|
+
gr_count = a[c_notes].length
|
1762
|
+
group_addresses = []
|
1763
|
+
a[c_notes].each {|gr_entry|
|
1764
|
+
group_addresses.push(gr_entry[1])
|
1765
|
+
}
|
1766
|
+
b.email = group_addresses.join(", ")
|
1767
|
+
|
1768
|
+
b.group_names = a[c_email]
|
1769
|
+
b.group_total = a[3]
|
1770
|
+
b.group_email = (a[c_notes]).length > 0 ? a[c_addresses] : []
|
1771
|
+
else
|
1772
|
+
b.notes = a[c_notes]
|
1773
|
+
b.is_group = false
|
1774
|
+
b.groups = a[c_addresses]
|
1775
|
+
end
|
1776
|
+
end
|
1777
|
+
@contacts.push(b)
|
1778
|
+
end
|
1779
|
+
elsif type == "detail"
|
1780
|
+
details = {}
|
1781
|
+
if c_array == "clv"
|
1782
|
+
# Group details
|
1783
|
+
cov = Contact.new
|
1784
|
+
cov.is_group = true # is this a group?
|
1785
|
+
cov.id = raw[c_array][1][c_id] # group id
|
1786
|
+
cov.name = raw[c_array][1][c_name] # group name
|
1787
|
+
gr_count = (raw[c_array][1][c_detail]).length
|
1788
|
+
cov.group_names = raw[c_array][1][c_members] # string of names of group members
|
1789
|
+
cov.group_total = raw[c_array][1][c_total] # string, total number of members in group
|
1790
|
+
cov.group_email = raw[c_array][1][c_email] ? raw[c_array][1][c_email] : '' # formatted list of addresses as: Name <address>
|
1791
|
+
cov.notes = '' # no notes for groups... yet!
|
1792
|
+
group_addresses = [] # string of flattened email addresses
|
1793
|
+
cov.members = [] # array of group members
|
1794
|
+
(raw[c_array][1][c_detail]).each do |gr_entry|
|
1795
|
+
group_addresses.push(gr_entry[1])
|
1796
|
+
m = Member.new
|
1797
|
+
m.id = gr_entry[0]
|
1798
|
+
m.name = (gr_entry[2] ? gr_entry[2] : '')
|
1799
|
+
m.email = gr_entry[1]
|
1800
|
+
cov.members.push(m)
|
1801
|
+
end
|
1802
|
+
cov.email = (group_addresses.length > 0) ? group_addresses.join(", ") : ''
|
1803
|
+
|
1804
|
+
else
|
1805
|
+
# Contact details (advanced contact information)
|
1806
|
+
# used when a contact id was supplied for retrieval
|
1807
|
+
cov = Contact.new
|
1808
|
+
cov.is_group = false
|
1809
|
+
cov.id = raw[c_array][1][c_id]
|
1810
|
+
cov.name = raw[c_array][1][c_name]
|
1811
|
+
cov.email = raw[c_array][1][c_email]
|
1812
|
+
cov.groups = raw[c_array][1][c_groups]
|
1813
|
+
if raw[c_array][1][c_notes][0]
|
1814
|
+
cov.notes = (raw[c_array][1][c_notes][0] == "n") ? raw[c_array][1][c_notes][1] : ''
|
1815
|
+
else
|
1816
|
+
cov.notes = ''
|
1817
|
+
end
|
1818
|
+
num_details = (raw[c_array][1][c_detail]).length
|
1819
|
+
if num_details > 0
|
1820
|
+
raw[c_array][1][c_detail].each do |i|
|
1821
|
+
details[:detail_name] = i[0]
|
1822
|
+
temp = i[1] ? i[1] : []
|
1823
|
+
0.step(temp.length-1,2) do |j|
|
1824
|
+
case temp[j]
|
1825
|
+
when "p"
|
1826
|
+
field = :phone
|
1827
|
+
when "e"
|
1828
|
+
field = :email
|
1829
|
+
when "m"
|
1830
|
+
field = :mobile
|
1831
|
+
when "f"
|
1832
|
+
field = :fax
|
1833
|
+
when "b"
|
1834
|
+
field = :pager
|
1835
|
+
when "i"
|
1836
|
+
field = :im
|
1837
|
+
when "d"
|
1838
|
+
field = :company
|
1839
|
+
when "t"
|
1840
|
+
field = :position
|
1841
|
+
when "o"
|
1842
|
+
field = :other
|
1843
|
+
when "a"
|
1844
|
+
field = :address
|
1845
|
+
end
|
1846
|
+
|
1847
|
+
details[field] = temp[j+1]
|
1848
|
+
end
|
1849
|
+
|
1850
|
+
end
|
1851
|
+
|
1852
|
+
end
|
1853
|
+
cov.details = details
|
1854
|
+
end
|
1855
|
+
|
1856
|
+
@contacts.push(cov)
|
1857
|
+
end
|
1858
|
+
|
1859
|
+
# Contact groups
|
1860
|
+
if raw["cla"]
|
1861
|
+
for i in (1...(raw["cla"][1]).length)
|
1862
|
+
a = raw["cla"][1][i]
|
1863
|
+
b = {
|
1864
|
+
:id => a[0],
|
1865
|
+
:name => a[1],
|
1866
|
+
:addresses => a[2] ? a[2] : ''
|
1867
|
+
}
|
1868
|
+
@contacts_groups.push(b)
|
1869
|
+
end
|
1870
|
+
end
|
1871
|
+
@view = GM_CONTACT
|
1872
|
+
elsif type == GM_PREFERENCE
|
1873
|
+
prefs = {}
|
1874
|
+
raw["p"].each_with_index { |v,i|
|
1875
|
+
prefs[v[0]] = v[1] if i>0
|
1876
|
+
}
|
1877
|
+
@preference = Preference.new
|
1878
|
+
prefs.each do |k,v|
|
1879
|
+
case k
|
1880
|
+
when 'ix_nt'
|
1881
|
+
@preference.max_page_size = v
|
1882
|
+
when 'bx_hs'
|
1883
|
+
@preference.keyboard_shortcuts = (v == '1')
|
1884
|
+
when 'bx_sc'
|
1885
|
+
@preference.indicators = (v == '1')
|
1886
|
+
when 'sx_dl'
|
1887
|
+
@preference.display_language = v
|
1888
|
+
when 'sx_sg'
|
1889
|
+
@preference.signature = (v == '0') ? '' : v
|
1890
|
+
when 'sx_rt'
|
1891
|
+
@preference.reply_to = v
|
1892
|
+
when 'bx_ns'
|
1893
|
+
@preference.snippets = (v == '0')
|
1894
|
+
when 'sx_dn'
|
1895
|
+
@preference.display_name = v
|
1896
|
+
end
|
1897
|
+
end
|
1898
|
+
|
1899
|
+
@label_list = []
|
1900
|
+
@label_total = []
|
1901
|
+
raw["cta"][1].each { |v|
|
1902
|
+
@label_list.push(v[0])
|
1903
|
+
@label_total.push(v[1])
|
1904
|
+
}
|
1905
|
+
@other_emails = []
|
1906
|
+
if raw["cfs"]
|
1907
|
+
raw["cfs"][1].each {|v|
|
1908
|
+
@other_emails.push({"name"=>decode(v[0]),"email"=>v[1],"default"=>(v[2]==1)})
|
1909
|
+
}
|
1910
|
+
end
|
1911
|
+
@filter = []
|
1912
|
+
raw["fi"][1].each do |fi|
|
1913
|
+
f = Filter.new
|
1914
|
+
f.id = fi[0]
|
1915
|
+
f.query = fi[1]
|
1916
|
+
f.star = fi[3]
|
1917
|
+
f.label = fi[4]
|
1918
|
+
f.archive = fi[5]
|
1919
|
+
f.trash = fi[6]
|
1920
|
+
f.from = fi[2][0]
|
1921
|
+
f.to = fi[2][1]
|
1922
|
+
f.subject = fi[2][2]
|
1923
|
+
f.has = fi[2][3]
|
1924
|
+
f.hasnot = fi[2][4]
|
1925
|
+
f.attach = fi[2][5]
|
1926
|
+
|
1927
|
+
@filter.push(b)
|
1928
|
+
end
|
1929
|
+
@view = GM_PREFERENCE
|
1930
|
+
else
|
1931
|
+
@created = 0
|
1932
|
+
return nil
|
1933
|
+
end
|
1934
|
+
@message_list.box = @box if @message_list
|
1935
|
+
|
1936
|
+
@created = 1
|
1937
|
+
end
|
1938
|
+
|
1939
|
+
end
|
1940
|
+
|
1941
|
+
# a single filter
|
1942
|
+
class Filter
|
1943
|
+
attr_accessor :id,:query,:star,:label,:archive,:trash
|
1944
|
+
attr_accessor :from,:to,:subject,:has,:hasnot,:attach
|
1945
|
+
end
|
1946
|
+
|
1947
|
+
# a single box
|
1948
|
+
class Box
|
1949
|
+
attr_accessor :id, :is_read, :is_starred, :date, :msgid
|
1950
|
+
attr_accessor :sender, :flag, :subject, :snippet, :labels, :attachment
|
1951
|
+
|
1952
|
+
def read?
|
1953
|
+
is_read == 1
|
1954
|
+
end
|
1955
|
+
|
1956
|
+
def new?
|
1957
|
+
is_read != 1
|
1958
|
+
end
|
1959
|
+
|
1960
|
+
def star?
|
1961
|
+
is_starred == 1
|
1962
|
+
end
|
1963
|
+
|
1964
|
+
end
|
1965
|
+
|
1966
|
+
# a list of messages.
|
1967
|
+
class MessageList
|
1968
|
+
attr_reader :name, :total, :pos
|
1969
|
+
attr_accessor :box, :connection
|
1970
|
+
def initialize(name,total,pos)
|
1971
|
+
@name = name
|
1972
|
+
@total = total
|
1973
|
+
@pos = pos
|
1974
|
+
end
|
1975
|
+
|
1976
|
+
def each(&block)
|
1977
|
+
@box.each do |b|
|
1978
|
+
block.call(b)
|
1979
|
+
end
|
1980
|
+
end
|
1981
|
+
|
1982
|
+
def each_msg(&block)
|
1983
|
+
@box.each do |b|
|
1984
|
+
m = connection.fetch(:conversation=>b.id).message
|
1985
|
+
m.connection = @connection
|
1986
|
+
block.call(m)
|
1987
|
+
end
|
1988
|
+
end
|
1989
|
+
|
1990
|
+
end
|
1991
|
+
|
1992
|
+
# a Preference
|
1993
|
+
class Preference
|
1994
|
+
attr_accessor :max_page_size, :keyboard_shortcuts, :indicators, :display_language
|
1995
|
+
attr_accessor :signature, :reply_to, :snippets, :display_name
|
1996
|
+
|
1997
|
+
def initialize
|
1998
|
+
@max_page_size = '10'
|
1999
|
+
@keyboard_shortcuts = false
|
2000
|
+
@indicators = false
|
2001
|
+
@display_language = 'en'
|
2002
|
+
@signature = ''
|
2003
|
+
@reply_to = ''
|
2004
|
+
@snippets = false
|
2005
|
+
@display_name = ''
|
2006
|
+
end
|
2007
|
+
end
|
2008
|
+
|
2009
|
+
# Contact
|
2010
|
+
class Contact
|
2011
|
+
attr_accessor :id,:name,:email,:is_group,:notes,:groups,:group_names,:group_email,:group_total,:members,:details
|
2012
|
+
def initialize
|
2013
|
+
@id = ''
|
2014
|
+
@name = ''
|
2015
|
+
@email = ''
|
2016
|
+
@notes = ''
|
2017
|
+
@groups = ''
|
2018
|
+
@group_names = ''
|
2019
|
+
@group_email = ''
|
2020
|
+
@group_total = ''
|
2021
|
+
@members = ''
|
2022
|
+
@is_group = false
|
2023
|
+
@details = {}
|
2024
|
+
end
|
2025
|
+
|
2026
|
+
def group?
|
2027
|
+
@is_group
|
2028
|
+
end
|
2029
|
+
end
|
2030
|
+
|
2031
|
+
# a silgle Member
|
2032
|
+
class Member
|
2033
|
+
attr_accessor :id,:name,:email
|
2034
|
+
def initialize
|
2035
|
+
@id = ''
|
2036
|
+
@name = ''
|
2037
|
+
@email = ''
|
2038
|
+
end
|
2039
|
+
end
|
2040
|
+
|
2041
|
+
# a single attachment
|
2042
|
+
class Attachment
|
2043
|
+
attr_accessor :id, :filename, :type, :size
|
2044
|
+
end
|
2045
|
+
|
2046
|
+
# a single conversation
|
2047
|
+
class Conversation
|
2048
|
+
attr_accessor :id, :index, :body, :draft_parent, :is_draft, :attachment
|
2049
|
+
attr_accessor :snippet, :subject, :dt, :dt_easy, :bcc_email, :cc_email
|
2050
|
+
attr_accessor :reply_email, :recv_email, :recv, :sender_email, :sender, :is_star
|
2051
|
+
def read?
|
2052
|
+
is_read == 1
|
2053
|
+
end
|
2054
|
+
|
2055
|
+
def new?
|
2056
|
+
is_read != 1
|
2057
|
+
end
|
2058
|
+
|
2059
|
+
def star?
|
2060
|
+
is_starred == 1
|
2061
|
+
end
|
2062
|
+
|
2063
|
+
end
|
2064
|
+
|
2065
|
+
# a single message
|
2066
|
+
class Message
|
2067
|
+
attr_reader :title, :total, :id, :labels, :starred
|
2068
|
+
attr_accessor :conv, :connection
|
2069
|
+
def initialize(title,total,id,labels,starred)
|
2070
|
+
@title = title
|
2071
|
+
@total = total
|
2072
|
+
@id = id
|
2073
|
+
@labels = labels
|
2074
|
+
@starred = starred
|
2075
|
+
end
|
2076
|
+
|
2077
|
+
def method_missing(methId)
|
2078
|
+
str = methId.id2name
|
2079
|
+
@conv[0].method(str).call
|
2080
|
+
end
|
2081
|
+
|
2082
|
+
#
|
2083
|
+
# return boolean
|
2084
|
+
# param string label
|
2085
|
+
# desc apply label to message
|
2086
|
+
#
|
2087
|
+
def apply_label(label)
|
2088
|
+
@connection.perform_action(GM_ACT_APPLYLABEL, @id, label)
|
2089
|
+
end
|
2090
|
+
|
2091
|
+
#
|
2092
|
+
# return boolean
|
2093
|
+
# param string label
|
2094
|
+
# desc remove label from message
|
2095
|
+
#
|
2096
|
+
def remove_label(label)
|
2097
|
+
@connection.perform_action(GM_ACT_REMOVELABEL, @id, label)
|
2098
|
+
end
|
2099
|
+
|
2100
|
+
#
|
2101
|
+
# return boolean
|
2102
|
+
# desc apply star to a message
|
2103
|
+
#
|
2104
|
+
def apply_star()
|
2105
|
+
@connection.perform_action(GM_ACT_STAR,@id, '')
|
2106
|
+
end
|
2107
|
+
|
2108
|
+
#
|
2109
|
+
# return boolean
|
2110
|
+
# param string msgid
|
2111
|
+
# desc remove star from a message
|
2112
|
+
#
|
2113
|
+
def remove_star()
|
2114
|
+
@connection.perform_action(GM_ACT_UNSTAR,@id, '')
|
2115
|
+
end
|
2116
|
+
|
2117
|
+
#
|
2118
|
+
# return boolean
|
2119
|
+
# desc archive a message
|
2120
|
+
#
|
2121
|
+
def archive()
|
2122
|
+
@connection.perform_action(GM_ACT_ARCHIVE,@id, '')
|
2123
|
+
end
|
2124
|
+
|
2125
|
+
#
|
2126
|
+
# return boolean
|
2127
|
+
# param string msgid
|
2128
|
+
# desc archive a message
|
2129
|
+
#
|
2130
|
+
def unarchive()
|
2131
|
+
@connection.perform_action(GM_ACT_INBOX,@id, '')
|
2132
|
+
end
|
2133
|
+
|
2134
|
+
#
|
2135
|
+
# return boolean
|
2136
|
+
# param string msgid
|
2137
|
+
# desc mark a message as read
|
2138
|
+
#
|
2139
|
+
def mark_read()
|
2140
|
+
@connection.perform_action(GM_ACT_READ,@id, '')
|
2141
|
+
end
|
2142
|
+
|
2143
|
+
#
|
2144
|
+
# return boolean
|
2145
|
+
# param string msgid
|
2146
|
+
# desc mark a message as unread
|
2147
|
+
#
|
2148
|
+
def mark_unread()
|
2149
|
+
@connection.perform_action(GM_ACT_UNREAD,@id, '')
|
2150
|
+
end
|
2151
|
+
|
2152
|
+
def read?()
|
2153
|
+
@conv[0].read?
|
2154
|
+
end
|
2155
|
+
|
2156
|
+
def new?()
|
2157
|
+
@conv[0].new?
|
2158
|
+
end
|
2159
|
+
|
2160
|
+
#
|
2161
|
+
# return boolean
|
2162
|
+
# param string msgid
|
2163
|
+
# desc report a message as spam
|
2164
|
+
#
|
2165
|
+
def report_spam()
|
2166
|
+
@connection.perform_action(GM_ACT_SPAM,@id, '')
|
2167
|
+
end
|
2168
|
+
|
2169
|
+
#
|
2170
|
+
# return boolean
|
2171
|
+
# param string msgid
|
2172
|
+
# desc report a message as not spam
|
2173
|
+
#
|
2174
|
+
def report_not_spam()
|
2175
|
+
@connection.perform_action(GM_ACT_UNSPAM,@id, '')
|
2176
|
+
end
|
2177
|
+
|
2178
|
+
#
|
2179
|
+
# return boolean
|
2180
|
+
# desc move a message to trash
|
2181
|
+
#
|
2182
|
+
def trash()
|
2183
|
+
@connection.perform_action(GM_ACT_TRASH,@id, '')
|
2184
|
+
end
|
2185
|
+
|
2186
|
+
#
|
2187
|
+
# return boolean
|
2188
|
+
# desc move a message from trash to inbox
|
2189
|
+
#
|
2190
|
+
def untrash()
|
2191
|
+
@connection.perform_action(GM_ACT_UNTRASH,@id, '')
|
2192
|
+
end
|
2193
|
+
|
2194
|
+
#
|
2195
|
+
# return boolean
|
2196
|
+
# desc delete a message forever
|
2197
|
+
#
|
2198
|
+
def delete()
|
2199
|
+
if connected?
|
2200
|
+
@connection.perform_action(GM_ACT_DELFOREVER,@id, '')
|
2201
|
+
else
|
2202
|
+
false
|
2203
|
+
end
|
2204
|
+
end
|
2205
|
+
|
2206
|
+
def original()
|
2207
|
+
@connection.fetch(:show_original=>@id)
|
2208
|
+
end
|
2209
|
+
end
|
2210
|
+
|
2211
|
+
# Singleton method
|
2212
|
+
# return bool
|
2213
|
+
# desc Connect to GMail with default session management settings.
|
2214
|
+
#
|
2215
|
+
|
2216
|
+
def GMailer.connect(*param)
|
2217
|
+
g = Connection.new(*param)
|
2218
|
+
@connection = g
|
2219
|
+
if block_given?
|
2220
|
+
yield(g)
|
2221
|
+
g.disconnect()
|
2222
|
+
else
|
2223
|
+
g
|
1789
2224
|
end
|
2225
|
+
end
|
1790
2226
|
|
1791
2227
|
end
|
1792
2228
|
|