public
Description: A RubyCocoa Gmail Notifier for Mac OS X
Homepage: http://ashchan.com/projects/gmail-notifr
Clone URL: git://github.com/ashchan/gmail-notifr.git
Click here to lend your support to: gmail-notifr and make a donation at www.pledgie.com !
gmail-notifr / GNChecker.rb
100644 189 lines (146 sloc) 4.783 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#
# GNChecker.rb
# Gmail Notifr
#
# Created by James Chen on 8/27/09.
# Copyright (c) 2009 ashchan.com. All rights reserved.
#
 
require 'osx/cocoa'
 
class GNChecker < OSX::NSObject
  def init
    super_init
  end
  
  def initWithAccount(account)
    init
    @account = account
    @guid = account.guid
    @messages = []
    
    @checker_path = NSBundle.mainBundle.pathForAuxiliaryExecutable('gmailchecker')
 
    self
  end
  
  def forAccount?(account)
    account.guid == @account.guid
  end
  
  def forGuid?(guid)
    @guid == guid
  end
  
  def userError?
    @userError
  end
  
  def connectionError?
    @connectionError
  end
  
  def messages
    @messages
  end
  
  def messageCount
    return 0 unless @account && @account.enabled?
    @messageCount || 0
  end
  
  def reset
    cleanup
    NSNotificationCenter.defaultCenter.postNotificationName_object_userInfo(GNCheckingAccountNotification, self, :guid => @account.guid)
 
    if @account && @account.enabled?
      @timer = NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats(
        @account.interval * 60, self, 'checkMail', nil, true)
 
      @checker = NSTask.alloc.init
      @checker.setCurrentDirectoryPath(@checker_path.stringByDeletingLastPathComponent)
      @checker.setLaunchPath(@checker_path)
 
      
      args = NSMutableArray.alloc.init
      args.addObject(@account.username.to_s)
      # pass password as base64 encoded to gmailchecker
      args.addObject([@account.password.to_s].pack("m"))
      @checker.setArguments(args)
      
      @pipe = NSPipe.alloc.init
      @checker.setStandardOutput(@pipe)
  
      nc = NSNotificationCenter.defaultCenter
      fn = @pipe.fileHandleForReading
      nc.addObserver_selector_name_object(self, 'checkResult', NSFileHandleReadToEndOfFileCompletionNotification, fn)
      
      @checker.launch
      
      fn.readToEndOfFileInBackgroundAndNotify
    else
      notifyMenuUpdate
    end
  end
  
  def checkMail
    reset
  end
  
  def checkResult(notification)
    @checkedAt = DateTime.now
    
    preferences = GNPreferences.sharedInstance
 
    results = YAML.load(
      NSString.alloc.initWithData_encoding(
        notification.userInfo.valueForKey(NSFileHandleNotificationDataItem),
        NSUTF8StringEncoding
      )
    )
    
    result = results[@account.username.to_s]
    return unless result
    
    @messages.clear
    @messageCount = result[:count]
    @connectionError = result[:error] == "ConnectionError"
    @userError = result[:error] == "UserError"
 
    result[:messages].each do |msg|
      @messages << {
        :subject => msg[:subject],
        :author => msg[:author],
        :link => normalizeMessageLink(msg[:link]),
        :id => msg[:id],
        :date => msg[:date],
        :summary => msg[:summary]
      }
    end
    
    shouldNotify = @account.enabled? && @messages.size > 0
    if shouldNotify
      newestDate = @messages.map { |m| m[:date] }.sort[-1]
      
      if @newestDate
        shouldNotify = newestDate > @newestDate
      end
 
      @newestDate = newestDate
    end
    
    notifyMenuUpdate
    
    if shouldNotify && @account.growl
      info = @messages.map { |m| "#{m[:subject]}\nFrom: #{m[:author]}" }.join("\n#{'-' * 30}\n\n")
      if @messageCount > @messages.size
        info += "\n\n..."
      end
      
      unreadCount = @messageCount == 1 ? NSLocalizedString("Unread Message") % @messageCount :
          NSLocalizedString("Unread Messages") % @messageCount
      
      notify(@account.username, [unreadCount, info].join("\n\n"))
    end
    if shouldNotify && @account.sound != GNSound::SOUND_NONE && sound = NSSound.soundNamed(@account.sound)
      sound.play
    end
  end
  
  def checkedAt
    @checkedAt ? @checkedAt.strftime("%H:%M") : "NA"
  end
  
  def notifyMenuUpdate
    NSNotificationCenter.defaultCenter.postNotificationName_object_userInfo(GNAccountMenuUpdateNotification, self, :guid => @account.guid, :checkedAt => checkedAt)
  end
  
  def notify(title, desc)
    Growl::Notifier.sharedInstance.notify('new_messages', title, desc, :click_context => title)
  end
  
  def cleanup
    @checker.interrupt and @checker = nil if @checker
    @timer.invalidate if @timer
    
    if @pipe
      NSNotificationCenter.defaultCenter.removeObserver_name_object(self, NSFileHandleReadToEndOfFileCompletionNotification, @pipe.fileHandleForReading)
    end
  end
  
  def cleanupAndQuit
    cleanup
    @timer = nil
    @pipe = nil
  end
  
  private
  def normalizeMessageLink(link)
    if @account.username.include?("@")
      domain = @account.username.split("@")[1]
      if domain != "gmail.com" && domain != "googlemail.com"
        link = link.gsub("/mail?", "/a/#{domain}/?")
      end
    end
    
    link
  end
end