gmailer 0.0.8 → 0.0.9

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.
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