Guest User

Untitled

a guest
Feb 22nd, 2018
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.67 KB | None | 0 0
  1. require 'gserver'
  2. require 'digest/md5'
  3. require 'rubygems'
  4. require 'active_record'
  5.  
  6. dbconfig = YAML::load_file(File.dirname(__FILE__) + '/config/database.yml')
  7. ActiveRecord::Base.establish_connection(dbconfig['development'])
  8.  
  9. # CREATE TABLE emails (id integer primary key autoincrement, mail_from, rcpt_to, subject, email, user_id integer);
  10. # CREATE TABLE users (id integer primary key autoincrement, username, password, email);
  11.  
  12. class Email < ActiveRecord::Base
  13. def initialize(*kvars)
  14. @deleted = false
  15. super(kvars)
  16. end
  17. def deleted?
  18. @deleted
  19. end
  20. def deleted=(deleted)
  21. @deleted = deleted
  22. end
  23. end
  24.  
  25. class User < ActiveRecord::Base
  26. end
  27.  
  28. class POP3Server < GServer
  29. attr_writer :hostname
  30. def serve(io)
  31. @state = 'auth'
  32. @failed = 0
  33. @apop_challenge = "<#{rand(10**4 - 1)}.#{rand(10**9 - 1)}@#{@hostname}>"
  34. io.print("+OK POP3 server ready #{@apop_challenge}\r\n")
  35. loop do
  36. if IO.select([io], nil, nil, 0.1)
  37. begin
  38. data = io.readpartial(4096)
  39. puts ">> #{data.chomp}"
  40. ok, op = process_line(data)
  41. break unless ok
  42. puts "<< #{op.chomp}"
  43. io.print op
  44. rescue Exception
  45. end
  46. end
  47. break if io.closed?
  48. end
  49. io.close unless io.closed?
  50. end
  51.  
  52. def user(username)
  53. @user = User.find(:first, :conditions => { :username => username })
  54. end
  55. def pass(password)
  56. return false unless @user
  57. return false unless @user.password == password
  58. true
  59. end
  60. def emails
  61. @emails = [ Email.find_all_by_user_id(@user.id) ].flatten
  62. end
  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. def list(msgid = nil)
  73. msgid = msgid.to_i if msgid
  74. if msgid
  75. return false if msgid > @emails.length or @emails[msgid-1].deleted?
  76. return [ [msgid, @emails[msgid].email.length] ]
  77. else
  78. msgs = []
  79. @emails.each_with_index do |e,i|
  80. msgs << [ i + 1, e.email.length ]
  81. end
  82. msgs
  83. end
  84. end
  85. def retr(msgid)
  86. msgid = msgid.to_i
  87. return false if msgid > @emails.length or @emails[msgid-1].deleted?
  88. @emails[msgid-1].email
  89. end
  90. def dele(msgid)
  91. msgid = msgid.to_i
  92. return false if msgid > @emails.length
  93. @emails[msgid-1].deleted = true
  94. end
  95. def rset
  96. @emails.each do |e|
  97. e.deleted = false
  98. end
  99. end
  100. def quit
  101. @emails.each do |e|
  102. if e.deleted?
  103. Email.delete(e.id)
  104. end
  105. end
  106. end
  107. def apop(username, hash)
  108. user(username)
  109. return false unless @user
  110. if Digest::MD5.new.update("#{@apop_challenge}#{@user.password}").hexdigest == hash
  111. return true
  112. end
  113. false
  114. end
  115.  
  116. def process_line(line)
  117. line.chomp!
  118. case @state
  119. when 'auth'
  120. case line
  121. when /^QUIT$/
  122. return false, "+OK dewey POP3 server signing off\r\n"
  123. when /^USER (.+)$/
  124. user($1)
  125. if @user
  126. return true, "+OK #{@user.username} is most welcome here\r\n"
  127. else
  128. @failed += 1
  129. if @failed > 2
  130. return false, "-ERR you're out!\r\n"
  131. end
  132. return true, "-ERR sorry, no mailbox for #{$1} here\r\n"
  133. end
  134. when /^PASS (.+)$/
  135. if pass($1)
  136. @state = 'trans'
  137. emails
  138. msgs, bytes = stat
  139. return true, "+OK #{@user.username}'s maildrop has #{msgs} messages (#{bytes} octets)\r\n"
  140. else
  141. @failed += 1
  142. if @failed > 2
  143. return false, "-ERR you're out!\r\n"
  144. end
  145. return true, "-ERR no dope.\r\n"
  146. end
  147. when /^APOP ([^\s]+) (.+)$/
  148. if apop($1,$2)
  149. @state = 'trans'
  150. emails
  151. return true, "+OK #{@user.username} is most welcome here\r\n"
  152. else
  153. @failed += 1
  154. if @failed > 2
  155. return false, "-ERR you're out!\r\n"
  156. end
  157. return true, "-ERR sorry, no mailbox for #{$1} here\r\n"
  158. end
  159. end
  160. when 'trans'
  161. case line
  162. when /^NOOP$/
  163. return true, "+OK\r\n"
  164. when /^STAT$/
  165. msgs, bytes = stat
  166. return true, "+OK #{msgs} #{bytes}\r\n"
  167. when /^LIST$/
  168. msgs, bytes = stat
  169. msg = "+OK #{msgs} messages (#{bytes} octets)\r\n"
  170. list.each do |num, bytes|
  171. msg += "#{num} #{bytes}\r\n"
  172. end
  173. msg += ".\r\n"
  174. return true, msg
  175. when /^LIST (\d+)$/
  176. msgs, bytes = stat
  177. num, bytes = list($1)
  178. if num
  179. return true, "+OK #{num} #{bytes}\r\n"
  180. else
  181. return true, "-ERR no such message, only #{msgs} messages in maildrop\r\n"
  182. end
  183. when /^RETR (\d+)$/
  184. msg = retr($1)
  185. if msg
  186. msg = "+OK #{msg.length} octets\r\n" + msg
  187. msg += "\r\n.\r\n"
  188. else
  189. msg = "-ERR no such message\r\n"
  190. end
  191. return true, msg
  192. when /^DELE (\d+)$/
  193. if dele($1)
  194. return true, "+OK message #{$1} deleted\r\n"
  195. else
  196. return true, "-ERR message #{$1} already deleted\r\n"
  197. end
  198. when /^RSET$/
  199. rset
  200. msgs, bytes = stat
  201. return true, "+OK maildrop has #{msgs} messages (#{bytes} octets)\r\n"
  202. when /^QUIT$/
  203. @state = 'update'
  204. quit
  205. msgs, bytes = stat
  206. if msgs > 0
  207. return true, "+OK dewey POP3 server signing off (#{msgs} messages left)\r\n"
  208. else
  209. return true, "+OK dewey POP3 server signing off (maildrop empty)\r\n"
  210. end
  211. when /^TOP (\d+) (\d+)$/
  212. lines = $2
  213. msg = retr($1)
  214. unless msg
  215. return true, "-ERR no such message\r\n"
  216. end
  217. cnt = nil
  218. final = ""
  219. msg.split(/\n/).each do |l|
  220. final += l+"\n"
  221. if cnt
  222. cnt += 1
  223. break if cnt > lines
  224. end
  225. if l !~ /\w/
  226. cnt = 0
  227. end
  228. end
  229. return true, "+OK\r\n"+final+".\r\n"
  230. when /^UIDL$/
  231. msgid = 0
  232. msg = ''
  233. @email.each do |e|
  234. msgid += 1
  235. next if e.deleted?
  236. msg += "#{msgid} #{Digest::MD5.new.update(msg).hexdigest}\r\n"
  237. end
  238. return true, "+OK\r\n#{msg}.\r\n";
  239. end
  240. when 'update'
  241. case line
  242. when /^QUIT$/
  243. return true, "+OK dewey POP3 server signing off\r\n"
  244. end
  245. end
  246. return true, "-ERR unknown command\r\n"
  247. end
  248. end
  249.  
  250. a = POP3Server.new(2226,'',4,$stderr,true,true)
  251. a.hostname = "localhost"
  252. a.start
  253. a.join
Add Comment
Please, Sign In to add comment