Example #1
0
	def __init_ui(self):
		self._LCTRL_items.set_columns([_('By'), _('When'), _('Description')])

		self._BTN_archive_items.Disable()

		# there's no GetToolTipText() in wx2.8
		self.__mail_script_exists, path = gmShellAPI.detect_external_binary(binary = r'gm-mail_doc')
		if not self.__mail_script_exists:
			self._BTN_mail_items.Disable()
			tt = self._BTN_mail_items.GetToolTipText() + '\n\n' + _('<gm-mail_doc(.bat) not found>')
			self._BTN_mail_items.SetToolTip(tt)

		self.__fax_script_exists, path = gmShellAPI.detect_external_binary(binary = r'gm-fax_doc')
		if not self.__fax_script_exists:
			self._BTN_fax_items.Disable()
			tt = self._BTN_fax_items.GetToolTipText() + '\n\n' + _('<gm-fax_doc(.bat) not found>')
			self._BTN_fax_items.SetToolTip(tt)

		self.__burn_script_exists, path = gmShellAPI.detect_external_binary(binary = r'gm-burn_doc')
		if not self.__burn_script_exists:
			self._BTN_burn_items.Disable()
			tt = self._BTN_burn_items.GetToolTipText() + '\n\n' + _('<gm-burn_doc(.bat) not found>')
			self._BTN_burn_items.SetToolTip(tt)

		# make me and listctrl file drop targets
		dt = gmGuiHelpers.cFileDropTarget(target = self)
		self.SetDropTarget(dt)
		dt = gmGuiHelpers.cFileDropTarget(on_drop_callback = self._drop_target_consume_filenames)
		self._LCTRL_items.SetDropTarget(dt)
Example #2
0
	def __init__(self):
		# detect KOrganizer
		found, cmd = gmShellAPI.detect_external_binary(binary = u'konsolekalendar')
		if not found:
			raise gmExceptions.ConstructorError('cannot detect "konsolekalendar" via [%s]' % cmd)

		gmPlugin.cNotebookPlugin.__init__(self)
Example #3
0
	def _on_mail_items_button_pressed(self, event):
		event.Skip()

		_log.debug('gm-mail_doc(.bat) API: "MAIL-PROGRAM PRAXIS-VCF ZIP-ARCHIVE"')

		found, external_cmd = gmShellAPI.detect_external_binary('gm-mail_doc')
		if not found:
			gmDispatcher.send(signal = 'statustext', msg = _('Cannot send e-mail: <gm-mail_doc(.bat)> not found'))
			return False

		zip_file = self.__export_as_zip (
			_('Mailing documents as zip archive'),
			encrypt = True
		)
		if zip_file is None:
			gmDispatcher.send(signal = 'statustext', msg = _('Cannot send e-mail: no archive created.'))
			return False

		prax = gmPraxis.gmCurrentPraxisBranch()
		args = [external_cmd, prax.vcf, zip_file]
		success, ret_code, stdout = gmShellAPI.run_process(cmd_line = args, verbose = _cfg.get(option = 'debug'))
		if not success:
			gmGuiHelpers.gm_show_error (
				aMessage = _('Error mailing documents.'),
				aTitle = _('Mailing documents')
			)
			return False

		self.__save_soap_note(soap = _('Mailed:\n - %s') % '\n - '.join([ i['description'] for i in items ]))
		return True
Example #4
0
def decrypt_pdf(filename: str = None,
                passphrase: str = None,
                verbose: bool = False) -> str:
    assert (filename is not None), '<filename> must not be None'
    assert (passphrase is not None), '<passphrase> must not be None'

    gmLog2.add_word2hide(passphrase)
    _log.debug('attempting PDF decryption')
    for cmd in ['qpdf', 'qpdf.exe']:
        found, binary = gmShellAPI.detect_external_binary(binary=cmd)
        if found:
            break
    if not found:
        _log.warning('no qpdf binary found')
        return None

    filename_decrypted = '%s.decrypted.pdf' % os.path.splitext(filename)[0]
    args = [
        binary, '--verbose', '--password-mode=unicode', '--decrypt',
        '--password=%s' % passphrase, '--', filename, filename_decrypted
    ]
    success, exit_code, stdout = gmShellAPI.run_process(
        cmd_line=args,
        encoding='utf8',
        verbose=verbose,
        acceptable_return_codes=[0, 3])
    if not success:
        return None

    return filename_decrypted
Example #5
0
def encrypt_pdf(filename=None, passphrase=None, verbose=False):
	assert (filename is not None), '<filename> must not be None'
	assert (passphrase is not None), '<passphrase> must not be None'

	if len(passphrase) < 5:
		_log.error('<passphrase> must be at least 5 characters/signs/digits')
		return None
	gmLog2.add_word2hide(passphrase)

	_log.debug('attempting PDF encryption')
	for cmd in ['qpdf', 'qpdf.exe']:
		found, binary = gmShellAPI.detect_external_binary(binary = cmd)
		if found:
			break
	if not found:
		_log.warning('no qpdf binary found')
		return None

	filename_encrypted = '%s.encrypted.pdf' % os.path.splitext(filename)[0]
	args = [
		binary,
		'--verbose',
		'--encrypt', passphrase, '', '128',
		'--print=full', '--modify=none', '--extract=n',
		'--use-aes=y',
		'--',
		filename,
		filename_encrypted
	]
	success, exit_code, stdout = gmShellAPI.run_process(cmd_line = args, encoding = 'utf8', verbose = verbose)
	if success:
		return filename_encrypted
	return None
Example #6
0
    def _on_mail_items_button_pressed(self, event):
        event.Skip()

        items = self._LCTRL_items.get_selected_item_data(only_one=False)
        if len(items) == 0:
            return True

        found, external_cmd = gmShellAPI.detect_external_binary('gm-mail_doc')
        if not found:
            return False

        files2mail = []
        for item in items:
            files2mail.append(item.save_to_file())

        cmd = '%s %s' % (external_cmd, ' '.join(files2mail))
        if os.name == 'nt':
            blocking = True
        else:
            blocking = False
        success = gmShellAPI.run_command_in_shell(command=cmd,
                                                  blocking=blocking)
        if not success:
            gmGuiHelpers.gm_show_error(aMessage=_('Error mailing documents.'),
                                       aTitle=_('Mailing documents'))
            return False

        self.save_soap_note(soap=_('Mailed:\n - %s') %
                            '\n - '.join([i['description'] for i in items]))
        return True
Example #7
0
    def __init_ui(self):
        self._LCTRL_items.set_columns([_('By'), _('When'), _('Description')])

        self._BTN_archive_items.Disable()

        # there's no GetToolTipString() in wx2.8
        self.__mail_script_exists, path = gmShellAPI.detect_external_binary(
            binary=r'gm-mail_doc')
        if not self.__mail_script_exists:
            self._BTN_mail_items.Disable()
            try:
                tt = self._BTN_mail_items.GetToolTipString() + u'\n\n' + _(
                    '<gm-mail_doc(.bat) not found>')
            except AttributeError:
                tt = _('<gm-mail_doc(.bat) not found>')
            self._BTN_mail_items.SetToolTipString(tt)

        self.__fax_script_exists, path = gmShellAPI.detect_external_binary(
            binary=r'gm-fax_doc')
        if not self.__fax_script_exists:
            self._BTN_fax_items.Disable()
            try:
                tt = self._BTN_fax_items.GetToolTipString() + u'\n\n' + _(
                    '<gm-fax_doc(.bat) not found>')
            except AttributeError:
                tt = _('<gm-fax_doc(.bat) not found>')
            self._BTN_fax_items.SetToolTipString(tt)

        self.__burn_script_exists, path = gmShellAPI.detect_external_binary(
            binary=r'gm-burn_doc')
        if not self.__burn_script_exists:
            self._BTN_burn_items.Disable()
            try:
                tt = self._BTN_burn_items.GetToolTipString() + u'\n\n' + _(
                    '<gm-burn_doc(.bat) not found>')
            except AttributeError:
                tt = _('<gm-burn_doc(.bat) not found>')
            self._BTN_burn_items.SetToolTipString(tt)

        # make me and listctrl a file drop target
        dt = gmGuiHelpers.cFileDropTarget(self)
        self.SetDropTarget(dt)
        dt = gmGuiHelpers.cFileDropTarget(self._LCTRL_items)
        self._LCTRL_items.SetDropTarget(dt)
        self._LCTRL_items.add_filenames = self.add_filenames_to_listctrl
