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 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.9.26"])
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.2.9"])
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.beta.18"
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.spec_opts << %w{-Ilib -Ispec}
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.spec_opts << %w{-Ilib -Ispec}
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 = File.exist?('VERSION') ? File.read('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
- def log_msg(str) #:nodoc:
24
- puts str.to_s
25
- end
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
- def error(str) #:nodoc:
33
- @@error_messages << str
34
- warn("Error: #{str}")
35
- end
25
+ def oops(str) #:nodoc:
26
+ @@oops_messages << str
27
+ warn("Oops: #{str}")
28
+ end
36
29
 
37
- #######################
38
- #So that we can use log_msg when calling delete_search_indexes() by itself
39
- module_function :log_msg, :oops, :error
40
- #######################
30
+ def error(str) #:nodoc:
31
+ @@error_messages << str
32
+ warn("Error: #{str}")
33
+ end
41
34
 
42
- # Parses the provided log.
43
- # Returns a LogFile instance or false if an error occurred.
44
- def parse(logfile_path, my_aliases)
45
- logfile_path = File.expand_path(logfile_path)
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
- if(ext == "html" || ext == "htm")
49
- parser = HtmlLogParser.new(logfile_path, my_aliases)
50
- elsif(ext == "txt")
51
- parser = TextLogParser.new(logfile_path, my_aliases)
52
- else
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
- return parser.parse()
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
- # Parses the provided log and writes out the log in Adium format.
61
- # Returns:
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
- unless File.directory?(output_dir)
84
- puts "Output log directory (#{output_dir}) does not exist or is not a directory."
85
- begin
86
- FileUtils.mkdir_p(output_dir)
87
- rescue Errno::EACCES
88
- puts "Permission denied, could not create output directory (#{output_dir})"
89
- return false
90
- end
91
- end
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
- logfile_obj = parse(logfile_path, my_aliases)
94
- return false if logfile_obj == false
95
- dest_file_path = logfile_obj.write_out(overwrite, output_dir)
96
- if dest_file_path == false
97
- error("Successfully parsed file, but failed to write it out. Path: #{logfile_path}.")
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
- # Newly-converted logs are viewable in the Adium Chat Transcript
109
- # Viewer, but are not indexed, so a search of the logs doesn't give
110
- # results from the converted logs. To fix this, we delete the cached log
111
- # indexes, which forces Adium to re-index.
112
- #
113
- # Note: This function is run by LogConverter after converting all of its
114
- # files. LogFile.write_out intentionally does _not_ run it in order to
115
- # allow for batch-processing of files. Thus, you will probably want to run
116
- # Pidgin2Adium.delete_search_indexes after running LogFile.write_out in
117
- # your own scripts.
118
- def delete_search_indexes()
119
- log_msg "Deleting log search indexes in order to force re-indexing of imported logs..."
120
- dirty_file = File.expand_path("~/Library/Caches/Adium/Default/DirtyLogs.plist")
121
- log_index_file = File.expand_path("~/Library/Caches/Adium/Default/Logs.index")
122
- [dirty_file, log_index_file].each do |f|
123
- if File.exist?(f)
124
- if File.writable?(f)
125
- File.delete(f)
126
- else
127
- error("File exists but is not writable. Please delete it yourself: #{f}")
128
- end
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
- module_function :parse, :parse_and_generate, :delete_search_indexes
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
- if @chat_str.nil?
45
- # Faster than inject() or each()
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, 11, 02, 00, AM}
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}) (\d{1,2}):(\d{2}):(\d{2}) ([AP]M)$}
55
- # "2007-04-17 12:33:13" => %w{2007, 04, 17, 12, 33, 13}
56
- @time_regex = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\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
- @service,
60
- @user_SN,
61
- @partner_SN,
62
- # @basic_time_info is for files that only have the full
63
- # timestamp at the top; we can use it to fill in the minimal
64
- # per-line timestamps. It is a hash with 3 keys:
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
- def get_time_zone_offset()
177
- # We must have a tz_offset or else the Adium Chat Log viewer
178
- # doesn't read the date correctly and then:
179
- # 1) the log has an empty start date column in the viewer
180
- # 2) The timestamps are all the same for the whole log
181
- tz_match = /([-\+]\d+)[A-Z]{3}\.(?:txt|htm|html)/.match(@src_path)
182
- if tz_match and tz_match[1]
183
- tz_offset = tz_match[1]
184
- else
185
- tz_offset = Pidgin2Adium::DEFAULT_TZ_OFFSET
186
- end
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
- def try_to_parse_first_line_time(first_line_time)
191
- formats = [
192
- "%m/%d/%Y %I:%M:%S %P", # 01/22/2008 03:01:45 PM
193
- "%Y-%m-%d %H:%M:%S" # 2008-01-22 23:08:24
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
- begin
198
- parsed = Time.strptime(first_line_time, format)
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
- parsed = nil
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
- # 04:01:45 AM
224
- minimal_format_with_ampm = "%I:%M:%S %P"
225
- # 23:01:45
226
- minimal_format_without_ampm = "%H:%M:%S"
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
- # Use Date._strptime to allow filling in the blanks on minimal
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, is_first_line = false)
215
+ def create_adium_time(time)
267
216
  return nil if time.nil?
268
- if is_first_line
269
- new_time = try_to_parse_first_line_time(time)
270
- else
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
- if is_first_line
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
- def pre_parse
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
- service = first_line_match[4]
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 = case pidgin_chat_time_start
306
- when @time_regex
307
- {:year => $1.to_i,
308
- :mon => $2.to_i,
309
- :mday => $3.to_i}
310
- when @time_regex_first_line
311
- {:year => $3.to_i,
312
- :mon => $1.to_i,
313
- :mday => $2.to_i}
314
- end
315
- adium_chat_time_start = create_adium_time(pidgin_chat_time_start, true)
316
- return [service,
317
- user_SN,
318
- partner_SN,
319
- basic_time_info,
320
- adium_chat_time_start]
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
@@ -0,0 +1,3 @@
1
+ module Pidgin2Adium
2
+ VERSION = "3.2.0"
3
+ end
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.1.1"
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-08-13}
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.9.26"])
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.2.9"])
95
+ s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
96
96
  else
97
- s.add_dependency(%q<bundler>, [">= 0.9.26"])
97
+ s.add_dependency(%q<bundler>, [">= 1.0.0"])
98
98
  s.add_dependency(%q<jeweler>, [">= 0"])
99
- s.add_dependency(%q<rspec>, [">= 1.2.9"])
99
+ s.add_dependency(%q<rspec>, [">= 1.3.0"])
100
100
  end
101
101
  else
102
- s.add_dependency(%q<bundler>, [">= 0.9.26"])
102
+ s.add_dependency(%q<bundler>, [">= 1.0.0"])
103
103
  s.add_dependency(%q<jeweler>, [">= 0"])
104
- s.add_dependency(%q<rspec>, [">= 1.2.9"])
104
+ s.add_dependency(%q<rspec>, [">= 1.3.0"])
105
105
  end
106
106
  end
107
107
 
@@ -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, true)
50
- time.should == "2007-04-18T11.02.00-0500"
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 == "2007-08-20T12:33:13-0500"
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 == "2008-01-15T04:22:05-0500"
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 == "2008-01-15T04:22:05-0500"
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.14.45-0500' # chat start time
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-0500', # time
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
@@ -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
- - 1
8
- - 1
9
- version: 3.1.1
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-08-13 00:00:00 -07:00
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
- - 9
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
- - 2
59
- - 9
60
- version: 1.2.9
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