493 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			493 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!/usr/bin/python
 | 
						|
# -*- coding: utf-8 -*-
 | 
						|
#
 | 
						|
# Copyright 2013 The Plaso Project Authors.
 | 
						|
# Please see the AUTHORS file for details on individual authors.
 | 
						|
#
 | 
						|
# Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
# you may not use this file except in compliance with the License.
 | 
						|
# You may obtain a copy of the License at
 | 
						|
#
 | 
						|
#    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
#
 | 
						|
# Unless required by applicable law or agreed to in writing, software
 | 
						|
# distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
# See the License for the specific language governing permissions and
 | 
						|
# limitations under the License.
 | 
						|
"""This file contains a basic Skype SQLite parser."""
 | 
						|
 | 
						|
import logging
 | 
						|
 | 
						|
from plaso.events import time_events
 | 
						|
from plaso.parsers import sqlite
 | 
						|
from plaso.parsers.sqlite_plugins import interface
 | 
						|
 | 
						|
 | 
						|
__author__ = 'Joaquin Moreno Garijo (bastionado@gmail.com)'
 | 
						|
 | 
						|
 | 
						|
class SkypeChatEvent(time_events.PosixTimeEvent):
 | 
						|
  """Convenience class for a Skype event."""
 | 
						|
 | 
						|
  DATA_TYPE = 'skype:event:chat'
 | 
						|
 | 
						|
  def __init__(self, row, to_account):
 | 
						|
    """Build a Skype Event from a single row.
 | 
						|
 | 
						|
    Args:
 | 
						|
      row: A row object (instance of sqlite3.Row) that contains the
 | 
						|
           extracted data from a single row in the database.
 | 
						|
      to_account: A string containing the accounts (excluding the
 | 
						|
                  author) of the conversation.
 | 
						|
    """
 | 
						|
    super(SkypeChatEvent, self).__init__(
 | 
						|
        row['timestamp'], 'Chat from Skype', self.DATA_TYPE)
 | 
						|
 | 
						|
    self.title = row['title']
 | 
						|
    self.text = row['body_xml']
 | 
						|
    self.from_account = u'{0:s} <{1:s}>'.format(
 | 
						|
        row['from_displayname'], row['author'])
 | 
						|
    self.to_account = to_account
 | 
						|
 | 
						|
 | 
						|
class SkypeAccountEvent(time_events.PosixTimeEvent):
 | 
						|
  """Convenience class for account information."""
 | 
						|
 | 
						|
  DATA_TYPE = 'skype:event:account'
 | 
						|
 | 
						|
  def __init__(
 | 
						|
      self, timestamp, usage, identifier, full_name, display_name, email,
 | 
						|
      country):
 | 
						|
    """Initialize the event.
 | 
						|
 | 
						|
    Args:
 | 
						|
      timestamp: The POSIX timestamp value.
 | 
						|
      usage: A string containing the description string of the timestamp.
 | 
						|
      identifier: The row identifier.
 | 
						|
      full_name: A string containing the full name of the Skype account holder.
 | 
						|
      display_name: A string containing the chosen display name of the account
 | 
						|
                    holder.
 | 
						|
      email: A string containing the registered email address of the account
 | 
						|
             holder.
 | 
						|
      country: A string containing the chosen home country of the account
 | 
						|
               holder.
 | 
						|
    """
 | 
						|
    super(SkypeAccountEvent, self).__init__(timestamp, usage)
 | 
						|
 | 
						|
    self.offset = identifier
 | 
						|
    self.username = u'{0:s} <{1:s}>'.format(full_name, display_name)
 | 
						|
    self.display_name = display_name
 | 
						|
    self.email = email
 | 
						|
    self.country = country
 | 
						|
    self.data_type = self.DATA_TYPE
 | 
						|
 | 
						|
 | 
						|
