# -*- coding: utf-8 -*-
# Copyright (C) 2010-2023 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
#
# Python X2Go is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Python X2Go 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
"""\
For MIME box jobs there are currently three handling actions available:
:class:`x2go.mimeboxactions.X2GoMIMEboxActionOPEN`, :class:`x2go.mimeboxactions.X2GoMIMEboxActionOPENWITH` and :class:`x2go.mimeboxactions.X2GoMIMEboxActionSAVEAS`.
"""
__NAME__ = 'x2gomimeboxactions-pylib'
__package__ = 'x2go'
__name__ = 'x2go.mimeboxactions'
# modules
import os
import copy
import time
from .defaults import X2GOCLIENT_OS as _X2GOCLIENT_OS
if _X2GOCLIENT_OS in ("Windows"):
import subprocess
import win32api
else:
from . import gevent_subprocess as subprocess
from . import x2go_exceptions
WindowsErrror = x2go_exceptions.WindowsError
# Python X2Go modules
from . import log
from . import x2go_exceptions
_MIMEBOX_ENV = os.environ.copy()
[docs]
class X2GoMIMEboxAction(object):
__name__ = 'NAME'
__description__ = 'DESCRIPTION'
def __init__(self, client_instance=None, logger=None, loglevel=log.loglevel_DEFAULT):
"""\
This is a meta class and has no functionality as such. It is used as parent
class by »real« X2Go MIME box actions.
:param client_instance: the underlying :class:`x2go.client.X2GoClient` instance
:type client_instance: ``obj``
:param logger: you can pass an :class:`x2go.log.X2GoLogger` object to the
:class:`x2go.mimeboxactions.X2GoMIMEboxAction` constructor
:type logger: ``obj``
:param loglevel: if no :class:`x2go.log.X2GoLogger` object has been supplied a new one will be
constructed with the given loglevel
:type loglevel: ``int``
"""
if logger is None:
self.logger = log.X2GoLogger(loglevel=loglevel)
else:
self.logger = copy.deepcopy(logger)
self.logger.tag = __NAME__
# these get set from within the X2GoMIMEboxQueue class
self.profile_name = 'UNKNOWN'
self.session_name = 'UNKNOWN'
self.client_instance = client_instance
@property
def name(self):
"""\
Return the X2Go MIME box action's name.
:returns: MIME box action name
:rtype: ``str``
"""
return self.__name__
@property
def description(self):
"""\
Return the X2Go MIME box action's description text.
:returns: MIME box action's description
:rtype: ``str``
"""
return self.__description__
def _do_process(self, mimebox_file, mimebox_dir, ):
"""\
Perform the defined MIME box action (doing nothing in :class:`x2go.mimeboxactions.X2GoMIMEboxAction` parent class).
:param mimebox_file: file name as placed in to the X2Go MIME box directory
:type mimebox_file: ``str``
:param mimebox_dir: location of the X2Go session's MIME box directory
:type mimebox_dir: ``str``
"""
pass
[docs]
def do_process(self, mimebox_file, mimebox_dir, ):
"""\
Wrapper method for the actual processing of MIME
box actions.
:param mimebox_file: file name as placed in to the X2Go MIME box directory
:type mimebox_file: ``str``
:param mimebox_dir: location of the X2Go session's MIME box directory
:type mimebox_dir: ``str``
"""
mimebox_file = os.path.normpath(mimebox_file)
mimebox_dir = os.path.normpath(mimebox_dir)
self._do_process(mimebox_file, mimebox_dir)
[docs]
class X2GoMIMEboxActionOPEN(X2GoMIMEboxAction):
"""\
MIME box action that opens incoming files in the system's default application.
"""
__name__= 'OPEN'
__decription__= 'Open incoming file with local system\'s default application.'
def __init__(self, client_instance=None, logger=None, loglevel=log.loglevel_DEFAULT):
"""\
:param client_instance: the underlying :class:`x2go.client.X2GoClient` instance
:type client_instance: ``obj``
:param logger: you can pass an :class:`x2go.log.X2GoLogger` object to the
:class:`x2go.mimeboxactions.X2GoMIMEboxActionOPEN` constructor
:type logger: ``obj``
:param loglevel: if no :class:`x2go.log.X2GoLogger` object has been supplied a new one will be
constructed with the given loglevel
:type loglevel: ``int``
"""
self.client_instance = client_instance
X2GoMIMEboxAction.__init__(self, logger=logger, loglevel=loglevel)
def _do_process(self, mimebox_file, mimebox_dir, ):
"""\
Open an incoming MIME box file in the system's default application.
:param mimebox_file: file name as placed in to the MIME box directory
:type mimebox_file: ``str``
:param mimebox_dir: location of the X2Go session's MIME box directory
:type mimebox_dir: ``str``
"""
mimebox_file = os.path.normpath(mimebox_file)
mimebox_dir = os.path.normpath(mimebox_dir)
if _X2GOCLIENT_OS == "Windows":
self.logger('opening incoming MIME box file with Python\'s os.startfile() command: %s' % mimebox_file, loglevel=log.loglevel_DEBUG)
try:
os.startfile(os.path.join(mimebox_dir, mimebox_file))
except WindowsError as win_err:
if self.client_instance:
self.client_instance.HOOK_mimeboxaction_error(mimebox_file,
profile_name=self.profile_name,
session_name=self.session_name,
err_msg=str(win_err)
)
else:
self.logger('Encountered WindowsError: %s' % str(win_err), loglevel=log.loglevel_ERROR)
time.sleep(20)
else:
cmd_line = [ 'xdg-open', os.path.join(mimebox_dir, mimebox_file), ]
self.logger('opening MIME box file with command: %s' % ' '.join(cmd_line), loglevel=log.loglevel_DEBUG)
subprocess.Popen(cmd_line, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=_MIMEBOX_ENV)
time.sleep(20)
[docs]
class X2GoMIMEboxActionOPENWITH(X2GoMIMEboxAction):
"""\
MIME box action that calls the system's ,,Open with...'' dialog on incoming files. Currently only
properly implementable on Windows platforms.
"""
__name__= 'OPENWITH'
__decription__= 'Evoke ,,Open with...\'\' dialog on incoming MIME box files.'
def __init__(self, client_instance=None, logger=None, loglevel=log.loglevel_DEFAULT):
"""\
:param client_instance: the underlying :class:`x2go.client.X2GoClient` instance
:type client_instance: ``obj``
:param logger: you can pass an :class:`x2go.log.X2GoLogger` object to the
:class:`x2go.mimeboxactions.X2GoMIMEboxActionOPENWITH` constructor
:type logger: ``obj``
:param loglevel: if no :class:`x2go.log.X2GoLogger` object has been supplied a new one will be
constructed with the given loglevel
:type loglevel: ``int``
"""
self.client_instance = client_instance
X2GoMIMEboxAction.__init__(self, logger=logger, loglevel=loglevel)
def _do_process(self, mimebox_file, mimebox_dir, ):
"""\
Open an incoming MIME box file in the system's default application.
:param mimebox_file: file name as placed in to the MIME box directory
:type mimebox_file: ``str``
:param mimebox_dir: location of the X2Go session's MIME box directory
:type mimebox_dir: ``str``
"""
mimebox_file = os.path.normpath(mimebox_file)
mimebox_dir = os.path.normpath(mimebox_dir)
if _X2GOCLIENT_OS == "Windows":
self.logger('evoking Open-with dialog on incoming MIME box file: %s' % mimebox_file, loglevel=log.loglevel_DEBUG)
win32api.ShellExecute (
0,
"open",
"rundll32.exe",
"shell32.dll,OpenAs_RunDLL %s" % os.path.join(mimebox_dir, mimebox_file),
None,
0,
)
time.sleep(20)
else:
self.logger('the evocation of the Open-with dialog box is currently not available on Linux, falling back to MIME box action OPEN', loglevel=log.loglevel_WARN)
cmd_line = [ 'xdg-open', os.path.join(mimebox_dir, mimebox_file), ]
self.logger('opening MIME box file with command: %s' % ' '.join(cmd_line), loglevel=log.loglevel_DEBUG)
subprocess.Popen(cmd_line, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=_MIMEBOX_ENV)
time.sleep(20)
[docs]
class X2GoMIMEboxActionSAVEAS(X2GoMIMEboxAction):
"""\
MIME box action that allows saving incoming MIME box files to a local folder. What this
MIME box actually does is calling a hook method in the :class:`x2go.client.X2GoClient` instance that
can be hi-jacked by one of your application's methods which then can handle the ,,Save as...''
request.
"""
__name__ = 'SAVEAS'
__decription__= 'Save incoming file as...'
def __init__(self, client_instance=None, logger=None, loglevel=log.loglevel_DEFAULT):
"""\
:param client_instance: an :class:`x2go.client.X2GoClient` instance, within your customized :class:`x2go.client.X2GoClient` make sure
you have a ``HOOK_open_mimebox_saveas_dialog(filename=<str>)`` method defined that will actually
handle the incoming mimebox file.
:type client_instance: ``obj``
:param logger: you can pass an :class:`x2go.log.X2GoLogger` object to the
:class:`x2go.mimeboxactions.X2GoMIMEboxActionSAVEAS` constructor
:type logger: ``obj``
:param loglevel: if no :class:`x2go.log.X2GoLogger` object has been supplied a new one will be
constructed with the given loglevel
:type loglevel: ``int``
:raises X2GoMIMEboxActionException: if the client_instance has not been passed to the SAVEAS MIME box action
"""
if client_instance is None:
raise x2go_exceptions.X2GoMIMEboxActionException('the SAVEAS MIME box action needs to know the X2GoClient instance (client=<instance>)')
X2GoMIMEboxAction.__init__(self, client_instance=client_instance, logger=logger, loglevel=loglevel)
def _do_process(self, mimebox_file, mimebox_dir):
"""\
Call an :class:`x2go.client.X2GoClient` hook method (``HOOK_open_mimebox_saveas_dialog``) that
can handle the MIME box's SAVEAS action.
:param mimebox_file: file name as placed in to the MIME box directory
:type mimebox_file: ``str``
:param mimebox_dir: location of the X2Go session's MIME box directory
:type mimebox_dir: ``str``
:param mimebox_file: PDF file name as placed in to the X2Go spool directory
"""
mimebox_file = os.path.normpath(mimebox_file)
mimebox_dir = os.path.normpath(mimebox_dir)
self.logger('Session %s (%s) is calling X2GoClient class hook method <client_instance>.HOOK_open_mimebox_saveas_dialog(%s)' % (self.session_name, self.profile_name, mimebox_file), loglevel=log.loglevel_NOTICE)
self.client_instance.HOOK_open_mimebox_saveas_dialog(os.path.join(mimebox_dir, mimebox_file), profile_name=self.profile_name, session_name=self.session_name)
time.sleep(60)