Example #8
0
    def __init__(self):
        # detect KOrganizer
        found, cmd = gmShellAPI.detect_external_binary(
            binary='konsolekalendar')
        if not found:
            raise gmExceptions.ConstructorError(
                'cannot detect "konsolekalendar" via [%s]' % cmd)

        gmPlugin.cNotebookPlugin.__init__(self)
Example #9
0
    def _on_burn_items_button_pressed(self, event):
        event.Skip()

        found, external_cmd = gmShellAPI.detect_external_binary('gm-burn_doc')
        if not found:
            return False

        items = self._LCTRL_items.get_selected_item_data(only_one=False)
        if len(items) == 0:
            items = self._LCTRL_items.get_item_data()

        base_dir = None
        dlg = wx.DirDialog(
            self,
            message=_(
                'If you wish to include an existing directory select it here:'
            ),
            defaultPath=os.path.join(gmTools.gmPaths().home_dir, 'gnumed'),
            style=wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST)
        choice = dlg.ShowModal()
        path2include = dlg.GetPath()
        if choice == wx.ID_OK:
            if not gmTools.dir_is_empty(path2include):
                base_dir = path2include

        export_dir = gmPerson.gmCurrentPatient().export_area.export(
            base_dir=base_dir, items=items, with_metadata=True)
        if export_dir is None:
            return False

        cmd = u'%s %s' % (external_cmd, export_dir)
        if os.name == 'nt':
            blocking = True
        else:
            blocking = False
        success = gmShellAPI.run_command_in_shell(command=cmd,
                                                  blocking=blocking)
        if not success:
            gmGuiHelpers.gm_show_error(
                aMessage=_('Error burning documents to CD/DVD.'),
                aTitle=_('Burning documents'))
            return False

        self.save_soap_note(soap=_('Burned onto CD/DVD:\n - %s') %
                            u'\n - '.join([i['description'] for i in items]))

        browse_index = gmGuiHelpers.gm_show_question(
            title=title,
            question=_('Browse patient data pack ?'),
            cancel_button=False)
        if browse_index:
            gmNetworkTools.open_url_in_browser(
                url=u'file://%s' % os.path.join(export_dir, u'index.html'))

        return True
Example #10
0
def aes_encrypt_file(filename=None,
                     passphrase=None,
                     comment=None,
                     verbose=False,
                     remove_unencrypted=False):
    assert (filename is not None), '<filename> must not be None'
    assert (passphrase is not None), '<passphrase> must not be None'

    if len(passphrase) < 5:
        _log.error('<passphrase> must be at least 5 characters/signs/digits')
        return None
    gmLog2.add_word2hide(passphrase)

    #add 7z/winzip url to comment.txt
    _log.debug('attempting 7z AES encryption')
    for cmd in ['7z', '7z.exe']:
        found, binary = gmShellAPI.detect_external_binary(binary=cmd)
        if found:
            break
    if not found:
        _log.warning('no 7z binary found, trying gpg')
        return None

    if comment is not None:
        archive_path, archive_name = os.path.split(os.path.abspath(filename))
        comment_filename = gmTools.get_unique_filename(
            prefix='%s.7z.comment-' % archive_name,
            tmp_dir=archive_path,
            suffix='.txt')
        with open(comment_filename,
                  mode='wt',
                  encoding='utf8',
                  errors='replace') as comment_file:
            comment_file.write(comment)
    else:
        comment_filename = ''
    filename_encrypted = '%s.7z' % filename
    args = [
        binary, 'a', '-bb3', '-mx0',
        "-p%s" % passphrase, filename_encrypted, filename, comment_filename
    ]
    encrypted, exit_code, stdout = gmShellAPI.run_process(cmd_line=args,
                                                          encoding='utf8',
                                                          verbose=verbose)
    gmTools.remove_file(comment_filename)
    if not encrypted:
        return None
    if not remove_unencrypted:
        return filename_encrypted
    if gmTools.remove_file(filename):
        return filename_encrypted
    gmTools.remove_file(filename_encrypted)
    return None
Example #11
0
	def _on_fax_items_button_pressed(self, event):
		event.Skip()

		_log.debug('gm-fax_doc(.bat) API: "FAX-PROGRAM FAXNUMBER-OR-<EMPTY> LIST-OF-FILES-TO-FAX" (any file type !)')

		found, external_cmd = gmShellAPI.detect_external_binary('gm-fax_doc')
		if not found:
			gmDispatcher.send(signal = 'statustext', msg = _('Cannot send fax: <gm-fax_doc(.bat)> not found'))
			return False

		items = self._LCTRL_items.get_selected_item_data(only_one = False)
		if len(items) == 0:
			items = self._LCTRL_items.get_item_data()
			if len(items) == 0:
				gmDispatcher.send(signal = 'statustext', msg = _('Cannot send fax: no items'))
				return None
			if len(items) > 1:
				# ask, might be a lot
				process_all = gmGuiHelpers.gm_show_question (
					title = _('Faxing documents'),
					question = _('You have not selected any entries.\n\nSend fax with all %s entries ?') % len(items),
					cancel_button = False
				)
				if not process_all:
					return None

			return False

		files2fax = []
		for item in items:
			files2fax.append(item.save_to_file())
		fax_number = wx.GetTextFromUser (
			_('Please enter the fax number here !\n\n'
			  'It can be left empty if the external\n'
			  'fax software knows how to get the number.'),
			caption = _('Faxing documents'),
			parent = self,
			centre = True
		)
		if fax_number == '':
			fax_number = 'EMPTY'
		args = [external_cmd, fax_number, ' '.join(files2fax)]
		success, ret_code, stdout = gmShellAPI.run_process(cmd_line = args, verbose = _cfg.get(option = 'debug'))
		if not success:
			gmGuiHelpers.gm_show_error (
				aMessage = _('Error faxing documents to\n\n  %s') % fax_number,
				aTitle = _('Faxing documents')
			)
			return False

		self.__save_soap_note(soap = _('Faxed to [%s]:\n - %s') % (fax_number, '\n - '.join([ i['description'] for i in items ])))
		return True
Example #12
0
def encrypt_pdf(filename: str = None,
                passphrase: str = None,
                verbose: bool = False,
                remove_unencrypted: bool = False) -> str:
    """Encrypt a PDF file per spec (AES, that is).

	Args:
		filename: PDF file to encrypt
		passphrase: minimum of 5 characters
		remove_unencrypted: remove unencrypted source file if encryption succeeds

	Returns:
		Name of encrypted PDF or None.
	"""
    assert (filename is not None), '<filename> must not be None'
    assert (passphrase is not None), '<passphrase> must not be None'
    if len(passphrase) < 5:
        _log.error('<passphrase> must be at least 5 characters/signs/digits')
        return None

    gmLog2.add_word2hide(passphrase)
    _log.debug('attempting PDF encryption')
    for cmd in ['qpdf', 'qpdf.exe']:
        found, binary = gmShellAPI.detect_external_binary(binary=cmd)
        if found:
            break
    if not found:
        _log.warning('no qpdf binary found')
        return None

    filename_encrypted = '%s.encrypted.pdf' % os.path.splitext(filename)[0]
    args = [
        binary, '--verbose', '--password-mode=unicode', '--encrypt',
        passphrase, '', '128', '--print=full', '--modify=none', '--extract=n',
        '--use-aes=y', '--', filename, filename_encrypted
    ]
    success, exit_code, stdout = gmShellAPI.run_process(
        cmd_line=args,
        encoding='utf8',
        verbose=verbose,
        acceptable_return_codes=[0, 3])
    if not success:
        return None

    if not remove_unencrypted:
        return filename_encrypted

    if gmTools.remove_file(filename):
        return filename_encrypted

    gmTools.remove_file(filename_encrypted)
    return None
