Class: Imap

Inherits:
Object
  • Object
show all
Includes:
Cinch::Plugin
Defined in:
lib/cinch/plugins/imap.rb

Constant Summary collapse

VERSION =
'0.1.2'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Imap

Returns a new instance of Imap.



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
# File 'lib/cinch/plugins/imap.rb', line 55

def initialize(*args)
  super
  @monitor_debug = false
  @mail_host = config[:host]
  @mail_user = config[:user]
  @mail_password = config[:password]
  @mail_folder = config[:folder] || 'INBOX'
  @mail_port = config[:port] || 143
  @mail_ssl = config[:ssl] || false
  @mark_as_read = config[:mark_as_read ] || true
  @interval = config[:interval] || 300
  @subject_matches = config[:subject_matches] || {}
  @from_rewrites = config[:from_rewrites] || {}
  @autostart = config[:autostart] || false
  @retain_days = config[:retain_days] || 0
  @maintenance_hour = config[:maintenance_hour] || 10

  if config.has_key?(:count_database)
    @count_database = config[:count_database]
  else
    @count_database = File.join(Dir.tmpdir, 'count.yml')
  end

  # Load or initialize a hash of counts
  @count = load_count
end

Instance Attribute Details

#autostartObject (readonly)

Returns the value of attribute autostart.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def autostart
  @autostart
end

#countObject (readonly)

Returns the value of attribute count.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def count
  @count
end

#count_databaseObject (readonly)

Returns the value of attribute count_database.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def count_database
  @count_database
end

#count_incrementedObject (readonly)

Returns the value of attribute count_incremented.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def count_incremented
  @count_incremented
end

#from_rewritesObject (readonly)

Returns the value of attribute from_rewrites.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def from_rewrites
  @from_rewrites
end

#intervalObject (readonly)

Returns the value of attribute interval.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def interval
  @interval
end

#mail_folderObject (readonly)

Returns the value of attribute mail_folder.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def mail_folder
  @mail_folder
end

#mail_hostObject (readonly)

Returns the value of attribute mail_host.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def mail_host
  @mail_host
end

#mail_passwordObject (readonly)

Returns the value of attribute mail_password.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def mail_password
  @mail_password
end

#mail_portObject (readonly)

Returns the value of attribute mail_port.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def mail_port
  @mail_port
end

#mail_sslObject (readonly)

Returns the value of attribute mail_ssl.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def mail_ssl
  @mail_ssl
end

#mail_userObject (readonly)

Returns the value of attribute mail_user.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def mail_user
  @mail_user
end

#maintenance_hourObject (readonly)

Returns the value of attribute maintenance_hour.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def maintenance_hour
  @maintenance_hour
end

#maintenance_neededObject (readonly)

Returns the value of attribute maintenance_needed.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def maintenance_needed
  @maintenance_needed
end

#mark_as_readObject (readonly)

Returns the value of attribute mark_as_read.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def mark_as_read
  @mark_as_read
end

#pollerObject (readonly)

Returns the value of attribute poller.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def poller
  @poller
end

#poller_createdObject (readonly)

Returns the value of attribute poller_created.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def poller_created
  @poller_created
end

#poller_nextObject (readonly)

Returns the value of attribute poller_next.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def poller_next
  @poller_next
end

#retain_daysObject (readonly)

Returns the value of attribute retain_days.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def retain_days
  @retain_days
end

#subject_matchesObject (readonly)

Returns the value of attribute subject_matches.



50
51
52
# File 'lib/cinch/plugins/imap.rb', line 50

def subject_matches
  @subject_matches
end

Instance Method Details

#about(m) ⇒ Object



113
114
115
# File 'lib/cinch/plugins/imap.rb', line 113

def about(m)
  m.reply "Looks like I'm on version %s" % VERSION
end

#create_poller(m, seconds) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/cinch/plugins/imap.rb', line 13

