Module: Pidgin2Adium
- Included in:
- BasicParser, LogConverter, LogFile
- Defined in:
- lib/pidgin2adium/messages/message.rb,
lib/pidgin2adium.rb,
lib/pidgin2adium/version.rb,
lib/pidgin2adium/log_file.rb,
lib/pidgin2adium/log_converter.rb,
lib/pidgin2adium/messages/event.rb,
lib/pidgin2adium/messages/xml_message.rb,
lib/pidgin2adium/parsers/basic_parser.rb,
lib/pidgin2adium/messages/status_message.rb,
lib/pidgin2adium/parsers/html_log_parser.rb,
lib/pidgin2adium/parsers/text_log_parser.rb,
lib/pidgin2adium/messages/auto_reply_message.rb,
ext/balance_tags_c/balance_tags_c.c
Overview
The Message class’s subclasses, each used for holding one line of a chat.
Defined Under Namespace
Classes: AutoReplyMessage, BasicParser, Event, HtmlLogParser, InvalidFirstLineError, LogConverter, LogFile, Message, StatusMessage, TextLogParser, XMLMessage
Constant Summary collapse
- FILE_EXISTS =
Returned by LogFile.write_out if the output logfile already exists.
42
- ADIUM_LOG_DIR =
File.('~/Library/Application Support/Adium 2.0/Users/Default/Logs/') << '/'
- BAD_DIRS =
These files/directories show up in Dir.entries()
%w{. .. .DS_Store Thumbs.db .system}
- VERSION =
"3.3.0"
- @@oops_messages =
For displaying after we finish converting
[]
- @@error_messages =
[]
Class Method Summary collapse
-
.balance_tags_c(text) ⇒ Object
Balances tags of text.
-
.delete_search_indexes ⇒ Object
Newly-converted logs are viewable in the Adium Chat Transcript Viewer, but are not indexed, so a search of the logs doesn’t give results from the converted logs.
-
.error(str) ⇒ Object
:nodoc:.
-
.log_msg(str) ⇒ Object
:nodoc:.
-
.oops(str) ⇒ Object
:nodoc:.
-
.parse(logfile_path, my_aliases, force_conversion) ⇒ Object
Parses the provided log.
-
.parse_and_generate(logfile_path, my_aliases, opts = {}) ⇒ Object
Parses the provided log and writes out the log in Adium format.
Class Method Details
.balance_tags_c(text) ⇒ Object
Balances tags of text. Returns modified text.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'ext/balance_tags_c/balance_tags_c.c', line 30 VALUE (VALUE mod, VALUE text){ if( TYPE(text) != T_STRING ){ rb_raise(rb_eArgError, "bad argument to balance_tags_c, String only please."); } VALUE = rb_ary_new2(1); int stacksize = 0; VALUE tagqueue = rb_str_new2(""); VALUE ZERO = INT2FIX(0), ONE = INT2FIX(1); VALUE newtext = rb_str_new2(""); // Known single-entity/self-closing VALUE = rb_ary_new3(5, rb_str_new2("br"), rb_str_new2("hr"), rb_str_new2("img"), rb_str_new2("input"), rb_str_new2("meta")); // Tags that can be immediately nested within themselves VALUE = rb_ary_new3(4, rb_str_new2("blockquote"), rb_str_new2("div"), rb_str_new2("span"), rb_str_new2("font")); // 1: tagname, with possible leading "/" // 2: attributes VALUE tag_regex = rb_eval_string("/<(\\/?\\w*)\\s*([^>]*)>/"); VALUE pos; // position in text VALUE match; VALUE tag; VALUE attributes; VALUE t; // loop variable when over at end of while loop int matchlen; int done = 0; int j, k, i; // loop counters // WP bug fix for comments - in case you REALLY meant to type '< !--' rb_funcall(text, rb_intern("gsub!"), 2, rb_str_new2("< !--"), rb_str_new2("< !--")); // WP bug fix for LOVE <3 (and other situations with '<' before a number) rb_funcall(text,rb_intern("gsub!"), 2, rb_eval_string("/<([0-9]{1})/"), rb_str_new2("<\\1")); pos = rb_funcall(text, rb_intern("=~"), 1, tag_regex); done = (pos == Qnil); while ( ! done ){ rb_str_concat(newtext, tagqueue); match = rb_funcall(text, rb_intern("match"), 1, tag_regex); tag = rb_funcall(rb_reg_nth_match(1, match), rb_intern("downcase"), 0); attributes = rb_reg_nth_match(2, match); matchlen = NUM2INT(rb_funcall(rb_reg_nth_match(0, match), rb_intern("size"), 0)); // clear the shifter tagqueue = rb_str_new2(""); // Pop or Push if (0 == rb_str_cmp(rb_str_substr(tag, 0, 1), rb_str_new2("/"))){ // End Tag rb_funcall(tag, rb_intern("slice!"), 2, ZERO, ONE); // if too many closing if(stacksize <= 0){ tag = rb_str_new2(""); //or close to be safe: tag = '/' << tag } else if (0 == rb_str_cmp(RARRAY_PTR()[stacksize - 1], tag)){ // found closing tag // if stacktop value == tag close value then pop // Close Tag tag = rb_str_append(rb_str_new2("</"), tag); rb_str_concat(tag, rb_str_new2(">")); // Pop rb_ary_pop(); stacksize--; } else { // closing tag not at top, search for it for(j=stacksize-1; j>=0; j--){ if(0 == rb_str_cmp(RARRAY_PTR()[j], tag) ){ // add tag to tagqueue for(k = stacksize-1;k>=j;k--){ rb_str_concat(tagqueue, rb_str_new2("</")); rb_str_concat(tagqueue, rb_ary_pop()); rb_str_concat(tagqueue, rb_str_new2(">")); stacksize--; } break; } } tag = rb_str_new2(""); } } else { // Begin Tag // Tag Cleaning if( ( RSTRING_LEN(attributes) > 0 && // test length before rb_str_substr (0 == rb_str_cmp(rb_str_substr(attributes, -1, 1), rb_str_new2("/"))) ) || (0 == rb_str_cmp(tag, rb_str_new2(""))) ){ // If: self-closing or '', don't do anything. } else if ( rb_ary_includes(single_tags, tag) ) { // ElseIf: it's a known single-entity tag but it doesn't close itself, do so rb_str_concat(attributes, rb_str_new2("/")); } else { // Push the tag onto the stack // If the top of the stack is the same as the tag we want // to push, close previous tag if ( (stacksize > 0) && (Qfalse == rb_ary_includes(nestable_tags, tag)) && (0 == rb_str_cmp(rb_ary_entry(tagstack, stacksize - 1), tag))){ tagqueue = rb_str_new2("</"); rb_str_concat(tagqueue, rb_ary_pop(tagstack)); rb_str_concat(tagqueue, rb_str_new2(">")); stacksize--; } rb_ary_push(tagstack, tag); stacksize++; } // Attributes if( 0 != rb_str_cmp(attributes, rb_str_new2("")) ){ attributes = rb_str_plus(rb_str_new2(" "), attributes); } tag = rb_str_plus(rb_str_new2("<"), tag); rb_str_concat(tag, attributes); rb_str_concat(tag, rb_str_new2(">")); //If already queuing a close tag, then put this tag on, too if( RSTRING_LEN(tagqueue) > 0 ){ rb_str_concat(tagqueue, tag); tag = rb_str_new2(""); } } rb_str_concat(newtext, rb_str_plus(rb_str_substr(text, 0, NUM2INT(pos)), tag)); text = rb_str_substr(text, NUM2INT(pos)+matchlen, RSTRING_LEN(text) - (NUM2INT(pos)+matchlen)); pos = rb_funcall(text, rb_intern("=~"), 1, tag_regex); done = (pos == Qnil); } // Clear Tag Queue rb_str_concat(newtext, tagqueue); // Add Remaining text rb_str_concat(newtext, text); i = NUM2INT(rb_funcall(tagstack, rb_intern("length"), 0)) - 1; // Empty Stack for(; i >= 0; i--){ // Add remaining tags to close t = RARRAY_PTR(tagstack)[i]; rb_str_concat(newtext, rb_str_new2("</")); rb_str_concat(newtext, t); rb_str_concat(newtext, rb_str_new2(">")); } // WP fix for the bug with HTML comments rb_funcall(newtext, rb_intern("gsub!"), 2, rb_str_new2("< !--"), rb_str_new2("<!--")); rb_funcall(newtext, rb_intern("gsub!"), 2, rb_str_new2("< !--"), rb_str_new2("< !--")); return newtext; } |
.delete_search_indexes ⇒ Object
Newly-converted logs are viewable in the Adium Chat Transcript Viewer, but are not indexed, so a search of the logs doesn’t give results from the converted logs. To fix this, we delete the cached log indexes, which forces Adium to re-index.
Note: This function is run by LogConverter after converting all of its files. LogFile.write_out intentionally does not run it in order to allow for batch-processing of files. Thus, you will probably want to run Pidgin2Adium.delete_search_indexes after running LogFile.write_out in your own scripts.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/pidgin2adium.rb', line 119 def delete_search_indexes() log_msg "Deleting log search indexes in order to force re-indexing of imported logs..." dirty_file = File.("~/Library/Caches/Adium/Default/DirtyLogs.plist") log_index_file = File.("~/Library/Caches/Adium/Default/Logs.index") [dirty_file, log_index_file].each do |f| if File.exist?(f) if File.writable?(f) File.delete(f) else error("File exists but is not writable. Please delete it yourself: #{f}") end end end log_msg "...done." log_msg "When you next start the Adium Chat Transcript Viewer, it will re-index the logs, which may take a while." end |
.error(str) ⇒ Object
:nodoc:
30 31 32 33 |
# File 'lib/pidgin2adium.rb', line 30 def error(str) #:nodoc: << str warn("Error: #{str}") end |
.log_msg(str) ⇒ Object
:nodoc:
21 22 23 |
# File 'lib/pidgin2adium.rb', line 21 def log_msg(str) #:nodoc: puts str.to_s end |
.oops(str) ⇒ Object
:nodoc:
25 26 27 28 |
# File 'lib/pidgin2adium.rb', line 25 def oops(str) #:nodoc: << str warn("Oops: #{str}") end |
.parse(logfile_path, my_aliases, force_conversion) ⇒ Object
Parses the provided log. Returns a LogFile instance or false if an error occurred.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/pidgin2adium.rb', line 42 def parse(logfile_path, my_aliases, force_conversion) logfile_path = File.(logfile_path) ext = File.extname(logfile_path).sub('.', '').downcase if(ext == "html" || ext == "htm") parser_class = HtmlLogParser elsif(ext == "txt") parser_class = TextLogParser else error("Doing nothing, logfile is not a text or html file. Path: #{logfile_path}.") return false end parser = parser_class.new(logfile_path, my_aliases, force_conversion) return parser.parse() end |
.parse_and_generate(logfile_path, my_aliases, opts = {}) ⇒ Object
Parses the provided log and writes out the log in Adium format. Returns:
* true if it successfully converted and wrote out the log,
* false if an error occurred, or
* Pidgin2Adium::FILE_EXISTS if file already exists AND
opts[:overwrite] = false.
You can add options using the opts hash, which can have the following keys, all of which are optional:
-
overwrite: If true, then overwrite even if log is found.
Defaults to false.
-
output_dir: The top-level dir to put the logs in. Logs under output_dir are still each in their own folders, etc. Defaults to Pidgin2Adium::ADIUM_LOG_DIR
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/pidgin2adium.rb', line 73 def parse_and_generate(logfile_path, my_aliases, opts = {}) opts = {} unless opts.is_a?(Hash) overwrite = !!opts[:overwrite] force_conversion = opts[:force_conversion] if opts.key?(:output_dir) output_dir = opts[:output_dir] else output_dir = ADIUM_LOG_DIR end unless File.directory?(output_dir) puts "Output log directory (#{output_dir}) does not exist or is not a directory." begin FileUtils.mkdir_p(output_dir) rescue Errno::EACCES puts "Permission denied, could not create output directory (#{output_dir})" return false end end logfile_obj = parse(logfile_path, my_aliases, force_conversion) return false if logfile_obj == false dest_file_path = logfile_obj.write_out(overwrite, output_dir) if dest_file_path == false error("Successfully parsed file, but failed to write it out. Path: #{logfile_path}.") return false elsif dest_file_path == FILE_EXISTS log_msg("File already exists.") return FILE_EXISTS else log_msg("Output to: #{dest_file_path}") return true end end |