def __toggle_callback(self, cell, path):
     """Callback function to toggle option"""
     options.toggle(path)
     if online_update_notification_enabled:
         self.cb_beta.set_sensitive(options.get('check_online_updates'))
         if 'nt' == os.name:
             self.cb_winapp2.set_sensitive(
                 options.get('check_online_updates'))
     if 'auto_hide' == path:
         self.cb_refresh_operations()
     if 'auto_start' == path:
         if 'nt' == os.name:
             swc = Windows.start_with_computer
         if 'posix' == os.name:
             swc = Unix.start_with_computer
         try:
             swc(options.get(path))
         except:
             traceback.print_exc()
             dlg = gtk.MessageDialog(self.parent,
                                     type=gtk.MESSAGE_ERROR,
                                     buttons=gtk.BUTTONS_OK,
                                     message_format=str(sys.exc_info()[1]))
             dlg.run()
             dlg.destroy()
Example #2
0
    def __init__(self, *args, **kwargs):
        super(GUI, self).__init__(*args, **kwargs)

        from bleachbit import RecognizeCleanerML
        RecognizeCleanerML.RecognizeCleanerML()
        register_cleaners()

        self.populate_window()

        # Redirect logging to the GUI.
        bb_logger = logging.getLogger('bleachbit')
        gtklog = GtkLoggerHandler(self.append_text)
        bb_logger.addHandler(gtklog)
        if 'nt' == os.name and 'windows_exe' == getattr(sys, 'frozen', None):
            # On Microsoft Windows this avoids py2exe redirecting stderr to
            # bleachbit.exe.log.
            # sys.frozen = console_exe means the console is shown
            from bleachbit import logger_sh
            bb_logger.removeHandler(logger_sh)

        if options.get("first_start") and 'posix' == os.name:
            pref = PreferencesDialog(self, self.cb_refresh_operations)
            pref.run()
            options.set('first_start', False)
        if bleachbit.online_update_notification_enabled and options.get("check_online_updates"):
            self.check_online_updates()
        if 'nt' == os.name:
            # BitDefender false positive.  BitDefender didn't mark BleachBit as infected or show
            # anything in its log, but sqlite would fail to import unless BitDefender was in "game mode."
            # http://bleachbit.sourceforge.net/forum/074-fails-errors
            try:
                import sqlite3
            except ImportError as e:
                self.append_text(
                    _("Error loading the SQLite module: the antivirus software may be blocking it."), 'error')
Example #3
0
 def __toggle_callback(self, cell, path):
     global win10_provider
     """Callback function to toggle option"""
     options.toggle(path)
     if online_update_notification_enabled:
         self.cb_beta.set_sensitive(options.get('check_online_updates'))
         if 'nt' == os.name:
             self.cb_winapp2.set_sensitive(
                 options.get('check_online_updates'))
     if 'auto_hide' == path:
         self.refresh_operations = True
     if 'dark_mode' == path:
         if os.name != 'nt' or options.get("win10_mode") == False:
             Gtk.Settings.get_default().set_property(
                 'gtk-application-prefer-dark-theme',
                 options.get('dark_mode'))
     if 'win10_mode' == path:
         if options.get("win10_mode"):
             screen = Gdk.Display.get_default_screen(
                 Gdk.Display.get_default())
             Gtk.StyleContext.add_provider_for_screen(
                 screen, bleachbit.GUI.Bleachbit._style_provider, 600)
         else:
             screen = Gdk.Display.get_default_screen(
                 Gdk.Display.get_default())
             Gtk.StyleContext.remove_provider_for_screen(
                 screen, bleachbit.GUI.Bleachbit._style_provider)
     if 'debug' == path:
         from bleachbit.Log import set_root_log_level
         set_root_log_level()
Example #4
0
 def __toggle_callback(self, cell, path):
     """Callback function to toggle option"""
     options.toggle(path)
     if online_update_notification_enabled:
         self.cb_beta.set_sensitive(options.get('check_online_updates'))
         if 'nt' == os.name:
             self.cb_winapp2.set_sensitive(
                 options.get('check_online_updates'))
     if 'auto_hide' == path:
         self.cb_refresh_operations()
     if 'auto_start' == path:
         if 'nt' == os.name:
             swc = Windows.start_with_computer
         if 'posix' == os.name:
             swc = Unix.start_with_computer
         try:
             swc(options.get(path))
         except:
             traceback.print_exc()
             dlg = gtk.MessageDialog(self.parent,
                                     type=gtk.MESSAGE_ERROR,
                                     buttons=gtk.BUTTONS_OK,
                                     message_format=str(sys.exc_info()[1]))
             dlg.run()
             dlg.destroy()