def create_poller(m, seconds)
  poller.stop if poller
  @poller_created = Time.now
  @poller_next = (Time.now + seconds).strftime('%T')
  @poller = Timer(seconds) do
    @poller_next = (Time.now + poller.interval).strftime('%T')
    imap = imap_connect(m)
    m.reply "DEBUG: connected to imap" if @monitor_debug
    m.reply "DEBUG: imap is nil? %s" % imap.nil? if @monitor_debug
    imap_poll(m, imap) unless imap.nil?
    if maintenance_hour == Time.now.hour
      imap_purge(m, imap, retain_days) if maintenance_needed
      @maintenance_needed = false
    else
      @maintenance_needed = true
    end
    write(m, 'count') if count_incremented
    imap.disconnect unless imap.nil?
  end
end

#get_messages(m, conn) ⇒ Object



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/cinch/plugins/imap.rb', line 201

def get_messages(m, conn)
  m.reply "DEBUG: in get_messages with %s " % conn if @monitor_debug
  conn.search(["UNSEEN"]).each do |message_id|
    envelope = conn.fetch(message_id, "ENVELOPE")[0].attr["ENVELOPE"]
    name = envelope.from[0].name
    mailbox = envelope.from[0].mailbox
    #reply_to = envelope.reply_to[0]
    host = envelope.from[0].host
    from = name.nil? ? host : name
    subj = envelope.subject
    conn.store(message_id, "+FLAGS", [:Seen]) if mark_as_read
    m.reply("DEBUG: Found message") if @monitor_debug
    yield from, host, subj
  end
end

#get_old_date(days = retain_days) ⇒ Object



184
185
186
# File 'lib/cinch/plugins/imap.rb', line 184

def get_old_date(days = retain_days)
  (Time.now - 60 * 60 * 24 * days).strftime("%d-%b-%Y")
end

#imap_connect(m) ⇒ Object



217
218
219
220
221
222
223
224
225
# File 'lib/cinch/plugins/imap.rb', line 217

def imap_connect(m)
  connection = Net::IMAP.new(mail_host, mail_port, mail_ssl)
  connection.(mail_user, mail_password)
  connection.select(mail_folder)
  connection
rescue Net::IMAP::NoResponseError
  m.reply "Mail server %s is offline" % mail_server
  nil
end

#imap_poll(m, connection) ⇒ Object



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/cinch/plugins/imap.rb', line 227

def imap_poll(m, connection)
  m.reply "DEBUG: in imap_poll with %s" % connection if @monitor_debug

  # This is used by the write method.
  # It will be set to true if anything is returned from the poll
  @count_incremented = false

  get_messages(m, connection) do |from, host, subj|
    m.reply "DEBUG: returned from get_messages" if @monitor_debug
    message_from, message_prefix = from, nil
    from_rewrites.each do |k, v|
      message_from = "#{v}" if from =~ /#{k}/ or host == k
    end
    subject_matches.each do |k, v|
      message_prefix = "#{v}" if subj =~ /#{k}/
    end

    # for reporting
    case subj
    when /PROBLEM/
      @count[:problem] += 1 if count.has_key?(:problem)
    when /RECOVERY/
      @count[:recovery] += 1 if count.has_key?(:recovery)
    when /ACKNOWLEDGED/
      @count[:acknowledged] += 1 if count.has_key?(:acknowledged)
    else 
      @count[:other] += 1 if count.has_key?(:other)
    end
    m.reply "%s %s: %s" % [message_prefix, message_from, subj]

    @count_incremented = true
  end
end

#imap_purge(m, connection = imap_connect(m), retain = 0) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/cinch/plugins/imap.rb', line 188

def imap_purge(m, connection = imap_connect(m), retain = 0)
  m.reply "Time to make the donuts!"
  previous_date = get_old_date(retain)
  connection.search(["BEFORE", get_old_date]).each do |message_id|
    m.reply "Setting delete flag on #{message_id}"
    envelope = connection.fetch(message_id, "ENVELOPE")[0].attr["ENVELOPE"]
    connection.store(message_id, "+FLAGS", [:Deleted])
  end
  m.reply "Running expunge"
  connection.expunge
  m.reply "Complete"
