2
Feed2Imap - RSS/Atom Aggregator uploading to an IMAP Server, or local Maildir
3
Copyright (c) 2009 Andreas Rottmann
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program. If not, see <http://www.gnu.org/licenses/>.
24
MYHOSTNAME = Socket.gethostname
28
def putmail(folder, mail, date = Time::now)
29
store_message(folder_dir(folder), date, nil) do |f|
34
def updatemail(folder, mail, idx, date = Time::now)
35
dir = folder_dir(folder)
36
guarantee_maildir(dir)
37
mail_files = find_mails(dir, idx)
39
if mail_files.length > 0
40
# get the info from the first result and delete everything
41
info = maildir_file_info(mail_files[0])
42
mail_files.each { |f| File.delete(File.join(dir, f)) }
44
store_message(dir, date, info) { |f| f.puts(mail) }
51
def cleanup(folder, dryrun = false)
52
dir = folder_dir(folder)
53
puts "-- Considering #{dir}:"
54
guarantee_maildir(dir)
57
recent_time = Time.now() -- (3 * 24 * 60 * 60) # 3 days
58
Dir[File.join(dir, 'cur', '*')].each do |fn|
59
flags = maildir_file_info_flags(fn)
60
# don't consider not-seen, flagged, or recent messages
61
mtime = File.mtime(fn)
62
next if (not flags.index('S') or
66
mail = RMail::Parser.read(f)
69
puts "To remove: #{subject} #{mtime}"
71
puts "Removing: #{subject} #{mtime}"
76
puts "-- Deleted #{del_count} messages"
82
def folder_dir(folder)
83
return File.join('/', folder)
86
def store_message(dir, date, info, &block)
89
guarantee_maildir(dir)
96
new_fn = new_maildir_basefn
97
tmp_path = File.join(dir, 'tmp', new_fn)
98
new_path = File.join(dir, 'new', new_fn)
100
fd = IO::sysopen(tmp_path,
101
Fcntl::O_WRONLY | Fcntl::O_EXCL | Fcntl::O_CREAT)
113
# provide a writable interface for the caller
116
File.link tmp_path, new_path
119
File.unlink tmp_path if File.exists? tmp_path
124
cur_path = File.join(dir, 'cur', new_fn + ':' + info)
125
File.rename(new_path, cur_path)
132
def find_mails(dir, idx)
134
['cur', 'new'].each do |d|
135
subdir = File.join(dir, d)
136
raise "#{subdir} not a directory" unless File.directory? subdir
137
Dir[File.join(subdir, '*')].each do |fn|
139
mail = RMail::Parser.read(f)
140
cache_index = mail.header['Message-Id']
141
next if not (cache_index and cache_index == idx)
142
dir_paths.push(File.join(d, File.basename(fn)))
149
def guarantee_maildir(dir)
150
# Ensure maildir-folderness
151
['new', 'cur', 'tmp'].each do |d|
152
FileUtils.mkdir_p(File.join(dir, d))
156
def maildir_file_info(file)
157
basename = File.basename(file)
158
colon = basename.rindex(':')
160
return (colon and basename.slice(colon + 1, -1))
163
# Shamelessly taken from
164
# http://gitorious.org/sup/mainline/blobs/master/lib/sup/maildir.rb
165
def new_maildir_basefn
167
"#{Time.now.to_i.to_s}.#{$$}#{Kernel.rand(1000000)}.#{MYHOSTNAME}"