Example #5
0
    def set_windows10_theme(self):
        """Toggle the Windows 10 theme"""
        if not 'nt' == os.name:
            return

        if not self._style_provider_regular:
            self._style_provider_regular = Gtk.CssProvider()
            self._style_provider_regular.load_from_path(
                os.path.join(windows10_theme_path, 'gtk.css'))
        if not self._style_provider_dark:
            self._style_provider_dark = Gtk.CssProvider()
            self._style_provider_dark.load_from_path(
                os.path.join(windows10_theme_path, 'gtk-dark.css'))

        screen = Gdk.Display.get_default_screen(Gdk.Display.get_default())
        if self._style_provider is not None:
            Gtk.StyleContext.remove_provider_for_screen(
                screen, self._style_provider)
        if options.get("win10_theme"):
            if options.get("dark_mode"):
                self._style_provider = self._style_provider_dark
            else:
                self._style_provider = self._style_provider_regular
            Gtk.StyleContext.add_provider_for_screen(
                screen, self._style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
        else:
            self._style_provider = None
Example #6
0
 def is_running(self):
     """Return whether the program is currently running"""
     resp_cli=""
     logger = logging.getLogger(__name__)
     for running in self.running:
         test = running[0]
         pathname = running[1]
         if 'exe' == test and 'posix' == os.name:
             if Unix.is_running(pathname):
                 #print "debug: process '%s' is running" % pathname
                 logger.debug("Debug: process '%s' is running", pathname)
                 if options.get("close_run"):
                     if not subprocess.mswindows:
                         #print "debug: Closing process '%s'" % pathname
                         if "--preset" in sys.argv:
                             resp_cli = raw_input("Do you Want BleachBit to Close " + pathname + " y/n : ")
                         else:
                             resp = GuiBasic.message_dialog(None,"Do you Want BleachBit to Close " + pathname,gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO)
                         if gtk.RESPONSE_YES == resp or resp_cli.lower() == "y":
                         # user cancelled, so don't toggle option
                             logger.debug("Debug: Closing process '%s'",pathname)
                             subprocess.check_output(["killall", "-9", pathname])
                         if not Unix.is_running(pathname):
                             logger.debug("Debug: Closing process '%s' successful",pathname)
                             return False
                 return True
         elif 'exe' == test and 'nt' == os.name:
             if Windows.is_process_running(pathname):
                 #print "debug: process '%s' is running" % pathname
                 logger.debug("Debug: process '%s' is running", pathname)
                 if options.get("close_run"):
                     if subprocess.mswindows:
                         #print "debug: Closing process '%s'" % pathname
                         if "--preset" in sys.argv:
                             resp_cli = raw_input("Do you Want BleachBit to Close " + pathname + " y/n : ")
                         else:
                             resp = GuiBasic.message_dialog(None,"Do you Want BleachBit to Close " + pathname,gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO)
                         if gtk.RESPONSE_YES == resp or resp_cli.lower() == "y":
                             logger.debug("debug: Closing process '%s'",pathname)
                             subprocess.check_output(["taskkill", "/IM", pathname])
                         if not Windows.is_process_running(pathname):
                             logger.debug("debug: Closing process '%s' successful",pathname)
                             return False
                 logger.debug("process '%s' is running", pathname)
                 return True
         elif 'exe' == test and 'nt' == os.name:
             if Windows.is_process_running(pathname):
                 logger.debug("process '%s' is running", pathname)
                 return True
         elif 'pathname' == test:
             expanded = expanduser(expandvars(pathname))
             for globbed in glob.iglob(expanded):
                 if os.path.exists(globbed):
                     logger.debug("file '%s' exists indicating '%s' is running", self.name)
                     return True
         else:
             raise RuntimeError(
                 "Unknown running-detection test '%s'" % test)
     return False
Example #7
0
 def __toggle_callback(self, cell, path):
     """Callback function to toggle option"""
     options.toggle(path)
     if online_update_notification_enabled:
         self.cb_beta.set_sensitive(options.get('check_online_updates'))
         if 'nt' == os.name:
             self.cb_winapp2.set_sensitive(options.get('check_online_updates'))
     if 'auto_hide' == path:
         self.refresh_operations = True
Example #8
0
    def cb_register_cleaners_done(self):
        """Called from register_cleaners()"""
        self.progressbar.hide()
        # update tree view
        self.tree_store.refresh_rows()
        # expand tree view
        self.view.expand_all()

        # Check for online updates.
        if not self._auto_exit and \
            bleachbit.online_update_notification_enabled and \
            options.get("check_online_updates") and \
                not hasattr(self, 'checked_for_updates'):
            self.checked_for_updates = True
            self.check_online_updates()

        # Show information for first start.
        # (The first start flag is set also for each new version.)
        if options.get("first_start") and not self._auto_exit:
            if os.name == 'posix':
                self.append_text(
                    _('Access the application menu by clicking the hamburger icon on the title bar.'
                      ))
                pref = self.get_preferences_dialog()
                pref.run()
            if os.name == 'nt':
                self.append_text(
                    _('Access the application menu by clicking the logo on the title bar.'
                      ))
            options.set('first_start', False)

        if os.name == 'nt':
            # BitDefender false positive.  BitDefender didn't mark BleachBit as infected or show
            # anything in its log, but sqlite would fail to import unless BitDefender was in "game mode."
            # http://bleachbit.sourceforge.net/forum/074-fails-errors
            try:
                import sqlite3
            except ImportError as e:
                self.append_text(
                    _("Error loading the SQLite module: the antivirus software may be blocking it."
                      ), 'error')

        # Show notice about admin privileges.
        if os.name == 'posix' and os.path.expanduser('~') == '/root':
            self.append_text(
                _('You are running BleachBit with administrative privileges for cleaning shared parts of the system, and references to the user profile folder will clean only the root account.'
                  ) + '\n')
        if os.name == 'nt' and options.get('shred'):
            from win32com.shell.shell import IsUserAnAdmin
            if not IsUserAnAdmin():
                self.append_text(
                    _('Run BleachBit with administrator privileges to improve the accuracy of overwriting the contents of files.'
                      ))
                self.append_text('\n')

        # remove from idle loop (see GObject.idle_add)
        return False
Example #9
0
    def __init__(self, uac=True, shred_paths=None, exit=False):
        if uac and 'nt' == os.name and Windows.elevate_privileges():
            # privileges escalated in other process
            sys.exit(0)
        if not exit:
            from bleachbit import RecognizeCleanerML
            RecognizeCleanerML.RecognizeCleanerML()
            register_cleaners()
        self.create_window()
        gobject.threads_init()

        # Redirect logging to the GUI.
        bb_logger = logging.getLogger('bleachbit')
        gtklog = GtkLoggerHandler(self.append_text)
        bb_logger.addHandler(gtklog)
        if 'nt' == os.name and 'windows_exe' == getattr(sys, 'frozen', None):
            # On Microsoft Windows this avoids py2exe redirecting stderr to
            # bleachbit.exe.log.
            # sys.frozen = console_exe means the console is shown
            from bleachbit import logger_sh
            bb_logger.removeHandler(logger_sh)
        if shred_paths:
            self.shred_paths(shred_paths)
            return
        if options.get("first_start") and 'posix' == os.name:
            pref = PreferencesDialog(self.window, self.cb_refresh_operations)
            pref.run()
            options.set('first_start', False)
        if bleachbit.online_update_notification_enabled and options.get(
                "check_online_updates"):
            self.check_online_updates()
        if 'nt' == os.name:
            # BitDefender false positive.  BitDefender didn't mark BleachBit as infected or show
            # anything in its log, but sqlite would fail to import unless BitDefender was in "game mode."
            # https://www.bleachbit.org/forum/074-fails-errors
            try:
                import sqlite3
            except ImportError:
                logger.exception(
                    _("Error loading the SQLite module: the antivirus software may be blocking it."
                      ))
        if 'posix' == os.name and bleachbit.expanduser('~') == '/root':
            self.append_text(
                _('You are running BleachBit with administrative privileges for cleaning shared parts of the system, and references to the user profile folder will clean only the root account.'
                  ))
        if 'nt' == os.name and options.get('shred'):
            from win32com.shell.shell import IsUserAnAdmin
            if not IsUserAnAdmin():
                self.append_text(
                    _('Run BleachBit with administrator privileges to improve the accuracy of overwriting the contents of files.'
                      ))
                self.append_text('\n')
        if exit:
            # This is used for automated testing of whether the GUI can start.
            gobject.idle_add(lambda: gtk.main_quit(),
                             priority=gobject.PRIORITY_LOW)
Example #10
0
    def __init__(self, auto_exit, *args, **kwargs):
        super(GUI, self).__init__(*args, **kwargs)

        self.auto_exit = auto_exit

        self.set_wmclass(APP_NAME, APP_NAME)
        self.populate_window()

        # Redirect logging to the GUI.
        bb_logger = logging.getLogger('bleachbit')
        gtklog = GtkLoggerHandler(self.append_text)
        bb_logger.addHandler(gtklog)
        if os.name == 'nt' and getattr(sys, 'frozen', None) == 'windows_exe':
            # On Microsoft Windows this avoids py2exe redirecting stderr to
            # bleachbit.exe.log.
            # sys.frozen = console_exe means the console is shown
            from bleachbit import logger_sh
            bb_logger.removeHandler(logger_sh)

        Gtk.Settings.get_default().set_property(
            'gtk-application-prefer-dark-theme', options.get('dark_mode'))

        if options.is_corrupt():
            logger.error(
                _('Resetting the configuration file because it is corrupt: %s')
                % bleachbit.options_file)
            bleachbit.Options.init_configuration()

        if options.get("first_start") and os.name == 'posix' and not auto_exit:
            pref = PreferencesDialog(self, self.cb_refresh_operations)
            pref.run()
            options.set('first_start', False)
        if os.name == 'nt':
            # BitDefender false positive.  BitDefender didn't mark BleachBit as infected or show
            # anything in its log, but sqlite would fail to import unless BitDefender was in "game mode."
            # http://bleachbit.sourceforge.net/forum/074-fails-errors
            try:
                import sqlite3
            except ImportError as e:
                self.append_text(
                    _("Error loading the SQLite module: the antivirus software may be blocking it."
                      ), 'error')

        if os.name == 'posix' and bleachbit.expanduser('~') == '/root':
            self.append_text(
                _('You are running BleachBit with administrative privileges for cleaning shared parts of the system, and references to the user profile folder will clean only the root account.'
                  ))
        if os.name == 'nt' and options.get('shred'):
            from win32com.shell.shell import IsUserAnAdmin
            if not IsUserAnAdmin():
                self.append_text(
                    _('Run BleachBit with administrator privileges to improve the accuracy of overwriting the contents of files.'
                      ))
                self.append_text('\n')

        GLib.idle_add(self.cb_refresh_operations)
Example #11
0
    def sqlite_clean_helper(self,
                            sql,
                            fn,
                            clean_func,
                            check_func=None,
                            setup_func=None):
        """Helper for cleaning special SQLite cleaning"""

        self.assertFalse(
            sql and fn,
            "sql and fn are mutually exclusive ways to create the data")

        if fn:
            filename = os.path.join(self.dir_base, fn)
            if not os.path.exists(filename):
                import pdb
                pdb.set_trace()
            self.assert_(os.path.exists(filename))

        # create sqlite file
        if sql:
            # create test file
            tmpdir = tempfile.mkdtemp('bleachbit-sqlite-test')
            (fd, filename) = tempfile.mkstemp(dir=tmpdir)
            os.close(fd)

            # additional setup
            if setup_func:
                setup_func(filename)

            # before SQL creation executed, cleaning should fail
            self.assertRaises(sqlite3.DatabaseError, clean_func, filename)
            # create
            bleachbit.FileUtilities.execute_sqlite3(filename, sql)
            self.assert_(os.path.exists(filename))

        # clean the file
        old_shred = options.get('shred')
        options.set('shred', False, commit=False)
        self.assertFalse(options.get('shred'))
        clean_func(filename)
        options.set('shred', True, commit=False)
        self.assertTrue(options.get('shred'))
        options.set('shred', old_shred, commit=False)
        clean_func(filename)
        self.assert_(os.path.exists(filename))

        # check
        if check_func:
            check_func(self, filename)

        # tear down
        bleachbit.FileUtilities.delete(filename)
        self.assert_(not os.path.exists(filename))
Example #12
0
 def check_online_updates(self):
     """Check for software updates in background"""
     from bleachbit import Update
     try:
         updates = Update.check_updates(
             options.get('check_beta'), options.get('update_winapp2'),
             self.append_text,
             lambda: GLib.idle_add(self.cb_refresh_operations))
         if updates:
             GLib.idle_add(lambda: Update.update_dialog(self, updates))
     except Exception:
         logger.exception(_("Error when checking for updates: "))
 def __toggle_callback(self, cell, path):
     """Callback function to toggle option"""
     options.toggle(path)
     if online_update_notification_enabled:
         self.cb_beta.set_sensitive(options.get('check_online_updates'))
         if 'nt' == os.name:
             self.cb_winapp2.set_sensitive(
                 options.get('check_online_updates'))
     if 'auto_hide' == path:
         self.refresh_operations = True
     if 'dark_mode' == path:
         Gtk.Settings.get_default().set_property(
             'gtk-application-prefer-dark-theme', options.get('dark_mode'))
Example #14
0
 def check_online_updates(self):
     """Check for software updates in background"""
     from bleachbit import Update
     try:
         updates = Update.check_updates(options.get('check_beta'),
                                        options.get('update_winapp2'),
                                        self.append_text,
                                        lambda: gobject.idle_add(self.cb_refresh_operations))
         if updates:
             gobject.idle_add(
                 lambda: Update.update_dialog(self.window, updates))
     except Exception:
         logger.exception(_("Error when checking for updates: "))
Example #15
0
    def sqlite_clean_helper(self,
                            sql,
                            fn,
                            clean_func,
                            check_func=None,
                            setup_func=None):
        """Helper for cleaning special SQLite cleaning"""

        self.assertFalse(
            sql and fn,
            "sql and fn are mutually exclusive ways to create the data")

        if fn:
            filename = os.path.normpath(os.path.join(self.dir_base, fn))
            self.assertExists(filename)

        # create sqlite file
        elif sql:
            # create test file
            filename = self.mkstemp(prefix='bleachbit-test-sqlite')

            # additional setup
            if setup_func:
                setup_func(filename)

            # before SQL creation executed, cleaning should fail
            self.assertRaises(sqlite3.DatabaseError, clean_func, filename)
            # create
            FileUtilities.execute_sqlite3(filename, sql)
            self.assertExists(filename)
        else:
            raise RuntimeError('neither fn nor sql supplied')

        # clean the file
        old_shred = options.get('shred')
        options.set('shred', False, commit=False)
        self.assertFalse(options.get('shred'))
        clean_func(filename)
        options.set('shred', True, commit=False)
        self.assertTrue(options.get('shred'))
        options.set('shred', old_shred, commit=False)
        clean_func(filename)
        self.assertExists(filename)

        # check
        if check_func:
            check_func(self, filename)

        # tear down
        FileUtilities.delete(filename)
        self.assertNotExists(filename)
Example #16
0
    def __init__(self, uac=True, shred_paths=None, exit=False):
        if uac and 'nt' == os.name and Windows.elevate_privileges():
            # privileges escalated in other process
            sys.exit(0)
        if not exit:
            from bleachbit import RecognizeCleanerML
            RecognizeCleanerML.RecognizeCleanerML()
            register_cleaners()
        self.create_window()
        gobject.threads_init()

        # Redirect logging to the GUI.
        bb_logger = logging.getLogger('bleachbit')
        gtklog = GtkLoggerHandler(self.append_text)
        bb_logger.addHandler(gtklog)
        if 'nt' == os.name and 'windows_exe' == getattr(sys, 'frozen', None):
            # On Microsoft Windows this avoids py2exe redirecting stderr to
            # bleachbit.exe.log.
            # sys.frozen = console_exe means the console is shown
            from bleachbit import logger_sh
            bb_logger.removeHandler(logger_sh)
        if shred_paths:
            self.shred_paths(shred_paths)
            return
        if options.get("first_start") and 'posix' == os.name:
            pref = PreferencesDialog(self.window, self.cb_refresh_operations)
            pref.run()
            options.set('first_start', False)
        if bleachbit.online_update_notification_enabled and options.get("check_online_updates"):
            self.check_online_updates()
        if 'nt' == os.name:
            # BitDefender false positive.  BitDefender didn't mark BleachBit as infected or show
            # anything in its log, but sqlite would fail to import unless BitDefender was in "game mode."
            # https://www.bleachbit.org/forum/074-fails-errors
            try:
                import sqlite3
            except ImportError:
                logger.exception(_("Error loading the SQLite module: the antivirus software may be blocking it."))
        if 'posix' == os.name and bleachbit.expanduser('~') == '/root':
            self.append_text(
                _('You are running BleachBit with administrative privileges for cleaning shared parts of the system, and references to the user profile folder will clean only the root account.'))
        if 'nt' == os.name and options.get('shred'):
            from win32com.shell.shell import IsUserAnAdmin
            if not IsUserAnAdmin():
                self.append_text(
                    _('Run BleachBit with administrator privileges to improve the accuracy of overwriting the contents of files.'))
                self.append_text('\n')
        if exit:
            # This is used for automated testing of whether the GUI can start.
            gobject.idle_add(
                lambda: gtk.main_quit(), priority=gobject.PRIORITY_LOW)
Example #17
0
    def sqlite_clean_helper(
            self, sql, fn, clean_func, check_func=None, setup_func=None):
        """Helper for cleaning special SQLite cleaning"""

        self.assertFalse(
            sql and fn, "sql and fn are mutually exclusive ways to create the data")

        if fn:
            filename = os.path.join(self.dir_base, fn)
            if not os.path.exists(filename):
                import pdb
                pdb.set_trace()
            self.assert_(os.path.exists(filename))

        # create sqlite file
        if sql:
            # create test file
            tmpdir = tempfile.mkdtemp('bleachbit-sqlite-test')
            (fd, filename) = tempfile.mkstemp(dir=tmpdir)
            os.close(fd)

            # additional setup
            if setup_func:
                setup_func(filename)

            # before SQL creation executed, cleaning should fail
            self.assertRaises(sqlite3.DatabaseError,
                              clean_func, filename)
            # create
            bleachbit.FileUtilities.execute_sqlite3(filename, sql)
            self.assert_(os.path.exists(filename))

        # clean the file
        old_shred = options.get('shred')
        options.set('shred', False, commit=False)
        self.assertFalse(options.get('shred'))
        clean_func(filename)
        options.set('shred', True, commit=False)
        self.assertTrue(options.get('shred'))
        options.set('shred', old_shred, commit=False)
        clean_func(filename)
        self.assert_(os.path.exists(filename))

        # check
        if check_func:
            check_func(self, filename)

        # tear down
        bleachbit.FileUtilities.delete(filename)
        self.assert_(not os.path.exists(filename))
Example #18
0
def bytes_to_human(bytes_i):
    # type: (int) -> str
    """Display a file size in human terms (megabytes, etc.) using preferred standard (SI or IEC)"""

    if bytes_i < 0:
        return '-' + bytes_to_human(-bytes_i)

    from bleachbit.Options import options
    if options.get('units_iec'):
        prefixes = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi']
        base = 1024.0
    else:
        prefixes = ['', 'k', 'M', 'G', 'T', 'P']
        base = 1000.0

    assert (isinstance(bytes_i, int))

    if 0 == bytes_i:
        return '0B'

    if bytes_i >= base**3:
        decimals = 2
    elif bytes_i >= base:
        decimals = 1
    else:
        decimals = 0

    for exponent in range(0, len(prefixes)):
        if bytes_i < base:
            abbrev = round(bytes_i, decimals)
            suf = prefixes[exponent]
            return locale.str(abbrev) + suf + 'B'
        else:
            bytes_i /= base
    return 'A lot.'
Example #19
0
def clean_json(path, target):
    """Delete key in the JSON file"""
    import json
    changed = False
    targets = target.split('/')

    # read file to parser
    js = json.load(open(path, 'r'))

    # change file
    pos = js
    while True:
        new_target = targets.pop(0)
        if not isinstance(pos, dict):
            break
        if new_target in pos and len(targets) > 0:
            # descend
            pos = pos[new_target]
        elif new_target in pos:
            # delete terminal target
            changed = True
            del (pos[new_target])
        else:
            # target not found
            break
        if 0 == len(targets):
            # target not found
            break

    if changed:
        from bleachbit.Options import options
        if options.get('shred'):
            delete(path, True)
        # write file
        json.dump(js, open(path, 'w'))
Example #20
0
def clean_ini(path, section, parameter):
    """Delete sections and parameters (aka option) in the file"""

    # read file to parser
    config = bleachbit.RawConfigParser()
    fp = codecs.open(path, 'r', encoding='utf_8_sig')
    config.readfp(fp)

    # change file
    changed = False
    if config.has_section(section):
        if parameter is None:
            changed = True
            config.remove_section(section)
        elif config.has_option(section, parameter):
            changed = True
            config.remove_option(section, parameter)

    # write file
    if changed:
        from bleachbit.Options import options
        fp.close()
        if options.get('shred'):
            delete(path, True)
        fp = codecs.open(path, 'wb', encoding='utf_8')
        config.write(fp)
Example #21
0
def execute_sqlite3(path, cmds):
    """Execute 'cmds' on SQLite database 'path'"""
    import sqlite3
    conn = sqlite3.connect(path)
    cursor = conn.cursor()

    # overwrites deleted content with zeros
    # https://www.sqlite.org/pragma.html#pragma_secure_delete
    from bleachbit.Options import options
    if options.get('shred'):
        cursor.execute('PRAGMA secure_delete=ON')

    for cmd in cmds.split(';'):
        try:
            cursor.execute(cmd)
        except sqlite3.DatabaseError as exc:
            raise sqlite3.DatabaseError(
                '%s: %s' % (bleachbit.decode_str(exc), path))
        except sqlite3.OperationalError as exc:
            if exc.message.find('no such function: ') >= 0:
                # fixme: determine why randomblob and zeroblob are not
                # available
                logger.exception(exc.message)
            else:
                raise sqlite3.OperationalError(
                    '%s: %s' % (bleachbit.decode_str(exc), path))
    cursor.close()
    conn.commit()
    conn.close()
Example #22
0
def bytes_to_human(bytes_i):
    # type: (int) -> str
    """Display a file size in human terms (megabytes, etc.) using preferred standard (SI or IEC)"""

    if bytes_i < 0:
        return '-' + bytes_to_human(-bytes_i)

    from bleachbit.Options import options
    if options.get('units_iec'):
        prefixes = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi']
        base = 1024.0
    else:
        prefixes = ['', 'k', 'M', 'G', 'T', 'P']
        base = 1000.0

    assert(isinstance(bytes_i, (int, long)))

    if 0 == bytes_i:
        return "0"

    if bytes_i >= base ** 3:
        decimals = 2
    elif bytes_i >= base:
        decimals = 1
    else:
        decimals = 0

    for exponent in range(0, len(prefixes)):
        if bytes_i < base:
            abbrev = round(bytes_i, decimals)
            suf = prefixes[exponent]
            return locale.str(abbrev) + suf + 'B'
        else:
            bytes_i /= base
    return 'A lot.'
Example #23
0
def clean_ini(path, section, parameter):
    """Delete sections and parameters (aka option) in the file"""

    # read file to parser
    config = bleachbit.RawConfigParser()
    fp = codecs.open(path, 'r', encoding='utf_8_sig')
    config.readfp(fp)

    # change file
    changed = False
    if config.has_section(section):
        if parameter is None:
            changed = True
            config.remove_section(section)
        elif config.has_option(section, parameter):
            changed = True
            config.remove_option(section, parameter)

    # write file
    if changed:
        from bleachbit.Options import options
        fp.close()
        if options.get('shred'):
            delete(path, True)
        fp = codecs.open(path, 'wb', encoding='utf_8')
        config.write(fp)
Example #24
0
    def set_windows10_theme(self):
        """Toggle the Windows 10 theme"""
        if not 'nt' == os.name:
            return
        exec_path = os.path.dirname(sys.executable)
        windows_10_theme_exe_path = os.path.normpath(
            os.path.join(exec_path, 'themes/windows10/gtk.css'))
        windows_10_theme_source_path = "themes/windows10/gtk.css"
        load_path = None

        if os.path.exists(windows_10_theme_exe_path):
            load_path = windows_10_theme_exe_path
        elif os.path.exists(windows_10_theme_source_path):
            load_path = windows_10_theme_source_path

        if not self._style_provider:
            self._style_provider = Gtk.CssProvider()

            if not load_path:
                logger.warning('cannot find windows10/gtk.css')
                return

            self._style_provider.load_from_path(load_path)

        screen = Gdk.Display.get_default_screen(Gdk.Display.get_default())
        if options.get("win10_theme"):
            Gtk.StyleContext.add_provider_for_screen(screen,
                                                     self._style_provider, 600)
        else:
            Gtk.StyleContext.remove_provider_for_screen(
                screen, self._style_provider)
Example #25
0
    def worker_done(self, worker, really_delete):
        """Callback for when Worker is done"""
        self.progressbar.set_text("")
        self.progressbar.set_fraction(1)
        self.progressbar.set_text(_("Done."))
        self.textview.scroll_mark_onscreen(self.textbuffer.get_insert())
        self.set_sensitive(True)

        # Close the program after cleaning is completed.
        # if the option is selected under preference.

        if really_delete:
            if options.get("exit_done"):
                sys.exit()

        # notification for long-running process
        elapsed = (time.time() - self.start_time)
        logger.debug('elapsed time: %d seconds', elapsed)
        if elapsed < 10 or self.is_active():
            return
        try:
            gi.require_version('Notify', '0.7')
            from gi.repository import Notify
        except:
            logger.debug('Notify not available')
        else:
            if Notify.init(APP_NAME):
                notify = Notify.Notification.new('BleachBit', _("Done."),
                                                 'bleachbit')
                if os.name == 'posix' and bleachbit.expanduser('~') == '/root':
                    notify.set_hint("desktop-entry", "bleachbit-root")
                else:
                    notify.set_hint("desktop-entry", "bleachbit")
                notify.show()
                notify.set_timeout(10000)
Example #26
0
    def worker_done(self, worker, really_delete):
        """Callback for when Worker is done"""
        self.progressbar.set_text("")
        self.progressbar.set_fraction(1)
        self.progressbar.set_text(_("Done."))
        self.textview.scroll_mark_onscreen(self.textbuffer.get_insert())
        self.set_sensitive(True)

        # Close the program after cleaning is completed.
        # if the option is selected under preference.

        if really_delete:
            if options.get("exit_done"):
                sys.exit()

        # notification for long-running process
        elapsed = (time.time() - self.start_time)
        logger.debug('elapsed time: %d seconds', elapsed)
        if elapsed < 10 or self.window.is_active():
            return
        try:
            import pynotify
        except ImportError:
            logger.debug('pynotify not available')
        else:
            if pynotify.init(APP_NAME):
                notify = pynotify.Notification('BleachBit',
                                               _("Done."),
                                               icon='bleachbit')
                notify.show()
                notify.set_timeout(10000)
Example #27
0
    def __init__(self, uac=True, shred_paths=None, exit=False):
        if uac and 'nt' == os.name and Windows.elevate_privileges():
            # privileges escalated in other process
            sys.exit(0)
        Gtk.Application.__init__(self, application_id='org.gnome.Bleachbit', flags=Gio.ApplicationFlags.FLAGS_NONE)
        if not exit:
            from bleachbit import RecognizeCleanerML
            RecognizeCleanerML.RecognizeCleanerML()
            register_cleaners()
        GObject.threads_init()

        if shred_paths:
            self.shred_paths(shred_paths)
            return
        if 'nt' == os.name:
            # BitDefender false positive.  BitDefender didn't mark BleachBit as infected or show
            # anything in its log, but sqlite would fail to import unless BitDefender was in "game mode."
            # https://www.bleachbit.org/forum/074-fails-errors
            try:
                import sqlite3
            except ImportError:
                logger.exception(_("Error loading the SQLite module: the antivirus software may be blocking it."))
        if 'posix' == os.name and bleachbit.expanduser('~') == '/root':
            self.append_text(
                _('You are running BleachBit with administrative privileges for cleaning shared parts of the system, and references to the user profile folder will clean only the root account.'))
        if 'nt' == os.name and options.get('shred'):
            from win32com.shell.shell import IsUserAnAdmin
            if not IsUserAnAdmin():
                self.append_text(
                    _('Run BleachBit with administrator privileges to improve the accuracy of overwriting the contents of files.'))
                self.append_text('\n')
        if exit:
            # This is used for automated testing of whether the GUI can start.
            print('Success')
            GObject.idle_add(lambda: self.quit(), priority=GObject.PRIORITY_LOW)
Example #28
0
    def __init__(self, auto_exit, *args, **kwargs):
        super(GUI, self).__init__(*args, **kwargs)

        self.auto_exit = auto_exit

        self.set_wmclass(APP_NAME, APP_NAME)
        self.populate_window()

        # Redirect logging to the GUI.
        bb_logger = logging.getLogger('bleachbit')
        from bleachbit.Log import GtkLoggerHandler
        self.gtklog = GtkLoggerHandler(self.append_text)
        bb_logger.addHandler(self.gtklog)

        # process any delayed logs
        from bleachbit.Log import DelayLog
        if isinstance(sys.stderr, DelayLog):
            for msg in sys.stderr.read():
                self.append_text(msg)
            # if stderr was redirected - keep redirecting it
            sys.stderr = self.gtklog

        self.set_windows10_theme()
        Gtk.Settings.get_default().set_property(
            'gtk-application-prefer-dark-theme', options.get('dark_mode'))

        if options.is_corrupt():
            logger.error(
                _('Resetting the configuration file because it is corrupt: %s') % bleachbit.options_file)
            bleachbit.Options.init_configuration()

        GLib.idle_add(self.cb_refresh_operations)
Example #29
0
    def worker_done(self, worker, really_delete):
        """Callback for when Worker is done"""
        self.progressbar.set_text("")
        self.progressbar.set_fraction(1)
        self.progressbar.set_text(_("Done."))
        self.textview.scroll_mark_onscreen(self.textbuffer.get_insert())
        self.set_sensitive(True)

        # Close the program after cleaning is completed.
        # if the option is selected under preference.

        if really_delete:
            if options.get("exit_done"):
                sys.exit()

        # notification for long-running process
        elapsed = (time.time() - self.start_time)
        logger.debug('elapsed time: %d seconds', elapsed)
        if elapsed < 10 or self.window.is_active():
            return
        try:
            import pynotify
        except ImportError:
            logger.debug('pynotify not available')
        else:
            if pynotify.init(APP_NAME):
                notify = pynotify.Notification('BleachBit', _("Done."),
                                               icon='bleachbit')
                if 'posix' == os.name and bleachbit.expanduser('~') == '/root':
                    notify.set_hint("desktop-entry", "bleachbit-root")
                else:
                    notify.set_hint("desktop-entry", "bleachbit")
                notify.show()
                notify.set_timeout(10000)
Example #30
0
def clean_json(path, target):
    """Delete key in the JSON file"""
    import json
    changed = False
    targets = target.split('/')

    # read file to parser
    js = json.load(open(path, 'r'))

    # change file
    pos = js
    while True:
        new_target = targets.pop(0)
        if not isinstance(pos, dict):
            break
        if new_target in pos and len(targets) > 0:
            # descend
            pos = pos[new_target]
        elif new_target in pos:
            # delete terminal target
            changed = True
            del(pos[new_target])
        else:
            # target not found
            break
        if 0 == len(targets):
            # target not found
            break

    if changed:
        from bleachbit.Options import options
        if options.get('shred'):
            delete(path, True)
        # write file
        json.dump(js, open(path, 'w'))
Example #31
0
 def update_log_level(self):
     """Set the log level"""
     from bleachbit.Options import options
     if options.get('debug'):
         self.min_level = logging.DEBUG
     else:
         self.min_level = logging.WARNING
Example #32
0
def execute_sqlite3(path, cmds):
    """Execute 'cmds' on SQLite database 'path'"""
    import sqlite3
    import contextlib
    with contextlib.closing(sqlite3.connect(path)) as conn:
        cursor = conn.cursor()

        # overwrites deleted content with zeros
        # https://www.sqlite.org/pragma.html#pragma_secure_delete
        from bleachbit.Options import options
        if options.get('shred'):
            cursor.execute('PRAGMA secure_delete=ON')

        for cmd in cmds.split(';'):
            try:
                cursor.execute(cmd)
            except sqlite3.OperationalError as exc:
                if str(exc).find('no such function: ') >= 0:
                    # fixme: determine why randomblob and zeroblob are not
                    # available
                    logger.exception(exc.message)
                else:
                    raise sqlite3.OperationalError('%s: %s' % (exc, path))
            except sqlite3.DatabaseError as exc:
                raise sqlite3.DatabaseError('%s: %s' % (exc, path))

        cursor.close()
        conn.commit()
 def __init__(self, parent_window=None):
     self.parent_window = parent_window
     try:
         self.salt = options.get('hashsalt')
     except bleachbit.NoOptionError:
         self.salt = hashdigest(str(random.random()))
         options.set('hashsalt', self.salt)
     self.__scan()
 def __init__(self, parent_window=None):
     self.parent_window = parent_window
     try:
         self.salt = options.get('hashsalt')
     except bleachbit.NoOptionError:
         self.salt = hashdigest(os.urandom(512))
         options.set('hashsalt', self.salt)
     self.__scan()
Example #35
0
    def on_show(self, widget):
        # restore window position, size and state
        if not options.get('remember_geometry'):
            return
        if options.has_option("window_x") and options.has_option("window_y") and \
           options.has_option("window_width") and options.has_option("window_height"):
            r = Gdk.Rectangle()
            (r.x, r.y) = (options.get("window_x"), options.get("window_y"))
            (r.width, r.height) = (options.get("window_width"),
                                   options.get("window_height"))

            screen = self.get_screen()
            monitor_num = screen.get_monitor_at_point(r.x, r.y)
            g = screen.get_monitor_geometry(monitor_num)

            # only restore position and size if window left corner
            # is within the closest monitor
            if r.x >= g.x and r.x < g.x + g.width and \
               r.y >= g.y and r.y < g.y + g.height:
                logger.debug(
                    "closest monitor ({}) geometry = {}+{}, window geometry = {}+{}"
                    .format(monitor_num, (g.x, g.y), (g.width, g.height),
                            (r.x, r.y), (r.width, r.height)))
                self.move(r.x, r.y)
                self.resize(r.width, r.height)
        if options.get("window_fullscreen"):
            self.fullscreen()
        elif options.get("window_maximized"):
            self.maximize()
Example #36
0
    def sqlite_clean_helper(self, sql, fn, clean_func, check_func=None, setup_func=None):
        """Helper for cleaning special SQLite cleaning"""

        self.assertFalse(sql and fn, "sql and fn are mutually exclusive ways to create the data")

        if fn:
            filename = os.path.normpath(os.path.join(self.dir_base, fn))
            self.assertExists(filename)

        # create sqlite file
        elif sql:
            # create test file
            filename = self.mkstemp(prefix='bleachbit-test-sqlite')

            # additional setup
            if setup_func:
                setup_func(filename)

            # before SQL creation executed, cleaning should fail
            self.assertRaises(sqlite3.DatabaseError, clean_func, filename)
            # create
            FileUtilities.execute_sqlite3(filename, sql)
            self.assertExists(filename)
        else:
            raise RuntimeError('neither fn nor sql supplied')

        # clean the file
        old_shred = options.get('shred')
        options.set('shred', False, commit=False)
        self.assertFalse(options.get('shred'))
        clean_func(filename)
        options.set('shred', True, commit=False)
        self.assertTrue(options.get('shred'))
        options.set('shred', old_shred, commit=False)
        clean_func(filename)
        self.assertExists(filename)

        # check
        if check_func:
            check_func(self, filename)

        # tear down
        FileUtilities.delete(filename)
        self.assertNotExists(filename)
Example #37
0
def clean_ini(path, section, parameter):
    """Delete sections and parameters (aka option) in the file"""

    def write(parser, ini_file):
        """
        Reimplementation of the original RowConfigParser write function.

        This function is 99% same as its origin. The only change is
        removing a cast to str. This is needed to handle unicode chars.
        """
        if parser._defaults:
            ini_file.write("[%s]\n" % "DEFAULT")
            for (key, value) in parser._defaults.items():
                ini_file.write("%s = %s\n" %
                               (key, str(value).replace('\n', '\n\t')))
            ini_file.write("\n")
        for section in parser._sections:
            ini_file.write("[%s]\n" % section)
            for (key, value) in parser._sections[section].items():
                if key == "__name__":
                    continue
                if (value is not None) or (parser._optcre == parser.OPTCRE):
                    # The line bellow is the only changed line of the original function.
                    # This is the orignal line for reference:
                    # key = " = ".join((key, str(value).replace('\n', '\n\t')))
                    key = " = ".join((key, value.replace('\n', '\n\t')))
                ini_file.write("%s\n" % (key))
            ini_file.write("\n")

    encoding = detect_encoding(path) or 'utf_8_sig'

    # read file to parser
    config = bleachbit.RawConfigParser()
    config.optionxform = lambda option: option
    config.write = write
    with open(path, 'r', encoding=encoding) as fp:
        config.read_file(fp)

    # change file
    changed = False
    if config.has_section(section):
        if parameter is None:
            changed = True
            config.remove_section(section)
        elif config.has_option(section, parameter):
            changed = True
            config.remove_option(section, parameter)

    # write file
    if changed:
        from bleachbit.Options import options
        fp.close()
        if options.get('shred'):
            delete(path, True)
        with open(path, 'w', encoding=encoding, newline='') as fp:
            config.write(config, fp)
Example #38
0
    def build_app_menu(self):

        if os.name == 'nt':
            """
            Load windows 10 theme
            """
            exec_path = os.path.dirname(sys.executable)
            windows_10_theme_exe_path = os.path.normpath(
                os.path.join(exec_path, 'themes/windows10/gtk.css'))
            windows_10_theme_source_path = "themes/windows10/gtk.css"

            Bleachbit._style_provider = Gtk.CssProvider()

            if os.path.exists(windows_10_theme_exe_path):
                Bleachbit._style_provider.load_from_path(
                    windows_10_theme_exe_path)

            elif os.path.exists(windows_10_theme_source_path):
                Bleachbit._style_provider.load_from_path(
                    windows_10_theme_source_path)

            if options.get("win10_mode"):
                screen = Gdk.Display.get_default_screen(
                    Gdk.Display.get_default())
                Gtk.StyleContext.add_provider_for_screen(
                    screen, Bleachbit._style_provider, 600)
        """Build the application menu

        On Linux with GTK 3.24, this code is necessary but not sufficient for
        the menu to work. The headerbar code is also needed.

        On Windows with GTK 3.18, this cde is sufficient for the menu to work.
        """
        builder = Gtk.Builder()
        builder.add_from_file(bleachbit.app_menu_filename)
        menu = builder.get_object('app-menu')
        self.set_app_menu(menu)

        # set up mappings between <attribute name="action"> in app-menu.ui and methods in this class
        actions = {
            'shredFiles': self.cb_shred_file,
            'shredFolders': self.cb_shred_folder,
            'shredClipboard': self.cb_shred_clipboard,
            'wipeFreeSpace': self.cb_wipe_free_space,
            'makeChaff': self.cb_make_chaff,
            'shredQuit': self.cb_shred_quit,
            'preferences': self.cb_preferences_dialog,
            'diagnostics': self.diagnostic_dialog,
            'help': self.cb_help,
            'about': self.about
        }

        for action_name, callback in actions.items():
            action = Gio.SimpleAction.new(action_name, None)
            action.connect('activate', callback)
            self.add_action(action)
Example #39
0
def set_root_log_level():
    """Adjust the root log level

    This runs later in the application's startup process when the
    configuration is loaded or after a change via the GUI.
    """
    from bleachbit.Options import options
    is_debug = options.get('debug')
    root_logger = logging.getLogger('bleachbit')
    root_logger.setLevel(logging.DEBUG if is_debug else logging.INFO)
Example #40
0
    def run_operations(self, __widget):
        """Event when the 'delete' toolbar button is clicked."""
        # fixme: should present this dialog after finding operations

        # Disable delete confirmation message.
        # if the option is selected under preference.

        if options.get("delete_confirmation"):
            if not GuiBasic.delete_confirmation_dialog(self.window, True):
                return
        self.preview_or_run_operations(True)
Example #41
0
    def run_operations(self, __widget):
        """Event when the 'delete' toolbar button is clicked."""
        # fixme: should present this dialog after finding operations

        # Disable delete confirmation message.
        # if the option is selected under preference.

        if options.get("delete_confirmation"):
            if not GuiBasic.delete_confirmation_dialog(self, True):
                return
        self.preview_or_run_operations(True)
Example #42
0
 def __toggle_callback(self, cell, path):
     """Callback function to toggle option"""
     options.toggle(path)
     if online_update_notification_enabled:
         self.cb_beta.set_sensitive(options.get('check_online_updates'))
         if 'nt' == os.name:
             self.cb_winapp2.set_sensitive(
                 options.get('check_online_updates'))
     if 'auto_hide' == path:
         self.refresh_operations = True
     if 'dark_mode' == path:
         if 'nt' == os.name and options.get('win10_theme'):
             self.cb_set_windows10_theme()
         Gtk.Settings.get_default().set_property(
             'gtk-application-prefer-dark-theme', options.get('dark_mode'))
     if 'win10_theme' == path:
         self.cb_set_windows10_theme()
     if 'debug' == path:
         from bleachbit.Log import set_root_log_level
         set_root_log_level()
Example #43
0
def __shred_sqlite_char_columns(table, cols=None, where=""):
    """Create an SQL command to shred character columns"""
    cmd = ""
    if cols and options.get('shred'):
        cmd += "update or ignore %s set %s %s;" % \
            (table, ",".join(["%s = randomblob(length(%s))" % (col, col)
                              for col in cols]), where)
        cmd += "update or ignore %s set %s %s;" % \
            (table, ",".join(["%s = zeroblob(length(%s))" % (col, col)
                              for col in cols]), where)
    cmd += "delete from %s %s;" % (table, where)
    return cmd
Example #44
0
 def refresh_rows(self):
     """Clear rows (cleaners) and add them fresh"""
     if None != self.row_changed_handler_id:
         self.tree_store.disconnect(self.row_changed_handler_id)
     self.tree_store.clear()
     for key in sorted(backends):
         if not any(backends[key].get_options()):
             # localizations has no options, so it should be hidden
             # https://github.com/az0/bleachbit/issues/110
             continue
         c_name = backends[key].get_name()
         c_id = backends[key].get_id()
         c_value = options.get_tree(c_id, None)
         if not c_value and options.get('auto_hide') and backends[key].auto_hide():
             logger.debug("automatically hiding cleaner '%s'", c_id)
             continue
         parent = self.tree_store.append(None, (c_name, c_value, c_id, ""))
         for (o_id, o_name) in backends[key].get_options():
             o_value = options.get_tree(c_id, o_id)
             self.tree_store.append(parent, (o_name, o_value, o_id, ""))
     self.row_changed_handler_id = self.tree_store.connect("row-changed",
                                                           self.on_row_changed)
Example #45
0
    def __general_page(self):
        """Return a widget containing the general page"""

        if 'nt' == os.name:
            swcc = Windows.start_with_computer_check
        if 'posix' == os.name:
            swcc = Unix.start_with_computer_check

        options.set('auto_start', swcc())

        vbox = gtk.VBox()

        if online_update_notification_enabled:
            cb_updates = gtk.CheckButton(
                _("Check periodically for software updates via the Internet"))
            cb_updates.set_active(options.get('check_online_updates'))
            cb_updates.connect(
                'toggled', self.__toggle_callback, 'check_online_updates')
            cb_updates.set_tooltip_text(
                _("If an update is found, you will be given the option to view information about it.  Then, you may manually download and install the update."))
            vbox.pack_start(cb_updates, False)

            updates_box = gtk.VBox()
            updates_box.set_border_width(10)

            self.cb_beta = gtk.CheckButton(_("Check for new beta releases"))
            self.cb_beta.set_active(options.get('check_beta'))
            self.cb_beta.set_sensitive(options.get('check_online_updates'))
            self.cb_beta.connect(
                'toggled', self.__toggle_callback, 'check_beta')
            updates_box.pack_start(self.cb_beta, False)

            if 'nt' == os.name:
                self.cb_winapp2 = gtk.CheckButton(
                    _("Download and update cleaners from community (winapp2.ini)"))
                self.cb_winapp2.set_active(options.get('update_winapp2'))
                self.cb_winapp2.set_sensitive(
                    options.get('check_online_updates'))
                self.cb_winapp2.connect(
                    'toggled', self.__toggle_callback, 'update_winapp2')
                updates_box.pack_start(self.cb_winapp2, False)

            vbox.pack_start(updates_box, False)

        # TRANSLATORS: This means to hide cleaners which would do
        # nothing.  For example, if Firefox were never used on
        # this system, this option would hide Firefox to simplify
        # the list of cleaners.
        cb_auto_hide = gtk.CheckButton(_("Hide irrelevant cleaners"))
        cb_auto_hide.set_active(options.get('auto_hide'))
        cb_auto_hide.connect('toggled', self.__toggle_callback, 'auto_hide')
        vbox.pack_start(cb_auto_hide, False)

        # TRANSLATORS: Overwriting is the same as shredding.  It is a way
        # to prevent recovery of the data. You could also translate
        # 'Shred files to prevent recovery.'
        cb_shred = gtk.CheckButton(_("Overwrite contents of files to prevent recovery"))
        cb_shred.set_active(options.get('shred'))
        cb_shred.connect('toggled', self.__toggle_callback, 'shred')
        cb_shred.set_tooltip_text(
            _("Overwriting is ineffective on some file systems and with certain BleachBit operations.  Overwriting is significantly slower."))
        vbox.pack_start(cb_shred, False)

        cb_start = gtk.CheckButton(_("Start BleachBit with computer"))
        cb_start.set_active(options.get('auto_start'))
        cb_start.connect('toggled', self.__toggle_callback, 'auto_start')
        vbox.pack_start(cb_start, False)

        # Close the application after cleaning is complete.
        cb_exit = gtk.CheckButton(_("Exit after cleaning"))
        cb_exit.set_active(options.get('exit_done'))
        cb_exit.connect('toggled', self.__toggle_callback, 'exit_done')
        vbox.pack_start(cb_exit, False)

        # Disable delete confirmation message.
        cb_popup = gtk.CheckButton(_("Confirm before delete"))
        cb_popup.set_active(options.get('delete_confirmation'))
        cb_popup.connect(
            'toggled', self.__toggle_callback, 'delete_confirmation')
        vbox.pack_start(cb_popup, False)

        # Use base 1000 over 1024?
        cb_units_iec = gtk.CheckButton(
            _("Use IEC sizes (1 KiB = 1024 bytes) instead of SI (1 kB = 1000 bytes)"))
        cb_units_iec.set_active(options.get("units_iec"))
        cb_units_iec.connect('toggled', self.__toggle_callback, 'units_iec')
        vbox.pack_start(cb_units_iec, False)
        return vbox
Example #46
0
def delete(path, shred=False, ignore_missing=False, allow_shred=True):
    """Delete path that is either file, directory, link or FIFO.

       If shred is enabled as a function parameter or the BleachBit global
       parameter, the path will be shredded unless allow_shred = False.
    """
    from bleachbit.Options import options
    is_special = False
    path = extended_path(path)
    if not os.path.lexists(path):
        if ignore_missing:
            return
        raise OSError(2, 'No such file or directory', path)
    if 'posix' == os.name:
        # With certain (relatively rare) files on Windows os.lstat()
        # may return Access Denied
        mode = os.lstat(path)[stat.ST_MODE]
        is_special = stat.S_ISFIFO(mode) or stat.S_ISLNK(mode)
    if is_special:
        os.remove(path)
    elif os.path.isdir(path):
        delpath = path
        if allow_shred and (shred or options.get('shred')):
            delpath = wipe_name(path)
        try:
            os.rmdir(delpath)
        except OSError as e:
            # [Errno 39] Directory not empty
            # https://bugs.launchpad.net/bleachbit/+bug/1012930
            if errno.ENOTEMPTY == e.errno:
                logger.info("directory is not empty: %s", path)
            else:
                raise
        except WindowsError as e:
            # WindowsError: [Error 145] The directory is not empty:
            # 'C:\\Documents and Settings\\username\\Local Settings\\Temp\\NAILogs'
            # Error 145 may happen if the files are scheduled for deletion
            # during reboot.
            if 145 == e.winerror:
                logger.info("directory is not empty: %s", path)
            else:
                raise
    elif os.path.isfile(path):
        # wipe contents
        if allow_shred and (shred or options.get('shred')):
            try:
                wipe_contents(path)
            except pywinerror as e:
                # 2 = The system cannot find the file specified.
                # This can happen with a broken symlink
                # https://github.com/bleachbit/bleachbit/issues/195
                if 2 != e.winerror:
                    raise
                # If a broken symlink, try os.remove() below.
            except IOError as e:
                # permission denied (13) happens shredding MSIE 8 on Windows 7
                logger.debug("IOError #%s shredding '%s'", e.errno, path, exc_info=True)
            # wipe name
            os.remove(wipe_name(path))
        else:
            # unlink
            os.remove(path)
    else:
        logger.info("special file type cannot be deleted: %s", path)