gmailer 0.0.5 → 0.0.6

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 +16 -11
  2. data/README +44 -12
  3. data/gmailer.rb +1314 -0
  4. metadata +2 -1
data/CHANGES CHANGED
@@ -1,20 +1,25 @@
1
+ == 0.0.6 - 29-Aug-2005
2
+ - add edit star method
3
+ - add edit archive method
4
+ - rename get_ method
5
+
1
6
  == 0.0.5 - 28-Aug-2005
2
- * add edit label mothods
3
- * add edit preference method
4
- * fix some bugs
7
+ - add edit label mothods
8
+ - add edit preference method
9
+ - fix some bugs
5
10
 
6
11
  == 0.0.4 - 26-Aug-2005
7
- * remove camelCase methods
8
- * fix some bugs
9
- * modify some key name
12
+ - remove camelCase methods
13
+ - fix some bugs
14
+ - modify some key name
10
15
 
11
16
  == 0.0.3 - 25-Aug-2005
12
- * add some methods
13
- * add support for proxy
17
+ - add some methods
18
+ - add support for proxy
14
19
 
15
20
  == 0.0.2 - 20-Aug-2005
16
- * add some methods
17
- * make more compact and simple
21
+ - add some methods
22
+ - make more compact and simple
18
23
 
19
24
  == 0.0.1 - 17-Aug-2005
20
- * Initial release
25
+ - Initial release
data/README CHANGED
@@ -9,7 +9,7 @@
9
9
  gmail.set_login_info(name, pwd)
10
10
  if gmail.connect
11
11
  gmail.fetch_box(GM_LABEL, "my_label", 0)
12
- snapshot = gmail.get_snapshot(GM_LABEL)
12
+ snapshot = gmail.snapshot(GM_LABEL)
13
13
  if snapshot
14
14
  puts "Total # of conversations of my_label = " + snapshot.box_total.to_s
15
15
  end
@@ -65,7 +65,7 @@ Or shorter
65
65
  gmail.set_login_info(name, pwd)
66
66
  if gmail.connect
67
67
  gmail.fetch_box(GM_CONTACT, "freq", 0)
68
- snapshot = gmail.get_snapshot(GM_CONTACT)
68
+ snapshot = gmail.snapshot(GM_CONTACT)
69
69
  puts "Your frequently used addresses:"
