# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Mobius Forensic Toolkit
# Copyright (C) 2008,2009,2010 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 glob
import os
import os.path
import mobius.extension.pickle
import mobius.extension.compiler
from mobius.extension.model import *

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief Data
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
g_extensions = {}

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief Global variable container
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class GlobalData (object):
  pass

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.new
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_new ():
  extension = Extension ()
  return extension

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.open
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_open (path):
  pickle = mobius.extension.pickle.Pickle ()
  extension = pickle.load (path)
  return extension

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.save
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_save (extension, path):
  pickle = mobius.extension.pickle.Pickle ()
  pickle.save (extension, path)

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.start-all
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_start_all ():
  cache_dir = mobius.mediator.call ('app.get-path', 'cache', 'extensions')
  extension_dir = mobius.mediator.call ('app.get-path', 'extensions')

  if not os.path.isdir (cache_dir):
    os.makedirs (cache_dir)

  # load extensions
  for path in glob.iglob ('%s/*.xml' % extension_dir):

    # check if cached code is up to date
    filename = os.path.basename (os.path.splitext (path)[0]) + '.py'
    pyfile = os.path.join (cache_dir, filename)
    cache_is_valid = False

    if os.path.exists (pyfile):
      st_pyfile = os.stat (pyfile)	# pyfile modification time
      st_extension = os.stat (path)	# extension modification time

      if st_extension.st_mtime <= st_pyfile.st_mtime:
        cache_is_valid = True

    # generate code if necessary
    if not cache_is_valid:
      compiler = mobius.extension.compiler.Compiler ()
      compiler.compile (path, pyfile)

    # load extension
    try:
      extension = mobius.mediator.call ('extension.open', path)
      extension.path = path
      extension.pyfile = pyfile
      g_extensions[extension.id] = extension
    except Exception, e:
      print 'Error loading extension "%s": %s' % (os.path.basename (path), e)

  # start API
  for extension in g_extensions.itervalues ():
    try:
      mobius.mediator.call ('extension.start-api', extension)
    except Exception, e:
      print 'Error starting extension "%s" API: %s' % (os.path.basename (extension.path), e)

  # start extensions
  for extension in g_extensions.itervalues ():
    try:
      mobius.mediator.call ('extension.start', extension)
    except Exception, e:
      print 'Error starting extension "%s": %s' % (os.path.basename (extension.path), e)

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.stop-all
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_stop_all ():

  # stop extensions
  for extension in g_extensions.itervalues ():
    mobius.mediator.call ('extension.stop', extension)

  # stop extensions API
  for extension in g_extensions.values ():
    extension = g_extensions.pop (extension.id, None)
    extension.mediator.clear ()

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.start-api
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_start_api (extension):
  extension.mediator = mobius.mediator.copy ()

  # instance data
  extension.gdata = GlobalData ()
  extension.gdata.mediator = extension.mediator
  extension.gdata.extension = extension
  extension.module = {'gdata' : extension.gdata}

  code = open (extension.pyfile).read () + '\n'
  bytecode = compile (code, '%s:main' % extension.id, 'exec')
  exec bytecode in extension.module

  start_api = extension.module.get ('pvt_start_api')
  start_api ()

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.start
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_start (extension):
  pvt_start = extension.module.get ('pvt_start')

  if pvt_start:
    pvt_start ()

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.stop
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_stop (extension):
  pvt_stop = extension.module.get ('pvt_stop')

  if pvt_stop:
    pvt_stop ()

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.new-service
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_new_service ():
  service = Service ()
  return service

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.new-callback
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_new_callback ():
  callback = Callback ()
  return callback

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.new-arg
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_new_arg ():
  arg = Arg ()
  return arg

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.uninstall
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_uninstall (extension_id):

    # stop extension
    extension = g_extensions.pop (extension_id)
    mobius.mediator.call ('extension.stop', extension)
    extension.mediator.clear ()

    # remove file from extensions directory
    os.remove (extension.path)

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.list
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_list ():
  return g_extensions.values ()

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief service: extension.get
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def svc_extension_get (extension_id):
  return g_extensions.get (extension_id)
