pidgin2adium 1.0.0 → 2.0.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/History.txt +6 -0
 - data/Manifest.txt +10 -0
 - data/README.rdoc +106 -0
 - data/Rakefile.rb +26 -0
 - data/bin/pidgin2adium +72 -0
 - data/lib/pidgin2adium.rb +120 -0
 - data/lib/pidgin2adium/{balance-tags.rb → balance_tags.rb} +32 -29
 - data/lib/pidgin2adium/log_converter.rb +68 -0
 - data/lib/pidgin2adium/log_file.rb +101 -0
 - data/lib/pidgin2adium/log_parser.rb +590 -0
 - metadata +39 -19
 - data/bin/pidgin2adium_logs +0 -67
 - data/bin/pidgin2adium_status +0 -15
 - data/lib/pidgin2adium/ChatFileGenerator.rb +0 -59
 - data/lib/pidgin2adium/SrcFileParse.rb +0 -485
 - data/lib/pidgin2adium/logs.rb +0 -250
 - data/lib/pidgin2adium/status.rb +0 -113
 
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification 
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: pidgin2adium
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version 
         
     | 
| 
       4 
     | 
    
         
            -
              version:  
     | 
| 
      
 4 
     | 
    
         
            +
              version: 2.0.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors: 
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Gabe B-W
         
     | 
| 
         @@ -9,32 +9,52 @@ autorequire: 
     | 
|
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
            date: 2009- 
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2009-11-24 00:00:00 -05:00
         
     | 
| 
       13 
13 
     | 
    
         
             
            default_executable: 
         
     | 
| 
       14 
     | 
    
         
            -
            dependencies:  
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
      
 14 
     | 
    
         
            +
            dependencies: 
         
     | 
| 
      
 15 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 16 
     | 
    
         
            +
              name: hoe
         
     | 
| 
      
 17 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 18 
     | 
    
         
            +
              version_requirement: 
         
     | 
| 
      
 19 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 20 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 21 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 22 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 23 
     | 
    
         
            +
                    version: 2.3.3
         
     | 
| 
      
 24 
     | 
    
         
            +
                version: 
         
     | 
| 
      
 25 
     | 
    
         
            +
            description: |-
         
     | 
| 
      
 26 
     | 
    
         
            +
              Pidgin2Adium is a fast, easy way to convert Pidgin (formerly gaim) logs to the
         
     | 
| 
      
 27 
     | 
    
         
            +
              Adium format.
         
     | 
| 
      
 28 
     | 
    
         
            +
              Note that it assumes a Mac OS X environment with Adium installed.
         
     | 
| 
      
 29 
     | 
    
         
            +
            email: 
         
     | 
| 
      
 30 
     | 
    
         
            +
            - gbw@brandeis.edu
         
     | 
| 
       18 
31 
     | 
    
         
             
            executables: 
         
     | 
| 
       19 
     | 
    
         
            -
            -  
     | 
| 
       20 
     | 
    
         
            -
            - pidgin2adium_status
         
     | 
| 
      
 32 
     | 
    
         
            +
            - pidgin2adium
         
     | 
| 
       21 
33 
     | 
    
         
             
            extensions: []
         
     | 
| 
       22 
34 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
            extra_rdoc_files:  
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 35 
     | 
    
         
            +
            extra_rdoc_files: 
         
     | 
| 
      
 36 
     | 
    
         
            +
            - History.txt
         
     | 
| 
      
 37 
     | 
    
         
            +
            - Manifest.txt
         
     | 
| 
      
 38 
     | 
    
         
            +
            - README.rdoc
         
     | 
| 
       25 
39 
     | 
    
         
             
            files: 
         
     | 
| 
       26 
     | 
    
         
            -
            -  
     | 
| 
       27 
     | 
    
         
            -
            -  
     | 
| 
       28 
     | 
    
         
            -
            -  
     | 
| 
       29 
     | 
    
         
            -
            -  
     | 
| 
       30 
     | 
    
         
            -
            -  
     | 
| 
      
 40 
     | 
    
         
            +
            - History.txt
         
     | 
| 
      
 41 
     | 
    
         
            +
            - Manifest.txt
         
     | 
| 
      
 42 
     | 
    
         
            +
            - README.rdoc
         
     | 
| 
      
 43 
     | 
    
         
            +
            - Rakefile.rb
         
     | 
| 
      
 44 
     | 
    
         
            +
            - bin/pidgin2adium
         
     | 
| 
      
 45 
     | 
    
         
            +
            - lib/pidgin2adium.rb
         
     | 
| 
      
 46 
     | 
    
         
            +
            - lib/pidgin2adium/balance_tags.rb
         
     | 
| 
      
 47 
     | 
    
         
            +
            - lib/pidgin2adium/log_converter.rb
         
     | 
| 
      
 48 
     | 
    
         
            +
            - lib/pidgin2adium/log_file.rb
         
     | 
| 
      
 49 
     | 
    
         
            +
            - lib/pidgin2adium/log_parser.rb
         
     | 
| 
       31 
50 
     | 
    
         
             
            has_rdoc: true
         
     | 
| 
       32 
     | 
    
         
            -
            homepage: http:// 
     | 
| 
      
 51 
     | 
    
         
            +
            homepage: http://rubyforge.org/projects/pidgin2adium/
         
     | 
| 
       33 
52 
     | 
    
         
             
            licenses: []
         
     | 
| 
       34 
53 
     | 
    
         | 
| 
       35 
54 
     | 
    
         
             
            post_install_message: 
         
     | 
| 
       36 
     | 
    
         
            -
            rdoc_options:  
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
      
 55 
     | 
    
         
            +
            rdoc_options: 
         
     | 
| 
      
 56 
     | 
    
         
            +
            - --main
         
     | 
| 
      
 57 
     | 
    
         
            +
            - README.rdoc
         
     | 
| 
       38 
58 
     | 
    
         
             
            require_paths: 
         
     | 
| 
       39 
59 
     | 
    
         
             
            - lib
         
     | 
| 
       40 
60 
     | 
    
         
             
            required_ruby_version: !ruby/object:Gem::Requirement 
         
     | 
| 
         @@ -55,6 +75,6 @@ rubyforge_project: pidgin2adium 
     | 
|
| 
       55 
75 
     | 
    
         
             
            rubygems_version: 1.3.5
         
     | 
| 
       56 
76 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       57 
77 
     | 
    
         
             
            specification_version: 3
         
     | 
| 
       58 
     | 
    
         
            -
            summary:  
     | 
| 
      
 78 
     | 
    
         
            +
            summary: Pidgin2Adium is a fast, easy way to convert Pidgin (formerly gaim) logs to the Adium format
         
     | 
| 
       59 
79 
     | 
    
         
             
            test_files: []
         
     | 
| 
       60 
80 
     | 
    
         | 
    
        data/bin/pidgin2adium_logs
    DELETED
    
    | 
         @@ -1,67 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #!/usr/bin/ruby -w
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            =begin
         
     | 
| 
       4 
     | 
    
         
            -
            Author: Gabe Berke-Williams, 2008
         
     | 
| 
       5 
     | 
    
         
            -
            This is the shell script, which is a wrapper around Pidgin2Adium::Logs.
         
     | 
| 
       6 
     | 
    
         
            -
            Call it like so:
         
     | 
| 
       7 
     | 
    
         
            -
            <tt>pidgin2adium_logs.rb -i ~/in_logs/ -o ~/out_logs/ -l AIM.myscreenname -a me,screenname,my_pidgin_alias,other_pidgin_alias</tt>
         
     | 
| 
       8 
     | 
    
         
            -
            For <tt>-a/--aliases</tt>, there is no need to use spaces or capitalization, since spaces will be stripped out and the aliases will
         
     | 
| 
       9 
     | 
    
         
            -
            be lowercased anyway.
         
     | 
| 
       10 
     | 
    
         
            -
            =end
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
            require 'pidgin2adium/logs'
         
     | 
| 
       13 
     | 
    
         
            -
            require 'optparse'
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
            options = {}
         
     | 
| 
       16 
     | 
    
         
            -
            OptionParser.new do |opts|
         
     | 
| 
       17 
     | 
    
         
            -
                opts.banner = "Usage: #{File.basename($0)} [options]"
         
     | 
| 
       18 
     | 
    
         
            -
                opts.on('-i IN_DIR', '--in IN_DIR', 'Specify directory where pidgin logs are stored') do |v|
         
     | 