70
70
  snapshot.contacts.each { |item|
71
71
  puts "Name: " + item["name"] + ", Email: " + item["email"]
@@ -84,8 +84,8 @@ Or shorter
84
84
  === Get list of labels and get list of messages
85
85
 
86
86
  GMailer.connect(:username=>name,:password=>pwd) do |g|
87
- labels = g.get_labels
88
- g.get_messages(:label=>labels[0]).each {|m|
87
+ labels = g.labels
88
+ g.messages(:label=>labels[0]).each {|m|
89
89
  puts "Subject: #{m['subject']} / Snippet: #{m['snippet']}" if m['new?']
90
90
  }
91
91
  end
@@ -121,10 +121,30 @@ GMailer.connect(:username=>name,:password=>pwd) do |g|
121
121
  :reply_to=>'return@foo.bar',
122
122
  :snippets=>true,
123
123
  :display_name=>'Display Name')
124
- pref = g.get_preference
124
+ pref = g.preference
125
125
  puts "Display language:#{pref['display_language']}, Max Page Size:#{pref['max_page_size']}"
126
126
  end
127
127
 
128
+ === Apply star and remove star
129
+
130
+ GMailer.connect(:username=>name,:password=>pwd) do |g|
131
+ #apply star to a message
132
+ g.apply_star(msgid)
133
+
134
+ #remove star from a message
135
+ g.remove_star(msgid)
136
+ end
137
+
138
+ === Archive and unarchive a message
139
+
140
+ GMailer.connect(:username=>name,:password=>pwd) do |g|
141
+ #archive a message
142
+ g.archive(msgid)
143
+
144
+ #unarchive a message
145
+ g.unarchive(msgid)
146
+ end
147
+
128
148
  == Class Methods
129
149
  GMailer.new(charset='UTF-8')
130
150
  Returns a new GMailer object and set up charset.
@@ -168,24 +188,24 @@ fetch_box(type,box,position)
168
188
  box: name of "box" (e.g. Inbox, your_label, "all"/"freq" of contacts)
169
189
  position: cursor for paged result.
170
190
 
171
- get_snapshot(type)
191
+ snapshot(type)
172
192
  To get a "snapshot", an object (see GMailSnapshot below) for you to
173
193
  access query result at ease.
174
194
 
175
- get_labels()
195
+ labels()
176
196
  To get list of labels.
177
197
 
178
- get_preference()
198
+ preference()
179
199
  To get hash of preference setting.
180
200
 
181
- get_messages()
201
+ messages()
182
202
  To get list of messages.
183
203
 
184
- get_attachment(attachment_id,message_id,filename,zipped)
204
+ attachment(attachment_id,message_id,filename,zipped)
185
205
  To download an attachment of a message. If zipped is true, download ALL
186
206
  attachements of message_id in a zip file.
187
207
 
188
- get_attachments_of(conv, path_to_store_files)
208
+ attachments_of(conv, path_to_store_files)
189
209
  To download ALL files attached to a conversation. The full path of
190
210
  downloaded files will be returned (as array).
191
211
 
@@ -204,6 +224,18 @@ apply_label(msgid,label)
204
224
  remove_label(msgid,label)
205
225
  To remove a label to a message
206
226
 
227
+ apply_star(msgid)
228
+ To apply starring to a message
229
+
230
+ remove_star(msgid)
231
+ To remove starring from a message
232
+
233
+ archive(msgid)
234
+ To archive a message
235
+
236
+ unarchive(msgid)
237
+ To unarchive a message
238
+
207
239
  update_preference(preference hash)
208
240
  To update preference setting
209
241
  hash is one of :max_page_size(25,50,100),:keyboard_shortcuts(true,false),:indicators(true,false),
@@ -233,7 +265,7 @@ disconnect()
233
265
  dump(query)
234
266
  To dump ALL it gets from URL query string, including headers.
235
267
 
236
- get_standard_box()
268
+ standard_box()
237
269
  To get an array of names of the "standard box" (Inbox, Starred, etc.)
238
270
 
239
271
  invite(email)
data/gmailer.rb ADDED
@@ -0,0 +1,1314 @@
1
+ #
2
+ # = gmailer.rb: A class for interface to Google's webmail service
3
+ #
4
+ # Author:: Park Heesob
5
+ #
6
+ # project home page: http://rubyforge.org/projects/gmailutils
7
+ #
8
+
9
+ # $D_ON = false
10
+
11
+ require 'net/https'
12
+
13
+ GM_LNK_GMAIL = "/mail/"
14
+ GM_LNK_HOST = "mail.google.com"
15
+ GM_LNK_LOGIN = "/accounts/ServiceLoginAuth"
16
+ GM_LNK_LOGOUT = "/mail/?logout"
17
+ GM_LNK_ATTACHMENT = "/mail/?view=att&disp=att"
18
+ GM_LNK_ATTACHMENT_ZIPPED = "/mail/?view=att&disp=zip"
19
+
20
+ GM_USER_AGENT = "Mozilla/5.0 (X11 U Linux i686 en-US rv:1.4b) Gecko/20040612 Mozilla Firebird/0.9"
21
+
22
+ GM_STANDARD = 0x001
23
+ GM_LABEL = 0x002
24
+ GM_CONVERSATION = 0x004
25
+ GM_QUERY = 0x008
26
+ GM_CONTACT = 0x010
27
+ GM_PREFERENCE = 0x020
28
+
29
+ GM_ACT_CREATELABEL = 1
30
+ GM_ACT_DELETELABEL = 2
31
+ GM_ACT_RENAMELABEL = 3
32
+ GM_ACT_APPLYLABEL = 4
33
+ GM_ACT_REMOVELABEL = 5
34
+ GM_ACT_PREFERENCE = 6
35
+ GM_ACT_STAR = 7
36
+ GM_ACT_UNSTAR = 8
37
+ GM_ACT_SPAM = 9
38
+ GM_ACT_UNSPAM = 10
39
+ GM_ACT_READ = 11
40
+ GM_ACT_UNREAD = 12
41
+ GM_ACT_TRASH = 13
42
+ GM_ACT_DELFOREVER = 14
43
+ GM_ACT_ARCHIVE = 15
44
+ GM_ACT_INBOX = 16
45
+ GM_ACT_UNTRASH = 17
46
+ GM_ACT_UNDRAFT = 18
47
+ GM_ACT_TRASHMSG = 19 # trash individual message
48
+ GM_ACT_DELSPAM = 20 # delete spam, forever
49
+ GM_ACT_DELTRASHED = 21 # delete trash message, forever
50
+
51
+ class GMailer
52
+
53
+ VERSION = "0.0.6"
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
212
+
213
+ # Singleton method
214
+ # return bool
215
+ # desc Connect to GMail with default session management settings.
216
+ #
217
+
218
+ def GMailer.connect(*param)
219
+ g = GMailer.new(*param)
220
+ g.connect_no_cookie()
221
+ if block_given?
222
+ yield(g)
223
+ g.disconnect()
224
+ else
225
+ g
226
+ end
227
+ end
228
+
229
+
230
+ #
231
+ # return bool
232
+ # desc See if it is connected to GMail.
233
+ #
234
+ def is_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 is_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 is_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 is_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 is_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 is_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 is_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 is_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 is_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 is_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 is_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 is_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 is_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 is_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 is_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 archive a message
649
+ #
650
+ def archive(msgid)
651
+ if is_connected()
652
+ perform_action(GM_ACT_ARCHIVE,msgid, '')
653
+ else
654
+ false
655
+ end
656
+ end
657
+
658
+ #
659
+ # return boolean
660
+ # param string msgid
661
+ # desc archive a message
662
+ #
663
+ def unarchive(msgid)
664
+ if is_connected()
665
+ perform_action(GM_ACT_INBOX,msgid, '')
666
+ else
667
+ false
668
+ end
669
+ end
670
+
671
+ #
672
+ # return hash of preference
673
+ # desc get preferences
674
+ #
675
+ def preference()
676
+ if is_connected()
677
+ fetch(:preference=>"all").preference
678
+ else
679
+ nil
680
+ end
681
+ end
682
+
683
+ #
684
+ # return array of messages
685
+ # desc get message lists
686
+ #
687
+ def messages(hash_param)
688
+ if is_connected()
689
+ fetch(hash_param) {|s| s.box }
690
+ else
691
+ nil
692
+ end
693
+ end
694
+
695
+ #
696
+ # return string
697
+ # param string query
698
+ # desc Dump everything to output.
699
+ #
700
+ def dump(query)
701
+ page = ''
702
+ if is_connected()
703
+ Debugger::say("Dumping...")
704
+ query += "&zv=" + (rand(2000)*2147483.648).to_i.to_s
705
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
706
+ np.start { |http|
707
+ response = http.get(GM_LNK_GMAIL + "?"+query,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
708
+ page = response.body
709
+ }
710
+
711
+ Debugger::say("Finished dumping " + page.length.to_s + " bytes.")
712
+ else # not logged in yet
713
+ Debugger::say("Failed to dump: not connected.")
714
+ end
715
+ page
716
+ end
717
+
718
+ def stripslashes(string)
719
+ encode(string.gsub("\\\"", "\"").gsub("\\'", "'").gsub("\\\\", "\\"))
720
+ end
721
+
722
+
723
+ #
724
+ # return bool
725
+ # param string to
726
+ # param string subject
727
+ # param string body
728
+ # param string cc
729
+ # param string bcc
730
+ # param string msg_id
731
+ # param string thread_id
732
+ # param string[] files
733
+ # desc Send GMail.
734
+ #
735
+ def send(*param)
736
+ if param.length==1 && param[0].class==Hash
737
+ param = param[0]
738
+ to = param[:to] || ''
739
+ subject = param[:subject] || ''
740
+ body = param[:body] || ''
741
+ cc = param[:cc] || ''
742
+ bcc = param[:bcc] || ''
743
+ msg_id = param[:msg_id] || ''
744
+ thread_id = param[:msg_id] || ''
745
+ files = param[:files] || []
746
+ draft = param[:draft] || false
747
+ draft_id = param[:draft_id] || ''
748
+ elsif param.length==10
749
+ to, subject, body, cc, bcc, msg_id, thread_id, files, draft, draft_id = param
750
+ else
751
+ raise ArgumentError, 'Invalid argument'
752
+ end
753
+
754
+ if is_connected()
755
+ Debugger::say("Starting to send mail...")
756
+
757
+ postdata = {}
758
+ if draft
759
+ postdata["view"] = "sd"
760
+ postdata["draft"] = draft_id
761
+ postdata["rm"] = msg_id
762
+ postdata["th"] = thread_id
763
+ else
764
+ postdata["view"] = "sm"
765
+ postdata["draft"] = draft_id
766
+ postdata["rm"] = msg_id
767
+ postdata["th"] = thread_id
768
+ end
769
+ postdata["msgbody"] = stripslashes(body)
770
+ postdata["to"] = stripslashes(to)
771
+ postdata["subject"] = stripslashes(subject)
772
+ postdata["cc"] = stripslashes(cc)
773
+ postdata["bcc"] = stripslashes(bcc)
774
+
775
+ postdata["cmid"] = 1
776
+ postdata["ishtml"] = 0
777
+
778
+ cc = @cookie_str.split(';')
779
+ cc.each {|cc_part|
780
+ cc_parts = cc_part.split('=')
781
+ if(cc_parts[0]=='GMAIL_AT')
782
+ postdata["at"] = cc_parts[1]
783
+ break
784
+ end
785
+ }
786
+
787
+ boundary = "----#{Time.now.to_i}#{(rand(2000)*2147483.648).to_i}"
788
+ postdata2 = []
789
+ postdata.each {|k,v|
790
+ postdata2.push("Content-Disposition: form-data; name=\"#{k}\"\r\n\r\n#{v}\r\n")
791
+ }
792
+
793
+ files.each_with_index {|f,i|
794
+ content = File.open(f,'rb') { |c| c.read }
795
+ postdata2.push("Content-Disposition: form-data; name=\"file#{i}\"; filename=\"#{File.basename(f)}\"\r\n" +
796
+ "Content-Transfer-Encoding: binary\r\n" +
797
+ "Content-Type: application/octet-stream\r\n\r\n" + content + "\r\n")
798
+ }
799
+
800
+ postdata = postdata2.collect { |p|
801
+ "--" + boundary + "\r\n" + p
802
+ }.join('') + "--" + boundary + "--\r\n"
803
+
804
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
805
+ response = nil
806
+ # np.set_debug_output($stderr)
807
+ np.start { |http|
808
+ response = http.post(GM_LNK_GMAIL, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT,'Content-type' => 'multipart/form-data; boundary=' + boundary } )
809
+ }
810
+ Debugger::say("Finished sending email.")
811
+ true
812
+ else
813
+ Debugger::say("Failed to send email: not connected.")
814
+ false
815
+ end
816
+
817
+ end
818
+
819
+ #
820
+ # return bool
821
+ # param constant act
822
+ # param string[] id
823
+ # param string para
824
+ # desc Perform action on messages.
825
+ #
826
+ def perform_action(act, id, para)
827
+
828
+ if is_connected()
829
+ Debugger::say("Start performing action...")
830
+
831
+ if (act == GM_ACT_DELFOREVER)
832
+ perform_action(GM_ACT_TRASH, id, 0) # trash it before
833
+ end
834
+ postdata = "act="
835
+
836
+ action_codes = ["ib", "cc_", "dc_", "nc_", "ac_", "rc_", "prefs", "st", "xst",
837
+ "sp", "us", "rd", "ur", "tr", "dl", "rc_^i", "ib", "ib", "dd", "dm", "dl", "dl"]
838
+ postdata += action_codes[act] ? action_codes[act] : action_codes[GM_ACT_INBOX]
839
+ if ([GM_ACT_APPLYLABEL,GM_ACT_REMOVELABEL,GM_ACT_CREATELABEL,
840
+ GM_ACT_DELETELABEL,GM_ACT_RENAMELABEL,GM_ACT_PREFERENCE].include?(act))
841
+ postdata += para.to_s
842
+ end
843
+
844
+ cc = @cookie_str.split(';')
845
+ cc.each {|cc_part|
846
+ cc_parts = cc_part.split('=')
847
+ if(cc_parts[0]=='GMAIL_AT')
848
+ postdata += "&at=" + cc_parts[1]
849
+ break
850
+ end
851
+ }
852
+
853
+ if (act == GM_ACT_TRASHMSG)
854
+ postdata += "&m=" + id.to_s
855
+ else
856
+ if id.class==Array
857
+ id.each {|t| postdata += "&t="+t.to_s }
858
+ else
859
+ postdata += "&t="+id.to_s
860
+ end
861
+ end
862
+ postdata += "&vp="
863
+
864
+ if [GM_ACT_UNTRASH,GM_ACT_DELFOREVER,GM_ACT_DELTRASHED].include?(act)
865
+ link = GM_LNK_GMAIL+"?search=trash&view=tl&start=0"
866
+ elsif (act == GM_ACT_DELSPAM)
867
+ link = GM_LNK_GMAIL+"?search=spam&view=tl&start=0"
868
+ else
869
+ link = GM_LNK_GMAIL+"?search=query&q=&view=tl&start=0"
870
+ end
871
+
872
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
873
+ # np.set_debug_output($stderr)
874
+ np.start { |http|
875
+ response = http.post(link, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
876
+ result = response.body
877
+ }
878
+
879
+ Debugger::say("Finished performing action.")
880
+ return true
881
+ else
882
+ Debugger::say("Failed to perform action: not connected.")
883
+ return false
884
+ end
885
+
886
+ end
887
+
888
+ #
889
+ # return void
890
+ # desc Disconnect from GMail.
891
+ #
892
+ def disconnect()
893
+ Debugger::say("Start disconnecting...")
894
+
895
+ response = nil
896
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
897
+ # np.set_debug_output($stderr)
898
+ np.start { |http|
899
+ response = http.get(GM_LNK_LOGOUT,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT })
900
+ }
901
+ arr = URI::split(response["Location"])
902
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(arr[2], 80)
903
+ # np.set_debug_output($stderr)
904
+ np.start { |http|
905
+ response = http.get(arr[5]+'?'+arr[7], {'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
906
+ }
907
+
908
+ Debugger::say("Logged-out from GMail.")
909
+ @cookie_str = ''
910
+ Debugger::say("Completed disconnecting.")
911
+ end
912
+
913
+ #
914
+ # return GMailSnapshot
915
+ # param constant type
916
+ # desc Get GMSnapshot by type.
917
+ #
918
+ def snapshot(type)
919
+ if [GM_STANDARD,GM_LABEL,GM_CONVERSATION,GM_QUERY,GM_PREFERENCE,GM_CONTACT].include?(type)
920
+ return GMailSnapshot.new(type, @raw, @charset)
921
+ else
922
+ return GMailSnapshot.new(GM_STANDARD, @raw, @charset) # assuming normal by default
923
+ end
924
+ end
925
+
926
+ def snap(type)
927
+ action = GM_STANDARD
928
+ case type
929
+ when :standard
930
+ action = GM_STANDARD
931
+ when :label
932
+ action = GM_LABEL
933
+ when :conversation
934
+ action = GM_CONVERSATION
935
+ when :query
936
+ action = GM_QUERY
937
+ when :preference
938
+ action = GM_PREFERENCE
939
+ when :contact
940
+ action = GM_CONTACT
941
+ else
942
+ raise ArgumentError, 'Invalid type'
943
+ end
944
+ snapshot(action)
945
+ end
946
+
947
+ #
948
+ # return bool
949
+ # param string email
950
+ # desc Send Gmail invite to email
951
+ #
952
+ def invite(email)
953
+
954
+ if is_connected()
955
+ Debugger::say("Start sending invite...")
956
+
957
+ postdata = "act=ii&em=" + URI.escape(email)
958
+
959
+ cc = @cookie_str.split(';')
960
+ cc.each {|cc_part|
961
+ cc_parts = cc_part.split('=')
962
+ if(cc_parts[0]=='GMAIL_AT')
963
+ postdata += "&at=" + cc_parts[1]
964
+ break
965
+ end
966
+ }
967
+
968
+ link = GM_LNK_GMAIL + "?view=ii"
969
+
970
+ np = Net::HTTP::Proxy(@proxy_host,@proxy_port,@proxy_user,@proxy_pass).new(GM_LNK_HOST, 80)
971
+ np.use_ssl = true
972
+ np.verify_mode = OpenSSL::SSL::VERIFY_NONE
973
+ # np.set_debug_output($stderr)
974
+ np.start { |http|
975
+ response = http.post(link, postdata,{'Cookie' => @cookie_str,'User-agent' => GM_USER_AGENT} )
976
+ }
977
+
978
+ Debugger::say("Finished sending invite.")
979
+ true
980
+ else
981
+ Debugger::say("Failed to send invite: not connected.")
982
+ false
983
+ end
984
+
985
+ end
986
+
987
+ #
988
+ # return string[]
989
+ # desc (Static) Get names of standard boxes.
990
+ #
991
+ def standard_box()
992
+ ["Inbox","Starred","Sent","Drafts","All","Spam","Trash"]
993
+ end
994
+
995
+ #
996
+ # return string
997
+ # param string header
998
+ # desc (Static Private) Extract cookies from header.
999
+ #
1000
+ def __cookies(header)
1001
+ return '' unless header
1002
+ arr = []
1003
+ header.split(', ').each { |x|
1004
+ if x.include?('GMT')
1005
+ arr[-1] += ", " + x
1006
+ else
1007
+ arr.push x
1008
+ end
1009
+ }
1010
+ arr.delete_if {|x| x.include?('LSID=EXPIRED') }
1011
+ arr.map! {|x| x.split(';')[0]}
1012
+ arr.join(';')
1013
+ end
1014
+
1015
+ end
1016
+
1017
+
1018
+ class GMailSnapshot
1019
+
1020
+ GM_STANDARD = 0x001
1021
+ GM_LABEL = 0x002
1022
+ GM_CONVERSATION = 0x004
1023
+ GM_QUERY = 0x008
1024
+ GM_CONTACT = 0x010
1025
+ GM_PREFERENCE = 0x020
1026
+
1027
+ def decode(str)
1028
+ return str if @charset.upcase == 'UTF-8'
1029
+ begin
1030
+ require 'Win32API'
1031
+ str = str.unpack("U*").pack("S*") + "\0"
1032
+ ostr = "\0" * 256
1033
+ wideCharToMultiByte = Win32API.new('kernel32','WideCharToMultiByte',['L','L','P','L','P','L','L','L'],'L')
1034
+ wideCharToMultiByte.Call(0,0,str,-1,ostr,256,0,0)
1035
+ ostr.strip
1036
+ rescue LoadError
1037
+ require 'iconv'
1038
+ Iconv::iconv(@charset,'UTF-8',str)[0]
1039
+ end
1040
+ end
1041
+
1042
+ def strip_tags(str,allowable_tags='')
1043
+ str.gsub(/<[^>]*>/, '')
1044
+ end
1045
+
1046
+ #
1047
+ # return GMailSnapshot
1048
+ # param constant type
1049
+ # param array raw
1050
+ # desc Constructor.
1051
+ #
1052
+ attr_reader :gmail_ver, :quota_mb, :quota_per, :preference
1053
+ attr_reader :std_box_new, :have_invit, :label_list, :label_new
1054
+ attr_reader :box_name, :box_total, :box_pos, :box
1055
+ attr_reader :conv_title, :conv_total, :conv_id, :conv_labels, :conv_starred, :conv
1056
+ attr_reader :contacts
1057
+
1058
+ def initialize(type, raw, charset='UTF-8')
1059
+
1060
+ @charset = charset
1061
+ if (raw.class!=Hash)
1062
+ @created = 0
1063
+ return nil
1064
+ elsif (raw.empty?)
1065
+ @created = 0
1066
+ return nil
1067
+ end
1068
+ if [GM_STANDARD,GM_LABEL,GM_CONVERSATION,GM_QUERY].include?(type)
1069
+ @gmail_ver = raw["v"][1]
1070
+ if raw["qu"]
1071
+ @quota_mb = raw["qu"][1]
1072
+ @quota_per = raw["qu"][3]
1073
+ end
1074
+ if (raw["ds"].class!=Array)
1075
+ @created = 0
1076
+ return nil
1077
+ end
1078
+ @std_box_new = raw["ds"][1..-1]
1079
+ #if (isset(raw["p"])) {
1080
+ # @owner = raw["p"][5][1]
1081
+ # @owner_email = raw["p"][6][1]
1082
+ #end
1083
+ @have_invit = raw["i"][1]
1084
+ @label_list = []
1085
+ @label_new = []
1086
+ raw["ct"][1].each {|v|
1087
+ @label_list.push(v[0])
1088
+ @label_new.push(v[1])
1089
+ }
1090
+ if raw["ts"]
1091
+ @view = (GM_STANDARD|GM_LABEL|GM_QUERY)
1092
+ @box_name = raw["ts"][5]
1093
+ @box_total = raw["ts"][3]
1094
+ @box_pos = raw["ts"][1]
1095
+ end
1096
+ @box = []
1097
+ if raw["t"]
1098
+ raw["t"].each {|t|
1099
+ if (t != "t")
1100
+ b = {
1101
+ "id"=>t[0],
1102
+ "is_read"=>(t[1] != 1 ? 1 : 0),
1103
+ "new?"=>(t[1] == 1),
1104
+ "is_starred"=>(t[2] == 1 ? 1 : 0),
1105
+ "star?"=>(t[2] == 1),
1106
+ "date"=>decode(strip_tags(t[3])),
1107
+ "sender"=>decode(strip_tags(t[4])),
1108
+ "flag"=>t[5],
1109
+ "subject"=>decode(strip_tags(t[6])),
1110
+ "snippet"=>decode(t[7]),
1111
+ "labels"=>t[8].empty? ? [] : t[8].map{|tt|decode(tt)},
1112
+ "attachment"=>t[9].empty? ? []: decode(t[9]).split(","),
1113
+ "msgid"=>t[10]
1114
+ }
1115
+ @box.push(b)
1116
+ end
1117
+ }
1118
+ end
1119
+
1120
+ if (!raw["cs"].nil?)
1121
+ @view = GM_CONVERSATION
1122
+ @conv_title = raw["cs"][2]
1123
+ @conv_total = raw["cs"][8]
1124
+ @conv_id = raw["cs"][1]
1125
+ @conv_labels = raw["cs"][5].empty? ? '' : raw["cs"][5]
1126
+ if !@conv_labels.empty?
1127
+ ij = @conv_labels.index("^i")
1128
+ if !ij.nil?
1129
+ @conv_labels[ij] = "Inbox"
1130
+ end
1131
+ ij = @conv_labels.index("^s")
1132
+ if !ij.nil?
1133
+ @conv_labels[ij] = "Spam"
1134
+ end
1135
+ ij = @conv_labels.index("^k")
1136
+ if !ij.nil?
1137
+ @conv_labels[ij] = "Trash"
1138
+ end
1139
+ ij = @conv_labels.index("^t")
1140
+ if !ij.nil?
1141
+ @conv_labels[ij] = '' # Starred
1142
+ end
1143
+ ij = @conv_labels.index("^r")
1144
+ if !ij.nil?
1145
+ @conv_labels[ij] = "Drafts"
1146
+ end
1147
+ end
1148
+
1149
+ @conv_starred = false
1150
+
1151
+ @conv = []
1152
+ b = {}
1153
+ raw["mg"].each {|r|
1154
+ if (r[0] == "mb" && !b.empty?)
1155
+ b["body"] += r[1]
1156
+ if (r[2] == 0)
1157
+ @conv.push(b)
1158
+ b = {}
1159
+ end
1160
+ elsif (r[0] == "mi")
1161
+ if !b.empty?
1162
+ @conv.push(b)
1163
+ b = {}
1164
+ end
1165
+ b = {}
1166
+ b["index"] = r[2]
1167
+ b["id"] = r[3]
1168
+ b["is_star"] = r[4]
1169
+ if (b["is_star"] == 1)
1170
+ @conv_starred = true
1171
+ end
1172
+ b["sender"] = r[6]
1173
+ b["sender_email"] = r[8].gsub("\"",'') # remove annoying d-quotes in address
1174
+ b["recv"] = r[9]
1175
+ b["recv_email"] = r[11].to_s.gsub("\"",'')
1176
+ b["reply_email"] = r[14].to_s.gsub("\"",'')
1177
+ b["dt_easy"] = r[10]
1178
+ b["dt"] = r[15]
1179
+ b["subject"] = r[16]
1180
+ b["snippet"] = r[17]
1181
+ b["attachment"] = []
1182
+ r[18].each {|bb|
1183
+ b["attachment"].push({"id"=>bb[0],"filename"=>bb[1],"type"=>bb[2],"size"=>bb[3]})
1184
+ }
1185
+ b["is_draft"] = false
1186
+ b["body"] = ''
1187
+ elsif (r[0] == "di")
1188
+ if !b.empty?
1189
+ @conv.push(b)
1190
+ b = {}
1191
+ end
1192
+ b = {}
1193
+ b["index"] = r[2]
1194
+ b["id"] = r[3]
1195
+ b["is_star"] = r[4]
1196
+ @conv_starred = (b["is_star"] == 1)
1197
+ b["sender"] = r[6]
1198
+ b["sender_email"] = r[8].gsub("\"",'') # remove annoying d-quotes in address
1199
+ b["recv"] = r[9]
1200
+ b["recv_email"] = r[11].gsub("\"",'')
1201
+ b["reply_email"] = r[14].gsub("\"",'')
1202
+ b["cc_email"] = r[12].gsub("\"",'')
1203
+ b["bcc_email"] = r[13].gsub("\"",'')
1204
+ b["dt_easy"] = r[10]
1205
+ b["dt"] = r[15]
1206
+ b["subject"] = r[16]
1207
+ b["snippet"] = r[17]
1208
+ b["attachment"] = []
1209
+ r[18].each {|bb|
1210
+ b["attachment"].push({"id"=>bb[0],"filename"=>bb[1],"type"=>bb[2],"size"=>bb[3]})
1211
+ }
1212
+ b["is_draft"] = true
1213
+ b["draft_parent"] = r[5]
1214
+ b["body"] = r[20]
1215
+ end
1216
+ }
1217
+ @conv.push(b) unless b.empty?
1218
+ end
1219
+ elsif type == GM_CONTACT
1220
+ @contacts = []
1221
+ if raw["ce"]
1222
+ raw["ce"].each {|a|
1223
+ b = {
1224
+ "name"=>a[2],
1225
+ "email"=>a[4].gsub("\"",'')
1226
+ }
1227
+ if !a[5].empty?
1228
+ b["notes"] = a[5]
1229
+ end
1230
+ @contacts.push(b)
1231
+ }
1232
+ end
1233
+ @view = GM_CONTACT
1234
+ elsif type == GM_PREFERENCE
1235
+ prefs = {}
1236
+ raw["p"].each_with_index { |v,i|
1237
+ prefs[v[0]] = v[1] if i>0
1238
+ }
1239
+ @preference = {'max_page_size'=>'10',
1240
+ 'keyboard_shortcuts'=>false,
1241
+ 'indicators'=>false,
1242
+ 'display_language'=>'en',
1243
+ 'signature'=>'',
1244
+ 'reply_to'=>'',
1245
+ 'snippets'=>false,
1246
+ 'display_name'=>'',
1247
+ }
1248
+ prefs.each do |k,v|
1249
+ case k
1250
+ when 'ix_nt'
1251
+ @preference['max_page_size'] = v
1252
+ when 'bx_hs'
1253
+ @preference['keyboard_shortcuts'] = (v == '1')
1254
+ when 'bx_sc'
1255
+ @preference['indicators'] = (v == '1')
1256
+ when 'sx_dl'
1257
+ @preference['display_language'] = v
1258
+ when 'sx_sg'
1259
+ @preference['signature'] = (v == '0') ? '' : v
1260
+ when 'sx_rt'
1261
+ @preference['reply_to'] = v
1262
+ when 'bx_ns'
1263
+ @preference['snippets'] = (v == '0')
1264
+ when 'sx_dn'
1265
+ @preference['display_name'] = v
1266
+ end
1267
+ end
1268
+
1269
+ @label_list = []
1270
+ @label_total = []
1271
+ raw["cta"][1].each { |v|
1272
+ @label_list.push(v[0])
1273
+ @label_total.push(v[1])
1274
+ }
1275
+ @filter = []
1276
+ @filter_rules = []
1277
+ raw["fi"][1].each { |fi|
1278
+ b = {
1279
+ "id" => fi[0],
1280
+ "query" => fi[1],
1281
+ "star" => fi[3],
1282
+ "label" => fi[4],
1283
+ "archive" => fi[5],
1284
+ "trash" => fi[6] #,"forward" => fi[7]
1285
+ }
1286
+ bb = {
1287
+ "from" => fi[2][0],
1288
+ "to" => fi[2][1],
1289
+ "subject" => fi[2][2],
1290
+ "has" => fi[2][3],
1291
+ "hasnot" => fi[2][4],
1292
+ "attach" => fi[2][5]
1293
+ }
1294
+
1295
+ @filter.push(b)
1296
+ @filter_rules.push(bb)
1297
+ }
1298
+ @view = GM_PREFERENCE
1299
+ else
1300
+ @created = 0
1301
+ return nil
1302
+ end
1303
+ @created = 1
1304
+ end
1305
+
1306
+ end
1307
+
1308
+
1309
+ class Debugger
1310
+ def Debugger.say(str)
1311
+ puts str if $D_ON
1312
+ end
1313
+ end
1314
+