Example #13
0
    def __init_ui(self):

        self._LBL_dir_is_empty.Label = ''
        self._LBL_subdirectory.Label = ''

        if self.__burn2cd:
            self._LBL_existing_data.Hide()
            self._BTN_browse_directory.Disable()
            self._RBTN_include_data.Hide()
            self._RBTN_remove_data.Hide()
            self._CHBOX_include_directory.Show()
            self._CHBOX_use_subdirectory.Hide()
            self._LBL_subdirectory.Hide()
            self._CHBOX_generate_metadata.Hide()
            lines = [
                _('Preparing patient media for burning onto CD / DVD'), ''
            ]
            found, external_cmd = gmShellAPI.detect_external_binary(
                'gm-burn_doc')
            if not found:
                lines.append(_('Script <gm-burn_doc(.bat)> not found.'))
                lines.append('')
                lines.append(
                    _('Cannot attempt to burn patient media onto CD/DVD.'))
                self._BTN_save.Disable()
            else:
                lines.append(
                    _('Patient: %s') % self.__patient['description_gender'])
                lines.append('')
                lines.append(
                    _('Number of items to export onto CD/DVD: %s\n') %
                    self.__item_count)
            self._LBL_header.Label = '\n'.join(lines)
            return

        lines = [
            _('Preparing patient media for saving to disk (USB, harddrive).'),
            '',
            _('Patient: %s') % self.__patient['description_gender'], '',
            _('Number of items to export to disk: %s\n') % self.__item_count
        ]
        self._LBL_header.Label = '\n'.join(lines)
        self._LBL_directory.Label = os.path.join(gmTools.gmPaths().home_dir,
                                                 'gnumed')
        self.__refresh_dir_is_empty()
Example #14
0
def gpg_decrypt_file(filename=None, verbose=False, target_ext=None):
	"""The system is expected to be set up for safely getting the
	   passphrase from the user, typically via gpg-agent.
	"""
	assert (filename is not None), '<filename> must not be None'

	_log.debug('attempting GPG decryption')
	for cmd in ['gpg2', 'gpg', 'gpg2.exe', 'gpg.exe']:
		found, binary = gmShellAPI.detect_external_binary(binary = cmd)
		if found:
			break
	if not found:
		_log.warning('no gpg binary found')
		return None

	basename = os.path.splitext(filename)[0]
	filename_decrypted = gmTools.get_unique_filename(prefix = '%s-decrypted-' % basename, suffix = target_ext)
	args = [
		binary,
		'--utf8-strings',
		'--display-charset', 'utf-8',
		'--batch',
		'--no-greeting',
		'--enable-progress-filter',
		'--decrypt',
		'--output', filename_decrypted
		##'--use-embedded-filename'				# not all encrypted files carry a filename
	]
	if verbose:
		args.extend ([
			'--verbose', '--verbose',
			'--debug-level', '8',
			'--debug', 'packet,mpi,crypto,filter,iobuf,memory,cache,memstat,trust,hashing,clock,lookup,extprog'
			##'--debug-all',						# will log passphrase
			##'--debug, 'ipc',						# will log passphrase
			##'--debug-level', 'guru',				# will log passphrase
			##'--debug-level', '9',					# will log passphrase
		])
	args.append(filename)
	success, exit_code, stdout = gmShellAPI.run_process(cmd_line = args, verbose = verbose, encoding = 'utf-8')
	if success:
		return filename_decrypted
	return None
Example #15
0
def aes_encrypt_file(filename=None, passphrase=None, comment=None, verbose=False, remove_unencrypted=False):
	assert (filename is not None), '<filename> must not be None'
	assert (passphrase is not None), '<passphrase> must not be None'

	if len(passphrase) < 5:
		_log.error('<passphrase> must be at least 5 characters/signs/digits')
		return None
	gmLog2.add_word2hide(passphrase)

	#add 7z/winzip url to comment.txt
	_log.debug('attempting 7z AES encryption')
	for cmd in ['7z', '7z.exe']:
		found, binary = gmShellAPI.detect_external_binary(binary = cmd)
		if found:
			break
	if not found:
		_log.warning('no 7z binary found, trying gpg')
		return None

	if comment is not None:
		archive_path, archive_name = os.path.split(os.path.abspath(filename))
		comment_filename = gmTools.get_unique_filename (
			prefix = '%s.7z.comment-' % archive_name,
			tmp_dir = archive_path,
			suffix = '.txt'
		)
		with open(comment_filename, mode = 'wt', encoding = 'utf8', errors = 'replace') as comment_file:
			comment_file.write(comment)
	else:
		comment_filename = ''
	filename_encrypted = '%s.7z' % filename
	args = [binary, 'a', '-bb3', '-mx0', "-p%s" % passphrase, filename_encrypted, filename, comment_filename]
	encrypted, exit_code, stdout = gmShellAPI.run_process(cmd_line = args, encoding = 'utf8', verbose = verbose)
	gmTools.remove_file(comment_filename)
	if not encrypted:
		return None
	if not remove_unencrypted:
		return filename_encrypted
	if gmTools.remove_file(filename):
		return filename_encrypted
	gmTools.remove_file(filename_encrypted)
	return None
Example #16
0
def gpg_decrypt_file(filename=None, passphrase=None, verbose=False, target_ext=None):
	assert (filename is not None), '<filename> must not be None'

	_log.debug('attempting GPG decryption')
	for cmd in ['gpg2', 'gpg', 'gpg2.exe', 'gpg.exe']:
		found, binary = gmShellAPI.detect_external_binary(binary = cmd)
		if found:
			break
	if not found:
		_log.warning('no gpg binary found')
		return None

	basename = os.path.splitext(filename)[0]
	filename_decrypted = gmTools.get_unique_filename(prefix = '%s-decrypted-' % basename, suffix = target_ext)
	args = [
		binary,
		'--utf8-strings',
		'--display-charset', 'utf-8',
		'--batch',
		'--no-greeting',
		'--enable-progress-filter',
		'--decrypt',
		'--output', filename_decrypted
		##'--use-embedded-filename'				# not all encrypted files carry a filename
	]
	if verbose:
		args.extend ([
			'--verbose', '--verbose',
			'--debug-level', '8',
			'--debug', 'packet,mpi,crypto,filter,iobuf,memory,cache,memstat,trust,hashing,clock,lookup,extprog'
			##'--debug-all',						# will log passphrase
			##'--debug, 'ipc',						# will log passphrase
			##'--debug-level', 'guru',				# will log passphrase
			##'--debug-level', '9',					# will log passphrase
		])
	args.append(filename)
	success, exit_code, stdout = gmShellAPI.run_process(cmd_line = args, verbose = verbose, encoding = 'utf-8')
	if success:
		return filename_decrypted
	return None
Example #17
0
def is_encrypted_pdf(filename: str = None, verbose: bool = False) -> bool:
    """Check encryption status of PDF.

	Requires qpdf to be installed.

	Returns:
		True/False/None: None -- unknown or not PDF
	"""
    assert (filename is not None), '<filename> must not be None'

    mimetype = gmMimeLib.guess_mimetype(filename=filename)
    if mimetype != 'application/pdf':
        _log.info('not a PDF')
        return None

    _log.debug('checking PDF encryption')
    for cmd in ['qpdf', 'qpdf.exe']:
        found, binary = gmShellAPI.detect_external_binary(binary=cmd)
        if found:
            break
    if not found:
        _log.warning('no qpdf binary found')
        return None

    args = [binary, '--verbose', '--is-encrypted', '--', filename]
    success, exit_code, stdout = gmShellAPI.run_process(
        cmd_line=args,
        encoding='utf8',
        verbose=verbose,
        acceptable_return_codes=[0, 2])
    if not success:
        return None

    if exit_code == 0:
        return True

    if exit_code == 2:
        return False

    return None
Example #18
0
    def _on_fax_items_button_pressed(self, event):
        event.Skip()

        items = self._LCTRL_items.get_selected_item_data(only_one=False)
        if len(items) == 0:
            return

        found, external_cmd = gmShellAPI.detect_external_binary('gm-fax_doc')
        if not found:
            return False

        files2fax = []
        for item in items:
            files2fax.append(item.save_to_file())

        fax_number = wx.GetTextFromUser(_(
            'Please enter the fax number here !\n\n'
            'It can be left empty if the external\n'
            'fax software knows how to get the number.'),
                                        caption=_('Faxing documents'),
                                        parent=self,
                                        centre=True)

        cmd = '%s "%s" %s' % (external_cmd, fax_number, ' '.join(files2fax))
        if os.name == 'nt':
            blocking = True
        else:
            blocking = False
        success = gmShellAPI.run_command_in_shell(command=cmd,
                                                  blocking=blocking)
        if not success:
            gmGuiHelpers.gm_show_error(
                aMessage=_('Error faxing documents to\n\n  %s') % fax_number,
                aTitle=_('Faxing documents'))
            return False

        self.save_soap_note(
            soap=_('Faxed to [%s]:\n - %s') %
            (fax_number, '\n - '.join([i['description'] for i in items])))
        return True
