Logo Search packages:      
Sourcecode: gajim version File versions  Download package

migrate_logs_to_dot9_db.py

#!/bin/sh
''':'
exec python -OOt "$0" ${1+"$@"}
' '''
## Contributors for this file:
## - Yann Le Boulanger <asterix@lagaule.org>
## - Nikos Kouremenos <kourem@gmail.com>
##
## Copyright (C) 2003-2004 Yann Le Boulanger <asterix@lagaule.org>
##                         Vincent Hanquez <tab@snarc.org>
## Copyright (C) 2005 Yann Le Boulanger <asterix@lagaule.org>
##                    Vincent Hanquez <tab@snarc.org>
##                    Nikos Kouremenos <nkour@jabber.org>
##                    Dimitur Kirov <dkirov@gmail.com>
##                    Travis Shirk <travis@pobox.com>
##                    Norman Rasmussen <norman@rasmussen.co.za>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published
## by the Free Software Foundation; version 2 only.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##

import os
import sre
import sys
import time
import signal
from common import logger
from common import i18n

_ = i18n._
try:
      PREFERRED_ENCODING = sys.getpreferredencoding()
except:
      PREFERRED_ENCODING = 'utf-8'
from common.helpers import from_one_line, decode_string

signal.signal(signal.SIGINT, signal.SIG_DFL) # ^C exits the application

from pysqlite2 import dbapi2 as sqlite

if os.name == 'nt':
      try:
            PATH_TO_LOGS_BASE_DIR = os.path.join(os.environ['appdata'], 'Gajim', 'Logs')
            PATH_TO_DB = os.path.join(os.environ['appdata'], 'Gajim', 'logs.db') # database is called logs.db
      except KeyError:
            # win9x
            PATH_TO_LOGS_BASE_DIR = '../src/Logs'
            PATH_TO_DB = '../src/logs.db'
else:
      PATH_TO_LOGS_BASE_DIR = os.path.expanduser('~/.gajim/logs')
      PATH_TO_DB = os.path.expanduser('~/.gajim/logs.db') # database is called logs.db



class Migration:
      def __init__(self):
            self.constants = logger.Constants()
            self.DONE = False
            self.PROCESSING = False

            if os.path.exists(PATH_TO_DB):
                  print '%s already exists. Exiting..' % PATH_TO_DB
                  sys.exit()

            self.jids_already_in = [] # jid we already put in DB

      def get_jid(self, dirname, filename):
            # jids.jid text column will be JID if TC-related, room_jid if GC-related,
            # ROOM_JID/nick if pm-related. Here I get names from filenames
            if dirname.endswith('logs') or dirname.endswith('Logs'):
                  # we have file (not dir) in logs base dir, so it's TC
                  jid = filename # file is JID
            else:
                  # we are in a room folder (so it can be either pm or message in room)
                  if filename == os.path.basename(dirname): # room/room
                        jid = dirname # filename is ROOM_JID
                  else: #room/nick it's pm
                        jid = dirname + '/' + filename

            if jid.startswith('/'):
                  p = len(PATH_TO_LOGS_BASE_DIR)
                  jid = jid[p+1:]
            jid = jid.lower()
            return jid

      def decode_jid(self, string):
            '''try to decode (to make it Unicode instance) given jid'''
            string = decode_string(string)
            if isinstance(string, str):
                  return None # decode failed
            return string

      def visit(self, arg, dirname, filenames):
            s = _('Visiting %s') % dirname
            if self.queue:
                  self.queue.put(s)
            else:
                  print s
            for filename in filenames:
                  # Don't take this file into account, this is dup info
                  # notifications are also in contact log file
                  if filename in ('notify.log', 'README'):
                        continue
                  path_to_text_file = os.path.join(dirname, filename)
                  if os.path.isdir(path_to_text_file):
                        continue

                  jid = self.get_jid(dirname, filename)

                  jid = self.decode_jid(jid)
                  if not jid:
                        continue

                  if filename == os.path.basename(dirname): # gajim@conf/gajim@conf then gajim@conf is type room
                        jid_type = self.constants.JID_ROOM_TYPE
                        #Type of log
                        typ = 'room'
                  else:
                        jid_type = self.constants.JID_NORMAL_TYPE
                        #Type of log
                        typ = _('normal')
                  s = _('Processing %s of type %s') % (jid, typ)
                  if self.queue:
                        self.queue.put(s.encode(PREFERRED_ENCODING))
                  else:
                        print s.encode(PREFERRED_ENCODING)

                  JID_ID = None
                  f = open(path_to_text_file, 'r')
                  lines = f.readlines()
                  for line in lines:
                        line = from_one_line(line)
                        splitted_line = line.split(':')
                        if len(splitted_line) > 2:
                              # type in logs is one of 
                              # 'gc', 'gcstatus', 'recv', 'sent' and if nothing of those
                              # it is status
                              # new db has:
                              # status, gcstatus, gc_msg, (we only recv those 3),
                              # single_msg_recv, chat_msg_recv, chat_msg_sent, single_msg_sent
                              # to meet all our needs
                              # here I convert
                              # gc ==> gc_msg, gcstatus ==> gcstatus, recv ==> chat_msg_recv
                              # sent ==> chat_msg_sent, status ==> status
                              typ = splitted_line[1] # line[1] has type of logged message
                              message_data = splitted_line[2:] # line[2:] has message data
                              # line[0] is date,
                              # some lines can be fucked up, just drop them
                              try:
                                    tim = int(float(splitted_line[0]))
                              except:
                                    continue

                              contact_name = None
                              show = None
                              if typ == 'gc':
                                    contact_name = message_data[0]
                                    message = ':'.join(message_data[1:])
                                    kind = self.constants.KIND_GC_MSG
                              elif typ == 'gcstatus':
                                    contact_name = message_data[0]
                                    show = message_data[1]
                                    message = ':'.join(message_data[2:]) # status msg
                                    kind = self.constants.KIND_GCSTATUS
                              elif typ == 'recv':
                                    message = ':'.join(message_data[0:])
                                    kind = self.constants.KIND_CHAT_MSG_RECV
                              elif typ == 'sent':
                                    message = ':'.join(message_data[0:])
                                    kind = self.constants.KIND_CHAT_MSG_SENT
                              else: # status
                                    kind = self.constants.KIND_STATUS
                                    show = message_data[0]
                                    message = ':'.join(message_data[1:]) # status msg

                              message = message[:-1] # remove last \n
                              if not message:
                                    continue

                              # jid is already in the DB, don't create a new row, just get his jid_id
                              if not JID_ID:
                                    if jid in self.jids_already_in:
                                          self.cur.execute('SELECT jid_id FROM jids WHERE jid = "%s"' % jid)
                                          JID_ID = self.cur.fetchone()[0]
                                    else:
                                          self.jids_already_in.append(jid)
                                          self.cur.execute('INSERT INTO jids (jid, type) VALUES (?, ?)',
                                                (jid, jid_type))
                                          self.con.commit()
                                          JID_ID = self.cur.lastrowid

                              sql = 'INSERT INTO logs (jid_id, contact_name, time, kind, show, message) '\
                                    'VALUES (?, ?, ?, ?, ?, ?)'

                              values = (JID_ID, contact_name, tim, kind, show, message)
                              self.cur.execute(sql, values)
                  self.con.commit()

      def migrate(self, queue = None):
            self.queue = queue
            self.con = sqlite.connect(PATH_TO_DB) 
            os.chmod(PATH_TO_DB, 0600) # rw only for us
            self.cur = self.con.cursor()
            # create the tables
            # kind can be
            # status, gcstatus, gc_msg, (we only recv for those 3),
            # single_msg_recv, chat_msg_recv, chat_msg_sent, single_msg_sent
            # to meet all our needs
            # logs.jid_id --> jids.jid_id but Sqlite doesn't do FK etc so it's done in python code
            self.cur.executescript(
                  '''
                  CREATE TABLE jids(
                        jid_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
                        jid TEXT UNIQUE,
                        type INTEGER
                  );

                  CREATE TABLE unread_messages(
                        message_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
                        jid_id INTEGER
                  );
                  
                  CREATE TABLE logs(
                        log_line_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
                        jid_id INTEGER,
                        contact_name TEXT,
                        time INTEGER,
                        kind INTEGER,
                        show INTEGER,
                        message TEXT,
                        subject TEXT
                  );
                  '''
            )

            self.con.commit()

            self.PROCESSING = True
            os.path.walk(PATH_TO_LOGS_BASE_DIR, self.visit, None)
            s = '''

We do not use plain-text files anymore, because they do not meet our needs.
Those files here are logs for Gajim up until 0.8.2
We now use an sqlite database called logs.db found in %s
You can now safely remove your %s folder
Thank you''' % (os.path.dirname(PATH_TO_LOGS_BASE_DIR), PATH_TO_LOGS_BASE_DIR)
            f = open(os.path.join(PATH_TO_LOGS_BASE_DIR, 'README'), 'w')
            f.write(s)
            f.close()
            if queue:
                  queue.put(s)
            self.DONE = True

if __name__ == '__main__':
      # magic argumen 'dont_wait' tells us that script is run from Gajim
      if len(sys.argv) < 2 or sys.argv[1] != 'dont_wait':
            print 'IMPORTNANT: PLEASE READ http://trac.gajim.org/wiki/MigrateLogToDot9DB'
            print 'Migration will start in 40 seconds unless you press Ctrl+C'
            time.sleep(40) # give the user time to act
            print
            print 'Starting Logs Migration'
            print '======================='
            print 'Please do NOT run Gajim until this script is over'
      m = Migration()
      m.migrate()

Generated by  Doxygen 1.6.0   Back to index