cwninja-popthis 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README.markdown +25 -0
  2. data/Rakefile +50 -0
  3. data/lib/pop_this.rb +220 -0
  4. metadata +58 -0
data/README.markdown ADDED
@@ -0,0 +1,25 @@
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 (you can be nice back, but that's another story), and I'm going to let you get at your mails with POP3!
10
+
11
+ Wheeeeeeeee!
12
+
13
+ Also, I stole most of the code from [http://snippets.dzone.com/posts/show/5906](http://snippets.dzone.com/posts/show/5906).
14
+
15
+ So, erm, yeah.
16
+
17
+ It will accept any username, and any password, and will only ever serve up the given dir.
18
+
19
+ I hope you like it. I do!
20
+
21
+ ## Usage
22
+
23
+ Usage: popthis [port] [path]
24
+ Default port: 2220
25
+ Default path: current working directory
data/Rakefile ADDED
@@ -0,0 +1,50 @@
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.1"
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
+
27
+ s.has_rdoc = true
28
+ s.extra_rdoc_files = ["README.markdown"]
29
+ s.rdoc_options = ['--line-numbers', '--inline-source', "--main", "README.textile"]
30
+
31
+ s.authors = ["Tom Lea"]
32
+ s.email = %q{commit@tomlea.co.uk}
33
+
34
+ s.platform = Gem::Platform::RUBY
35
+ end
36
+
37
+ Rake::GemPackageTask.new spec do |pkg|
38
+ pkg.need_tar = true
39
+ pkg.need_zip = true
40
+ end
41
+
42
+ desc "Clean files generated by rake tasks"
43
+ task :clobber => [:clobber_package]
44
+
45
+ desc "Generate a gemspec file"
46
+ task :gemspec do
47
+ File.open("#{spec.name}.gemspec", 'w') do |f|
48
+ f.write spec.to_ruby
49
+ end
50
+ end
data/lib/pop_this.rb ADDED
@@ -0,0 +1,220 @@
1
+ require 'gserver'
2
+ require 'digest/md5'
3
+ module PopThis
4
+ class POP3Server < GServer
5
+ attr_writer :hostname
6
+ attr_writer :dir
7
+
8
+ def initialize(port, dir)
9
+ super(port)
10
+ @dir = dir
11
+ end
12
+
13
+ class Email
14
+ attr_reader :filename
15
+ attr_accessor :deleted
16
+
17
+ def self.all(dir = nil)
18
+ dir ||= Dir.pwd
19
+ Dir.glob("#{ dir }/*").reject{|fn| fn =~ /^\./ || File.directory?(fn) }.map{|fn| Email.new(fn) }
20
+ end
21
+
22
+ def self.delete(email)
23
+ File.delete(email.filename)
24
+ end
25
+
26
+ def initialize(filename)
27
+ @filename = filename
28
+ @deleted = false
29
+ end
30
+
31
+ def email
32
+ @email ||= File.read(@filename)
33
+ end
34
+
35
+ def deleted?
36
+ deleted
37
+ end
38
+ end
39
+
40
+ def serve(io)
41
+ @state = 'auth'
42
+ @failed = 0
43
+ io.print("+OK POP3 server ready\r\n")
44
+ loop do
45
+ if IO.select([io], nil, nil, 0.1)
46
+ begin
47
+ data = io.readpartial(4096)
48
+ puts ">> #{data.chomp}"
49
+ ok, op = process_line(data)
50
+ puts "<< #{op.chomp}"
51
+ io.print op
52
+ break unless ok
53
+ rescue Exception
54
+ end
55
+ end
56
+ break if io.closed?
57
+ end
58
+ io.close unless io.closed?
59
+ end
60
+
61
+ def emails
62
+ @emails = Email.all(@dir)
63
+ end
64
+
65
+ def stat
66
+ msgs = bytes = 0
67
+ @emails.each do |e|
68
+ next if e.deleted?
69
+ msgs += 1
70
+ bytes += e.email.length
71
+ end
72
+ return msgs, bytes
73
+ end
74
+
75
+ def list(msgid = nil)
76
+ msgid = msgid.to_i if msgid
77
+ if msgid
78
+ return false if msgid > @emails.length or @emails[msgid-1].deleted?
79
+ return [ [msgid, @emails[msgid].email.length] ]
80
+ else
81
+ msgs = []
82
+ @emails.each_with_index do |e,i|
83
+ msgs << [ i + 1, e.email.length ]
84
+ end
85
+ msgs
86
+ end
87
+ end
88
+
89
+ def retr(msgid)
90
+ msgid = msgid.to_i
91
+ return false if msgid > @emails.length or @emails[msgid-1].deleted?
92
+ @emails[msgid-1].email
93
+ end
94
+
95
+ def dele(msgid)
96
+ msgid = msgid.to_i
97
+ return false if msgid > @emails.length
98
+ @emails[msgid-1].deleted = true
99
+ end
100
+
101
+ def rset
102
+ @emails.each do |e|
103
+ e.deleted = false
104
+ end
105
+ end
106
+
107
+ def quit
108
+ @emails.each do |e|
109
+ if e.deleted?
110
+ Email.delete(e)
111
+ end
112
+ end
113
+ end
114
+
115
+ def process_line(line)
116
+ line.chomp!
117
+ case @state
118
+ when 'auth'
119
+ case line
120
+ when /^QUIT$/
121
+ return false, "+OK popthis POP3 server signing off\r\n"
122
+ when /^USER (.+)$/
123
+ return true, "+OK #{$1} is most welcome here\r\n"
124
+ when /^PASS (.+)$/
125
+ @state = 'trans'
126
+ emails
127
+ msgs, bytes = stat
128
+ return true, "+OK #{msgs} messages (#{bytes} octets)\r\n"
129
+ end
130
+ when 'trans'
131
+ case line
132
+ when /^NOOP$/
133
+ return true, "+OK\r\n"
134
+ when /^STAT$/
135
+ msgs, bytes = stat
136
+ return true, "+OK #{msgs} #{bytes}\r\n"
137
+ when /^LIST$/
138
+ msgs, bytes = stat
139
+ msg = "+OK #{msgs} messages (#{bytes} octets)\r\n"
140
+ list.each do |num, bytes|
141
+ msg += "#{num} #{bytes}\r\n"
142
+ end
143
+ msg += ".\r\n"
144
+ return true, msg
145
+ when /^LIST (\d+)$/
146
+ msgs, bytes = stat
147
+ num, bytes = list($1)
148
+ if num
149
+ return true, "+OK #{num} #{bytes}\r\n"
150
+ else
151
+ return true, "-ERR no such message, only #{msgs} messages in maildrop\r\n"
152
+ end
153
+ when /^RETR (\d+)$/
154
+ msg = retr($1)
155
+ if msg
156
+ msg = "+OK #{msg.length} octets\r\n" + msg
157
+ msg += "\r\n.\r\n"
158
+ else
159
+ msg = "-ERR no such message\r\n"
160
+ end
161
+ return true, msg
162
+ when /^DELE (\d+)$/
163
+ if dele($1)
164
+ return true, "+OK message #{$1} deleted\r\n"
165
+ else
166
+ return true, "-ERR message #{$1} already deleted\r\n"
167
+ end
168
+ when /^RSET$/
169
+ rset
170
+ msgs, bytes = stat
171
+ return true, "+OK maildrop has #{msgs} messages (#{bytes} octets)\r\n"
172
+ when /^QUIT$/
173
+ @state = 'update'
174
+ quit
175
+ msgs, bytes = stat
176
+ if msgs > 0
177
+ return false, "+OK popthis server signing off (#{msgs} messages left)\r\n"
178
+ else
179
+ return false, "+OK popthis server signing off (folder empty)\r\n"
180
+ end
181
+ when /^TOP (\d+) (\d+)$/
182
+ lines = $2
183
+ msg = retr($1)
184
+ unless msg
185
+ return true, "-ERR no such message\r\n"
186
+ end
187
+ cnt = nil
188
+ final = ""
189
+ msg.split(/\n/).each do |l|
190
+ final += l+"\n"
191
+ if cnt
192
+ cnt += 1
193
+ break if cnt > lines
194
+ end
195
+ if l !~ /\w/
196
+ cnt = 0
197
+ end
198
+ end
199
+ return true, "+OK\r\n"+final+".\r\n"
200
+ when /^UIDL$/
201
+ msgid = 0
202
+ msg = ''
203
+ @emails.each do |e|
204
+ msgid += 1
205
+ next if e.deleted?
206
+ msg += "#{msgid} #{Digest::MD5.hexdigest(e.email)}\r\n"
207
+ end
208
+ return true, "+OK\r\n#{msg}.\r\n";
209
+ end
210
+ when 'update'
211
+ case line
212
+ when /^QUIT$/
213
+ return true, "+OK popthis server signing off\r\n"
214
+ end
215
+ end
216
+ return true, "-ERR unknown command\r\n"
217
+ end
218
+
219
+ end
220
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cwninja-popthis
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Tom Lea
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-28 00:00:00 -07: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
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.markdown
24
+ files:
25
+ - README.markdown
26
+ - Rakefile
27
+ - lib/pop_this.rb
28
+ has_rdoc: true
29
+ homepage:
30
+ post_install_message:
31
+ rdoc_options:
32
+ - --line-numbers
33
+ - --inline-source
34
+ - --main
35
+ - README.textile
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: "0"
43
+ version:
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ requirements: []
51
+
52
+ rubyforge_project:
53
+ rubygems_version: 1.2.0
54
+ signing_key:
55
+ specification_version: 2
56
+ summary: Run a pop server serving up the current dir.
57
+ test_files: []
58
+