Example #19
0
def _get_system_startfile_cmd(filename):

    global _system_startfile_cmd

    if _system_startfile_cmd == '':
        return False, None

    if _system_startfile_cmd is not None:
        return True, _system_startfile_cmd % filename

    open_cmd_candidates = list(open_cmds)

    for candidate in open_cmd_candidates:
        found, binary = gmShellAPI.detect_external_binary(binary=candidate)
        if not found:
            continue
        _system_startfile_cmd = open_cmds[candidate]
        _log.info('detected local startfile cmd: [%s]', _system_startfile_cmd)
        return True, _system_startfile_cmd % filename

    _system_startfile_cmd = ''
    return False, None
Example #20
0
def _get_system_startfile_cmd(filename):

	global _system_startfile_cmd

	if _system_startfile_cmd == '':
		return False, None

	if _system_startfile_cmd is not None:
		return True, _system_startfile_cmd % filename

	open_cmd_candidates = open_cmds.keys()

	for candidate in open_cmd_candidates:
		found, binary = gmShellAPI.detect_external_binary(binary = candidate)
		if not found:
			continue
		_system_startfile_cmd = open_cmds[candidate]
		_log.info('detected local startfile cmd: [%s]', _system_startfile_cmd)
		return True, _system_startfile_cmd % filename

	_system_startfile_cmd = ''
	return False, None
Example #21
0
    def is_valid(value):

        if value is None:
            gmDispatcher.send(signal='statustext',
                              msg=_('You need to actually set an editor.'),
                              beep=True)
            return False, value

        if value.strip() == u'':
            gmDispatcher.send(signal='statustext',
                              msg=_('You need to actually set an editor.'),
                              beep=True)
            return False, value

        found, binary = gmShellAPI.detect_external_binary(value)
        if not found:
            gmDispatcher.send(signal='statustext',
                              msg=_('The command [%s] is not found.') % value,
                              beep=True)
            return True, value

        return True, binary
Example #22
0
	def __burn_dir_to_disk(self, base_dir):

		_log.debug('gm-burn_doc(.bat) API: "DIRECTORY-TO-BURN-FROM"')

		found, burn_cmd = gmShellAPI.detect_external_binary('gm-burn_doc')
		if not found:
			gmDispatcher.send(signal = 'statustext', msg = _('Cannot burn to disk: Helper not found.'))	# should not happen
			return False

		args = [burn_cmd, base_dir]
		wx.BeginBusyCursor()
		try:
			success, ret_code, stdout = gmShellAPI.run_process(cmd_line = args, verbose = _cfg.get(option = 'debug'))
		finally:
			wx.EndBusyCursor()
		if success:
			return True

		gmGuiHelpers.gm_show_error (
			aMessage = _('Error burning documents to CD/DVD.'),
			aTitle = _('Burning documents')
		)
		return False
Example #23
0
	def __detect_binary(self):

		if self.path_to_binary is not None:
			return True

		found, cmd = gmShellAPI.find_first_binary(binaries = [
			r'/usr/bin/freediams',
			r'freediams',
			r'/Applications/FreeDiams.app/Contents/MacOs/FreeDiams',
			r'C:\Program Files (x86)\FreeDiams\freediams.exe',
			r'C:\Program Files\FreeDiams\freediams.exe',
			r'c:\programs\freediams\freediams.exe',
			r'freediams.exe'
		])

		if found:
			self.path_to_binary = cmd
			return True

		try:
			self.custom_path_to_binary
		except AttributeError:
			_log.error('cannot find FreeDiams binary, no custom path set')
			return False

		if self.custom_path_to_binary is None:
			_log.error('cannot find FreeDiams binary')
			return False

		found, cmd = gmShellAPI.detect_external_binary(binary = self.custom_path_to_binary)
		if found:
			self.path_to_binary = cmd
			return True

		_log.error('cannot find FreeDiams binary')
		return False
Example #24
0
	def __detect_binary(self):

		if self.path_to_binary is not None:
			return True

		found, cmd = gmShellAPI.find_first_binary(binaries = [
			r'/usr/bin/freediams',
			r'freediams',
			r'/Applications/FreeDiams.app/Contents/MacOs/FreeDiams',
			r'C:\Program Files (x86)\FreeDiams\freediams.exe',
			r'C:\Program Files\FreeDiams\freediams.exe',
			r'c:\programs\freediams\freediams.exe',
			r'freediams.exe'
		])

		if found:
			self.path_to_binary = cmd
			return True

		try:
			self.custom_path_to_binary
		except AttributeError:
			_log.error('cannot find FreeDiams binary, no custom path set')
			return False

		if self.custom_path_to_binary is None:
			_log.error('cannot find FreeDiams binary')
			return False

		found, cmd = gmShellAPI.detect_external_binary(binary = self.custom_path_to_binary)
		if found:
			self.path_to_binary = cmd
			return True

		_log.error('cannot find FreeDiams binary')
		return False
Example #25
0
def encrypt_file_symmetric_7z(filename: str = None,
                              passphrase: str = None,
                              comment: str = None,
                              verbose: bool = False,
                              remove_unencrypted: bool = False) -> str:
    """Encrypt a file symmetrically with 7zip.

	Args:
		filename: the file to encrypt
		passphrase: minimum of 5 characters
		comment: a comment on the file to be put into a sidecar file, will also be encrypted
		remove_unencrypted: remove unencrypted source file if encryption succeeded

	Returns:
		Name of encrypted file or None.
	"""
    assert (filename is not None), '<filename> must not be None'
    assert (passphrase is not None), '<passphrase> must not be None'
    if len(passphrase) < 5:
        _log.error('<passphrase> must be at least 5 characters/signs/digits')
        return None

    gmLog2.add_word2hide(passphrase)

    #add 7z/winzip url to comment.txt
    _log.debug('attempting 7z AES encryption')
    for cmd in ['7z', '7z.exe']:
        found, binary = gmShellAPI.detect_external_binary(binary=cmd)
        if found:
            break
    if not found:
        _log.warning('no 7z binary found, trying gpg')
        return None

    if comment is not None:
        archive_path, archive_name = os.path.split(os.path.abspath(filename))
        comment_filename = gmTools.get_unique_filename(
            prefix='%s.7z.comment-' % archive_name,
            tmp_dir=archive_path,
            suffix='.txt')
        with open(comment_filename,
                  mode='wt',
                  encoding='utf8',
                  errors='replace') as comment_file:
            comment_file.write(comment)
    else:
        comment_filename = ''
    filename_encrypted = '%s.7z' % filename
    args = [
        binary, 'a', '-bb3', '-mx0',
        "-p%s" % passphrase, filename_encrypted, filename, comment_filename
    ]
    encrypted, exit_code, stdout = gmShellAPI.run_process(cmd_line=args,
                                                          encoding='utf8',
                                                          verbose=verbose)
    gmTools.remove_file(comment_filename)
    if not encrypted:
        return None

    if not remove_unencrypted:
        return filename_encrypted

    if gmTools.remove_file(filename):
        return filename_encrypted

    gmTools.remove_file(filename_encrypted)
    return None