class SkypeSMSEvent(time_events.PosixTimeEvent):
 | 
						|
  """Convenience EventObject for SMS."""
 | 
						|
 | 
						|
  DATA_TYPE = 'skype:event:sms'
 | 
						|
 | 
						|
  def __init__(self, row, dst_number):
 | 
						|
    """Read the information related with the SMS.
 | 
						|
 | 
						|
      Args:
 | 
						|
        row: row form the sql query.
 | 
						|
          row['time_sms']: timestamp when the sms was send.
 | 
						|
          row['dstnum_sms']: number which receives the sms.
 | 
						|
          row['msg_sms']: text send to this sms.
 | 
						|
        dst_number: phone number where the user send the sms.
 | 
						|
    """
 | 
						|
    super(SkypeSMSEvent, self).__init__(
 | 
						|
        row['time_sms'], 'SMS from Skype', self.DATA_TYPE)
 | 
						|
 | 
						|
    self.number = dst_number
 | 
						|
    self.text = row['msg_sms']
 | 
						|
 | 
						|
 | 
						|
class SkypeCallEvent(time_events.PosixTimeEvent):
 | 
						|
  """Convenience EventObject for the calls."""
 | 
						|
 | 
						|
  DATA_TYPE = 'skype:event:call'
 | 
						|
 | 
						|
  def __init__(self, timestamp, call_type, user_start_call,
 | 
						|
               source, destination, video_conference):
 | 
						|
    """Contains information if the call was cancelled, accepted or finished.
 | 
						|
 | 
						|
      Args:
 | 
						|
        timestamp: the timestamp of the event.
 | 
						|
        call_type: WAITING, STARTED, FINISHED.
 | 
						|
        user_start_call: boolean, true indicates that the owner
 | 
						|
                         account started the call.
 | 
						|
        source: the account which started the call.
 | 
						|
        destination: the account which gets the call.
 | 
						|
        video_conference: boolean, if is true it was a videoconference.
 | 
						|
    """
 | 
						|
 | 
						|
    super(SkypeCallEvent, self).__init__(
 | 
						|
        timestamp, 'Call from Skype', self.DATA_TYPE)
 | 
						|
 | 
						|
    self.call_type = call_type
 | 
						|
    self.user_start_call = user_start_call
 | 
						|
    self.src_call = source
 | 
						|
    self.dst_call = destination
 | 
						|
    self.video_conference = video_conference
 | 
						|
 | 
						|
 | 
						|
class SkypeTransferFileEvent(time_events.PosixTimeEvent):
 | 
						|
  """Evaluate the action of send a file."""
 | 
						|
 | 
						|
  DATA_TYPE = 'skype:event:transferfile'
 | 
						|
 | 
						|
  def __init__(self, row, timestamp, action_type, source, destination):
 | 
						|
    """Actions related with sending files.
 | 
						|
 | 
						|
      Args:
 | 
						|
        row:
 | 
						|
          filepath: path from the file.
 | 
						|
          filename: name of the file.
 | 
						|
          filesize: size of the file.
 | 
						|
        timestamp: when the action happens.
 | 
						|
        action_type: GETSOLICITUDE, SENDSOLICITUDE, ACCEPTED, FINISHED.
 | 
						|
        source: The account that sent the file.
 | 
						|
        destination: The account that received the file.
 | 
						|
    """
 | 
						|
 | 
						|
    super(SkypeTransferFileEvent, self).__init__(
 | 
						|
        timestamp, 'File transfer from Skype', self.DATA_TYPE)
 | 
						|
 | 
						|
    self.offset = row['id']
 | 
						|
    self.action_type = action_type
 | 
						|
    self.source = source
 | 
						|
    self.destination = destination
 | 
						|
    self.transferred_filepath = row['filepath']
 | 
						|
    self.transferred_filename = row['filename']
 | 
						|
    try:
 | 
						|
      self.transferred_filesize = int(row['filesize'])
 | 
						|
    except ValueError:
 | 
						|
      logging.debug(u'Unknown filesize {0:s}'.format(
 | 
						|
          self.transferred_filename))
 | 
						|
      self.transferred_filesize = 0
 | 
						|
 | 
						|
 | 
						|
