gmailer 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+