Class: Mapi::PropertySet
- Inherits:
-
Object
- Object
- Mapi::PropertySet
- Includes:
- Constants
- Defined in:
- lib/mapi/property_set.rb
Overview
The Mapi::PropertySet class is used to wrap the lower level Msg or Pst property stores, and provide a consistent and more friendly interface. It allows you to just say:
properties.subject
instead of:
properites.raw[0x0037, PS_MAPI]
The underlying store can be just a hash, or lazily loading directly from the file. A good compromise is to cache all the available keys, and just return the values on demand, rather than load up many possibly unwanted values.
Defined Under Namespace
Modules: Constants Classes: Key
Constant Summary collapse
- NAMES =
{ oleguid['00020328'] => 'PS_MAPI', oleguid['00020329'] => 'PS_PUBLIC_STRINGS', oleguid['00020380'] => 'PS_ROUTING_EMAIL_ADDRESSES', oleguid['00020381'] => 'PS_ROUTING_ADDRTYPE', oleguid['00020382'] => 'PS_ROUTING_DISPLAY_NAME', oleguid['00020383'] => 'PS_ROUTING_ENTRYID', oleguid['00020384'] => 'PS_ROUTING_SEARCH_KEY', # string properties in this namespace automatically get added to the internet headers oleguid['00020386'] => 'PS_INTERNET_HEADERS', # theres are bunch of outlook ones i think # http://blogs.msdn.com/stephen_griffin/archive/2006/05/10/outlook-2007-beta-documentation-notification-based-indexing-support.aspx # IPM.Appointment oleguid['00062002'] => 'PSETID_Appointment', # IPM.Task oleguid['00062003'] => 'PSETID_Task', # used for IPM.Contact oleguid['00062004'] => 'PSETID_Address', oleguid['00062008'] => 'PSETID_Common', # didn't find a source for this name. it is for IPM.StickyNote oleguid['0006200e'] => 'PSETID_Note', # for IPM.Activity. also called the journal? oleguid['0006200a'] => 'PSETID_Log', }
- SUPPORT_DIR =
duplicated here for now
File.dirname(__FILE__) + '/../..'
- TAGS =
data files that provide for the code to symbolic name mapping guids in named_map are really constant references to the above
YAML.load_file "#{SUPPORT_DIR}/data/mapitags.yaml"
- NAMED_MAP =
YAML.load_file("#{SUPPORT_DIR}/data/named_map.yaml").inject({}) do |hash, (key, value)| hash.update Key.new(key[0], const_get(key[1])) => value end
Instance Attribute Summary collapse
-
#raw ⇒ Object
readonly
Returns the value of attribute raw.
Instance Method Summary collapse
- #[](arg, guid = nil) ⇒ Object
- #[]=(arg, *args) ⇒ Object
-
#body ⇒ Object
for providing rtf to plain text conversion.
-
#body_html ⇒ Object
for providing rtf to html extraction or conversion.
-
#body_rtf ⇒ Object
for providing rtf decompression.
-
#initialize(raw) ⇒ PropertySet
constructor
raw
should be an hash-like object that mapsKey
s to values. - #inspect ⇒ Object
- #keys ⇒ Object
- #method_missing(name, *args) ⇒ Object
-
#resolve(arg, guid = nil) ⇒ Object
resolve
arg
(could be key, code, string, or symbol), and possibleguid
to a key. -
#sym_to_key ⇒ Object
this is the function that creates a symbol to key mapping.
- #to_h ⇒ Object
- #values ⇒ Object
Constructor Details
#initialize(raw) ⇒ PropertySet
raw
should be an hash-like object that maps Key
s to values. Should respond_to? [], keys, values, each, and optionally []=, and delete.
149 150 151 |
# File 'lib/mapi/property_set.rb', line 149 def initialize raw @raw = raw end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args) ⇒ Object
211 212 213 214 215 216 217 218 219 |
# File 'lib/mapi/property_set.rb', line 211 def method_missing name, *args if name.to_s !~ /\=$/ and args.empty? self[name] elsif name.to_s =~ /(.*)\=$/ and args.length == 1 self[$1] = args[0] else super end end |
Instance Attribute Details
#raw ⇒ Object (readonly)
Returns the value of attribute raw.
145 146 147 |
# File 'lib/mapi/property_set.rb', line 145 def raw @raw end |
Instance Method Details
#[](arg, guid = nil) ⇒ Object
199 200 201 |
# File 'lib/mapi/property_set.rb', line 199 def [] arg, guid=nil raw[resolve(arg, guid)] end |
#[]=(arg, *args) ⇒ Object
203 204 205 206 207 208 209 |
# File 'lib/mapi/property_set.rb', line 203 def []= arg, *args args.unshift nil if args.length == 1 guid, value = args # FIXME this won't really work properly. it would need to go # to TAGS to resolve, as it often won't be there already... raw[resolve(arg, guid)] = value end |
#body ⇒ Object
for providing rtf to plain text conversion. later, html to text too.
237 238 239 240 241 242 243 244 245 246 |
# File 'lib/mapi/property_set.rb', line 237 def body return @body if defined?(@body) @body = (self[:body] rescue nil) # last resort if !@body or @body.strip.empty? Log.warn 'creating text body from rtf' @body = (RTF::Converter.rtf2text body_rtf rescue nil) end @body end |
#body_html ⇒ Object
for providing rtf to html extraction or conversion
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'lib/mapi/property_set.rb', line 263 def body_html return @body_html if defined?(@body_html) @body_html = self[:body_html] # sometimes body_html is a stream, and sometimes a string @body_html = @body_html.read if @body_html.respond_to?(:read) @body_html = nil if @body_html.to_s.strip.empty? if body_rtf and !@body_html begin @body_html = RTF.rtf2html body_rtf rescue Log.warn 'unable to extract html from rtf' end if !@body_html Log.warn 'creating html body from rtf' begin @body_html = RTF::Converter.rtf2text body_rtf, :html rescue Log.warn 'unable to convert rtf to html' end end end @body_html end |
#body_rtf ⇒ Object
for providing rtf decompression
249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/mapi/property_set.rb', line 249 def body_rtf return @body_rtf if defined?(@body_rtf) @body_rtf = nil if self[:rtf_compressed] begin @body_rtf = RTF.rtfdecompr self[:rtf_compressed].read rescue Log.warn 'unable to decompress rtf' end end @body_rtf end |
#inspect ⇒ Object
225 226 227 228 229 230 |
# File 'lib/mapi/property_set.rb', line 225 def inspect "#<#{self.class} " + to_h.sort_by { |k, v| k.to_s }.map do |k, v| v = v.inspect "#{k}=#{v.length > 32 ? v[0..29] + '..."' : v}" end.join(' ') + '>' end |
#keys ⇒ Object
191 192 193 |
# File 'lib/mapi/property_set.rb', line 191 def keys sym_to_key.keys end |
#resolve(arg, guid = nil) ⇒ Object
resolve arg
(could be key, code, string, or symbol), and possible guid
to a key. returns nil on failure
155 156 157 158 159 160 161 162 163 164 |
# File 'lib/mapi/property_set.rb', line 155 def resolve arg, guid=nil if guid; Key.new arg, guid else case arg when Key; arg when Integer; Key.new arg else sym_to_key[arg.to_sym] end end end |
#sym_to_key ⇒ Object
this is the function that creates a symbol to key mapping. currently this works by making a pass through the raw properties, but conceivably you could map symbols to keys using the mapitags directly. problem with that would be that named properties wouldn’t map automatically, but maybe thats not too important.
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/mapi/property_set.rb', line 170 def sym_to_key return @sym_to_key if @sym_to_key @sym_to_key = {} raw.keys.each do |key| sym = key.to_sym unless Symbol === sym Log.debug "couldn't find symbolic name for key #{key.inspect}" next end if @sym_to_key[sym] Log.warn "duplicate key #{key.inspect}" # we give preference to PS_MAPI keys @sym_to_key[sym] = key if key.guid == PS_MAPI else # just assign @sym_to_key[sym] = key end end @sym_to_key end |
#to_h ⇒ Object
221 222 223 |
# File 'lib/mapi/property_set.rb', line 221 def to_h sym_to_key.inject({}) { |hash, (sym, key)| hash.update sym => raw[key] } end |
#values ⇒ Object
195 196 197 |
# File 'lib/mapi/property_set.rb', line 195 def values sym_to_key.values.map { |key| raw[key] } end |