Example #26
0
def encrypt_file_symmetric_gpg(filename=None,
                               comment=None,
                               verbose=False,
                               passphrase=None,
                               remove_unencrypted=False) -> str:
    """Encrypt file symmetrically with GPG.

	Args:
		filename: the file to encrypt
		passphrase: minimum of 5 characters if given
		comment: a comment on the file to be put into a sidecar file, will also be encrypted
		remove_unencrypted: remove unencrypted source file if encryption succeeded

	Returns:
		Name of encrypted file or None.
	"""
    #add short decr instr to comment
    assert (filename is not None), '<filename> must not be None'
    if passphrase is not None:
        if len(passphrase) < 5:
            _log.error(
                '<passphrase> must be at least 5 characters/signs/digits')
            return None

    _log.debug('attempting symmetric GPG encryption')
    for cmd in ['gpg2', 'gpg', 'gpg2.exe', 'gpg.exe']:
        found, binary = gmShellAPI.detect_external_binary(binary=cmd)
        if found:
            break
    if not found:
        _log.warning('no gpg binary found')
        return None

    filename_encrypted = filename + '.asc'
    args = [
        binary, '--utf8-strings', '--display-charset', 'utf-8', '--batch',
        '--no-greeting', '--enable-progress-filter', '--symmetric',
        '--cipher-algo', 'AES256', '--armor', '--output', filename_encrypted
    ]
    if comment is not None:
        args.extend(['--comment', comment])
    if verbose:
        args.extend([
            '--verbose',
            '--verbose',
            '--debug-level',
            '8',
            '--debug',
            'packet,mpi,crypto,filter,iobuf,memory,cache,memstat,trust,hashing,clock,lookup,extprog',
            ##'--debug-all',						# will log passphrase
            ##'--debug, 'ipc',						# will log passphrase
            ##'--debug-level', 'guru',				# will log passphrase
            ##'--debug-level', '9',					# will log passphrase
        ])
    pwd_fname = None
    if passphrase is not None:
        pwd_file = tempfile.NamedTemporaryFile(mode='w+t',
                                               encoding='utf8',
                                               delete=False)
        pwd_fname = pwd_file.name
        args.extend(
            ['--pinentry-mode', 'loopback', '--passphrase-file', pwd_fname])
        pwd_file.write(passphrase)
        pwd_file.close()
    args.append(filename)
    try:
        success, exit_code, stdout = gmShellAPI.run_process(cmd_line=args,
                                                            verbose=verbose,
                                                            encoding='utf-8')
    finally:
        if pwd_fname is not None:
            os.remove(pwd_fname)
    if not success:
        return None

    if not remove_unencrypted:
        return filename_encrypted

    if gmTools.remove_file(filename):
        return filename_encrypted

    gmTools.remove_file(filename_encrypted)
    return None
Example #27
0
def create_encrypted_zip_archive_from_dir(source_dir: str,
                                          comment: str = None,
                                          overwrite: bool = True,
                                          passphrase: str = None,
                                          verbose: bool = False) -> bool:
    """Create encrypted archive of a directory.

	The encrypted archive file will always be named
	"datawrapper.zip" for confidentiality reasons. If callers
	want another name they will have to shutil.move() the zip
	file themselves. This archive will be compressed and
	AES256 encrypted with the given passphrase. Therefore,
	the result will not decrypt with earlier versions of
	unzip software. On Windows, 7z oder WinZip are needed.

	The zip format does not support header encryption thereby
	allowing attackers to gain knowledge of patient details
	by observing the names of files and directories inside
	the encrypted archive. To reduce that attack surface,
	GNUmed will create _another_ zip archive inside
	"datawrapper.zip", which eventually wraps up the patient
	data as "data.zip". That archive is not compressed and
	not encrypted, and can thus be unpacked with any old
	unzipper.

	Note that GNUmed does NOT remember the passphrase for
	you. You will have to take care of that yourself, and
	possibly also safely hand over the passphrase to any
	receivers of the zip archive.

	Args:
		source_dir: the directory to archive and encrypt
		comment: included as a file containing the comment
		overwrite: remove preexisting archive before creation, avoiding *updating* of same, and thereby including unintended data
		passphrase: minimum length of 5 if given

	Returns:
		True / False / None (other error)
	"""
    assert (source_dir is not None), '<source_dir> must not be <None>'
    if len(passphrase) < 5:
        _log.error('<passphrase> must be at least 5 characters/signs/digits')
        return None

    gmLog2.add_word2hide(passphrase)
    source_dir = os.path.abspath(source_dir)
    if not os.path.isdir(source_dir):
        _log.error('<source_dir> does not exist or is not a directory: %s',
                   source_dir)
        return False

    for cmd in ['7z', '7z.exe']:
        found, binary = gmShellAPI.detect_external_binary(binary=cmd)
        if found:
            break
    if not found:
        _log.warning('no 7z binary found')
        return None

    sandbox_dir = gmTools.mk_sandbox_dir()
    archive_path_inner = os.path.join(sandbox_dir, 'data')
    if not gmTools.mkdir(archive_path_inner):
        _log.error('cannot create scratch space for inner achive: %s',
                   archive_path_inner)
    archive_fname_inner = 'data.zip'
    archive_name_inner = os.path.join(archive_path_inner, archive_fname_inner)
    archive_path_outer = gmTools.gmPaths().tmp_dir
    archive_fname_outer = 'datawrapper.zip'
    archive_name_outer = os.path.join(archive_path_outer, archive_fname_outer)
    # remove existing archives so they don't get *updated* rather than newly created
    if overwrite:
        if not gmTools.remove_file(archive_name_inner, force=True):
            _log.error('cannot remove existing archive [%s]',
                       archive_name_inner)
            return False

        if not gmTools.remove_file(archive_name_outer, force=True):
            _log.error('cannot remove existing archive [%s]',
                       archive_name_outer)
            return False

    # 7z does not support ZIP comments so create a text file holding the comment
    if comment is not None:
        tmp, fname = os.path.split(source_dir.rstrip(os.sep))
        comment_filename = os.path.join(sandbox_dir,
                                        '000-%s-comment.txt' % fname)
        with open(comment_filename,
                  mode='wt',
                  encoding='utf8',
                  errors='replace') as comment_file:
            comment_file.write(comment)

    # create inner (data) archive: uncompressed, unencrypted, similar to a tar archive
    args = [
        binary,
        'a',  # create archive
        '-sas',  # be smart about archive name extension
        '-bd',  # no progress indicator
        '-mx0',  # no compression (only store files)
        '-mcu=on',  # UTF8 filenames
        '-l',  # store content of links, not links
        '-scsUTF-8',  # console charset
        '-tzip'  # force ZIP format
    ]
    if verbose:
        args.append('-bb3')
        args.append('-bt')
    else:
        args.append('-bb1')
    args.append(archive_name_inner)
    args.append(source_dir)
    if comment is not None:
        args.append(comment_filename)
    success, exit_code, stdout = gmShellAPI.run_process(cmd_line=args,
                                                        encoding='utf8',
                                                        verbose=verbose)
    if not success:
        _log.error('cannot create inner archive')
        return None

    # create "decompress instructions" file
    instructions_filename = os.path.join(
        archive_path_inner, '000-on_Windows-open_with-WinZip_or_7z_tools')
    open(instructions_filename, mode='wt').close()

    # create outer (wrapper) archive: compressed, encrypted
    args = [
        binary,
        'a',  # create archive
        '-sas',  # be smart about archive name extension
        '-bd',  # no progress indicator
        '-mx9',  # best available zip compression ratio
        '-mcu=on',  # UTF8 filenames
        '-l',  # store content of links, not links
        '-scsUTF-8',  # console charset
        '-tzip',  # force ZIP format
        '-mem=AES256',  # force useful encryption
        '-p%s' % passphrase  # set passphrase
    ]
    if verbose:
        args.append('-bb3')
        args.append('-bt')
    else:
        args.append('-bb1')
    args.append(archive_name_outer)
    args.append(archive_path_inner)
    success, exit_code, stdout = gmShellAPI.run_process(cmd_line=args,
                                                        encoding='utf8',
                                                        verbose=verbose)
    if success:
        return archive_name_outer

    _log.error('cannot create outer archive')
    return None
