#!/usr/bin/python3 # This isn't a completely working script yet, the framework is there # This script interactively renames gaim logs based on a regex in the first line # It is useful if you have a bunch of gaim logs not in their regular dirs # for eg: if you accidentally deleted them and used an undelete program # It will need customisation for your needs import os import re import sys # Requires urwid: http://urwid.org/ import urwid import urwid.curses_display class GaimLogRenamer: text_regex = re.compile(r'^Conversation with ([^ /]*)[^ ]* at ([^-]*)-([^-]*)-([^ ]*) ([^:]*):([^:]*):([^ ]*) on ([^ /]*)[^ ]* \(([^)]*)\).*$') html_regex = re.compile(r'^.*Conversation with ([^ /]*)[^ ]* at ([^-]*)-([^-]*)-([^ ]*) ([^:]*):([^:]*):([^ ]*) on ([^ /]*)[^ ]* \(([^)]*)\).*') root = '/home/pabs/chat/im-recovery/logs' compare = '/usr/bin/meld' interactive = 0 skip_broken = 0 def __init__(self): if sys.stdout.isatty(): self.interactive = 1 if self.interactive: self.banner = urwid.Text( ('banner', "pabs' mass gaim chat file renamer"), align="center") self.stats_text = urwid.Text( ('stats', 'STATS GO HERE'), align="center" ) self.stats = urwid.AttrWrap( self.stats_text, 'stats' ) self.keys_text = urwid.Text( ('keys', 'q = quit n = next r = rename d = delete'), align="center" ) self.keys = urwid.AttrWrap( self.keys_text, 'keys' ) self.dir_text = urwid.Text( ('dir', 'DIR GOES HERE'), align="center" ) self.dir = urwid.AttrWrap( self.dir_text, 'dir' ) self.files_text = urwid.Text( ('files', 'FILES GO HERE'), align="center" ) self.files = urwid.AttrWrap( self.files_text, 'files' ) self.file_text = urwid.Text( ('file', 'FILE GOES HERE'), align="center" ) self.file = urwid.AttrWrap( self.file_text, 'file' ) self.suggest_text = urwid.Text( ('suggest', 'FILE GOES HERE'), align="center" ) self.suggest = urwid.AttrWrap( self.suggest_text, 'suggest' ) self.warning_text = urwid.Text( ('warning', 'FILE GOES HERE'), align="center" ) self.warning = urwid.AttrWrap( self.warning_text, 'warning' ) self.view_text = urwid.Text( ('view', 'VIEW GOES HERE'), align="left" ) self.view = urwid.AttrWrap( self.view_text, 'view' ) self.items = [ self.keys, self.stats, self.dir, self.files, self.file, self.suggest, self.warning, self.view ] self.listbox = urwid.ListBox( self.items ) self.header = urwid.AttrWrap( self.banner, 'banner' ) self.top = urwid.Frame(self.listbox, self.header) def main(self): if self.interactive: self.ui = urwid.curses_display.Screen() self.ui.register_palette([ ('banner', 'black', 'dark cyan', 'standout'), ('keys', 'black', 'dark green', 'standout'), ('stats', 'black', 'dark cyan', 'standout'), ('dir', 'black', 'dark red', 'standout'), ('files', 'black', 'dark red', 'standout'), ('file', 'black', 'light gray', 'standout'), ('suggest', 'black', 'light gray', 'standout'), ('warning', 'black', 'dark red', 'standout'), ('view', 'black', 'dark cyan', 'standout'), ]) self.ui.run_wrapper( self.run ) else: self.run() def run(self): if self.interactive: self.size = self.ui.get_cols_rows() for root, dirs, files in os.walk(self.root): if self.interactive: sizes = map(lambda x: os.path.getsize('%s/%s' % (root, x)), files) text = "%s bytes in %s files" % (sum(sizes), len(files)) self.dir_text.set_text( root ) self.stats_text.set_text( text ) self.files_text.set_text( ' '.join(files) ) if len(files): for fn in files: if self.interactive: full_name = "%s/%s" % (root, fn) self.file_text.set_text( full_name ) ret = self.suggest_name( full_name ) self.suggest_text.set_text( ret[1] ) self.warning_text.set_text( ret[0] ) # FIXME: add an edit box if ret[0] == '' or not self.skip_broken: ret = self.process_events() if ret == 'quit': return else: f = "%s/%s" % (root, fn) ret = self.suggest_name(f) print("%s: %s %s" % ( ret[0], f, ret[1] )) def suggest_name(self, name): # Read the first line f = open( name, 'r' ) firstline = f.readline() f.close() warning = '' # Test if the file contains NUL bytes f = open( name, 'rb' ) d = f.read() f.close() if d.find('\x00') >= 0: warning += 'contains NUL! ' # Check if the first line matches a text or html regex m = self.html_regex.match(firstline) if m: ext = 'html' last_line = "\n" if d[-len(last_line):] != last_line: warning += 'malformed html! ' else: ext = 'txt' m = self.text_regex.match(firstline) if not m: return ('no match','') # Get the matches g = list(m.groups()) if len(g) != 9: return ('not enough matches: '+str(len(g)), '') # Some old files missy the account name if g[7] == '': # FIXME: distinguish between multiple accounts if g[8] == 'icq': g[7] = '270582044' elif g[8] == 'msn': g[7] = 'pabs3@hotmail.com' elif g[8] == 'yahoo': g[7] = 'pabsness slashdotaccount' elif g[8] == 'jabber': g[7] = 'pabs@jabber.org pabs@jabber.org.au paul.is.wise@gmail.com' # Some old files have S in place of seconds if g[6] == 'S': g[6] = '00' # Validate the matches if g[8] not in ('icq', 'msn', 'yahoo', 'jabber'): warning += 'wrong proto: %s ' % g[8] if len(g[1]) != 4: warning += 'wrong len(4): m1 ' for i in range(2,6): if len(g[i]) != 2: warning += 'wrong len(2): m%s ' %i return (warning, "/home/pabs/.purple/logs/%s/%s/%s/%s-%s-%s.%s%s%s.%s" % ( g[8], g[7], g[0], g[1], g[2], g[3], g[4], g[5], g[6], ext) ) def process_events(self): cont = True while cont: self.draw_screen( self.size ) keys = self.ui.get_input() if "n" in keys: cont = False for k in keys: if k == "window resize": self.size = self.ui.get_cols_rows() continue elif k == 'q': return 'quit' elif k == 'r': old = os.path.join( self.dir_text.get_text()[0], self.file_text.get_text()[0] ) new = self.suggest_text.get_text()[0] if os.path.exists( new ): os.spawnv(os.P_WAIT, self.compare, [self.compare, old, new]) #raise NameError, "file exists: meld '%s' '%s'\nrm -f '%s'" % (new, old, old) else: #raise NameError, 'os.rename %s %s %s %s' % (old, new, os.path.exists(old), os.path.exists(new) ) try: os.makedirs( os.path.dirname( new ) ) except: # We don't care if the new directory is already there pass os.rename( old, new ) cont = False elif k == 'd': old = os.path.join( self.dir_text.get_text()[0], self.file_text.get_text()[0] ) os.remove( old ) cont = False self.top.keypress( self.size, k ) def draw_screen(self, size): canvas = self.top.render( size, focus=True ) self.ui.draw_screen( size, canvas ) GaimLogRenamer().main()