| 
       19 
     | 
    
         
            -
            	options[:in] = v
         
     | 
| 
       20 
     | 
    
         
            -
                end
         
     | 
| 
       21 
     | 
    
         
            -
                opts.on('-o', '--out OUT_DIR', 'Specify directory where Adium logs will be stored (not the Adium directory in ~/Library)') do |out|
         
     | 
| 
       22 
     | 
    
         
            -
            	options[:out] = out
         
     | 
| 
       23 
     | 
    
         
            -
                end
         
     | 
| 
       24 
     | 
    
         
            -
                opts.on('-l', '--libdir LIBRARY_DIR',
         
     | 
| 
       25 
     | 
    
         
            -
            	    'Specify dirname where Adium logs are stored (eg "AIM.<username>" for',
         
     | 
| 
       26 
     | 
    
         
            -
            	    '~/Library/Application Support/Adium 2.0/Users/Default/Logs/AIM.<username>)') do |ld|
         
     | 
| 
       27 
     | 
    
         
            -
            	options[:libdir] = ld
         
     | 
| 
       28 
     | 
    
         
            -
                end
         
     | 
| 
       29 
     | 
    
         
            -
                opts.on('-d', '--debug', 'Turn debug on.') do |lf|
         
     | 
| 
       30 
     | 
    
         
            -
            	options[:debug] = true
         
     | 
| 
       31 
     | 
    
         
            -
                end
         
     | 
| 
       32 
     | 
    
         
            -
                opts.on('-t', "--time-zone [TIME ZONE]",
         
     | 
| 
       33 
     | 
    
         
            -
            	    "Set time zone like \"EST\". Defaults to local time zone: #{Time.now.zone}") do |tz|
         
     | 
| 
       34 
     | 
    
         
            -
            	options[:timezone] = tz
         
     | 
| 
       35 
     | 
    
         
            -
                end
         
     | 
| 
       36 
     | 
    
         
            -
                opts.on('-a', "--aliases MY_ALIASES_AND_SNs",
         
     | 
| 
       37 
     | 
    
         
            -
            	    "A comma-separated list of your aliases and screenname(s) so this script knows which person in a chat is you.",
         
     | 
| 
       38 
     | 
    
         
            -
            	    "Whitespace is removed and aliases are lowercased.") do |aliases|
         
     | 
| 
       39 
     | 
    
         
            -
            	options[:aliases] = aliases.split(',')
         
     | 
| 
       40 
     | 
    
         
            -
                end
         
     | 
| 
       41 
     | 
    
         
            -
                opts.on_tail("-h", "--help", "Show this message") do
         
     | 
| 
       42 
     | 
    
         
            -
            	puts opts
         
     | 
| 
       43 
     | 
    
         
            -
            	exit
         
     | 
| 
       44 
     | 
    
         
            -
                end
         
     | 
| 
       45 
     | 
    
         
            -
            end.parse!
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
            need_opts = false
         
     | 
| 
       48 
     | 
    
         
            -
            required_opts = [[:i, :in], [:o, :out], [:l, :libdir], [:a, :aliases]]
         
     | 
| 
       49 
     | 
    
         
            -
            required_opts.each do |short, long|
         
     | 
| 
       50 
     | 
    
         
            -
                if options.has_key?(short) or options.has_key?(long)
         
     | 
| 
       51 
     | 
    
         
            -
            	next
         
     | 
| 
       52 
     | 
    
         
            -
                else
         
     | 
| 
       53 
     | 
    
         
            -
            	need_opts = true
         
     | 
| 
       54 
     | 
    
         
            -
            	puts "Required option -#{short}/--#{long} missing."
         
     | 
| 
       55 
     | 
    
         
            -
                end
         
     | 
| 
       56 
     | 
    
         
            -
            end
         
     | 
| 
       57 
     | 
    
         
            -
            exit 1 if need_opts
         
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
            log_converter  =  Pidgin2Adium::Logs.new(options[:in],
         
     | 
| 
       60 
     | 
    
         
            -
            					 options[:out],
         
     | 
| 
       61 
     | 
    
         
            -
            					 options[:aliases],
         
     | 
| 
       62 
     | 
    
         
            -
            					 options[:libdir],
         
     | 
| 
       63 
     | 
    
         
            -
            					 options[:timezone],
         
     | 
| 
       64 
     | 
    
         
            -
            					 options[:debug]
         
     | 
| 
       65 
     | 
    
         
            -
            					)
         
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
            log_converter.start
         
     | 
    
        data/bin/pidgin2adium_status
    DELETED
    
    | 
         @@ -1,15 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #!/usr/bin/ruby
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            # Shell script wrapper for Pidgin2Adium::Status
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            require 'pidgin2adium/status'
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
            xml_file = ARGV[0]
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
            unless File.readable?(xml_file)
         
     | 
| 
       10 
     | 
    
         
            -
                puts "XML file (#{xml_file}) is not readable. Exiting."
         
     | 
| 
       11 
     | 
    
         
            -
                exit 1
         
     | 
| 
       12 
     | 
    
         
            -
            end
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
            status_converter = Pidgin2Adium::Status.new(xml_file)
         
     | 
| 
       15 
     | 
    
         
            -
            status_converter.start
         
     | 
| 
         @@ -1,59 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # ADD DOCUMENTATION
         
     | 
| 
       2 
     | 
    
         
            -
            require 'pidgin2adium/balance-tags.rb'
         
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
            module Pidgin2Adium
         
     | 
| 
       5 
     | 
    
         
            -
                class ChatFileGenerator
         
     | 
| 
       6 
     | 
    
         
            -
            	def initialize(service, userSN, partnerSN, adiumChatTimeStart, destDirBase)
         
     | 
| 
       7 
     | 
    
         
            -
            	    @service = service
         
     | 
| 
       8 
     | 
    
         
            -
            	    @userSN = userSN
         
     | 
| 
       9 
     | 
    
         
            -
            	    @partnerSN = partnerSN
         
     | 
| 
       10 
     | 
    
         
            -
            	    @adiumChatTimeStart = adiumChatTimeStart
         
     | 
| 
       11 
     | 
    
         
            -
            	    @destDirBase = destDirBase
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
            	    # @chatLines is an array of Message, Status, and Event objects
         
     | 
| 
       14 
     | 
    
         
            -
            	    @chatLines = []
         
     | 
| 
       15 
     | 
    
         
            -
            	    # key is for Pidgin, value is for Adium
         
     | 
| 
       16 
     | 
    
         
            -
            	    # Just used for <service>.<screenname> in directory structure
         
     | 
| 
       17 
     | 
    
         
            -
            	    @SERVICE_NAME_MAP = {'aim' => 'AIM',
         
     | 
| 
       18 
     | 
    
         
            -
            		'jabber' =>'jabber',
         
     | 
| 
       19 
     | 
    
         
            -
            		'gtalk'=> 'GTalk',
         
     | 
| 
       20 
     | 
    
         
            -
            		'icq' => 'ICQ',
         
     | 
| 
       21 
     | 
    
         
            -
            		'qq' => 'QQ',
         
     | 
| 
       22 
     | 
    
         
            -
            		'msn' => 'MSN',
         
     | 
| 
       23 
     | 
    
         
            -
            		'yahoo' => 'Yahoo'}
         
     | 
| 
       24 
     | 
    
         
            -
            	end
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
            	# Add a line to @chatLines.
         
     | 
| 
       27 
     | 
    
         
            -
            	# It is its own method because attr_writer creates the method
         
     | 
| 
       28 
     | 
    
         
            -
            	# 'chatMessage=', which doesn't help for chatMessage.push
         
     | 
| 
       29 
     | 
    
         
            -
            	def appendLine(line)
         
     | 
| 
       30 
     | 
    
         
            -
            	    @chatLines.push(line)
         
     | 
| 
       31 
     | 
    
         
            -
            	end
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
            	# Returns path of output file
         
     | 
| 
       34 
     | 
    
         
            -
            	def convert()
         
     | 
| 
       35 
     | 
    
         
            -
            	    serviceName = @SERVICE_NAME_MAP[@service.downcase]
         
     | 
| 
       36 
     | 
    
         
            -
            	    destDirReal = File.join(@destDirBase, "#{serviceName}.#{@userSN}", @partnerSN, "#{@partnerSN} (#{@adiumChatTimeStart}).chatlog")
         
     | 