Example #28
0
def create_encrypted_zip_archive_from_dir(source_dir, comment=None, overwrite=True, passphrase=None, verbose=False):
	"""Use 7z to create an encrypted ZIP archive of a directory.

	<source_dir>		will be included into the archive
	<comment>			included as a file containing the comment
	<overwrite>			remove existing archive before creation, avoiding
						*updating* of those, and thereby including unintended data
	<passphrase>		minimum length of 5

	The resulting zip archive will always be named
	"datawrapper.zip" for confidentiality reasons. If callers
	want another name they will have to shutil.move() the zip
	file themselves. This archive will be compressed and
	AES256 encrypted with the given passphrase. Therefore,
	the result will not decrypt with earlier versions of
	unzip software. On Windows, 7z oder WinZip are needed.

	The zip format does not support header encryption thereby
	allowing attackers to gain knowledge of patient details
	by observing the names of files and directories inside
	the encrypted archive.

	To reduce that attack surface, GNUmed will create
	_another_ zip archive inside "datawrapper.zip", which
	eventually wraps up the patient data as "data.zip". That
	archive is not compressed and not encrypted, and can thus
	be unpacked with any old unzipper.

	Note that GNUmed does NOT remember the passphrase for
	you. You will have to take care of that yourself, and
	possibly also safely hand over the passphrase to any
	receivers of the zip archive.
	"""
	if len(passphrase) < 5:
		_log.error('<passphrase> must be at least 5 characters/signs/digits')
		return None
	gmLog2.add_word2hide(passphrase)

	source_dir = os.path.abspath(source_dir)
	if not os.path.isdir(source_dir):
		_log.error('<source_dir> does not exist or is not a directory: %s', source_dir)
		return False

	for cmd in ['7z', '7z.exe']:
		found, binary = gmShellAPI.detect_external_binary(binary = cmd)
		if found:
			break
	if not found:
		_log.warning('no 7z binary found')
		return None

	sandbox_dir = gmTools.mk_sandbox_dir()
	archive_path_inner = os.path.join(sandbox_dir, 'data')
	if not gmTools.mkdir(archive_path_inner):
		_log.error('cannot create scratch space for inner achive: %s', archive_path_inner)
	archive_fname_inner = 'data.zip'
	archive_name_inner = os.path.join(archive_path_inner, archive_fname_inner)
	archive_path_outer = gmTools.gmPaths().tmp_dir
	archive_fname_outer = 'datawrapper.zip'
	archive_name_outer = os.path.join(archive_path_outer, archive_fname_outer)
	# remove existing archives so they don't get *updated* rather than newly created
	if overwrite:
		if not gmTools.remove_file(archive_name_inner, force = True):
			_log.error('cannot remove existing archive [%s]', archive_name_inner)
			return False

		if not gmTools.remove_file(archive_name_outer, force = True):
			_log.error('cannot remove existing archive [%s]', archive_name_outer)
			return False

	# 7z does not support ZIP comments so create a text file holding the comment
	if comment is not None:
		tmp, fname = os.path.split(source_dir.rstrip(os.sep))
		comment_filename = os.path.join(sandbox_dir, '000-%s-comment.txt' % fname)
		with open(comment_filename, mode = 'wt', encoding = 'utf8', errors = 'replace') as comment_file:
			comment_file.write(comment)

	# create inner (data) archive: uncompressed, unencrypted, similar to a tar archive
	args = [
		binary,
		'a',				# create archive
		'-sas',				# be smart about archive name extension
		'-bd',				# no progress indicator
		'-mx0',				# no compression (only store files)
		'-mcu=on',			# UTF8 filenames
		'-l',				# store content of links, not links
		'-scsUTF-8',		# console charset
		'-tzip'				# force ZIP format
	]
	if verbose:
		args.append('-bb3')
		args.append('-bt')
	else:
		args.append('-bb1')
	args.append(archive_name_inner)
	args.append(source_dir)
	if comment is not None:
		args.append(comment_filename)
	success, exit_code, stdout = gmShellAPI.run_process(cmd_line = args, encoding = 'utf8', verbose = verbose)
	if not success:
		_log.error('cannot create inner archive')
		return None

	# create "decompress instructions" file
	instructions_filename = os.path.join(archive_path_inner, '000-on_Windows-open_with-WinZip_or_7z_tools')
	open(instructions_filename, mode = 'wt').close()

	# create outer (wrapper) archive: compressed, encrypted
	args = [
		binary,
		'a',					# create archive
		'-sas',					# be smart about archive name extension
		'-bd',					# no progress indicator
		'-mx9',					# best available zip compression ratio
		'-mcu=on',				# UTF8 filenames
		'-l',					# store content of links, not links
		'-scsUTF-8',			# console charset
		'-tzip',				# force ZIP format
		'-mem=AES256',			# force useful encryption
		'-p%s' % passphrase		# set passphrase
	]
	if verbose:
		args.append('-bb3')
		args.append('-bt')
	else:
		args.append('-bb1')
	args.append(archive_name_outer)
	args.append(archive_path_inner)
	success, exit_code, stdout = gmShellAPI.run_process(cmd_line = args, encoding = 'utf8', verbose = verbose)
	if success:
		return archive_name_outer
	_log.error('cannot create outer archive')
	return None
Example #29
0
def create_zip_archive_from_dir(source_dir: str,
                                archive_name: str = None,
                                comment: str = None,
                                overwrite: bool = True,
                                verbose: bool = False) -> str:
    """Create archive of a directory.

	Args:
		source_dir: the directory to archive and encrypt
		archive_name: name of resulting zip archive
		comment: included as a file containing the comment
		overwrite: remove preexisting archive before creation, avoiding *updating* of same, and thereby including unintended data

	Returns:
		archive name / False / None (other error)
	"""
    assert (source_dir is not None), '<source_dir> must not be <None>'
    source_dir = os.path.abspath(source_dir)
    if not os.path.isdir(source_dir):
        _log.error('<source_dir> does not exist or is not a directory: %s',
                   source_dir)
        return False

    for cmd in ['7z', '7z.exe']:
        found, binary = gmShellAPI.detect_external_binary(binary=cmd)
        if found:
            break
    if not found:
        _log.warning('no 7z binary found')
        return None

    if archive_name is None:
        # do not assume we can write to "sourcedir/../"
        archive_path = gmTools.gmPaths().tmp_dir
        # but do take archive name from source_dir
        tmp, archive_fname = os.path.split(source_dir.rstrip(os.sep) + '.zip')
        archive_name = os.path.join(archive_path, archive_fname)
    # remove any existing archives so they don't get *updated*
    # rather than newly created
    if overwrite:
        if not gmTools.remove_file(archive_name, force=True):
            _log.error('cannot remove existing archive [%s]', archive_name)
            return False
    # 7z does not support ZIP comments so create
    # a text file holding the comment ...
    if comment is not None:
        comment_filename = os.path.abspath(archive_name) + '.comment.txt'
        if gmTools.remove_file(comment_filename, force=True):
            with open(comment_filename,
                      mode='wt',
                      encoding='utf8',
                      errors='replace') as comment_file:
                comment_file.write(comment)
        else:
            _log.error('cannot remove existing archive comment file [%s]',
                       comment_filename)
            comment = None

    # compress
    args = [
        binary,
        'a',  # create archive
        '-sas',  # be smart about archive name extension
        '-bd',  # no progress indicator
        '-mx9',  # best available zip compression ratio
        '-mcu=on',  # UTF8 filenames
        '-l',  # store content of links, not links
        '-scsUTF-8',  # console charset
        '-tzip'  # force ZIP format
    ]
    if verbose:
        args.append('-bb3')
        args.append('-bt')
    else:
        args.append('-bb1')
    args.append(archive_name)
    args.append(source_dir)
    if comment is not None:
        args.append(comment_filename)
    success, exit_code, stdout = gmShellAPI.run_process(cmd_line=args,
                                                        encoding='utf8',
                                                        verbose=verbose)
    if comment is not None:
        gmTools.remove_file(comment_filename)
    if success:
        return archive_name

    return None
