popthis 0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.markdown +31 -0
  2. data/Rakefile +51 -0
  3. data/bin/popthis +35 -0
  4. data/lib/pop_this.rb +218 -0
  5. metadata +60 -0
@@ -0,0 +1,31 @@
1
+ # Can't POP(3) This.
2
+
3
+ <img src="http://cwninja.github.com/popthis/hammertime.gif" alt="Hammer Time"/>
4
+
5
+ So you downloaded [inaction_mailer](http://github.com/cwninja/inaction_mailer), and you had a folder full of e-mails generated while writing your app?
6
+
7
+ Now you want to preview your e-mails?!? You people are never happy!
8
+
9
+ Well, I'm a little tipsy, so I'm going to be nice, and I'm going to let you get at your mails with POP3!
10
+
11
+ I hope you like it. I do!
12
+
13
+ ## Usage:
14
+
15
+ Start the server:
16
+
17
+ popthis tmp/mails/
18
+
19
+ Now, configure your mail client as follows:
20
+
21
+ * Server: **localhost**
22
+ * Protocol: **POP3**
23
+ * Port: **2220**
24
+ * Username: anything
25
+ * Password: anything
26
+
27
+ You should now be able to see the contents of your tmp/mails folder in your mail client!
28
+
29
+ ## Origins:
30
+
31
+ I stole most of the code from [here](http://snippets.dzone.com/posts/show/5906)... so credit where credit's due.
@@ -0,0 +1,51 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/gempackagetask'
5
+
6
+ desc 'Default: run unit tests.'
7
+ task :default => :test
8
+
9
+ desc 'Test the plugin.'
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << 'lib'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ spec = Gem::Specification.new do |s|
17
+ s.name = "popthis"
18
+ s.version = "0.3"
19
+ s.summary = "Run a pop server serving up the current dir."
20
+ s.description = "Run a pop server serving up the current dir."
21
+
22
+ s.files = FileList['[A-Z]*', 'lib/**/*.rb', 'test/**/*.rb', 'rails/*']
23
+ s.require_path = 'lib'
24
+ s.test_files = Dir[*['test/**/*_test.rb']]
25
+ s.bindir = 'bin'
26
+ s.executables = FileList["bin/*"].map { |f| File.basename(f) }
27
+
28
+ s.has_rdoc = true
29
+ s.extra_rdoc_files = ["README.markdown"]
30
+ s.rdoc_options = ['--line-numbers', '--inline-source', "--main", "README.textile"]
31
+
32
+ s.authors = ["Tom Lea"]
33
+ s.email = %q{commit@tomlea.co.uk}
34
+
35
+ s.platform = Gem::Platform::RUBY
36
+ end
37
+
38
+ Rake::GemPackageTask.new spec do |pkg|
39
+ pkg.need_tar = true
40
+ pkg.need_zip = true
41
+ end
42
+
43
+ desc "Clean files generated by rake tasks"
44
+ task :clobber => [:clobber_package]
45
+
46
+ desc "Generate a gemspec file"
47
+ task :gemspec do
48
+ File.open("#{spec.name}.gemspec", 'w') do |f|
49
+ f.write spec.to_ruby
50
+ end
51
+ end
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require File.join(File.dirname(__FILE__), *%w[.. lib pop_this])
4
+
5
+ options = {
6
+ :host => "localhost",
7
+ :port => 2220
8
+ }
9
+
10
+ OptionParser.new do |opts|
11
+ opts.banner = "Usage: popthis [options] [path]"
12
+
13
+ opts.on("-p", "--port PORT", "Listen on PORT (default 2220)") do |v|
14
+ options[:port] = v.to_i
15
+ end
16
+
17
+ opts.on("-H", "--host HOST", "Listen on HOST (default localhost)") do |v|
18
+ options[:host] = v
19
+ end
20
+
21
+ opts.on_tail("-h", "--help", "Show this message") do
22
+ puts opts
23
+ exit
24
+ end
25
+ end.parse!
26
+
27
+ options[:path] = File.expand_path( ARGV.shift || Dir.pwd )
28
+
29
+ p options
30
+ server = PopThis::POP3Server.new(options)
31
+
32
+ trap("INT"){ server.stop }
33
+
34
+ server.start
35
+ server.join
@@ -0,0 +1,218 @@
1
+ require 'gserver'
2
+ require 'digest/md5'
3
+ module PopThis
4
+ class POP3Server < GServer
5
+
6
+ def initialize(options)
7
+ @hostname = options[:host]
8
+ super(options[:port])
9
+ @dir = options[:path]
10
+ end
11
+
12
+ class Email
13
+ attr_reader :filename
14
+ attr_accessor :deleted
15
+
16
+ def self.all(dir)
17
+ Dir.glob("#{ dir }/*").reject{|fn| fn =~ /^\./ || File.directory?(fn) }.map{|fn| Email.new(fn) }
18
+ end
19
+
20
+ def self.delete(email)
21
+ File.delete(email.filename)
22
+ end
23
+
24
+ def initialize(filename)
25
+ @filename = filename
26
+ @deleted = false
27
+ end
28
+
29
+ def email
30
+ @email ||= File.read(@filename)
31
+ end
32
+
33
+ def deleted?
34
+ deleted
35
+ end
36
+ end
37
+
38
+ def serve(io)
39
+ @state = 'auth'
40
+ @failed = 0
41
+ io.print("+OK POP3 server ready\r\n")
42
+ loop do
43
+ if IO.select([io], nil, nil, 0.1)
44
+ begin
45
+ data = io.readpartial(4096)
46
+ puts ">> #{data.chomp}"
47
+ ok, op = process_line(data)
48
+ puts "<< #{op.chomp}"
49
+ io.print op
50
+ break unless ok
51
+ rescue Exception
52
+ end
53
+ end
54
+ break if io.closed?
55
+ end
56
+ io.close unless io.closed?
57
+ end
58
+
59
+ def emails
60
+ @emails = Email.all(@dir)
61
+ end
62
+
63
+ def stat
64
+ msgs = bytes = 0
65
+ @emails.each do |e|
66
+ next if e.deleted?
67
+ msgs += 1
68
+ bytes += e.email.length
69
+ end
70
+ return msgs, bytes
71
+ end
72
+
73
+ def list(msgid = nil)
74
+ msgid = msgid.to_i if msgid
75
+ if msgid
76
+ return false if msgid > @emails.length or @emails[msgid-1].deleted?
77
+ return [ [msgid, @emails[msgid].email.length] ]
78
+ else
79
+ msgs = []
80
+ @emails.each_with_index do |e,i|
81
+ msgs << [ i + 1, e.email.length ]
82
+ end
83
+ msgs
84
+ end
85
+ end
86
+
87
+ def retr(msgid)
88
+ msgid = msgid.to_i
89
+ return false if msgid > @emails.length or @emails[msgid-1].deleted?
90
+ @emails[msgid-1].email
91
+ end
92
+
93
+ def dele(msgid)
94
+ msgid = msgid.to_i
95
+ return false if msgid > @emails.length
96
+ @emails[msgid-1].deleted = true
97
+ end
98
+
99
+ def rset
100
+ @emails.each do |e|
101
+ e.deleted = false
102
+ end
103
+ end
104
+
105
+ def quit
106
+ @emails.each do |e|
107
+ if e.deleted?
108
+ Email.delete(e)
109
+ end
110
+ end
111
+ end
112
+
113
+ def process_line(line)
114
+ line.chomp!
115
+ case @state
116
+ when 'auth'
117
+ case line
118
+ when /^QUIT$/
119
+ return false, "+OK popthis POP3 server signing off\r\n"
120
+ when /^USER (.+)$/
121
+ return true, "+OK #{$1} is most welcome here\r\n"
122
+ when /^PASS (.+)$/
123
+ @state = 'trans'
124
+ emails
125
+ msgs, bytes = stat
126
+ return true, "+OK #{msgs} messages (#{bytes} octets)\r\n"
127
+ end
128
+ when 'trans'
129
+ case line
130
+ when /^NOOP$/
131
+ return true, "+OK\r\n"
132
+ when /^STAT$/
133
+ msgs, bytes = stat
134
+ return true, "+OK #{msgs} #{bytes}\r\n"
135
+ when /^LIST$/
136
+ msgs, bytes = stat
137
+ msg = "+OK #{msgs} messages (#{bytes} octets)\r\n"
138
+ list.each do |num, bytes|
139
+ msg += "#{num} #{bytes}\r\n"
140
+ end
141
+ msg += ".\r\n"
142
+ return true, msg
143
+ when /^LIST (\d+)$/
144
+ msgs, bytes = stat
145
+ num, bytes = list($1)
146
+ if num
147
+ return true, "+OK #{num} #{bytes}\r\n"
148
+ else
149
+ return true, "-ERR no such message, only #{msgs} messages in maildrop\r\n"
150
+ end
151
+ when /^RETR (\d+)$/
152
+ msg = retr($1)
153
+ if msg
154
+ msg = "+OK #{msg.length} octets\r\n" + msg
155
+ msg += "\r\n.\r\n"
156
+ else
157
+ msg = "-ERR no such message\r\n"
158
+ end
159
+ return true, msg
160
+ when /^DELE (\d+)$/
161
+ if dele($1)
162
+ return true, "+OK message #{$1} deleted\r\n"
163
+ else
164
+ return true, "-ERR message #{$1} already deleted\r\n"
165
+ end
166
+ when /^RSET$/
167
+ rset
168
+ msgs, bytes = stat
169
+ return true, "+OK maildrop has #{msgs} messages (#{bytes} octets)\r\n"
170
+ when /^QUIT$/
171
+ @state = 'update'
172
+ quit
173
+ msgs, bytes = stat
174
+ if msgs > 0
175
+ return false, "+OK popthis server signing off (#{msgs} messages left)\r\n"
176
+ else
177
+ return false, "+OK popthis server signing off (folder empty)\r\n"
178
+ end
179
+ when /^TOP (\d+) (\d+)$/
180
+ lines = $2
181
+ msg = retr($1)
182
+ unless msg
183
+ return true, "-ERR no such message\r\n"
184
+ end
185
+ cnt = nil
186
+ final = ""
187
+ msg.split(/\n/).each do |l|
188
+ final += l+"\n"
189
+ if cnt
190
+ cnt += 1
191
+ break if cnt > lines
192
+ end
193
+ if l !~ /\w/
194
+ cnt = 0
195
+ end
196
+ end
197
+ return true, "+OK\r\n"+final+".\r\n"
198
+ when /^UIDL$/
199
+ msgid = 0
200
+ msg = ''
201
+ @emails.each do |e|
202
+ msgid += 1
203
+ next if e.deleted?
204
+ msg += "#{msgid} #{Digest::MD5.hexdigest(e.email)}\r\n"
205
+ end
206
+ return true, "+OK\r\n#{msg}.\r\n";
207
+ end
208
+ when 'update'
209
+ case line
210
+ when /^QUIT$/
211
+ return true, "+OK popthis server signing off\r\n"
212
+ end
213
+ end
214
+ return true, "-ERR unknown command\r\n"
215
+ end
216
+
217
+ end
218
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: popthis
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.3"
5
+ platform: ruby
6
+ authors:
7
+ - Tom Lea
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-23 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Run a pop server serving up the current dir.
17
+ email: commit@tomlea.co.uk
18
+ executables:
19
+ - popthis
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.markdown
24
+ files:
25
+ - Rakefile
26
+ - README.markdown
27
+ - lib/pop_this.rb
28
+ has_rdoc: true
29
+ homepage:
30
+ licenses: []
31
+
32
+ post_install_message:
33
+ rdoc_options:
34
+ - --line-numbers
35
+ - --inline-source
36
+ - --main
37
+ - README.textile
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ requirements: []
53
+
54
+ rubyforge_project:
55
+ rubygems_version: 1.3.5
56
+ signing_key:
57
+ specification_version: 3
58
+ summary: Run a pop server serving up the current dir.
59
+ test_files: []
60
+