end

#imap_test(m) ⇒ Object



171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/cinch/plugins/imap.rb', line 171

def imap_test(m)
  begin
    imap = imap_connect(m)
    status = []
    status << "Retain Days: %s" % retain_days
    status << "Before: %s" % imap.search(["BEFORE", get_old_date]).length
    status << "Since: %s" % imap.search(["SINCE", get_old_date]).length
    status << "Unseen: %s" % imap.search(["UNSEEN"]).length
    status << "Seen: %s" % imap.search(["NOT", "NEW"]).length
    imap.disconnect
    m.reply status.join(', ')
  end
end

#listen(m) ⇒ Object



34
35
36
# File 'lib/cinch/plugins/imap.rb', line 34

def listen(m)
  create_poller(m, interval) if autostart
end

#load_count(timestamp = year_and_month) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
# File 'lib/cinch/plugins/imap.rb', line 82

def load_count(timestamp = year_and_month)
  # load a hash where YYYY-MM is used for each key
  YAML.load_file(count_database).fetch(timestamp)
rescue
  if count.is_a?(Hash)
    "No data found for #{timestamp}"
  else
    # initialize
    Hash[:problem, 0, :recovery, 0, :acknowledged, 0, :other, 0]
  end
end

#monitor(m, option) ⇒ Object



120
121
122
123
124
125
126
127
128
# File 'lib/cinch/plugins/imap.rb', line 120

def monitor(m, option)
  action = case option
           when "on", "start"
             :start
           when "off", "stop"
             :stop
           end
  poller.send(action)
end

#monitor_debug(m, option) ⇒ Object



129
130
131
# File 'lib/cinch/plugins/imap.rb', line 129

def monitor_debug(m, option)
  @monitor_debug = option == "on"
end

#set_interval(m, sec) ⇒ Object



116
117
118
119
# File 'lib/cinch/plugins/imap.rb', line 116

def set_interval(m, sec)
  seconds = sec.to_i
  create_poller(m, seconds)
end

#show(m, command, timestamp = year_and_month) ⇒ Object



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
# File 'lib/cinch/plugins/imap.rb', line 132

def show(m, command, timestamp = year_and_month)
  case command
  when /config/
    config.each do |k, v|
    m.reply "#{k}: #{config[k]}" unless k == :password
    end
  when /count/

    # Check formatting of argument
    case timestamp
    when /^\d{4}-\d{2}$/

      # A past month may have been requested
      data = timestamp == year_and_month ? count : load_count(timestamp)
      counts = []
      data.each do |k,v|
        counts << "#{k.capitalize}: #{v}"
      end if data.is_a?(Hash)

      response = data.is_a?(Hash) ? counts.join(', ') : data
    else
      response = "Optional timestamp must be in YYYY-MM format." 
    end

  m.reply response
  when /status/
    message = []
    message << "Enabled: %s" % poller.started?
    message << "Interval: %s" % poller.interval.to_i
    message << "Next: %s" % poller_next if poller.started?
    m.reply message.join(', ')
  else
    usage(m)
  end
end

#usage(m) ⇒ Object



167
168
169
170
# File 'lib/cinch/plugins/imap.rb', line 167

def usage(m)
  m.reply "Usage: !monitor <command>"
  m.reply "Commands: start, stop, on, off, test, interval <seconds>, show <config|count [YYYY-MM]|status>"
end

#write(m, command) ⇒ Object

write to the file system



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/cinch/plugins/imap.rb', line 98

def write(m, command)
  case command
  when /count/
    # read in existing data or create a new hash
    data = YAML.load_file(count_database) || Hash.new
    # add to it
    data[year_and_month] = count
    # write it out
    open(count_database, 'w') { |f| f.puts data.to_yaml }
  else
    usage(m)
  end
rescue => e
  m.reply e
end

#year_and_monthObject



93
94
95
# File 'lib/cinch/plugins/imap.rb', line 93

def year_and_month
  "#{Time.now.year}-#{Time.now.strftime('%m')}"
end