gmailer 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/CHANGES +6 -0
  2. data/README +35 -57
  3. data/gmailer.rb +1602 -1383
  4. metadata +2 -2
data/CHANGES CHANGED
@@ -1,3 +1,9 @@
1
+ == 0.0.9 - 8-Sep-2005
2
+ - fix fetch message body bug
3
+ - fix encode, decode bug
4
+ - rename some method like trash_in,trash_out
5
+ - add show original mail
6
+
1
7
  == 0.0.8 - 3-Sep-2005
2
8
  - rename is_connected method
3
9
  - add send mail as feature
data/README CHANGED
@@ -5,55 +5,20 @@
5
5
  == Synopsis
6
6
  ==== A typical code sequence for fetching gmails
7
7
 
8
- gmail = GMailer.new
9
- gmail.set_login_info(name, pwd)
10
- if gmail.connect
11
- gmail.fetch_box(GM_LABEL, "my_label", 0)
12
- snapshot = gmail.snapshot(GM_LABEL)
13
- if snapshot
14
- puts "Total # of conversations of my_label = " + snapshot.box_total.to_s
15
- end
16
- gmail.disconnect
17
- end
18
-
19
- Or more simpler
20
-
21
- GMailer.connect(name, pwd) do |gmail|
22
- snapshot = gmail.fetch_box(GM_LABEL, "my_label", 0)
23
- if snapshot
24
- puts "Total # of conversations of my_label = " + snapshot.box_total.to_s
25
- end
26
- end
27
-
28
- Or even
29
-
30
8
  GMailer.connect(name, pwd) do |g|
31
- g.fetch(:label=>"my_label") {|snapshot|
32
- puts "Total # of conversations of my_label = " + snapshot.box_total.to_s
9
+ g.messages(:label=>"my_label") {|ml|
10
+ puts "Total # of conversations of my_label = " + ml.total.to_s
33
11
  }
34
12
  end
35
13
 
36
14
 
37
15
  === Sending new gmails with gmailer
38
16
 
39
- gmail = GMailer.new
40
- gmail.set_login_info(name, pwd)
41
- if gmail.connect
42
- to = "who@what.com, my_friend@his_company.com, god@heaven.org"
43
- cc = "foo@bar.com"
44
- subject = "Hello There!"
45
- message = "Hi...\n\nBlah blah blah~..."
46
- attachments = ["./my_pic.jpg", "./my_cv.txt"]
47
- gmail.send(to, subject, message, cc, '','', '', attachments, false, '')
48
- end
49
-
50
- Or shorter
51
-
52
17
  GMailer.connect(name, pwd) do |g|
53
18
  # 'From' default gmail.com account
54
19
  g.send(
55
- :to => "who@what.com, my_friend@his_company.com, god@heaven.org"
56
- :cc => "foo@bar.com"
20
+ :to => "who@what.com, my_friend@his_company.com, god@heaven.org",
21
+ :cc => "foo@bar.com",
57
22
  :subject => "Hello There!",
58
23
  :body => "Hi...\n\nBlah blah blah~...",
59
24
  :files => ["./my_pic.jpg", "./my_cv.txt"])
@@ -61,8 +26,8 @@ Or shorter
61
26
  # multiple verified email addresses and choose one 'From:' email address
62
27
  g.send(
63
28
  :from => "verified@email.com",
64
- :to => "who@what.com, my_friend@his_company.com, god@heaven.org"
65
- :cc => "foo@bar.com"
29
+ :to => "who@what.com, my_friend@his_company.com, god@heaven.org",
30
+ :cc => "foo@bar.com",
66
31
  :subject => "Hello There!",
67
32
  :body => "Hi...\n\nBlah blah blah~...",
68
33
  :files => ["./my_pic.jpg", "./my_cv.txt"])
@@ -71,19 +36,6 @@ Or shorter
71
36
 
72
37
  === Playing around with contact list
73
38
 
74
- gmail = GMailer.new
75
- gmail.set_login_info(name, pwd)
76
- if gmail.connect
77
- gmail.fetch_box(GM_CONTACT, "freq", 0)
78
- snapshot = gmail.snapshot(GM_CONTACT)
79
- puts "Your frequently used addresses:"
80
- snapshot.contacts.each { |item|
81
- puts "Name: " + item["name"] + ", Email: " + item["email"]
82
- }
83
- end
84
-
85
- Or shorter
86
-
87
39
  GMailer.connect(name, pwd) do |g|
88
40
  puts "Your frequently used addresses:"
89
41
  g.fetch(:contact=>"freq").each do |item|
@@ -172,17 +124,17 @@ GMailer.connect(:username=>name,:password=>pwd) do |g|
172
124
  g.report_spam(msgid)
173
125
 
174
126
  #report a message as not spam
175
- g.not_spam(msgid)
127
+ g.report_not_spam(msgid)
176
128
  end
177
129
 
178
130
  === Trash In & Out and delete a message
179
131
 
180
132
  GMailer.connect(:username=>name,:password=>pwd) do |g|
181
133
  #move a message to trash
182
- g.trash_in(msgid)
134
+ g.trash(msgid)
183
135
 
184
136
  #move a message from trash to inbox
185
- g.trash_out(msgid)
137
+ g.untrash(msgid)
186
138
 
187
139
  #delete a trash message forever
188
140
  g.delete_trash(msgid)
@@ -194,6 +146,26 @@ GMailer.connect(:username=>name,:password=>pwd) do |g|
194
146
  g.delete_message(msgid)
195
147
  end
196
148
 
149
+ === Show Original Message
150
+
151
+ GMailer.connect(:username=>name,:password=>pwd) do |g|
152
+ #show original
153
+ g.show_original(msgid)
154
+ }
155
+
156
+ === Fetch messages with filter
157
+
158
+ GMailer.connect(:username=>name,:password=>pwd) do |g|
159
+ g.messages(:standard=>'all',:read=>false).each {|msg|
160
+ msg.apply_star
161
+ msg.apply_label(label)
162
+ puts "subject: " + msg.subject
163
+ puts "from: " + msg.sender
164
+ puts msg.body
165
+ puts msg.original
166
+ }
167
+ end
168
+
197
169
  == Class Methods
198
170
  GMailer.new(charset='UTF-8')
199
171
  Returns a new GMailer object and set up charset.
@@ -279,6 +251,12 @@ apply_star(msgid)
279
251
  remove_star(msgid)
280
252
  To remove starring from a message
281
253
 
254
+ trash(msgid)
255
+ To move a message to trash
256
+
257
+ untrash(msgid)
258
+ To move a message out of trash
259
+
282
260
  archive(msgid)
283
261
  To archive a message
284
262
 
data/gmailer.rb CHANGED
@@ -25,6 +25,7 @@ GM_CONVERSATION = 0x004
25
25
  GM_QUERY = 0x008
26
26
  GM_CONTACT = 0x010
27
27
  GM_PREFERENCE = 0x020
28
+ GM_SHOWORIGINAL = 0x040
28
29
 
29
30
  GM_ACT_CREATELABEL = 1
30
31
  GM_ACT_DELETELABEL = 2
@@ -48,167 +49,1605 @@ GM_ACT_TRASHMSG = 19 # trash individual message
48
49
  GM_ACT_DELSPAM = 20 # delete spam, forever
49
50
  GM_ACT_DELTRASH = 21 # delete trash message, forever
50
51
 
