pidgin2adium 3.1.1 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +12 -7
- data/lib/pidgin2adium.rb +97 -99
- data/lib/pidgin2adium/log_file.rb +2 -5
- data/lib/pidgin2adium/messages/message.rb +17 -0
- data/lib/pidgin2adium/parsers/basic_parser.rb +88 -125
- data/lib/version.rb +3 -0
- data/pidgin2adium.gemspec +9 -9
- data/spec/basic_parser_spec.rb +7 -25
- data/spec/html_log_parser_spec.rb +3 -3
- data/spec/log_file_spec.rb +12 -0
- data/spec/text_log_parser_spec.rb +1 -1
- metadata +11 -11
- data/VERSION +0 -1
data/Rakefile
CHANGED
@@ -1,19 +1,21 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
|
+
require './lib/version.rb'
|
3
4
|
|
4
5
|
begin
|
5
6
|
require 'jeweler'
|
6
7
|
Jeweler::Tasks.new do |gem|
|
7
8
|
gem.name = "pidgin2adium"
|
9
|
+
gem.version = Pidgin2Adium::VERSION
|
8
10
|
gem.summary = %Q{Pidgin2Adium is a fast, easy way to convert Pidgin (formerly gaim) logs to the Adium format}
|
9
11
|
gem.description = %Q{Pidgin2Adium is a fast, easy way to convert Pidgin (formerly gaim) logs to the Adium format.}
|
10
12
|
gem.email = "gbw@brandeis.edu"
|
11
13
|
gem.homepage = "http://github.com/gabebw/pidgin2adium"
|
12
14
|
gem.authors = ["Gabe Berke-Williams"]
|
13
15
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
|
-
gem.add_development_dependency(%q<bundler>, [">= 0.
|
16
|
+
gem.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
15
17
|
gem.add_development_dependency(%q<jeweler>, [">= 0"])
|
16
|
-
gem.add_development_dependency(%q<rspec>, [">= 1.
|
18
|
+
gem.add_development_dependency(%q<rspec>, [">= 1.3.0"])
|
17
19
|
end
|
18
20
|
Jeweler::GemcutterTasks.new
|
19
21
|
rescue LoadError
|
@@ -22,22 +24,22 @@ end
|
|
22
24
|
|
23
25
|
begin
|
24
26
|
# RSpec 2
|
25
|
-
gem "rspec", ">= 2.0.0
|
27
|
+
gem "rspec", ">= 2.0.0"
|
26
28
|
require 'rspec/core/rake_task'
|
27
29
|
|
28
30
|
RSpec::Core::RakeTask.new(:spec) do |spec|
|
29
|
-
spec.
|
31
|
+
spec.rspec_opts = %w{-Ilib -Ispec}
|
30
32
|
spec.pattern = 'spec/**/*_spec.rb'
|
31
33
|
end
|
32
34
|
|
33
35
|
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
34
|
-
spec.
|
36
|
+
spec.rspec_opts = %w{-Ilib -Ispec}
|
35
37
|
spec.pattern = 'spec/**/*_spec.rb'
|
36
38
|
spec.rcov = true
|
37
39
|
end
|
38
40
|
rescue Gem::LoadError
|
39
41
|
# RSpec 1
|
40
|
-
gem "rspec"
|
42
|
+
gem "rspec", "~> 1.3.0"
|
41
43
|
require 'spec/rake/spectask'
|
42
44
|
|
43
45
|
Spec::Rake::SpecTask.new(:spec) do |spec|
|
@@ -50,6 +52,9 @@ rescue Gem::LoadError
|
|
50
52
|
spec.pattern = 'spec/**/*_spec.rb'
|
51
53
|
spec.rcov = true
|
52
54
|
end
|
55
|
+
rescue Gem::LoadError => bang
|
56
|
+
puts "!! Please install RSpec: `gem install rspec`"
|
57
|
+
raise bang
|
53
58
|
end
|
54
59
|
|
55
60
|
task :spec => :check_dependencies
|
@@ -59,7 +64,7 @@ task :default => :spec
|
|
59
64
|
|
60
65
|
require 'rake/rdoctask'
|
61
66
|
Rake::RDocTask.new do |rdoc|
|
62
|
-
version =
|
67
|
+
version = Pidgin2Adium::VERSION
|
63
68
|
|
64
69
|
rdoc.rdoc_dir = 'rdoc'
|
65
70
|
rdoc.title = "pidgin2adium #{version}"
|
data/lib/pidgin2adium.rb
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
|
6
6
|
require 'fileutils'
|
7
7
|
require 'time'
|
8
|
+
require 'version'
|
8
9
|
require 'pidgin2adium/parsers/all'
|
9
10
|
|
10
11
|
module Pidgin2Adium
|
@@ -13,124 +14,121 @@ module Pidgin2Adium
|
|
13
14
|
ADIUM_LOG_DIR = File.expand_path('~/Library/Application Support/Adium 2.0/Users/Default/Logs/') << '/'
|
14
15
|
# These files/directories show up in Dir.entries()
|
15
16
|
BAD_DIRS = %w{. .. .DS_Store Thumbs.db .system}
|
16
|
-
VERSION = "3.1.0"
|
17
|
-
# "-0500" (3d rather than 2d to allow for "+")
|
18
|
-
DEFAULT_TZ_OFFSET = sprintf('%+03d00', Time.zone_offset(Time.now.zone) / 3600)
|
19
17
|
# For displaying after we finish converting
|
20
18
|
@@oops_messages = []
|
21
19
|
@@error_messages = []
|
22
20
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
def oops(str) #:nodoc:
|
28
|
-
@@oops_messages << str
|
29
|
-
warn("Oops: #{str}")
|
30
|
-
end
|
21
|
+
def log_msg(str) #:nodoc:
|
22
|
+
puts str.to_s
|
23
|
+
end
|
31
24
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
25
|
+
def oops(str) #:nodoc:
|
26
|
+
@@oops_messages << str
|
27
|
+
warn("Oops: #{str}")
|
28
|
+
end
|
36
29
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
30
|
+
def error(str) #:nodoc:
|
31
|
+
@@error_messages << str
|
32
|
+
warn("Error: #{str}")
|
33
|
+
end
|
41
34
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
ext = File.extname(logfile_path).sub('.', '').downcase
|
35
|
+
#######################
|
36
|
+
#So that we can use log_msg when calling delete_search_indexes() by itself
|
37
|
+
module_function :log_msg, :oops, :error
|
38
|
+
#######################
|
47
39
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
error("Doing nothing, logfile is not a text or html file. Path: #{logfile_path}.")
|
54
|
-
return false
|
55
|
-
end
|
40
|
+
# Parses the provided log.
|
41
|
+
# Returns a LogFile instance or false if an error occurred.
|
42
|
+
def parse(logfile_path, my_aliases)
|
43
|
+
logfile_path = File.expand_path(logfile_path)
|
44
|
+
ext = File.extname(logfile_path).sub('.', '').downcase
|
56
45
|
|
57
|
-
|
46
|
+
if(ext == "html" || ext == "htm")
|
47
|
+
parser = HtmlLogParser.new(logfile_path, my_aliases)
|
48
|
+
elsif(ext == "txt")
|
49
|
+
parser = TextLogParser.new(logfile_path, my_aliases)
|
50
|
+
else
|
51
|
+
error("Doing nothing, logfile is not a text or html file. Path: #{logfile_path}.")
|
52
|
+
return false
|
58
53
|
end
|
59
54
|
|
60
|
-
|
61
|
-
|
62
|
-
# * true if it successfully converted and wrote out the log,
|
63
|
-
# * false if an error occurred, or
|
64
|
-
# * Pidgin2Adium::FILE_EXISTS if file already exists AND
|
65
|
-
# opts[:overwrite] = false.
|
66
|
-
#
|
67
|
-
# You can add options using the _opts_ hash, which can have the following
|
68
|
-
# keys, all of which are optional:
|
69
|
-
# * *overwrite*: If true, then overwrite even if log is found.
|
70
|
-
# Defaults to false.
|
71
|
-
# * *output_dir*: The top-level dir to put the logs in.
|
72
|
-
# Logs under output_dir are still each in their own folders, etc.
|
73
|
-
# Defaults to Pidgin2Adium::ADIUM_LOG_DIR
|
74
|
-
def parse_and_generate(logfile_path, my_aliases, opts = {})
|
75
|
-
opts = {} unless opts.is_a?(Hash)
|
76
|
-
overwrite = !!opts[:overwrite]
|
77
|
-
if opts.key?(:output_dir)
|
78
|
-
output_dir = opts[:output_dir]
|
79
|
-
else
|
80
|
-
output_dir = ADIUM_LOG_DIR
|
81
|
-
end
|
55
|
+
return parser.parse()
|
56
|
+
end
|
82
57
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
58
|
+
# Parses the provided log and writes out the log in Adium format.
|
59
|
+
# Returns:
|
60
|
+
# * true if it successfully converted and wrote out the log,
|
61
|
+
# * false if an error occurred, or
|
62
|
+
# * Pidgin2Adium::FILE_EXISTS if file already exists AND
|
63
|
+
# opts[:overwrite] = false.
|
64
|
+
#
|
65
|
+
# You can add options using the _opts_ hash, which can have the following
|
66
|
+
# keys, all of which are optional:
|
67
|
+
# * *overwrite*: If true, then overwrite even if log is found.
|
68
|
+
# Defaults to false.
|
69
|
+
# * *output_dir*: The top-level dir to put the logs in.
|
70
|
+
# Logs under output_dir are still each in their own folders, etc.
|
71
|
+
# Defaults to Pidgin2Adium::ADIUM_LOG_DIR
|
72
|
+
def parse_and_generate(logfile_path, my_aliases, opts = {})
|
73
|
+
opts = {} unless opts.is_a?(Hash)
|
74
|
+
overwrite = !!opts[:overwrite]
|
75
|
+
if opts.key?(:output_dir)
|
76
|
+
output_dir = opts[:output_dir]
|
77
|
+
else
|
78
|
+
output_dir = ADIUM_LOG_DIR
|
79
|
+
end
|
92
80
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
81
|
+
unless File.directory?(output_dir)
|
82
|
+
puts "Output log directory (#{output_dir}) does not exist or is not a directory."
|
83
|
+
begin
|
84
|
+
FileUtils.mkdir_p(output_dir)
|
85
|
+
rescue Errno::EACCES
|
86
|
+
puts "Permission denied, could not create output directory (#{output_dir})"
|
98
87
|
return false
|
99
|
-
elsif dest_file_path == FILE_EXISTS
|
100
|
-
log_msg("File already exists.")
|
101
|
-
return FILE_EXISTS
|
102
|
-
else
|
103
|
-
log_msg("Output to: #{dest_file_path}")
|
104
|
-
return true
|
105
88
|
end
|
106
89
|
end
|
107
90
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
91
|
+
logfile_obj = parse(logfile_path, my_aliases)
|
92
|
+
return false if logfile_obj == false
|
93
|
+
dest_file_path = logfile_obj.write_out(overwrite, output_dir)
|
94
|
+
if dest_file_path == false
|
95
|
+
error("Successfully parsed file, but failed to write it out. Path: #{logfile_path}.")
|
96
|
+
return false
|
97
|
+
elsif dest_file_path == FILE_EXISTS
|
98
|
+
log_msg("File already exists.")
|
99
|
+
return FILE_EXISTS
|
100
|
+
else
|
101
|
+
log_msg("Output to: #{dest_file_path}")
|
102
|
+
return true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Newly-converted logs are viewable in the Adium Chat Transcript
|
107
|
+
# Viewer, but are not indexed, so a search of the logs doesn't give
|
108
|
+
# results from the converted logs. To fix this, we delete the cached log
|
109
|
+
# indexes, which forces Adium to re-index.
|
110
|
+
#
|
111
|
+
# Note: This function is run by LogConverter after converting all of its
|
112
|
+
# files. LogFile.write_out intentionally does _not_ run it in order to
|
113
|
+
# allow for batch-processing of files. Thus, you will probably want to run
|
114
|
+
# Pidgin2Adium.delete_search_indexes after running LogFile.write_out in
|
115
|
+
# your own scripts.
|
116
|
+
def delete_search_indexes()
|
117
|
+
log_msg "Deleting log search indexes in order to force re-indexing of imported logs..."
|
118
|
+
dirty_file = File.expand_path("~/Library/Caches/Adium/Default/DirtyLogs.plist")
|
119
|
+
log_index_file = File.expand_path("~/Library/Caches/Adium/Default/Logs.index")
|
120
|
+
[dirty_file, log_index_file].each do |f|
|
121
|
+
if File.exist?(f)
|
122
|
+
if File.writable?(f)
|
123
|
+
File.delete(f)
|
124
|
+
else
|
125
|
+
error("File exists but is not writable. Please delete it yourself: #{f}")
|
129
126
|
end
|
130
127
|
end
|
131
|
-
log_msg "...done."
|
132
|
-
log_msg "When you next start the Adium Chat Transcript Viewer, it will re-index the logs, which may take a while."
|
133
128
|
end
|
129
|
+
log_msg "...done."
|
130
|
+
log_msg "When you next start the Adium Chat Transcript Viewer, it will re-index the logs, which may take a while."
|
131
|
+
end
|
134
132
|
|
135
|
-
|
133
|
+
module_function :parse, :parse_and_generate, :delete_search_indexes
|
136
134
|
end
|
@@ -41,11 +41,8 @@ module Pidgin2Adium
|
|
41
41
|
|
42
42
|
# Returns contents of log file
|
43
43
|
def to_s
|
44
|
-
|
45
|
-
|
46
|
-
@chat_str = @chat_lines.map{|l| l.to_s }.join
|
47
|
-
end
|
48
|
-
return @chat_str
|
44
|
+
# Faster than inject() or each()
|
45
|
+
@chat_str ||= @chat_lines.map{|l| l.to_s }.join
|
49
46
|
end
|
50
47
|
|
51
48
|
def each(&blk)
|
@@ -8,15 +8,32 @@ module Pidgin2Adium
|
|
8
8
|
# appropriate for putting in an Adium log file.
|
9
9
|
# Subclasses: XMLMessage, AutoReplyMessage, StatusMessage, Event.
|
10
10
|
class Message
|
11
|
+
include Comparable
|
11
12
|
def initialize(sender, time, buddy_alias)
|
12
13
|
# The sender's screen name
|
13
14
|
@sender = sender
|
14
15
|
# The time the message was sent, in Adium format (e.g.
|
15
16
|
# "2008-10-05T22:26:20-0800")
|
16
17
|
@time = time
|
18
|
+
@time_object = Time.parse(@time)
|
17
19
|
# The receiver's alias (NOT screen name)
|
18
20
|
@buddy_alias = buddy_alias
|
19
21
|
end
|
20
22
|
attr_accessor :sender, :time, :buddy_alias
|
23
|
+
|
24
|
+
# Compare this Message to +other_message+, based on their timestamps.
|
25
|
+
# Returns a number < 0 if this message was sent before +other_message+,
|
26
|
+
# 0 if they were sent at the same time, and a number > 0 if this message
|
27
|
+
# was sent after +other_message+.
|
28
|
+
def <=>(other_message)
|
29
|
+
return @time_object - other_message.time_object
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
# Protected because Time.parse doesn't have exactly the right time
|
34
|
+
# zone. It works fine for <=>, though.
|
35
|
+
def time_object
|
36
|
+
return @time_object
|
37
|
+
end
|
21
38
|
end
|
22
39
|
end
|
@@ -34,8 +34,6 @@ module Pidgin2Adium
|
|
34
34
|
# us an alias.
|
35
35
|
@user_alias = user_aliases.split(',')[0]
|
36
36
|
|
37
|
-
@tz_offset = get_time_zone_offset()
|
38
|
-
|
39
37
|
@log_file_is_valid = true
|
40
38
|
begin
|
41
39
|
file = File.new(@src_path, 'r')
|
@@ -48,28 +46,20 @@ module Pidgin2Adium
|
|
48
46
|
return nil
|
49
47
|
end
|
50
48
|
|
51
|
-
# Time regexes must be set before pre_parse().
|
52
|
-
# "4/18/2007 11:02:00 AM" => %w{4, 18, 2007
|
49
|
+
# Time regexes must be set before pre_parse!().
|
50
|
+
# "4/18/2007 11:02:00 AM" => %w{4, 18, 2007}
|
53
51
|
# ONLY used (if at all) in first line of chat ("Conversation with...at...")
|
54
|
-
@time_regex_first_line = %r{^(\d{1,2})/(\d{1,2})/(\d{4})
|
55
|
-
# "2007-04-17 12:33:13" => %w{2007, 04, 17
|
56
|
-
@time_regex = /^(\d{4})-(\d{2})-(\d{2})
|
52
|
+
@time_regex_first_line = %r{^(\d{1,2})/(\d{1,2})/(\d{4}) \d{1,2}:\d{2}:\d{2} [AP]M$}
|
53
|
+
# "2007-04-17 12:33:13" => %w{2007, 04, 17}
|
54
|
+
@time_regex = /^(\d{4})-(\d{2})-(\d{2}) \d{2}:\d{2}:\d{2}$/
|
57
55
|
|
58
56
|
begin
|
59
|
-
|
60
|
-
|
61
|
-
@
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
# * :year
|
66
|
-
# * :mon
|
67
|
-
# * :mday (day of month)
|
68
|
-
# You should be able to fill everything else in. If you can't,
|
69
|
-
# something's wrong.
|
70
|
-
@basic_time_info,
|
71
|
-
# When the chat started, in Adium's format
|
72
|
-
@adium_chat_time_start = pre_parse()
|
57
|
+
successfully_set_variables = pre_parse!
|
58
|
+
if not successfully_set_variables
|
59
|
+
error("Failed to set some key variables: #{@src_path}")
|
60
|
+
@log_file_is_valid = false
|
61
|
+
return
|
62
|
+
end
|
73
63
|
rescue InvalidFirstLineError
|
74
64
|
# The first line isn't parseable
|
75
65
|
@log_file_is_valid = false
|
@@ -173,119 +163,76 @@ module Pidgin2Adium
|
|
173
163
|
return LogFile.new(@file_content, @service, @user_SN, @partner_SN, @adium_chat_time_start)
|
174
164
|
end
|
175
165
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
return tz_offset
|
166
|
+
# Returns a Time object, or nil if the format string doesn't match the
|
167
|
+
# time string.
|
168
|
+
def strptime(time, format)
|
169
|
+
date_hash = Date._strptime(time, format)
|
170
|
+
return nil if date_hash.nil?
|
171
|
+
# Fill in any blanks using @basic_time_info
|
172
|
+
date_hash = @basic_time_info.merge(date_hash)
|
173
|
+
time = Time.local(date_hash[:year], date_hash[:mon], date_hash[:mday],
|
174
|
+
date_hash[:hour], date_hash[:min], date_hash[:sec],
|
175
|
+
date_hash[:sec_fraction], date_hash[:zone])
|
176
|
+
time
|
188
177
|
end
|
189
178
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
179
|
+
# Tries to parse _time_ (a string) according to the formats in _formats_, which
|
180
|
+
# should be an array of strings. For more on acceptable format strings,
|
181
|
+
# see the official documentation for Time.strptime. Returns a Time
|
182
|
+
# object or nil (if no formats matched).
|
183
|
+
def try_to_parse_time_with_formats(time, formats)
|
195
184
|
parsed = nil
|
196
185
|
formats.each do |format|
|
197
|
-
|
198
|
-
|
199
|
-
break
|
200
|
-
rescue ArgumentError
|
201
|
-
end
|
186
|
+
parsed = strptime(time, format)
|
187
|
+
break unless parsed.nil?
|
202
188
|
end
|
203
189
|
parsed
|
204
190
|
end
|
205
191
|
|
206
192
|
def try_to_parse_time(time)
|
207
193
|
formats = [
|
194
|
+
"%m/%d/%Y %I:%M:%S %P", # 01/22/2008 03:01:45 PM
|
195
|
+
"%Y-%m-%d %H:%M:%S", # 2008-01-22 23:08:24
|
208
196
|
"%Y/%m/%d %H:%M:%S", # 2008/01/22 04:01:45
|
209
|
-
"%Y-%m-%d %H:%M:%S" # 2008-01-22 04:01:45
|
197
|
+
"%Y-%m-%d %H:%M:%S", # 2008-01-22 04:01:45
|
198
|
+
'%a %d %b %Y %H:%M:%S %p %Z' # "Sat 18 Apr 2009 10:43:35 AM PDT"
|
210
199
|
]
|
211
|
-
|
212
|
-
formats.each do |format|
|
213
|
-
begin
|
214
|
-
parsed = Time.strptime(time, format)
|
215
|
-
break
|
216
|
-
rescue ArgumentError
|
217
|
-
end
|
218
|
-
end
|
219
|
-
parsed
|
200
|
+
try_to_parse_time_with_formats(time, formats)
|
220
201
|
end
|
221
202
|
|
222
203
|
def try_to_parse_minimal_time(minimal_time)
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
time_hash = nil
|
204
|
+
formats = [
|
205
|
+
"%I:%M:%S %P", # 04:01:45 AM
|
206
|
+
"%H:%M:%S" # 23:01:45
|
207
|
+
]
|
229
208
|
|
230
|
-
|
231
|
-
# timestamps
|
232
|
-
if minimal_time =~ /[AP]M$/
|
233
|
-
time_hash = Date._strptime(minimal_time, minimal_format_with_ampm)
|
234
|
-
else
|
235
|
-
time_hash = Date._strptime(minimal_time, minimal_format_without_ampm)
|
236
|
-
end
|
237
|
-
if time_hash.nil?
|
238
|
-
# Date._strptime returns nil on failure
|
239
|
-
return nil
|
240
|
-
end
|
241
|
-
# Fill in the blanks
|
242
|
-
time_hash[:year] = @basic_time_info[:year]
|
243
|
-
time_hash[:mon] = @basic_time_info[:mon]
|
244
|
-
time_hash[:mday] = @basic_time_info[:mday]
|
245
|
-
new_time = Time.local(time_hash[:year],
|
246
|
-
time_hash[:mon],
|
247
|
-
time_hash[:mday],
|
248
|
-
time_hash[:hour],
|
249
|
-
time_hash[:min],
|
250
|
-
time_hash[:sec])
|
251
|
-
new_time
|
209
|
+
try_to_parse_time_with_formats(minimal_time, formats)
|
252
210
|
end
|
253
211
|
|
254
|
-
|
255
|
-
#--
|
256
|
-
# Adium time format: YYYY-MM-DD\THH:MM:SS[+-]TZ_HRS like:
|
257
|
-
# 2008-10-05T22:26:20-0800
|
258
|
-
# HOWEVER:
|
259
|
-
# If it's the first line, then return it like this (note periods):
|
260
|
-
# 2008-10-05T22.26.20-0800
|
261
|
-
# because it will be used in the filename.
|
262
|
-
#++
|
263
212
|
# Converts a pidgin datestamp to an Adium one.
|
264
213
|
# Returns a string representation of _time_ or
|
265
214
|
# nil if it couldn't parse the provided _time_.
|
266
|
-
def create_adium_time(time
|
215
|
+
def create_adium_time(time)
|
267
216
|
return nil if time.nil?
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
new_time = try_to_parse_time(time)
|
272
|
-
if new_time.nil?
|
273
|
-
new_time = try_to_parse_minimal_time(time)
|
274
|
-
end
|
217
|
+
new_time = try_to_parse_time(time)
|
218
|
+
if new_time.nil?
|
219
|
+
new_time = try_to_parse_minimal_time(time)
|
275
220
|
end
|
276
221
|
|
277
222
|
return nil if new_time.nil?
|
278
223
|
|
279
|
-
|
280
|
-
adium_time = new_time.strftime("%Y-%m-%dT%H.%M.%S#{@tz_offset}")
|
281
|
-
else
|
282
|
-
adium_time = new_time.strftime("%Y-%m-%dT%H:%M:%S#{@tz_offset}")
|
283
|
-
end
|
284
|
-
adium_time
|
224
|
+
new_time.xmlschema
|
285
225
|
end
|
286
226
|
|
287
|
-
# Extract required data from the file. Run by parse.
|
288
|
-
|
227
|
+
# Extract required data from the file. Run by parse. Sets these
|
228
|
+
# variables:
|
229
|
+
# * @service
|
230
|
+
# * @user_SN
|
231
|
+
# * @partner_SN
|
232
|
+
# * @basic_time_info
|
233
|
+
# * @adium_chat_time_start
|
234
|
+
# Returns true if none of these variables are false or nil.
|
235
|
+
def pre_parse!
|
289
236
|
# Deal with first line.
|
290
237
|
|
291
238
|
# the first line is special. It tells us (in order of regex groups):
|
@@ -297,27 +244,43 @@ module Pidgin2Adium
|
|
297
244
|
if first_line_match.nil?
|
298
245
|
raise InvalidFirstLineError
|
299
246
|
else
|
300
|
-
|
247
|
+
# first_line_match is like so:
|
248
|
+
# ["Conversation with BUDDY_PERSON at 2006-12-21 22:36:06 on awesome SN (aim)",
|
249
|
+
# "BUDDY_PERSON",
|
250
|
+
# "2006-12-21 22:36:06",
|
251
|
+
# "awesome SN",
|
252
|
+
# "aim"]
|
253
|
+
@service = first_line_match[4]
|
301
254
|
# @user_SN is normalized to avoid "AIM.name" and "AIM.na me" folders
|
302
|
-
user_SN = first_line_match[3].downcase.tr(' ', '')
|
303
|
-
partner_SN = first_line_match[1]
|
255
|
+
@user_SN = first_line_match[3].downcase.tr(' ', '')
|
256
|
+
@partner_SN = first_line_match[1]
|
304
257
|
pidgin_chat_time_start = first_line_match[2]
|
305
|
-
basic_time_info
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
258
|
+
# @basic_time_info is for files that only have the full
|
259
|
+
# timestamp at the top; we can use it to fill in the minimal
|
260
|
+
# per-line timestamps. It is a hash with 3 keys:
|
261
|
+
# * :year
|
262
|
+
# * :mon
|
263
|
+
# * :mday (day of month)
|
264
|
+
# You should be able to fill everything else in. If you can't,
|
265
|
+
# something's wrong.
|
266
|
+
@basic_time_info = case pidgin_chat_time_start
|
267
|
+
when @time_regex
|
268
|
+
{:year => $1.to_i,
|
269
|
+
:mon => $2.to_i,
|
270
|
+
:mday => $3.to_i}
|
271
|
+
when @time_regex_first_line
|
272
|
+
{:year => $3.to_i,
|
273
|
+
:mon => $1.to_i,
|
274
|
+
:mday => $2.to_i}
|
275
|
+
end
|
276
|
+
# Need @basic_time_info set for create_adium_time
|
277
|
+
# When the chat started, in Adium's format
|
278
|
+
@adium_chat_time_start = create_adium_time(pidgin_chat_time_start)
|
279
|
+
[@service,
|
280
|
+
@user_SN,
|
281
|
+
@partner_SN,
|
282
|
+
@basic_time_info,
|
283
|
+
@adium_chat_time_start].all?
|
321
284
|
end
|
322
285
|
end
|
323
286
|
|
data/lib/version.rb
ADDED
data/pidgin2adium.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{pidgin2adium}
|
8
|
-
s.version = "3.
|
8
|
+
s.version = "3.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Gabe Berke-Williams"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-10-12}
|
13
13
|
s.default_executable = %q{pidgin2adium}
|
14
14
|
s.description = %q{Pidgin2Adium is a fast, easy way to convert Pidgin (formerly gaim) logs to the Adium format.}
|
15
15
|
s.email = %q{gbw@brandeis.edu}
|
@@ -30,7 +30,6 @@ Gem::Specification.new do |s|
|
|
30
30
|
"Manifest.txt",
|
31
31
|
"README.rdoc",
|
32
32
|
"Rakefile",
|
33
|
-
"VERSION",
|
34
33
|
"bin/pidgin2adium",
|
35
34
|
"config/website.yml",
|
36
35
|
"ext/balance_tags_c/balance_tags_c.c",
|
@@ -50,6 +49,7 @@ Gem::Specification.new do |s|
|
|
50
49
|
"lib/pidgin2adium/parsers/basic_parser.rb",
|
51
50
|
"lib/pidgin2adium/parsers/html_log_parser.rb",
|
52
51
|
"lib/pidgin2adium/parsers/text_log_parser.rb",
|
52
|
+
"lib/version.rb",
|
53
53
|
"pidgin2adium.gemspec",
|
54
54
|
"spec/balance_tags_c_extn_spec.rb",
|
55
55
|
"spec/basic_parser_spec.rb",
|
@@ -90,18 +90,18 @@ Gem::Specification.new do |s|
|
|
90
90
|
s.specification_version = 3
|
91
91
|
|
92
92
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
93
|
-
s.add_development_dependency(%q<bundler>, [">= 0.
|
93
|
+
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
94
94
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
95
|
-
s.add_development_dependency(%q<rspec>, [">= 1.
|
95
|
+
s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
|
96
96
|
else
|
97
|
-
s.add_dependency(%q<bundler>, [">= 0.
|
97
|
+
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
98
98
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
99
|
-
s.add_dependency(%q<rspec>, [">= 1.
|
99
|
+
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
100
100
|
end
|
101
101
|
else
|
102
|
-
s.add_dependency(%q<bundler>, [">= 0.
|
102
|
+
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
103
103
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
104
|
-
s.add_dependency(%q<rspec>, [">= 1.
|
104
|
+
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
data/spec/basic_parser_spec.rb
CHANGED
@@ -13,24 +13,6 @@ describe "BasicParser" do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
describe "#get_time_zone_offset" do
|
17
|
-
context "with no timezone available" do
|
18
|
-
it "should return the local time zone" do
|
19
|
-
bp = Pidgin2Adium::BasicParser.new(@text_logfile_path,
|
20
|
-
@aliases)
|
21
|
-
bp.get_time_zone_offset.should == @current_tz_offset
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
context "with a time zone available" do
|
26
|
-
it "should return the logfiles's time zone" do
|
27
|
-
bp = Pidgin2Adium::BasicParser.new(@html_logfile_path,
|
28
|
-
@aliases)
|
29
|
-
bp.get_time_zone_offset.should == "-0500"
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
16
|
describe "#create_adium_time" do
|
35
17
|
before(:each) do
|
36
18
|
@first_line_time = "4/18/2007 11:02:00 AM"
|
@@ -46,23 +28,23 @@ describe "BasicParser" do
|
|
46
28
|
end
|
47
29
|
|
48
30
|
it "should parse a first line time correctly" do
|
49
|
-
time = @bp.create_adium_time(@first_line_time
|
50
|
-
time.should
|
31
|
+
time = @bp.create_adium_time(@first_line_time)
|
32
|
+
time.should =~ /2007-04-18T11:02:00-\d{2}:00/
|
51
33
|
end
|
52
34
|
|
53
35
|
it "should parse a normal time correctly" do
|
54
36
|
time = @bp.create_adium_time(@time)
|
55
|
-
time.should
|
37
|
+
time.should =~ /2007-08-20T12:33:13-\d{2}:00/
|
56
38
|
end
|
57
39
|
|
58
40
|
it "should parse a minimal time correctly" do
|
59
41
|
time = @bp.create_adium_time(@minimal_time)
|
60
|
-
time.should
|
42
|
+
time.should =~ /2008-01-15T04:22:05-\d{2}:00/
|
61
43
|
end
|
62
44
|
|
63
45
|
it "should parse a minimal time without AM/PM correctly" do
|
64
46
|
time = @bp.create_adium_time(@minimal_time_2)
|
65
|
-
time.should
|
47
|
+
time.should =~ /2008-01-15T04:22:05-\d{2}:00/
|
66
48
|
end
|
67
49
|
|
68
50
|
it "should return an array of nils for an invalid time" do
|
@@ -92,7 +74,7 @@ describe "BasicParser" do
|
|
92
74
|
'othersn', # my SN
|
93
75
|
'aolsystemmsg', # other person's SN
|
94
76
|
{:year=>2008, :mon=>1, :mday=>15}, # basic time info
|
95
|
-
'2008-01-15T07
|
77
|
+
'2008-01-15T07:14:45-05:00' # chat start time
|
96
78
|
]
|
97
79
|
end
|
98
80
|
end
|
@@ -129,7 +111,7 @@ describe "BasicParser" do
|
|
129
111
|
"To sign off the other location(s), reply to this message " + "with the number 1. Click " +
|
130
112
|
"<a href='http://www.aim.com/password/routing.adp'>here</a> " +
|
131
113
|
"for more information."
|
132
|
-
@matches = ['2008-01-15T07.14.45-
|
114
|
+
@matches = ['2008-01-15T07.14.45-05:00', # time
|
133
115
|
'AOL System Msg', # alias
|
134
116
|
nil, # not an auto-reply
|
135
117
|
body # message body
|
@@ -128,7 +128,7 @@ describe "HtmlLogParser" do
|
|
128
128
|
first_msg.sender.should == "aolsystemmsg"
|
129
129
|
first_msg.buddy_alias.should == "AOL System Msg"
|
130
130
|
# Use regex to ignore time zone
|
131
|
-
first_msg.time.should =~ /^2008-01-15T07:14:45[-+]\d{2}00$/
|
131
|
+
first_msg.time.should =~ /^2008-01-15T07:14:45[-+]\d{2}:00$/
|
132
132
|
# This fails due to balance_tags_c().
|
133
133
|
good_body = %Q{Your screen name (otherSN) is now signed into AOL(R) Instant Messenger (TM) in 2 locations.} + " " +
|
134
134
|
%Q{To sign off the other location(s), reply to this message with the number 1.} + " " +
|
@@ -137,13 +137,13 @@ describe "HtmlLogParser" do
|
|
137
137
|
|
138
138
|
second_msg.sender.should == "othersn"
|
139
139
|
second_msg.buddy_alias.should == "Gabe B-W"
|
140
|
-
second_msg.time.should =~ /^2008-01-15T07:14:48[-+]\d{2}00$/
|
140
|
+
second_msg.time.should =~ /^2008-01-15T07:14:48[-+]\d{2}:00$/
|
141
141
|
second_msg.body.should == "1"
|
142
142
|
|
143
143
|
third_msg.sender.should == "aolsystemmsg"
|
144
144
|
third_msg.buddy_alias.should == "AOL System Msg"
|
145
145
|
# Use regex to ignore time zone
|
146
|
-
third_msg.time.should =~ /^2008-01-15T07:14:48[-+]\d{2}00$/
|
146
|
+
third_msg.time.should =~ /^2008-01-15T07:14:48[-+]\d{2}:00$/
|
147
147
|
third_msg.body.should == "Your other AIM sessions have been signed-off. You are now signed-on from 1 location(s)."
|
148
148
|
end
|
149
149
|
end
|
data/spec/log_file_spec.rb
CHANGED
@@ -73,6 +73,18 @@ describe "LogFile" do
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
76
|
+
|
77
|
+
describe "#max" do
|
78
|
+
it "should return the most recent message" do
|
79
|
+
@logfile.max.should == @messages.last
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#min" do
|
84
|
+
it "should return the oldest message" do
|
85
|
+
@logfile.min.should == @messages.first
|
86
|
+
end
|
87
|
+
end
|
76
88
|
end
|
77
89
|
|
78
90
|
describe "#write_out" do
|
@@ -36,7 +36,7 @@ describe "TextLogParser" do
|
|
36
36
|
msg.body.should == "what are you doing tomorrow?"
|
37
37
|
msg.buddy_alias.should == "Gabe B-W"
|
38
38
|
# Use regex to ignore time zone
|
39
|
-
msg.time.should =~ /^2006-12-21T22:36:11[-+]\d{2}00$/
|
39
|
+
msg.time.should =~ /^2006-12-21T22:36:11[-+]\d{2}:00$/
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 3
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 3.
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 3.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Gabe Berke-Williams
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-10-12 00:00:00 -04:00
|
18
18
|
default_executable: pidgin2adium
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -26,10 +26,10 @@ dependencies:
|
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
segments:
|
29
|
+
- 1
|
30
|
+
- 0
|
29
31
|
- 0
|
30
|
-
|
31
|
-
- 26
|
32
|
-
version: 0.9.26
|
32
|
+
version: 1.0.0
|
33
33
|
type: :development
|
34
34
|
version_requirements: *id001
|
35
35
|
- !ruby/object:Gem::Dependency
|
@@ -55,9 +55,9 @@ dependencies:
|
|
55
55
|
- !ruby/object:Gem::Version
|
56
56
|
segments:
|
57
57
|
- 1
|
58
|
-
-
|
59
|
-
-
|
60
|
-
version: 1.
|
58
|
+
- 3
|
59
|
+
- 0
|
60
|
+
version: 1.3.0
|
61
61
|
type: :development
|
62
62
|
version_requirements: *id003
|
63
63
|
description: Pidgin2Adium is a fast, easy way to convert Pidgin (formerly gaim) logs to the Adium format.
|
@@ -80,7 +80,6 @@ files:
|
|
80
80
|
- Manifest.txt
|
81
81
|
- README.rdoc
|
82
82
|
- Rakefile
|
83
|
-
- VERSION
|
84
83
|
- bin/pidgin2adium
|
85
84
|
- config/website.yml
|
86
85
|
- ext/balance_tags_c/balance_tags_c.c
|
@@ -100,6 +99,7 @@ files:
|
|
100
99
|
- lib/pidgin2adium/parsers/basic_parser.rb
|
101
100
|
- lib/pidgin2adium/parsers/html_log_parser.rb
|
102
101
|
- lib/pidgin2adium/parsers/text_log_parser.rb
|
102
|
+
- lib/version.rb
|
103
103
|
- pidgin2adium.gemspec
|
104
104
|
- spec/balance_tags_c_extn_spec.rb
|
105
105
|
- spec/basic_parser_spec.rb
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
3.1.1
|