# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Mobius Forensic Toolkit
# Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 Eduardo Aguiar
#
# 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; either version 2, or (at your option) any later
# version.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
import mobius
import binascii

BTINFO_SER_VERSION = 11		# Shareaza 2.7.10.2

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief Generic data holder
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class dataholder (object):
  pass

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief decode CBTInfo structure (IMPLEMENT)
# @see BTInfo.cpp - CBTInfo::Serialize
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def decode (decoder):
  version = decoder.get_dword ()

  if version > BTINFO_SER_VERSION:
    mobius.core.log ("p2p.shareaza.CBTInfo.py: Version > %d" % BTINFO_SER_VERSION)

  hash_bth = decoder.get_hex_string (20)

  if not hash_bth:
    return None

  data = dataholder ()
  data.version = version
  data.hash_bth = hash_bth
  data.total_upload = 0
  data.total_download = 0
  data.encoding = None
  data.comment = None
  data.creation_time = None
  data.created_by = None
  data.b_private = None
  data.main_tracker = None
  data.files = []
  data.trackers = []

  if version >= 2:
    data.size = decoder.get_qword ()
  else:
    data.size = decoder.get_dword ()

  data.block_size = decoder.get_dword ()
  data.block_count = decoder.get_dword ()
  data.block_hashes = []

  for i in xrange (data.block_count):
    h = binascii.hexlify (decoder.get_data (20))
    data.block_hashes.append (h)

  if version >= 4:
    data.total_upload = decoder.get_qword ()

  if version >= 6:
    data.total_download = decoder.get_qword ()

  data.name = decoder.get_string ()

  if version >= 3:
    data.encoding = decoder.get_dword ()
    data.comment = decoder.get_string ()
    data.creation_time = decoder.get_unix_time ()
    data.created_by = decoder.get_string ()

  if version >= 5:
    data.b_private = decoder.get_bool ()

  count = decoder.get_count ()

  for i in xrange (count):
    f = decode_CBTFile (decoder, version)
    data.files.append (f)

  if version < 7:
    data.main_tracker = decoder.get_string ()

  if version >= 4:
    data.tracker_index = decoder.get_int ()
    data.tracker_mode = decoder.get_int ()

    if version < 7:
      if decoder.get_count ():
        tracker = decode_CBTTracker (decoder)
        data.trackers.append (tracker)

      count = decoder.get_count ()

      for i in xrange (count):
        tracker = decode_CBTTracker (decoder)
        data.trackers.append (tracker)

  if version >= 10:
    length = decoder.get_dword ()
    decoder.skip (length)

  if version >= 11:
    data.info_start = decoder.get_dword ()
    data.info_size = decoder.get_dword ()

  return data

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief decode CBTFile structure
# @see BTInfo.cpp - CBTFile::Serialize
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def decode_CBTFile (decoder, version):
  data = dataholder ()
  data.name = None
  data.hash_ed2k = None
  data.hash_tiger = None
  data.hash_md5 = None
  data.file_priority = None

  if version >= 2:
    data.size = decoder.get_qword ()
  else:
    data.size = decoder.get_dword ()

  data.path = decoder.get_string ()

  if version >= 9:
    data.name = decoder.get_string ()

  data.hash_sha1 = decoder.get_hex_string (20)

  if version >= 4:
    data.hash_ed2k = decoder.get_hex_string (16)
    data.hash_tiger = decoder.get_hex_string (24)

    if version < 8:
      data.file_priority = decoder.get_int ()

  if version >= 6:
    data.hash_md5 = decoder.get_hex_string (16)

  return data

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief decode CBTTracker structure
# @see BTInfo.cpp - CBTTracker::Serialize
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def decode_CBTTracker (decoder):
  data = dataholder ()

  data.address = decoder.get_string ()
  data.last_access = decoder.get_unix_time ()
  data.last_success = decoder.get_unix_time ()
  data.next_try = decoder.get_unix_time ()
  data.failures = decoder.get_dword ()
  data.tier = decoder.get_int ()
  data.type = decoder.get_int ()

  return data