51
- class GMailer
52
-
53
- VERSION = "0.0.8"
54
-
55
- @cookie_str
56
- @login
57
- @pwd
58
- @raw # raw packets
59
- @contact_raw # raw packets for address book
60
- @timezone
61
- @created
62
- @proxy_host
63
- @proxy_port
64
- @proxy_user
65
- @proxy_pass
66
-
67
- def encode(str)
68
- return str if @charset.upcase == 'UTF-8'
69
- begin
70
- require 'Win32API'
71
- str += "\0"
72
- ostr = "\0" * 256
73
- multiByteToWideChar = Win32API.new('kernel32','MultiByteToWideChar',['L','L','P','L','P','L'],'L')
74
- multiByteToWideChar.Call(0,0,str,-1,ostr,128)
75
- (ostr.strip + "\0").unpack("S*").pack("U*")
76
- rescue LoadError
77
- require 'iconv'
78
- Iconv::iconv('UTF-8',@charset,str)[0]
79
- end
80
- end
81
-
82
- #
83
- # return GMailer
84
- # desc Constructor
85
- #
86
- def initialize(*param)
87
- Debugger::say("Constructing GMailer...")
88
- @login = ''
89
- @pwd = ''
90
- @raw = {}
91
- @proxy_host = nil
92
- @proxy_port = 0
93
- @proxy_user = nil
94
- @proxy_pass = nil
95
- @proxy = false
96
- if param.length==1 && param[0].class==Hash
97
- param = param[0]
98
- set_login_info(param[:username]||'',param[:password]||'')
99
- @proxy_host = param[:proxy_host]
100
- @proxy = !@proxy_host.nil?
101
- @proxy_port = param[:proxy_port] || 80
102
- @proxy_user = param[:proxy_user]
103
- @proxy_pass = param[:proxy_pass]
104
- @charset = param[:charset] || 'UTF-8'
105
- elsif param.length==0
106
- @charset = 'UTF-8'
107
- elsif param.length==1
108
- @charset = param[0]
109
- elsif param.length==2
110
- @charset = 'UTF-8'
111
- set_login_info(param[0],param[1])
112
- elsif param.length==3
113
- @charset = param[2]
114
- set_login_info(param[0],param[1])
115
- else
116
- raise ArgumentError, 'Invalid argument'
117
- end
118
- Debugger::say("Constructing completed.")
119
- end
120
-
121
- #
122
- # return void
123
- # param string my_login
124
- # param string my_pwd
125
- # param int my_tz
126
- # desc Set GMail login information.
127
- #
128
- def set_login_info(my_login, my_pwd, my_tz=0)
129
- @login = my_login
130
- @pwd = my_pwd
131
- @timezone = (my_tz*-60).to_i.to_s
132
- Debugger::say("LoginInfo set.")
133
- end
134
-
135
- #
136
- # return bool
137
- # desc Connect to GMail without setting any session/cookie.
138
- #
139
- def connect_no_cookie()
140
- Debugger::say("Start connecting without cookie...")
141
-
142
- postdata = "service=mail&Email=" + URI.escape(@login) + "&Passwd=" + URI.escape(@pwd) + "&null=Sign%20in&continue=" +
143
- URI.escape('https://mail.google.com/mail/?ui=html&zy=l') + "&rm=false&PersistentCookie=yes"
144
-
145
- np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 443)
146
- np.use_ssl = true
147
- np.verify_mode = OpenSSL::SSL::VERIFY_NONE
148
- result = ''
149
- response = nil
150
- # np.set_debug_output($stderr)
151
- np.start { |http|
152
- response = http.post(GM_LNK_LOGIN, postdata,{'User-agent' => GM_USER_AGENT} )
153
- result = response.body
154
- }
155
-
156
- if result.include?("errormsg")
157
- @cookie_str = ''
158
- Debugger::say("Connect failed: " + result)
159
- return false
160
- end
161
-
162
- cookies = __cookies(response['set-cookie'])
163
- arr = URI::split(response["Location"])
164
- np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 443)
165
- np.use_ssl = true
166
- np.verify_mode = OpenSSL::SSL::VERIFY_NONE
167
- result = ''
168
- response = nil
169
- # np.set_debug_output($stderr)
170
- np.start { |http|
171
- response = http.get(arr[5]+'?'+arr[7], {'Cookie' => cookies,'User-agent' => GM_USER_AGENT} )
172
- result = response.body
173
- }
174
-
175
- arr = URI::split(response["Location"])
176
- np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 443)
177
- np.use_ssl = true
178
- np.verify_mode = OpenSSL::SSL::VERIFY_NONE
179
- result = ''
180
- response = nil
181
- # np.set_debug_output($stderr)
182
- np.start { |http|
183
- response = http.get(arr[5]+'?'+arr[7], {'Cookie' => cookies,'User-agent' => GM_USER_AGENT} )
184
- result = response.body
185
- }
186
-
187
- @loc = response["Location"]
188
- cookies += ';' + __cookies(response['set-cookie'])
189
- np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 443)
190
- np.use_ssl = true
191
- np.verify_mode = OpenSSL::SSL::VERIFY_NONE
192
- # np.set_debug_output($stderr)
193
- np.start { |http|
194
- response = http.get(@loc, {'Cookie' => cookies,'User-agent' => GM_USER_AGENT} )
195
- result = response.body
196
- }
197
- cookies += ';' + __cookies(response['set-cookie'])
198
-
199
- @cookie_str = cookies + ";TZ=" + @timezone
200
-
201
- Debugger::say("Finished connecting without cookie.")
202
- return true
203
- end
204
-
205
- #
206
- # return bool
207
- # desc Connect to GMail with default session management settings.
208
- #
209
- def connect()
210
- connect_no_cookie()
211
- end
52
+ module GMailer
53
+ VERSION = "0.0.9"
54
+ attr_accessor :connection
55
+
56
+ # the main class.
57
+ class Connection
58
+ @cookie_str
59
+ @login
60
+ @pwd
61
+ @raw # raw packets
62
+ @contact_raw # raw packets for address book
63
+ @timezone
64
+ @created
65
+ @proxy_host
66
+ @proxy_port
67
+ @proxy_user
68
+ @proxy_pass
69
+
70
+ def encode(str)
71
+ return str if @charset.upcase == 'UTF-8'
72
+ begin
73
+ require 'Win32API'
74
+ str += "\0"
75
+ ostr = "\0" * str.length*2
76
+ multiByteToWideChar = Win32API.new('kernel32','MultiByteToWideChar',['L','L','P','L','P','L'],'L')
77
+ multiByteToWideChar.Call(0,0,str,-1,ostr,str.length*2)
78
+ (ostr.strip + "\0").unpack("S*").pack("U*")
79
+ rescue LoadError
80
+ require 'iconv'
81
+ Iconv::iconv('UTF-8',@charset,str)[0]
82
+ end
83
+ end
84
+
85
+ #
86
+ # return GMailer
87
+ # desc Constructor
88
+ #
89
+ def initialize(*param)
90
+ @login = ''
91
+ @pwd = ''
92
+ @raw = {}
93
+ @proxy_host = nil
94
+ @proxy_port = 0
95
+ @proxy_user = nil
96
+ @proxy_pass = nil
97
+ @proxy = false
98
+ @type = 0
99
+ if param.length==1 && param[0].class==Hash
100
+ param = param[0]
101
+ set_login_info(param[:username]||'',param[:password]||'')
102
+ @proxy_host = param[:proxy_host]
103
+ @proxy = !@proxy_host.nil?
104
+ @proxy_port = param[:proxy_port] || 80
105
+ @proxy_user = param[:proxy_user]
106
+ @proxy_pass = param[:proxy_pass]
107
+ @charset = param[:charset] || 'UTF-8'
108
+ elsif param.length==0
109
+ @charset = 'UTF-8'
110
+ elsif param.length==1
111
+ @charset = param[0]
112
+ elsif param.length==2
113
+ @charset = 'UTF-8'
114
+ set_login_info(param[0],param[1])
115
+ elsif param.length==3
116
+ @charset = param[2]
117
+ set_login_info(param[0],param[1])
118
+ else
119
+ raise ArgumentError, 'Invalid argument'
120
+ end
121
+ connect_no_cookie
122
+ end
123
+
124
+ #
125
+ # return void
126
+ # param string my_login
127
+ # param string my_pwd
128
+ # param int my_tz
129
+ # desc Set GMail login information.
130
+ #
131
+ def set_login_info(my_login, my_pwd, my_tz=0)
132
+ @login = my_login
133
+ @pwd = my_pwd
134
+ @timezone = (my_tz*-60).to_i.to_s
135
+ end
136
+
137
+ #
138
+ # return bool
139
+ # desc Connect to GMail without setting any session/cookie.
140
+ #
141
+ def connect_no_cookie()
142
+
143
+ postdata = "service=mail&Email=" + URI.escape(@login) + "&Passwd=" + URI.escape(@pwd) + "&null=Sign%20in&continue=" +
144
+ URI.escape('https://mail.google.com/mail/?ui=html&zy=l') + "&rm=false&PersistentCookie=yes"
145
+
146
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 443)
147
+ np.use_ssl = true
148
+ np.verify_mode = OpenSSL::SSL::VERIFY_NONE
149
+ result = ''
150
+ response = nil
151
+ # np.set_debug_output($stderr)
152
+ np.start { |http|
153
+ response = http.post(GM_LNK_LOGIN, postdata,{'User-agent' => GM_USER_AGENT} )
154
+ result = response.body
155
+ }
156
+
157
+ if result.include?("errormsg")
158
+ @cookie_str = ''
159
+ return false
160
+ end
161
+
162
+ cookies = __cookies(response['set-cookie'])
163
+ arr = URI::split(response["Location"])
164
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 443)
165
+ np.use_ssl = true
166
+ np.verify_mode = OpenSSL::SSL::VERIFY_NONE
167
+ result = ''
168
+ response = nil
169
+ # np.set_debug_output($stderr)
170
+ np.start { |http|
171
+ response = http.get(arr[5]+'?'+arr[7], {'Cookie' => cookies,'User-agent' => GM_USER_AGENT} )
172
+ result = response.body
173
+ }
174
+
175
+ arr = URI::split(response["Location"])
176
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 443)
177
+ np.use_ssl = true
178
+ np.verify_mode = OpenSSL::SSL::VERIFY_NONE
179
+ result = ''
180
+ response = nil
181
+ # np.set_debug_output($stderr)
182
+ np.start { |http|
183
+ response = http.get(arr[5]+'?'+arr[7], {'Cookie' => cookies,'User-agent' => GM_USER_AGENT} )
184
+ result = response.body
185
+ }
186
+
187
+ @loc = response["Location"]
188
+ cookies += ';' + __cookies(response['set-cookie'])
189
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 443)
190
+ np.use_ssl = true
191
+ np.verify_mode = OpenSSL::SSL::VERIFY_NONE
192
+ # np.set_debug_output($stderr)
193
+ np.start { |http|
194
+ response = http.get(@loc, {'Cookie' => cookies,'User-agent' => GM_USER_AGENT} )
195
+ result = response.body
196
+ }
197
+ cookies += ';' + __cookies(response['set-cookie'])
198
+
199
+ @cookie_str = cookies + ";TZ=" + @timezone
200
+
201
+ return true
202
+ end
203
+
204
+ #
205
+ # return bool
206
+ # desc Connect to GMail with default session management settings.
207
+ #
208
+ def connect()
209
+ connect_no_cookie()
210
+ end
211
+
212
+
213
+
214
+ #
215
+ # return bool
216
+ # desc See if it is connected to GMail.
217
+ #
218
+ def connected?
219
+ !@cookie_str.empty?
220
+ end
221
+
222
+ #
223
+ # return bool
224
+ # param string query
225
+ # desc Fetch contents by URL query.
226
+ #
227
+ def __fetch(query)
228
+ if connected?
229
+ query += "&zv=" + (rand(2000)*2147483.648).to_i.to_s
230
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
231
+ # np.set_debug_output($stderr)
232
+ inbox = ''
233
+ np.start { |http|
234
+ response = http.get(GM_LNK_GMAIL + "?" + query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
235
+ inbox = response.body
236
+ }
237
+ if @type == GM_SHOWORIGINAL
238
+ @raw = inbox
239
+ else
240
+ state = 0
241
+ tmp = ''
242
+ inbox.each do |l|
243
+ if /^D\(.*\);$/.match(l)
244
+ state = 0
245
+ tmp += l
246
+ elsif l[0,3]=='D(['
247
+ state = 1
248
+ tmp += l.chomp
249
+ elsif l[0,2]==');'
250
+ state = 2
251
+ tmp += ")\n"
252
+ elsif state == 1
253
+ tmp += l.chomp
254
+ end
255
+ end
256
+ inbox = tmp
257
+ matches = inbox.scan(/D\((.*)\)/).flatten
258
+ packets = {}
259
+ matches.each {|x|
260
+ tmp = eval(x.gsub(",,",",'',").gsub(",,",",'',").gsub(",]",",'']").gsub('#{','#\{'))
261
+ if (packets[tmp[0]] || (tmp[0]=="mi"||tmp[0]=="mb"||tmp[0]=="di"))
262
+ if (tmp[0]=="t"||tmp[0]=="ts"||tmp[0]=="a"||tmp[0]=="cl")
263
+ packets[tmp[0]] += tmp[1..-1]
264
+ end
265
+ if (tmp[0]=="mi"||tmp[0]=="mb"||tmp[0]=="di")
266
+ if !packets["mg"].nil?
267
+ packets["mg"].push(tmp)
268
+ else
269
+ packets["mg"] = [tmp]
270
+ end
271
+ end
272
+ else
273
+ packets[tmp[0]] = tmp
274
+ end
275
+ }
276
+ if packets["cl"] && packets["cl"].length > 1
277
+ packets["ce"] = []
278
+ for i in 1 .. packets["cl"].length-1
279
+ packets["ce"].push(packets["cl"][i])
280
+ end
281
+ end
282
+ @raw = packets
283
+ end
284
+
285
+ true
286
+ else # not logged in yet
287
+ false
288
+ end
289
+ end
290
+ private :__fetch
291
+
292
+ #
293
+ # return bool
294
+ # param constant type
295
+ # param mixed box
296
+ # param int pos
297
+ # desc Fetch contents from GMail by type.
298
+ #
299
+ def fetch_box(type, box, pos)
300
+ @type = type
301
+ if connected?
302
+ case type
303
+ when GM_STANDARD
304
+ q = "search=" + box.downcase + "&view=tl&start=" + pos.to_s
305
+
306
+ when GM_LABEL
307
+ q = "search=cat&cat=" + box.to_s + "&view=tl&start=" + pos.to_s
308
+
309
+ when GM_CONVERSATION
310
+ q = "search=inbox&ser=1&view=cv"
311
+ if (box.class==Array)
312
+ q += "&th=" + box[0].to_s
313
+ for i in 1 .. box.length
314
+ q += "&msgs=" + box[i].to_s
315
+ end
316
+ else
317
+ q += "&th=" + box.to_s
318
+ end
319
+
320
+ when GM_SHOWORIGINAL
321
+ q = "view=om&th=" + box.to_s
322
+
323
+ when GM_QUERY
324
+ q = "search=query&q=" + URI.escape(box.to_s) + "&view=tl&start=" + pos.to_s
325
+
326
+ when GM_PREFERENCE
327
+ q = "view=pr&pnl=g"
328
+
329
+ when GM_CONTACT
330
+ if box.downcase == "all"
331
+ q = "view=cl&search=contacts&pnl=a"
332
+ else
333
+ q = "view=cl&search=contacts&pnl=d"
334
+ end
335
+
336
+ else
337
+ q = "search=inbox&view=tl&start=0&init=1"
338
+ end
339
+
340
+ __fetch(q)
341
+ else
342
+ false
343
+ end
344
+ end
345
+
346
+ #
347
+ # return snapshot
348
+ # param constant type
349
+ # param mixed box
350
+ # param int pos
351
+ # desc Fetch contents from GMail by type.
352
+ #
353
+ def fetch(hash_param)
354
+ type = GM_STANDARD
355
+ box = "inbox"
356
+ pos = 0
357
+ @filter = {}
358
+ hash_param.keys.each do |k|
359
+ case k
360
+ when :label
361
+ type = GM_LABEL
362
+ box = hash_param[k]
363
+ when :standard
364
+ type = GM_STANDARD
365
+ box = hash_param[k]
366
+ when :conversation
367
+ type = GM_CONVERSATION
368
+ box = hash_param[k]
369
+ when :show_original
370
+ type = GM_SHOWORIGINAL
371
+ box = hash_param[k]
372
+ when :preference
373
+ type = GM_PREFERENCE
374
+ box = hash_param[k]
375
+ when :contact
376
+ type = GM_CONTACT
377
+ box = hash_param[k]
378
+ when :query
379
+ type = GM_QUERY
380
+ box = hash_param[k]
381
+ when :pos
382
+ pos = hash_param[k].to_i
383
+ when :read
384
+ @filter[:read] = hash_param[k]
385
+ when :star
386
+ @filter[:star] = hash_param[k]
387
+ else
388
+ raise ArgumentError, 'Invalid hash argument'
389
+ end
390
+ end
391
+ box = "inbox" unless box
392
+ fetch_box(type,box,pos)
393
+ if type == GM_SHOWORIGINAL
394
+ snapshot = @raw
395
+ else
396
+ snapshot = snapshot(type)
397
+ end
398
+ if block_given?
399
+ yield(snapshot)
400
+ elsif type == GM_CONTACT
401
+ snapshot.contacts
402
+ else
403
+ snapshot
404
+ end
405
+ end
406
+
407
+ #
408
+ # return string[]
409
+ # param string[] convs
410
+ # param string path
411
+ # desc Save all attaching files of conversations to a path.
412
+ #
413
+ def attachments_of(convs, path)
414
+
415
+ if connected?
416
+ if (convs.class != Array)
417
+ convs = [convs] # array wrapper
418
+ end
419
+ final = []
420
+ convs.each { |v|
421
+ if v["attachment"]
422
+ v["attachment"].each { |vv|
423
+ f = path+"/"+vv["filename"]
424
+ f = path+"/"+vv["filename"]+"."+rand(2000).to_s while (FileTest.exist?(f))
425
+ if attachment(vv["id"],v["id"],f,false)
426
+ final.push(f)
427
+ end
428
+ }
429
+ end
430
+ }
431
+ final
432
+ else
433
+ nil
434
+ end
435
+ end
436
+
437
+ #
438
+ # return string[]
439
+ # param string[] convs
440
+ # param string path
441
+ # desc Save all attaching files of conversations to a path.
442
+ #
443
+ def zip_attachments_of(convs, path)
444
+
445
+ if connected?
446
+ if (convs.class != Array)
447
+ convs = [convs] # array wrapper
448
+ end
449
+ final = []
450
+ convs.each {|v|
451
+ if v["attachment"]
452
+ f = path+"/attachment.zip"
453
+ f = path+"/attachment."+rand(2000).to_s+".zip" while (FileTest.exist?(f))
454
+ if attachment(v["attachment"][0]["id"],v["id"],f,true)
455
+ final.push(f)
456
+ end
457
+ end
458
+ }
459
+ final
460
+ else
461
+ nil
462
+ end
463
+ end
464
+
465
+ #
466
+ # return bool
467
+ # param string attid
468
+ # param string msgid
469
+ # param string filename
470
+ # desc Save attachment with attachment ID attid and message ID msgid to file with name filename.
471
+ #
472
+ def attachment(attid, msgid, filename, zipped=false)
473
+
474
+ if connected?
475
+
476
+ if !zipped
477
+ query = GM_LNK_ATTACHMENT + "&attid=" + URI.escape(attid) + "&th=" + URI.escape(msgid)
478
+ else
479
+ query = GM_LNK_ATTACHMENT_ZIPPED + "&th=" + URI.escape(msgid)
480
+ end
481
+
482
+ File.open(filename,"wb") { |f|
483
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
484
+ np.start { |http|
485
+ response = http.get(query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
486
+ f.write(response.body)
487
+ }
488
+ }
489
+ true
490
+ else
491
+ false
492
+ end
493
+ end
494
+
495
+ #
496
+ # return array of labels
497
+ # desc get label lists
498
+ #
499
+ def labels()
500
+ if connected?
501
+ fetch(:standard=>"inbox") {|s| s.label_list }
502
+ else
503
+ nil
504
+ end
505
+ end
506
+
507
+ #
508
+ # return string
509
+ # param string label
510
+ # desc validate label
511
+ #
512
+ def validate_label(label)
513
+ label.strip!
514
+ if label==''
515
+ raise ArgumentError, 'Error: Labels cannot empty string'
516
+ end
517
+ if label.length > 40
518
+ raise ArgumentError, 'Error: Labels cannot contain more than 40 characters'
519
+ end
520
+ if label.include?('^')
521
+ raise ArgumentError, "Error: Labels cannot contain the character '^'"
522
+ end
523
+ label
524
+ end
525
+
526
+ #
527
+ # return boolean
528
+ # param string label
529
+ # desc create label
530
+ #
531
+ def create_label(label)
532
+ if connected?
533
+ perform_action(GM_ACT_CREATELABEL, '', validate_label(label))
534
+ else
535
+ false
536
+ end
537
+ end
538
+
539
+ #
540
+ # return boolean
541
+ # param string label
542
+ # desc create label
543
+ #
544
+ def delete_label(label)
545
+ if connected?
546
+ perform_action(GM_ACT_DELETELABEL, '', validate_label(label))
547
+ else
548
+ false
549
+ end
550
+ end
551
+
552
+ #
553
+ # return boolean
554
+ # param string old_label
555
+ # param string new_label
556
+ # desc create label
557
+ #
558
+ def rename_label(old_label,new_label)
559
+ if connected?
560
+ perform_action(GM_ACT_RENAMELABEL, '',
561
+ validate_label(old_label) +'^' + validate_label(new_label))
562
+ else
563
+ false
564
+ end
565
+ end
566
+
567
+ #
568
+ # return boolean
569
+ # param string msgid
570
+ # param string label
571
+ # desc apply label to message
572
+ #
573
+ def apply_label(id,label)
574
+ if connected?
575
+ perform_action(GM_ACT_APPLYLABEL, id, validate_label(label))
576
+ else
577
+ false
578
+ end
579
+ end
580
+
581
+ #
582
+ # return boolean
583
+ # param string msgid
584
+ # param string label
585
+ # desc remove label from message
586
+ #
587
+ def remove_label(id,label)
588
+ if connected?
589
+ perform_action(GM_ACT_REMOVELABEL, id, validate_label(label))
590
+ else
591
+ false
592
+ end
593
+ end
594
+
595
+ #
596
+ # return boolean
597
+ # param string hash_param
598
+ # desc remove label from message
599
+ #
600
+ def update_preference(hash_param)
601
+ if connected?
602
+ args = {}
603
+ hash_param.keys.each do |k|
604
+ case k
605
+ when :max_page_size
606
+ args['p_ix_nt'] = hash_param[k]
607
+ when :keyboard_shortcuts
608
+ args['p_bx_hs'] = hash_param[k] ? '1' : '0'
609
+ when :indicators
610
+ args['p_bx_sc'] = hash_param[k] ? '1' : '0'
611
+ when :display_language
612
+ args['p_sx_dl'] = hash_param[k]
613
+ when :signature
614
+ args['p_sx_sg'] = hash_param[k]
615
+ when :reply_to
616
+ args['p_sx_rt'] = hash_param[k]
617
+ when :snippets
618
+ args['p_bx_ns'] = hash_param[k] ? '0' : '1'
619
+ when :display_name
620
+ args['p_sx_dn'] = hash_param[k]
621
+ end
622
+ end
623
+ param = '&' + args.to_a.map {|x| x.join('=')}.join('&')
624
+ perform_action(GM_ACT_PREFERENCE,'', param)
625
+ else
626
+ false
627
+ end
628
+ end
629
+
630
+ #
631
+ # return boolean
632
+ # param string msgid
633
+ # desc apply star to a message
634
+ #
635
+ def apply_star(msgid)
636
+ if connected?
637
+ perform_action(GM_ACT_STAR,msgid, '')
638
+ else
639
+ false
640
+ end
641
+ end
642
+
643
+ #
644
+ # return boolean
645
+ # param string msgid
646
+ # desc remove star from a message
647
+ #
648
+ def remove_star(msgid)
649
+ if connected?
650
+ perform_action(GM_ACT_UNSTAR,msgid, '')
651
+ else
652
+ false
653
+ end
654
+ end
655
+
656
+ #
657
+ # return boolean
658
+ # param string msgid
659
+ # desc report a message as spam
660
+ #
661
+ def report_spam(msgid)
662
+ if connected?
663
+ perform_action(GM_ACT_SPAM,msgid, '')
664
+ else
665
+ false
666
+ end
667
+ end
668
+
669
+ #
670
+ # return boolean
671
+ # param string msgid
672
+ # desc report a message as not spam
673
+ #
674
+ def report_not_spam(msgid)
675
+ if connected?
676
+ perform_action(GM_ACT_UNSPAM,msgid, '')
677
+ else
678
+ false
679
+ end
680
+ end
681
+
682
+ #
683
+ # return boolean
684
+ # param string msgid
685
+ # desc delete a spam message forever
686
+ #
687
+ def delete_spam(msgid)
688
+ if connected?
689
+ perform_action(GM_ACT_DELSPAM,msgid, '')
690
+ else
691
+ false
692
+ end
693
+ end
694
+
695
+ #
696
+ # return boolean
697
+ # param string msgid
698
+ # desc mark a message as read
699
+ #
700
+ def mark_read(msgid)
701
+ if connected?
702
+ perform_action(GM_ACT_READ,msgid, '')
703
+ else
704
+ false
705
+ end
706
+ end
707
+
708
+ #
709
+ # return boolean
710
+ # param string msgid
711
+ # desc mark a message as unread
712
+ #
713
+ def mark_unread(msgid)
714
+ if connected?
715
+ perform_action(GM_ACT_UNREAD,msgid, '')
716
+ else
717
+ false
718
+ end
719
+ end
720
+
721
+ #
722
+ # return original message string
723
+ # param string msgid
724
+ # desc show original message format
725
+ #
726
+ def show_original(msgid)
727
+ if connected?
728
+ fetch(:show_original=>msgid)
729
+ else
730
+ false
731
+ end
732
+ end
733
+
734
+ #
735
+ # return boolean
736
+ # param string msgid
737
+ # desc move a message to trash
738
+ #
739
+ def trash(msgid)
740
+ if connected?
741
+ perform_action(GM_ACT_TRASH,msgid, '')
742
+ else
743
+ false
744
+ end
745
+ end
746
+
747
+ #
748
+ # return boolean
749
+ # param string msgid
750
+ # desc move a message from trash to inbox
751
+ #
752
+ def untrash(msgid)
753
+ if connected?
754
+ perform_action(GM_ACT_UNTRASH,msgid, '')
755
+ else
756
+ false
757
+ end
758
+ end
759
+
760
+ #
761
+ # return boolean
762
+ # param string msgid
763
+ # desc delete a trash message forever
764
+ #
765
+ def delete_trash(msgid)
766
+ if connected?
767
+ perform_action(GM_ACT_DELTRASH,msgid, '')
768
+ else
769
+ false
770
+ end
771
+ end
772
+
773
+ #
774
+ # return boolean
775
+ # param string msgid
776
+ # desc delete a message forever
777
+ #
778
+ def delete_message(msgid)
779
+ if connected?
780
+ perform_action(GM_ACT_DELFOREVER,msgid, '')
781
+ else
782
+ false
783
+ end
784
+ end
785
+
786
+ #
787
+ # return boolean
788
+ # param string msgid
789
+ # desc archive a message
790
+ #
791
+ def archive(msgid)
792
+ if connected?
793
+ perform_action(GM_ACT_ARCHIVE,msgid, '')
794
+ else
795
+ false
796
+ end
797
+ end
798
+
799
+ #
800
+ # return boolean
801
+ # param string msgid
802
+ # desc archive a message
803
+ #
804
+ def unarchive(msgid)
805
+ if connected?
806
+ perform_action(GM_ACT_INBOX,msgid, '')
807
+ else
808
+ false
809
+ end
810
+ end
811
+
812
+
813
+ #
814
+ # return hash of preference
815
+ # desc get preferences
816
+ #
817
+ def preference()
818
+ if connected?
819
+ fetch(:preference=>"all").preference
820
+ else
821
+ nil
822
+ end
823
+ end
824
+
825
+ #
826
+ # return array of messages
827
+ # desc get message lists
828
+ #
829
+ def messages(hash_param)
830
+ if connected?
831
+ ml = fetch(hash_param).message_list
832
+ @filter.keys.each do |k|
833
+ case k
834
+ when :read
835
+ ml.box = ml.box.find_all { |x| x['read?'] == @filter[k] }
836
+ when :star
837
+ ml.box = ml.box.find_all { |x| x['star?'] == @filter[k] }
838
+ end
839
+ end
840
+ ml.connection = self
841
+ if block_given?
842
+ yield(ml)
843
+ else
844
+ ml
845
+ end
846
+ else
847
+ nil
848
+ end
849
+ end
850
+
851
+ #
852
+ # return string
853
+ # param string query
854
+ # desc Dump everything to output.
855
+ #
856
+ def dump(query)
857
+ page = ''
858
+ if connected?
859
+ query += "&zv=" + (rand(2000)*2147483.648).to_i.to_s
860
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
861
+ np.start { |http|
862
+ response = http.get(GM_LNK_GMAIL + "?"+query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
863
+ page = response.body
864
+ }
865
+ else # not logged in yet
866
+
867
+ end
868
+ page
869
+ end
870
+
871
+ def stripslashes(string)
872
+ encode(string.gsub("\\\"", "\"").gsub("\\'", "'").gsub("\\\\", "\\"))
873
+ end
874
+
875
+
876
+ #
877
+ # return bool
878
+ # param string to
879
+ # param string subject
880
+ # param string body
881
+ # param string cc
882
+ # param string bcc
883
+ # param string msg_id
884
+ # param string thread_id
885
+ # param string[] files
886
+ # desc Send GMail.
887
+ #
888
+ def send(*param)
889
+ if param.length==1 && param[0].class==Hash
890
+ param = param[0]
891
+ from = param[:from] || ''
892
+ to = param[:to] || ''
893
+ subject = param[:subject] || ''
894
+ body = param[:body] || ''
895
+ cc = param[:cc] || ''
896
+ bcc = param[:bcc] || ''
897
+ msg_id = param[:msg_id] || ''
898
+ thread_id = param[:msg_id] || ''
899
+ files = param[:files] || []
900
+ draft = param[:draft] || false
901
+ draft_id = param[:draft_id] || ''
902
+ elsif param.length==10
903
+ to, subject, body, cc, bcc, msg_id, thread_id, files, draft, draft_id = param
904
+ elsif param.length==11
905
+ from, to, subject, body, cc, bcc, msg_id, thread_id, files, draft, draft_id = param
906
+ else
907
+ raise ArgumentError, 'Invalid argument'
908
+ end
909
+
910
+ if connected?
911
+ other_emails = fetch(:preference=>"all").other_emails
912
+ if other_emails.length>0
913
+ other_emails.each {|v|
914
+ from = v['email'] if from=='' && v['default']
915
+ }
916
+ from = @login + 'gmail.com' if from==''
917
+ else
918
+ from = nil
919
+ end
920
+
921
+ postdata = {}
922
+ if draft
923
+ postdata["view"] = "sd"
924
+ postdata["draft"] = draft_id
925
+ postdata["rm"] = msg_id
926
+ postdata["th"] = thread_id
927
+ else
928
+ postdata["view"] = "sm"
929
+ postdata["draft"] = draft_id
930
+ postdata["rm"] = msg_id
931
+ postdata["th"] = thread_id
932
+ end
933
+ postdata["msgbody"] = stripslashes(body)
934
+ postdata["from"] = stripslashes(from) if from
935
+ postdata["to"] = stripslashes(to)
936
+ postdata["subject"] = stripslashes(subject)
937
+ postdata["cc"] = stripslashes(cc)
938
+ postdata["bcc"] = stripslashes(bcc)
939
+
940
+ postdata["cmid"] = 1
941
+ postdata["ishtml"] = 0
942
+
943
+ cc = @cookie_str.split(';')
944
+ cc.each {|cc_part|
945
+ cc_parts = cc_part.split('=')
946
+ if(cc_parts[0]=='GMAIL_AT')
947
+ postdata["at"] = cc_parts[1]
948
+ break
949
+ end
950
+ }
951
+
952
+ boundary = "----#{Time.now.to_i}#{(rand(2000)*2147483.648).to_i}"
953
+ postdata2 = []
954
+ postdata.each {|k,v|
955
+ postdata2.push("Content-Disposition: form-data; name=\"#{k}\"\r\n\r\n#{v}\r\n")
956
+ }
957
+
958
+ files.each_with_index {|f,i|
959
+ content = File.open(f,'rb') { |c| c.read }
960
+ postdata2.push("Content-Disposition: form-data; name=\"file#{i}\"; filename=\"#{File.basename(f)}\"\r\n" +
961
+ "Content-Transfer-Encoding: binary\r\n" +
962
+ "Content-Type: application/octet-stream\r\n\r\n" + content + "\r\n")
963
+ }
964
+
965
+ postdata = postdata2.collect { |p|
966
+ "--" + boundary + "\r\n" + p
967
+ }.join('') + "--" + boundary + "--\r\n"
968
+
969
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
970
+ response = nil
971
+ # np.set_debug_output($stderr)
972
+ np.start { |http|
973
+ response = http.post(GM_LNK_GMAIL, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT,'Content-type' => 'multipart/form-data; boundary=' + boundary } )
974
+ }
975
+ true
976
+ else
977
+ false
978
+ end
979
+
980
+ end
981
+
982
+ #
983
+ # return bool
984
+ # param constant act
985
+ # param string[] id
986
+ # param string para
987
+ # desc Perform action on messages.
988
+ #
989
+ def perform_action(act, id, para)
990
+
991
+ if connected?
992
+
993
+ if (act == GM_ACT_DELFOREVER)
994
+ perform_action(GM_ACT_TRASH, id, 0) # trash it before
995
+ end
996
+ postdata = "act="
997
+
998
+ action_codes = ["ib", "cc_", "dc_", "nc_", "ac_", "rc_", "prefs", "st", "xst",
999
+ "sp", "us", "rd", "ur", "tr", "dl", "rc_^i", "ib", "ib", "dd", "dm", "dl", "dl"]
1000
+ postdata += action_codes[act] ? action_codes[act] : action_codes[GM_ACT_INBOX]
1001
+ if act == GM_ACT_RENAMELABEL then
1002
+ paras = para.split('^')
1003
+ para = validate_label(paras[0])+'^'+validate_label(paras[1])
1004
+ elsif ([GM_ACT_APPLYLABEL,GM_ACT_REMOVELABEL,GM_ACT_CREATELABEL,
1005
+ GM_ACT_DELETELABEL,].include?(act))
1006
+ para = validate_label(para)
1007
+ end
1008
+ if ([GM_ACT_APPLYLABEL,GM_ACT_REMOVELABEL,GM_ACT_CREATELABEL,
1009
+ GM_ACT_DELETELABEL,GM_ACT_RENAMELABEL,GM_ACT_PREFERENCE].include?(act))
1010
+ postdata += para.to_s
1011
+ end
1012
+
1013
+ cc = @cookie_str.split(';')
1014
+ cc.each {|cc_part|
1015
+ cc_parts = cc_part.split('=')
1016
+ if(cc_parts[0]=='GMAIL_AT')
1017
+ postdata += "&at=" + cc_parts[1]
1018
+ break
1019
+ end
1020
+ }
1021
+
1022
+ if (act == GM_ACT_TRASHMSG)
1023
+ postdata += "&m=" + id.to_s
1024
+ else
1025
+ if id.class==Array
1026
+ id.each {|t| postdata += "&t="+t.to_s }
1027
+ else
1028
+ postdata += "&t="+id.to_s
1029
+ end
1030
+ end
1031
+ postdata += "&vp="
1032
+
1033
+ if [GM_ACT_UNTRASH,GM_ACT_DELFOREVER,GM_ACT_DELTRASH].include?(act)
1034
+ link = GM_LNK_GMAIL+"?search=trash&view=tl&start=0"
1035
+ elsif (act == GM_ACT_DELSPAM)
1036
+ link = GM_LNK_GMAIL+"?search=spam&view=tl&start=0"
1037
+ else
1038
+ link = GM_LNK_GMAIL+"?search=query&q=&view=tl&start=0"
1039
+ end
1040
+
1041
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
1042
+ # np.set_debug_output($stderr)
1043
+ np.start { |http|
1044
+ response = http.post(link, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
1045
+ result = response.body
1046
+ }
1047
+
1048
+ return true
1049
+ else
1050
+ return false
1051
+ end
1052
+
1053
+ end
1054
+
1055
+ #
1056
+ # return void
1057
+ # desc Disconnect from GMail.
1058
+ #
1059
+ def disconnect()
1060
+
1061
+ response = nil
1062
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
1063
+ # np.set_debug_output($stderr)
1064
+ np.start { |http|
1065
+ response = http.get(GM_LNK_LOGOUT,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
1066
+ }
1067
+ arr = URI::split(response["Location"])
1068
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 80)
1069
+ # np.set_debug_output($stderr)
1070
+ np.start { |http|
1071
+ response = http.get(arr[5]+'?'+arr[7], {'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
1072
+ }
1073
+
1074
+ @cookie_str = ''
1075
+ end
1076
+
1077
+ #
1078
+ # return GMailSnapshot
1079
+ # param constant type
1080
+ # desc Get GMSnapshot by type.
1081
+ #
1082
+ def snapshot(type)
1083
+ if [GM_STANDARD,GM_LABEL,GM_CONVERSATION,GM_QUERY,GM_PREFERENCE,GM_CONTACT].include?(type)
1084
+ return GMailSnapshot.new(type, @raw, @charset)
1085
+ else
1086
+ return GMailSnapshot.new(GM_STANDARD, @raw, @charset) # assuming normal by default
1087
+ end
1088
+ end
1089
+
1090
+ def snap(type)
1091
+ action = GM_STANDARD
1092
+ case type
1093
+ when :standard
1094
+ action = GM_STANDARD
1095
+ when :label
1096
+ action = GM_LABEL
1097
+ when :conversation
1098
+ action = GM_CONVERSATION
1099
+ when :query
1100
+ action = GM_QUERY
1101
+ when :preference
1102
+ action = GM_PREFERENCE
1103
+ when :contact
1104
+ action = GM_CONTACT
1105
+ else
1106
+ raise ArgumentError, 'Invalid type'
1107
+ end
1108
+ snapshot(action)
1109
+ end
1110
+
1111
+ #
1112
+ # return bool
1113
+ # param string email
1114
+ # desc Send Gmail invite to email
1115
+ #
1116
+ def invite(email)
1117
+
1118
+ if connected?
1119
+
1120
+ postdata = "act=ii&em=" + URI.escape(email)
1121
+
1122
+ cc = @cookie_str.split(';')
1123
+ cc.each {|cc_part|
1124
+ cc_parts = cc_part.split('=')
1125
+ if(cc_parts[0]=='GMAIL_AT')
1126
+ postdata += "&at=" + cc_parts[1]
1127
+ break
1128
+ end
1129
+ }
1130
+
1131
+ link = GM_LNK_GMAIL + "?view=ii"
1132
+
1133
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
1134
+ np.use_ssl = true
1135
+ np.verify_mode = OpenSSL::SSL::VERIFY_NONE
1136
+ # np.set_debug_output($stderr)
1137
+ np.start { |http|
1138
+ response = http.post(link, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
1139
+ }
1140
+
1141
+ true
1142
+ else
1143
+ false
1144
+ end
1145
+
1146
+ end
1147
+
1148
+ #
1149
+ # return string[]
1150
+ # desc (Static) Get names of standard boxes.
1151
+ #
1152
+ def standard_box()
1153
+ ["Inbox","Starred","Sent","Drafts","All","Spam","Trash"]
1154
+ end
1155
+
1156
+ #
1157
+ # return string
1158
+ # param string header
1159
+ # desc (Static Private) Extract cookies from header.
1160
+ #
1161
+ def __cookies(header)
1162
+ return '' unless header
1163
+ arr = []
1164
+ header.split(', ').each { |x|
1165
+ if x.include?('GMT')
1166
+ arr[-1] += ", " + x
1167
+ else
1168
+ arr.push x
1169
+ end
1170
+ }
1171
+ arr.delete_if {|x| x.include?('LSID=EXPIRED') }
1172
+ arr.map! {|x| x.split(';')[0]}
1173
+ arr.join(';')
1174
+ end
1175
+
1176
+ end
1177
+
1178
+
1179
+ class GMailSnapshot
1180
+
1181
+ GM_STANDARD = 0x001
1182
+ GM_LABEL = 0x002
1183
+ GM_CONVERSATION = 0x004
1184
+ GM_QUERY = 0x008
1185
+ GM_CONTACT = 0x010
1186
+ GM_PREFERENCE = 0x020
1187
+
1188
+ def decode(str)
1189
+ return str if @charset.upcase == 'UTF-8'
1190
+ begin
1191
+ require 'Win32API'
1192
+ str = str.unpack("U*").pack("S*") + "\0"
1193
+ ostr = "\0" * str.length*2
1194
+ wideCharToMultiByte = Win32API.new('kernel32','WideCharToMultiByte',['L','L','P','L','P','L','L','L'],'L')
1195
+ wideCharToMultiByte.Call(0,0,str,-1,ostr,str.length*2,0,0)
1196
+ ostr.strip
1197
+ rescue LoadError
1198
+ require 'iconv'
1199
+ Iconv::iconv(@charset,'UTF-8',str)[0]
1200
+ end
1201
+ end
1202
+
1203
+ def strip_tags(str,allowable_tags='')
1204
+ str.gsub(/<[^>]*>/, '')
1205
+ end
1206
+
1207
+ #
1208
+ # return GMailSnapshot
1209
+ # param constant type
1210
+ # param array raw
1211
+ # desc Constructor.
1212
+ #
1213
+ attr_reader :gmail_ver, :quota_mb, :quota_per, :preference
1214
+ attr_reader :std_box_new, :have_invit, :label_list, :label_new
1215
+ attr_reader :message_list
1216
+ attr_reader :message
1217
+ attr_reader :contacts, :other_emails
1218
+
1219
+ def initialize(type, raw, charset='UTF-8')
1220
+ @charset = charset
1221
+ if (raw.class!=Hash)
1222
+ @created = 0
1223
+ return nil
1224
+ elsif (raw.empty?)
1225
+ @created = 0
1226
+ return nil
1227
+ end
1228
+ if [GM_STANDARD,GM_LABEL,GM_CONVERSATION,GM_QUERY].include?(type)
1229
+ @gmail_ver = raw["v"][1]
1230
+ if raw["qu"]
1231
+ @quota_mb = raw["qu"][1]
1232
+ @quota_per = raw["qu"][3]
1233
+ end
1234
+ if (raw["ds"].class!=Array)
1235
+ @created = 0
1236
+ return nil
1237
+ end
1238
+ @std_box_new = raw["ds"][1..-1]
1239
+ #if (isset(raw["p"])) {
1240
+ # @owner = raw["p"][5][1]
1241
+ # @owner_email = raw["p"][6][1]
1242
+ #end
1243
+ @have_invit = raw["i"][1]
1244
+ @label_list = []
1245
+ @label_new = []
1246
+ raw["ct"][1].each {|v|
1247
+ @label_list.push(v[0])
1248
+ @label_new.push(v[1])
1249
+ }
1250
+ if raw["ts"]
1251
+ @view = (GM_STANDARD|GM_LABEL|GM_QUERY)
1252
+ @message_list = MessageList.new(raw["ts"][5],raw["ts"][3],raw["ts"][1])
1253
+ end
1254
+ @box = []
1255
+ if raw["t"]
1256
+ raw["t"].each {|t|
1257
+ if (t != "t")
1258
+ b = {
1259
+ "id"=>t[0],
1260
+ "is_read"=>(t[1] != 1 ? 1 : 0),
1261
+ "read?"=>(t[1] != 1),
1262
+ "new?"=>(t[1] == 1),
1263
+ "is_starred"=>(t[2] == 1 ? 1 : 0),
1264
+ "star?"=>(t[2] == 1),
1265
+ "date"=>decode(strip_tags(t[3])),
1266
+ "sender"=>decode(strip_tags(t[4])),
1267
+ "flag"=>t[5],
1268
+ "subject"=>decode(strip_tags(t[6])),
1269
+ "snippet"=>decode(t[7].gsub('&quot;','"').gsub('&hellip;','...')),
1270
+ "labels"=>t[8].empty? ? [] : t[8].map{|tt|decode(tt)},
1271
+ "attachment"=>t[9].empty? ? []: decode(t[9]).split(","),
1272
+ "msgid"=>t[10]
1273
+ }
1274
+ @box.push(b)
1275
+ end
1276
+ }
1277
+ end
1278
+
1279
+ if (!raw["cs"].nil?)
1280
+ @view = GM_CONVERSATION
1281
+ @conv_title = raw["cs"][2]
1282
+ @conv_total = raw["cs"][8]
1283
+ @conv_id = raw["cs"][1]
1284
+ @conv_labels = raw["cs"][5].empty? ? '' : raw["cs"][5]
1285
+ if !@conv_labels.empty?
1286
+ ij = @conv_labels.index("^i")
1287
+ if !ij.nil?
1288
+ @conv_labels[ij] = "Inbox"
1289
+ end
1290
+ ij = @conv_labels.index("^s")
1291
+ if !ij.nil?
1292
+ @conv_labels[ij] = "Spam"
1293
+ end
1294
+ ij = @conv_labels.index("^k")
1295
+ if !ij.nil?
1296
+ @conv_labels[ij] = "Trash"
1297
+ end
1298
+ ij = @conv_labels.index("^t")
1299
+ if !ij.nil?
1300
+ @conv_labels[ij] = '' # Starred
1301
+ end
1302
+ ij = @conv_labels.index("^r")
1303
+ if !ij.nil?
1304
+ @conv_labels[ij] = "Drafts"
1305
+ end
1306
+ end
1307
+
1308
+ @conv_starred = false
1309
+
1310
+ @conv = []
1311
+ b = {}
1312
+ raw["mg"].each {|r|
1313
+ if (r[0] == "mb")
1314
+ b["body"] = '' if b["body"].nil?
1315
+ b["body"] += r[1]
1316
+ if (r[2] == 0)
1317
+ b["body"] = decode(b["body"])
1318
+ @conv.push(b)
1319
+ b = {}
1320
+ end
1321
+ elsif (r[0] == "mi")
1322
+ if !b.empty?
1323
+ @conv.push(b)
1324
+ b = {}
1325
+ end
1326
+ b = {}
1327
+ b["index"] = r[2]
1328
+ b["id"] = r[3]
1329
+ b["is_star"] = r[4]
1330
+ if (b["is_star"] == 1)
1331
+ @conv_starred = true
1332
+ end
1333
+ b["sender"] = decode(r[6])
1334
+ b["sender_email"] = r[8].gsub("\"",'') # remove annoying d-quotes in address
1335
+ b["recv"] = r[9]
1336
+ b["recv_email"] = r[11].to_s.gsub("\"",'')
1337
+ b["reply_email"] = r[14].to_s.gsub("\"",'')
1338
+ b["dt_easy"] = r[10]
1339
+ b["dt"] = r[15]
1340
+ b["subject"] = decode(r[16])
1341
+ b["snippet"] = decode(r[17])
1342
+ b["attachment"] = []
1343
+ r[18].each {|bb|
1344
+ b["attachment"].push({"id"=>bb[0],"filename"=>bb[1],"type"=>bb[2],"size"=>bb[3]})
1345
+ }
1346
+ b["is_draft"] = false
1347
+ b["body"] = ''
1348
+ elsif (r[0] == "di")
1349
+ if !b.empty?
1350
+ @conv.push(b)
1351
+ b = {}
1352
+ end
1353
+ b = {}
1354
+ b["index"] = r[2]
1355
+ b["id"] = r[3]
1356
+ b["is_star"] = r[4]
1357
+ @conv_starred = (b["is_star"] == 1)
1358
+ b["sender"] = decode(r[6])
1359
+ b["sender_email"] = r[8].gsub("\"",'') # remove annoying d-quotes in address
1360
+ b["recv"] = r[9]
1361
+ b["recv_email"] = r[11].gsub("\"",'')
1362
+ b["reply_email"] = r[14].gsub("\"",'')
1363
+ b["cc_email"] = r[12].gsub("\"",'')
1364
+ b["bcc_email"] = r[13].gsub("\"",'')
1365
+ b["dt_easy"] = r[10]
1366
+ b["dt"] = r[15]
1367
+ b["subject"] = decode(r[16])
1368
+ b["snippet"] = decode(r[17])
1369
+ b["attachment"] = []
1370
+ r[18].each {|bb|
1371
+ b["attachment"].push({"id"=>bb[0],"filename"=>bb[1],"type"=>bb[2],"size"=>bb[3]})
1372
+ }
1373
+ b["is_draft"] = true
1374
+ b["draft_parent"] = r[5]
1375
+ b["body"] = decode(r[20])
1376
+ end
1377
+ }
1378
+ @conv.push(b) unless b.empty?
1379
+ @message = Message.new(@conv_tile,@conv_total,@conv_id,@conv_labels,@conv_starred)
1380
+ @message.conv = @conv
1381
+ end
1382
+ elsif type == GM_CONTACT
1383
+ @contacts = []
1384
+ if raw["ce"]
1385
+ raw["ce"].each {|a|
1386
+ b = {
1387
+ "name"=>a[2],
1388
+ "email"=>a[4].gsub("\"",'')
1389
+ }
1390
+ if !a[5].empty?
1391
+ b["notes"] = a[5]
1392
+ end
1393
+ @contacts.push(b)
1394
+ }
1395
+ end
1396
+ @view = GM_CONTACT
1397
+ elsif type == GM_PREFERENCE
1398
+ prefs = {}
1399
+ raw["p"].each_with_index { |v,i|
1400
+ prefs[v[0]] = v[1] if i>0
1401
+ }
1402
+ @preference = {'max_page_size'=>'10',
1403
+ 'keyboard_shortcuts'=>false,
1404
+ 'indicators'=>false,
1405
+ 'display_language'=>'en',
1406
+ 'signature'=>'',
1407
+ 'reply_to'=>'',
1408
+ 'snippets'=>false,
1409
+ 'display_name'=>'',
1410
+ }
1411
+ prefs.each do |k,v|
1412
+ case k
1413
+ when 'ix_nt'
1414
+ @preference['max_page_size'] = v
1415
+ when 'bx_hs'
1416
+ @preference['keyboard_shortcuts'] = (v == '1')
1417
+ when 'bx_sc'
1418
+ @preference['indicators'] = (v == '1')
1419
+ when 'sx_dl'
1420
+ @preference['display_language'] = v
1421
+ when 'sx_sg'
1422
+ @preference['signature'] = (v == '0') ? '' : v
1423
+ when 'sx_rt'
1424
+ @preference['reply_to'] = v
1425
+ when 'bx_ns'
1426
+ @preference['snippets'] = (v == '0')
1427
+ when 'sx_dn'
1428
+ @preference['display_name'] = v
1429
+ end
1430
+ end
1431
+
1432
+ @label_list = []
1433
+ @label_total = []
1434
+ raw["cta"][1].each { |v|
1435
+ @label_list.push(v[0])
1436
+ @label_total.push(v[1])
1437
+ }
1438
+ @other_emails = []
1439
+ if raw["cfs"]
1440
+ raw["cfs"][1].each {|v|
1441
+ @other_emails.push({"name"=>decode(v[0]),"email"=>v[1],"default"=>(v[2]==1)})
1442
+ }
1443
+ end
1444
+ @filter = []
1445
+ @filter_rules = []
1446
+ raw["fi"][1].each { |fi|
1447
+ b = {
1448
+ "id" => fi[0],
1449
+ "query" => fi[1],
1450
+ "star" => fi[3],
1451
+ "label" => fi[4],
1452
+ "archive" => fi[5],
1453
+ "trash" => fi[6] #,"forward" => fi[7]
1454
+ }
1455
+ bb = {
1456
+ "from" => fi[2][0],
1457
+ "to" => fi[2][1],
1458
+ "subject" => fi[2][2],
1459
+ "has" => fi[2][3],
1460
+ "hasnot" => fi[2][4],
1461
+ "attach" => fi[2][5]
1462
+ }
1463
+
1464
+ @filter.push(b)
1465
+ @filter_rules.push(bb)
1466
+ }
1467
+ @view = GM_PREFERENCE
1468
+ else
1469
+ @created = 0
1470
+ return nil
1471
+ end
1472
+ @message_list.box = @box if @message_list
1473
+
1474
+ @created = 1
1475
+ end
1476
+
1477
+ end
1478
+
1479
+ # a list of messages.
1480
+ class MessageList
1481
+ attr_reader :name, :total, :pos
1482
+ attr_accessor :box, :connection
1483
+ def initialize(name,total,pos)
1484
+ @name = name
1485
+ @total = total
1486
+ @pos = pos
1487
+ end
1488
+
1489
+ def each(&block)
1490
+ @box.each do |b|
1491
+ m = connection.fetch(:conversation=>b['id']).message
1492
+ m.connection = @connection
1493
+ block.call(m)
1494
+ end
1495
+ end
1496
+
1497
+ def map(&block)
1498
+ @box.map do |b|
1499
+ m = connection.fetch(:conversation=>b['id']).message
1500
+ m.connection = @connection
1501
+ block.call(m)
1502
+ end
1503
+ end
1504
+
1505
+ end
1506
+
1507
+ # a single message
1508
+ class Message
1509
+ attr_reader :title, :total, :id, :labels, :starred
1510
+ attr_accessor :conv, :connection
1511
+ def initialize(title,total,id,labels,starred)
1512
+ @title = title
1513
+ @total = total
1514
+ @id = id
1515
+ @labels = labels
1516
+ @starred = starred
1517
+ end
1518
+
1519
+ def method_missing(methId)
1520
+ str = methId.id2name
1521
+ @conv[0][str]
1522
+ end
1523
+
1524
+ #
1525
+ # return boolean
1526
+ # param string label
1527
+ # desc apply label to message
1528
+ #
1529
+ def apply_label(label)
1530
+ @connection.perform_action(GM_ACT_APPLYLABEL, @id, label)
1531
+ end
1532
+
1533
+ #
1534
+ # return boolean
1535
+ # param string label
1536
+ # desc remove label from message
1537
+ #
1538
+ def remove_label(label)
1539
+ @connection.perform_action(GM_ACT_REMOVELABEL, @id, label)
1540
+ end
1541
+
1542
+ #
1543
+ # return boolean
1544
+ # desc apply star to a message
1545
+ #
1546
+ def apply_star()
1547
+ @connection.perform_action(GM_ACT_STAR,@id, '')
1548
+ end
1549
+
1550
+ #
1551
+ # return boolean
1552
+ # param string msgid
1553
+ # desc remove star from a message
1554
+ #
1555
+ def remove_star()
1556
+ @connection.perform_action(GM_ACT_UNSTAR,@id, '')
1557
+ end
1558
+
1559
+ #
1560
+ # return boolean
1561
+ # desc archive a message
1562
+ #
1563
+ def archive()
1564
+ @connection.perform_action(GM_ACT_ARCHIVE,@id, '')
1565
+ end
1566
+
1567
+ #
1568
+ # return boolean
1569
+ # param string msgid
1570
+ # desc archive a message
1571
+ #
1572
+ def unarchive()
1573
+ @connection.perform_action(GM_ACT_INBOX,@id, '')
1574
+ end
1575
+
1576
+ def archived?()
1577
+ end
1578
+
1579
+ #
1580
+ # return boolean
1581
+ # param string msgid
1582
+ # desc mark a message as read
1583
+ #
1584
+ def mark_read()
1585
+ @connection.perform_action(GM_ACT_READ,@id, '')
1586
+ end
1587
+
1588
+ #
1589
+ # return boolean
1590
+ # param string msgid
1591
+ # desc mark a message as unread
1592
+ #
1593
+ def mark_unread()
1594
+ @connection.perform_action(GM_ACT_UNREAD,@id, '')
1595
+ end
1596
+
1597
+ def read?()
1598
+ @conv[0]['read?']
1599
+ end
1600
+
1601
+ #
1602
+ # return boolean
1603
+ # param string msgid
1604
+ # desc report a message as spam
1605
+ #
1606
+ def report_spam()
1607
+ @connection.perform_action(GM_ACT_SPAM,@id, '')
1608
+ end
1609
+
1610
+ #
1611
+ # return boolean
1612
+ # param string msgid
1613
+ # desc report a message as not spam
1614
+ #
1615
+ def report_not_spam()
1616
+ @connection.perform_action(GM_ACT_UNSPAM,@id, '')
1617
+ end
1618
+
1619
+ #
1620
+ # return boolean
1621
+ # desc move a message to trash
1622
+ #
1623
+ def trash()
1624
+ @connection.perform_action(GM_ACT_TRASH,@id, '')
1625
+ end
1626
+
1627
+ #
1628
+ # return boolean
1629
+ # desc move a message from trash to inbox
1630
+ #
1631
+ def untrash()
1632
+ @connection.perform_action(GM_ACT_UNTRASH,@id, '')
1633
+ end
1634
+
1635
+ #
1636
+ # return boolean
1637
+ # desc delete a message forever
1638
+ #
1639
+ def delete()
1640
+ if connected?
1641
+ @connection.perform_action(GM_ACT_DELFOREVER,@id, '')
1642
+ else
1643
+ false
1644
+ end
1645
+ end
1646
+
1647
+ def original()
1648
+ @connection.fetch(:show_original=>@id)
1649
+ end
1650
+ end
212
1651
 
213
1652
  # Singleton method
214
1653
  # return bool
@@ -216,8 +1655,8 @@ class GMailer
216
1655
  #
217
1656
 
218
1657
  def GMailer.connect(*param)
219
- g = GMailer.new(*param)
220
- g.connect_no_cookie()
1658
+ g = Connection.new(*param)
1659
+ @connection = g
221
1660
  if block_given?
222
1661
  yield(g)
223
1662
  g.disconnect()
@@ -226,1225 +1665,5 @@ class GMailer
226
1665
  end
227
1666
  end
228
1667
 
229
-
230
- #
231
- # return bool
232
- # desc See if it is connected to GMail.
233
- #
234
- def connected?
235
- !@cookie_str.empty?
236
- end
237
-
238
- #
239
- # return bool
240
- # param string query
241
- # desc Fetch contents by URL query.
242
- #
243
- def __fetch(query)
244
- if connected?
245
- Debugger::say("Start fetching query: " + query)
246
- query += "&zv=" + (rand(2000)*2147483.648).to_i.to_s
247
- np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
248
- # np.set_debug_output($stderr)
249
- inbox = ''
250
- np.start { |http|
251
- response = http.get(GM_LNK_GMAIL + "?" + query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
252
- inbox = response.body
253
- }
254
-
255
- inbox = inbox.gsub("\n",'').gsub("D([","\nD([").gsub("])","])\n")
256
-
257
- matches = inbox.scan(/D\((.*)\)/).flatten
258
- packets = {}
259
- matches.each {|x|
260
- tmp = eval(x.gsub(",,",",'',").gsub(",,",",'',"))
261
- if (packets[tmp[0]] || (tmp[0]=="mi"||tmp[0]=="mb"||tmp[0]=="di"))
262
- if (tmp[0]=="t"||tmp[0]=="ts"||tmp[0]=="a"||tmp[0]=="cl")
263
- packets[tmp[0]] += tmp[1..-1]
264
- end
265
- if (tmp[0]=="mi"||tmp[0]=="mb"||tmp[0]=="di")
266
- if !packets["mg"].nil?
267
- packets["mg"].push(tmp)
268
- else
269
- packets["mg"] = [tmp]
270
- end
271
- end
272
- else
273
- packets[tmp[0]] = tmp
274
- end
275
- }
276
- if packets["cl"] && packets["cl"].length > 1
277
- packets["ce"] = []
278
- for i in 1 .. packets["cl"].length-1
279
- packets["ce"].push(packets["cl"][i])
280
- end
281
- end
282
- @raw = packets
283
-
284
- Debugger::say("Fetch completed.")
285
- true
286
- else # not logged in yet
287
- Debugger::say("Fetch failed: not connected.")
288
- false
289
- end
290
- end
291
- private :__fetch
292
-
293
- #
294
- # return bool
295
- # param constant type
296
- # param mixed box
297
- # param int pos
298
- # desc Fetch contents from GMail by type.
299
- #
300
- def fetch_box(type, box, pos)
301
-
302
- if connected?
303
- case type
304
- when GM_STANDARD
305
- q = "search=" + box.downcase + "&view=tl&start=" + pos.to_s
306
-
307
- when GM_LABEL
308
- q = "search=cat&cat=" + box.to_s + "&view=tl&start=" + pos.to_s
309
-
310
- when GM_CONVERSATION
311
- q = "search=inbox&ser=1&view=cv"
312
- if (box.class==Array)
313
- q += "&th=" + box[0].to_s
314
- for i in 1 .. box.length
315
- q += "&msgs=" + box[i].to_s
316
- end
317
- else
318
- q += "&th=" + box.to_s
319
- end
320
-
321
- when GM_QUERY
322
- q = "search=query&q=" + URI.escape(box.to_s) + "&view=tl&start=" + pos.to_s
323
-
324
- when GM_PREFERENCE
325
- q = "view=pr&pnl=g"
326
-
327
- when GM_CONTACT
328
- if box.downcase == "all"
329
- q = "view=cl&search=contacts&pnl=a"
330
- else
331
- q = "view=cl&search=contacts&pnl=d"
332
- end
333
-
334
- else
335
- q = "search=inbox&view=tl&start=0&init=1"
336
- end
337
-
338
- __fetch(q)
339
- else
340
- false
341
- end
342
- end
343
-
344
- #
345
- # return snapshot
346
- # param constant type
347
- # param mixed box
348
- # param int pos
349
- # desc Fetch contents from GMail by type.
350
- #
351
- def fetch(hash_param)
352
- type = GM_STANDARD
353
- box = "inbox"
354
- pos = 0
355
- hash_param.keys.each do |k|
356
- case k
357
- when :label
358
- type = GM_LABEL
359
- box = hash_param[k]
360
- when :standard
361
- type = GM_STANDARD
362
- box = hash_param[k]
363
- when :conversation
364
- type = GM_CONVERSATION
365
- box = hash_param[k]
366
- when :preference
367
- type = GM_PREFERENCE
368
- box = hash_param[k]
369
- when :contact
370
- type = GM_CONTACT
371
- box = hash_param[k]
372
- when :query
373
- type = GM_QUERY
374
- box = hash_param[k]
375
- when :pos
376
- pos = hash_param[k].to_i
377
- else
378
- raise ArgumentError, 'Invalid hash argument'
379
- end
380
- end
381
- box = "inbox" unless box
382
- fetch_box(type,box,pos)
383
- snapshot = snapshot(type)
384
- if block_given?
385
- yield(snapshot)
386
- elsif type == GM_CONTACT
387
- snapshot.contacts
388
- else
389
- snapshot
390
- end
391
- end
392
-
393
- #
394
- # return string[]
395
- # param string[] convs
396
- # param string path
397
- # desc Save all attaching files of conversations to a path.
398
- #
399
- def attachments_of(convs, path)
400
-
401
- if connected?
402
- if (convs.class != Array)
403
- convs = [convs] # array wrapper
404
- end
405
- final = []
406
- convs.each { |v|
407
- if v["attachment"]
408
- v["attachment"].each { |vv|
409
- f = path+"/"+vv["filename"]
410
- f = path+"/"+vv["filename"]+"."+rand(2000).to_s while (FileTest.exist?(f))
411
- if attachment(vv["id"],v["id"],f,false)
412
- final.push(f)
413
- end
414
- }
415
- end
416
- }
417
- final
418
- else
419
- nil
420
- end
421
- end
422
-
423
- #
424
- # return string[]
425
- # param string[] convs
426
- # param string path
427
- # desc Save all attaching files of conversations to a path.
428
- #
429
- def zip_attachments_of(convs, path)
430
-
431
- if connected?
432
- if (convs.class != Array)
433
- convs = [convs] # array wrapper
434
- end
435
- final = []
436
- convs.each {|v|
437
- if v["attachment"]
438
- f = path+"/attachment.zip"
439
- f = path+"/attachment."+rand(2000).to_s+".zip" while (FileTest.exist?(f))
440
- if attachment(v["attachment"][0]["id"],v["id"],f,true)
441
- final.push(f)
442
- end
443
- end
444
- }
445
- final
446
- else
447
- nil
448
- end
449
- end
450
-
451
- #
452
- # return bool
453
- # param string attid
454
- # param string msgid
455
- # param string filename
456
- # desc Save attachment with attachment ID attid and message ID msgid to file with name filename.
457
- #
458
- def attachment(attid, msgid, filename, zipped=false)
459
-
460
- if connected?
461
- Debugger::say("Start getting attachment...")
462
-
463
- if !zipped
464
- query = GM_LNK_ATTACHMENT + "&attid=" + URI.escape(attid) + "&th=" + URI.escape(msgid)
465
- else
466
- query = GM_LNK_ATTACHMENT_ZIPPED + "&th=" + URI.escape(msgid)
467
- end
468
-
469
- File.open(filename,"wb") { |f|
470
- np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
471
- np.start { |http|
472
- response = http.get(query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
473
- f.write(response.body)
474
- }
475
- }
476
- Debugger::say("Completed getting attachment.")
477
- true
478
- else
479
- Debugger::say("Failed to get attachment: not connected.")
480
- false
481
- end
482
- end
483
-
484
- #
485
- # return array of labels
486
- # desc get label lists
487
- #
488
- def labels()
489
- if connected?
490
- fetch(:standard=>"inbox") {|s| s.label_list }
491
- else
492
- nil
493
- end
494
- end
495
-
496
- #
497
- # return string
498
- # param string label
499
- # desc validate label
500
- #
501
- def validate_label(label)
502
- label.strip!
503
- if label==''
504
- raise ArgumentError, 'Error: Labels cannot empty string'
505
- end
506
- if label.length > 40
507
- raise ArgumentError, 'Error: Labels cannot contain more than 40 characters'
508
- end
509
- if label.include?('^')
510
- raise ArgumentError, "Error: Labels cannot contain the character '^'"
511
- end
512
- label
513
- end
514
-
515
- #
516
- # return boolean
517
- # param string label
518
- # desc create label
519
- #
520
- def create_label(label)
521
- if connected?
522
- perform_action(GM_ACT_CREATELABEL, '', validate_label(label))
523
- else
524
- false
525
- end
526
- end
527
-
528
- #
529
- # return boolean
530
- # param string label
531
- # desc create label
532
- #
533
- def delete_label(label)
534
- if connected?
535
- perform_action(GM_ACT_DELETELABEL, '', validate_label(label))
536
- else
537
- false
538
- end
539
- end
540
-
541
- #
542
- # return boolean
543
- # param string old_label
544
- # param string new_label
545
- # desc create label
546
- #
547
- def rename_label(old_label,new_label)
548
- if connected?
549
- perform_action(GM_ACT_RENAMELABEL, '',
550
- validate_label(old_label) +'^' + validate_label(new_label))
551
- else
552
- false
553
- end
554
- end
555
-
556
- #
557
- # return boolean
558
- # param string msgid
559
- # param string label
560
- # desc apply label to message
561
- #
562
- def apply_label(id,label)
563
- if connected?
564
- perform_action(GM_ACT_APPLYLABEL, id, validate_label(label))
565
- else
566
- false
567
- end
568
- end
569
-
570
- #
571
- # return boolean
572
- # param string msgid
573
- # param string label
574
- # desc remove label from message
575
- #
576
- def remove_label(id,label)
577
- if connected?
578
- perform_action(GM_ACT_REMOVELABEL, id, validate_label(label))
579
- else
580
- false
581
- end
582
- end
583
-
584
- #
585
- # return boolean
586
- # param string hash_param
587
- # desc remove label from message
588
- #
589
- def update_preference(hash_param)
590
- if connected?
591
- args = {}
592
- hash_param.keys.each do |k|
593
- case k
594
- when :max_page_size
595
- args['p_ix_nt'] = hash_param[k]
596
- when :keyboard_shortcuts
597
- args['p_bx_hs'] = hash_param[k] ? '1' : '0'
598
- when :indicators
599
- args['p_bx_sc'] = hash_param[k] ? '1' : '0'
600
- when :display_language
601
- args['p_sx_dl'] = hash_param[k]
602
- when :signature
603
- args['p_sx_sg'] = hash_param[k]
604
- when :reply_to
605
- args['p_sx_rt'] = hash_param[k]
606
- when :snippets
607
- args['p_bx_ns'] = hash_param[k] ? '0' : '1'
608
- when :display_name
609
- args['p_sx_dn'] = hash_param[k]
610
- end
611
- end
612
- param = '&' + args.to_a.map {|x| x.join('=')}.join('&')
613
- perform_action(GM_ACT_PREFERENCE,'', param)
614
- else
615
- false
616
- end
617
- end
618
-
619
- #
620
- # return boolean
621
- # param string msgid
622
- # desc apply star to a message
623
- #
624
- def apply_star(msgid)
625
- if connected?
626
- perform_action(GM_ACT_STAR,msgid, '')
627
- else
628
- false
629
- end
630
- end
631
-
632
- #
633
- # return boolean
634
- # param string msgid
635
- # desc remove star from a message
636
- #
637
- def remove_star(msgid)
638
- if connected?
639
- perform_action(GM_ACT_UNSTAR,msgid, '')
640
- else
641
- false
642
- end
643
- end
644
-
645
- #
646
- # return boolean
647
- # param string msgid
648
- # desc report a message as spam
649
- #
650
- def report_spam(msgid)
651
- if connected?
652
- perform_action(GM_ACT_SPAM,msgid, '')
653
- else
654
- false
655
- end
656
- end
657
-
658
- #
659
- # return boolean
660
- # param string msgid
661
- # desc report a message as not spam
662
- #
663
- def not_spam(msgid)
664
- if connected?
665
- perform_action(GM_ACT_UNSPAM,msgid, '')
666
- else
667
- false
668
- end
669
- end
670
-
671
- #
672
- # return boolean
673
- # param string msgid
674
- # desc delete a spam message forever
675
- #
676
- def delete_spam(msgid)
677
- if connected?
678
- perform_action(GM_ACT_DELSPAM,msgid, '')
679
- else
680
- false
681
- end
682
- end
683
-
684
- #
685
- # return boolean
686
- # param string msgid
687
- # desc mark a message as read
688
- #
689
- def mark_read(msgid)
690
- if connected?
691
- perform_action(GM_ACT_READ,msgid, '')
692
- else
693
- false
694
- end
695
- end
696
-
697
- #
698
- # return boolean
699
- # param string msgid
700
- # desc mark a message as unread
701
- #
702
- def mark_unread(msgid)
703
- if connected?
704
- perform_action(GM_ACT_UNREAD,msgid, '')
705
- else
706
- false
707
- end
708
- end
709
-
710
- #
711
- # return boolean
712
- # param string msgid
713
- # desc move a message to trash
714
- #
715
- def trash_in(msgid)
716
- if connected?
717
- perform_action(GM_ACT_TRASH,msgid, '')
718
- else
719
- false
720
- end
721
- end
722
-
723
- #
724
- # return boolean
725
- # param string msgid
726
- # desc move a message from trash to inbox
727
- #
728
- def trash_out(msgid)
729
- if connected?
730
- perform_action(GM_ACT_UNTRASH,msgid, '')
731
- else
732
- false
733
- end
734
- end
735
-
736
- #
737
- # return boolean
738
- # param string msgid
739
- # desc delete a trash message forever
740
- #
741
- def delete_trash(msgid)
742
- if connected?
743
- perform_action(GM_ACT_DELTRASH,msgid, '')
744
- else
745
- false
746
- end
747
- end
748
-
749
- #
750
- # return boolean
751
- # param string msgid
752
- # desc delete a message forever
753
- #
754
- def delete_message(msgid)
755
- if connected?
756
- perform_action(GM_ACT_DELFOREVER,msgid, '')
757
- else
758
- false
759
- end
760
- end
761
-
762
- #
763
- # return boolean
764
- # param string msgid
765
- # desc archive a message
766
- #
767
- def archive(msgid)
768
- if connected?
769
- perform_action(GM_ACT_ARCHIVE,msgid, '')
770
- else
771
- false
772
- end
773
- end
774
-
775
- #
776
- # return boolean
777
- # param string msgid
778
- # desc archive a message
779
- #
780
- def unarchive(msgid)
781
- if connected?
782
- perform_action(GM_ACT_INBOX,msgid, '')
783
- else
784
- false
785
- end
786
- end
787
-
788
- #
789
- # return hash of preference
790
- # desc get preferences
791
- #
792
- def preference()
793
- if connected?
794
- fetch(:preference=>"all").preference
795
- else
796
- nil
797
- end
798
- end
799
-
800
- #
801
- # return array of messages
802
- # desc get message lists
803
- #
804
- def messages(hash_param)
805
- if connected?
806
- fetch(hash_param) {|s| s.box }
807
- else
808
- nil
809
- end
810
- end
811
-
812
- #
813
- # return string
814
- # param string query
815
- # desc Dump everything to output.
816
- #
817
- def dump(query)
818
- page = ''
819
- if connected?
820
- Debugger::say("Dumping...")
821
- query += "&zv=" + (rand(2000)*2147483.648).to_i.to_s
822
- np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
823
- np.start { |http|
824
- response = http.get(GM_LNK_GMAIL + "?"+query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
825
- page = response.body
826
- }
827
-
828
- Debugger::say("Finished dumping " + page.length.to_s + " bytes.")
829
- else # not logged in yet
830
- Debugger::say("Failed to dump: not connected.")
831
- end
832
- page
833
- end
834
-
835
- def stripslashes(string)
836
- encode(string.gsub("\\\"", "\"").gsub("\\'", "'").gsub("\\\\", "\\"))
837
- end
838
-
839
-
840
- #
841
- # return bool
842
- # param string to
843
- # param string subject
844
- # param string body
845
- # param string cc
846
- # param string bcc
847
- # param string msg_id
848
- # param string thread_id
849
- # param string[] files
850
- # desc Send GMail.
851
- #
852
- def send(*param)
853
- if param.length==1 && param[0].class==Hash
854
- param = param[0]
855
- from = param[:from] || ''
856
- to = param[:to] || ''
857
- subject = param[:subject] || ''
858
- body = param[:body] || ''
859
- cc = param[:cc] || ''
860
- bcc = param[:bcc] || ''
861
- msg_id = param[:msg_id] || ''
862
- thread_id = param[:msg_id] || ''
863
- files = param[:files] || []
864
- draft = param[:draft] || false
865
- draft_id = param[:draft_id] || ''
866
- elsif param.length==10
867
- to, subject, body, cc, bcc, msg_id, thread_id, files, draft, draft_id = param
868
- elsif param.length==11
869
- from, to, subject, body, cc, bcc, msg_id, thread_id, files, draft, draft_id = param
870
- else
871
- raise ArgumentError, 'Invalid argument'
872
- end
873
-
874
- if connected?
875
- Debugger::say("Starting to send mail...")
876
- other_emails = fetch(:preference=>"all").other_emails
877
- if other_emails.length>0
878
- other_emails.each {|v|
879
- from = v['email'] if from=='' && v['default']
880
- }
881
- from = @login + 'gmail.com' if from==''
882
- else
883
- from = nil
884
- end
885
-
886
- postdata = {}
887
- if draft
888
- postdata["view"] = "sd"
889
- postdata["draft"] = draft_id
890
- postdata["rm"] = msg_id
891
- postdata["th"] = thread_id
892
- else
893
- postdata["view"] = "sm"
894
- postdata["draft"] = draft_id
895
- postdata["rm"] = msg_id
896
- postdata["th"] = thread_id
897
- end
898
- postdata["msgbody"] = stripslashes(body)
899
- postdata["from"] = stripslashes(from) if from
900
- postdata["to"] = stripslashes(to)
901
- postdata["subject"] = stripslashes(subject)
902
- postdata["cc"] = stripslashes(cc)
903
- postdata["bcc"] = stripslashes(bcc)
904
-
905
- postdata["cmid"] = 1
906
- postdata["ishtml"] = 0
907
-
908
- cc = @cookie_str.split(';')
909
- cc.each {|cc_part|
910
- cc_parts = cc_part.split('=')
911
- if(cc_parts[0]=='GMAIL_AT')
912
- postdata["at"] = cc_parts[1]
913
- break
914
- end
915
- }
916
-
917
- boundary = "----#{Time.now.to_i}#{(rand(2000)*2147483.648).to_i}"
918
- postdata2 = []
919
- postdata.each {|k,v|
920
- postdata2.push("Content-Disposition: form-data; name=\"#{k}\"\r\n\r\n#{v}\r\n")
921
- }
922
-
923
- files.each_with_index {|f,i|
924
- content = File.open(f,'rb') { |c| c.read }
925
- postdata2.push("Content-Disposition: form-data; name=\"file#{i}\"; filename=\"#{File.basename(f)}\"\r\n" +
926
- "Content-Transfer-Encoding: binary\r\n" +
927
- "Content-Type: application/octet-stream\r\n\r\n" + content + "\r\n")
928
- }
929
-
930
- postdata = postdata2.collect { |p|
931
- "--" + boundary + "\r\n" + p
932
- }.join('') + "--" + boundary + "--\r\n"
933
-
934
- np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
935
- response = nil
936
- # np.set_debug_output($stderr)
937
- np.start { |http|
938
- response = http.post(GM_LNK_GMAIL, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT,'Content-type' => 'multipart/form-data; boundary=' + boundary } )
939
- }
940
- Debugger::say("Finished sending email.")
941
- true
942
- else
943
- Debugger::say("Failed to send email: not connected.")
944
- false
945
- end
946
-
947
- end
948
-
949
- #
950
- # return bool
951
- # param constant act
952
- # param string[] id
953
- # param string para
954
- # desc Perform action on messages.
955
- #
956
- def perform_action(act, id, para)
957
-
958
- if connected?
959
- Debugger::say("Start performing action...")
960
-
961
- if (act == GM_ACT_DELFOREVER)
962
- perform_action(GM_ACT_TRASH, id, 0) # trash it before
963
- end
964
- postdata = "act="
965
-
966
- action_codes = ["ib", "cc_", "dc_", "nc_", "ac_", "rc_", "prefs", "st", "xst",
967
- "sp", "us", "rd", "ur", "tr", "dl", "rc_^i", "ib", "ib", "dd", "dm", "dl", "dl"]
968
- postdata += action_codes[act] ? action_codes[act] : action_codes[GM_ACT_INBOX]
969
- if ([GM_ACT_APPLYLABEL,GM_ACT_REMOVELABEL,GM_ACT_CREATELABEL,
970
- GM_ACT_DELETELABEL,GM_ACT_RENAMELABEL,GM_ACT_PREFERENCE].include?(act))
971
- postdata += para.to_s
972
- end
973
-
974
- cc = @cookie_str.split(';')
975
- cc.each {|cc_part|
976
- cc_parts = cc_part.split('=')
977
- if(cc_parts[0]=='GMAIL_AT')
978
- postdata += "&at=" + cc_parts[1]
979
- break
980
- end
981
- }
982
-
983
- if (act == GM_ACT_TRASHMSG)
984
- postdata += "&m=" + id.to_s
985
- else
986
- if id.class==Array
987
- id.each {|t| postdata += "&t="+t.to_s }
988
- else
989
- postdata += "&t="+id.to_s
990
- end
991
- end
992
- postdata += "&vp="
993
-
994
- if [GM_ACT_UNTRASH,GM_ACT_DELFOREVER,GM_ACT_DELTRASH].include?(act)
995
- link = GM_LNK_GMAIL+"?search=trash&view=tl&start=0"
996
- elsif (act == GM_ACT_DELSPAM)
997
- link = GM_LNK_GMAIL+"?search=spam&view=tl&start=0"
998
- else
999
- link = GM_LNK_GMAIL+"?search=query&q=&view=tl&start=0"
1000
- end
1001
-
1002
- np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
1003
- # np.set_debug_output($stderr)
1004
- np.start { |http|
1005
- response = http.post(link, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
1006
- result = response.body
1007
- }
1008
-
1009
- Debugger::say("Finished performing action.")
1010
- return true
1011
- else
1012
- Debugger::say("Failed to perform action: not connected.")
1013
- return false
1014
- end
1015
-
1016
- end
1017
-
1018
- #
1019
- # return void
1020
- # desc Disconnect from GMail.
1021
- #
1022
- def disconnect()
1023
- Debugger::say("Start disconnecting...")
1024
-
1025
- response = nil
1026
- np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
1027
- # np.set_debug_output($stderr)
1028
- np.start { |http|
1029
- response = http.get(GM_LNK_LOGOUT,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
1030
- }
1031
- arr = URI::split(response["Location"])
1032
- np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 80)
1033
- # np.set_debug_output($stderr)
1034
- np.start { |http|
1035
- response = http.get(arr[5]+'?'+arr[7], {'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
1036
- }
1037
-
1038
- Debugger::say("Logged-out from GMail.")
1039
- @cookie_str = ''
1040
- Debugger::say("Completed disconnecting.")
1041
- end
1042
-
1043
- #
1044
- # return GMailSnapshot
1045
- # param constant type
1046
- # desc Get GMSnapshot by type.
1047
- #
1048
- def snapshot(type)
1049
- if [GM_STANDARD,GM_LABEL,GM_CONVERSATION,GM_QUERY,GM_PREFERENCE,GM_CONTACT].include?(type)
1050
- return GMailSnapshot.new(type, @raw, @charset)
1051
- else
1052
- return GMailSnapshot.new(GM_STANDARD, @raw, @charset) # assuming normal by default
1053
- end
1054
- end
1055
-
1056
- def snap(type)
1057
- action = GM_STANDARD
1058
- case type
1059
- when :standard
1060
- action = GM_STANDARD
1061
- when :label
1062
- action = GM_LABEL
1063
- when :conversation
1064
- action = GM_CONVERSATION
1065
- when :query
1066
- action = GM_QUERY
1067
- when :preference
1068
- action = GM_PREFERENCE
1069
- when :contact
1070
- action = GM_CONTACT
1071
- else
1072
- raise ArgumentError, 'Invalid type'
1073
- end
1074
- snapshot(action)
1075
- end
1076
-
1077
- #
1078
- # return bool
1079
- # param string email
1080
- # desc Send Gmail invite to email
1081
- #
1082
- def invite(email)
1083
-
1084
- if connected?
1085
- Debugger::say("Start sending invite...")
1086
-
1087
- postdata = "act=ii&em=" + URI.escape(email)
1088
-
1089
- cc = @cookie_str.split(';')
1090
- cc.each {|cc_part|
1091
- cc_parts = cc_part.split('=')
1092
- if(cc_parts[0]=='GMAIL_AT')
1093
- postdata += "&at=" + cc_parts[1]
1094
- break
1095
- end
1096
- }
1097
-
1098
- link = GM_LNK_GMAIL + "?view=ii"
1099
-
1100
- np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
1101
- np.use_ssl = true
1102
- np.verify_mode = OpenSSL::SSL::VERIFY_NONE
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
- }
1107
-
1108
- Debugger::say("Finished sending invite.")
1109
- true
1110
- else
1111
- Debugger::say("Failed to send invite: not connected.")
1112
- false
1113
- end
1114
-
1115
- end
1116
-
1117
- #
1118
- # return string[]
1119
- # desc (Static) Get names of standard boxes.
1120
- #
1121
- def standard_box()
1122
- ["Inbox","Starred","Sent","Drafts","All","Spam","Trash"]
1123
- end
1124
-
1125
- #
1126
- # return string
1127
- # param string header
1128
- # desc (Static Private) Extract cookies from header.
1129
- #
1130
- def __cookies(header)
1131
- return '' unless header
1132
- arr = []
1133
- header.split(', ').each { |x|
1134
- if x.include?('GMT')
1135
- arr[-1] += ", " + x
1136
- else
1137
- arr.push x
1138
- end
1139
- }
1140
- arr.delete_if {|x| x.include?('LSID=EXPIRED') }
1141
- arr.map! {|x| x.split(';')[0]}
1142
- arr.join(';')
1143
- end
1144
-
1145
- end
1146
-
1147
-
1148
- class GMailSnapshot
1149
-
1150
- GM_STANDARD = 0x001
1151
- GM_LABEL = 0x002
1152
- GM_CONVERSATION = 0x004
1153
- GM_QUERY = 0x008
1154
- GM_CONTACT = 0x010
1155
- GM_PREFERENCE = 0x020
1156
-
1157
- def decode(str)
1158
- return str if @charset.upcase == 'UTF-8'
1159
- begin
1160
- require 'Win32API'
1161
- str = str.unpack("U*").pack("S*") + "\0"
1162
- ostr = "\0" * 256
1163
- wideCharToMultiByte = Win32API.new('kernel32','WideCharToMultiByte',['L','L','P','L','P','L','L','L'],'L')
1164
- wideCharToMultiByte.Call(0,0,str,-1,ostr,256,0,0)
1165
- ostr.strip
1166
- rescue LoadError
1167
- require 'iconv'
1168
- Iconv::iconv(@charset,'UTF-8',str)[0]
1169
- end
1170
- end
1171
-
1172
- def strip_tags(str,allowable_tags='')
1173
- str.gsub(/<[^>]*>/, '')
1174
- end
1175
-
1176
- #
1177
- # return GMailSnapshot
1178
- # param constant type
1179
- # param array raw
1180
- # desc Constructor.
1181
- #
1182
- attr_reader :gmail_ver, :quota_mb, :quota_per, :preference
1183
- attr_reader :std_box_new, :have_invit, :label_list, :label_new
1184
- attr_reader :box_name, :box_total, :box_pos, :box
1185
- attr_reader :conv_title, :conv_total, :conv_id, :conv_labels, :conv_starred, :conv
1186
- attr_reader :contacts, :other_emails
1187
-
1188
- def initialize(type, raw, charset='UTF-8')
1189
-
1190
- @charset = charset
1191
- if (raw.class!=Hash)
1192
- @created = 0
1193
- return nil
1194
- elsif (raw.empty?)
1195
- @created = 0
1196
- return nil
1197
- end
1198
- if [GM_STANDARD,GM_LABEL,GM_CONVERSATION,GM_QUERY].include?(type)
1199
- @gmail_ver = raw["v"][1]
1200
- if raw["qu"]
1201
- @quota_mb = raw["qu"][1]
1202
- @quota_per = raw["qu"][3]
1203
- end
1204
- if (raw["ds"].class!=Array)
1205
- @created = 0
1206
- return nil
1207
- end
1208
- @std_box_new = raw["ds"][1..-1]
1209
- #if (isset(raw["p"])) {
1210
- # @owner = raw["p"][5][1]
1211
- # @owner_email = raw["p"][6][1]
1212
- #end
1213
- @have_invit = raw["i"][1]
1214
- @label_list = []
1215
- @label_new = []
1216
- raw["ct"][1].each {|v|
1217
- @label_list.push(v[0])
1218
- @label_new.push(v[1])
1219
- }
1220
- if raw["ts"]
1221
- @view = (GM_STANDARD|GM_LABEL|GM_QUERY)
1222
- @box_name = raw["ts"][5]
1223
- @box_total = raw["ts"][3]
1224
- @box_pos = raw["ts"][1]
1225
- end
1226
- @box = []
1227
- if raw["t"]
1228
- raw["t"].each {|t|
1229
- if (t != "t")
1230
- b = {
1231
- "id"=>t[0],
1232
- "is_read"=>(t[1] != 1 ? 1 : 0),
1233
- "new?"=>(t[1] == 1),
1234
- "is_starred"=>(t[2] == 1 ? 1 : 0),
1235
- "star?"=>(t[2] == 1),
1236
- "date"=>decode(strip_tags(t[3])),
1237
- "sender"=>decode(strip_tags(t[4])),
1238
- "flag"=>t[5],
1239
- "subject"=>decode(strip_tags(t[6])),
1240
- "snippet"=>decode(t[7].gsub('&quot;','"').gsub('&hellip;','...')),
1241
- "labels"=>t[8].empty? ? [] : t[8].map{|tt|decode(tt)},
1242
- "attachment"=>t[9].empty? ? []: decode(t[9]).split(","),
1243
- "msgid"=>t[10]
1244
- }
1245
- @box.push(b)
1246
- end
1247
- }
1248
- end
1249
-
1250
- if (!raw["cs"].nil?)
1251
- @view = GM_CONVERSATION
1252
- @conv_title = raw["cs"][2]
1253
- @conv_total = raw["cs"][8]
1254
- @conv_id = raw["cs"][1]
1255
- @conv_labels = raw["cs"][5].empty? ? '' : raw["cs"][5]
1256
- if !@conv_labels.empty?
1257
- ij = @conv_labels.index("^i")
1258
- if !ij.nil?
1259
- @conv_labels[ij] = "Inbox"
1260
- end
1261
- ij = @conv_labels.index("^s")
1262
- if !ij.nil?
1263
- @conv_labels[ij] = "Spam"
1264
- end
1265
- ij = @conv_labels.index("^k")
1266
- if !ij.nil?
1267
- @conv_labels[ij] = "Trash"
1268
- end
1269
- ij = @conv_labels.index("^t")
1270
- if !ij.nil?
1271
- @conv_labels[ij] = '' # Starred
1272
- end
1273
- ij = @conv_labels.index("^r")
1274
- if !ij.nil?
1275
- @conv_labels[ij] = "Drafts"
1276
- end
1277
- end
1278
-
1279
- @conv_starred = false
1280
-
1281
- @conv = []
1282
- b = {}
1283
- raw["mg"].each {|r|
1284
- if (r[0] == "mb" && !b.empty?)
1285
- b["body"] += r[1]
1286
- if (r[2] == 0)
1287
- @conv.push(b)
1288
- b = {}
1289
- end
1290
- elsif (r[0] == "mi")
1291
- if !b.empty?
1292
- @conv.push(b)
1293
- b = {}
1294
- end
1295
- b = {}
1296
- b["index"] = r[2]
1297
- b["id"] = r[3]
1298
- b["is_star"] = r[4]
1299
- if (b["is_star"] == 1)
1300
- @conv_starred = true
1301
- end
1302
- b["sender"] = r[6]
1303
- b["sender_email"] = r[8].gsub("\"",'') # remove annoying d-quotes in address
1304
- b["recv"] = r[9]
1305
- b["recv_email"] = r[11].to_s.gsub("\"",'')
1306
- b["reply_email"] = r[14].to_s.gsub("\"",'')
1307
- b["dt_easy"] = r[10]
1308
- b["dt"] = r[15]
1309
- b["subject"] = r[16]
1310
- b["snippet"] = r[17]
1311
- b["attachment"] = []
1312
- r[18].each {|bb|
1313
- b["attachment"].push({"id"=>bb[0],"filename"=>bb[1],"type"=>bb[2],"size"=>bb[3]})
1314
- }
1315
- b["is_draft"] = false
1316
- b["body"] = ''
1317
- elsif (r[0] == "di")
1318
- if !b.empty?
1319
- @conv.push(b)
1320
- b = {}
1321
- end
1322
- b = {}
1323
- b["index"] = r[2]
1324
- b["id"] = r[3]
1325
- b["is_star"] = r[4]
1326
- @conv_starred = (b["is_star"] == 1)
1327
- b["sender"] = r[6]
1328
- b["sender_email"] = r[8].gsub("\"",'') # remove annoying d-quotes in address
1329
- b["recv"] = r[9]
1330
- b["recv_email"] = r[11].gsub("\"",'')
1331
- b["reply_email"] = r[14].gsub("\"",'')
1332
- b["cc_email"] = r[12].gsub("\"",'')
1333
- b["bcc_email"] = r[13].gsub("\"",'')
1334
- b["dt_easy"] = r[10]
1335
- b["dt"] = r[15]
1336
- b["subject"] = r[16]
1337
- b["snippet"] = r[17]
1338
- b["attachment"] = []
1339
- r[18].each {|bb|
1340
- b["attachment"].push({"id"=>bb[0],"filename"=>bb[1],"type"=>bb[2],"size"=>bb[3]})
1341
- }
1342
- b["is_draft"] = true
1343
- b["draft_parent"] = r[5]
1344
- b["body"] = r[20]
1345
- end
1346
- }
1347
- @conv.push(b) unless b.empty?
1348
- end
1349
- elsif type == GM_CONTACT
1350
- @contacts = []
1351
- if raw["ce"]
1352
- raw["ce"].each {|a|
1353
- b = {
1354
- "name"=>a[2],
1355
- "email"=>a[4].gsub("\"",'')
1356
- }
1357
- if !a[5].empty?
1358
- b["notes"] = a[5]
1359
- end
1360
- @contacts.push(b)
1361
- }
1362
- end
1363
- @view = GM_CONTACT
1364
- elsif type == GM_PREFERENCE
1365
- prefs = {}
1366
- raw["p"].each_with_index { |v,i|
1367
- prefs[v[0]] = v[1] if i>0
1368
- }
1369
- @preference = {'max_page_size'=>'10',
1370
- 'keyboard_shortcuts'=>false,
1371
- 'indicators'=>false,
1372
- 'display_language'=>'en',
1373
- 'signature'=>'',
1374
- 'reply_to'=>'',
1375
- 'snippets'=>false,
1376
- 'display_name'=>'',
1377
- }
1378
- prefs.each do |k,v|
1379
- case k
1380
- when 'ix_nt'
1381
- @preference['max_page_size'] = v
1382
- when 'bx_hs'
1383
- @preference['keyboard_shortcuts'] = (v == '1')
1384
- when 'bx_sc'
1385
- @preference['indicators'] = (v == '1')
1386
- when 'sx_dl'
1387
- @preference['display_language'] = v
1388
- when 'sx_sg'
1389
- @preference['signature'] = (v == '0') ? '' : v
1390
- when 'sx_rt'
1391
- @preference['reply_to'] = v
1392
- when 'bx_ns'
1393
- @preference['snippets'] = (v == '0')
1394
- when 'sx_dn'
1395
- @preference['display_name'] = v
1396
- end
1397
- end
1398
-
1399
- @label_list = []
1400
- @label_total = []
1401
- raw["cta"][1].each { |v|
1402
- @label_list.push(v[0])
1403
- @label_total.push(v[1])
1404
- }
1405
- @other_emails = []
1406
- if raw["cfs"]
1407
- raw["cfs"][1].each {|v|
1408
- @other_emails.push({"name"=>decode(v[0]),"email"=>v[1],"default"=>(v[2]==1)})
1409
- }
1410
- end
1411
- @filter = []
1412
- @filter_rules = []
1413
- raw["fi"][1].each { |fi|
1414
- b = {
1415
- "id" => fi[0],
1416
- "query" => fi[1],
1417
- "star" => fi[3],
1418
- "label" => fi[4],
1419
- "archive" => fi[5],
1420
- "trash" => fi[6] #,"forward" => fi[7]
1421
- }
1422
- bb = {
1423
- "from" => fi[2][0],
1424
- "to" => fi[2][1],
1425
- "subject" => fi[2][2],
1426
- "has" => fi[2][3],
1427
- "hasnot" => fi[2][4],
1428
- "attach" => fi[2][5]
1429
- }
1430
-
1431
- @filter.push(b)
1432
- @filter_rules.push(bb)
1433
- }
1434
- @view = GM_PREFERENCE
1435
- else
1436
- @created = 0
1437
- return nil
1438
- end
1439
- @created = 1
1440
- end
1441
-
1442
- end
1443
-
1444
-
1445
- class Debugger
1446
- def Debugger.say(str)
1447
- puts str if $D_ON
1448
- end
1449
1668
  end
1450
1669