Example #30
0
def convert_latex_to_pdf(filename: str = None,
                         verbose: bool = False,
                         is_sandboxed: bool = False) -> str:
    """Compile LaTeX code to PDF using pdflatex.

	Args:
		is_sandboxed: whether or not to create a sandbox for compiling

	Returns:
		Name of resulting PDF, or None on failure.
	"""
    global __LaTeX_version_checked
    global __pdflatex_executable
    if not __LaTeX_version_checked:
        __LaTeX_version_checked = True
        found, __pdflatex_executable = gmShellAPI.detect_external_binary(
            binary='pdflatex')
        if not found:
            _log.error('pdflatex not found')
            return None

        cmd_line = [__pdflatex_executable, '-version']
        success, ret_code, stdout = gmShellAPI.run_process(cmd_line=cmd_line,
                                                           encoding='utf8',
                                                           verbose=True)
        if not success:
            _log.error('[%s] failed, LaTeX not usable', cmd_line)
            return None

    if is_sandboxed:
        sandbox_dir = os.path.split(filename)[0]
    else:
        sandbox_dir = gmTools.mk_sandbox_dir(
            prefix=gmTools.fname_stem(filename) + '_')
        shutil.copy(filename, sandbox_dir)
        filename = os.path.join(sandbox_dir, os.path.split(filename)[1])
    _log.debug('LaTeX sandbox directory: [%s]', sandbox_dir)
    cmd_final = [
        __pdflatex_executable, '-recorder', '-interaction=nonstopmode',
        "-output-directory=%s" % sandbox_dir
    ]
    cmd_draft = cmd_final + ['-draftmode']
    # LaTeX can need up to three runs to get cross references et al right
    for cmd2run in [cmd_draft, cmd_draft, cmd_final]:
        success, ret_code, stdout = gmShellAPI.run_process(
            cmd_line=cmd2run + [filename],
            acceptable_return_codes=[0],
            encoding='utf8',
            verbose=True  #_cfg.get(option = 'debug')
        )
        if not success:
            _log.error(
                'problem running pdflatex, cannot generate form output, trying diagnostics'
            )
            found, binary = gmShellAPI.find_first_binary(
                binaries=['lacheck', 'miktex-lacheck.exe'])
            if not found:
                _log.debug('lacheck not found')
            else:
                cmd_line = [binary, filename]
                success, ret_code, stdout = gmShellAPI.run_process(
                    cmd_line=cmd_line, encoding='utf8', verbose=True)
            found, binary = gmShellAPI.find_first_binary(
                binaries=['chktex', 'ChkTeX.exe'])
            if not found:
                _log.debug('chcktex not found')
            else:
                cmd_line = [binary, '--verbosity=2', '--headererr', filename]
                success, ret_code, stdout = gmShellAPI.run_process(
                    cmd_line=cmd_line, encoding='utf8', verbose=True)
            return None

    return '%s.pdf' % os.path.splitext(filename)[0]
Example #31
0
def create_zip_archive_from_dir(source_dir, archive_name=None, comment=None, overwrite=True, verbose=False):

	source_dir = os.path.abspath(source_dir)
	if not os.path.isdir(source_dir):
		_log.error('<source_dir> does not exist or is not a directory: %s', source_dir)
		return False

	for cmd in ['7z', '7z.exe']:
		found, binary = gmShellAPI.detect_external_binary(binary = cmd)
		if found:
			break
	if not found:
		_log.warning('no 7z binary found')
		return None

	if archive_name is None:
		# do not assume we can write to "sourcedir/../"
		archive_path = gmTools.gmPaths().tmp_dir
		# but do take archive name from source_dir
		tmp, archive_fname = os.path.split(source_dir.rstrip(os.sep) + '.zip')
		archive_name = os.path.join(archive_path, archive_fname)
	# remove any existing archives so they don't get *updated*
	# rather than newly created
	if overwrite:
		if not gmTools.remove_file(archive_name, force = True):
			_log.error('cannot remove existing archive [%s]', archive_name)
			return False
	# 7z does not support ZIP comments so create
	# a text file holding the comment ...
	if comment is not None:
		comment_filename = os.path.abspath(archive_name) + '.comment.txt'
		if gmTools.remove_file(comment_filename, force = True):
			with open(comment_filename, mode = 'wt', encoding = 'utf8', errors = 'replace') as comment_file:
				comment_file.write(comment)
		else:
			_log.error('cannot remove existing archive comment file [%s]', comment_filename)
			comment = None

	# compress
	args = [
		binary,
		'a',				# create archive
		'-sas',				# be smart about archive name extension
		'-bd',				# no progress indicator
		'-mx9',				# best available zip compression ratio
		'-mcu=on',			# UTF8 filenames
		'-l',				# store content of links, not links
		'-scsUTF-8',		# console charset
		'-tzip'				# force ZIP format
	]
	if verbose:
		args.append('-bb3')
		args.append('-bt')
	else:
		args.append('-bb1')
	args.append(archive_name)
	args.append(source_dir)
	if comment is not None:
		args.append(comment_filename)
	success, exit_code, stdout = gmShellAPI.run_process(cmd_line = args, encoding = 'utf8', verbose = verbose)
	if comment is not None:
		gmTools.remove_file(comment_filename)
	if success:
		return archive_name

	return None
Example #32
0
def gpg_encrypt_file_symmetric(filename=None, comment=None, verbose=False, passphrase=None, remove_unencrypted=False):

	#add short decr instr to comment
	assert (filename is not None), '<filename> must not be None'

	_log.debug('attempting symmetric GPG encryption')
	for cmd in ['gpg2', 'gpg', 'gpg2.exe', 'gpg.exe']:
		found, binary = gmShellAPI.detect_external_binary(binary = cmd)
		if found:
			break
	if not found:
		_log.warning('no gpg binary found')
		return None
	filename_encrypted = filename + '.asc'
	args = [
		binary,
		'--utf8-strings',
		'--display-charset', 'utf-8',
		'--batch',
		'--no-greeting',
		'--enable-progress-filter',
		'--symmetric',
		'--cipher-algo', 'AES256',
		'--armor',
		'--output', filename_encrypted
	]
	if comment is not None:
		args.extend(['--comment', comment])
	if verbose:
		args.extend ([
			'--verbose', '--verbose',
			'--debug-level', '8',
			'--debug', 'packet,mpi,crypto,filter,iobuf,memory,cache,memstat,trust,hashing,clock,lookup,extprog',
			##'--debug-all',						# will log passphrase
			##'--debug, 'ipc',						# will log passphrase
			##'--debug-level', 'guru',				# will log passphrase
			##'--debug-level', '9',					# will log passphrase
		])
	pwd_fname = None
	if passphrase is not None:
		pwd_file = tempfile.NamedTemporaryFile(mode = 'w+t', encoding = 'utf8', delete = False)
		pwd_fname = pwd_file.name
		args.extend ([
			'--pinentry-mode', 'loopback',
			'--passphrase-file', pwd_fname
		])
		pwd_file.write(passphrase)
		pwd_file.close()
	args.append(filename)
	try:
		success, exit_code, stdout = gmShellAPI.run_process(cmd_line = args, verbose = verbose, encoding = 'utf-8')
	finally:
		if pwd_fname is not None:
			os.remove(pwd_fname)
	if not success:
		return None
	if not remove_unencrypted:
		return filename_encrypted
	if gmTools.remove_file(filename):
		return filename_encrypted
	gmTools.remove_file(filename_encrypted)
	return None
Example #33
0
	def __update_media_list(self):

		self._LCTRL_removable_media.remove_items_safely()
		items = []
		data = []

		found, self.__burn_script = gmShellAPI.detect_external_binary('gm-burn_doc')

		# USB / MMC drives
		removable_partitions = gmTools.enumerate_removable_partitions()
		for key in removable_partitions:
			part = removable_partitions[key]
			if part['is_mounted'] is False:
				continue
			items.append ([
				part['bus'].upper(),
				_('%s (%s %s) - %s free') % (
					part['fs_label'],
					part['vendor'],
					part['model'],
					gmTools.size2str(part['bytes_free'])
				),
				_('%s (%s): %s in %s on %s') % (
					part['mountpoint'],
					gmTools.size2str(part['size_in_bytes']),
					part['fs_type'],
					part['partition'],
					part['device']
				)
			])
			data.append(part)
		for key in removable_partitions:
			part = removable_partitions[key]
			if part['is_mounted'] is True:
				continue
			items.append ([
				part['bus'].upper(),
				'%s (%s %s)' % (
					part['fs_label'],
					part['vendor'],
					part['model']
				),
				_('%s on %s, not mounted') % (
					part['partition'],
					part['device']
				)
			])
			data.append(part)

		# optical drives: CD/DVD/BD
		optical_writers = gmTools.enumerate_optical_writers()
		for cdrw in optical_writers:
			items.append ([
				cdrw['type'].upper(),
				cdrw['model'],
				cdrw['device']
			])
			data.append(cdrw)

		self._LCTRL_removable_media.set_string_items(items)
		self._LCTRL_removable_media.set_data(data)
		self._LCTRL_removable_media.set_column_widths()

		self._BTN_save2media.Disable()
