pidgin2adium 3.1.1 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|