| 
       37 
     | 
    
         
            -
            	    FileUtils.mkdir_p(destDirReal)
         
     | 
| 
       38 
     | 
    
         
            -
            	    destFilePath = destDirReal << '/' << "#{@partnerSN} (#{@adiumChatTimeStart}).xml"
         
     | 
| 
       39 
     | 
    
         
            -
            	    if File.exist?(destFilePath)
         
     | 
| 
       40 
     | 
    
         
            -
            		return Pidgin2Adium::Logs::FILE_EXISTS
         
     | 
| 
       41 
     | 
    
         
            -
            	    end
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
            	    allMsgs = ""
         
     | 
| 
       44 
     | 
    
         
            -
            	    # TODO: inject?
         
     | 
| 
       45 
     | 
    
         
            -
            	    @chatLines.each { |obj| allMsgs << obj.getOutput() }
         
     | 
| 
       46 
     | 
    
         
            -
            	    # xml is done.
         
     | 
| 
       47 
     | 
    
         
            -
            	    
         
     | 
| 
       48 
     | 
    
         
            -
            	    # no \n before </chat> because allMsgs has it already
         
     | 
| 
       49 
     | 
    
         
            -
            	    ret = sprintf('<?xml version="1.0" encoding="UTF-8" ?>'<<"\n"+
         
     | 
| 
       50 
     | 
    
         
            -
            		      '<chat xmlns="http://purl.org/net/ulf/ns/0.4-02" account="%s" service="%s">'<<"\n"<<'%s</chat>', @userSN, serviceName, allMsgs)
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
            	    # we already checked to see if the file previously existed.
         
     | 
| 
       53 
     | 
    
         
            -
            	    outfile = File.new(destFilePath, 'w')
         
     | 
| 
       54 
     | 
    
         
            -
            	    outfile.puts(ret)
         
     | 
| 
       55 
     | 
    
         
            -
            	    outfile.close
         
     | 
| 
       56 
     | 
    
         
            -
            	    return destFilePath
         
     | 
| 
       57 
     | 
    
         
            -
            	end
         
     | 
| 
       58 
     | 
    
         
            -
                end
         
     | 
| 
       59 
     | 
    
         
            -
            end
         
     | 
| 
         @@ -1,485 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # =SrcFileParse
         
     | 
| 
       2 
     | 
    
         
            -
            # The class +SrcFileParse+ has 2 subclasses, +SrcTxtFileParse+ and +SrcHtmlFileParse+
         
     | 
| 
       3 
     | 
    
         
            -
            # It parses the file passed into it and extracts the following
         
     | 
| 
       4 
     | 
    
         
            -
            # from each line in the chat: time, alias, and message and/or status.
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
            require 'parsedate'
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
            module Pidgin2Adium
         
     | 
| 
       9 
     | 
    
         
            -
                # The two subclasses of +SrcFileParse+,
         
     | 
| 
       10 
     | 
    
         
            -
                # +SrcTxtFileParse+ and +SrcHtmlFileParse+, only differ
         
     | 
| 
       11 
     | 
    
         
            -
                # in that they have their own @lineRegex, @lineRegexStatus,
         
     | 
| 
       12 
     | 
    
         
            -
                # and most importantly, createMsg and createStatusOrEventMsg, which take
         
     | 
| 
       13 
     | 
    
         
            -
                # the +MatchData+ objects from matching against @lineRegex or
         
     | 
| 
       14 
     | 
    
         
            -
                # @lineRegexStatus, respectively and return object instances.
         
     | 
| 
       15 
     | 
    
         
            -
                # +createMsg+ returns a +Message+ instance (or one of its subclasses).
         
     | 
| 
       16 
     | 
    
         
            -
                # +createStatusOrEventMsg+ returns a +Status+ or +Event+ instance.
         
     | 
| 
       17 
     | 
    
         
            -
                class SrcFileParse
         
     | 
| 
       18 
     | 
    
         
            -
            	def initialize(srcPath, destDirBase, userAliases, userTZ, userTZOffset)
         
     | 
| 
       19 
     | 
    
         
            -
            	    @srcPath = srcPath
         
     | 
| 
       20 
     | 
    
         
            -
            	    # these two are to pass to chatFG in parseFile
         
     | 
| 
       21 
     | 
    
         
            -
            	    @destDirBase = destDirBase
         
     | 
| 
       22 
     | 
    
         
            -
            	    @userAliases = userAliases
         
     | 
| 
       23 
     | 
    
         
            -
            	    @userTZ = userTZ
         
     | 
| 
       24 
     | 
    
         
            -
            	    @userTZOffset = userTZOffset
         
     | 
| 
       25 
     | 
    
         
            -
            	    @tzOffset = getTimeZoneOffset()
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
            	    # Used in @lineRegex{,Status}. Only one group: the entire timestamp.
         
     | 
| 
       28 
     | 
    
         
            -
            	    @timestampRegexStr = '\(((?:\d{4}-\d{2}-\d{2} )?\d{1,2}:\d{1,2}:\d{1,2}(?: .{1,2})?)\)'
         
     | 
| 
       29 
     | 
    
         
            -
            	    # the first line is special: it tells us
         
     | 
| 
       30 
     | 
    
         
            -
            	    # 1) who we're talking to 
         
     | 
| 
       31 
     | 
    
         
            -
            	    # 2) what time/date
         
     | 
| 
       32 
     | 
    
         
            -
            	    # 3) what SN we used
         
     | 
| 
       33 
     | 
    
         
            -
            	    # 4) what protocol (AIM, icq, jabber...)
         
     | 
| 
       34 
     | 
    
         
            -
            	    @firstLineRegex = /Conversation with (.+?) at (.+?) on (.+?) \((.+?)\)/
         
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
            	    # Possible formats for timestamps:
         
     | 
| 
       37 
     | 
    
         
            -
            	    # "2007-04-17 12:33:13" => %w{2007, 04, 17, 12, 33, 13}
         
     | 
| 
       38 
     | 
    
         
            -
            	    @timeRegexOne = /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/
         
     | 
| 
       39 
     | 
    
         
            -
            	    # "4/18/2007 11:02:00 AM" => %w{4, 18, 2007, 11, 02, 00, AM}
         
     | 
| 
       40 
     | 
    
         
            -
            	    @timeRegexTwo = %r{(\d{1,2})/(\d{1,2})/(\d{4}) (\d{1,2}):(\d{2}):(\d{2}) ([AP]M)}
         
     | 
| 
       41 
     | 
    
         
            -
            	    # sometimes a line in a chat doesn't have a full timestamp
         
     | 
| 
       42 
     | 
    
         
            -
            	    # "04:22:05 AM" => %w{04 22 05 AM}
         
     | 
| 
       43 
     | 
    
         
            -
            	    @minimalTimeRegex = /(\d{1,2}):(\d{2}):(\d{2}) ?([AP]M)?/
         
     | 
| 
       44 
     | 
    
         
            -
            	    
         
     | 
| 
       45 
     | 
    
         
            -
            	    # {user,partner}SN set in parseFile() after reading the first line
         
     | 
| 
       46 
     | 
    
         
            -
            	    @userSN = nil
         
     | 
| 
       47 
     | 
    
         
            -
            	    @partnerSN = nil
         
     | 
| 
       48 
     | 
    
         
            -
            	    
         
     | 
| 
       49 
     | 
    
         
            -
            	    # @basicTimeInfo is for files that only have the full timestamp at
         
     | 
| 
       50 
     | 
    
         
            -
            	    # the top; we can use it to fill in the minimal per-line timestamps.
         
     | 
| 
       51 
     | 
    
         
            -
            	    # It has only 3 elements (year, month, dayofmonth) because
         
     | 
| 
       52 
     | 
    
         
            -
            	    # you should be able to fill everything else in.
         
     | 
| 
       53 
     | 
    
         
            -
            	    # If you can't, something's wrong.
         
     | 
| 
       54 
     | 
    
         
            -
            	    @basicTimeInfo = []
         
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
            	    # @userAlias is set each time getSenderByAlias is called. Set an
         
     | 
| 
       57 
     | 
    
         
            -
            	    # initial value just in case the first message doesn't give us an
         
     | 
| 
       58 
     | 
    
         
            -
            	    # alias.
         
     | 
| 
       59 
     | 
    
         
            -
            	    @userAlias = @userAliases[0]
         
     | 
| 
       60 
     | 
    
         
            -
            	    
         
     | 
| 
       61 
     | 
    
         
            -
            	    # @statusMap, @libPurpleEvents, and @events are used in
         
     | 
| 
       62 
     | 
    
         
            -
            	    # createStatusOrEventMessage.
         
     | 
| 
       63 
     | 
    
         
            -
            	    @statusMap = {
         
     | 
| 
       64 
     | 
    
         
            -
            		/(.+) logged in\.$/ => 'online',
         
     | 
| 
       65 
     | 
    
         
            -
            		/(.+) logged out\.$/ => 'offline',
         
     | 
| 
       66 
     | 
    
         
            -
            		/(.+) has signed on\.$/ => 'online',
         
     | 
| 
       67 
     | 
    
         
            -
            		/(.+) has signed off\.$/ => 'offline',
         
     | 
| 
       68 
     | 
    
         
            -
            		/(.+) has gone away\.$/ => 'away',
         
     | 
| 
       69 
     | 
    
         
            -
            		/(.+) is no longer away\.$/ => 'available',
         
     | 
| 
       70 
     | 
    
         
            -
            		/(.+) has become idle\.$/ => 'idle',
         
     | 
| 
       71 
     | 
    
         
            -
            		/(.+) is no longer idle\.$/ => 'available'
         
     | 
| 
       72 
     | 
    
         
            -
            	    }
         
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
            	    # libPurpleEvents are all of eventType libPurple
         
     | 
| 
       75 
     | 
    
         
            -
            	    @libPurpleEvents = [
         
     | 
| 
       76 
     | 
    
         
            -
            		# file transfer
         
     | 
| 
       77 
     | 
    
         
            -
            		/Starting transfer of .+ from (.+)/,
         
     | 
| 
       78 
     | 
    
         
            -
            		/^Offering to send .+ to (.+)$/,
         
     | 
| 
       79 
     | 
    
         
            -
            		/(.+) is offering to send file/,
         
     | 
| 
       80 
     | 
    
         
            -
            		/^Transfer of file .+ complete$/,
         
     | 
| 
       81 
     | 
    
         
            -
            		/Error reading|writing|accessing .+: .+/,
         
     | 
| 
       82 
     | 
    
         
            -
            		/You cancelled the transfer of/,
         
     | 
| 
       83 
     | 
    
         
            -
            		/File transfer cancelled/,
         
     | 
| 
       84 
     | 
    
         
            -
            		/(.+) cancelled the transfer of/,
         
     | 
| 
       85 
     | 
    
         
            -
            		/(.+) cancelled the file transfer/,
         
     | 
| 
       86 
     | 
    
         
            -
            		# Direct IM - actual (dis)connect events are their own types
         
     | 
| 
       87 
     | 
    
         
            -
            		/^Attempting to connect to (.+) at .+ for Direct IM\./,
         
     | 
| 
       88 
     | 
    
         
            -
            		/^Asking (.+) to connect to us at .+ for Direct IM\./,
         
     | 
| 
       89 
     | 
    
         
            -
            		/^Attempting to connect via proxy server\.$/,
         
     | 
| 
       90 
     | 
    
         
            -
            		/^Direct IM with (.+) failed/,
         
     | 
| 
       91 
     | 
    
         
            -
            		# encryption
         
     | 
| 
       92 
     | 
    
         
            -
            		/Received message encrypted with wrong key/,
         
     | 
| 
       93 
     | 
    
         
            -
            		/^Requesting key\.\.\.$/,
         
     | 
| 
       94 
     | 
    
         
            -
            		/^Outgoing message lost\.$/,
         
     | 
| 
       95 
     | 
    
         
            -
            		/^Conflicting Key Received!$/,
         
     | 
| 
       96 
     | 
    
         
            -
            		/^Error in decryption- asking for resend\.\.\.$/,
         
     | 
| 
       97 
     | 
    
         
            -
            		/^Making new key pair\.\.\.$/,
         
     | 
| 
       98 
     | 
    
         
            -
            		# file transfer - these are in this (non-used) list because you can't get the alias out of matchData[1]
         
     | 
| 
       99 
     | 
    
         
            -
            		/^You canceled the transfer of .+$/,
         
     | 
| 
       100 
     | 
    
         
            -
            		# sending errors
         
     | 
| 
       101 
     | 
    
         
            -
            		/^Last outgoing message not received properly- resetting$/,
         
     | 
| 
       102 
     | 
    
         
            -
            		/'Resending\.\.\./,
         
     | 
| 
       103 
     | 
    
         
            -
            		# connection errors
         
     | 
| 
       104 
     | 
    
         
            -
            		/Lost connection with the remote user:.+/,
         
     | 
| 
       105 
     | 
    
         
            -
            		# chats
         
     | 
| 
       106 
     | 
    
         
            -
            		/^.+ entered the room\.$/,
         
     | 
| 
       107 
     | 
    
         
            -
            		/^.+ left the room\.$/
         
     | 
| 
       108 
     | 
    
         
            -
            	    ]
         
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
            	    # non-libpurple events
         
     | 
| 
       111 
     | 
    
         
            -
            	    # Each key maps to an eventType string. The keys will be matched against a line of chat
         
     | 
| 
       112 
     | 
    
         
            -
            	    # and the partner's alias will be in regex group 1, IF the alias is matched.
         
     | 
| 
       113 
     | 
    
         
            -
            	    @eventMap = {
         
     | 
| 
       114 
     | 
    
         
            -
            		# .+ is not an alias, it's a proxy server so no grouping
         
     | 
| 
       115 
     | 
    
         
            -
            		/^Attempting to connect to .+\.$/ => 'direct-im-connect',
         
     | 
| 
       116 
     | 
    
         
            -
            		# NB: pidgin doesn't track when Direct IM is disconnected, AFAIK
         
     | 
| 
       117 
     | 
    
         
            -
            		/^Direct IM established$/ => 'directIMConnected',
         
     | 
| 
       118 
     | 
    
         
            -
            		/Unable to send message. The message is too large./ => 'chat-error',
         
     | 
| 
       119 
     | 
    
         
            -
            		/You missed .+ messages from (.+) because they were too large./ => 'chat-error'
         
     | 
| 
       120 
     | 
    
         
            -
            	    }
         
     | 
| 
       121 
     | 
    
         
            -
            	end
         
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
       123 
     | 
    
         
            -
            	def getTimeZoneOffset()
         
     | 
| 
       124 
     | 
    
         
            -
            	    tzMatch = /([-\+]\d+)[A-Z]{3}\.txt|html?/.match(@srcPath)
         
     | 
| 
       125 
     | 
    
         
            -
            	    tzOffset = tzMatch[1] rescue @userTZOffset
         
     | 
| 
       126 
     | 
    
         
            -
            	    return tzOffset
         
     | 
| 
       127 
     | 
    
         
            -
            	end
         
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
            	# Adium time format: YYYY-MM-DD\THH.MM.SS[+-]TZ_HRS like:
         
     | 
| 
       130 
     | 
    
         
            -
            	# 2008-10-05T22.26.20-0800
         
     | 
| 
       131 
     | 
    
         
            -
            	def createAdiumTime(time)
         
     | 
| 
       132 
     | 
    
         
            -
            	    # parsedDate = [year, month, day, hour, min, sec]
         
     | 
| 
       133 
     | 
    
         
            -
            	    parsedDate = case time
         
     | 
| 
       134 
     | 
    
         
            -
            			 when @timeRegexOne
         
     | 
| 
       135 
     | 
    
         
            -
            			     [$~[1].to_i, # year
         
     | 
| 
       136 
     | 
    
         
            -
            			     $~[2].to_i,  # month
         
     | 
| 
       137 
     | 
    
         
            -
            			     $~[3].to_i,  # day
         
     | 
| 
       138 
     | 
    
         
            -
            			     $~[4].to_i,  # hour
         
     | 
| 
       139 
     | 
    
         
            -
            			     $~[5].to_i,  # minute
         
     | 
| 
       140 
     | 
    
         
            -
            			     $~[6].to_i]  # seconds
         
     | 
| 
       141 
     | 
    
         
            -
            			 when @timeRegexTwo
         
     | 
| 
       142 
     | 
    
         
            -
            			     hours = $~[4].to_i
         
     | 
| 
       143 
     | 
    
         
            -
            			     if $~[7] == 'PM' and hours != 12
         
     | 
| 
       144 
     | 
    
         
            -
            				 hours += 12
         
     | 
| 
       145 
     | 
    
         
            -
            			     end
         
     | 
| 
       146 
     | 
    
         
            -
            			     [$~[3].to_i, # year
         
     | 
| 
       147 
     | 
    
         
            -
            			      $~[1].to_i, # month
         
     | 
| 
       148 
     | 
    
         
            -
            			      $~[2].to_i, # day
         
     | 
| 
       149 
     | 
    
         
            -
            			      hours,
         
     | 
| 
       150 
     | 
    
         
            -
            			      $~[5].to_i, # minutes
         
     | 
| 
       151 
     | 
    
         
            -
            			      $~[6].to_i] # seconds
         
     | 
| 
       152 
     | 
    
         
            -
            			 when @minimalTimeRegex
         
     | 
| 
       153 
     | 
    
         
            -
            			     # "04:22:05" => %w{04 22 05}
         
     | 
| 
       154 
     | 
    
         
            -
            			     hours = $~[1].to_i
         
     | 
| 
       155 
     | 
    
         
            -
            			     if $~[4] == 'PM' and hours != 12
         
     | 
| 
       156 
     | 
    
         
            -
            				 hours += 12
         
     | 
| 
       157 
     | 
    
         
            -
            			     end
         
     | 
| 
       158 
     | 
    
         
            -
            			     @basicTimeInfo + # [year, month, day]
         
     | 
| 
       159 
     | 
    
         
            -
            			     [hours,
         
     | 
| 
       160 
     | 
    
         
            -
            			      $~[2].to_i, # minutes
         
     | 
| 
       161 
     | 
    
         
            -
            			      $~[3].to_i] # seconds
         
     | 
| 
       162 
     | 
    
         
            -
            			 else
         
     | 
| 
       163 
     | 
    
         
            -
            			     Pidgin2Adium.logMsg("You have found an odd timestamp.", true)
         
     | 
| 
       164 
     | 
    
         
            -
            			     Pidgin2Adium.logMsg("Please report it to the developer.")
         
     | 
| 
       165 
     | 
    
         
            -
            			     Pidgin2Adium.logMsg("The timestamp: #{time}")
         
     | 
| 
       166 
     | 
    
         
            -
            			     Pidgin2Adium.logMsg("Continuing...")
         
     | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
       168 
     | 
    
         
            -
            			     ParseDate.parsedate(time)
         
     | 
| 
       169 
     | 
    
         
            -
            			 end
         
     | 
| 
       170 
     | 
    
         
            -
            	    return Time.local(*parsedDate).strftime("%Y-%m-%dT%H.%M.%S#{@tzOffset}")
         
     | 
| 
       171 
     | 
    
         
            -
            	end
         
     | 
| 
       172 
     | 
    
         
            -
             
     | 
| 
       173 
     | 
    
         
            -
            	# parseFile slurps up @srcPath into one big string and runs
         
     | 
| 
       174 
     | 
    
         
            -
            	# SrcHtmlFileParse.cleanup if it's an HTML file.
         
     | 
| 
       175 
     | 
    
         
            -
            	# It then uses regexes to break up the string, uses create(Status)Msg
         
     | 
| 
       176 
     | 
    
         
            -
            	# to turn the regex MatchData into data hashes, and feeds it to
         
     | 
| 
       177 
     | 
    
         
            -
            	# ChatFileGenerator, which creates the XML data string.
         
     | 
| 
       178 
     | 
    
         
            -
            	# This method returns a ChatFileGenerator object.
         
     | 
| 
       179 
     | 
    
         
            -
            	def parseFile()
         
     | 
| 
       180 
     | 
    
         
            -
            	    file = File.new(@srcPath, 'r')
         
     | 
| 
       181 
     | 
    
         
            -
            	    # Deal with first line.
         
     | 
| 
       182 
     | 
    
         
            -
            	    firstLine = file.readline()
         
     | 
| 
       183 
     | 
    
         
            -
            	    firstLineMatch = @firstLineRegex.match(firstLine)
         
     | 
| 
       184 
     | 
    
         
            -
            	    if firstLineMatch.nil?
         
     | 
| 
       185 
     | 
    
         
            -
            		file.close()
         
     | 
| 
       186 
     | 
    
         
            -
            		Pidgin2Adium.logMsg("Parsing of #{@srcPath} failed (could not find valid first line).", true)
         
     | 
| 
       187 
     | 
    
         
            -
            		return false
         
     | 
| 
       188 
     | 
    
         
            -
            	    else
         
     | 
| 
       189 
     | 
    
         
            -
            		# one big string, without the first line
         
     | 
| 
       190 
     | 
    
         
            -
            		if self.class == SrcHtmlFileParse
         
     | 
| 
       191 
     | 
    
         
            -
            		    fileContent = self.cleanup(file.read())
         
     | 
| 
       192 
     | 
    
         
            -
            		else
         
     | 
| 
       193 
     | 
    
         
            -
            		    fileContent = file.read()
         
     | 
| 
       194 
     | 
    
         
            -
            		end
         
     | 
| 
       195 
     | 
    
         
            -
            		file.close()
         
     | 
| 
       196 
     | 
    
         
            -
            	    end
         
     | 
| 
       197 
     | 
    
         
            -
            	    
         
     | 
| 
       198 
     | 
    
         
            -
            	    service = firstLineMatch[4]
         
     | 
| 
       199 
     | 
    
         
            -
            	    # userSN is standardized to avoid "AIM.name" and "AIM.na me" folders
         
     | 
| 
       200 
     | 
    
         
            -
            	    @userSN = firstLineMatch[3].downcase.gsub(' ', '')
         
     | 
| 
       201 
     | 
    
         
            -
            	    @partnerSN = firstLineMatch[1]
         
     | 
| 
       202 
     | 
    
         
            -
            	    pidginChatTimeStart = firstLineMatch[2]
         
     | 
| 
       203 
     | 
    
         
            -
            	    @basicTimeInfo = case firstLine
         
     | 
| 
       204 
     | 
    
         
            -
            			     when @timeRegexOne: [$1.to_i, $2.to_i, $3.to_i]
         
     | 
| 
       205 
     | 
    
         
            -
            			     when @timeRegexTwo: [$3.to_i, $1.to_i, $2.to_i]
         
     | 
| 
       206 
     | 
    
         
            -
            			     end
         
     | 
| 
       207 
     | 
    
         
            -
             
     | 
| 
       208 
     | 
    
         
            -
            	    chatFG = ChatFileGenerator.new(service,
         
     | 
| 
       209 
     | 
    
         
            -
            					   @userSN,
         
     | 
| 
       210 
     | 
    
         
            -
            					   @partnerSN,
         
     | 
| 
       211 
     | 
    
         
            -
            					   createAdiumTime(pidginChatTimeStart),
         
     | 
| 
       212 
     | 
    
         
            -
            					   @destDirBase)
         
     | 
| 
       213 
     | 
    
         
            -
            	    fileContent.each_line do |line|
         
     | 
| 
       214 
     | 
    
         
            -
            		case line
         
     | 
| 
       215 
     | 
    
         
            -
            		when @lineRegex
         
     | 
| 
       216 
     | 
    
         
            -
            		    chatFG.appendLine( createMsg($~.captures) )
         
     | 
| 
       217 
     | 
    
         
            -
            		when @lineRegexStatus
         
     | 
| 
       218 
     | 
    
         
            -
            		    msg = createStatusOrEventMsg($~.captures)
         
     | 
| 
       219 
     | 
    
         
            -
            		    # msg is nil if we couldn't parse the status line
         
     | 
| 
       220 
     | 
    
         
            -
            		    chatFG.appendLine(msg) unless msg.nil?
         
     | 
| 
       221 
     | 
    
         
            -
            		end
         
     | 
| 
       222 
     | 
    
         
            -
            	    end
         
     | 
| 
       223 
     | 
    
         
            -
            	    return chatFG
         
     | 
| 
       224 
     | 
    
         
            -
            	end
         
     | 
| 
       225 
     | 
    
         
            -
             
     | 
| 
       226 
     | 
    
         
            -
            	def getSenderByAlias(aliasName)
         
     | 
| 
       227 
     | 
    
         
            -
            	    if @userAliases.include? aliasName.downcase.sub(/^\*{3}/,'').gsub(/\s+/, '')
         
     | 
| 
       228 
     | 
    
         
            -
            		# Set the current alias being used of the ones in @userAliases
         
     | 
| 
       229 
     | 
    
         
            -
            		@userAlias = aliasName.sub(/^\*{3}/, '')
         
     | 
| 
       230 
     | 
    
         
            -
            		return @userSN
         
     | 
| 
       231 
     | 
    
         
            -
            	    else
         
     | 
| 
       232 
     | 
    
         
            -
            		return @partnerSN
         
     | 
| 
       233 
     | 
    
         
            -
            	    end
         
     | 
| 
       234 
     | 
    
         
            -
            	end
         
     | 
| 
       235 
     | 
    
         
            -
             
     | 
| 
       236 
     | 
    
         
            -
            	# createMsg takes an array of captures from matching against @lineRegex
         
     | 
| 
       237 
     | 
    
         
            -
            	# and returns a Message object or one of its subclasses.
         
     | 
| 
       238 
     | 
    
         
            -
            	# It can be used for SrcTxtFileParse and SrcHtmlFileParse because
         
     | 
| 
       239 
     | 
    
         
            -
            	# both of them return data in the same indexes in the matches array.
         
     | 
| 
       240 
     | 
    
         
            -
            	def createMsg(matches)
         
     | 
| 
       241 
     | 
    
         
            -
            	    msg = nil
         
     | 
| 
       242 
     | 
    
         
            -
            	    # Either a regular message line or an auto-reply/away message.
         
     | 
| 
       243 
     | 
    
         
            -
            	    time = createAdiumTime(matches[0])
         
     | 
| 
       244 
     | 
    
         
            -
            	    aliasStr = matches[1]
         
     | 
| 
       245 
     | 
    
         
            -
            	    sender = getSenderByAlias(aliasStr)
         
     | 
| 
       246 
     | 
    
         
            -
            	    body = matches[3]
         
     | 
| 
       247 
     | 
    
         
            -
            	    if matches[2] # auto-reply
         
     | 
| 
       248 
     | 
    
         
            -
            		msg = AutoReplyMessage.new(sender, time, aliasStr, body)
         
     | 
| 
       249 
     | 
    
         
            -
            	    else
         
     | 
| 
       250 
     | 
    
         
            -
            		# normal message
         
     | 
| 
       251 
     | 
    
         
            -
            		msg = XMLMessage.new(sender, time, aliasStr, body)
         
     | 
| 
       252 
     | 
    
         
            -
            	    end
         
     | 
| 
       253 
     | 
    
         
            -
            	    return msg
         
     | 
| 
       254 
     | 
    
         
            -
            	end
         
     | 
| 
       255 
     | 
    
         
            -
             
     | 
| 
       256 
     | 
    
         
            -
            	# createStatusOrEventMsg takes an array of +MatchData+ captures from
         
     | 
| 
       257 
     | 
    
         
            -
            	# matching against @lineRegexStatus and returns an Event or Status.
         
     | 
| 
       258 
     | 
    
         
            -
            	def createStatusOrEventMsg(matches)
         
     | 
| 
       259 
     | 
    
         
            -
            	    # ["22:58:00", "BuddyName logged in."]
         
     | 
| 
       260 
     | 
    
         
            -
            	    # 0: time
         
     | 
| 
       261 
     | 
    
         
            -
            	    # 1: status message or event
         
     | 
| 
       262 
     | 
    
         
            -
            	    msg = nil
         
     | 
| 
       263 
     | 
    
         
            -
            	    time = createAdiumTime(matches[0])
         
     | 
| 
       264 
     | 
    
         
            -
            	    str = matches[1]
         
     | 
| 
       265 
     | 
    
         
            -
            	    regex, status = @statusMap.detect{|regex, status| str =~ regex}
         
     | 
| 
       266 
     | 
    
         
            -
            	    if regex and status
         
     | 
| 
       267 
     | 
    
         
            -
            		# Status message
         
     | 
| 
       268 
     | 
    
         
            -
            		aliasStr = regex.match(str)[1]
         
     | 
| 
       269 
     | 
    
         
            -
            		sender = getSenderByAlias(aliasStr)
         
     | 
| 
       270 
     | 
    
         
            -
            		msg = StatusMessage.new(sender, time, aliasStr, status)
         
     | 
| 
       271 
     | 
    
         
            -
            	    else
         
     | 
| 
       272 
     | 
    
         
            -
            		# Test for event
         
     | 
| 
       273 
     | 
    
         
            -
            		regex = @libPurpleEvents.detect{|regex| str =~ regex }
         
     | 
| 
       274 
     | 
    
         
            -
            		eventType = 'libpurpleEvent' if regex
         
     | 
| 
       275 
     | 
    
         
            -
            		unless regex and eventType
         
     | 
| 
       276 
     | 
    
         
            -
            		    # not a libpurple event, try others
         
     | 
| 
       277 
     | 
    
         
            -
            		    regexAndEventType = @eventMap.detect{|regex,eventType| str =~ regex}
         
     | 
| 
       278 
     | 
    
         
            -
            		    if regexAndEventType.nil?
         
     | 
| 
       279 
     | 
    
         
            -
            			Pidgin2Adium.logMsg("You have found an odd status line. Please send this line to the developer.", true)
         
     | 
| 
       280 
     | 
    
         
            -
            			Pidgin2Adium.logMsg("The line is: #{str}", true)
         
     | 
| 
       281 
     | 
    
         
            -
            			return nil
         
     | 
| 
       282 
     | 
    
         
            -
            		    else
         
     | 
| 
       283 
     | 
    
         
            -
            			regex = regexAndEventType[0]
         
     | 
| 
       284 
     | 
    
         
            -
            			eventType = regexAndEventType[1]
         
     | 
| 
       285 
     | 
    
         
            -
            		    end
         
     | 
| 
       286 
     | 
    
         
            -
            		end
         
     | 
| 
       287 
     | 
    
         
            -
            		if regex and eventType
         
     | 
| 
       288 
     | 
    
         
            -
            		    regexMatches = regex.match(str)
         
     | 
| 
       289 
     | 
    
         
            -
            		    # Event message
         
     | 
| 
       290 
     | 
    
         
            -
            		    if regexMatches.size == 1
         
     | 
| 
       291 
     | 
    
         
            -
            			# No alias - this means it's the user
         
     | 
| 
       292 
     | 
    
         
            -
            			aliasStr = @userAlias
         
     | 
| 
       293 
     | 
    
         
            -
            			sender = @userSN
         
     | 
| 
       294 
     | 
    
         
            -
            		    else
         
     | 
| 
       295 
     | 
    
         
            -
            			aliasStr = regex.match(str)[1]
         
     | 
| 
       296 
     | 
    
         
            -
            			sender = getSenderByAlias(aliasStr)
         
     | 
| 
       297 
     | 
    
         
            -
            		    end
         
     | 
| 
       298 
     | 
    
         
            -
            		    msg = Event.new(sender, time, aliasStr, str, eventType)
         
     | 
| 
       299 
     | 
    
         
            -
            		end
         
     | 
| 
       300 
     | 
    
         
            -
            	    end
         
     | 
| 
       301 
     | 
    
         
            -
            	    return msg
         
     | 
| 
       302 
     | 
    
         
            -
            	end
         
     | 
| 
       303 
     | 
    
         
            -
                end
         
     | 
| 
       304 
     | 
    
         
            -
             
     | 
| 
       305 
     | 
    
         
            -
                class SrcTxtFileParse < SrcFileParse
         
     | 
| 
       306 
     | 
    
         
            -
            	def initialize(srcPath, destDirBase, userAliases, userTZ, userTZOffset)
         
     | 
| 
       307 
     | 
    
         
            -
            	    super(srcPath, destDirBase, userAliases, userTZ, userTZOffset)
         
     | 
| 
       308 
     | 
    
         
            -
            	    # @lineRegex matches a line in a TXT log file other than the first
         
     | 
| 
       309 
     | 
    
         
            -
            	    # @lineRegex matchdata:
         
     | 
| 
       310 
     | 
    
         
            -
            	    # 0: timestamp
         
     | 
| 
       311 
     | 
    
         
            -
            	    # 1: screen name or alias, if alias set
         
     | 
| 
       312 
     | 
    
         
            -
            	    # 2: "<AUTO-REPLY>" or nil
         
     | 
| 
       313 
     | 
    
         
            -
            	    # 3: message body
         
     | 
| 
       314 
     | 
    
         
            -
            	    @lineRegex = /#{@timestampRegexStr} (.*?) ?(<AUTO-REPLY>)?: (.*)$/o
         
     | 
| 
       315 
     | 
    
         
            -
            	    # @lineRegexStatus matches a status line
         
     | 
| 
       316 
     | 
    
         
            -
            	    # @lineRegexStatus matchdata:
         
     | 
| 
       317 
     | 
    
         
            -
            	    # 0: timestamp
         
     | 
| 
       318 
     | 
    
         
            -
            	    # 1: status message
         
     | 
| 
       319 
     | 
    
         
            -
            	    @lineRegexStatus = /#{@timestampRegexStr} ([^:]+?)[\r\n]/o
         
     | 
| 
       320 
     | 
    
         
            -
            	end
         
     | 
| 
       321 
     | 
    
         
            -
             
     | 
| 
       322 
     | 
    
         
            -
                end
         
     | 
| 
       323 
     | 
    
         
            -
             
     | 
| 
       324 
     | 
    
         
            -
                class SrcHtmlFileParse < SrcFileParse
         
     | 
| 
       325 
     | 
    
         
            -
            	def initialize(srcPath, destDirBase, userAliases, userTZ, userTZOffset)
         
     | 
| 
       326 
     | 
    
         
            -
            	    super(srcPath, destDirBase, userAliases, userTZ, userTZOffset)
         
     | 
| 
       327 
     | 
    
         
            -
            	    # @lineRegex matches a line in an HTML log file other than the first
         
     | 
| 
       328 
     | 
    
         
            -
            	    # time matches on either "2008-11-17 14:12" or "14:12"
         
     | 
| 
       329 
     | 
    
         
            -
            	    # @lineRegex match obj:
         
     | 
| 
       330 
     | 
    
         
            -
            	    # 0: timestamp, extended or not
         
     | 
| 
       331 
     | 
    
         
            -
            	    # 1: screen name or alias, if alias set
         
     | 
| 
       332 
     | 
    
         
            -
            	    # 2: "<AUTO-REPLY>" or nil
         
     | 
| 
       333 
     | 
    
         
            -
            	    # 3: message body
         
     | 
| 
       334 
     | 
    
         
            -
            	    #  <span style='color: #000000;'>test sms</span>
         
     | 
| 
       335 
     | 
    
         
            -
            	    @lineRegex = /#{@timestampRegexStr} ?<b>(.*?) ?(<AUTO-REPLY>)?:?<\/b> ?(.*)<br ?\/>/o
         
     | 
| 
       336 
     | 
    
         
            -
            	    # @lineRegexStatus matches a status line
         
     | 
| 
       337 
     | 
    
         
            -
            	    # @lineRegexStatus match obj:
         
     | 
| 
       338 
     | 
    
         
            -
            	    # 0: timestamp
         
     | 
| 
       339 
     | 
    
         
            -
            	    # 1: status message
         
     | 
| 
       340 
     | 
    
         
            -
            	    @lineRegexStatus = /#{@timestampRegexStr} ?<b> (.*?)<\/b><br ?\/>/o
         
     | 
| 
       341 
     | 
    
         
            -
            	end
         
     | 
| 
       342 
     | 
    
         
            -
             
     | 
| 
       343 
     | 
    
         
            -
            	# Removes <font> tags, empty <a>s, and spans with either no color
         
     | 
| 
       344 
     | 
    
         
            -
            	# information or color information that just turns the text black.
         
     | 
| 
       345 
     | 
    
         
            -
            	# Returns a string.
         
     | 
| 
       346 
     | 
    
         
            -
            	def cleanup(text)
         
     | 
| 
       347 
     | 
    
         
            -
            	    # Pidgin and Adium both show bold using
         
     | 
| 
       348 
     | 
    
         
            -
            	    # <span style="font-weight: bold;"> except Pidgin uses single quotes
         
     | 
| 
       349 
     | 
    
         
            -
            	    # and Adium uses double quotes
         
     | 
| 
       350 
     | 
    
         
            -
            	    text.gsub!(/<\/?(html|body|font).*?>/, '')
         
     | 
| 
       351 
     | 
    
         
            -
            	    # These empty links are sometimes appended to every line in a chat,
         
     | 
| 
       352 
     | 
    
         
            -
            	    # for some weird reason. Remove them.
         
     | 
| 
       353 
     | 
    
         
            -
            	    text.gsub!(%r{<a href='.+?'>\s*?</a>}, '')
         
     | 
| 
       354 
     | 
    
         
            -
            	    text.gsub!(%r{(.*?)<span.+style='(.+?)'>(.*?)</span>(.*)}) do |s|
         
     | 
| 
       355 
     | 
    
         
            -
            		# before = text before match
         
     | 
| 
       356 
     | 
    
         
            -
            		# style = style declaration
         
     | 
| 
       357 
     | 
    
         
            -
            		# innertext = text inside <span>
         
     | 
| 
       358 
     | 
    
         
            -
            		# after = text after match
         
     | 
| 
       359 
     | 
    
         
            -
            		before, style, innertext, after = *($~[1..4])
         
     | 
| 
       360 
     | 
    
         
            -
            		# TODO: remove after from string then see what balanceTags does
         
     | 
| 
       361 
     | 
    
         
            -
            		# Remove empty spans.
         
     | 
| 
       362 
     | 
    
         
            -
            		nil if innertext == ''
         
     | 
| 
       363 
     | 
    
         
            -
            		# Only allow some style declarations
         
     | 
| 
       364 
     | 
    
         
            -
            		# We keep:
         
     | 
| 
       365 
     | 
    
         
            -
            		# font-weight: bold
         
     | 
| 
       366 
     | 
    
         
            -
            		# color (except #000000)
         
     | 
| 
       367 
     | 
    
         
            -
            		# text-decoration: underline
         
     | 
| 
       368 
     | 
    
         
            -
            		styleparts = style.split(/; ?/)
         
     | 
| 
       369 
     | 
    
         
            -
            		styleparts.map! do |p|
         
     | 
| 
       370 
     | 
    
         
            -
            		    # Short-circuit for common declaration
         
     | 
| 
       371 
     | 
    
         
            -
            		    # Yes, sometimes there's a ">" before the ";".
         
     | 
| 
       372 
     | 
    
         
            -
            		    if p == 'color: #000000;' or p == 'color: #000000>;'
         
     | 
| 
       373 
     | 
    
         
            -
            			nil
         
     | 
| 
       374 
     | 
    
         
            -
            		    else
         
     | 
| 
       375 
     | 
    
         
            -
            			case p
         
     | 
| 
       376 
     | 
    
         
            -
            			when /font-family/: nil
         
     | 
| 
       377 
     | 
    
         
            -
            			when /font-size/: nil
         
     | 
| 
       378 
     | 
    
         
            -
            			when /background/: nil
         
     | 
| 
       379 
     | 
    
         
            -
            			end
         
     | 
| 
       380 
     | 
    
         
            -
            		    end
         
     | 
| 
       381 
     | 
    
         
            -
            		end
         
     | 
| 
       382 
     | 
    
         
            -
            		styleparts.compact!
         
     | 
| 
       383 
     | 
    
         
            -
            		if styleparts.empty?
         
     | 
| 
       384 
     | 
    
         
            -
            		    style = ''
         
     | 
| 
       385 
     | 
    
         
            -
            		elsif styleparts.size == 1
         
     | 
| 
       386 
     | 
    
         
            -
            		    style = styleparts[0] << ';'
         
     | 
| 
       387 
     | 
    
         
            -
            		else
         
     | 
| 
       388 
     | 
    
         
            -
            		    style = styleparts.join('; ') << ';'
         
     | 
| 
       389 
     | 
    
         
            -
            		end
         
     | 
| 
       390 
     | 
    
         
            -
            		if style != ''
         
     | 
| 
       391 
     | 
    
         
            -
            		    innertext = "<span style=\"#{style}\">#{innertext}</span>"
         
     | 
| 
       392 
     | 
    
         
            -
            		end
         
     | 
| 
       393 
     | 
    
         
            -
            		before + innertext + after
         
     | 
| 
       394 
     | 
    
         
            -
            	    end
         
     | 
| 
       395 
     | 
    
         
            -
            	    # Pidgin uses <em>, Adium uses <span>
         
     | 
| 
       396 
     | 
    
         
            -
            	    if text.gsub!('<em>', '<span style="italic">')
         
     | 
| 
       397 
     | 
    
         
            -
            		text.gsub!('</em>', '</span>')
         
     | 
| 
       398 
     | 
    
         
            -
            	    end
         
     | 
| 
       399 
     | 
    
         
            -
            	    return text
         
     | 
| 
       400 
     | 
    
         
            -
            	end
         
     | 
| 
       401 
     | 
    
         
            -
                end
         
     | 
| 
       402 
     | 
    
         
            -
             
     | 
| 
       403 
     | 
    
         
            -
                # A holding object for each line of the chat.
         
     | 
| 
       404 
     | 
    
         
            -
                # It is subclassed as appropriate (eg AutoReplyMessage).
         
     | 
| 
       405 
     | 
    
         
            -
                # All Messages have senders, times, and aliases.
         
     | 
| 
       406 
     | 
    
         
            -
                class Message
         
     | 
| 
       407 
     | 
    
         
            -
            	def initialize(sender, time, aliasStr)
         
     | 
| 
       408 
     | 
    
         
            -
            	    @sender = sender
         
     | 
| 
       409 
     | 
    
         
            -
            	    @time = time
         
     | 
| 
       410 
     | 
    
         
            -
            	    @aliasStr = aliasStr
         
     | 
| 
       411 
     | 
    
         
            -
            	end
         
     | 
| 
       412 
     | 
    
         
            -
                end
         
     | 
| 
       413 
     | 
    
         
            -
               
         
     | 
| 
       414 
     | 
    
         
            -
                # Basic message with body text (as opposed to pure status messages, which
         
     | 
| 
       415 
     | 
    
         
            -
                # have no body).
         
     | 
| 
       416 
     | 
    
         
            -
                class XMLMessage < Message
         
     | 
| 
       417 
     | 
    
         
            -
            	def initialize(sender, time, aliasStr, body)
         
     | 
| 
       418 
     | 
    
         
            -
            	    super(sender, time, aliasStr)
         
     | 
| 
       419 
     | 
    
         
            -
            	    @body = body
         
     | 
| 
       420 
     | 
    
         
            -
            	    normalizeBody!()
         
     | 
| 
       421 
     | 
    
         
            -
            	end
         
     | 
| 
       422 
     | 
    
         
            -
             
     | 
| 
       423 
     | 
    
         
            -
            	def getOutput
         
     | 
| 
       424 
     | 
    
         
            -
            	    return sprintf('<message sender="%s" time="%s" alias="%s">%s</message>' << "\n",
         
     | 
| 
       425 
     | 
    
         
            -
            			   @sender, @time, @aliasStr, @body)
         
     | 
| 
       426 
     | 
    
         
            -
            	end
         
     | 
| 
       427 
     | 
    
         
            -
             
     | 
| 
       428 
     | 
    
         
            -
            	def normalizeBody!
         
     | 
| 
       429 
     | 
    
         
            -
            	    normalizeBodyEntities!()
         
     | 
| 
       430 
     | 
    
         
            -
            	    # Fix mismatched tags. Yes, it's faster to do it per-message
         
     | 
| 
       431 
     | 
    
         
            -
            	    # than all at once.
         
     | 
| 
       432 
     | 
    
         
            -
            	    @body = Pidgin2Adium.balanceTags(@body)
         
     | 
| 
       433 
     | 
    
         
            -
            	    if @aliasStr[0,3] == '***'
         
     | 
| 
       434 
     | 
    
         
            -
            		# "***<alias>" is what pidgin sets as the alias for a /me action
         
     | 
| 
       435 
     | 
    
         
            -
            		@aliasStr.slice!(0,3)
         
     | 
| 
       436 
     | 
    
         
            -
            		@body = '*' << @body << '*'
         
     | 
| 
       437 
     | 
    
         
            -
            	    end
         
     | 
| 
       438 
     | 
    
         
            -
            	    @body = '<div><span style="font-family: Helvetica; font-size: 12pt;">' <<
         
     | 
| 
       439 
     | 
    
         
            -
            	    @body << 
         
     | 
| 
       440 
     | 
    
         
            -
            	    '</span></div>'
         
     | 
| 
       441 
     | 
    
         
            -
            	end
         
     | 
| 
       442 
     | 
    
         
            -
             
     | 
| 
       443 
     | 
    
         
            -
            	def normalizeBodyEntities!
         
     | 
| 
       444 
     | 
    
         
            -
            	    # Convert '&' to '&' only if it's not followed by an entity.
         
     | 
| 
       445 
     | 
    
         
            -
            	    @body.gsub!(/&(?!lt|gt|amp|quot|apos)/, '&')
         
     | 
| 
       446 
     | 
    
         
            -
            	    # replace single quotes with ''' but only outside <span>s.
         
     | 
| 
       447 
     | 
    
         
            -
            	    @body.gsub!(/(.*?)(<span.*?>.*?<\/span>)(.*?)/) do
         
     | 
| 
       448 
     | 
    
         
            -
            		before, span, after = $1, ($2||''), $3||''
         
     | 
| 
       449 
     | 
    
         
            -
            		before.gsub("'", '&aquot;') <<
         
     | 
| 
       450 
     | 
    
         
            -
            		    span <<
         
     | 
| 
       451 
     | 
    
         
            -
            		    after.gsub("'", '&aquot;')
         
     | 
| 
       452 
     | 
    
         
            -
            	    end
         
     | 
| 
       453 
     | 
    
         
            -
            	end
         
     | 
| 
       454 
     | 
    
         
            -
                end
         
     | 
| 
       455 
     | 
    
         
            -
             
     | 
| 
       456 
     | 
    
         
            -
                # An auto reply message, meaning it has a body.
         
     | 
| 
       457 
     | 
    
         
            -
                class AutoReplyMessage < XMLMessage
         
     | 
| 
       458 
     | 
    
         
            -
            	def getOutput
         
     | 
| 
       459 
     | 
    
         
            -
            	    return sprintf('<message sender="%s" time="%s" auto="true" alias="%s">%s</message>' << "\n", @sender, @time, @aliasStr, @body)
         
     | 
| 
       460 
     | 
    
         
            -
            	end
         
     | 
| 
       461 
     | 
    
         
            -
                end
         
     | 
| 
       462 
     | 
    
         
            -
             
     | 
| 
       463 
     | 
    
         
            -
                # A message saying e.g. "Blahblah has gone away."
         
     | 
| 
       464 
     | 
    
         
            -
                class StatusMessage < Message
         
     | 
| 
       465 
     | 
    
         
            -
            	def initialize(sender, time, aliasStr, status)
         
     | 
| 
       466 
     | 
    
         
            -
            	    super(sender, time, aliasStr) 
         
     | 
| 
       467 
     | 
    
         
            -
            	    @status = status
         
     | 
| 
       468 
     | 
    
         
            -
            	end
         
     | 
| 
       469 
     | 
    
         
            -
            	def getOutput
         
     | 
| 
       470 
     | 
    
         
            -
            	    return sprintf('<status type="%s" sender="%s" time="%s" alias="%s"/>' << "\n", @status, @sender, @time, @aliasStr)
         
     | 
| 
       471 
     | 
    
         
            -
            	end
         
     | 
| 
       472 
     | 
    
         
            -
                end
         
     | 
| 
       473 
     | 
    
         
            -
              
         
     | 
| 
       474 
     | 
    
         
            -
                # An <event> line of the chat
         
     | 
| 
       475 
     | 
    
         
            -
                class Event < XMLMessage
         
     | 
| 
       476 
     | 
    
         
            -
            	def initialize(sender, time, aliasStr, body, type="libpurpleMessage")
         
     | 
| 
       477 
     | 
    
         
            -
            	    super(sender, time, aliasStr, body)
         
     | 
| 
       478 
     | 
    
         
            -
            	    @type = type
         
     | 
| 
       479 
     | 
    
         
            -
            	end
         
     | 
| 
       480 
     | 
    
         
            -
             
     | 
| 
       481 
     | 
    
         
            -
            	def getOutput
         
     | 
| 
       482 
     | 
    
         
            -
            	    return sprintf('<event type="%s" sender="%s" time="%s" alias="%s">%s</event>', @type, @sender, @time, @aliasStr, @body)
         
     | 
| 
       483 
     | 
    
         
            -
            	end
         
     | 
| 
       484 
     | 
    
         
            -
                end
         
     | 
| 
       485 
     | 
    
         
            -
            end # end module
         
     |