2005-05-12 15:43:17 +02:00
|
|
|
## logger.py
|
2003-11-30 17:02:00 +01:00
|
|
|
##
|
2006-10-06 00:50:52 +02:00
|
|
|
## Copyright (C) 2005-2006 Nikos Kouremenos <kourem@gmail.com>
|
2006-10-06 00:49:28 +02:00
|
|
|
## Copyright (C) 2005-2006 Yann Le Boulanger <asterix@lagaule.org>
|
2003-11-30 17:02:00 +01:00
|
|
|
##
|
|
|
|
## 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
|
2005-11-23 20:12:52 +01:00
|
|
|
import sys
|
2003-11-30 17:02:00 +01:00
|
|
|
import time
|
2005-11-23 20:12:52 +01:00
|
|
|
import datetime
|
2005-08-25 18:50:02 +02:00
|
|
|
|
2005-12-05 12:13:08 +01:00
|
|
|
import exceptions
|
2006-06-04 11:54:11 +02:00
|
|
|
import gajim
|
|
|
|
|
2005-11-23 20:12:52 +01:00
|
|
|
try:
|
|
|
|
from pysqlite2 import dbapi2 as sqlite
|
|
|
|
except ImportError:
|
2005-12-01 18:16:53 +01:00
|
|
|
raise exceptions.PysqliteNotAvailable
|
|
|
|
|
2005-11-23 20:12:52 +01:00
|
|
|
if os.name == 'nt':
|
|
|
|
try:
|
|
|
|
# Documents and Settings\[User Name]\Application Data\Gajim\logs.db
|
|
|
|
LOG_DB_PATH = os.path.join(os.environ['appdata'], 'Gajim', 'logs.db')
|
|
|
|
except KeyError:
|
|
|
|
# win9x, ./logs.db
|
|
|
|
LOG_DB_PATH = 'logs.db'
|
|
|
|
else: # Unices
|
|
|
|
LOG_DB_PATH = os.path.expanduser('~/.gajim/logs.db')
|
|
|
|
|
|
|
|
try:
|
|
|
|
LOG_DB_PATH = LOG_DB_PATH.decode(sys.getfilesystemencoding())
|
|
|
|
except:
|
|
|
|
pass
|
2005-09-02 23:45:35 +02:00
|
|
|
|
2005-11-26 00:23:25 +01:00
|
|
|
class Constants:
|
|
|
|
def __init__(self):
|
|
|
|
(
|
|
|
|
self.JID_NORMAL_TYPE,
|
2005-11-30 15:16:26 +01:00
|
|
|
self.JID_ROOM_TYPE
|
2005-11-26 00:23:25 +01:00
|
|
|
) = range(2)
|
|
|
|
|
|
|
|
(
|
|
|
|
self.KIND_STATUS,
|
|
|
|
self.KIND_GCSTATUS,
|
|
|
|
self.KIND_GC_MSG,
|
|
|
|
self.KIND_SINGLE_MSG_RECV,
|
|
|
|
self.KIND_CHAT_MSG_RECV,
|
|
|
|
self.KIND_SINGLE_MSG_SENT,
|
2006-04-10 16:00:04 +02:00
|
|
|
self.KIND_CHAT_MSG_SENT,
|
|
|
|
self.KIND_ERROR
|
|
|
|
) = range(8)
|
2005-11-26 00:23:25 +01:00
|
|
|
|
|
|
|
(
|
|
|
|
self.SHOW_ONLINE,
|
|
|
|
self.SHOW_CHAT,
|
|
|
|
self.SHOW_AWAY,
|
|
|
|
self.SHOW_XA,
|
|
|
|
self.SHOW_DND,
|
|
|
|
self.SHOW_OFFLINE
|
|
|
|
) = range(6)
|
|
|
|
|
2006-07-30 00:29:59 +02:00
|
|
|
(
|
|
|
|
self.TYPE_AIM,
|
|
|
|
self.TYPE_GG,
|
|
|
|
self.TYPE_HTTP_WS,
|
|
|
|
self.TYPE_ICQ,
|
|
|
|
self.TYPE_MSN,
|
|
|
|
self.TYPE_QQ,
|
|
|
|
self.TYPE_SMS,
|
|
|
|
self.TYPE_SMTP,
|
|
|
|
self.TYPE_TLEN,
|
|
|
|
self.TYPE_YAHOO,
|
|
|
|
self.TYPE_NEWMAIL,
|
|
|
|
self.TYPE_RSS,
|
|
|
|
self.TYPE_WEATHER,
|
|
|
|
) = range(13)
|
|
|
|
|
2005-11-26 00:23:25 +01:00
|
|
|
constants = Constants()
|
2005-11-24 19:29:45 +01:00
|
|
|
|
2005-04-16 00:02:13 +02:00
|
|
|
class Logger:
|
|
|
|
def __init__(self):
|
2005-12-05 14:56:02 +01:00
|
|
|
self.jids_already_in = [] # holds jids that we already have in DB
|
2006-07-31 09:45:29 +02:00
|
|
|
self.con = None
|
|
|
|
|
2005-11-23 20:12:52 +01:00
|
|
|
if not os.path.exists(LOG_DB_PATH):
|
|
|
|
# this can happen only the first time (the time we create the db)
|
2005-11-26 00:23:25 +01:00
|
|
|
# db is not created here but in src/common/checks_paths.py
|
2005-11-23 20:12:52 +01:00
|
|
|
return
|
2005-12-08 10:46:59 +01:00
|
|
|
self.init_vars()
|
2006-07-31 09:45:29 +02:00
|
|
|
|
2005-12-08 10:46:59 +01:00
|
|
|
def init_vars(self):
|
2005-11-27 13:22:07 +01:00
|
|
|
# if locked, wait up to 20 sec to unlock
|
|
|
|
# before raise (hopefully should be enough)
|
2006-07-31 09:45:29 +02:00
|
|
|
if self.con:
|
|
|
|
self.con.close()
|
2005-12-05 18:22:50 +01:00
|
|
|
self.con = sqlite.connect(LOG_DB_PATH, timeout = 20.0,
|
2005-11-27 13:22:07 +01:00
|
|
|
isolation_level = 'IMMEDIATE')
|
2005-12-05 18:22:50 +01:00
|
|
|
self.cur = self.con.cursor()
|
2006-07-31 09:45:29 +02:00
|
|
|
|
2005-11-23 20:12:52 +01:00
|
|
|
self.get_jids_already_in_db()
|
2005-07-02 01:13:46 +02:00
|
|
|
|
2005-11-23 20:12:52 +01:00
|
|
|
def get_jids_already_in_db(self):
|
2005-12-05 18:22:50 +01:00
|
|
|
self.cur.execute('SELECT jid FROM jids')
|
2006-02-03 00:44:09 +01:00
|
|
|
rows = self.cur.fetchall() # list of tupples: [(u'aaa@bbb',), (u'cc@dd',)]
|
2006-07-31 09:45:29 +02:00
|
|
|
self.jids_already_in = []
|
2005-11-23 20:12:52 +01:00
|
|
|
for row in rows:
|
|
|
|
# row[0] is first item of row (the only result here, the jid)
|
|
|
|
self.jids_already_in.append(row[0])
|
|
|
|
|
2005-11-26 00:23:25 +01:00
|
|
|
def jid_is_from_pm(self, jid):
|
2005-11-23 20:12:52 +01:00
|
|
|
'''if jid is gajim@conf/nkour it's likely a pm one, how we know
|
|
|
|
gajim@conf is not a normal guy and nkour is not his resource?
|
2005-11-26 00:23:25 +01:00
|
|
|
we ask if gajim@conf is already in jids (with type room jid)
|
|
|
|
this fails if user disables logging for room and only enables for
|
|
|
|
pm (so higly unlikely) and if we fail we do not go chaos
|
|
|
|
(user will see the first pm as if it was message in room's public chat)
|
|
|
|
and after that all okay'''
|
2005-11-23 20:12:52 +01:00
|
|
|
|
|
|
|
possible_room_jid, possible_nick = jid.split('/', 1)
|
2006-10-06 00:49:28 +02:00
|
|
|
return self.jid_is_room_jid(possible_room_jid)
|
2006-03-24 19:46:48 +01:00
|
|
|
|
2006-10-06 00:49:28 +02:00
|
|
|
def jid_is_room_jid(self, jid):
|
2006-04-19 12:36:45 +02:00
|
|
|
self.cur.execute('SELECT jid_id FROM jids WHERE jid=? AND type=?',
|
2006-10-06 09:03:08 +02:00
|
|
|
(jid, constants.JID_ROOM_TYPE))
|
2005-12-05 18:22:50 +01:00
|
|
|
row = self.cur.fetchone()
|
2006-04-09 21:08:57 +02:00
|
|
|
if row is None:
|
2005-11-23 20:12:52 +01:00
|
|
|
return False
|
2006-04-09 21:08:57 +02:00
|
|
|
else:
|
|
|
|
return True
|
2005-11-23 20:12:52 +01:00
|
|
|
|
2005-11-26 01:03:09 +01:00
|
|
|
def get_jid_id(self, jid, typestr = None):
|
2005-11-23 20:12:52 +01:00
|
|
|
'''jids table has jid and jid_id
|
|
|
|
logs table has log_id, jid_id, contact_name, time, kind, show, message
|
|
|
|
so to ask logs we need jid_id that matches our jid in jids table
|
2006-02-06 21:34:06 +01:00
|
|
|
this method wants jid and returns the jid_id for later sql-ing on logs
|
2006-02-03 00:44:09 +01:00
|
|
|
typestr can be 'ROOM' or anything else depending on the type of JID
|
|
|
|
and is only needed to be specified when the JID is new in DB
|
2005-11-23 20:12:52 +01:00
|
|
|
'''
|
2005-11-24 19:29:45 +01:00
|
|
|
if jid.find('/') != -1: # if it has a /
|
2005-11-26 01:03:09 +01:00
|
|
|
jid_is_from_pm = self.jid_is_from_pm(jid)
|
|
|
|
if not jid_is_from_pm: # it's normal jid with resource
|
2005-11-24 19:29:45 +01:00
|
|
|
jid = jid.split('/', 1)[0] # remove the resource
|
2005-11-23 20:12:52 +01:00
|
|
|
if jid in self.jids_already_in: # we already have jids in DB
|
2006-04-19 12:36:45 +02:00
|
|
|
self.cur.execute('SELECT jid_id FROM jids WHERE jid=?', [jid])
|
2005-12-05 18:22:50 +01:00
|
|
|
jid_id = self.cur.fetchone()[0]
|
2005-11-26 00:23:25 +01:00
|
|
|
else: # oh! a new jid :), we add it now
|
2005-11-26 01:03:09 +01:00
|
|
|
if typestr == 'ROOM':
|
|
|
|
typ = constants.JID_ROOM_TYPE
|
|
|
|
else:
|
|
|
|
typ = constants.JID_NORMAL_TYPE
|
2005-12-05 18:22:50 +01:00
|
|
|
self.cur.execute('INSERT INTO jids (jid, type) VALUES (?, ?)', (jid, typ))
|
2005-11-26 16:21:52 +01:00
|
|
|
try:
|
2005-12-05 18:22:50 +01:00
|
|
|
self.con.commit()
|
2005-11-26 16:21:52 +01:00
|
|
|
except sqlite.OperationalError, e:
|
2005-11-29 19:31:45 +01:00
|
|
|
print >> sys.stderr, str(e)
|
2005-12-05 18:22:50 +01:00
|
|
|
jid_id = self.cur.lastrowid
|
2005-11-23 20:12:52 +01:00
|
|
|
self.jids_already_in.append(jid)
|
|
|
|
return jid_id
|
|
|
|
|
2005-11-26 00:23:25 +01:00
|
|
|
def convert_human_values_to_db_api_values(self, kind, show):
|
|
|
|
'''coverts from string style to constant ints for db'''
|
|
|
|
if kind == 'status':
|
|
|
|
kind_col = constants.KIND_STATUS
|
|
|
|
elif kind == 'gcstatus':
|
|
|
|
kind_col = constants.KIND_GCSTATUS
|
|
|
|
elif kind == 'gc_msg':
|
|
|
|
kind_col = constants.KIND_GC_MSG
|
|
|
|
elif kind == 'single_msg_recv':
|
|
|
|
kind_col = constants.KIND_SINGLE_MSG_RECV
|
|
|
|
elif kind == 'single_msg_sent':
|
|
|
|
kind_col = constants.KIND_SINGLE_MSG_SENT
|
|
|
|
elif kind == 'chat_msg_recv':
|
|
|
|
kind_col = constants.KIND_CHAT_MSG_RECV
|
|
|
|
elif kind == 'chat_msg_sent':
|
|
|
|
kind_col = constants.KIND_CHAT_MSG_SENT
|
2006-04-10 16:00:04 +02:00
|
|
|
elif kind == 'error':
|
|
|
|
kind_col = constants.KIND_ERROR
|
2005-11-28 17:41:34 +01:00
|
|
|
|
2005-11-26 00:23:25 +01:00
|
|
|
if show == 'online':
|
|
|
|
show_col = constants.SHOW_ONLINE
|
|
|
|
elif show == 'chat':
|
|
|
|
show_col = constants.SHOW_CHAT
|
|
|
|
elif show == 'away':
|
|
|
|
show_col = constants.SHOW_AWAY
|
|
|
|
elif show == 'xa':
|
|
|
|
show_col = constants.SHOW_XA
|
|
|
|
elif show == 'dnd':
|
|
|
|
show_col = constants.SHOW_DND
|
|
|
|
elif show == 'offline':
|
|
|
|
show_col = constants.SHOW_OFFLINE
|
2005-11-28 18:56:57 +01:00
|
|
|
elif show is None:
|
|
|
|
show_col = None
|
2005-11-28 18:34:43 +01:00
|
|
|
else: # invisible in GC when someone goes invisible
|
|
|
|
# it's a RFC violation .... but we should not crash
|
|
|
|
show_col = 'UNKNOWN'
|
2005-11-26 00:23:25 +01:00
|
|
|
|
|
|
|
return kind_col, show_col
|
2006-07-30 00:29:59 +02:00
|
|
|
|
|
|
|
def convert_human_transport_type_to_db_api_values(self, type_):
|
|
|
|
'''converts from string style to constant ints for db'''
|
|
|
|
if type_ == 'aim':
|
|
|
|
return constants.TYPE_AIM
|
|
|
|
if type_ == 'gadu-gadu':
|
|
|
|
return constants.TYPE_GG
|
|
|
|
if type_ == 'http-ws':
|
|
|
|
return constants.TYPE_HTTP_WS
|
|
|
|
if type_ == 'icq':
|
|
|
|
return constants.TYPE_ICQ
|
|
|
|
if type_ == 'msn':
|
|
|
|
return constants.TYPE_MSN
|
|
|
|
if type_ == 'qq':
|
|
|
|
return constants.TYPE_QQ
|
|
|
|
if type_ == 'sms':
|
|
|
|
return constants.TYPE_SMS
|
|
|
|
if type_ == 'smtp':
|
|
|
|
return constants.TYPE_SMTP
|
|
|
|
if type_ == 'tlen':
|
|
|
|
return constants.TYPE_TLEN
|
|
|
|
if type_ == 'yahoo':
|
|
|
|
return constants.TYPE_YAHOO
|
|
|
|
if type_ == 'newmail':
|
|
|
|
return constants.TYPE_NEWMAIL
|
|
|
|
if type_ == 'rss':
|
|
|
|
return constants.TYPE_RSS
|
|
|
|
if type_ == 'weather':
|
|
|
|
return constants.TYPE_WEATHER
|
|
|
|
return None
|
|
|
|
|
|
|
|
def convert_api_values_to_human_transport_type(self, type_id):
|
|
|
|
'''converts from constant ints for db to string style'''
|
|
|
|
if type_id == constants.TYPE_AIM:
|
|
|
|
return 'aim'
|
|
|
|
if type_id == constants.TYPE_GG:
|
|
|
|
return 'gadu-gadu'
|
|
|
|
if type_id == constants.TYPE_HTTP_WS:
|
|
|
|
return 'http-ws'
|
|
|
|
if type_id == constants.TYPE_ICQ:
|
|
|
|
return 'icq'
|
|
|
|
if type_id == constants.TYPE_MSN:
|
|
|
|
return 'msn'
|
|
|
|
if type_id == constants.TYPE_QQ:
|
|
|
|
return 'qq'
|
|
|
|
if type_id == constants.TYPE_SMS:
|
|
|
|
return 'sms'
|
|
|
|
if type_id == constants.TYPE_SMTP:
|
|
|
|
return 'smtp'
|
|
|
|
if type_id == constants.TYPE_TLEN:
|
|
|
|
return 'tlen'
|
|
|
|
if type_id == constants.TYPE_YAHOO:
|
|
|
|
return 'yahoo'
|
|
|
|
if type_id == constants.TYPE_NEWMAIL:
|
|
|
|
return 'newmail'
|
|
|
|
if type_id == constants.TYPE_RSS:
|
|
|
|
return 'rss'
|
|
|
|
if type_id == constants.TYPE_WEATHER:
|
|
|
|
return 'weather'
|
|
|
|
|
2006-04-11 00:08:02 +02:00
|
|
|
def commit_to_db(self, values, write_unread = False):
|
2005-11-26 00:23:25 +01:00
|
|
|
#print 'saving', values
|
2005-11-26 16:21:52 +01:00
|
|
|
sql = 'INSERT INTO logs (jid_id, contact_name, time, kind, show, message, subject) VALUES (?, ?, ?, ?, ?, ?, ?)'
|
2005-12-05 18:22:50 +01:00
|
|
|
self.cur.execute(sql, values)
|
2006-04-11 00:08:02 +02:00
|
|
|
message_id = None
|
|
|
|
try:
|
|
|
|
self.con.commit()
|
|
|
|
if write_unread:
|
|
|
|
message_id = self.cur.lastrowid
|
|
|
|
except sqlite.OperationalError, e:
|
|
|
|
print >> sys.stderr, str(e)
|
|
|
|
if message_id:
|
2006-04-11 13:28:36 +02:00
|
|
|
self.insert_unread_events(message_id, values[0])
|
2006-04-11 00:08:02 +02:00
|
|
|
return message_id
|
|
|
|
|
2006-04-11 13:28:36 +02:00
|
|
|
def insert_unread_events(self, message_id, jid_id):
|
2006-04-11 00:08:02 +02:00
|
|
|
''' add unread message with id: message_id'''
|
2006-04-11 13:28:36 +02:00
|
|
|
sql = 'INSERT INTO unread_messages VALUES (%d, %d)' % (message_id, jid_id)
|
2006-04-11 00:08:02 +02:00
|
|
|
self.cur.execute(sql)
|
|
|
|
try:
|
|
|
|
self.con.commit()
|
|
|
|
except sqlite.OperationalError, e:
|
|
|
|
print >> sys.stderr, str(e)
|
|
|
|
|
|
|
|
def set_read_messages(self, message_ids):
|
|
|
|
''' mark all messages with ids in message_ids as read'''
|
|
|
|
ids = ','.join([str(i) for i in message_ids])
|
|
|
|
sql = 'DELETE FROM unread_messages WHERE message_id IN (%s)' % ids
|
|
|
|
self.cur.execute(sql)
|
2005-11-26 16:21:52 +01:00
|
|
|
try:
|
2005-12-05 18:22:50 +01:00
|
|
|
self.con.commit()
|
2005-11-26 16:21:52 +01:00
|
|
|
except sqlite.OperationalError, e:
|
2005-11-29 19:31:45 +01:00
|
|
|
print >> sys.stderr, str(e)
|
2005-11-26 00:23:25 +01:00
|
|
|
|
2006-04-11 01:06:11 +02:00
|
|
|
def get_unread_msgs_for_jid(self, jid):
|
2006-04-11 00:36:55 +02:00
|
|
|
''' get unread messages for jid '''
|
|
|
|
if not jid:
|
|
|
|
return
|
|
|
|
jid = jid.lower()
|
|
|
|
jid_id = self.get_jid_id(jid)
|
2006-04-11 13:28:36 +02:00
|
|
|
all_messages = []
|
2006-04-19 12:28:42 +02:00
|
|
|
try:
|
|
|
|
self.cur.execute(
|
|
|
|
'SELECT message_id from unread_messages WHERE jid_id = %d' % jid_id)
|
|
|
|
results = self.cur.fetchall()
|
|
|
|
except:
|
2006-07-28 18:15:18 +02:00
|
|
|
pass
|
2006-04-19 12:28:42 +02:00
|
|
|
|
2006-04-11 13:28:36 +02:00
|
|
|
for message in results:
|
|
|
|
msg_id = message[0]
|
|
|
|
self.cur.execute('''
|
|
|
|
SELECT log_line_id, message, time, subject FROM logs
|
|
|
|
WHERE jid_id = %d AND log_line_id = %d
|
|
|
|
''' % (jid_id, msg_id)
|
|
|
|
)
|
|
|
|
results = self.cur.fetchall()
|
|
|
|
all_messages.append(results[0])
|
|
|
|
return all_messages
|
2006-04-11 00:36:55 +02:00
|
|
|
|
2006-04-09 21:46:11 +02:00
|
|
|
def write(self, kind, jid, message = None, show = None, tim = None,
|
|
|
|
subject = None):
|
2005-11-23 20:12:52 +01:00
|
|
|
'''write a row (status, gcstatus, message etc) to logs database
|
|
|
|
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
|
|
|
|
we cannot know if it is pm or normal chat message, we try to guess
|
2005-11-26 00:23:25 +01:00
|
|
|
see jid_is_from_pm() which is called by get_jid_id()
|
2005-11-23 20:12:52 +01:00
|
|
|
|
|
|
|
we analyze jid and store it as follows:
|
|
|
|
jids.jid text column will hold JID if TC-related, room_jid if GC-related,
|
|
|
|
ROOM_JID/nick if pm-related.'''
|
2005-11-24 19:29:45 +01:00
|
|
|
|
2005-12-05 14:56:02 +01:00
|
|
|
if self.jids_already_in == []: # only happens if we just created the db
|
2005-12-05 18:22:50 +01:00
|
|
|
self.con = sqlite.connect(LOG_DB_PATH, timeout = 20.0,
|
2005-11-27 13:22:07 +01:00
|
|
|
isolation_level = 'IMMEDIATE')
|
2005-12-05 18:22:50 +01:00
|
|
|
self.cur = self.con.cursor()
|
2005-11-24 19:29:45 +01:00
|
|
|
|
2005-11-03 09:50:35 +01:00
|
|
|
jid = jid.lower()
|
2005-11-23 20:12:52 +01:00
|
|
|
contact_name_col = None # holds nickname for kinds gcstatus, gc_msg
|
|
|
|
# message holds the message unless kind is status or gcstatus,
|
|
|
|
# then it holds status message
|
|
|
|
message_col = message
|
2005-11-26 00:23:25 +01:00
|
|
|
subject_col = subject
|
2005-11-23 20:12:52 +01:00
|
|
|
if tim:
|
|
|
|
time_col = int(float(time.mktime(tim)))
|
2005-04-16 00:02:13 +02:00
|
|
|
else:
|
2005-11-23 20:12:52 +01:00
|
|
|
time_col = int(float(time.time()))
|
|
|
|
|
2005-11-26 01:03:09 +01:00
|
|
|
kind_col, show_col = self.convert_human_values_to_db_api_values(kind,
|
|
|
|
show)
|
2006-04-11 00:08:02 +02:00
|
|
|
|
|
|
|
write_unread = False
|
|
|
|
|
2005-11-26 00:23:25 +01:00
|
|
|
# now we may have need to do extra care for some values in columns
|
2005-11-23 20:12:52 +01:00
|
|
|
if kind == 'status': # we store (not None) time, jid, show, msg
|
|
|
|
# status for roster items
|
2005-11-26 01:03:09 +01:00
|
|
|
jid_id = self.get_jid_id(jid)
|
2005-11-28 18:34:43 +01:00
|
|
|
if show is None: # show is None (xmpp), but we say that 'online'
|
|
|
|
show_col = constants.SHOW_ONLINE
|
2005-07-21 23:39:47 +02:00
|
|
|
|
2005-11-23 20:12:52 +01:00
|
|
|
elif kind == 'gcstatus':
|
|
|
|
# status in ROOM (for pm status see status)
|
2005-11-28 18:34:43 +01:00
|
|
|
if show is None: # show is None (xmpp), but we say that 'online'
|
|
|
|
show_col = constants.SHOW_ONLINE
|
2005-11-23 20:12:52 +01:00
|
|
|
jid, nick = jid.split('/', 1)
|
2005-11-26 01:03:09 +01:00
|
|
|
jid_id = self.get_jid_id(jid, 'ROOM') # re-get jid_id for the new jid
|
2005-11-23 20:12:52 +01:00
|
|
|
contact_name_col = nick
|
2005-11-26 00:23:25 +01:00
|
|
|
|
2005-11-23 20:12:52 +01:00
|
|
|
elif kind == 'gc_msg':
|
|
|
|
if jid.find('/') != -1: # if it has a /
|
|
|
|
jid, nick = jid.split('/', 1)
|
2005-06-08 11:19:54 +02:00
|
|
|
else:
|
2005-11-23 20:12:52 +01:00
|
|
|
# it's server message f.e. error message
|
|
|
|
# when user tries to ban someone but he's not allowed to
|
|
|
|
nick = None
|
2005-11-26 01:03:09 +01:00
|
|
|
jid_id = self.get_jid_id(jid, 'ROOM') # re-get jid_id for the new jid
|
2005-11-23 20:12:52 +01:00
|
|
|
contact_name_col = nick
|
2005-11-26 01:03:09 +01:00
|
|
|
else:
|
|
|
|
jid_id = self.get_jid_id(jid)
|
2006-04-11 00:08:02 +02:00
|
|
|
if kind == 'chat_msg_recv':
|
|
|
|
write_unread = True
|
2005-11-28 18:34:43 +01:00
|
|
|
|
|
|
|
if show_col == 'UNKNOWN': # unknown show, do not log
|
|
|
|
return
|
2005-11-26 01:03:09 +01:00
|
|
|
|
2005-11-26 00:23:25 +01:00
|
|
|
values = (jid_id, contact_name_col, time_col, kind_col, show_col,
|
|
|
|
message_col, subject_col)
|
2006-04-11 00:08:02 +02:00
|
|
|
return self.commit_to_db(values, write_unread)
|
|
|
|
|
2005-11-23 20:12:52 +01:00
|
|
|
def get_last_conversation_lines(self, jid, restore_how_many_rows,
|
2006-06-04 19:21:14 +02:00
|
|
|
pending_how_many, timeout, account):
|
2005-11-23 20:12:52 +01:00
|
|
|
'''accepts how many rows to restore and when to time them out (in minutes)
|
|
|
|
(mark them as too old) and number of messages that are in queue
|
|
|
|
and are already logged but pending to be viewed,
|
|
|
|
returns a list of tupples containg time, kind, message,
|
|
|
|
list with empty tupple if nothing found to meet our demands'''
|
|
|
|
jid = jid.lower()
|
|
|
|
jid_id = self.get_jid_id(jid)
|
2006-06-04 19:21:14 +02:00
|
|
|
where_sql = self._build_contact_where(account, jid)
|
|
|
|
|
2005-11-27 18:33:57 +01:00
|
|
|
now = int(float(time.time()))
|
|
|
|
timed_out = now - (timeout * 60) # before that they are too old
|
2005-11-23 20:12:52 +01:00
|
|
|
# so if we ask last 5 lines and we have 2 pending we get
|
|
|
|
# 3 - 8 (we avoid the last 2 lines but we still return 5 asked)
|
2005-12-05 18:22:50 +01:00
|
|
|
self.cur.execute('''
|
2005-11-23 20:12:52 +01:00
|
|
|
SELECT time, kind, message FROM logs
|
2006-06-10 19:23:58 +02:00
|
|
|
WHERE (%s) AND kind IN (%d, %d, %d, %d) AND time > %d
|
2005-11-23 20:12:52 +01:00
|
|
|
ORDER BY time DESC LIMIT %d OFFSET %d
|
2006-06-04 19:21:14 +02:00
|
|
|
''' % (where_sql, constants.KIND_SINGLE_MSG_RECV, constants.KIND_CHAT_MSG_RECV,
|
2005-11-26 00:23:25 +01:00
|
|
|
constants.KIND_SINGLE_MSG_SENT, constants.KIND_CHAT_MSG_SENT,
|
2005-11-27 18:33:57 +01:00
|
|
|
timed_out, restore_how_many_rows, pending_how_many)
|
2005-11-23 20:12:52 +01:00
|
|
|
)
|
2005-04-16 00:02:13 +02:00
|
|
|
|
2005-12-05 18:22:50 +01:00
|
|
|
results = self.cur.fetchall()
|
2005-11-27 18:33:57 +01:00
|
|
|
results.reverse()
|
|
|
|
return results
|
2005-11-24 02:39:47 +01:00
|
|
|
|
|
|
|
def get_unix_time_from_date(self, year, month, day):
|
|
|
|
# year (fe 2005), month (fe 11), day (fe 25)
|
|
|
|
# returns time in seconds for the second that starts that date since epoch
|
|
|
|
# gimme unixtime from year month day:
|
|
|
|
d = datetime.date(year, month, day)
|
|
|
|
local_time = d.timetuple() # time tupple (compat with time.localtime())
|
|
|
|
start_of_day = int(time.mktime(local_time)) # we have time since epoch baby :)
|
|
|
|
return start_of_day
|
|
|
|
|
2006-06-04 11:54:11 +02:00
|
|
|
def get_conversation_for_date(self, jid, year, month, day, account):
|
2005-11-23 20:12:52 +01:00
|
|
|
'''returns contact_name, time, kind, show, message
|
|
|
|
for each row in a list of tupples,
|
|
|
|
returns list with empty tupple if we found nothing to meet our demands'''
|
|
|
|
jid = jid.lower()
|
|
|
|
jid_id = self.get_jid_id(jid)
|
2006-06-04 11:54:11 +02:00
|
|
|
where_sql = self._build_contact_where(account, jid)
|
|
|
|
|
2005-11-24 02:39:47 +01:00
|
|
|
start_of_day = self.get_unix_time_from_date(year, month, day)
|
2005-11-25 23:13:39 +01:00
|
|
|
seconds_in_a_day = 86400 # 60 * 60 * 24
|
|
|
|
last_second_of_day = start_of_day + seconds_in_a_day - 1
|
2005-11-20 22:58:08 +01:00
|
|
|
|
2005-12-05 18:22:50 +01:00
|
|
|
self.cur.execute('''
|
2005-11-23 20:12:52 +01:00
|
|
|
SELECT contact_name, time, kind, show, message FROM logs
|
2006-06-04 11:54:11 +02:00
|
|
|
WHERE (%s)
|
2005-11-23 20:12:52 +01:00
|
|
|
AND time BETWEEN %d AND %d
|
|
|
|
ORDER BY time
|
2006-06-04 11:54:11 +02:00
|
|
|
''' % (where_sql, start_of_day, last_second_of_day))
|
2005-11-20 22:58:08 +01:00
|
|
|
|
2005-12-05 18:22:50 +01:00
|
|
|
results = self.cur.fetchall()
|
2005-11-23 20:12:52 +01:00
|
|
|
return results
|
2005-11-29 15:41:01 +01:00
|
|
|
|
2006-06-04 11:54:11 +02:00
|
|
|
def get_search_results_for_query(self, jid, query, account):
|
2005-11-29 15:41:01 +01:00
|
|
|
'''returns contact_name, time, kind, show, message
|
|
|
|
for each row in a list of tupples,
|
|
|
|
returns list with empty tupple if we found nothing to meet our demands'''
|
|
|
|
jid = jid.lower()
|
|
|
|
jid_id = self.get_jid_id(jid)
|
2006-06-04 11:54:11 +02:00
|
|
|
|
|
|
|
if False: #query.startswith('SELECT '): # it's SQL query (FIXME)
|
2005-11-29 15:41:01 +01:00
|
|
|
try:
|
2005-12-05 18:22:50 +01:00
|
|
|
self.cur.execute(query)
|
2005-11-29 15:41:01 +01:00
|
|
|
except sqlite.OperationalError, e:
|
|
|
|
results = [('', '', '', '', str(e))]
|
|
|
|
return results
|
|
|
|
|
|
|
|
else: # user just typed something, we search in message column
|
2006-06-04 11:54:11 +02:00
|
|
|
where_sql = self._build_contact_where(account, jid)
|
2005-11-29 15:41:01 +01:00
|
|
|
like_sql = '%' + query + '%'
|
2005-12-05 18:22:50 +01:00
|
|
|
self.cur.execute('''
|
2005-11-30 18:30:58 +01:00
|
|
|
SELECT contact_name, time, kind, show, message, subject FROM logs
|
2006-06-04 11:54:11 +02:00
|
|
|
WHERE (%s) AND message LIKE '%s'
|
2005-11-29 15:41:01 +01:00
|
|
|
ORDER BY time
|
2006-06-04 11:54:11 +02:00
|
|
|
''' % (where_sql, like_sql))
|
2005-11-29 15:41:01 +01:00
|
|
|
|
2005-12-05 18:22:50 +01:00
|
|
|
results = self.cur.fetchall()
|
2005-11-29 15:41:01 +01:00
|
|
|
return results
|
|
|
|
|
2006-06-04 11:54:11 +02:00
|
|
|
def get_days_with_logs(self, jid, year, month, max_day, account):
|
2005-12-21 11:54:41 +01:00
|
|
|
'''returns the list of days that have logs (not status messages)'''
|
2005-11-24 02:39:47 +01:00
|
|
|
jid = jid.lower()
|
|
|
|
jid_id = self.get_jid_id(jid)
|
2006-03-01 22:15:01 +01:00
|
|
|
days_with_logs = []
|
2006-06-04 11:54:11 +02:00
|
|
|
where_sql = self._build_contact_where(account, jid)
|
|
|
|
|
2005-12-21 11:54:41 +01:00
|
|
|
# First select all date of month whith logs we want
|
|
|
|
start_of_month = self.get_unix_time_from_date(year, month, 1)
|
2005-11-24 02:39:47 +01:00
|
|
|
seconds_in_a_day = 86400 # 60 * 60 * 24
|
2005-12-21 11:54:41 +01:00
|
|
|
last_second_of_month = start_of_month + (seconds_in_a_day * max_day) - 1
|
|
|
|
|
2005-12-05 18:22:50 +01:00
|
|
|
self.cur.execute('''
|
2005-12-21 11:54:41 +01:00
|
|
|
SELECT time FROM logs
|
2006-06-04 11:54:11 +02:00
|
|
|
WHERE (%s)
|
2005-11-24 02:39:47 +01:00
|
|
|
AND time BETWEEN %d AND %d
|
2005-11-29 14:18:21 +01:00
|
|
|
AND kind NOT IN (%d, %d)
|
2005-12-21 11:54:41 +01:00
|
|
|
ORDER BY time
|
2006-06-04 11:54:11 +02:00
|
|
|
''' % (where_sql, start_of_month, last_second_of_month,
|
2005-11-29 14:18:21 +01:00
|
|
|
constants.KIND_STATUS, constants.KIND_GCSTATUS))
|
2005-12-21 11:54:41 +01:00
|
|
|
result = self.cur.fetchall()
|
|
|
|
|
2006-02-03 00:44:09 +01:00
|
|
|
# Copy all interesant time in a temporary table
|
2005-12-21 11:54:41 +01:00
|
|
|
self.cur.execute('CREATE TEMPORARY TABLE blabla(time,INTEGER)')
|
|
|
|
for line in result:
|
|
|
|
self.cur.execute('''
|
|
|
|
INSERT INTO blabla (time) VALUES (%d)
|
|
|
|
''' % (line[0]))
|
|
|
|
|
2006-02-03 00:44:09 +01:00
|
|
|
# then search in this small temp table for each day
|
2006-03-01 22:15:01 +01:00
|
|
|
for day in xrange(1, max_day + 1): # count from 1 to 28 or to 30 or to 31
|
2005-12-21 11:54:41 +01:00
|
|
|
start_of_day = self.get_unix_time_from_date(year, month, day)
|
|
|
|
last_second_of_day = start_of_day + seconds_in_a_day - 1
|
|
|
|
|
|
|
|
# just ask one row to see if we have sth for this date
|
|
|
|
self.cur.execute('''
|
|
|
|
SELECT time FROM blabla
|
|
|
|
WHERE time BETWEEN %d AND %d
|
|
|
|
LIMIT 1
|
|
|
|
''' % (start_of_day, last_second_of_day))
|
|
|
|
result = self.cur.fetchone()
|
|
|
|
if result:
|
2006-03-01 22:15:01 +01:00
|
|
|
days_with_logs[0:0]=[day]
|
2005-12-21 11:54:41 +01:00
|
|
|
|
2006-02-03 00:44:09 +01:00
|
|
|
# Delete temporary table
|
2005-12-21 11:54:41 +01:00
|
|
|
self.cur.execute('DROP TABLE blabla')
|
2005-12-05 18:22:50 +01:00
|
|
|
result = self.cur.fetchone()
|
2006-03-01 22:15:01 +01:00
|
|
|
return days_with_logs
|
2005-11-30 22:56:42 +01:00
|
|
|
|
2006-06-04 11:54:11 +02:00
|
|
|
def get_last_date_that_has_logs(self, jid, account = None, is_room = False):
|
2005-11-30 22:56:42 +01:00
|
|
|
'''returns last time (in seconds since EPOCH) for which
|
|
|
|
we had logs (excluding statuses)'''
|
|
|
|
jid = jid.lower()
|
2006-06-04 11:54:11 +02:00
|
|
|
|
|
|
|
where_sql = ''
|
|
|
|
if not is_room:
|
|
|
|
where_sql = self._build_contact_where(account, jid)
|
|
|
|
else:
|
|
|
|
jid_id = self.get_jid_id(jid, 'ROOM')
|
|
|
|
where_sql = 'jid_id = %s' % jid_id
|
2005-12-05 18:22:50 +01:00
|
|
|
self.cur.execute('''
|
2005-11-30 22:56:42 +01:00
|
|
|
SELECT time FROM logs
|
2006-06-04 11:54:11 +02:00
|
|
|
WHERE (%s)
|
|
|
|
AND kind NOT IN (%d, %d)
|
2005-11-30 22:56:42 +01:00
|
|
|
ORDER BY time DESC LIMIT 1
|
2006-06-04 11:54:11 +02:00
|
|
|
''' % (where_sql, constants.KIND_STATUS, constants.KIND_GCSTATUS))
|
2005-12-26 19:23:57 +01:00
|
|
|
|
|
|
|
results = self.cur.fetchone()
|
2005-12-26 19:34:02 +01:00
|
|
|
if results is not None:
|
2005-12-26 19:23:57 +01:00
|
|
|
result = results[0]
|
|
|
|
else:
|
|
|
|
result = None
|
|
|
|
|
2005-11-30 22:56:42 +01:00
|
|
|
return result
|
2006-06-04 11:54:11 +02:00
|
|
|
|
|
|
|
def _build_contact_where(self, account, jid):
|
|
|
|
'''build the where clause for a jid, including metacontacts
|
|
|
|
jid(s) if any'''
|
|
|
|
where_sql = ''
|
|
|
|
# will return empty list if jid is not associated with
|
|
|
|
# any metacontacts
|
|
|
|
family = gajim.contacts.get_metacontacts_family(account, jid)
|
|
|
|
if family:
|
|
|
|
for user in family:
|
|
|
|
jid_id = self.get_jid_id(user['jid'])
|
|
|
|
where_sql += 'jid_id = %s' % jid_id
|
|
|
|
if user != family[-1]:
|
|
|
|
where_sql += ' OR '
|
|
|
|
else: # if jid was not associated with metacontacts
|
|
|
|
jid_id = self.get_jid_id(jid)
|
|
|
|
where_sql = 'jid_id = %s' % jid_id
|
|
|
|
return where_sql
|
2006-07-30 00:29:59 +02:00
|
|
|
|
|
|
|
def save_transport_type(self, jid, type_):
|
|
|
|
'''save the type of the transport in DB'''
|
|
|
|
type_id = self.convert_human_transport_type_to_db_api_values(type_)
|
|
|
|
if not type_id:
|
|
|
|
# unknown type
|
|
|
|
return
|
|
|
|
self.cur.execute(
|
|
|
|
'SELECT type from transports_cache WHERE transport = "%s"' % jid)
|
|
|
|
results = self.cur.fetchall()
|
|
|
|
if results:
|
|
|
|
result = results[0][0]
|
|
|
|
if result == type_id:
|
|
|
|
return
|
|
|
|
self.cur.execute(
|
|
|
|
'UPDATE transports_cache SET type = %d WHERE transport = "%s"' % (type_id,
|
|
|
|
jid))
|
|
|
|
try:
|
|
|
|
self.con.commit()
|
|
|
|
except sqlite.OperationalError, e:
|
|
|
|
print >> sys.stderr, str(e)
|
|
|
|
return
|
|
|
|
self.cur.execute(
|
|
|
|
'INSERT INTO transports_cache VALUES ("%s", %d)' % (jid, type_id))
|
|
|
|
try:
|
|
|
|
self.con.commit()
|
|
|
|
except sqlite.OperationalError, e:
|
|
|
|
print >> sys.stderr, str(e)
|
|
|
|
|
|
|
|
def get_transports_type(self):
|
|
|
|
'''return all the type of the transports in DB'''
|
|
|
|
self.cur.execute(
|
|
|
|
'SELECT * from transports_cache')
|
|
|
|
results = self.cur.fetchall()
|
|
|
|
if not results:
|
|
|
|
return {}
|
|
|
|
answer = {}
|
|
|
|
for result in results:
|
|
|
|
answer[result[0]] = self.convert_api_values_to_human_transport_type(result[1])
|
|
|
|
return answer
|