class SkypePlugin(interface.SQLitePlugin):
 | 
						|
  """SQLite plugin for Skype main.db SQlite database file."""
 | 
						|
 | 
						|
  NAME = 'skype'
 | 
						|
  DESCRIPTION = u'Parser for Skype SQLite database files.'
 | 
						|
 | 
						|
  # Queries for building cache.
 | 
						|
  QUERY_DEST_FROM_TRANSFER = (
 | 
						|
      u'SELECT parent_id, partner_handle AS skypeid, '
 | 
						|
      u'partner_dispname AS skypename FROM transfers')
 | 
						|
  QUERY_SOURCE_FROM_TRANSFER = (
 | 
						|
      u'SELECT pk_id, partner_handle AS skypeid, '
 | 
						|
      u'partner_dispname AS skypename FROM transfers')
 | 
						|
 | 
						|
  # Define the needed queries.
 | 
						|
  QUERIES = [
 | 
						|
      (('SELECT c.id, c.participants, c.friendlyname AS title, '
 | 
						|
        'm.author AS author, m.from_dispname AS from_displayname, '
 | 
						|
        'm.body_xml, m.timestamp, c.dialog_partner FROM Chats c, Messages m '
 | 
						|
        'WHERE c.name = m.chatname'), 'ParseChat'),
 | 
						|
      (('SELECT id, fullname, given_displayname, emails, '
 | 
						|
        'country, profile_timestamp, authreq_timestamp, '
 | 
						|
        'lastonline_timestamp, mood_timestamp, sent_authrequest_time, '
 | 
						|
        'lastused_timestamp FROM Accounts'), 'ParseAccountInformation'),
 | 
						|
      (('SELECT id, target_numbers AS dstnum_sms, timestamp AS time_sms, '
 | 
						|
        'body AS msg_sms FROM SMSes'), 'ParseSMS'),
 | 
						|
      (('SELECT id, partner_handle, partner_dispname, offer_send_list, '
 | 
						|
        'starttime, accepttime, finishtime, filepath, filename, filesize, '
 | 
						|
        'status, parent_id, pk_id FROM Transfers'), 'ParseFileTransfer'),
 | 
						|
      (('SELECT c.id, cm.guid, c.is_incoming, '
 | 
						|
        'cm.call_db_id, cm.videostatus, c.begin_timestamp AS try_call, '
 | 
						|
        'cm.start_timestamp AS accept_call, cm.call_duration '
 | 
						|
        'FROM Calls c, CallMembers cm '
 | 
						|
        'WHERE c.id = cm.call_db_id;'), 'ParseCall')]
 | 
						|
 | 
						|
  # The required tables.
 | 
						|
  REQUIRED_TABLES = frozenset([
 | 
						|
      'Chats', 'Accounts', 'Conversations', 'Contacts', 'SMSes', 'Transfers',
 | 
						|
      'CallMembers', 'Calls'])
 | 
						|
 | 
						|
  def ParseAccountInformation(
 | 
						|
      self, parser_context, row, file_entry=None, parser_chain=None, query=None,
 | 
						|
      **unused_kwargs):
 | 
						|
    """Parses the Accounts database.
 | 
						|
 | 
						|
    Args:
 | 
						|
      parser_context: A parser context object (instance of ParserContext).
 | 
						|
      row: The row resulting from the query.
 | 
						|
      file_entry: Optional file entry object (instance of dfvfs.FileEntry).
 | 
						|
                  The default is None.
 | 
						|
      parser_chain: Optional string containing the parsing chain up to this
 | 
						|
                    point. The default is None.
 | 
						|
      query: Optional query string. The default is None.
 | 
						|
    """
 | 
						|
    if row['profile_timestamp']:
 | 
						|
      event_object = SkypeAccountEvent(
 | 
						|
          row['profile_timestamp'], u'Profile Changed', row['id'],
 | 
						|
          row['fullname'], row['given_displayname'], row['emails'],
 | 
						|
          row['country'])
 | 
						|
      parser_context.ProduceEvent(
 | 
						|
          event_object, query=query, parser_chain=parser_chain,
 | 
						|
          file_entry=file_entry)
 | 
						|
 | 
						|
    if row['authreq_timestamp']:
 | 
						|
      event_object = SkypeAccountEvent(
 | 
						|
          row['authreq_timestamp'], u'Authenticate Request', row['id'],
 | 
						|
          row['fullname'], row['given_displayname'], row['emails'],
 | 
						|
          row['country'])
 | 
						|
      parser_context.ProduceEvent(
 | 
						|
          event_object, query=query, parser_chain=parser_chain,
 | 
						|
          file_entry=file_entry)
 | 
						|
 | 
						|
    if row['lastonline_timestamp']:
 | 
						|
      event_object = SkypeAccountEvent(
 | 
						|
          row['lastonline_timestamp'], u'Last Online', row['id'],
 | 
						|
          row['fullname'], row['given_displayname'], row['emails'],
 | 
						|
          row['country'])
 | 
						|
      parser_context.ProduceEvent(
 | 
						|
          event_object, query=query, parser_chain=parser_chain,
 | 
						|
          file_entry=file_entry)
 | 
						|
 | 
						|
    if row['mood_timestamp']:
 | 
						|
      event_object = SkypeAccountEvent(
 | 
						|
          row['mood_timestamp'], u'Mood Event', row['id'],
 | 
						|
          row['fullname'], row['given_displayname'], row['emails'],
 | 
						|
          row['country'])
 | 
						|
      parser_context.ProduceEvent(
 | 
						|
          event_object, query=query, parser_chain=parser_chain,
 | 
						|
          file_entry=file_entry)
 | 
						|
 | 
						|
    if row['sent_authrequest_time']:
 | 
						|
      event_object = SkypeAccountEvent(
 | 
						|
          row['sent_authrequest_time'], u'Auth Request Sent', row['id'],
 | 
						|
          row['fullname'], row['given_displayname'], row['emails'],
 | 
						|
          row['country'])
 | 
						|
      parser_context.ProduceEvent(
 | 
						|
          event_object, query=query, parser_chain=parser_chain,
 | 
						|
          file_entry=file_entry)
 | 
						|
 | 
						|
    if row['lastused_timestamp']:
 | 
						|
      event_object = SkypeAccountEvent(
 | 
						|
          row['lastused_timestamp'], u'Last Used', row['id'],
 | 
						|
          row['fullname'], row['given_displayname'], row['emails'],
 | 
						|
          row['country'])
 | 
						|
      parser_context.ProduceEvent(
 | 
						|
          event_object, query=query, parser_chain=parser_chain,
 | 
						|
          file_entry=file_entry)
 | 
						|
 | 
						|
  def ParseChat(
 | 
						|
      self, parser_context, row, file_entry=None, parser_chain=None, query=None,
 | 
						|
      **unused_kwargs):
 | 
						|
    """Parses a chat message row.
 | 
						|
 | 
						|
    Args:
 | 
						|
      parser_context: A parser context object (instance of ParserContext).
 | 
						|
      row: The row resulting from the query.
 | 
						|
      file_entry: Optional file entry object (instance of dfvfs.FileEntry).
 | 
						|
                  The default is None.
 | 
						|
      parser_chain: Optional string containing the parsing chain up to this
 | 
						|
                    point. The default is None.
 | 
						|
      query: Optional query string. The default is None.
 | 
						|
    """
 | 
						|
    to_account = ''
 | 
						|
    accounts = []
 | 
						|
    participants = row['participants'].split(' ')
 | 
						|
    for participant in participants:
 | 
						|
      if participant != row['author']:
 | 
						|
        accounts.append(participant)
 | 
						|
    to_account = u', '.join(accounts)
 | 
						|
 | 
						|
    if not to_account:
 | 
						|
      if row['dialog_partner']:
 | 
						|
        to_account = row['dialog_partner']
 | 
						|
      else:
 | 
						|
        to_account = u'Unknown User'
 | 
						|
 | 
						|
    event_object = SkypeChatEvent(row, to_account)
 | 
						|
    parser_context.ProduceEvent(
 | 
						|
        event_object, query=query, parser_chain=parser_chain,
 | 
						|
        file_entry=file_entry)
 | 
						|
 | 
						|
  def ParseSMS(
 | 
						|
      self, parser_context, row, file_entry=None, parser_chain=None, query=None,
 | 
						|
      **unused_kwargs):
 | 
						|
    """Parse SMS.
 | 
						|
 | 
						|
    Args:
 | 
						|
      parser_context: A parser context object (instance of ParserContext).
 | 
						|
      row: The row resulting from the query.
 | 
						|
      file_entry: Optional file entry object (instance of dfvfs.FileEntry).
 | 
						|
                  The default is None.
 | 
						|
      parser_chain: Optional string containing the parsing chain up to this
 | 
						|
                    point. The default is None.
 | 
						|
      query: Optional query string. The default is None.
 | 
						|
    """
 | 
						|
    dst_number = row['dstnum_sms'].replace(' ', '')
 | 
						|
 | 
						|
    event_object = SkypeSMSEvent(row, dst_number)
 | 
						|
    parser_context.ProduceEvent(
 | 
						|
        event_object, query=query, parser_chain=parser_chain,
 | 
						|
        file_entry=file_entry)
 | 
						|
 | 
						|
  def ParseCall(
 | 
						|
      self, parser_context, row, file_entry=None, parser_chain=None, query=None,
 | 
						|
      **unused_kwargs):
 | 
						|
    """Parse the calls taking into accounts some rows.
 | 
						|
 | 
						|
    Args:
 | 
						|
      parser_context: A parser context object (instance of ParserContext).
 | 
						|
      row: The row resulting from the query.
 | 
						|
      file_entry: Optional file entry object (instance of dfvfs.FileEntry).
 | 
						|
                  The default is None.
 | 
						|
      parser_chain: Optional string containing the parsing chain up to this
 | 
						|
                    point. The default is None.
 | 
						|
      query: Optional query string. The default is None.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
      aux = row['guid']
 | 
						|
      if aux:
 | 
						|
        aux_list = aux.split('-')
 | 
						|
        src_aux = aux_list[0]
 | 
						|
        dst_aux = aux_list[1]
 | 
						|
      else:
 | 
						|
        src_aux = u'Unknown [no GUID]'
 | 
						|
        dst_aux = u'Unknown [no GUID]'
 | 
						|
    except IndexError:
 | 
						|
      src_aux = u'Unknown [{0:s}]'.format(row['guid'])
 | 
						|
      dst_aux = u'Unknown [{0:s}]'.format(row['guid'])
 | 
						|
 | 
						|
    if row['is_incoming'] == '0':
 | 
						|
      user_start_call = True
 | 
						|
      source = src_aux
 | 
						|
      if row['ip_address']:
 | 
						|
        destination = u'{0:s} <{1:s}>'.format(dst_aux, row['ip_address'])
 | 
						|
      else:
 | 
						|
        destination = dst_aux
 | 
						|
    else:
 | 
						|
      user_start_call = False
 | 
						|
      source = src_aux
 | 
						|
      destination = dst_aux
 | 
						|
 | 
						|
    if row['videostatus'] == '3':
 | 
						|
      video_conference = True
 | 
						|
    else:
 | 
						|
      video_conference = False
 | 
						|
 | 
						|
    event_object = SkypeCallEvent(
 | 
						|
        row['try_call'], 'WAITING', user_start_call, source, destination,
 | 
						|
        video_conference)
 | 
						|
    parser_context.ProduceEvent(
 | 
						|
        event_object, query=query, parser_chain=parser_chain,
 | 
						|
        file_entry=file_entry)
 | 
						|
 | 
						|
    if row['accept_call']:
 | 
						|
      event_object = SkypeCallEvent(
 | 
						|
          row['accept_call'], 'ACCEPTED', user_start_call, source, destination,
 | 
						|
          video_conference)
 | 
						|
      parser_context.ProduceEvent(
 | 
						|
          event_object, query=query, parser_chain=parser_chain,
 | 
						|
          file_entry=file_entry)
 | 
						|
 | 
						|
      if row['call_duration']:
 | 
						|
        try:
 | 
						|
          timestamp = int(row['accept_call']) + int(row['call_duration'])
 | 
						|
          event_object = SkypeCallEvent(
 | 
						|
              timestamp, 'FINISHED', user_start_call, source, destination,
 | 
						|
              video_conference)
 | 
						|
          parser_context.ProduceEvent(
 | 
						|
              event_object, query=query, parser_chain=parser_chain,
 | 
						|
              file_entry=file_entry)
 | 
						|
 | 
						|
        except ValueError:
 | 
						|
          logging.debug((
 | 
						|
              u'[{0:s}] Unable to determine when the call {1:s} was '
 | 
						|
              u'finished.').format(self.NAME, row['id']))
 | 
						|
 | 
						|
  def ParseFileTransfer(
 | 
						|
      self, parser_context, row, file_entry=None, parser_chain=None, cache=None,
 | 
						|
      database=None, query=None, **unused_kwargs):
 | 
						|
    """Parse the transfer files.
 | 
						|
 | 
						|
     There is no direct relationship between who sends the file and
 | 
						|
     who accepts the file.
 | 
						|
 | 
						|
    Args:
 | 
						|
      parser_context: A parser context object (instance of ParserContext).
 | 
						|
      row: the row with all information related with the file transfers.
 | 
						|
      file_entry: Optional file entry object (instance of dfvfs.FileEntry).
 | 
						|
                  The default is None.
 | 
						|
      parser_chain: Optional string containing the parsing chain up to this
 | 
						|
                    point. The default is None.
 | 
						|
      query: Optional query string. The default is None.
 | 
						|
      cache: a cache object (instance of SQLiteCache).
 | 
						|
      database: A database object (instance of SQLiteDatabase).
 | 
						|
    """
 | 
						|
    source_dict = cache.GetResults('source')
 | 
						|
    if not source_dict:
 | 
						|
      cursor = database.cursor
 | 
						|
      results = cursor.execute(self.QUERY_SOURCE_FROM_TRANSFER)
 | 
						|
      cache.CacheQueryResults(
 | 
						|
          results, 'source', 'pk_id', ('skypeid', 'skypename'))
 | 
						|
      source_dict = cache.GetResults('source')
 | 
						|
 | 
						|
    dest_dict = cache.GetResults('destination')
 | 
						|
    if not dest_dict:
 | 
						|
      cursor = database.cursor
 | 
						|
      results = cursor.execute(self.QUERY_DEST_FROM_TRANSFER)
 | 
						|
      cache.CacheQueryResults(
 | 
						|
          results, 'destination', 'parent_id', ('skypeid', 'skypename'))
 | 
						|
      dest_dict = cache.GetResults('destination')
 | 
						|
 | 
						|
    source = u'Unknown'
 | 
						|
    destination = u'Unknown'
 | 
						|
 | 
						|
    if row['parent_id']:
 | 
						|
      destination = u'{0:s} <{1:s}>'.format(
 | 
						|
          row['partner_handle'], row['partner_dispname'])
 | 
						|
      skype_id, skype_name = source_dict.get(row['parent_id'], [None, None])
 | 
						|
      if skype_name:
 | 
						|
        source = u'{0:s} <{1:s}>'.format(skype_id, skype_name)
 | 
						|
    else:
 | 
						|
      source = u'{0:s} <{1:s}>'.format(
 | 
						|
          row['partner_handle'], row['partner_dispname'])
 | 
						|
 | 
						|
      if row['pk_id']:
 | 
						|
        skype_id, skype_name = dest_dict.get(row['pk_id'], [None, None])
 | 
						|
        if skype_name:
 | 
						|
          destination = u'{0:s} <{1:s}>'.format(skype_id, skype_name)
 | 
						|
 | 
						|
    if row['status'] == 8:
 | 
						|
      if row['starttime']:
 | 
						|
        event_object = SkypeTransferFileEvent(
 | 
						|
            row, row['starttime'], 'GETSOLICITUDE', source, destination)
 | 
						|
        parser_context.ProduceEvent(
 | 
						|
            event_object, query=query, parser_chain=parser_chain,
 | 
						|
            file_entry=file_entry)
 | 
						|
 | 
						|
      if row['accepttime']:
 | 
						|
        event_object = SkypeTransferFileEvent(
 | 
						|
            row, row['accepttime'], 'ACCEPTED', source, destination)
 | 
						|
        parser_context.ProduceEvent(
 | 
						|
            event_object, query=query, parser_chain=parser_chain,
 | 
						|
            file_entry=file_entry)
 | 
						|
 | 
						|
      if row['finishtime']:
 | 
						|
        event_object = SkypeTransferFileEvent(
 | 
						|
            row, row['finishtime'], 'FINISHED', source, destination)
 | 
						|
        parser_context.ProduceEvent(
 | 
						|
            event_object, query=query, parser_chain=parser_chain,
 | 
						|
            file_entry=file_entry)
 | 
						|
 | 
						|
    elif row['status'] == 2 and row['starttime']:
 | 
						|
      event_object = SkypeTransferFileEvent(
 | 
						|
          row, row['starttime'], 'SENDSOLICITUDE', source, destination)
 | 
						|
      parser_context.ProduceEvent(
 | 
						|
          event_object, query=query, parser_chain=parser_chain,
 | 
						|
          file_entry=file_entry)
 | 
						|
 | 
						|
 | 
						|
sqlite.SQLiteParser.RegisterPlugin(SkypePlugin)
 |