Example #34
0
def gpg_encrypt_file_symmetric(filename=None,
                               comment=None,
                               verbose=False,
                               passphrase=None,
                               remove_unencrypted=False):

    #add short decr instr to comment
    assert (filename is not None), '<filename> must not be None'

    _log.debug('attempting symmetric GPG encryption')
    for cmd in ['gpg2', 'gpg', 'gpg2.exe', 'gpg.exe']:
        found, binary = gmShellAPI.detect_external_binary(binary=cmd)
        if found:
            break
    if not found:
        _log.warning('no gpg binary found')
        return None
    filename_encrypted = filename + '.asc'
    args = [
        binary, '--utf8-strings', '--display-charset', 'utf-8', '--batch',
        '--no-greeting', '--enable-progress-filter', '--symmetric',
        '--cipher-algo', 'AES256', '--armor', '--output', filename_encrypted
    ]
    if comment is not None:
        args.extend(['--comment', comment])
    if verbose:
        args.extend([
            '--verbose',
            '--verbose',
            '--debug-level',
            '8',
            '--debug',
            'packet,mpi,crypto,filter,iobuf,memory,cache,memstat,trust,hashing,clock,lookup,extprog',
            ##'--debug-all',						# will log passphrase
            ##'--debug, 'ipc',						# will log passphrase
            ##'--debug-level', 'guru',				# will log passphrase
            ##'--debug-level', '9',					# will log passphrase
        ])
    pwd_fname = None
    if passphrase is not None:
        pwd_file = tempfile.NamedTemporaryFile(mode='w+t',
                                               encoding='utf8',
                                               delete=False)
        pwd_fname = pwd_file.name
        args.extend(
            ['--pinentry-mode', 'loopback', '--passphrase-file', pwd_fname])
        pwd_file.write(passphrase)
        pwd_file.close()
    args.append(filename)
    try:
        success, exit_code, stdout = gmShellAPI.run_process(cmd_line=args,
                                                            verbose=verbose,
                                                            encoding='utf-8')
    finally:
        if pwd_fname is not None:
            os.remove(pwd_fname)
    if not success:
        return None
    if not remove_unencrypted:
        return filename_encrypted
    if gmTools.remove_file(filename):
        return filename_encrypted
    gmTools.remove_file(filename_encrypted)
    return None
Example #35
0
def convert_file(filename=None,
                 target_mime=None,
                 target_filename=None,
                 target_extension=None,
                 verbose=False):
    """Convert file from one format into another.

		target_mime: a mime type
	"""
    assert (target_mime is not None), '<target_mime> must not be None'
    assert (filename is not None), '<filename> must not be None'
    assert (filename != target_filename
            ), '<target_filename> must be different from <filename>'

    source_mime = guess_mimetype(filename=filename)
    if source_mime.casefold() == target_mime.casefold():
        _log.debug('source file [%s] already target mime type [%s]', filename,
                   target_mime)
        if target_filename is None:
            return filename

        shutil.copyfile(filename, target_filename)
        return target_filename

    converted_ext = guess_ext_by_mimetype(target_mime)
    if converted_ext is None:
        if target_filename is not None:
            tmp, converted_ext = os.path.splitext(target_filename)
    if converted_ext is None:
        converted_ext = target_extension  # can still stay None
    converted_ext = gmTools.coalesce(converted_ext, '').strip().lstrip('.')
    converted_fname = gmTools.get_unique_filename(suffix=converted_ext)
    _log.debug('attempting conversion: [%s] -> [<%s>:%s]', filename,
               target_mime, gmTools.coalesce(target_filename, converted_fname))

    # try user-local conversion script
    script_name = 'gm-convert_file'
    binary = os.path.join(gmTools.gmPaths().home_dir, 'bin', script_name)
    _log.debug('trying user-local script: %s', binary)
    _log.debug(
        '<%s> API: SOURCEFILE TARGET_MIMETYPE TARGET_EXTENSION TARGET_FILENAME',
        script_name)
    found, binary = gmShellAPI.detect_external_binary(binary=binary)
    if found:
        cmd_line = [
            binary, filename, target_mime, converted_ext, converted_fname
        ]
        success, returncode, stdout = gmShellAPI.run_process(cmd_line=cmd_line,
                                                             verbose=True)
        if success:
            if target_filename is None:
                return converted_fname

            shutil.copyfile(converted_fname, target_filename)
            return target_filename

    # try built-in conversions
    _log.debug('trying built-in conversion function')
    try:
        conversion_func = __CONVERSION_DELEGATES[source_mime][target_mime]
    except KeyError:
        conversion_func = None
    if conversion_func is not None:
        converted_fname = conversion_func(filename=filename, verbose=verbose)
        if converted_fname is not None:
            if target_filename is None:
                return converted_fname

            shutil.copyfile(converted_fname, target_filename)
            return target_filename

    # try system-wide conversion script
    paths = gmTools.gmPaths()
    local_script = os.path.join(paths.local_base_dir, '..', 'external-tools',
                                script_name)
    candidates = [script_name, local_script]  #, script_name + u'.bat'
    _log.debug('trying system-wide scripts: %s', candidates)
    found, binary = gmShellAPI.find_first_binary(binaries=candidates)
    if not found:  # try anyway
        _log.debug('trying anyway as last-ditch resort')
        binary = script_name  # + r'.bat'
    cmd_line = [binary, filename, target_mime, converted_ext, converted_fname]
    success, returncode, stdout = gmShellAPI.run_process(cmd_line=cmd_line,
                                                         verbose=True)
    if success:
        if target_filename is None:
            return converted_fname

        shutil.copyfile(converted_fname, target_filename)
        return target_filename

    # seems to have failed but check for target file anyway
    _log.error(
        'conversion script returned error exit code, checking target file anyway'
    )
    if not os.path.exists(converted_fname):
        return None

    _log.info('conversion target file found')
    stats = os.stat(converted_fname)
    if stats.st_size == 0:
        return None

    _log.info('conversion target file size > 0')
    achieved_mime = guess_mimetype(filename=converted_fname)
    if achieved_mime != target_mime:
        _log.error('target: [%s], achieved: [%s]', target_mime, achieved_mime)
        return None

    # we may actually have something despite a non-0 exit code
    _log.info(
        'conversion target file mime type [%s], as expected, might be usable',
        achieved_mime)
    if target_filename is None:
        return converted_fname

    shutil.copyfile(converted_fname, target_filename)
    return target_filename
Example #36
0
    def _on_burn_items_button_pressed(self, event):
        event.Skip()

        # anything to do ?
        found, external_cmd = gmShellAPI.detect_external_binary('gm-burn_doc')
        if not found:
            return
        items = self._LCTRL_items.get_selected_item_data(only_one=False)
        if len(items) == 0:
            items = self._LCTRL_items.get_item_data()
        if len(items) == 0:
            return

        pat = gmPerson.gmCurrentPatient()
        dlg = cCreatePatientMediaDlg(self,
                                     -1,
                                     burn2cd=True,
                                     patient=pat,
                                     item_count=len(items))
        choice = dlg.ShowModal()
        if choice != wx.ID_SAVE:
            return
        path2include = dlg._LBL_directory.Label.strip()
        include_selected_dir = dlg._CHBOX_include_directory.IsChecked()
        dlg.Destroy()

        # do the export
        base_dir = None
        if include_selected_dir:
            if gmTools.dir_is_empty(path2include) is False:
                base_dir = gmTools.get_unique_filename(suffix='.iso')
                try:
                    shutil.copytree(path2include, base_dir)
                except shutil.Error:
                    _log.exception(
                        'cannot copy include directory [%s] -> [%s]',
                        path2include, base_dir)
                    return

        export_dir = gmPerson.gmCurrentPatient().export_area.export(
            base_dir=base_dir, items=items, with_metadata=True)
        if export_dir is None:
            return

        # burn onto media
        cmd = '%s %s' % (external_cmd, export_dir)
        if os.name == 'nt':
            blocking = True
        else:
            blocking = False
        success = gmShellAPI.run_command_in_shell(command=cmd,
                                                  blocking=blocking)
        if not success:
            gmGuiHelpers.gm_show_error(
                aMessage=_('Error burning documents to CD/DVD.'),
                aTitle=_('Burning documents'))
            return

        self.save_soap_note(soap=_('Burned onto CD/DVD:\n - %s') %
                            '\n - '.join([i['description'] for i in items]))

        browse_index = gmGuiHelpers.gm_show_question(
            title=_('Creating patient media'),
            question=_('Browse patient data pack ?'),
            cancel_button=False)
        if browse_index:
            gmNetworkTools.open_url_in_browser(
                url='file://%s' % os.path.join(export_dir, 'index.html'))

        return True