Skip to content

Instantly share code, notes, and snippets.

@numinit
Last active December 11, 2015 01:49
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save numinit/4526237 to your computer and use it in GitHub Desktop.
puts "*** Loading Objective-C dependencies, this will take a moment"
require 'rubygems'
require 'htmlentities'
require 'json'
framework 'Foundation'
framework 'AppKit'
class Person
def initWithCoder decoder
end
end
class Presentity
def initWithCoder decoder
if decoder.allowsKeyedCoding
@service, @sender = decoder.decodeObjectForKey(:ServiceName), decoder.decodeObjectForKey(:ID)
else
@service, @sender = decoder.decodeObject, decoder.decodeObject
end
[@service, @sender]
end
end
class InstantMessage
def initWithCoder decoder
if decoder.allowsKeyedCoding
@sender = decoder.decodeObjectForKey(:Sender)
@when = decoder.decodeObjectForKey(:Time)
@text = decoder.decodeObjectForKey(:MessageText)
@flags = decoder.decodeObjectForKey(:Flags)
else
@sender = decoder.decodeObject
@when = decoder.decodeObject
@text = decoder.decodeObject
@flags = Pointer.new_with_type('I')
decoder.decodeValueOfObjCType('I', at: @flags)
end
attributes = {NSDocumentTypeDocumentAttribute => NSHTMLTextDocumentType, NSExcludedElementsDocumentAttribute => ['doctype', 'xml', 'html', 'head', 'body']}
mhtml = @text.nil? ? '' : @text.dataFromRange(NSMakeRange(0, @text.length), documentAttributes: attributes, error: nil)
[@sender, @when, NSString.stringWithUTF8String(mhtml)]
end
end
class GroupchatMessage < InstantMessage
end
if __FILE__ == $0
start = Time.now
$stderr.puts "*** Scanning directories"
logs = ARGV.collect{|d| Dir.glob("#{File.join d, '**', '*.ichat'}")}.flatten.sort{|a, b| File.basename(File.dirname(a)) <=> File.basename(File.dirname(b))}
$stderr.puts "*** Preparing to parse #{logs.count} chat logs"
logs.collect! do |f|
$stderr.puts "*** Reading: #{File.basename f, File.extname(f)}"
contents = File.open(f, 'rb').read
o = (contents[0,8] == 'bplist00' ? NSKeyedUnarchiver : NSUnarchiver).unarchiveObjectWithData(contents.to_data)
{
service: o.first,
participants: (o[3].is_a?(Array) ? o[3] : [o[3]]).collect {|(service, user)| {service: service, user: user}},
date: File.basename(File.dirname(f)),
messages: o[2].collect do |presentity, time, msg|
h = {
type: (presentity.nil? ? :system : :user),
time: time,
msg: HTMLEntities.new.decode(msg.gsub(%r{</?[^>]+?>}, '').strip)
}
# Get /me messages
me = h[:msg].match(/\A\/me\s*(.+)\z/)
h[:type], h[:msg] = :action, me[1] if !me.nil? && !me[1].nil?
h[:service], h[:user] = presentity.first, presentity.last unless presentity.nil?
h
end
}
end
$stderr.puts "*** Dumping to stdout, wait a second"
$stdout.write JSON.pretty_generate(logs)
$stderr.puts "*** Done in #{Time.now - start} seconds"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment