pidgin2adium 2.0.2 → 3.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/.autotest +9 -0
- data/History.txt +9 -0
- data/Manifest.txt +9 -1
- data/README.rdoc +8 -9
- data/Rakefile.rb +13 -2
- data/bin/pidgin2adium +1 -1
- data/ext/balance_tags_c/balance_tags_c.c +198 -0
- data/ext/balance_tags_c/extconf.rb +4 -0
- data/lib/pidgin2adium.rb +4 -2
- data/lib/pidgin2adium/log_file.rb +2 -2
- data/lib/pidgin2adium/log_parser.rb +17 -25
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/tasks/extconf.rake +13 -0
- data/tasks/extconf/balance_tags_c.rake +43 -0
- data/test/test_balance_tags_c_extn.rb +10 -0
- metadata +38 -10
- data/lib/pidgin2adium/balance_tags.rb +0 -118
    
        data/.autotest
    ADDED
    
    
    
        data/History.txt
    CHANGED
    
    | @@ -1,3 +1,12 @@ | |
| 1 | 
            +
            === 3.0.0 / 2010-01-31
         | 
| 2 | 
            +
            * balance_tags.rb is now a C extension (Pidgin2Adium.balance_tags_c)
         | 
| 3 | 
            +
              - the pure-ruby mixin balance_tags (without the trailing "_c") is gone
         | 
| 4 | 
            +
            * Better handling of command-line arguments
         | 
| 5 | 
            +
            * Format time zones offsets correctly (e.g. "+0500", not "+-0500")
         | 
| 6 | 
            +
            * Write Yahoo! and Jabber logs to correct directories (#27710)
         | 
| 7 | 
            +
            * Better matching of regexes against time strings
         | 
| 8 | 
            +
            * Better documentation
         | 
| 9 | 
            +
             | 
| 1 10 | 
             
            === 2.0.2 / 2009-12-18
         | 
| 2 11 | 
             
            * Much better documentation (more of it, and higher quality too!)
         | 
| 3 12 | 
             
            * Allow user-provided output dir at commandline
         | 
    
        data/Manifest.txt
    CHANGED
    
    | @@ -1,10 +1,18 @@ | |
| 1 | 
            +
            .autotest
         | 
| 1 2 | 
             
            History.txt
         | 
| 2 3 | 
             
            Manifest.txt
         | 
| 3 4 | 
             
            README.rdoc
         | 
| 4 5 | 
             
            Rakefile.rb
         | 
| 5 6 | 
             
            bin/pidgin2adium
         | 
| 7 | 
            +
            ext/balance_tags_c/balance_tags_c.c
         | 
| 8 | 
            +
            ext/balance_tags_c/extconf.rb
         | 
| 6 9 | 
             
            lib/pidgin2adium.rb
         | 
| 7 | 
            -
            lib/pidgin2adium/balance_tags.rb
         | 
| 8 10 | 
             
            lib/pidgin2adium/log_converter.rb
         | 
| 9 11 | 
             
            lib/pidgin2adium/log_file.rb
         | 
| 10 12 | 
             
            lib/pidgin2adium/log_parser.rb
         | 
| 13 | 
            +
            script/console
         | 
| 14 | 
            +
            script/destroy
         | 
| 15 | 
            +
            script/generate
         | 
| 16 | 
            +
            tasks/extconf.rake
         | 
| 17 | 
            +
            tasks/extconf/balance_tags_c.rake
         | 
| 18 | 
            +
            test/test_balance_tags_c_extn.rb
         | 
    
        data/README.rdoc
    CHANGED
    
    | @@ -37,10 +37,7 @@ Or: | |
| 37 37 | 
             
             $ pidgin2adium -i pidgin-logs -a gabe,gabeb-w,gbw
         | 
| 38 38 |  | 
| 39 39 | 
             
            ===Example (using library)
         | 
| 40 | 
            -
            The library style allows you to parse a log file and get back a
         | 
| 41 | 
            -
            LogFile[link:classes/Pidgin2Adium/LogFile.html] instance for easy reading, manipulation, etc.
         | 
| 42 | 
            -
            You can also create log files yourself using Pidgin2Adium.parse_and_generate[link:classes/Pidgin2Adium.html#M000006].
         | 
| 43 | 
            -
            For batch processing, use LogConverter[link:classes/Pidgin2Adium/LogConverter.html].
         | 
| 40 | 
            +
            The library style allows you to parse a log file and get back a LogFile[link:classes/Pidgin2Adium/LogFile.html] instance for easy reading, manipulation, etc. If you don't need to do anything with the individual messages, use Pidgin2Adium.parse[link:classes/Pidgin2Adium.html#M000002].
         | 
| 44 41 |  | 
| 45 42 | 
             
             require 'pidgin2adium'
         | 
| 46 43 | 
             
             logfile = Pidgin2Adium.parse("/path/to/log/file.html", "gabe,gbw,gabeb-w")
         | 
| @@ -81,15 +78,17 @@ For batch processing, use LogConverter[link:classes/Pidgin2Adium/LogConverter.ht | |
| 81 78 | 
             
            	puts "Successfully wrote out log file!"
         | 
| 82 79 | 
             
            	puts "Path to output file: #{success}"
         | 
| 83 80 | 
             
                end
         | 
| 84 | 
            -
                # This deletes search indexes  | 
| 85 | 
            -
                #  | 
| 86 | 
            -
                #  | 
| 87 | 
            -
                #  | 
| 81 | 
            +
                # This deletes search indexes so Adium re-indexes the new chat logs.
         | 
| 82 | 
            +
                # It is not automatically called after log_file.write_out()
         | 
| 83 | 
            +
                # Call it after converting all the logs, since it takes up a bit of
         | 
| 84 | 
            +
                # processing power.
         | 
| 88 85 | 
             
                Pidgin2Adium.delete_search_indexes()
         | 
| 89 86 | 
             
             end
         | 
| 90 87 |  | 
| 91 88 | 
             
            ===Example 2 (using library)
         | 
| 92 | 
            -
            If you want to  | 
| 89 | 
            +
            If you want to parse the file and write it out instead of just parsing it, use Pidgin2Adium.parse_and_generate.
         | 
| 90 | 
            +
             | 
| 91 | 
            +
            Note: For batch processing, use LogConverter[link:classes/Pidgin2Adium/LogConverter.html].
         | 
| 93 92 |  | 
| 94 93 | 
             
             require 'pidgin2adium'
         | 
| 95 94 | 
             
             # Both options are optional; without :output_dir, writes to Adium log dir
         | 
    
        data/Rakefile.rb
    CHANGED
    
    | @@ -18,12 +18,23 @@ $hoe = Hoe.spec 'pidgin2adium' do | |
| 18 18 | 
             
              #self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
         | 
| 19 19 | 
             
              self.rubyforge_name       = self.name # this is default value
         | 
| 20 20 | 
             
              # self.extra_deps         = [['activesupport','>= 2.0.2']]
         | 
| 21 | 
            +
              
         | 
| 22 | 
            +
              self.spec_extras[:extensions]  = "ext/balance_tags_c/extconf.rb"
         | 
| 23 | 
            +
            end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            $hoe.spec.rdoc_options = %w{--main README.rdoc}
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            # Use hanna RDoc template, if available
         | 
| 28 | 
            +
            begin
         | 
| 29 | 
            +
                gem "hanna"
         | 
| 30 | 
            +
                $hoe.spec.rdoc_options << '-T hanna'
         | 
| 31 | 
            +
            rescue GEM::LoadError
         | 
| 32 | 
            +
                # hanna not installed, continue
         | 
| 21 33 | 
             
            end
         | 
| 22 | 
            -
            # Use hanna RDoc template
         | 
| 23 | 
            -
            $hoe.spec.rdoc_options = %w{--main README.rdoc -T hanna}
         | 
| 24 34 |  | 
| 25 35 | 
             
            require 'newgem/tasks'
         | 
| 26 36 | 
             
            Dir['tasks/**/*.rake'].each { |t| load t }
         | 
| 37 | 
            +
            task :postrelease => [:publish_docs, :announce]
         | 
| 27 38 |  | 
| 28 39 | 
             
            # TODO - want other tests/tasks run by default? Add them to the list
         | 
| 29 40 | 
             
            # remove_task :default
         | 
    
        data/bin/pidgin2adium
    CHANGED
    
    | @@ -32,7 +32,7 @@ oparser = OptionParser.new do |opts| | |
| 32 32 | 
             
            	    "is you. Whitespace and case do not matter.") do |aliases|
         | 
| 33 33 | 
             
            	options[:aliases] = aliases
         | 
| 34 34 | 
             
                end
         | 
| 35 | 
            -
                opts.on('-o', '--out  | 
| 35 | 
            +
                opts.on('-o', '--out OUT_DIR',
         | 
| 36 36 | 
             
            	    'The top-level directory under which to',
         | 
| 37 37 | 
             
            	    'store the logs (each in its own folder',
         | 
| 38 38 | 
             
            	    'by screen name).',
         | 
| @@ -0,0 +1,198 @@ | |
| 1 | 
            +
            /*
         | 
| 2 | 
            +
             * Balances tags of string using a modified stack. Returns a balanced string.
         | 
| 3 | 
            +
             * 
         | 
| 4 | 
            +
             * From Wordpress's formatting.php and rewritten in C by
         | 
| 5 | 
            +
             * Gabe Berke-Williams, 2010.
         | 
| 6 | 
            +
             * 
         | 
| 7 | 
            +
             * Original Author:: Leonard Lin <leonard@acm.org>
         | 
| 8 | 
            +
             * License:: GPL v2.0
         | 
| 9 | 
            +
             * Copyright:: November 4, 2001
         | 
| 10 | 
            +
             */
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            #include <ruby.h>
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            #ifndef RARRAY_PTR
         | 
| 15 | 
            +
            #define RARRAY_PTR(arr)  RARRAY(arr)->ptr
         | 
| 16 | 
            +
            #endif
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            #ifndef RSTRING_LEN
         | 
| 19 | 
            +
            #define RSTRING_LEN(str) RSTRING(str)->len
         | 
| 20 | 
            +
            #endif
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            VALUE balance_tags_c(VALUE, VALUE);
         | 
| 23 | 
            +
            static VALUE mP2A;
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            /*
         | 
| 26 | 
            +
             * call-seq: Pidgin2Adium.balance_tags_c(text) => text with balanced HTML tags
         | 
| 27 | 
            +
             *
         | 
| 28 | 
            +
             * Balances tags of _text_. Returns modified text.
         | 
| 29 | 
            +
             */
         | 
| 30 | 
            +
            VALUE balance_tags_c(VALUE mod, VALUE text){
         | 
| 31 | 
            +
                if( TYPE(text) != T_STRING ){
         | 
| 32 | 
            +
            	rb_raise(rb_eArgError, "bad argument to balance_tags_c, String only please.");
         | 
| 33 | 
            +
                }
         | 
| 34 | 
            +
                VALUE tagstack = rb_ary_new2(1);
         | 
| 35 | 
            +
                int stacksize = 0;
         | 
| 36 | 
            +
                VALUE tagqueue = rb_str_new2("");
         | 
| 37 | 
            +
                VALUE ZERO = INT2FIX(0),
         | 
| 38 | 
            +
            	  ONE = INT2FIX(1);
         | 
| 39 | 
            +
                VALUE newtext = rb_str_new2("");
         | 
| 40 | 
            +
                // Known single-entity/self-closing tags
         | 
| 41 | 
            +
                VALUE single_tags = rb_ary_new3(5,
         | 
| 42 | 
            +
            	    rb_str_new2("br"),
         | 
| 43 | 
            +
            	    rb_str_new2("hr"),
         | 
| 44 | 
            +
            	    rb_str_new2("img"),
         | 
| 45 | 
            +
            	    rb_str_new2("input"),
         | 
| 46 | 
            +
            	    rb_str_new2("meta"));
         | 
| 47 | 
            +
                // Tags that can be immediately nested within themselves
         | 
| 48 | 
            +
                VALUE nestable_tags = rb_ary_new3(4,
         | 
| 49 | 
            +
            	    rb_str_new2("blockquote"),
         | 
| 50 | 
            +
            	    rb_str_new2("div"),
         | 
| 51 | 
            +
            	    rb_str_new2("span"),
         | 
| 52 | 
            +
            	    rb_str_new2("font"));
         | 
| 53 | 
            +
                // 1: tagname, with possible leading "/"
         | 
| 54 | 
            +
                // 2: attributes
         | 
| 55 | 
            +
                VALUE tag_regex = rb_reg_regcomp(rb_str_new2("<(\\/?\\w*)\\s*([^>]*)>"));
         | 
| 56 | 
            +
                VALUE pos;  // position in text
         | 
| 57 | 
            +
                VALUE match;
         | 
| 58 | 
            +
                VALUE tag;
         | 
| 59 | 
            +
                VALUE attributes;
         | 
| 60 | 
            +
                VALUE t; // loop variable when iterating over tagstack at end of while loop
         | 
| 61 | 
            +
                int matchlen;
         | 
| 62 | 
            +
                int done = 0;
         | 
| 63 | 
            +
                int j, k, i; // loop counters
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                // WP bug fix for comments - in case you REALLY meant to type '< !--'
         | 
| 66 | 
            +
                rb_funcall(text, rb_intern("gsub!"), 2,
         | 
| 67 | 
            +
            	    rb_str_new2("< !--"),
         | 
| 68 | 
            +
            	    rb_str_new2("<    !--"));
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                // WP bug fix for LOVE <3 (and other situations with '<' before a number)
         | 
| 71 | 
            +
                rb_funcall(text, rb_intern("gsub!"), 2,
         | 
| 72 | 
            +
            	    rb_reg_regcomp(rb_str_new2("<([0-9]{1})")),
         | 
| 73 | 
            +
            	    rb_str_new2("<\\1"));
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                pos = rb_funcall(text, rb_intern("=~"), 1, tag_regex);
         | 
| 76 | 
            +
                done = (pos == Qnil);
         | 
| 77 | 
            +
                while ( ! done ){
         | 
| 78 | 
            +
            	rb_str_concat(newtext, tagqueue);
         | 
| 79 | 
            +
            	match = rb_funcall(text, rb_intern("match"), 1, tag_regex);
         | 
| 80 | 
            +
            	tag = rb_funcall(rb_reg_nth_match(1, match), rb_intern("downcase"), 0);
         | 
| 81 | 
            +
            	attributes = rb_reg_nth_match(2, match);
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            	matchlen = NUM2INT(rb_funcall(rb_reg_nth_match(0, match), rb_intern("size"), 0));
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            	// clear the shifter
         | 
| 86 | 
            +
            	tagqueue = rb_str_new2("");
         | 
| 87 | 
            +
            	// Pop or Push
         | 
| 88 | 
            +
            	if (0 == rb_str_cmp(rb_str_substr(tag, 0, 1), rb_str_new2("/"))){ // End Tag
         | 
| 89 | 
            +
            	    rb_funcall(tag, rb_intern("slice!"), 2, ZERO, ONE);
         | 
| 90 | 
            +
            	    // if too many closing tags
         | 
| 91 | 
            +
            	    if(stacksize <= 0){
         | 
| 92 | 
            +
            		tag = rb_str_new2("");
         | 
| 93 | 
            +
            		//or close to be safe: tag = '/' << tag
         | 
| 94 | 
            +
            	    } else if (0 == rb_str_cmp(RARRAY_PTR(tagstack)[stacksize - 1], tag)){
         | 
| 95 | 
            +
            		// found closing tag
         | 
| 96 | 
            +
            		// if stacktop value == tag close value then pop
         | 
| 97 | 
            +
            		// Close Tag
         | 
| 98 | 
            +
            		tag = rb_str_append(rb_str_new2("</"), tag);
         | 
| 99 | 
            +
            		rb_str_concat(tag, rb_str_new2(">")); 
         | 
| 100 | 
            +
            		// Pop
         | 
| 101 | 
            +
            		rb_ary_pop(tagstack);
         | 
| 102 | 
            +
            		stacksize--;
         | 
| 103 | 
            +
            		} else { // closing tag not at top, search for it
         | 
| 104 | 
            +
            		    for(j=stacksize-1; j>=0; j--){
         | 
| 105 | 
            +
            			if(0 == rb_str_cmp(RARRAY_PTR(tagstack)[j], tag) ){
         | 
| 106 | 
            +
            			    // add tag to tagqueue
         | 
| 107 | 
            +
            			    for(k = stacksize-1;k>=j;k--){
         | 
| 108 | 
            +
            				rb_str_concat(tagqueue, rb_str_new2("</"));
         | 
| 109 | 
            +
            				rb_str_concat(tagqueue, rb_ary_pop(tagstack));
         | 
| 110 | 
            +
            				rb_str_concat(tagqueue, rb_str_new2(">"));
         | 
| 111 | 
            +
            				stacksize--;
         | 
| 112 | 
            +
            			    }
         | 
| 113 | 
            +
            			    break;
         | 
| 114 | 
            +
            			}
         | 
| 115 | 
            +
            		    }
         | 
| 116 | 
            +
            		    tag = rb_str_new2("");
         | 
| 117 | 
            +
            		}
         | 
| 118 | 
            +
            	    } else {
         | 
| 119 | 
            +
            		// Begin Tag
         | 
| 120 | 
            +
             | 
| 121 | 
            +
            		// Tag Cleaning
         | 
| 122 | 
            +
             | 
| 123 | 
            +
            		if( ( RSTRING_LEN(attributes) > 0 && // test length before rb_str_substr
         | 
| 124 | 
            +
            		    (0 == rb_str_cmp(rb_str_substr(attributes, -1, 1), rb_str_new2("/"))) ) ||
         | 
| 125 | 
            +
            			(0 == rb_str_cmp(tag, rb_str_new2(""))) ){
         | 
| 126 | 
            +
            		    // If: self-closing or '', don't do anything.
         | 
| 127 | 
            +
            		} else if ( rb_ary_includes(single_tags, tag) ) {
         | 
| 128 | 
            +
            		    // ElseIf: it's a known single-entity tag but it doesn't close itself, do so
         | 
| 129 | 
            +
            		    rb_str_concat(attributes, rb_str_new2("/"));
         | 
| 130 | 
            +
            		} else {
         | 
| 131 | 
            +
            		    // Push the tag onto the stack
         | 
| 132 | 
            +
            		    // If the top of the stack is the same as the tag we want
         | 
| 133 | 
            +
            		    // to push, close previous tag
         | 
| 134 | 
            +
            		    if ( (stacksize > 0) &&
         | 
| 135 | 
            +
            			(Qfalse == rb_ary_includes(nestable_tags, tag)) &&
         | 
| 136 | 
            +
            			(0 == rb_str_cmp(rb_ary_entry(tagstack, stacksize - 1), tag))){
         | 
| 137 | 
            +
            			tagqueue = rb_str_new2("</");
         | 
| 138 | 
            +
            			rb_str_concat(tagqueue, rb_ary_pop(tagstack));
         | 
| 139 | 
            +
            			rb_str_concat(tagqueue, rb_str_new2(">"));
         | 
| 140 | 
            +
            			stacksize--; 
         | 
| 141 | 
            +
            		    }
         | 
| 142 | 
            +
            		    rb_ary_push(tagstack, tag);
         | 
| 143 | 
            +
            		    stacksize++;
         | 
| 144 | 
            +
            		}
         | 
| 145 | 
            +
             | 
| 146 | 
            +
            		// Attributes
         | 
| 147 | 
            +
            		if( 0 != rb_str_cmp(attributes, rb_str_new2("")) ){
         | 
| 148 | 
            +
            		    attributes = rb_str_plus(rb_str_new2(" "), attributes);
         | 
| 149 | 
            +
            		}
         | 
| 150 | 
            +
            		tag = rb_str_plus(rb_str_new2("<"), tag);
         | 
| 151 | 
            +
            		rb_str_concat(tag, attributes);
         | 
| 152 | 
            +
            		rb_str_concat(tag, rb_str_new2(">"));
         | 
| 153 | 
            +
            		//If already queuing a close tag, then put this tag on, too
         | 
| 154 | 
            +
            		if( RSTRING_LEN(tagqueue) > 0 ){
         | 
| 155 | 
            +
            		    rb_str_concat(tagqueue, tag);
         | 
| 156 | 
            +
            		    tag = rb_str_new2("");
         | 
| 157 | 
            +
            		}
         | 
| 158 | 
            +
            	    }
         | 
| 159 | 
            +
            	    rb_str_concat(newtext,
         | 
| 160 | 
            +
            		    rb_str_plus(rb_str_substr(text, 0, pos-1), tag));
         | 
| 161 | 
            +
            	    text = rb_str_substr(text,
         | 
| 162 | 
            +
            		    NUM2INT(pos)+matchlen,
         | 
| 163 | 
            +
            		    RSTRING_LEN(text) - (NUM2INT(pos)+matchlen));
         | 
| 164 | 
            +
            	    pos = rb_funcall(text, rb_intern("=~"), 1, tag_regex);
         | 
| 165 | 
            +
            	    done = (pos == Qnil);
         | 
| 166 | 
            +
            	}
         | 
| 167 | 
            +
             | 
| 168 | 
            +
            	// Clear Tag Queue
         | 
| 169 | 
            +
            	rb_str_concat(newtext, tagqueue);
         | 
| 170 | 
            +
             | 
| 171 | 
            +
            	// Add Remaining text
         | 
| 172 | 
            +
            	rb_str_concat(newtext, text);
         | 
| 173 | 
            +
             | 
| 174 | 
            +
            	i = NUM2INT(rb_funcall(tagstack, rb_intern("length"), 0)) - 1;
         | 
| 175 | 
            +
            	// Empty Stack
         | 
| 176 | 
            +
            	for(; i >= 0; i--){
         | 
| 177 | 
            +
            	    // Add remaining tags to close
         | 
| 178 | 
            +
            	    t = RARRAY_PTR(tagstack)[i];
         | 
| 179 | 
            +
            	    rb_str_concat(newtext, rb_str_new2("</"));
         | 
| 180 | 
            +
            	    rb_str_concat(newtext, t);
         | 
| 181 | 
            +
            	    rb_str_concat(newtext, rb_str_new2(">"));
         | 
| 182 | 
            +
            	}
         | 
| 183 | 
            +
             | 
| 184 | 
            +
            	// WP fix for the bug with HTML comments
         | 
| 185 | 
            +
            	rb_funcall(newtext, rb_intern("gsub!"), 2,
         | 
| 186 | 
            +
            		rb_str_new2("< !--"),
         | 
| 187 | 
            +
            		rb_str_new2("<!--"));
         | 
| 188 | 
            +
            	rb_funcall(newtext, rb_intern("gsub!"), 2,
         | 
| 189 | 
            +
            		rb_str_new2("<    !--"),
         | 
| 190 | 
            +
            		rb_str_new2("< !--"));
         | 
| 191 | 
            +
             | 
| 192 | 
            +
            	return newtext;
         | 
| 193 | 
            +
            }
         | 
| 194 | 
            +
             | 
| 195 | 
            +
            void Init_balance_tags_c(){
         | 
| 196 | 
            +
                mP2A = rb_define_module("Pidgin2Adium");
         | 
| 197 | 
            +
                rb_define_module_function(mP2A, "balance_tags_c", balance_tags_c, 1);
         | 
| 198 | 
            +
            }
         | 
    
        data/lib/pidgin2adium.rb
    CHANGED
    
    | @@ -14,7 +14,7 @@ module Pidgin2Adium | |
| 14 14 | 
             
                ADIUM_LOG_DIR = File.expand_path('~/Library/Application Support/Adium 2.0/Users/Default/Logs/') << '/' 
         | 
| 15 15 | 
             
                # These files/directories show up in Dir.entries()
         | 
| 16 16 | 
             
                BAD_DIRS = %w{. .. .DS_Store Thumbs.db .system}
         | 
| 17 | 
            -
                VERSION = " | 
| 17 | 
            +
                VERSION = "3.0.0"
         | 
| 18 18 | 
             
                # For displaying after we finish converting
         | 
| 19 19 | 
             
                @@oops_messages = []
         | 
| 20 20 | 
             
                @@error_messages = []
         | 
| @@ -38,6 +38,7 @@ module Pidgin2Adium | |
| 38 38 | 
             
                module_function :log_msg, :oops, :error
         | 
| 39 39 | 
             
                #######################
         | 
| 40 40 |  | 
| 41 | 
            +
                # Parses the provided log.
         | 
| 41 42 | 
             
                # Returns a LogFile instance or false if an error occurred.
         | 
| 42 43 | 
             
                def parse(logfile_path, my_aliases)
         | 
| 43 44 | 
             
            	logfile_path = File.expand_path(logfile_path)
         | 
| @@ -54,7 +55,8 @@ module Pidgin2Adium | |
| 54 55 |  | 
| 55 56 | 
             
            	return parser.parse()
         | 
| 56 57 | 
             
                end
         | 
| 57 | 
            -
             | 
| 58 | 
            +
               
         | 
| 59 | 
            +
                # Parses the provided log and writes out the log in Adium format.
         | 
| 58 60 | 
             
                # Returns the path to the converted log, false if an error occurred, or
         | 
| 59 61 | 
             
                # Pidgin2Adium::FILE_EXISTS if file already exists AND opts[:overwrite] =
         | 
| 60 62 | 
             
                # false.
         | 
| @@ -26,12 +26,12 @@ module Pidgin2Adium | |
| 26 26 | 
             
            	    # key is for Pidgin, value is for Adium
         | 
| 27 27 | 
             
            	    # Just used for <service>.<screenname> in directory structure
         | 
| 28 28 | 
             
            	    service_name_map = {'aim' => 'AIM',
         | 
| 29 | 
            -
            		'jabber' =>' | 
| 29 | 
            +
            		'jabber' =>'Jabber',
         | 
| 30 30 | 
             
            		'gtalk'=> 'GTalk',
         | 
| 31 31 | 
             
            		'icq' => 'ICQ',
         | 
| 32 32 | 
             
            		'qq' => 'QQ',
         | 
| 33 33 | 
             
            		'msn' => 'MSN',
         | 
| 34 | 
            -
            		'yahoo' => 'Yahoo'}
         | 
| 34 | 
            +
            		'yahoo' => 'Yahoo!'}
         | 
| 35 35 |  | 
| 36 36 | 
             
            	    @service = service_name_map[service.downcase]
         | 
| 37 37 | 
             
            	end
         | 
| @@ -7,7 +7,7 @@ | |
| 7 7 | 
             
            require 'parsedate'
         | 
| 8 8 | 
             
            require 'time' # for Time.zone_offset
         | 
| 9 9 |  | 
| 10 | 
            -
            require ' | 
| 10 | 
            +
            require 'balance_tags_c'
         | 
| 11 11 | 
             
            require 'pidgin2adium/log_file'
         | 
| 12 12 |  | 
| 13 13 | 
             
            module Pidgin2Adium
         | 
| @@ -42,12 +42,12 @@ module Pidgin2Adium | |
| 42 42 | 
             
            	    # Time regexes must be set before pre_parse().
         | 
| 43 43 | 
             
            	    # "4/18/2007 11:02:00 AM" => %w{4, 18, 2007, 11, 02, 00, AM}
         | 
| 44 44 | 
             
            	    # ONLY used (if at all) in first line of chat ("Conversation with...at...")
         | 
| 45 | 
            -
            	    @time_regex_first_line = %r{(\d{1,2})/(\d{1,2})/(\d{4}) (\d{1,2}):(\d{2}):(\d{2}) ([AP]M)}
         | 
| 45 | 
            +
            	    @time_regex_first_line = %r{^(\d{1,2})/(\d{1,2})/(\d{4}) (\d{1,2}):(\d{2}):(\d{2}) ([AP]M)$}
         | 
| 46 46 | 
             
            	    # "2007-04-17 12:33:13" => %w{2007, 04, 17, 12, 33, 13}
         | 
| 47 | 
            -
            	    @time_regex =  | 
| 47 | 
            +
            	    @time_regex = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/
         | 
| 48 48 | 
             
            	    # sometimes a line in a chat doesn't have a full timestamp
         | 
| 49 49 | 
             
            	    # "04:22:05 AM" => %w{04 22 05 AM}
         | 
| 50 | 
            -
            	    @minimal_time_regex =  | 
| 50 | 
            +
            	    @minimal_time_regex = /^(\d{1,2}):(\d{2}):(\d{2})( [AP]M)?$/
         | 
| 51 51 |  | 
| 52 52 | 
             
            	    # Whether or not the first line is parseable.
         | 
| 53 53 | 
             
            	    @first_line_is_valid = true
         | 
| @@ -90,10 +90,10 @@ module Pidgin2Adium | |
| 90 90 | 
             
            		/(.+) is offering to send file/,
         | 
| 91 91 | 
             
            		/^Transfer of file .+ complete$/,
         | 
| 92 92 | 
             
            		/Error reading|writing|accessing .+: .+/,
         | 
| 93 | 
            -
            		/You  | 
| 93 | 
            +
            		/You cancell?ed the transfer of/,
         | 
| 94 94 | 
             
            		/File transfer cancelled/,
         | 
| 95 | 
            -
            		/( | 
| 96 | 
            -
            		/( | 
| 95 | 
            +
            		/(.+?) cancell?ed the transfer of/,
         | 
| 96 | 
            +
            		/(.+?) cancelled the file transfer/,
         | 
| 97 97 | 
             
            		# Direct IM - actual (dis)connect events are their own types
         | 
| 98 98 | 
             
            		/^Attempting to connect to (.+) at .+ for Direct IM\./,
         | 
| 99 99 | 
             
            		/^Asking (.+) to connect to us at .+ for Direct IM\./,
         | 
| @@ -106,9 +106,6 @@ module Pidgin2Adium | |
| 106 106 | 
             
            		/^Conflicting Key Received!$/,
         | 
| 107 107 | 
             
            		/^Error in decryption- asking for resend\.\.\.$/,
         | 
| 108 108 | 
             
            		/^Making new key pair\.\.\.$/,
         | 
| 109 | 
            -
            		# file transfer
         | 
| 110 | 
            -
            		/You canceled the transfer of/,
         | 
| 111 | 
            -
            		/(.+?) canceled the transfer of/, 
         | 
| 112 109 | 
             
            		# sending errors
         | 
| 113 110 | 
             
            		/^Last outgoing message not received properly- resetting$/,
         | 
| 114 111 | 
             
            		/Resending\.\.\./,
         | 
| @@ -178,9 +175,8 @@ module Pidgin2Adium | |
| 178 175 | 
             
            	    if tz_match and tz_match[1]
         | 
| 179 176 | 
             
            		tz_offset = tz_match[1]
         | 
| 180 177 | 
             
            	    else
         | 
| 181 | 
            -
            		zone = Time.local(Time.new.year).zone
         | 
| 182 178 | 
             
            		# "-0500" (3d rather than 2d to allow for "+")
         | 
| 183 | 
            -
            		tz_offset = sprintf(' | 
| 179 | 
            +
            		tz_offset = sprintf('%+03d00', Time.zone_offset(Time.now.zone) / 3600)
         | 
| 184 180 | 
             
            	    end
         | 
| 185 181 | 
             
            	    return tz_offset
         | 
| 186 182 | 
             
            	end
         | 
| @@ -255,7 +251,7 @@ module Pidgin2Adium | |
| 255 251 | 
             
            		user_SN = first_line_match[3].downcase.tr(' ', '')
         | 
| 256 252 | 
             
            		partner_SN = first_line_match[1]
         | 
| 257 253 | 
             
            		pidgin_chat_time_start = first_line_match[2]
         | 
| 258 | 
            -
            		basic_time_info = case  | 
| 254 | 
            +
            		basic_time_info = case pidgin_chat_time_start
         | 
| 259 255 | 
             
            				  when @time_regex: [$1.to_i, $2.to_i, $3.to_i]
         | 
| 260 256 | 
             
            				  when @time_regex_first_line: [$3.to_i, $1.to_i, $2.to_i]
         | 
| 261 257 | 
             
            				  end
         | 
| @@ -488,18 +484,15 @@ module Pidgin2Adium | |
| 488 484 |  | 
| 489 485 | 
             
            		styleparts = style.split(/; ?/)
         | 
| 490 486 | 
             
            		styleparts.map! do |p|
         | 
| 491 | 
            -
            		    if p  | 
| 492 | 
            -
            			 | 
| 493 | 
            -
            			# <span style="color: #000000>today;">today was busy</span>
         | 
| 494 | 
            -
            			# Then p = "color: #000000>today"
         | 
| 495 | 
            -
            			# Or it can end in ">;", with no text before the semicolon.
         | 
| 496 | 
            -
            			# So remove the ">" and anything following it.
         | 
| 497 | 
            -
            			
         | 
| 498 | 
            -
            			# Use regex instead of string, to account for funky ">" stuff
         | 
| 499 | 
            -
            			if p =~ /color: #000000/
         | 
| 487 | 
            +
            		    if p[0,5] == 'color'
         | 
| 488 | 
            +
            			if p.include?('color: #000000')
         | 
| 500 489 | 
             
            			    next
         | 
| 501 490 | 
             
            			elsif p =~ /(color: #[0-9a-fA-F]{6})(>.*)?/
         | 
| 502 | 
            -
            			    #  | 
| 491 | 
            +
            			    # Regarding the bit with the ">", sometimes this happens:
         | 
| 492 | 
            +
            			    # <span style="color: #000000>today;">today was busy</span>
         | 
| 493 | 
            +
            			    # Then p = "color: #000000>today"
         | 
| 494 | 
            +
            			    # Or it can end in ">;", with no text before the semicolon.
         | 
| 495 | 
            +
            			    # So keep the color but remove the ">" and anything following it.
         | 
| 503 496 | 
             
            			    next($1)
         | 
| 504 497 | 
             
            			end
         | 
| 505 498 | 
             
            		    else
         | 
| @@ -546,7 +539,6 @@ module Pidgin2Adium | |
| 546 539 | 
             
                # Basic message with body text (as opposed to pure status messages, which
         | 
| 547 540 | 
             
                # have no body).
         | 
| 548 541 | 
             
                class XMLMessage < Message
         | 
| 549 | 
            -
            	include Pidgin2Adium
         | 
| 550 542 | 
             
            	def initialize(sender, time, buddy_alias, body)
         | 
| 551 543 | 
             
            	    super(sender, time, buddy_alias)
         | 
| 552 544 | 
             
            	    @body = body
         | 
| @@ -571,7 +563,7 @@ module Pidgin2Adium | |
| 571 563 | 
             
            	    normalize_body_entities!()
         | 
| 572 564 | 
             
            	    # Fix mismatched tags. Yes, it's faster to do it per-message
         | 
| 573 565 | 
             
            	    # than all at once.
         | 
| 574 | 
            -
            	    @body =  | 
| 566 | 
            +
            	    @body = Pidgin2Adium.balance_tags_c(@body)
         | 
| 575 567 | 
             
            	    if @buddy_alias[0,3] == '***'
         | 
| 576 568 | 
             
            		# "***<alias>" is what pidgin sets as the alias for a /me action
         | 
| 577 569 | 
             
            		@buddy_alias.slice!(0,3)
         | 
    
        data/script/console
    ADDED
    
    | @@ -0,0 +1,10 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # File: script/console
         | 
| 3 | 
            +
            irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            libs =  " -r irb/completion"
         | 
| 6 | 
            +
            # Perhaps use a console_lib to store any extra methods I may want available in the cosole
         | 
| 7 | 
            +
            # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
         | 
| 8 | 
            +
            libs <<  " -r #{File.dirname(__FILE__) + '/../lib/p2a.rb'}"
         | 
| 9 | 
            +
            puts "Loading p2a gem"
         | 
| 10 | 
            +
            exec "#{irb} #{libs} --simple-prompt"
         | 
    
        data/script/destroy
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            begin
         | 
| 5 | 
            +
              require 'rubigen'
         | 
| 6 | 
            +
            rescue LoadError
         | 
| 7 | 
            +
              require 'rubygems'
         | 
| 8 | 
            +
              require 'rubigen'
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
            require 'rubigen/scripts/destroy'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ARGV.shift if ['--help', '-h'].include?(ARGV[0])
         | 
| 13 | 
            +
            RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
         | 
| 14 | 
            +
            RubiGen::Scripts::Destroy.new.run(ARGV)
         | 
    
        data/script/generate
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            begin
         | 
| 5 | 
            +
              require 'rubigen'
         | 
| 6 | 
            +
            rescue LoadError
         | 
| 7 | 
            +
              require 'rubygems'
         | 
| 8 | 
            +
              require 'rubigen'
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
            require 'rubigen/scripts/generate'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ARGV.shift if ['--help', '-h'].include?(ARGV[0])
         | 
| 13 | 
            +
            RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
         | 
| 14 | 
            +
            RubiGen::Scripts::Generate.new.run(ARGV)
         | 
    
        data/tasks/extconf.rake
    ADDED
    
    | @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            namespace :extconf do
         | 
| 2 | 
            +
              desc "Compiles the Ruby extension"
         | 
| 3 | 
            +
              task :compile
         | 
| 4 | 
            +
            end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            task :compile => "extconf:compile"
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            task :test => :compile
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            BIN = "*.{bundle,jar,so,obj,pdb,lib,def,exp}"
         | 
| 11 | 
            +
            $hoe.clean_globs |= ["ext/**/#{BIN}", "lib/**/#{BIN}", 'ext/**/Makefile']
         | 
| 12 | 
            +
            $hoe.spec.require_paths = Dir['{lib,ext/*}']
         | 
| 13 | 
            +
            $hoe.spec.extensions = FileList["ext/**/extconf.rb"].to_a
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            namespace :extconf do
         | 
| 2 | 
            +
              extension = File.basename(__FILE__, '.rake')
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              ext = "ext/#{extension}"
         | 
| 5 | 
            +
              ext_so = "#{ext}/#{extension}.#{Config::CONFIG['DLEXT']}"
         | 
| 6 | 
            +
              ext_files = FileList[
         | 
| 7 | 
            +
                "#{ext}/*.c",
         | 
| 8 | 
            +
                "#{ext}/*.h",
         | 
| 9 | 
            +
                "#{ext}/*.rl",
         | 
| 10 | 
            +
                "#{ext}/extconf.rb",
         | 
| 11 | 
            +
                "#{ext}/Makefile",
         | 
| 12 | 
            +
                # "lib"
         | 
| 13 | 
            +
              ]
         | 
| 14 | 
            +
             | 
| 15 | 
            +
             | 
| 16 | 
            +
              task :compile => extension do
         | 
| 17 | 
            +
                if Dir.glob("**/#{extension}.{o,so,dll}").length == 0
         | 
| 18 | 
            +
                  STDERR.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
         | 
| 19 | 
            +
                  STDERR.puts "Gem actually failed to build.  Your system is"
         | 
| 20 | 
            +
                  STDERR.puts "NOT configured properly to build #{GEM_NAME}."
         | 
| 21 | 
            +
                  STDERR.puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
         | 
| 22 | 
            +
                  exit(1)
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              desc "Builds just the #{extension} extension"
         | 
| 27 | 
            +
              task extension.to_sym => ["#{ext}/Makefile", ext_so ]
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              file "#{ext}/Makefile" => ["#{ext}/extconf.rb"] do
         | 
| 30 | 
            +
                Dir.chdir(ext) do ruby "extconf.rb" end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              file ext_so => ext_files do
         | 
| 34 | 
            +
                Dir.chdir(ext) do
         | 
| 35 | 
            +
                  sh(PLATFORM =~ /win32/ ? 'nmake' : 'make') do |ok, res|
         | 
| 36 | 
            +
                    if !ok
         | 
| 37 | 
            +
                      require "fileutils"
         | 
| 38 | 
            +
                      FileUtils.rm Dir.glob('*.{so,o,dll,bundle}')
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
    
        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: 3.0.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors: 
         | 
| 7 7 | 
             
            - Gabe B-W
         | 
| @@ -9,9 +9,29 @@ autorequire: | |
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 11 |  | 
| 12 | 
            -
            date:  | 
| 12 | 
            +
            date: 2010-01-31 00:00:00 -05:00
         | 
| 13 13 | 
             
            default_executable: 
         | 
| 14 14 | 
             
            dependencies: 
         | 
| 15 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 16 | 
            +
              name: rubyforge
         | 
| 17 | 
            +
              type: :development
         | 
| 18 | 
            +
              version_requirement: 
         | 
| 19 | 
            +
              version_requirements: !ruby/object:Gem::Requirement 
         | 
| 20 | 
            +
                requirements: 
         | 
| 21 | 
            +
                - - ">="
         | 
| 22 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 23 | 
            +
                    version: 2.0.3
         | 
| 24 | 
            +
                version: 
         | 
| 25 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 26 | 
            +
              name: gemcutter
         | 
| 27 | 
            +
              type: :development
         | 
| 28 | 
            +
              version_requirement: 
         | 
| 29 | 
            +
              version_requirements: !ruby/object:Gem::Requirement 
         | 
| 30 | 
            +
                requirements: 
         | 
| 31 | 
            +
                - - ">="
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 33 | 
            +
                    version: 0.3.0
         | 
| 34 | 
            +
                version: 
         | 
| 15 35 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 16 36 | 
             
              name: hoe
         | 
| 17 37 | 
             
              type: :development
         | 
| @@ -20,7 +40,7 @@ dependencies: | |
| 20 40 | 
             
                requirements: 
         | 
| 21 41 | 
             
                - - ">="
         | 
| 22 42 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 23 | 
            -
                    version: 2. | 
| 43 | 
            +
                    version: 2.5.0
         | 
| 24 44 | 
             
                version: 
         | 
| 25 45 | 
             
            description: |-
         | 
| 26 46 | 
             
              Pidgin2Adium is a fast, easy way to convert Pidgin (formerly gaim) logs to the
         | 
| @@ -30,23 +50,31 @@ email: | |
| 30 50 | 
             
            - pidgin2adium@brandeis.edu
         | 
| 31 51 | 
             
            executables: 
         | 
| 32 52 | 
             
            - pidgin2adium
         | 
| 33 | 
            -
            extensions:  | 
| 34 | 
            -
             | 
| 53 | 
            +
            extensions: 
         | 
| 54 | 
            +
            - ext/balance_tags_c/extconf.rb
         | 
| 35 55 | 
             
            extra_rdoc_files: 
         | 
| 36 56 | 
             
            - History.txt
         | 
| 37 57 | 
             
            - Manifest.txt
         | 
| 38 58 | 
             
            - README.rdoc
         | 
| 39 59 | 
             
            files: 
         | 
| 60 | 
            +
            - .autotest
         | 
| 40 61 | 
             
            - History.txt
         | 
| 41 62 | 
             
            - Manifest.txt
         | 
| 42 63 | 
             
            - README.rdoc
         | 
| 43 64 | 
             
            - Rakefile.rb
         | 
| 44 65 | 
             
            - bin/pidgin2adium
         | 
| 66 | 
            +
            - ext/balance_tags_c/balance_tags_c.c
         | 
| 67 | 
            +
            - ext/balance_tags_c/extconf.rb
         | 
| 45 68 | 
             
            - lib/pidgin2adium.rb
         | 
| 46 | 
            -
            - lib/pidgin2adium/balance_tags.rb
         | 
| 47 69 | 
             
            - lib/pidgin2adium/log_converter.rb
         | 
| 48 70 | 
             
            - lib/pidgin2adium/log_file.rb
         | 
| 49 71 | 
             
            - lib/pidgin2adium/log_parser.rb
         | 
| 72 | 
            +
            - script/console
         | 
| 73 | 
            +
            - script/destroy
         | 
| 74 | 
            +
            - script/generate
         | 
| 75 | 
            +
            - tasks/extconf.rake
         | 
| 76 | 
            +
            - tasks/extconf/balance_tags_c.rake
         | 
| 77 | 
            +
            - test/test_balance_tags_c_extn.rb
         | 
| 50 78 | 
             
            has_rdoc: true
         | 
| 51 79 | 
             
            homepage: http://rubyforge.org/projects/pidgin2adium/
         | 
| 52 80 | 
             
            licenses: []
         | 
| @@ -55,10 +83,10 @@ post_install_message: | |
| 55 83 | 
             
            rdoc_options: 
         | 
| 56 84 | 
             
            - --main
         | 
| 57 85 | 
             
            - README.rdoc
         | 
| 58 | 
            -
            - -T
         | 
| 59 | 
            -
            - hanna
         | 
| 86 | 
            +
            - -T hanna
         | 
| 60 87 | 
             
            require_paths: 
         | 
| 61 88 | 
             
            - lib
         | 
| 89 | 
            +
            - ext/balance_tags_c
         | 
| 62 90 | 
             
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 63 91 | 
             
              requirements: 
         | 
| 64 92 | 
             
              - - ">="
         | 
| @@ -78,5 +106,5 @@ rubygems_version: 1.3.5 | |
| 78 106 | 
             
            signing_key: 
         | 
| 79 107 | 
             
            specification_version: 3
         | 
| 80 108 | 
             
            summary: Pidgin2Adium is a fast, easy way to convert Pidgin (formerly gaim) logs to the Adium format
         | 
| 81 | 
            -
            test_files:  | 
| 82 | 
            -
             | 
| 109 | 
            +
            test_files: 
         | 
| 110 | 
            +
            - test/test_balance_tags_c_extn.rb
         | 
| @@ -1,118 +0,0 @@ | |
| 1 | 
            -
            module Pidgin2Adium
         | 
| 2 | 
            -
                # Balances tags of string using a modified stack. Returns a balanced
         | 
| 3 | 
            -
                # string, but also affects the text passed into it!
         | 
| 4 | 
            -
                # Use text = balance_tags(text).
         | 
| 5 | 
            -
                
         | 
| 6 | 
            -
                # From Wordpress's formatting.php; rewritten in Ruby by Gabe
         | 
| 7 | 
            -
                # Berke-Williams, 2009.
         | 
| 8 | 
            -
                # Author:: Leonard Lin <leonard@acm.org>
         | 
| 9 | 
            -
                # License:: GPL v2.0
         | 
| 10 | 
            -
                # Copyright:: November 4, 2001
         | 
| 11 | 
            -
                def balance_tags( text )
         | 
| 12 | 
            -
            	tagstack = []
         | 
| 13 | 
            -
            	stacksize = 0
         | 
| 14 | 
            -
            	tagqueue = ''
         | 
| 15 | 
            -
            	newtext = ''
         | 
| 16 | 
            -
            	single_tags = %w{br hr img input meta} # Known single-entity/self-closing tags
         | 
| 17 | 
            -
            	#nestable_tags = %w{blockquote div span} # Tags that can be immediately nested within themselves
         | 
| 18 | 
            -
            	nestable_tags = %w{blockquote div span font} # Tags that can be immediately nested within themselves
         | 
| 19 | 
            -
            	# 1: tagname, with possible leading "/"
         | 
| 20 | 
            -
            	# 2: attributes
         | 
| 21 | 
            -
            	tag_regex = /<(\/?\w*)\s*([^>]*)>/
         | 
| 22 | 
            -
             | 
| 23 | 
            -
            	# WP bug fix for comments - in case you REALLY meant to type '< !--'
         | 
| 24 | 
            -
            	text.gsub!('< !--', '<    !--')
         | 
| 25 | 
            -
             | 
| 26 | 
            -
            	# WP bug fix for LOVE <3 (and other situations with '<' before a number)
         | 
| 27 | 
            -
            	text.gsub!(/<([0-9]{1})/, '<\1')
         | 
| 28 | 
            -
             | 
| 29 | 
            -
            	while ( pos = (text =~ tag_regex) )
         | 
| 30 | 
            -
            	    newtext << tagqueue
         | 
| 31 | 
            -
            	    tag = $1.downcase
         | 
| 32 | 
            -
            	    attributes = $2
         | 
| 33 | 
            -
            	    matchlen = $~[0].size
         | 
| 34 | 
            -
             | 
| 35 | 
            -
            	    # clear the shifter
         | 
| 36 | 
            -
            	    tagqueue = ''
         | 
| 37 | 
            -
            	    # Pop or Push
         | 
| 38 | 
            -
            	    if (tag[0,1] == "/") # End Tag
         | 
| 39 | 
            -
            		tag.slice!(0,1)
         | 
| 40 | 
            -
            		# if too many closing tags
         | 
| 41 | 
            -
            		if(stacksize <= 0)
         | 
| 42 | 
            -
            		    tag = ''
         | 
| 43 | 
            -
            		    #or close to be safe: tag = '/' << tag
         | 
| 44 | 
            -
            		elsif (tagstack[stacksize - 1] == tag) # found closing tag
         | 
| 45 | 
            -
            		    # if stacktop value == tag close value then pop
         | 
| 46 | 
            -
            		    tag = '</' << tag << '>' # Close Tag
         | 
| 47 | 
            -
            		    # Pop
         | 
| 48 | 
            -
            		    tagstack.pop
         | 
| 49 | 
            -
            		    stacksize -= 1
         | 
| 50 | 
            -
            		else # closing tag not at top, search for it
         | 
| 51 | 
            -
            		    (stacksize-1).downto(0) do |j|
         | 
| 52 | 
            -
            			if (tagstack[j] == tag)
         | 
| 53 | 
            -
            			    # add tag to tagqueue
         | 
| 54 | 
            -
            			    ss = stacksize - 1
         | 
| 55 | 
            -
            			    ss.downto(j) do |k|
         | 
| 56 | 
            -
            				tagqueue << '</' << tagstack.pop << '>'
         | 
| 57 | 
            -
            				stacksize -= 1
         | 
| 58 | 
            -
            			    end
         | 
| 59 | 
            -
            			    break
         | 
| 60 | 
            -
            			end
         | 
| 61 | 
            -
            		    end
         | 
| 62 | 
            -
            		    tag = ''
         | 
| 63 | 
            -
            		end
         | 
| 64 | 
            -
            	    else
         | 
| 65 | 
            -
            		# Begin Tag
         | 
| 66 | 
            -
             | 
| 67 | 
            -
            		# Tag Cleaning
         | 
| 68 | 
            -
            		if( (attributes[-1,1] == '/') || (tag == '') )
         | 
| 69 | 
            -
            		    # If: self-closing or '', don't do anything.
         | 
| 70 | 
            -
            		elsif ( single_tags.include?(tag) )
         | 
| 71 | 
            -
            		    # ElseIf: it's a known single-entity tag but it doesn't close itself, do so
         | 
| 72 | 
            -
            		    attributes << '/'
         | 
| 73 | 
            -
            		else
         | 
| 74 | 
            -
            		    # Push the tag onto the stack
         | 
| 75 | 
            -
            		    # If the top of the stack is the same as the tag we want to push, close previous tag
         | 
| 76 | 
            -
            		    if ((stacksize > 0) &&
         | 
| 77 | 
            -
            			! nestable_tags.include?(tag) &&
         | 
| 78 | 
            -
            			(tagstack[stacksize - 1] == tag))
         | 
| 79 | 
            -
            			tagqueue = '</' << tagstack.pop << '>'
         | 
| 80 | 
            -
            			stacksize -= 1
         | 
| 81 | 
            -
            		    end
         | 
| 82 | 
            -
            		    tagstack.push(tag)
         | 
| 83 | 
            -
            		    stacksize += 1
         | 
| 84 | 
            -
            		end
         | 
| 85 | 
            -
             | 
| 86 | 
            -
            		# Attributes
         | 
| 87 | 
            -
            		if(attributes != '')
         | 
| 88 | 
            -
            		    attributes = ' ' << attributes
         | 
| 89 | 
            -
            		end
         | 
| 90 | 
            -
            		tag = '<' << tag << attributes << '>'
         | 
| 91 | 
            -
            		#If already queuing a close tag, then put this tag on, too
         | 
| 92 | 
            -
            		if (tagqueue)
         | 
| 93 | 
            -
            		    tagqueue << tag
         | 
| 94 | 
            -
            		    tag = ''
         | 
| 95 | 
            -
            		end
         | 
| 96 | 
            -
            	    end
         | 
| 97 | 
            -
            	    newtext << text[0,pos] << tag
         | 
| 98 | 
            -
            	    text = text[pos+matchlen, text.length - (pos+matchlen)]
         | 
| 99 | 
            -
            	end
         | 
| 100 | 
            -
             | 
| 101 | 
            -
            	# Clear Tag Queue
         | 
| 102 | 
            -
            	newtext << tagqueue
         | 
| 103 | 
            -
             | 
| 104 | 
            -
            	# Add Remaining text
         | 
| 105 | 
            -
            	newtext << text
         | 
| 106 | 
            -
             | 
| 107 | 
            -
            	# Empty Stack
         | 
| 108 | 
            -
            	tagstack.reverse_each do |t|
         | 
| 109 | 
            -
            	    newtext << '</' << t << '>' # Add remaining tags to close
         | 
| 110 | 
            -
            	end
         | 
| 111 | 
            -
             | 
| 112 | 
            -
            	# WP fix for the bug with HTML comments
         | 
| 113 | 
            -
            	newtext.gsub!("< !--", "<!--")
         | 
| 114 | 
            -
            	newtext.gsub!("<    !--", "< !--")
         | 
| 115 | 
            -
             | 
| 116 | 
            -
            	return newtext
         | 
| 117 | 
            -
                end
         | 
| 118 | 
            -
            end
         |