ruby-msg 1.2.17.3 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/FIXES +22 -0
- data/Rakefile +13 -16
- data/bin/msgtool +1 -1
- data/lib/msg.rb +26 -9
- data/lib/msg/properties.rb +28 -11
- metadata +19 -18
- data/bin/oletool +0 -35
- data/lib/ole/base.rb +0 -5
- data/lib/ole/file_system.rb +0 -181
- data/lib/ole/io_helpers.rb +0 -184
- data/lib/ole/storage.rb +0 -927
- data/lib/ole/types.rb +0 -36
- data/lib/support.rb +0 -51
- data/test/test_storage.rb +0 -139
- data/test/test_word_6.doc +0 -0
- data/test/test_word_95.doc +0 -0
- data/test/test_word_97.doc +0 -0
data/FIXES
CHANGED
@@ -32,3 +32,25 @@ recent fixes based on importing results into evolution
|
|
32
32
|
|
33
33
|
6. still unsure about how to do my "\r" handling.
|
34
34
|
|
35
|
+
7. need to join addresses with , instead of ; i think. evolution only shows the
|
36
|
+
first one otherwise it appears, but all when they are , separated.
|
37
|
+
|
38
|
+
8. need to solve ole storage issues with the very large file using extra bat
|
39
|
+
stuff.
|
40
|
+
|
41
|
+
9. retest a bit on evolution and thunderbird, and release. tested on a corups
|
42
|
+
of >1000 msg files, so should be starting to get pretty good quality.
|
43
|
+
|
44
|
+
10. longer term, things fall into a few basic categories:
|
45
|
+
|
46
|
+
- non mail conversions (look further into vcard, ical et al support for other
|
47
|
+
types of msg)
|
48
|
+
- further tests and robustness for what i handle now. ie, look into corner
|
49
|
+
cases covered so far, and work on the mime code. fix random charset encoding
|
50
|
+
issues, in the various weird mime ways, do header wrapping etc etc.
|
51
|
+
check fidelity of conversions, and capture some more properties as headers,
|
52
|
+
such as importance which i don't do yet.
|
53
|
+
- fix that named property bug. tidy up warnings, exceptions.
|
54
|
+
- extend conversion to make better html.
|
55
|
+
this is longer term. as i don't use the rtf, i need to make my html better.
|
56
|
+
emulating some rtf things. harder, not important atm.
|
data/Rakefile
CHANGED
@@ -6,8 +6,9 @@ require 'rake/gempackagetask'
|
|
6
6
|
require 'rbconfig'
|
7
7
|
require 'fileutils'
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
$:.unshift 'lib'
|
10
|
+
|
11
|
+
require 'msg'
|
11
12
|
|
12
13
|
PKG_NAME = 'ruby-msg'
|
13
14
|
PKG_VERSION = Msg::VERSION
|
@@ -23,18 +24,8 @@ end
|
|
23
24
|
# RDocTask wasn't working for me
|
24
25
|
desc 'Build the rdoc HTML Files'
|
25
26
|
task :rdoc do
|
26
|
-
system "rdoc -S -N
|
27
|
-
end
|
28
|
-
|
29
|
-
=begin
|
30
|
-
Rake::PackageTask.new(PKG_NAME, PKG_VERSION) do |p|
|
31
|
-
p.need_tar_gz = true
|
32
|
-
p.package_dir = 'build'
|
33
|
-
p.package_files.include("Rakefile", "README")
|
34
|
-
p.package_files.include("contrib/*.c")
|
35
|
-
p.package_files.include("test/test_*.rb", "test/*.doc", "lib/*.rb", "lib/ole/storage.rb")
|
27
|
+
system "rdoc -S -N --main Msg --tab-width 2 --title '#{PKG_NAME} documentation' lib"
|
36
28
|
end
|
37
|
-
=end
|
38
29
|
|
39
30
|
spec = Gem::Specification.new do |s|
|
40
31
|
s.name = PKG_NAME
|
@@ -46,20 +37,26 @@ spec = Gem::Specification.new do |s|
|
|
46
37
|
s.homepage = %q{http://code.google.com/p/ruby-msg}
|
47
38
|
#s.rubyforge_project = %q{ruby-msg}
|
48
39
|
|
49
|
-
s.executables = ['msgtool'
|
40
|
+
s.executables = ['msgtool']
|
50
41
|
s.files = Dir.glob('data/*.yaml') + ['Rakefile', 'README', 'FIXES']
|
51
42
|
s.files += Dir.glob("lib/**/*.rb")
|
52
|
-
s.files += Dir.glob("test/test_*.rb")
|
43
|
+
s.files += Dir.glob("test/test_*.rb")
|
53
44
|
s.files += Dir.glob("bin/*")
|
54
45
|
|
55
46
|
s.has_rdoc = true
|
47
|
+
s.rdoc_options += ['--main', 'Msg',
|
48
|
+
'--title', "#{PKG_NAME} documentation",
|
49
|
+
'--tab-width', '2']
|
50
|
+
|
56
51
|
|
57
52
|
s.autorequire = 'msg'
|
53
|
+
|
54
|
+
s.add_dependency 'ruby-ole', '>=1.2.1'
|
58
55
|
end
|
59
56
|
|
60
57
|
Rake::GemPackageTask.new(spec) do |p|
|
61
58
|
p.gem_spec = spec
|
62
|
-
|
59
|
+
p.need_tar = true
|
63
60
|
p.need_zip = false
|
64
61
|
p.package_dir = 'build'
|
65
62
|
end
|
data/bin/msgtool
CHANGED
data/lib/msg.rb
CHANGED
@@ -5,7 +5,7 @@ $: << File.dirname(__FILE__)
|
|
5
5
|
require 'yaml'
|
6
6
|
require 'base64'
|
7
7
|
|
8
|
-
require '
|
8
|
+
require 'rubygems'
|
9
9
|
require 'ole/storage'
|
10
10
|
require 'msg/properties'
|
11
11
|
require 'msg/rtf'
|
@@ -20,7 +20,7 @@ require 'mime'
|
|
20
20
|
#
|
21
21
|
|
22
22
|
class Msg
|
23
|
-
VERSION = '1.
|
23
|
+
VERSION = '1.3.1'
|
24
24
|
# we look here for the yaml files in data/, and the exe files for support
|
25
25
|
# decoding at the moment.
|
26
26
|
SUPPORT_DIR = File.dirname(__FILE__) + '/..'
|
@@ -144,9 +144,9 @@ class Msg
|
|
144
144
|
# of the ole name, or just leave it if we can't
|
145
145
|
recips = recips_by_type[type]
|
146
146
|
recips = (recips.sort_by { |r| r.obj.name[/\d{8}$/].hex } rescue recips)
|
147
|
-
#
|
147
|
+
# switched to using , for separation, not ;. see issue #4
|
148
148
|
# recips.empty? is strange. i wouldn't have thought it possible, but it was right?
|
149
|
-
headers[type.to_s.sub(/^(.)/) { $1.upcase }] = [recips.join('
|
149
|
+
headers[type.to_s.sub(/^(.)/) { $1.upcase }] = [recips.join(', ')] unless recips.empty?
|
150
150
|
end
|
151
151
|
headers['Subject'] = [props.subject] if props.subject
|
152
152
|
|
@@ -171,11 +171,28 @@ class Msg
|
|
171
171
|
headers['Date'] = [Time.iso8601(time.to_s).rfc2822] if time
|
172
172
|
end
|
173
173
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
174
|
+
# some very simplistic mapping between internet message headers and the
|
175
|
+
# mapi properties
|
176
|
+
# any of these could be causing duplicates due to case issues. the hack in #to_mime
|
177
|
+
# just stops re-duplication at that point. need to move some smarts into the mime
|
178
|
+
# code to handle it.
|
179
|
+
mapi_header_map = [
|
180
|
+
[:internet_message_id, 'Message-ID'],
|
181
|
+
[:in_reply_to_id, 'In-Reply-To'],
|
182
|
+
# don't set these values if they're equal to the defaults anyway
|
183
|
+
[:importance, 'Importance', proc { |val| val.to_s == '1' ? nil : val }],
|
184
|
+
[:priority, 'Priority', proc { |val| val.to_s == '1' ? nil : val }],
|
185
|
+
[:sensitivity, 'Sensitivity', proc { |val| val.to_s == '0' ? nil : val }],
|
186
|
+
# yeah?
|
187
|
+
[:conversation_topic, 'Thread-Topic'],
|
188
|
+
# not sure of the distinction here
|
189
|
+
# :originator_delivery_report_requested ??
|
190
|
+
[:read_receipt_requested, 'Disposition-Notification-To', proc { |val| from }]
|
191
|
+
]
|
192
|
+
mapi_header_map.each do |mapi, mime, *f|
|
193
|
+
next unless q = val = props.send(mapi) or headers.has_key?(mime)
|
194
|
+
next if f[0] and !(val = f[0].call(val))
|
195
|
+
headers[mime] = [val.to_s]
|
179
196
|
end
|
180
197
|
end
|
181
198
|
|
data/lib/msg/properties.rb
CHANGED
@@ -48,24 +48,28 @@ class Msg
|
|
48
48
|
# There also needs to be a way to look up properties more specifically:
|
49
49
|
#
|
50
50
|
# properties[0x0037] # => gets the subject
|
51
|
-
# properties[
|
52
|
-
# properties[
|
51
|
+
# properties[0x0037, PS_MAPI] # => still gets the subject
|
52
|
+
# properties['Keywords', PS_PUBLIC_STRINGS] # => gets outlook's categories array
|
53
53
|
#
|
54
|
-
# The
|
54
|
+
# The abbreviated versions work by "resolving" the symbols to full keys:
|
55
55
|
#
|
56
|
-
#
|
57
|
-
# properties.resolve :
|
56
|
+
# # the guid here is just PS_PUBLIC_STRINGS
|
57
|
+
# properties.resolve :keywords # => #<Key {00020329-0000-0000-c000-000000000046}/"Keywords">
|
58
|
+
# # the result here is actually also a key
|
59
|
+
# k = properties.resolve :subject # => 0x0037
|
60
|
+
# # it has a guid
|
61
|
+
# k.guid == Msg::Properties::PS_MAPI # => true
|
58
62
|
#
|
59
63
|
# = Parsing
|
60
64
|
#
|
61
65
|
# There are three objects that need to be parsed to load a +Msg+ property store:
|
62
66
|
#
|
63
|
-
#
|
67
|
+
# 1. The +nameid+ directory (<tt>Properties.parse_nameid</tt>)
|
64
68
|
# 2. The many +substg+ objects, whose names should match <tt>Properties::SUBSTG_RX</tt>
|
65
69
|
# (<tt>Properties#parse_substg</tt>)
|
66
70
|
# 3. The +properties+ file (<tt>Properties#parse_properties</tt>)
|
67
71
|
#
|
68
|
-
# Understanding of the formats is by no means perfect
|
72
|
+
# Understanding of the formats is by no means perfect.
|
69
73
|
#
|
70
74
|
# = TODO
|
71
75
|
#
|
@@ -79,7 +83,7 @@ class Msg
|
|
79
83
|
# current greedy-loading approach. still want strings to work nicely:
|
80
84
|
# props.subject
|
81
85
|
# but don't want to be loading up large binary blobs, typically attachments, eg
|
82
|
-
# props.attach_data
|
86
|
+
# props.attach_data
|
83
87
|
# probably the easiest solution is that the binary "encoding", be to return an io
|
84
88
|
# object instead. and you must read it if you want it as a string
|
85
89
|
# maybe i can avoid the greedy model anyway? rather than parsing the properties completely,
|
@@ -133,9 +137,13 @@ class Msg
|
|
133
137
|
attr_reader :unused
|
134
138
|
attr_reader :nameid
|
135
139
|
|
140
|
+
# +nameid+ is to provide a way to inherit from parent (needed for property sets for
|
141
|
+
# attachments and recipients, which inherit from the msg itself. what about nested
|
142
|
+
# msg??)
|
136
143
|
def initialize
|
137
144
|
@raw = {}
|
138
145
|
@unused = []
|
146
|
+
@nameid = nil
|
139
147
|
# FIXME
|
140
148
|
@body_rtf = @body_html = @body = false
|
141
149
|
end
|
@@ -144,7 +152,7 @@ class Msg
|
|
144
152
|
# The parsing methods
|
145
153
|
#++
|
146
154
|
|
147
|
-
def self.load obj
|
155
|
+
def self.load obj, ignore=nil
|
148
156
|
prop = Properties.new
|
149
157
|
prop.load obj
|
150
158
|
prop
|
@@ -154,9 +162,16 @@ class Msg
|
|
154
162
|
def load obj
|
155
163
|
# we need to do the nameid first, as it provides the map for later user defined properties
|
156
164
|
children = obj.children.dup
|
157
|
-
|
165
|
+
if nameid_obj = children.find { |child| child.name == '__nameid_version1.0' }
|
158
166
|
children.delete nameid_obj
|
159
|
-
Properties.parse_nameid nameid_obj
|
167
|
+
@nameid = Properties.parse_nameid nameid_obj
|
168
|
+
# hack to make it available to all msg files from the same ole storage object
|
169
|
+
class << obj.ole
|
170
|
+
attr_accessor :msg_nameid
|
171
|
+
end
|
172
|
+
obj.ole.msg_nameid = @nameid
|
173
|
+
elsif obj.ole
|
174
|
+
@nameid = obj.ole.msg_nameid rescue nil
|
160
175
|
end
|
161
176
|
# now parse the actual properties. i think dirs that match the substg should be decoded
|
162
177
|
# as properties to. 0x000d is just another encoding, the dir encoding. it should match
|
@@ -310,6 +325,8 @@ class Msg
|
|
310
325
|
elsif real_key = @nameid[key]
|
311
326
|
key = real_key
|
312
327
|
else
|
328
|
+
# i think i hit these when i have a named property, in the PS_MAPI
|
329
|
+
# guid
|
313
330
|
Log.warn "property in named range not in nameid #{key.inspect}"
|
314
331
|
key = Key.new key
|
315
332
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ruby-msg
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.
|
7
|
-
date: 2007-
|
6
|
+
version: 1.3.1
|
7
|
+
date: 2007-08-21 00:00:00 +10:00
|
8
8
|
summary: Ruby Msg library.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -36,36 +36,37 @@ files:
|
|
36
36
|
- README
|
37
37
|
- FIXES
|
38
38
|
- bin/msgtool
|
39
|
-
- bin/oletool
|
40
39
|
- lib/orderedhash.rb
|
41
40
|
- lib/rtf.rb
|
42
|
-
- lib/support.rb
|
43
41
|
- lib/mime.rb
|
44
42
|
- lib/msg.rb
|
45
|
-
- lib/ole/types.rb
|
46
|
-
- lib/ole/file_system.rb
|
47
|
-
- lib/ole/storage.rb
|
48
|
-
- lib/ole/io_helpers.rb
|
49
|
-
- lib/ole/base.rb
|
50
43
|
- lib/msg/rtf.rb
|
51
44
|
- lib/msg/properties.rb
|
52
45
|
- test/test_mime.rb
|
53
|
-
- test/test_storage.rb
|
54
|
-
- test/test_word_6.doc
|
55
|
-
- test/test_word_95.doc
|
56
|
-
- test/test_word_97.doc
|
57
46
|
test_files: []
|
58
47
|
|
59
|
-
rdoc_options:
|
60
|
-
|
48
|
+
rdoc_options:
|
49
|
+
- --main
|
50
|
+
- Msg
|
51
|
+
- --title
|
52
|
+
- ruby-msg documentation
|
53
|
+
- --tab-width
|
54
|
+
- "2"
|
61
55
|
extra_rdoc_files: []
|
62
56
|
|
63
57
|
executables:
|
64
58
|
- msgtool
|
65
|
-
- oletool
|
66
59
|
extensions: []
|
67
60
|
|
68
61
|
requirements: []
|
69
62
|
|
70
|
-
dependencies:
|
71
|
-
|
63
|
+
dependencies:
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: ruby-ole
|
66
|
+
version_requirement:
|
67
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: 1.2.1
|
72
|
+
version:
|
data/bin/oletool
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
#! /usr/bin/ruby
|
2
|
-
|
3
|
-
require 'optparse'
|
4
|
-
require 'rubygems'
|
5
|
-
require 'ole/storage'
|
6
|
-
|
7
|
-
def oletool
|
8
|
-
opts = {:verbose => false, :action => :tree}
|
9
|
-
op = OptionParser.new do |op|
|
10
|
-
op.banner = "Usage: oletool [options] [files]"
|
11
|
-
op.separator ''
|
12
|
-
op.on('-t', '--tree', 'Dump ole trees for files (default)') { opts[:action] = :tree }
|
13
|
-
op.on('-r', '--repack', 'Repack the ole files in canonical form') { opts[:action] = :repack }
|
14
|
-
op.separator ''
|
15
|
-
op.on('-v', '--[no-]verbose', 'Run verbosely') { |v| opts[:verbose] = v }
|
16
|
-
op.on_tail('-h', '--help', 'Show this message') { puts op; exit }
|
17
|
-
end
|
18
|
-
files = op.parse ARGV
|
19
|
-
if files.empty?
|
20
|
-
puts 'Must specify 1 or more msg files.'
|
21
|
-
puts op
|
22
|
-
exit 1
|
23
|
-
end
|
24
|
-
Ole::Log.level = opts[:verbose] ? Logger::WARN : Logger::FATAL
|
25
|
-
files.each do |file|
|
26
|
-
case opts[:action]
|
27
|
-
when :tree
|
28
|
-
Ole::Storage.open(file) { |ole| puts ole.root.to_tree }
|
29
|
-
when :repack
|
30
|
-
Ole::Storage.open(file, &:repack)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
oletool
|
data/lib/ole/base.rb
DELETED
data/lib/ole/file_system.rb
DELETED
@@ -1,181 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# = Introduction
|
3
|
-
#
|
4
|
-
# This file intends to provide file system-like api support, a la <tt>zip/zipfilesystem</tt>.
|
5
|
-
#
|
6
|
-
# Ideally, this will be the recommended interface, allowing Ole::Storage, Dir, and
|
7
|
-
# Zip::ZipFile to be used exchangablyk. It should be possible to write recursive copy using
|
8
|
-
# the plain api, such that you can copy dirs/files agnostically between any of ole docs, dirs,
|
9
|
-
# and zip files.
|
10
|
-
#
|
11
|
-
# = Usage
|
12
|
-
#
|
13
|
-
# Currently you can do something like the following:
|
14
|
-
#
|
15
|
-
# Ole::Storage.open 'test.doc' do |ole|
|
16
|
-
# ole.dir.entries '/' # => [".", "..", "\001Ole", "1Table", "\001CompObj", ...]
|
17
|
-
# ole.file.read "\001CompObj" # => "\001\000\376\377\003\n\000\000\377\377..."
|
18
|
-
# end
|
19
|
-
#
|
20
|
-
# = Notes
|
21
|
-
#
|
22
|
-
# *** This file is very incomplete
|
23
|
-
#
|
24
|
-
# i think its okay to have an api like this on top, but there are certain things that ole
|
25
|
-
# does that aren't captured.
|
26
|
-
# <tt>Ole::Storage</tt> can have multiple files with the same name, for example, or with
|
27
|
-
# / in the name, and other things that are probably invalid anyway.
|
28
|
-
# i think this should remain an addon, built on top of my core api.
|
29
|
-
# but still the ideas can be reflected in the core, ie, changing the read/write semantics.
|
30
|
-
#
|
31
|
-
# once the core changes are complete, this will be a pretty straight forward file to complete.
|
32
|
-
#
|
33
|
-
|
34
|
-
require 'ole/base'
|
35
|
-
|
36
|
-
module Ole # :nodoc:
|
37
|
-
class Storage
|
38
|
-
def file
|
39
|
-
@file ||= FileParent.new self
|
40
|
-
end
|
41
|
-
|
42
|
-
def dir
|
43
|
-
@dir ||= DirParent.new self
|
44
|
-
end
|
45
|
-
|
46
|
-
def dirent_from_path path_str
|
47
|
-
path = path_str.sub(/^\/*/, '').sub(/\/*$/, '')
|
48
|
-
dirent = @root
|
49
|
-
return dirent if path.empty?
|
50
|
-
path = path.split /\/+/
|
51
|
-
until path.empty?
|
52
|
-
raise "invalid path #{path_str.inspect}" if dirent.file?
|
53
|
-
if tmp = dirent[path.shift]
|
54
|
-
dirent = tmp
|
55
|
-
else
|
56
|
-
# allow write etc later.
|
57
|
-
raise "invalid path #{path_str.inspect}"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
dirent
|
61
|
-
end
|
62
|
-
|
63
|
-
class FileParent
|
64
|
-
def initialize ole
|
65
|
-
@ole = ole
|
66
|
-
end
|
67
|
-
|
68
|
-
def open path_str, mode='r', &block
|
69
|
-
dirent = @ole.dirent_from_path path_str
|
70
|
-
# like Errno::EISDIR
|
71
|
-
raise "#{path_str.inspect} is a directory" unless dirent.file?
|
72
|
-
dirent.open(&block)
|
73
|
-
end
|
74
|
-
|
75
|
-
alias new :open
|
76
|
-
|
77
|
-
def read path
|
78
|
-
open(path) { |f| f.read }
|
79
|
-
end
|
80
|
-
|
81
|
-
# crappy copy from Dir.
|
82
|
-
def unlink path
|
83
|
-
dirent = @ole.dirent_from_path path
|
84
|
-
# EPERM
|
85
|
-
raise "operation not permitted #{path.inspect}" unless dirent.file?
|
86
|
-
# i think we should free all of our blocks. i think the best way to do that would be
|
87
|
-
# like:
|
88
|
-
# open(path) { |f| f.truncate 0 }. which should free all our blocks from the
|
89
|
-
# allocation table. then if we remove ourself from our parent, we won't be part of
|
90
|
-
# the bat at save time.
|
91
|
-
# i think if you run repack, all free blocks should get zeroed.
|
92
|
-
open(path) { |f| f.truncate 0 }
|
93
|
-
parent = @ole.dirent_from_path(('/' + path).sub(/\/[^\/]+$/, ''))
|
94
|
-
parent.children.delete dirent
|
95
|
-
1 # hmmm. as per ::File ?
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
class DirParent
|
100
|
-
def initialize ole
|
101
|
-
@ole = ole
|
102
|
-
end
|
103
|
-
|
104
|
-
def open path_str
|
105
|
-
dirent = @ole.dirent_from_path path_str
|
106
|
-
# like Errno::ENOTDIR
|
107
|
-
raise "#{path_str.inspect} is not a directory" unless dirent.dir?
|
108
|
-
dir = Dir.new dirent, path_str
|
109
|
-
if block_given?
|
110
|
-
yield dir
|
111
|
-
else
|
112
|
-
dir
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# certain Dir class methods proxy in this fashion:
|
117
|
-
def entries path
|
118
|
-
open(path) { |dir| dir.entries }
|
119
|
-
end
|
120
|
-
|
121
|
-
# there are some other important ones, like:
|
122
|
-
# chroot (!), mkdir, chdir, rmdir, glob etc etc. for now, i think
|
123
|
-
# mkdir, and rmdir are the main ones we'd need to support
|
124
|
-
def rmdir path
|
125
|
-
dirent = @ole.dirent_from_path path
|
126
|
-
# repeating myself
|
127
|
-
raise "#{path.inspect} is not a directory" unless dirent.dir?
|
128
|
-
# ENOTEMPTY:
|
129
|
-
raise "directory not empty #{path.inspect}" unless dirent.children.empty?
|
130
|
-
# now delete it, how to do that? the canonical representation that is
|
131
|
-
# maintained is the root tree, and the children array. we must remove it
|
132
|
-
# from the children array.
|
133
|
-
# we need the parent then. this sucks but anyway:
|
134
|
-
parent = @ole.dirent_from_path path.sub(/\/[^\/]+$/, '') || '/'
|
135
|
-
# note that the way this currently works, on save and repack time this will get
|
136
|
-
# reflected. to work properly, ie to make a difference now it would have to re-write
|
137
|
-
# the dirent. i think that Ole::Storage#close will handle that. and maybe include a
|
138
|
-
# #repack.
|
139
|
-
parent.children.delete dirent
|
140
|
-
0 # hmmm. as per ::Dir ?
|
141
|
-
end
|
142
|
-
|
143
|
-
class Dir
|
144
|
-
include Enumerable
|
145
|
-
attr_reader :dirent, :path, :entries, :pos
|
146
|
-
|
147
|
-
def initialize dirent, path
|
148
|
-
@dirent, @path = dirent, path
|
149
|
-
@pos = 0
|
150
|
-
# FIXME: hack, and probably not really desired
|
151
|
-
@entries = %w[. ..] + @dirent.children.map(&:name)
|
152
|
-
end
|
153
|
-
|
154
|
-
def each(&block)
|
155
|
-
@entries.each(&block)
|
156
|
-
end
|
157
|
-
|
158
|
-
def close
|
159
|
-
end
|
160
|
-
|
161
|
-
def read
|
162
|
-
@entries[@pos]
|
163
|
-
ensure
|
164
|
-
@pos += 1 if @pos < @entries.length
|
165
|
-
end
|
166
|
-
|
167
|
-
def pos= pos
|
168
|
-
@pos = [[0, pos].max, @entries.length].min
|
169
|
-
end
|
170
|
-
|
171
|
-
def rewind
|
172
|
-
@pos = 0
|
173
|
-
end
|
174
|
-
|
175
|
-
alias tell :pos
|
176
|
-
alias seek :pos=
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|