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