mbox 0.0.4 → 0.0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -42,28 +42,33 @@ end.parse!
42
42
  end
43
43
  }
44
44
 
45
- class Connection < EventMachine::Protocols::LineAndTextProtocol
46
- @@unread = {}
45
+ $unread = {}
47
46
 
47
+ class Connection < EventMachine::Protocols::LineAndTextProtocol
48
48
  attr_accessor :boxes
49
49
 
50
50
  def receive_line (line)
51
51
  whole, target, command, rest = line.match(/^(.*?)\s+(.*?)(?:\s+(.+))?$/).to_a
52
52
 
53
- boxes = target == '*' ? @boxes : @boxes.select { |box| target.include? box.name }
53
+ boxes = target == '*' ? $boxes : $boxes.select { |box| target.include? box.name }
54
54
 
55
55
  if command == 'list'
56
56
  command = rest
57
57
 
58
58
  if command == 'unread'
59
- send_response boxes.select { |box|
60
- if @@unread[box] && @@unread[box].last_check < [File.ctime(box.path), File.mtime(box.path)].max
61
- @@unread[box] = Struct.new(:status, :last_check).new(box.has_unread?, Time.new)
62
- else
63
- @@unread[box] ||= Struct.new(:status, :last_check).new(box.has_unread?, Time.new)
59
+ send_response boxes.select {|box|
60
+ if !$unread[box] || $unread[box].last_check < [File.ctime(box.path), File.mtime(box.path)].max
61
+ unless $unread[:checking]
62
+ $unread[:checking] = true
63
+
64
+ EM.defer {
65
+ $unread[box] = Struct.new(:status, :last_check).new(box.has_unread?, Time.new)
66
+ $unread[:checking] = false
67
+ }
68
+ end
64
69
  end
65
70
 
66
- @@unread[box].status
71
+ $unread[box].status rescue false
67
72
  }.map(&:name)
68
73
  end
69
74
  end
@@ -77,15 +82,13 @@ class Connection < EventMachine::Protocols::LineAndTextProtocol
77
82
  end
78
83
 
79
84
  EM.run {
80
- boxes = options[:mail][:boxes].map {|name|
85
+ $boxes = options[:mail][:boxes].map {|name|
81
86
  Mbox.open("#{options[:mail][:directory]}/#{name}")
82
87
  }
83
88
 
84
- EM.start_server options[:host], options[:port], Connection do |c|
85
- c.boxes = boxes
86
- end
89
+ EM.start_server options[:host], options[:port], Connection
87
90
 
88
91
  EM.add_periodic_timer options[:every] do
89
- `fetchmail`
92
+ EM.system 'fetchmail'
90
93
  end
91
94
  }
@@ -34,5 +34,3 @@ if command == 'list'
34
34
  puts JSON.parse(socket.gets).join("\n")
35
35
  end
36
36
  end
37
-
38
- socket.close
@@ -35,7 +35,7 @@ class Content < Array
35
35
  headers = @headers.merge(headers)
36
36
  type = headers[:content_type]
37
37
 
38
- if matches = type.mime.match(%r{multipart/(\w+)})
38
+ if type && type.mime && matches = type.mime.match(%r{multipart/(\w+)})
39
39
  text.sub(/^.*?--#{type.boundary}\n/m, '').sub(/--#{type.boundary}--$/m, '').split("--#{type.boundary}\n").each {|part|
40
40
  stream = StringIO.new(part)
41
41
 
@@ -18,6 +18,7 @@
18
18
  #++
19
19
 
20
20
  require 'stringio'
21
+ require 'call-me/memoize'
21
22
 
22
23
  require 'mbox/mail/headers/status'
23
24
  require 'mbox/mail/headers/content_type'
@@ -25,22 +26,45 @@ require 'mbox/mail/headers/content_type'
25
26
  class Mbox; class Mail
26
27
 
27
28
  class Headers
28
- def self.name_to_symbol (name)
29
- return name if name.is_a? Symbol
29
+ class Name
30
+ def self.parse (text)
31
+ return text if text.is_a? self
30
32
 
31
- name = name.to_s.downcase.gsub('-', '_').to_sym
33
+ new(text)
34
+ end
35
+
36
+ def initialize (name)
37
+ name = name.to_s.downcase.gsub('-', '_').to_sym
32
38
 
33
- if name.empty?
34
- raise ArgumentError, 'cannot pass empty name'
39
+ if name.empty?
40
+ raise ArgumentError, 'cannot pass empty name'
41
+ end
42
+
43
+ @internal = name
35
44
  end
36
45
 
37
- name
38
- end
46
+ def == (other)
47
+ to_sym == Name.parse(other).to_sym
48
+ end
39
49
 
40
- def self.symbol_to_name (name)
41
- name.to_s.downcase.gsub('_', '-').gsub(/(\A|-)(.)/) {|match|
42
- match.upcase
43
- }
50
+ alias eql? ==
51
+
52
+ def hash
53
+ to_sym.hash
54
+ end
55
+
56
+ def to_sym
57
+ @internal
58
+ end
59
+
60
+ memoize
61
+ def to_s
62
+ to_sym.to_s.downcase.gsub('_', '-').gsub(/(\A|-)(.)/) {|match|
63
+ match.upcase
64
+ }
65
+ end
66
+
67
+ alias to_str to_s
44
68
  end
45
69
 
46
70
  def self.parse (input)
@@ -60,16 +84,16 @@ class Headers
60
84
  end
61
85
 
62
86
  def [] (name)
63
- @data[Headers.name_to_symbol(name)]
87
+ @data[Name.parse(name)]
64
88
  end
65
89
 
66
90
  def []= (name, value)
67
- name = Headers.name_to_symbol(name)
91
+ name = Name.parse(name)
68
92
 
69
- value = case name
70
- when :status then Status.parse(value)
71
- when :content_type then ContentType.parse(value)
72
- else value
93
+ if name == :status
94
+ value = Status.parse(value)
95
+ elsif name == :content_type
96
+ value = ContentType.parse(value)
73
97
  end
74
98
 
75
99
  if tmp = @data[name] && !tmp.is_a?(Array)
@@ -112,7 +136,7 @@ class Headers
112
136
 
113
137
  until input.eof? || (line = input.readline).chomp.empty?
114
138
  if !line.match(/^\s/)
115
- next unless matches = line.match(/^([^:]+):\s*(.+)$/)
139
+ next unless matches = line.match(/^([\w\-]+):\s*(.+)$/)
116
140
 
117
141
  whole, name, value = matches.to_a
118
142
 
@@ -121,7 +145,7 @@ class Headers
121
145
  elsif self[last]
122
146
  if self[last].is_a?(String)
123
147
  self[last] << " #{line}"
124
- elsif self[last].is_a?(Array)
148
+ elsif self[last].is_a?(Array) && self[last].last.is_a?(String)
125
149
  self[last].last << " #{line}"
126
150
  end
127
151
  end
@@ -135,12 +159,12 @@ class Headers
135
159
 
136
160
  each {|name, values|
137
161
  [values].flatten.each {|value|
138
- result << "#{Headers.symbol_to_name(name)}: #{value}\n"
162
+ result << "#{name}: #{value}\n"
139
163
  }
140
164
  }
141
165
 
142
166
  result
143
167
  end
144
168
  end
145
- end
146
- end
169
+
170
+ end; end
@@ -67,9 +67,17 @@ class Mbox
67
67
  def each (opts = {})
68
68
  @input.seek 0
69
69
 
70
+ if @input.respond_to? :flock
71
+ @input.flock File::LOCK_SH
72
+ end
73
+
70
74
  while mail = Mail.parse(@input, options.merge(opts))
71
75
  yield mail
72
76
  end
77
+
78
+ if @input.respond_to? :flock
79
+ @input.flock File::LOCK_UN
80
+ end
73
81
  end
74
82
 
75
83
  def [] (index, opts = {})
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.4.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-06 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2012-05-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: call-me
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  description: A simple library to read mbox files.
15
31
  email: meh@paranoici.org
16
32
  executables:
@@ -50,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
66
  version: '0'
51
67
  requirements: []
52
68
  rubyforge_project:
53
- rubygems_version: 1.8.23
69
+ rubygems_version: 1.8.24
54
70
  signing_key:
55
71
  specification_version: 3
56
72
  summary: A simple library to read mbox files.