diff -Nru /tmp/Jk5jXWKfRF/sbackup-0.10.3/debian/changelog /tmp/FlxBzI4QKq/sbackup-0.10.3/debian/changelog --- /tmp/Jk5jXWKfRF/sbackup-0.10.3/debian/changelog 2006-12-04 17:24:12.000000000 +0100 +++ /tmp/FlxBzI4QKq/sbackup-0.10.3/debian/changelog 2007-04-28 11:59:45.000000000 +0200 @@ -1,3 +1,31 @@ +sbackup (0.10.3-0.1ubuntu1) feisty; urgency=low + + * Non-maintainer upload. + * Enhancement. applied patch proposed by Oliver Gerlich. See: Bug #110113 + * GUI changes : + * added 2 radio boxes -simply and precisely on the Time Tab -. + Simply will use anacron, precisely will be the old behaviour + + * simple-backup-config : + * Code cleaned to prevent warnings about non existing GTK components : + see Bug #106818 + * To use anacron, sbackup creates a link to /usr/share/sbackup/sbackup + in /etc/cron.daily/ /etc/cron.monthly/ /etc/cron.weekly/ + /etc/cron.hourly/ if anacron option has been chosen + + * Created a sbackup script to install in /usr/share/sbackup/sbackup + (this script is almost the sme created by sbackup in /etc/cron.d/ + + * Makefile : + * add a flag to create non existing dirs + * install the "sbackup" script in "/usr/share/sbackup/sbackup" + + * the python files have been rename in *.py and the Makefile has been + changed to be compliant -links are created into BIN without + the py extention- + + -- Ouattara Oumar Aziz (alias wattazoum) Sat, 28 Apr 2007 10:08:29 +0200 + sbackup (0.10.3-0.1) unstable; urgency=high * Non-maintainer upload. diff -Nru /tmp/Jk5jXWKfRF/sbackup-0.10.3/debian/postrm /tmp/FlxBzI4QKq/sbackup-0.10.3/debian/postrm --- /tmp/Jk5jXWKfRF/sbackup-0.10.3/debian/postrm 2006-10-06 18:57:30.000000000 +0200 +++ /tmp/FlxBzI4QKq/sbackup-0.10.3/debian/postrm 2007-04-27 07:08:18.000000000 +0200 @@ -21,7 +21,7 @@ case "$1" in purge) - rm -f /etc/sbackup.conf /etc/cron.d/sbackup + rm -f /etc/sbackup.conf /etc/cron.d/sbackup /etc/cron.daily/sbackup /etc/cron.weekly/sbackup /etc/cron.monthly/sbackup /etc/cron.hourly/sbackup ;; diff -Nru /tmp/Jk5jXWKfRF/sbackup-0.10.3/Makefile /tmp/FlxBzI4QKq/sbackup-0.10.3/Makefile --- /tmp/Jk5jXWKfRF/sbackup-0.10.3/Makefile 2006-10-06 18:44:18.000000000 +0200 +++ /tmp/FlxBzI4QKq/sbackup-0.10.3/Makefile 2007-04-27 07:08:18.000000000 +0200 @@ -1,6 +1,5 @@ -PO = pt_BR lv nl es sv +PO = pt_BR lv nl es sv fr -DESTDIR = /usr/local PREFIX = /usr/local BIN = $(DESTDIR)/sbin/ SUPPORT = $(DESTDIR)/share/sbackup/ @@ -13,19 +12,25 @@ install: po-data install-po install -d $(BIN) $(SUPPORT) $(DOC) $(PIXDIR) $(DESTDIR)/share/applications $(DESTDIR)/etc - install ./sbackupd $(BIN) - install ./simple-backup-config $(BIN)/simple-backup-config - install ./simple-restore-gnome $(BIN)/simple-restore-gnome - install ./srestore.py $(BIN)/srestore.py - install ./upgrade_backups.py $(BIN)/upgrade_backups.py + install ./sbackupd.py $(SUPPORT) + ln -s ../share/sbackup/sbackupd.py $(BIN)/sbackupd + install ./simple-backup-config.py $(SUPPORT) + ln -s ../share/sbackup/simple-backup-config.py $(BIN)/simple-backup-config + install ./simple-restore-gnome.py $(SUPPORT) + ln -s ../share/sbackup/simple-restore-gnome.py $(BIN)/simple-restore-gnome + install ./srestore.py $(SUPPORT) + ln -s ../share/sbackup/srestore.py $(BIN)/srestore.py + install ./upgrade_backups.py $(SUPPORT) + ln -s ../share/sbackup/upgrade_backups.py $(BIN)/upgrade_backups.py # install ./simple-backup-tocd $(BIN) - install -m644 simple-backup-config.glade $(SUPPORT) - install -m644 sbackup-conf.png $(PIXDIR) - install -m644 sbackup-restore.png $(PIXDIR) - install -m644 sbackup.desktop $(DESTDIR)/share/applications/ - install -m644 srestore.desktop $(DESTDIR)/share/applications/ - install -m644 simple-restore.glade $(SUPPORT) -# install -m644 simple-backup-tocd.glade $(SUPPORT) + install -m644 -D simple-backup-config.glade $(SUPPORT) + install -m644 -D sbackup-conf.png $(PIXDIR) + install -m644 -D sbackup-restore.png $(PIXDIR) + install -m644 -D sbackup.desktop $(DESTDIR)/share/applications/ + install -m644 -D srestore.desktop $(DESTDIR)/share/applications/ + install -m644 -D simple-restore.glade $(SUPPORT) + install ./sbackup $(SUPPORT) +# install -m644 -D simple-backup-tocd.glade $(SUPPORT) ifeq ($(DESTDIR),/usr/local/) install -b -m600 sbackup.conf.example /etc/sbackup.conf @echo "[places]" >> /etc/sbackup.conf diff -Nru /tmp/Jk5jXWKfRF/sbackup-0.10.3/po/fr.po /tmp/FlxBzI4QKq/sbackup-0.10.3/po/fr.po --- /tmp/Jk5jXWKfRF/sbackup-0.10.3/po/fr.po 1970-01-01 01:00:00.000000000 +0100 +++ /tmp/FlxBzI4QKq/sbackup-0.10.3/po/fr.po 2007-04-27 07:08:18.000000000 +0200 @@ -0,0 +1,617 @@ +# French translation for sbackup +# Copyright (c) (c) 2006 Canonical Ltd, and Rosetta Contributors 2006 +# This file is distributed under the same license as the sbackup package. +# FIRST AUTHOR , 2006. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: sbackup\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2006-08-22 03:44+0100\n" +"PO-Revision-Date: 2007-04-19 12:21+0000\n" +"Last-Translator: Ouattara Aziz \n" +"Language-Team: French \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Rosetta-Export-Date: 2007-04-21 12:58:15+0000\n" + +#: simple-backup-config:65 +msgid "MP3 Music" +msgstr "Musique MP3" + +#: simple-backup-config:65 +msgid "AVI Video" +msgstr "Vidéo AVI" + +#: simple-backup-config:65 +msgid "MPEG Video" +msgstr "Vidéo MPEG" + +#: simple-backup-config:65 +msgid "Matrjoshka Video" +msgstr "Vidéo Matrjoshka" + +#: simple-backup-config:65 +msgid "OGG Multimedia container" +msgstr "Conteneur Multimédia OGG" + +#: simple-backup-config:65 +msgid "CD Images" +msgstr "Images CD" + +#: simple-backup-config:317 simple-backup-config:603 +msgid "Custom" +msgstr "Personnalisé" + +#: simple-backup-config:376 +msgid "Simple Backup Suite" +msgstr "Solution simple de sauvegarde" + +#: simple-backup-config:378 +msgid "" +"This is a user friendly backup solution for common desktop needs. The " +"project was was sponsored by Google during Google Summer of Code 2005 and " +"mentored by Ubuntu." +msgstr "" +"Ceci est une solution de sauvegarde conviviale pour les besoins courants " +"d'un usage sur le bureau. Ce projet a été sponsorisé dans le cadre du Google " +"Summer of Code 2005 avec Ubuntu comme mentor." + +#: simple-backup-config:381 +#, fuzzy +msgid "translator-credits" +msgstr "" +"Pierre Slamich \\nNicolas Velin " +"\\nGwendal Jabot " + +#: simple-backup-config:392 +msgid "A backup run is initiated in the background. The process id is: " +msgstr "Une sauvegarde est initiée en arrière-plan. L'id du processus est: " + +#: simple-backup-config:451 +msgid "Configuration save successful" +msgstr "La configuration a bien été sauvegardée" + +#: simple-backup-config:521 +msgid "Include file ..." +msgstr "Inclure un fichier ..." + +#: simple-backup-config:524 simple-backup-config:559 +msgid "All files" +msgstr "Tous les fichiers" + +#: simple-backup-config:537 +msgid "Include folder ..." +msgstr "Inclure un dossier ..." + +#: simple-backup-config:556 +msgid "Exclude file ..." +msgstr "Exclure un fichier ..." + +#: simple-backup-config:572 +msgid "Exclude folder ..." +msgstr "Exclure un dossier ..." + +#: simple-backup-config:648 +msgid "Empty expression. Please enter a valid regular expression." +msgstr "Expression vide. Veuillez entrer une expression régulière valide." + +#: simple-backup-config:665 +msgid "Empty filename or path. Please enter a valid filename or path." +msgstr "" +"Nom de fichier ou chemin vide. Veuillez entrer un nom de fichier ou un " +"chemin valide." + +#: simple-backup-config:671 +msgid "" +"It seems the path you entered does not exists. Do you want to add this wrong " +"path?" +msgstr "" +"Il semble que le chemin que vous avez indiqué n'existe pas. Voulez-vous " +"ajouter ce chemin incorrect?" + +#: simple-backup-config:859 +msgid "Currently backup configuration is only runnable by root" +msgstr "" +"La configuration actuelle de sauvegarde n'est exécutable que par " +"l'utilisateur root" + +#: simple-restore-gnome:137 +msgid "Path" +msgstr "Chemin" + +#: simple-restore-gnome:171 simple-restore-gnome:175 +msgid "Error: backups directory does not exist!" +msgstr "Erreur: le répertoire de sauvegardes n'existe pas !" + +#: simple-restore-gnome:212 +msgid "" +"Some of your backups are in an old backup format. Do you want to upgrade " +"them?\n" +"It should take only a few minutes." +msgstr "" +"Certaines de vos sauvegardes sont dans un ancien format de sauvegarde. " +"Voulez-vous les mettre à jour?\n" +"Cela ne devrait prendre que quelques minutes." + +#: simple-restore-gnome:232 +msgid "Error: no backups found in the target directory" +msgstr "Erreur: aucune sauvegarde n'a été trouvée dans le répertoire cible" + +#: simple-restore-gnome:249 +msgid "" +"Select any of the available backups to see list of files that can be " +"restored." +msgstr "" +"Sélectionnez n'importe laquelle des sauvegardes disponibles pour voir la " +"liste des fichiers qui peuvent être restaurés." + +#: simple-restore-gnome:254 +msgid "Choose a source folder" +msgstr "Choisissez un dossier source" + +#: simple-restore-gnome:333 +msgid "Loading ..." +msgstr "Chargement en cours ..." + +#: simple-restore-gnome:374 +msgid "Sorry, help is not implemented yet." +msgstr "Désolé, l'aide n'est pas encore implémentée." + +#: simple-restore-gnome:386 +#, python-format +msgid "Do you really want to restore backuped copy of '%s' to '%s' ?" +msgstr "" +"Voulez-vous vraiment restaurer la copie sauvegardée de '%s' vers '%s' ?" + +#: simple-restore-gnome:391 +msgid "Restoring ..." +msgstr "Restauration en cours ..." + +#: simple-restore-gnome:409 simple-restore-gnome:418 +msgid "Select restore location" +msgstr "Sélectionnez l'emplacement de restauration" + +#: srestore.py:74 +msgid "E: File not found in the backup snapshot" +msgstr "E: Fichier introuvable dans la sauvegarde instantannée." + +#: srestore.py:149 +msgid "Simple Backup suit command line restore utility\n" +msgstr "" +"Utilitaire de restauration en ligne de commande de solution simple de " +"sauvegarde\n" + +#: srestore.py:150 +msgid "" +" Usage: simple-restore backup-url file-or-dir-to-restore [target-file-or-dir]" +msgstr "" +" Usage : restauration-simple url-de-sauvegarde fichier-ou-rep-à-restaurer " +"[fichier-ou-rep-cible]" + +#: srestore.py:151 +#, fuzzy +msgid "" +" Note: backup-url must include the snapshot subdirectory name, for example:" +msgstr "" +" Note: url-de-sauvegarde doit inclure le nom du sous répertoire de la " +"sauvegarde précise, par exemple:" + +#: srestore.py:153 +msgid " Use simple-restore-gnome for more ease of use.\n" +msgstr " Utilisez simple-restore-gnome pour plus de facilité d'usage.\n" + +#: srestore.py:162 +msgid "Restore FAILED! Please check you parameters." +msgstr "La restauration a ECHOUE ! Veuillez vérifier vos paramètres." + +#: upgrade_backups.py:37 +#, python-format +msgid "I: Securing target directory at: %s" +msgstr "l: Sécurisation du dossier cible à : %s" + +#: upgrade_backups.py:69 +#, python-format +msgid "I: Securing permissions at: %s" +msgstr "l: Sécurisation des permissions à : %s" + +#: upgrade_backups.py:74 +#, python-format +msgid "I: Upgrading from v1.0 to v1.2: %s" +msgstr "l: Mise à jour de v1.0 vers v1.2 : %s" + +#: upgrade_backups.py:80 +#, python-format +msgid "I: Upgradeing to v1.3: %s" +msgstr "l: Mise à jour vers v1.3 : %s" + +#: upgrade_backups.py:118 +#, python-format +msgid "W: Damaged backup metainfo - file with newline detected: %s" +msgstr "" +"W : métainfo de sauvegarde endommagée - fichier avec retour à la ligne " +"détecté : %s" + +#: upgrade_backups.py:119 +msgid "I: Recovering file info ... this can take some time." +msgstr "" +"l: Récupération des informations du file ... cela peut prendre un certain " +"temps." + +#: upgrade_backups.py:128 +msgid "I: Recovery complete." +msgstr "I: Recouvrement des données terminé" + +#: upgrade_backups.py:315 +msgid "" +"\n" +"Simple Backup suit command line backup format upgrade\n" +"Usage: upgrade-backup backup-target-url\n" +"Note: backup-target-url must not include the snapshot subdirectory name, for " +"example:\n" +"\n" +" /var/backup/\n" +"\n" +"Use simple-restore-gnome for more ease of use.\n" +msgstr "" +"\n" +"Utilitaire en ligne de commande de mise à jour du format de sauvegarde de la " +"suite Simple Backup\n" +"Usage : upgrade-backup chemin-de-sauvegarde-cible\n" +"Note : chemin-de-sauvegarde-cible ne doit pas inclure de sous-répertoire de " +"sauvegarde précise, par exemple :\n" +"\n" +" /var/sauvegarde/\n" +"\n" +"Utilisez simple-restore-gnome pour plus de facilité d'utilisation.\n" + +#: simple-backup-config.glade:9 +msgid "Backup Properties" +msgstr "Propriétés de Sauvegarde" + +#: simple-backup-config.glade:53 +msgid "" +"Do backup now, with configuration above. Don't forget to save any " +"modification before click this button." +msgstr "" +"Faites une sauvegarde maintenant, avec la configuration ci-dessus. N'oubliez " +"pas de sauver toute modification avant de clicker sur ce bouton." + +#: simple-backup-config.glade:99 +msgid "_Backup Now!" +msgstr "_Sauvegarder Maintenant !" + +#: simple-backup-config.glade:130 +msgid "Saves any modification made in the backup configuration above." +msgstr "" +"Sauvegarde toute modification faite dans la configuration de sauvegarde ci-" +"dessus." + +#: simple-backup-config.glade:188 +msgid "Use recommended backup settings" +msgstr "Utiliser les paramètres de sauvegarde recommandés" + +#: simple-backup-config.glade:239 +msgid "" +"Do standard backups.\n" +"Defaults: daily incremental and weekly full backup to /var/backup of all " +"user files, /etc, /usr/local and /var. \n" +"Multimedia files, temporary files and files larger than 100 Mb are " +"excluded." +msgstr "" +"Faites des sauvegardes standards.\n" +"Par défaut : sauvegardes complètes quotidiennes incrémentales et " +"hebdomadaires vers /var/sauvegarde de tout les fichiers de l'utilisateur.\n" +"Les fichiers multimedia, les fichiers temporaires et les fichiers plus grand " +"que 100 Mo sont exclus." + +#: simple-backup-config.glade:274 +msgid "Use custom backup settings" +msgstr "Utiliser des paramètres de sauvegarde personnels" + +#: simple-backup-config.glade:326 +msgid "" +"Do backups according to the settings defined on the next pages of " +"this dialog." +msgstr "" +"Faire des sauvegardes selon les paramètres définis dans les pages " +"suivantes de ce dialogue. " + +#: simple-backup-config.glade:359 +msgid "Manual backups only" +msgstr "Sauvegardes manuelles uniquement" + +#: simple-backup-config.glade:411 +msgid "" +"Do not backup your data automatically. Note: this does not prevent " +"doing manual backups." +msgstr "" +"Ne pas sauvegarder automatiquement vos données. Notez bien: ceci ne " +"vous empêche pas de faire des sauvegardes manuelles." + +#: simple-backup-config.glade:449 +msgid "General" +msgstr "Général" + +#: simple-backup-config.glade:561 simple-backup-config.glade:816 +msgid "Add File" +msgstr "Ajouter un Fichier" + +#: simple-backup-config.glade:636 simple-backup-config.glade:891 +msgid "Add Directory" +msgstr "Ajouter un Répertoire" + +#: simple-backup-config.glade:694 +msgid "Include" +msgstr "Inclure" + +#: simple-backup-config.glade:949 +msgid "Paths" +msgstr "Chemins" + +#: simple-backup-config.glade:1055 +msgid "File types" +msgstr "Types de fichiers" + +#: simple-backup-config.glade:1161 +msgid "Regex" +msgstr "Exp. rég." + +#: simple-backup-config.glade:1201 +msgid "Do not backup files bigger than " +msgstr "Ne pas sauvegarder de fichiers plus gros que " + +#: simple-backup-config.glade:1240 +msgid "Mb" +msgstr "Mb" + +#: simple-backup-config.glade:1302 +msgid "Max size" +msgstr "Taille Maxi" + +#: simple-backup-config.glade:1331 +msgid "Exclude" +msgstr "Exlure" + +#: simple-backup-config.glade:1361 +msgid "Use default backup directory (/var/backup)" +msgstr "Utiliser le répertoire de sauvegarde par défaut (/var/backup)" + +#: simple-backup-config.glade:1381 +msgid "Use custom local backup directory" +msgstr "Utiliser un répertoire de sauvegarde personnalisé" + +#: simple-backup-config.glade:1424 +msgid "Select the destination folder" +msgstr "Choisissez le dossier de destination" + +#: simple-backup-config.glade:1450 +msgid "Use a remote directory (SSH or FTP)" +msgstr "Utiliser un répertoire distant (SSH ou FTP)" + +#: simple-backup-config.glade:1476 +msgid "" +"Please test writability of the target directory by pressing \"Test\" button " +"on the right." +msgstr "" +"Veuillez tests la capacité d'écriture du répertoire cible en appuyant sur le " +"bouton \"Test\" sur la droite." + +#: simple-backup-config.glade:1506 +msgid "ssh://username:password@example.com/remote/dir/" +msgstr "ssh://nomdutilisateur:motdepasse@exemple.fr/distant/repertoire/" + +#: simple-backup-config.glade:1566 +msgid "Test" +msgstr "Test" + +#: simple-backup-config.glade:1635 +msgid "" +"The selected destination is not writtable with current permissions.\n" +"The backups can not be written there." +msgstr "" +"La destination sélectionnée n'est pas écrivable avec les permissions " +"actuelles.\n" +"Les sauvegardes ne peuvent pas être écrites ici." + +#: simple-backup-config.glade:1679 +msgid "Destination" +msgstr "Destination" + +#: simple-backup-config.glade:1718 +msgid "Do backups " +msgstr "Faire des sauvegardes " + +#: simple-backup-config.glade:1744 +msgid "" +"never\n" +"hourly\n" +"daily\n" +"weekly\n" +"monthly\n" +"custom" +msgstr "" +"jamais\n" +"chaque heure\n" +"chaque jour\n" +"chaque semaine\n" +"chaque mois\n" +"personnalisé" + +#: simple-backup-config.glade:1764 +msgid "at:" +msgstr "à:" + +#: simple-backup-config.glade:1805 +msgid "Day of month:" +msgstr "Jour du mois:" + +#: simple-backup-config.glade:1833 +msgid "Day of week:" +msgstr "Jour de la semaine:" + +#: simple-backup-config.glade:1861 +msgid "Hour" +msgstr "Heure" + +#: simple-backup-config.glade:1889 +msgid "Minute" +msgstr "Minute" + +#: simple-backup-config.glade:2041 +msgid "Custom cron time definition: " +msgstr "Délai personnalisé du démon cron : " + +#: simple-backup-config.glade:2104 +msgid "Do a full backup at least once every" +msgstr "Faire une sauvegarde complète au moins tous les" + +#: simple-backup-config.glade:2149 simple-backup-config.glade:2366 +msgid "days" +msgstr "jours" + +#: simple-backup-config.glade:2204 +msgid "" +"You can configure how often to start a backup run and when to do it.\n" +"Unless a set number of days has passed since the last full backup, " +"incremental backups will be done.\n" +"See \"man 5 crontab\" for cron time definition format." +msgstr "" +"Vous pouvez configurer la fréquence de démarrage d'une sauvegarde et " +"quand le faire.\n" +"A moins qu'un nombre prédéfini de jours a passé depuis la dernière " +"sauvegarde complète, des sauvegardes incrémentalles seront faites." + +#: simple-backup-config.glade:2244 +msgid "Time" +msgstr "Heure" + +#: simple-backup-config.glade:2274 +msgid "Enable purging of old and incomplete backups" +msgstr "Activer la purge des sauvegardes vieilles et incomplètes" + +#: simple-backup-config.glade:2326 +msgid "Simple cutoff: Erase all backups older than " +msgstr "Simple coupure : Effacer toutes les sauvegardes plus vieilles que " + +#: simple-backup-config.glade:2431 +msgid "Logarithmic (Recommended)" +msgstr "Logarithmique (Recommandé)" + +#: simple-backup-config.glade:2452 +msgid "" +"Keep progressivelly less backups into the past:\n" +"Keep all backups from yesterday.\n" +"Keep one backup per day from last week.\n" +"Keep one backup per week from last month.\n" +"Keep one backup per month from last year.\n" +"Keep one backup per year further into past.\n" +"Erase all other backups.\n" +msgstr "" +" Garder progressivement moins de sauvegardes dans le passé :\n" +"Garder toutes les sauvegardes d'hier.\n" +"Garder une sauvegarde par jour de la semaine dernière.\n" +"Garder une sauvegarde par semaine du mois derniere.\n" +"Garder une sauvegarde par moins de l'année dernière.\n" +"Garder une sauvegarde par an plus loin dans le passé. \n" + +#: simple-backup-config.glade:2514 +msgid "" +"Note: Additionally all incomplete and irrecoverable backups will be " +"erased as long as there is a complete backup snapshot made later on." +msgstr "" +"Note : En plus, toutes les sauvegardes non terminées ou non " +"récupérables seront effacées tant qu'il y a une sauvegarde instantannée " +"complète faite plus tard." + +#: simple-backup-config.glade:2552 +msgid "Purging" +msgstr "Nettoyage" + +#: simple-backup-config.glade:2567 +msgid "Cleaning old backups" +msgstr "Purge des anciennes sauvegardes en cours" + +#: simple-backup-config.glade:2586 +msgid "Exclude file type" +msgstr "Exclure un type de fichier" + +#: simple-backup-config.glade:2657 +msgid "Standard file types:" +msgstr "Types standards de fichiers" + +#: simple-backup-config.glade:2703 +msgid "Custom defined file type with " +msgstr "Définir de façon personnalisée le type de fichier avec " + +#: simple-backup-config.glade:2743 +msgid "file extension" +msgstr "extension de fichier" + +#: simple-backup-config.glade:2783 +msgid "Exclude by regex" +msgstr "Exclure par regex (expression régulière)" + +#: simple-backup-config.glade:2855 +msgid "" +"Enter a regular expression.\n" +"Files and directories matching this expression will be excluded from backup." +msgstr "" +"Entre une expression régulière.\n" +"Les fichiers et les répertoires correspondant à cette expression seront " +"exclus de la sauvegarde." + +#: simple-backup-config.glade:2885 +msgid "$.*\\.mp3^" +msgstr "$.*\\.mp3^" + +#: simple-restore.glade:8 +msgid "Restore files/directories" +msgstr "Restaurer des fichiers/ dossiers" + +#: simple-restore.glade:42 +msgid "Restore Source Folder" +msgstr "Restaurer le Dossier de Source" + +#: simple-restore.glade:113 +msgid "Use default:" +msgstr "Utiliser celui defini par défaut :" + +#: simple-restore.glade:136 +#, fuzzy +msgid "Use custom:" +msgstr "Utiliser la personnalisation :" + +#: simple-restore.glade:194 +msgid "" +"Type in this box text like that:\n" +"\n" +"/home/user/folder - To use a local folder\n" +"ssh://user:password@machine:/remote/folder - To use a ssh location\n" +"ssh://user:password@machine:/remote/folder - To use a ftp location" +msgstr "" +"Entrez dans cette zone de texte comme cela :\n" +"\n" +"/home/utilisateur/dossier - Pour utiliser a dossier local\n" +"ssh://utilisateur:mot-de-passe@machine:/dossier/distant - Pour utiliser un " +"emplacement ssh\n" +"ftp://utilisateur:mot-de-passe@machine:/dossier/distant - Pour utiliser un " +"emplacement ftp" + +#: simple-restore.glade:273 +msgid "Available backups:" +msgstr "Sauvegardes disponibles:" + +#: simple-restore.glade:360 +msgid "Files and Folders to restore" +msgstr "Fichiers et Dossiers à restaurer" + +#: simple-restore.glade:544 +msgid "Restore" +msgstr "Restaurer" + +#: simple-restore.glade:620 +msgid "Restore As..." +msgstr "Restaurer en tant que..." \ Pas de fin de ligne à la fin du fichier. diff -Nru /tmp/Jk5jXWKfRF/sbackup-0.10.3/sbackup /tmp/FlxBzI4QKq/sbackup-0.10.3/sbackup --- /tmp/Jk5jXWKfRF/sbackup-0.10.3/sbackup 1970-01-01 01:00:00.000000000 +0100 +++ /tmp/FlxBzI4QKq/sbackup-0.10.3/sbackup 2007-04-27 07:08:18.000000000 +0200 @@ -0,0 +1,7 @@ +#!/bin/bash +# +# Sbackup Service file used by anacron + +if [ -x /usr/sbin/sbackupd ] +then /usr/sbin/sbackupd +fi diff -Nru /tmp/Jk5jXWKfRF/sbackup-0.10.3/sbackupd /tmp/FlxBzI4QKq/sbackup-0.10.3/sbackupd --- /tmp/Jk5jXWKfRF/sbackup-0.10.3/sbackupd 2006-10-06 19:14:57.000000000 +0200 +++ /tmp/FlxBzI4QKq/sbackup-0.10.3/sbackupd 1970-01-01 01:00:00.000000000 +0100 @@ -1,564 +0,0 @@ -#!/usr/bin/python -# -# Simple Backup suit -# -# Running this command will execute a single backup run according to a configuration file -# -# Author: Aigars Mahinovs -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -import sys -import os -import errno -import atexit -import stat -import datetime -import time -import os.path -import cPickle as pickle -import shutil -import ConfigParser -import re -import socket -import tempfile -import upgrade_backups -import getopt -try: - import gnomevfs -except ImportError: - import gnome.vfs as gnomevfs - -# Classes we use but that are not worth putting them in their own module -class MyConfigParser(ConfigParser.ConfigParser): - def __init__(self, verbose = False): - self.verbose = verbose - if self.verbose: print "MyConfigParser.__init__" - ConfigParser.ConfigParser.__init__(self); - self.valid_options = {} - self.filename_from_argv = None - self.filename = "" - self.argv_options = {} - - def set_valid_options(self, valid_options, parse_commandline = False): - pass - self.valid_options = valid_options - if parse_commandline and self.valid_options: - self.parse_commandline() - - def read(self, filename): - if self.verbose: print "MyConfigParser.read(%s)" % filename - - self.filename = self.filename_from_argv or filename - retValue = ConfigParser.ConfigParser.read(self, self.filename) - if self.valid_options: self.validate_config_file_options() - if self.argv_options: self.validate_argv_options() - if self.valid_options: self.validate_option_values() - return retValue - - def optionxform(self, option): - return str( option ) - - def parse_commandline(self): - if self.verbose: print "MyConfigParser.parse_commandline" - argv_parameters = [ "config-file=" ] - for section, data in self.valid_options.iteritems(): - for (key, vtype) in data.iteritems(): - if (key == '*') : continue - argv_parameters.append("%s:%s="% (section, key)) - (options, reminder) = \ - getopt.getopt(sys.argv[1:], '', argv_parameters) - self.argv_options = dict(options) - if (self.argv_options.has_key("--config-file")): - self.filename_from_argv = self.argv_options["--config-file"] - del self.argv_options["--config-file"] - - - def validate_config_file_options(self): - if self.verbose: print "MyConfigParser.validate_config_file_options" - if (self.valid_options is None): return - for section in self.sections(): - try: - for key in self.options(section): - if (not self.valid_options.has_key(section)): - raise Exception ("section [%s] in %s should not exist, aborting" % (section, config)) - if (self.valid_options[section].has_key(key) or - self.valid_options[section].has_key('*')): - continue - raise Exception ("key %s in section %s in file %s is not known,\na typo possibly?" - % (key, section, config)) - except Exception, e: - print e - sys.exit(1); - - def validate_argv_options(self): - if self.verbose: print "MyConfigParser.validate_argv_options" - for parameter, value in self.argv_options.iteritems(): - parameter = parameter[2:] - (section, key) = parameter.split(":") - self.set(section,key, value) - - def validate_option_values(self): - # check if all keys defined in valid_options have values now - pass -# for section, data in self.valid_options.iteritems(): -# for key, vtype in data.iteritems(): -# if key == '*': continue -# try: -# value = self.get(section, key) -# except Exception, e: -# raise Exception ("The definition for %s:%s is missing.\nDefine in the config file or on the command line" % -# (section, key)) -# if vtype is list: -# pass -# else: -# self.set(section, key, vtype(value)) - - def all_options(self): - retVal = [] - for section in self.sections(): - for key in self.options(section): - value = self.get(section, key, raw = True) - retVal.append( (key,value)) - return retVal - - def __str__(self): - retVal = [] - for section, sec_data in self._sections.iteritems(): - retVal.append("[%s]" % section) - [retVal.append("%s = %s" % (o, repr(v))) - for o, v in sec_data.items() - if o != '__name__'] - return "\n".join(retVal) - - -# Default values, constants and the like -our_options = { - 'general' : { 'target' : str , 'lockfile' : str , 'maxincrement' : int , 'format' : int, 'purge' : str }, - 'dirconfig' : { '*' : str }, - 'exclude' : { 'regex' : list, 'maxsize' : int }, - 'places' : { 'prefix' : str } -} - -# Define default values & load config file - -config = "/etc/sbackup.conf" -target = "/var/backup/" -increment = 0 -lockfile = "/var/lock/sbackup.lock" -hostname = socket.gethostname() -maxincrement = 7 -# Backup format: 1 - allways use .tar.gz -format=1 -os.umask( 077 ) - -# directories allready added to the archive -dirs_in = ["/"] - -dirconfig = { "/etc/":1, "/home/":1, "/usr/local/": 1, "/root/":1, "/var/": 1, "/var/cache/":0, "/var/spool/":0, "/var/tmp/":0 } -gexclude = [r"\.mp3",r"\.avi",r"\.mpeg",r"\.mkv",r"\.ogg", r"\.iso"] -maxsize = 10*1024*1024 - -# Check our user id -if os.geteuid() != 0: sys.exit ("Currently backup is only runnable by root") - -# second we read the config file, so must check if the user provided one on the -# commando line. - -#try: -conf = MyConfigParser() -conf.set_valid_options( our_options, parse_commandline = True) -conf.read( config ) -#except Exception, e: -# print "Error while reading config,\n"+str(e) -# sys.exit(1) -#else: -# pass - -for option, value in conf.all_options(): - # skip options with a funny name, notably the dirs in [dirconfig] - if re.search ("\W", option): continue - # print "setting %s = %s" % (option, value) - globals()[option]=value - -if not target: - print "Option target is missing, aborting." - sys.exit(1) - -if conf.has_section( "dirconfig" ): - dirconfig = dict([ (k, int(v)) for k,v in conf.items("dirconfig") ] ) -if conf.has_option( "exclude", "regex" ): - gexclude = str(conf.get( "exclude", "regex" )).split(",") - -rexclude = [ re.compile(p) for p in gexclude if len(p)>0] - -flist = False -flistid = 0 -flist_name = "" -fprops = False - -def btree_r_add( adir ): - """Add a directory to the btree with reversed recursion - take defaults from parent""" - global btree - - os.path.normpath( adir ) - - parent2 = os.path.split( adir )[0] - parent = parent2 - if parent == "/": - parent = "" - if adir in btree: - pass - elif parent in btree: - props = btree[parent] - for child in os.listdir( parent2 ): - btree[os.path.normpath(parent+"/"+child)] = props - btree[parent] = (-1, btree[parent][1], btree[parent][2]) - else: - btree_r_add( parent ) - props = btree[parent] - for child in os.listdir( parent2 ): - btree[os.path.normpath(parent+"/"+child)] = props - btree[parent] = (-1, btree[parent][1], btree[parent][2]) - -def is_parent( parent, child ): - """ Compares directories - returns child only if it is a child of the parent """ - if str(child)[0:len(parent)] == parent: - return child - else: - return False - -def do_backup_init( ): - global flist, flistid, flist_name, fprops, fpropsid, fprops_name - if local: - (flistid, flist_name) = tempfile.mkstemp() - flist = os.fdopen( flistid, "w" ) - fprops = open(tdir+"/fprops", "w") - else: - (flistid, flist_name) = tempfile.mkstemp() - flist = os.fdopen( flistid, "w" ) - (fpropsid, fprops_name) = tempfile.mkstemp() - fprops = os.fdopen( fpropsid, "w" ) - -def do_backup_finish( ): - flist.close() - fprops.close() - tarline = "tar -czS -C / --no-recursion --ignore-failed-read --null -T "+flist_name+" " - if local: - tarline = tarline+" --force-local -f "+tdir.replace(" ", "\ ")+"/files.tgz" - tarline = tarline+" 2>/dev/null" - os.system( tarline ) - shutil.move( flist_name, tdir+"/flist" ) - else: - tarline = tarline+" 2>/dev/null" - turi = gnomevfs.URI( tdir+"/files.tgz" ) - tardst = gnomevfs.create( turi, 2 ) - tarsrc = os.popen( tarline ) - shutil.copyfileobj( tarsrc, tardst, 100*1024 ) - tarsrc.close() - tardst.close() - s1 = open( fprops_name, "r" ) - turi = gnomevfs.URI( tdir+"/fprops" ) - d1 = gnomevfs.create( turi, 2 ) - shutil.copyfileobj( s1, d1 ) - s1.close() - d1.close() - s2 = open( flist_name, "r" ) - turi = gnomevfs.URI( tdir+"/flist" ) - d2 = gnomevfs.create( turi, 2 ) - shutil.copyfileobj( s2, d2 ) - s2.close() - d2.close() - -def do_add_dir ( dirname, props ): - do_add_file( dirname, props ) - -def do_add_file( dirname, props ): - parent = os.path.split( dirname )[0] - if not parent in dirs_in and parent != dirname: - s = os.lstat( parent ) - do_add_dir( parent, str(s.st_mode)+str(s.st_uid)+str(s.st_gid)+str(s.st_size)+str(s.st_mtime)) - flist.write( dirname+"\000" ) - fprops.write( props+"\000" ) - dirs_in.append( dirname ) - -def do_backup( adir ): - """ Finds all files to be backuped in the directory and calls respective backup suroutines """ - s = os.lstat(adir) - parent = os.path.split( adir )[0] - if not os.path.isdir(adir) or os.path.islink(adir): - if s.st_size > maxsize or prev.count( adir+","+str(s.st_mode)+str(s.st_uid)+str(s.st_gid)+str(s.st_size)+str(s.st_mtime) ): - return [] - for r in rexclude: - if r.search( adir ): - return [] - do_add_file( adir, str(s.st_mode)+str(s.st_uid)+str(s.st_gid)+str(s.st_size)+str(s.st_mtime) ) - else: - if not increment: - do_add_dir( adir, str(s.st_mode)+str(s.st_uid)+str(s.st_gid)+str(s.st_size)+str(s.st_mtime) ) - for child in os.listdir( adir ): - if os.path.isdir( adir+"/"+child ) and not os.path.islink( adir+"/"+child ): - do_backup( adir+"/"+child ) - else: - try: s = os.lstat( adir+"/"+child ) - except: continue - if maxsize > 0 and s.st_size > maxsize: - continue - if prev.count( adir+"/"+child+","+str(s.st_mode)+str(s.st_uid)+str(s.st_gid)+str(s.st_size)+str(s.st_mtime) ): - continue - skip=False - for r in rexclude: - if r.search( adir+"/"+child ): - skip=True - if skip: - continue - do_add_file( adir+"/"+child, str(s.st_mode)+str(s.st_uid)+str(s.st_gid)+str(s.st_size)+str(s.st_mtime) ) - -# End of helpfull functions :) - -good = False - -# Create the lockfile so noone disturbs us -try: - open( lockfile, "r" ) -except IOError: - good = True -if not good : sys.exit ("E: Another Simple Backup daemon already running: exiting") - -try: - lock = open( lockfile, "w+" ) -except IOError: - print "E: Cann't create a lockfile: ", sys.exc_info()[1] - sys.exit(1) - -def exitfunc(): - # All done - # Remove lockfile - lock.close - os.remove (lockfile) - -atexit.register(exitfunc) - -# Checking if the target directory is local or remote -local = True - -try: - if gnomevfs.get_uri_scheme( target ) == "file": - target = gnomevfs.get_local_path_from_uri( target ) - else: - local = False -except: - pass - -# Checking if the target directory exists (or can be created) -ok = -1 -tinfo = False -try: # Get target directory info - tinfo = gnomevfs.get_file_info( target ) -except: - try: # Try to create it, in case, it doesn't exist - gnomevfs.make_directory( target, 0700 ) - tinfo = gnomevfs.get_file_info( target ) - except: - ok = False -try: - if tinfo.valid_fields == 0: - ok = False -except: - ok = False - -if ok==-1: - # Now try to write to the target dir - try: - test = str( time.time() ) - gnomevfs.make_directory( target+"/"+test, 0700 ) - gnomevfs.remove_directory( target+"/"+test ) - ok = True - except: - ok = False - -if not ok: - print "E: Target directory is not writable - please test in simple-config-gnome!" - sys.exit(1) - -# Upgrade directories to new format -# and purge old backups - -purge = 0 -if conf.has_option("general", "purge"): - purge = conf.get("general", "purge") - -upgrader = upgrade_backups.SBUpgrade() -upgrader.upgrade_target( target, purge ) - -# Determine whether to do a full or incremental backup - -r = re.compile(r"^(\d{4})-(\d{2})-(\d{2})_(\d{2})[\:\.](\d{2})[\:\.](\d{2})\.\d+\..*?\.(.+)$") - -if local: - listing = os.listdir( target ) - listing = filter( r.search, listing ) -else: - d = gnomevfs.open_directory( target ) - listing = [] - for f in d: - if f.type == 2 and f.name != "." and f.name != ".." and r.search( f.name ): - listing.append( f.name ) - -listing.sort() -listing.reverse() - -# Check if these directories are complete and remove from the list those that are not -for adir in listing[:]: - if local and not os.access( target+"/"+adir+"/flist", os.F_OK ): - listing.remove( adir ) - if not local and not gnomevfs.exists( target+"/"+adir+"/flist" ): - listing.remove( adir ) #TODO - check more stuff - -prev = [] -base = False -maxincrement = int(maxincrement) - -if listing == []: - increment = 0 # No backups found -> make a full backup -else: - m = r.search( listing[0] ) - if m.group( 7 ) == "ful": # Last backup was full backup - if (datetime.date.today() - datetime.date(int(m.group(1)),int(m.group(2)),int(m.group(3)) ) ).days <= maxincrement : - # Less then maxincrement days passed since that -> make an increment - increment = time.mktime((int(m.group(1)),int(m.group(2)),int(m.group(3)),int(m.group(4)),int(m.group(5)),int(m.group(6)),0,0,-1)) - base = listing[0] - prev = [ a+","+b for a,b in zip(str( gnomevfs.read_entire_file( target+"/"+base+"/flist" ) ).split( "\000" ), str( gnomevfs.read_entire_file( target+"/"+base+"/fprops" )).split( "\000" )) ] - else: - increment = 0 # Too old -> make full backup - else: - r2 = re.compile(r"ful$") # Last backup was an increment - lets search for the last full one - for i in listing: - prev.extend( [ a+","+b for a,b in zip(str( gnomevfs.read_entire_file( target+"/"+i+"/flist" ) ).split( "\000" ), str( gnomevfs.read_entire_file( target+"/"+i+"/fprops" )).split( "\000" )) ] ) - if r2.search( i ): - m = r.search( i ) - if (datetime.date.today() - datetime.date(int(m.group(1)),int(m.group(2)),int(m.group(3)) ) ).days <= maxincrement : - # Last full backup is fresh -> make an increment - m = r.search( listing[0] ) - increment = time.mktime((int(m.group(1)),int(m.group(2)),int(m.group(3)),int(m.group(4)),int(m.group(5)),int(m.group(6)),0,0,-1)) - base = listing[0] - else: - increment = 0 # Last full backup is old -> make a full backup - prev = [] - break - else: - increment = 0 # No full backup found 8) -> lets make a full backup to be safe - prev = [] - - -# Determine and create backup target directory - -tdir = target + "/" + datetime.datetime.now().isoformat("_").replace( ":", "." ) + "." + hostname + "." -if increment != 0: - tdir = tdir + "inc/" -else: - tdir = tdir + "ful/" - -if local: - os.makedirs( tdir, 0700 ) - f = open( tdir+"ver", 'w' ) -else: - gnomevfs.make_directory( tdir, 0700 ) - f = gnomevfs.create( tdir+"ver", 2 ) - -f.write( "1.3\n" ) -f.close - - -# Create '.../base' here, if incremental backup - -if base: - if local: - f = open( tdir+"base", 'w' ) - else: - f = gnomevfs.create( tdir+"base", 2 ) - f.write( base+"\n" ) - f.close - -tar = True - -# Reduce the priority, so not to interfere with other processes -os.nice(20) - -# Initiate backup tree structure - -defexcludes = ["", "/dev", "/proc", "/sys", "/tmp"] -btree = {} -for defexclude in defexcludes: - if dirconfig.has_key(defexclude+"/"): - btree[defexclude] = (dirconfig.pop(defexclude+"/"),0,[]) - else: - btree[defexclude] = (0,0,[]) - -# Populate the backup tree structure -sdirs = dirconfig.keys() -sdirs.sort() -for adir in sdirs: - btree_r_add( adir ) - btree.update( btree.fromkeys( [adir2 for adir2 in btree.keys() if is_parent(adir, adir2)] , (dirconfig[adir],0,[]) ) ) -# btree[os.path.normpath(adir)] = (dirconfig[adir],0,[]) - -# Remove target from the backup -if local: - btree_r_add( target ) - btree.update( btree.fromkeys( [adir2 for adir2 in btree.keys() if is_parent(target, adir2)] , (0,0,[]) ) ) - btree[os.path.normpath(target)] = (0,0,[]) - -# Write excludes -if local: - pickle.dump( gexclude, open(tdir+"excludes","w") ) -else: - pickle.dump( gexclude, gnomevfs.create(tdir+"excludes", 2) ) - -# Backup list of installed packages (Debian only part) -try: - command = "dpkg --get-selections" - s = os.popen( command ) - if local: - d = open( tdir+"packages", "w" ) - else: - d = gnomevfs.create( tdir+"packages", 2 ) - shutil.copyfileobj( s, d ) - s.close() -except: - pass -# End of Debian only part - -# Make the backup ... -do_backup_init() -bdirs = btree.keys() -bdirs.sort() - -for adir in bdirs: - if adir == "": - adir2 = "/" - else: - adir2 = adir - if btree[adir][0] == 1 and os.path.exists( adir2 ): - do_backup( adir2 ) - -do_backup_finish() -# ... done. - -# Write statistics -# TODO for next versions # - -sys.exit( 0 ) - diff -Nru /tmp/Jk5jXWKfRF/sbackup-0.10.3/sbackup.desktop /tmp/FlxBzI4QKq/sbackup-0.10.3/sbackup.desktop --- /tmp/Jk5jXWKfRF/sbackup-0.10.3/sbackup.desktop 2006-10-06 18:44:18.000000000 +0200 +++ /tmp/FlxBzI4QKq/sbackup-0.10.3/sbackup.desktop 2007-04-27 07:08:18.000000000 +0200 @@ -11,3 +11,4 @@ Icon=sbackup-conf.png Name[pt_BR]=Configuração do Backup Comment[pt_BR]=Configure como seus backups são feitos +GenericName[en_GB]= diff -Nru /tmp/Jk5jXWKfRF/sbackup-0.10.3/sbackupd.py /tmp/FlxBzI4QKq/sbackup-0.10.3/sbackupd.py --- /tmp/Jk5jXWKfRF/sbackup-0.10.3/sbackupd.py 1970-01-01 01:00:00.000000000 +0100 +++ /tmp/FlxBzI4QKq/sbackup-0.10.3/sbackupd.py 2007-04-27 07:08:18.000000000 +0200 @@ -0,0 +1,564 @@ +#!/usr/bin/python +# +# Simple Backup suit +# +# Running this command will execute a single backup run according to a configuration file +# +# Author: Aigars Mahinovs +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +import os +import errno +import atexit +import stat +import datetime +import time +import os.path +import cPickle as pickle +import shutil +import ConfigParser +import re +import socket +import tempfile +import upgrade_backups +import getopt +try: + import gnomevfs +except ImportError: + import gnome.vfs as gnomevfs + +# Classes we use but that are not worth putting them in their own module +class MyConfigParser(ConfigParser.ConfigParser): + def __init__(self, verbose = False): + self.verbose = verbose + if self.verbose: print "MyConfigParser.__init__" + ConfigParser.ConfigParser.__init__(self); + self.valid_options = {} + self.filename_from_argv = None + self.filename = "" + self.argv_options = {} + + def set_valid_options(self, valid_options, parse_commandline = False): + pass + self.valid_options = valid_options + if parse_commandline and self.valid_options: + self.parse_commandline() + + def read(self, filename): + if self.verbose: print "MyConfigParser.read(%s)" % filename + + self.filename = self.filename_from_argv or filename + retValue = ConfigParser.ConfigParser.read(self, self.filename) + if self.valid_options: self.validate_config_file_options() + if self.argv_options: self.validate_argv_options() + if self.valid_options: self.validate_option_values() + return retValue + + def optionxform(self, option): + return str( option ) + + def parse_commandline(self): + if self.verbose: print "MyConfigParser.parse_commandline" + argv_parameters = [ "config-file=" ] + for section, data in self.valid_options.iteritems(): + for (key, vtype) in data.iteritems(): + if (key == '*') : continue + argv_parameters.append("%s:%s="% (section, key)) + (options, reminder) = \ + getopt.getopt(sys.argv[1:], '', argv_parameters) + self.argv_options = dict(options) + if (self.argv_options.has_key("--config-file")): + self.filename_from_argv = self.argv_options["--config-file"] + del self.argv_options["--config-file"] + + + def validate_config_file_options(self): + if self.verbose: print "MyConfigParser.validate_config_file_options" + if (self.valid_options is None): return + for section in self.sections(): + try: + for key in self.options(section): + if (not self.valid_options.has_key(section)): + raise Exception ("section [%s] in %s should not exist, aborting" % (section, config)) + if (self.valid_options[section].has_key(key) or + self.valid_options[section].has_key('*')): + continue + raise Exception ("key %s in section %s in file %s is not known,\na typo possibly?" + % (key, section, config)) + except Exception, e: + print e + sys.exit(1); + + def validate_argv_options(self): + if self.verbose: print "MyConfigParser.validate_argv_options" + for parameter, value in self.argv_options.iteritems(): + parameter = parameter[2:] + (section, key) = parameter.split(":") + self.set(section,key, value) + + def validate_option_values(self): + # check if all keys defined in valid_options have values now + pass +# for section, data in self.valid_options.iteritems(): +# for key, vtype in data.iteritems(): +# if key == '*': continue +# try: +# value = self.get(section, key) +# except Exception, e: +# raise Exception ("The definition for %s:%s is missing.\nDefine in the config file or on the command line" % +# (section, key)) +# if vtype is list: +# pass +# else: +# self.set(section, key, vtype(value)) + + def all_options(self): + retVal = [] + for section in self.sections(): + for key in self.options(section): + value = self.get(section, key, raw = True) + retVal.append( (key,value)) + return retVal + + def __str__(self): + retVal = [] + for section, sec_data in self._sections.iteritems(): + retVal.append("[%s]" % section) + [retVal.append("%s = %s" % (o, repr(v))) + for o, v in sec_data.items() + if o != '__name__'] + return "\n".join(retVal) + + +# Default values, constants and the like +our_options = { + 'general' : { 'target' : str , 'lockfile' : str , 'maxincrement' : int , 'format' : int, 'purge' : str }, + 'dirconfig' : { '*' : str }, + 'exclude' : { 'regex' : list, 'maxsize' : int }, + 'places' : { 'prefix' : str } +} + +# Define default values & load config file + +config = "/etc/sbackup.conf" +target = "/var/backup/" +increment = 0 +lockfile = "/var/lock/sbackup.lock" +hostname = socket.gethostname() +maxincrement = 7 +# Backup format: 1 - allways use .tar.gz +format=1 +os.umask( 077 ) + +# directories allready added to the archive +dirs_in = ["/"] + +dirconfig = { "/etc/":1, "/home/":1, "/usr/local/": 1, "/root/":1, "/var/": 1, "/var/cache/":0, "/var/spool/":0, "/var/tmp/":0 } +gexclude = [r"\.mp3",r"\.avi",r"\.mpeg",r"\.mkv",r"\.ogg", r"\.iso"] +maxsize = 10*1024*1024 + +# Check our user id +if os.geteuid() != 0: sys.exit ("Currently backup is only runnable by root") + +# second we read the config file, so must check if the user provided one on the +# commando line. + +#try: +conf = MyConfigParser() +conf.set_valid_options( our_options, parse_commandline = True) +conf.read( config ) +#except Exception, e: +# print "Error while reading config,\n"+str(e) +# sys.exit(1) +#else: +# pass + +for option, value in conf.all_options(): + # skip options with a funny name, notably the dirs in [dirconfig] + if re.search ("\W", option): continue + # print "setting %s = %s" % (option, value) + globals()[option]=value + +if not target: + print "Option target is missing, aborting." + sys.exit(1) + +if conf.has_section( "dirconfig" ): + dirconfig = dict([ (k, int(v)) for k,v in conf.items("dirconfig") ] ) +if conf.has_option( "exclude", "regex" ): + gexclude = str(conf.get( "exclude", "regex" )).split(",") + +rexclude = [ re.compile(p) for p in gexclude if len(p)>0] + +flist = False +flistid = 0 +flist_name = "" +fprops = False + +def btree_r_add( adir ): + """Add a directory to the btree with reversed recursion - take defaults from parent""" + global btree + + os.path.normpath( adir ) + + parent2 = os.path.split( adir )[0] + parent = parent2 + if parent == "/": + parent = "" + if adir in btree: + pass + elif parent in btree: + props = btree[parent] + for child in os.listdir( parent2 ): + btree[os.path.normpath(parent+"/"+child)] = props + btree[parent] = (-1, btree[parent][1], btree[parent][2]) + else: + btree_r_add( parent ) + props = btree[parent] + for child in os.listdir( parent2 ): + btree[os.path.normpath(parent+"/"+child)] = props + btree[parent] = (-1, btree[parent][1], btree[parent][2]) + +def is_parent( parent, child ): + """ Compares directories - returns child only if it is a child of the parent """ + if str(child)[0:len(parent)] == parent: + return child + else: + return False + +def do_backup_init( ): + global flist, flistid, flist_name, fprops, fpropsid, fprops_name + if local: + (flistid, flist_name) = tempfile.mkstemp() + flist = os.fdopen( flistid, "w" ) + fprops = open(tdir+"/fprops", "w") + else: + (flistid, flist_name) = tempfile.mkstemp() + flist = os.fdopen( flistid, "w" ) + (fpropsid, fprops_name) = tempfile.mkstemp() + fprops = os.fdopen( fpropsid, "w" ) + +def do_backup_finish( ): + flist.close() + fprops.close() + tarline = "tar -czS -C / --no-recursion --ignore-failed-read --null -T "+flist_name+" " + if local: + tarline = tarline+" --force-local -f "+tdir.replace(" ", "\ ")+"/files.tgz" + tarline = tarline+" 2>/dev/null" + os.system( tarline ) + shutil.move( flist_name, tdir+"/flist" ) + else: + tarline = tarline+" 2>/dev/null" + turi = gnomevfs.URI( tdir+"/files.tgz" ) + tardst = gnomevfs.create( turi, 2 ) + tarsrc = os.popen( tarline ) + shutil.copyfileobj( tarsrc, tardst, 100*1024 ) + tarsrc.close() + tardst.close() + s1 = open( fprops_name, "r" ) + turi = gnomevfs.URI( tdir+"/fprops" ) + d1 = gnomevfs.create( turi, 2 ) + shutil.copyfileobj( s1, d1 ) + s1.close() + d1.close() + s2 = open( flist_name, "r" ) + turi = gnomevfs.URI( tdir+"/flist" ) + d2 = gnomevfs.create( turi, 2 ) + shutil.copyfileobj( s2, d2 ) + s2.close() + d2.close() + +def do_add_dir ( dirname, props ): + do_add_file( dirname, props ) + +def do_add_file( dirname, props ): + parent = os.path.split( dirname )[0] + if not parent in dirs_in and parent != dirname: + s = os.lstat( parent ) + do_add_dir( parent, str(s.st_mode)+str(s.st_uid)+str(s.st_gid)+str(s.st_size)+str(s.st_mtime)) + flist.write( dirname+"\000" ) + fprops.write( props+"\000" ) + dirs_in.append( dirname ) + +def do_backup( adir ): + """ Finds all files to be backuped in the directory and calls respective backup suroutines """ + s = os.lstat(adir) + parent = os.path.split( adir )[0] + if not os.path.isdir(adir) or os.path.islink(adir): + if s.st_size > maxsize or prev.count( adir+","+str(s.st_mode)+str(s.st_uid)+str(s.st_gid)+str(s.st_size)+str(s.st_mtime) ): + return [] + for r in rexclude: + if r.search( adir ): + return [] + do_add_file( adir, str(s.st_mode)+str(s.st_uid)+str(s.st_gid)+str(s.st_size)+str(s.st_mtime) ) + else: + if not increment: + do_add_dir( adir, str(s.st_mode)+str(s.st_uid)+str(s.st_gid)+str(s.st_size)+str(s.st_mtime) ) + for child in os.listdir( adir ): + if os.path.isdir( adir+"/"+child ) and not os.path.islink( adir+"/"+child ): + do_backup( adir+"/"+child ) + else: + try: s = os.lstat( adir+"/"+child ) + except: continue + if maxsize > 0 and s.st_size > maxsize: + continue + if prev.count( adir+"/"+child+","+str(s.st_mode)+str(s.st_uid)+str(s.st_gid)+str(s.st_size)+str(s.st_mtime) ): + continue + skip=False + for r in rexclude: + if r.search( adir+"/"+child ): + skip=True + if skip: + continue + do_add_file( adir+"/"+child, str(s.st_mode)+str(s.st_uid)+str(s.st_gid)+str(s.st_size)+str(s.st_mtime) ) + +# End of helpfull functions :) + +good = False + +# Create the lockfile so noone disturbs us +try: + open( lockfile, "r" ) +except IOError: + good = True +if not good : sys.exit ("E: Another Simple Backup daemon already running: exiting") + +try: + lock = open( lockfile, "w+" ) +except IOError: + print "E: Cann't create a lockfile: ", sys.exc_info()[1] + sys.exit(1) + +def exitfunc(): + # All done + # Remove lockfile + lock.close + os.remove (lockfile) + +atexit.register(exitfunc) + +# Checking if the target directory is local or remote +local = True + +try: + if gnomevfs.get_uri_scheme( target ) == "file": + target = gnomevfs.get_local_path_from_uri( target ) + else: + local = False +except: + pass + +# Checking if the target directory exists (or can be created) +ok = -1 +tinfo = False +try: # Get target directory info + tinfo = gnomevfs.get_file_info( target ) +except: + try: # Try to create it, in case, it doesn't exist + gnomevfs.make_directory( target, 0700 ) + tinfo = gnomevfs.get_file_info( target ) + except: + ok = False +try: + if tinfo.valid_fields == 0: + ok = False +except: + ok = False + +if ok==-1: + # Now try to write to the target dir + try: + test = str( time.time() ) + gnomevfs.make_directory( target+"/"+test, 0700 ) + gnomevfs.remove_directory( target+"/"+test ) + ok = True + except: + ok = False + +if not ok: + print "E: Target directory is not writable - please test in simple-config-gnome!" + sys.exit(1) + +# Upgrade directories to new format +# and purge old backups + +purge = 0 +if conf.has_option("general", "purge"): + purge = conf.get("general", "purge") + +upgrader = upgrade_backups.SBUpgrade() +upgrader.upgrade_target( target, purge ) + +# Determine whether to do a full or incremental backup + +r = re.compile(r"^(\d{4})-(\d{2})-(\d{2})_(\d{2})[\:\.](\d{2})[\:\.](\d{2})\.\d+\..*?\.(.+)$") + +if local: + listing = os.listdir( target ) + listing = filter( r.search, listing ) +else: + d = gnomevfs.open_directory( target ) + listing = [] + for f in d: + if f.type == 2 and f.name != "." and f.name != ".." and r.search( f.name ): + listing.append( f.name ) + +listing.sort() +listing.reverse() + +# Check if these directories are complete and remove from the list those that are not +for adir in listing[:]: + if local and not os.access( target+"/"+adir+"/flist", os.F_OK ): + listing.remove( adir ) + if not local and not gnomevfs.exists( target+"/"+adir+"/flist" ): + listing.remove( adir ) #TODO - check more stuff + +prev = [] +base = False +maxincrement = int(maxincrement) + +if listing == []: + increment = 0 # No backups found -> make a full backup +else: + m = r.search( listing[0] ) + if m.group( 7 ) == "ful": # Last backup was full backup + if (datetime.date.today() - datetime.date(int(m.group(1)),int(m.group(2)),int(m.group(3)) ) ).days <= maxincrement : + # Less then maxincrement days passed since that -> make an increment + increment = time.mktime((int(m.group(1)),int(m.group(2)),int(m.group(3)),int(m.group(4)),int(m.group(5)),int(m.group(6)),0,0,-1)) + base = listing[0] + prev = [ a+","+b for a,b in zip(str( gnomevfs.read_entire_file( target+"/"+base+"/flist" ) ).split( "\000" ), str( gnomevfs.read_entire_file( target+"/"+base+"/fprops" )).split( "\000" )) ] + else: + increment = 0 # Too old -> make full backup + else: + r2 = re.compile(r"ful$") # Last backup was an increment - lets search for the last full one + for i in listing: + prev.extend( [ a+","+b for a,b in zip(str( gnomevfs.read_entire_file( target+"/"+i+"/flist" ) ).split( "\000" ), str( gnomevfs.read_entire_file( target+"/"+i+"/fprops" )).split( "\000" )) ] ) + if r2.search( i ): + m = r.search( i ) + if (datetime.date.today() - datetime.date(int(m.group(1)),int(m.group(2)),int(m.group(3)) ) ).days <= maxincrement : + # Last full backup is fresh -> make an increment + m = r.search( listing[0] ) + increment = time.mktime((int(m.group(1)),int(m.group(2)),int(m.group(3)),int(m.group(4)),int(m.group(5)),int(m.group(6)),0,0,-1)) + base = listing[0] + else: + increment = 0 # Last full backup is old -> make a full backup + prev = [] + break + else: + increment = 0 # No full backup found 8) -> lets make a full backup to be safe + prev = [] + + +# Determine and create backup target directory + +tdir = target + "/" + datetime.datetime.now().isoformat("_").replace( ":", "." ) + "." + hostname + "." +if increment != 0: + tdir = tdir + "inc/" +else: + tdir = tdir + "ful/" + +if local: + os.makedirs( tdir, 0700 ) + f = open( tdir+"ver", 'w' ) +else: + gnomevfs.make_directory( tdir, 0700 ) + f = gnomevfs.create( tdir+"ver", 2 ) + +f.write( "1.3\n" ) +f.close + + +# Create '.../base' here, if incremental backup + +if base: + if local: + f = open( tdir+"base", 'w' ) + else: + f = gnomevfs.create( tdir+"base", 2 ) + f.write( base+"\n" ) + f.close + +tar = True + +# Reduce the priority, so not to interfere with other processes +os.nice(20) + +# Initiate backup tree structure + +defexcludes = ["", "/dev", "/proc", "/sys", "/tmp"] +btree = {} +for defexclude in defexcludes: + if dirconfig.has_key(defexclude+"/"): + btree[defexclude] = (dirconfig.pop(defexclude+"/"),0,[]) + else: + btree[defexclude] = (0,0,[]) + +# Populate the backup tree structure +sdirs = dirconfig.keys() +sdirs.sort() +for adir in sdirs: + btree_r_add( adir ) + btree.update( btree.fromkeys( [adir2 for adir2 in btree.keys() if is_parent(adir, adir2)] , (dirconfig[adir],0,[]) ) ) +# btree[os.path.normpath(adir)] = (dirconfig[adir],0,[]) + +# Remove target from the backup +if local: + btree_r_add( target ) + btree.update( btree.fromkeys( [adir2 for adir2 in btree.keys() if is_parent(target, adir2)] , (0,0,[]) ) ) + btree[os.path.normpath(target)] = (0,0,[]) + +# Write excludes +if local: + pickle.dump( gexclude, open(tdir+"excludes","w") ) +else: + pickle.dump( gexclude, gnomevfs.create(tdir+"excludes", 2) ) + +# Backup list of installed packages (Debian only part) +try: + command = "dpkg --get-selections" + s = os.popen( command ) + if local: + d = open( tdir+"packages", "w" ) + else: + d = gnomevfs.create( tdir+"packages", 2 ) + shutil.copyfileobj( s, d ) + s.close() +except: + pass +# End of Debian only part + +# Make the backup ... +do_backup_init() +bdirs = btree.keys() +bdirs.sort() + +for adir in bdirs: + if adir == "": + adir2 = "/" + else: + adir2 = adir + if btree[adir][0] == 1 and os.path.exists( adir2 ): + do_backup( adir2 ) + +do_backup_finish() +# ... done. + +# Write statistics +# TODO for next versions # + +sys.exit( 0 ) + diff -Nru /tmp/Jk5jXWKfRF/sbackup-0.10.3/simple-backup-config /tmp/FlxBzI4QKq/sbackup-0.10.3/simple-backup-config --- /tmp/Jk5jXWKfRF/sbackup-0.10.3/simple-backup-config 2006-10-06 18:44:18.000000000 +0200 +++ /tmp/FlxBzI4QKq/sbackup-0.10.3/simple-backup-config 1970-01-01 01:00:00.000000000 +0100 @@ -1,862 +0,0 @@ -#!/usr/bin/python -# -# Simple Backup suit -# -# Running this command will start a configuration dialog -# -# Author: Aigars Mahinovs -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -# Imports - -import sys -import os -import pygtk -import gtk -import ConfigParser -import gtk.glade -import gobject -import re -import time -import locale -import gettext -import gnome.ui -from gettext import gettext as _ - -try: - import gnomevfs -except ImportError: - import gnome.vfs as gnomevfs - - -class MyConfigParser(ConfigParser.ConfigParser): - def optionxform(self, option): - return str( option ) - -class SBConf: - def __init__ (self): - # Startup part - - self.conf = MyConfigParser() - - # Default values - self.configfile = "/etc/sbackup.conf" - - self.regex = r"\.mp3,\.avi,\.mpeg,\.mkv,\.ogg,\.iso" - self.dirconfig = [('/etc/', '1'), ('/var/', '1'), ('/home/', '1'), ('/var/cache/', '0'), ('/var/tmp/', '0'), ('/var/spool/', '0'), ('/usr/local/', '1'), ('/media/', '0')] - self.maxsize = str(10*1024*1024) - self.target = "/var/backup" - self.maxincrement = str(7) - good = 0 - - self.known_ftypes = { "mp3": _("MP3 Music"), "avi": _("AVI Video"), "mpeg": _("MPEG Video"), "mpg": _("MPEG Video"), "mkv": _("Matrjoshka Video"), "ogg": _("OGG Multimedia container"), "iso": _("CD Images")} - - self.conf.add_section( "general" ) - self.conf.set( "general", "target", self.target ) - self.conf.set( "general", "lockfile", "sbackup.lock") - self.conf.set( "general", "maxincrement", self.maxincrement ) - self.conf.set( "general", "format", "1" ) - self.conf.set( "general", "purge", "log" ) - self.conf.add_section( "dirconfig" ) - self.conf.add_section( "exclude" ) - self.conf.set( "exclude", "regex", self.regex ) - self.conf.set( "exclude", "maxsize", self.maxsize ) - - self.conf.add_section( "places" ) - self.conf.set( "places", "prefix", "/usr" ) - - # Read the config file - self.conf.read( self.configfile ) - - # Setup glade and signals - gtk.glade.textdomain("sbackup") - self.widgets = gtk.glade.XML(self.conf.get("places", "prefix") + "/share/sbackup/simple-backup-config.glade") - self.widgets.get_widget("backup_properties_dialog").set_icon_from_file(self.conf.get("places", "prefix") + "/share/pixmaps/sbackup-conf.png") - - # Initiate all data structures - # Paths to be included or excluded - self.include = gtk.ListStore( str ) - self.includetv = self.widgets.get_widget("includetv") - self.includetv.set_model( self.include ) - cell = gtk.CellRendererText() - cell.set_property('editable', True) - cell.connect('edited', self.cell_edited_callback, (self.include, "dirconfig", 1)) - column = gtk.TreeViewColumn('Name', cell, text=0) - self.includetv.append_column(column) - - self.ex_paths = gtk.ListStore( str ) - self.ex_pathstv = self.widgets.get_widget("ex_pathstv") - self.ex_pathstv.set_model( self.ex_paths ) - cell1 = gtk.CellRendererText() - cell1.set_property('editable', True) - cell1.connect('edited', self.cell_edited_callback, (self.ex_paths, "dirconfig", 0)) - column1 = gtk.TreeViewColumn('Name', cell1, text=0) - self.ex_pathstv.append_column(column1) - - # Excluded file types and general regular expressions - self.ex_ftype = gtk.ListStore( str, str ) - self.ex_ftypetv = self.widgets.get_widget("ex_ftypetv") - self.ex_ftypetv.set_model( self.ex_ftype ) - cell3 = gtk.CellRendererText() - column3 = gtk.TreeViewColumn('File Type', cell3, text=0) - cell2 = gtk.CellRendererText() - column2 = gtk.TreeViewColumn('Ext.', cell2, text=1) - self.ex_ftypetv.append_column(column3) - self.ex_ftypetv.append_column(column2) - - self.ex_regex = gtk.ListStore( str ) - self.ex_regextv = self.widgets.get_widget("ex_regextv") - self.ex_regextv.set_model( self.ex_regex ) - cell4 = gtk.CellRendererText() - cell4.set_property('editable', True) - cell4.connect('edited', self.cell_regex_edited_callback) - column4 = gtk.TreeViewColumn('Name', cell4, text=0) - self.ex_regextv.append_column(column4) - - # Day of month table - self.time_dom = gtk.ListStore( str ) - self.time_domtv = self.widgets.get_widget("time_domtv") - self.time_domtv.set_model( self.time_dom ) - cell6 = gtk.CellRendererText() - column6 = gtk.TreeViewColumn('Name', cell6, text=0) - self.time_domtv.append_column(column6) - - for i in range(1, 32): - self.time_dom.append( [str(i)] ) - - # Day of week table - self.time_dow = gtk.ListStore( str ) - self.time_dowtv = self.widgets.get_widget("time_dowtv") - self.time_dowtv.set_model( self.time_dow ) - cell7 = gtk.CellRendererText() - column7 = gtk.TreeViewColumn('Name', cell7, text=0) - self.time_dowtv.append_column(column7) - - for i in range(0,7): - self.time_dow.append([ time.strftime( "%A", (2000,1,1,1,1,1,i,1,1)) ]) - - good = self.parse_conf() - - # Set the time information - cronline = False - try: cronline = open("/etc/cron.d/sbackup", "r").readline() - except: pass - if not cronline: - self.widgets.get_widget("main_radio3").set_active( True ) - self.widgets.get_widget("time_min").set_sensitive( False ) - self.widgets.get_widget("time_hour").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - self.widgets.get_widget("time_freq").set_active( 0 ) - else: - parsed = False - croninfo = cronline.split() - if croninfo[0] == "@hourly": - self.widgets.get_widget("time_min").set_value( 0 ) - self.widgets.get_widget("time_hour").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - self.widgets.get_widget("time_freq").set_active( 1 ) - elif croninfo[0] == "@daily": - good = good + 1 - self.widgets.get_widget("time_min").set_value( 0 ) - self.widgets.get_widget("time_hour").set_value( 0 ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - self.widgets.get_widget("time_freq").set_active( 2 ) - elif croninfo[0] == "@weekly": - self.widgets.get_widget("time_min").set_value( 0 ) - self.widgets.get_widget("time_hour").set_value( 0 ) - self.widgets.get_widget("time_dowtv").get_selection().select_path( (0) ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - self.widgets.get_widget("time_freq").set_active( 3 ) - elif croninfo[0] == "@monthly": - self.widgets.get_widget("time_min").set_value( 0 ) - self.widgets.get_widget("time_hour").set_value( 0 ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("time_domtv").get_selection().select_path( (0) ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - self.widgets.get_widget("time_freq").set_active( 4 ) - elif croninfo[0][0]=="@": - self.widgets.get_widget("time_min").set_sensitive( False ) - self.widgets.get_widget("time_hour").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( True ) - self.widgets.get_widget("time_freq").set_active( 5 ) - self.widgets.get_widget("ccronline").set_text( croninfo[0] ) - - else: - if croninfo[0].isdigit() and croninfo[1]=="*" and croninfo[2]=="*" and croninfo[3]=="*" and croninfo[4]=="*": - self.widgets.get_widget("time_min").set_value( int(croninfo[0]) ) - self.widgets.get_widget("time_hour").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - self.widgets.get_widget("time_freq").set_active( 1 ) - elif croninfo[0].isdigit() and croninfo[1].isdigit() and croninfo[2]=="*" and croninfo[3]=="*" and croninfo[4]=="*": - self.widgets.get_widget("time_min").set_value( int(croninfo[0]) ) - self.widgets.get_widget("time_hour").set_value( int(croninfo[1]) ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - self.widgets.get_widget("time_freq").set_active( 2 ) - elif croninfo[0].isdigit() and croninfo[1].isdigit() and croninfo[2]=="*" and croninfo[3]=="*" and croninfo[4].isdigit(): - self.widgets.get_widget("time_min").set_value( int(croninfo[0]) ) - self.widgets.get_widget("time_hour").set_value( int(croninfo[1]) ) - self.widgets.get_widget("time_dowtv").get_selection().select_path( (int(croninfo[4])-1) ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - self.widgets.get_widget("time_freq").set_active( 3 ) - elif croninfo[0].isdigit() and croninfo[1].isdigit() and croninfo[2].isdigit() and croninfo[3]=="*" and croninfo[4]=="*": - self.widgets.get_widget("time_min").set_value( int(croninfo[0]) ) - self.widgets.get_widget("time_hour").set_value( int(croninfo[1]) ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("time_domtv").get_selection().select_path( (int(croninfo[2])-1) ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - self.widgets.get_widget("time_freq").set_active( 4 ) - else: - self.widgets.get_widget("time_min").set_sensitive( False ) - self.widgets.get_widget("time_hour").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( True ) - self.widgets.get_widget("time_freq").set_active( 5 ) - self.widgets.get_widget("ccronline").set_text( " ".join(croninfo[0:5]) ) - - # Parse the purge settings - if self.conf.get("general", "purge") == "0": - # Purge disabled - self.widgets.get_widget("purge").set_active( False ) - self.widgets.get_widget("purge1").set_sensitive( False ) - self.widgets.get_widget("purge2").set_sensitive( False ) - self.widgets.get_widget("purgedays").set_sensitive( False ) - elif self.conf.get("general", "purge") == "log": - # Logarithmic purge - good += 1 - self.widgets.get_widget("purge").set_active( True ) - self.widgets.get_widget("purge1").set_sensitive( True ) - self.widgets.get_widget("purge2").set_sensitive( True ) - self.widgets.get_widget("purgedays").set_sensitive( False ) - self.widgets.get_widget("purge2").set_active( True ) - else: - purgedays = int( self.conf.get("general", "purge") ) - if not ( purgedays > 1 and purgedays < 10000 ): - self.widgets.get_widget("purge").set_active( False ) - self.widgets.get_widget("purge1").set_sensitive( False ) - self.widgets.get_widget("purge2").set_sensitive( False ) - self.widgets.get_widget("purgedays").set_sensitive( False ) - else: - # Regular purge - self.widgets.get_widget("purgedays").set_text( str(purgedays) ) - self.widgets.get_widget("purge").set_active( True ) - self.widgets.get_widget("purge1").set_sensitive( True ) - self.widgets.get_widget("purge2").set_sensitive( True ) - self.widgets.get_widget("purgedays").set_sensitive( True ) - self.widgets.get_widget("purge1").set_active( True ) - - - if cronline and good == 6: - self.widgets.get_widget("main_radio1").set_active( True ) - elif cronline: - self.widgets.get_widget("main_radio2").set_active( True ) - else: - self.widgets.get_widget("main_radio3").set_active( True ) - - self.widgets.get_widget("eventbox1").set_visible_window(False) - - self.widgets.signal_autoconnect(self) - - gnome.ui.authentication_manager_init() - - - def parse_conf( self, *args ): - good = 0 - - if self.conf.items( "dirconfig" ) == self.dirconfig: - good == good + 1 - - self.include.clear() - self.ex_paths.clear() - - for i,v in self.conf.items( "dirconfig" ): - if v=="1": - self.include.append( [i] ) - else: - self.ex_paths.append( [i] ) - - if self.conf.get("exclude", "regex") == self.regex: - good = good+1 - - self.ex_ftype.clear() - self.ex_regex.clear() - - list = str(self.conf.get( "exclude", "regex" )).split(",") - for i in list: - if re.match( r"\\\.\w+", i ): - if i[2:] in self.known_ftypes: - self.ex_ftype.append( [self.known_ftypes[i[2:]], i[2:]] ) - else: - self.ex_ftype.append( [_("Custom"), i[2:]] ) - else: - self.ex_regex.append( [i] ) - - # Set maximum size limits - self.widgets.get_widget("ex_maxsize").set_value( self.conf.getint("exclude", "maxsize")/(1024*1024) ) - if self.conf.getint("exclude", "maxsize") < 0: - self.widgets.get_widget("ex_maxsize").set_sensitive( False ) - self.widgets.get_widget("ex_max").set_active( False ) - else: - self.widgets.get_widget("ex_maxsize").set_sensitive( True ) - self.widgets.get_widget("ex_max").set_active( True ) - if self.conf.get("exclude", "maxsize" ) == self.maxsize: - good = good + 1 - - # Set the maximum time between full backups - self.widgets.get_widget("time_maxinc").set_value( int(self.conf.get("general", "maxincrement"))) - if self.conf.get("general", "maxincrement" ) == self.maxincrement: - good = good + 1 - - # Parse the target value - - if self.conf.get("general", "target" ) == self.target: - good = good + 1 - ctarget = self.conf.get("general", "target") - - # Checking if the target directory is local or remote - local = True - - try: - if gnomevfs.get_uri_scheme( ctarget ) == "file": - ctarget = gnomevfs.get_local_path_from_uri( ctarget ) - else: - local = False - except: - pass - - - if ctarget == self.target: - self.widgets.get_widget("dest1").set_active( True ) - self.widgets.get_widget("hbox11").set_sensitive( False ) - self.widgets.get_widget("hbox26").set_sensitive( False ) - elif local: - self.widgets.get_widget("dest2").set_active( True ) - self.widgets.get_widget("hbox11").set_sensitive( True ) - self.widgets.get_widget("dest_localpath").set_current_folder( ctarget ) - self.widgets.get_widget("hbox26").set_sensitive( False ) - else: - self.widgets.get_widget("dest3").set_active( True ) - self.widgets.get_widget("hbox11").set_sensitive( False ) - self.widgets.get_widget("hbox26").set_sensitive( True ) - self.widgets.get_widget("dest_remote").set_text( ctarget ) - - return good - -# Callbacks - - def on_about_clicked(self, *args): - about = gtk.AboutDialog() - about.set_name(_("Simple Backup Suite")) - about.set_version("0.10") - about.set_comments(_("This is a user friendly backup solution for common desktop needs. The project was was sponsored by Google during Google Summer of Code 2005 and mentored by Ubuntu.")) - about.set_transient_for(self.widgets.get_widget("backup_properties_dialog")) - about.set_copyright("Aigars Mahinovs ") - about.set_translator_credits(_("translator-credits")) - about.set_authors(["Aigars Mahinovs ", - "Jonh Wendell "]) - about.set_website("http://sourceforge.net/projects/sbackup/") - about.set_logo(gtk.gdk.pixbuf_new_from_file(self.conf.get("places", "prefix") + "/share/pixmaps/sbackup-conf.png")) - about.run() - about.destroy() - - - def on_backupnow_clicked(self, *args): - pid = os.spawnl( os.P_NOWAIT, self.conf.get("places", "prefix") + "/sbin/sbackupd" ) - dialog = gtk.MessageDialog(flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=gtk.BUTTONS_CLOSE, message_format=_("A backup run is initiated in the background. The process id is: ")+str(pid)+".") - dialog.run() - dialog.destroy() - - def on_save_clicked(self, *args): - self.conf.write( open( "/etc/sbackup.conf", "w" ) ) - cron = open( "/etc/cron.d/sbackup", "w" ) - tail = "\troot\tif [ -x " + self.conf.get("places", "prefix") + "/sbin/sbackupd ]; then " + self.conf.get("places", "prefix") + "/sbin/sbackupd; fi;" - cronline = "" - - cfreq = self.widgets.get_widget("time_freq").get_active() - cmin = int(self.widgets.get_widget("time_min").get_value()) - if self.widgets.get_widget("time_hour").get_property("sensitive"): - chour = int(self.widgets.get_widget("time_hour").get_value()) - else: chour = False - if self.widgets.get_widget("scrolledwindow7").get_property("sensitive"): - cdow = self.widgets.get_widget("time_dowtv").get_selection().get_selected_rows()[1] - try: cdow = cdow[0][0]+1 - except: cdow = 1 - else: cdow = False - if self.widgets.get_widget("scrolledwindow6").get_property("sensitive"): - cdom = self.widgets.get_widget("time_domtv").get_selection().get_selected_rows()[1] - try: cdom = cdom[0][0]+1 - except: cdom = 1 - else: cdom = False - - if cfreq == 0: - cronline == False - elif cfreq == 1 and cmin == 0: - cronline = "@hourly" - elif cfreq == 2 and cmin == 0 and chour == 0: - cronline = "@daily" - elif cfreq == 3 and cmin == 0 and chour == 0 and cdow == 1: - cronline = "@weekly" - elif cfreq == 4 and cmin == 0 and chour == 0 and cdom == 1: - cronline = "@montly" - elif cfreq == 5: - cronline = self.widgets.get_widget("ccronline").get_text() - else: - # minutes - cronline = str(cmin) + " " - # hours - if not chour == False: cronline = cronline + str(chour) + " " - else: cronline = cronline + "* " - # days of mounth - if not cdom == False: cronline = cronline + str(cdom) + " " - else: cronline = cronline + "* " - # mounth of year - cronline = cronline + "* " - # day of week - if not cdow == False: cronline = cronline + str(cdow) - else: cronline = cronline + "*" - - if cronline: cronline = cronline + tail + "\n" - if cronline and not self.widgets.get_widget("main_radio3").get_active(): cron.write( cronline ) - cron.close() - if not cronline: - try: os.remove("/etc/cron.d/sbackup") - except: pass - dialog = gtk.MessageDialog(flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=gtk.BUTTONS_CLOSE, message_format=_("Configuration save successful")) - dialog.run() - dialog.destroy() - - def on_main_radio_group_changed(self, *args): - if self.widgets.get_widget("main_radio1").get_active(): - # set all values to defaults - - self.conf = ConfigParser.ConfigParser() - self.conf.add_section( "general" ) - self.conf.set( "general", "target", self.target ) - self.conf.set( "general", "lockfile", "sbackup.lock") - self.conf.set( "general", "maxincrement", self.maxincrement ) - self.conf.set( "general", "format", "1" ) - self.conf.add_section( "dirconfig" ) - for i in self.dirconfig: - self.conf.set( "dirconfig", i[0], i[1] ) - self.conf.add_section( "exclude" ) - self.conf.set( "exclude", "regex", self.regex ) - self.conf.set( "exclude", "maxsize", self.maxsize ) - - self.parse_conf() - - self.widgets.get_widget("time_freq").set_active( 2 ) - self.widgets.get_widget("time_min").set_sensitive( True ) - self.widgets.get_widget("time_hour").set_sensitive( True ) - self.widgets.get_widget("time_min").set_value( 0 ) - self.widgets.get_widget("time_hour").set_value( 0 ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - - self.widgets.get_widget("purge").set_active( True ) - self.widgets.get_widget("purge1").set_active( 1 ) - self.widgets.get_widget("purgedays").set_sensitive( False ) - - # disable all tabs - self.widgets.get_widget("vbox11").set_sensitive( False ) - self.widgets.get_widget("notebook2").set_sensitive( False ) - self.widgets.get_widget("vbox12").set_sensitive( False ) - self.widgets.get_widget("vbox14").set_sensitive( False ) - self.widgets.get_widget("vbox21").set_sensitive( False ) - self.widgets.get_widget("vbox22").set_sensitive( False ) - - elif self.widgets.get_widget("main_radio2").get_active(): - # enable all tabs - self.widgets.get_widget("vbox11").set_sensitive( True ) - self.widgets.get_widget("notebook2").set_sensitive( True ) - self.widgets.get_widget("vbox12").set_sensitive( True ) - self.widgets.get_widget("vbox14").set_sensitive( True ) - self.widgets.get_widget("vbox21").set_sensitive( True ) - self.widgets.get_widget("vbox22").set_sensitive( False ) - else: - # enable all tabs - self.widgets.get_widget("vbox11").set_sensitive( True ) - self.widgets.get_widget("notebook2").set_sensitive( True ) - self.widgets.get_widget("vbox12").set_sensitive( True ) - self.widgets.get_widget("vbox14").set_sensitive( True ) - # disable Time tab - self.widgets.get_widget("time_freq").set_active( 0 ) - self.widgets.get_widget("time_min").set_sensitive( False ) - self.widgets.get_widget("time_hour").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - # disable regular backups - #try: os.remove("/etc/cron.d/sbackup") - #except: pass - - def on_inc_addfile_clicked(self, *args): - dialog = gtk.FileChooserDialog(_("Include file ..."), None, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) - dialog.set_default_response(gtk.RESPONSE_OK) - filter = gtk.FileFilter() - filter.set_name(_("All files")) - filter.add_pattern("*") - dialog.add_filter(filter) - - response = dialog.run() - if response == gtk.RESPONSE_OK: - self.include.append( [dialog.get_filename()] ) - self.conf.set( "dirconfig", dialog.get_filename(), "1" ) - elif response == gtk.RESPONSE_CANCEL: - pass - dialog.destroy() - - def on_inc_adddir_clicked(self, *args): - dialog = gtk.FileChooserDialog(_("Include folder ..."), None, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) - dialog.set_default_response(gtk.RESPONSE_OK) - - response = dialog.run() - if response == gtk.RESPONSE_OK: - self.include.append( [dialog.get_filename()+"/"] ) - self.conf.set( "dirconfig", dialog.get_filename()+"/", "1" ) - elif response == gtk.RESPONSE_CANCEL: - pass - dialog.destroy() - - def on_inc_del_clicked(self, *args): - (store, iter) = self.includetv.get_selection().get_selected() - if store and iter: - value = store.get_value( iter, 0 ) - self.conf.remove_option( "dirconfig", value ) - store.remove( iter ) - - def on_ex_addfile_clicked(self, *args): - dialog = gtk.FileChooserDialog(_("Exclude file ..."), None, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) - dialog.set_default_response(gtk.RESPONSE_OK) - filter = gtk.FileFilter() - filter.set_name(_("All files")) - filter.add_pattern("*") - dialog.add_filter(filter) - - response = dialog.run() - if response == gtk.RESPONSE_OK: - self.ex_paths.append( [dialog.get_filename()] ) - self.conf.set( "dirconfig", dialog.get_filename(), "0" ) - elif response == gtk.RESPONSE_CANCEL: - pass - dialog.destroy() - - def on_ex_adddir_clicked(self, *args): - dialog = gtk.FileChooserDialog(_("Exclude folder ..."), None, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) - dialog.set_default_response(gtk.RESPONSE_OK) - - response = dialog.run() - if response == gtk.RESPONSE_OK: - self.ex_paths.append( [dialog.get_filename()+"/"] ) - self.conf.set( "dirconfig", dialog.get_filename()+"/", "0" ) - elif response == gtk.RESPONSE_CANCEL: - pass - dialog.destroy() - - def on_ex_delpath_clicked(self, *args): - (store, iter) = self.ex_pathstv.get_selection().get_selected() - if store and iter: - value = store.get_value( iter, 0 ) - self.conf.remove_option( "dirconfig", value ) - store.remove( iter ) - - def on_addftype_clicked(self, *args): - dialog = self.widgets.get_widget("ftypedialog") - response = dialog.run() - dialog.hide() - if response == gtk.RESPONSE_OK: - if self.widgets.get_widget("ftype_st").get_active(): - ftype = self.widgets.get_widget("ftype_box").get_model()[self.widgets.get_widget("ftype_box").get_active()][0] - else: - ftype = self.widgets.get_widget("ftype_custom_ex").get_text() - - if ftype in self.known_ftypes: - self.ex_ftype.append( [self.known_ftypes[ftype], ftype] ) - else: - self.ex_ftype.append( [_("Custom"), ftype] ) - - r = self.conf.get( "exclude", "regex" ) - r = r + r",\." + ftype.strip() - self.conf.set( "exclude", "regex", r ) - elif response == gtk.RESPONSE_CANCEL: - pass - - def on_delftype_clicked(self, *args): - (store, iter) = self.ex_ftypetv.get_selection().get_selected() - if store and iter: - value = store.get_value( iter, 1 ) - r = self.conf.get( "exclude", "regex" ) - r = ","+r+"," - r = re.sub( r",\\."+re.escape(value)+"," , ",", r ) - r = r.lstrip( "," ).rstrip( "," ) - self.conf.set( "exclude", "regex", r ) - store.remove( iter ) - - def on_ex_addregex_clicked(self, *args): - dialog = self.widgets.get_widget("regexdialog") - response = dialog.run() - dialog.hide() - if response == gtk.RESPONSE_OK: - regex = self.widgets.get_widget("regex_box").get_text() - - self.ex_regex.append( [regex] ) - r = self.conf.get( "exclude", "regex" ) - r = r + r"," + regex.strip() - self.conf.set( "exclude", "regex", r ) - elif response == gtk.RESPONSE_CANCEL: - pass - - def on_ex_delregex_clicked(self, *args): - (store, iter) = self.ex_regextv.get_selection().get_selected() - if store and iter: - value = store.get_value( iter, 0 ) - r = self.conf.get( "exclude", "regex" ) - r = re.sub( r","+re.escape(value) , "", r ) - self.conf.set( "exclude", "regex", r ) - store.remove( iter ) - - def cell_regex_edited_callback(self, cell, path, new_text): - # Check if new path is empty - if (new_text == None) or (new_text == ""): - dialog = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=gtk.BUTTONS_CLOSE, message_format=_("Empty expression. Please enter a valid regular expression.")) - dialog.run() - dialog.destroy() - return - - # Remove old expression and add the new one - value = self.ex_regex[path][0] - r = self.conf.get( "exclude", "regex" ) - r = re.sub( r","+re.escape(value) , "", r ) - r = r + r"," + new_text.strip() - self.conf.set( "exclude", "regex", r ) - self.ex_regex[path][0] = new_text - - - def cell_edited_callback(self, cell, path, new_text, data): - # Check if new path is empty - if (new_text == None) or (new_text == ""): - dialog = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=gtk.BUTTONS_CLOSE, message_format=_("Empty filename or path. Please enter a valid filename or path.")) - dialog.run() - dialog.destroy() - return - # Check if new path exists and asks the user if path does not exists - if not os.path.exists(new_text): - dialog = gtk.MessageDialog(type=gtk.MESSAGE_QUESTION, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=gtk.BUTTONS_YES_NO, message_format=_("It seems the path you entered does not exists. Do you want to add this wrong path?")) - response = dialog.run() - dialog.destroy() - if response == gtk.RESPONSE_NO: - return - - model, section, value = data - self.conf.remove_option(section, model[path][0]) - model[path][0] = new_text - self.conf.set(section, new_text, value) - - def on_ex_max_toggled(self, *args): - if not self.widgets.get_widget("ex_max").get_active(): - self.widgets.get_widget("ex_maxsize").set_sensitive( False ) - self.conf.set( "exclude", "maxsize", "-1" ) - else: - self.widgets.get_widget("ex_maxsize").set_sensitive( True ) - self.conf.set( "exclude", "maxsize", str(int(self.widgets.get_widget("ex_maxsize").get_value())*1024*1024) ) - - def on_ex_maxsize_changed(self, *args): - self.conf.set( "exclude", "maxsize", str(int(self.widgets.get_widget("ex_maxsize").get_value())*1024*1024) ) - - def on_dest_group_changed(self, *args): - if self.widgets.get_widget("dest1").get_active(): - self.widgets.get_widget("hbox11").set_sensitive( False ) - self.widgets.get_widget("hbox26").set_sensitive( False ) - self.widgets.get_widget("dest_unusable").hide() - self.conf.set( "general", "target", self.target ) - elif self.widgets.get_widget("dest2").get_active(): - self.widgets.get_widget("hbox11").set_sensitive( True ) - self.widgets.get_widget("hbox26").set_sensitive( False ) - self.on_dest_localpath_selection_changed() - else: - self.widgets.get_widget("hbox11").set_sensitive( False ) - self.widgets.get_widget("hbox26").set_sensitive( True ) - self.on_dest_remote_changed() - - def on_dest_localpath_selection_changed(self, *args): - t = self.widgets.get_widget("dest_localpath").get_filename() - if (os.path.isdir( t ) and os.access( t, os.R_OK | os.W_OK | os.X_OK ) ): - self.conf.set( "general", "target", t ) - self.widgets.get_widget("dest_unusable").hide() - else: - self.widgets.get_widget("dest_unusable").show() - - def on_dest_remote_changed(self, *args): - self.widgets.get_widget("dest_remote_light").set_from_stock( gtk.STOCK_DIALOG_WARNING , gtk.ICON_SIZE_BUTTON) - gtk.tooltips_data_get(self.widgets.get_widget("eventbox1"))[0].set_tip(self.widgets.get_widget("eventbox1"), "Please test writability of the target directory by pressing \"Test\" button on the right.") - - def on_dest_remotetest_clicked(self, *args): - t = self.widgets.get_widget("dest_remote").get_text() - ok = -1 - tinfo = False - try: # Get target directory info - tinfo = gnomevfs.get_file_info( t ) - except: - try: # Try to create it, in case, it doesn't exist - gnomevfs.make_directory( t, 0700 ) - tinfo = gnomevfs.get_file_info( t ) - except: - ok = False - - try: - if tinfo.valid_fields == 0: - ok = False - except: - ok = False - - if ok==-1: - # Now try to write to the target dir - try: - test = str( time.time() ) - gnomevfs.make_directory( t+"/"+test, 0700 ) - gnomevfs.remove_directory( t+"/"+test ) - ok = True - except: - ok = False - - if ok: - self.conf.set( "general", "target", t ) - self.widgets.get_widget("dest_unusable").hide() - self.widgets.get_widget("dest_remote_light").set_from_stock( gtk.STOCK_YES , gtk.ICON_SIZE_BUTTON ) - gtk.tooltips_data_get(self.widgets.get_widget("eventbox1"))[0].set_tip(self.widgets.get_widget("eventbox1"), "Target directory is writable.") - else: - self.widgets.get_widget("dest_remote_light").set_from_stock( gtk.STOCK_DIALOG_ERROR , gtk.ICON_SIZE_BUTTON ) - gtk.tooltips_data_get(self.widgets.get_widget("eventbox1"))[0].set_tip(self.widgets.get_widget("eventbox1"), "Please change target directory and test writability of the target directory by pressing \"Test\" button on the right.") - self.widgets.get_widget("dest_unusable").show() - - - - def on_time_freq_changed(self, *args): - if self.widgets.get_widget("time_freq").get_active()==0: - self.widgets.get_widget("time_min").set_sensitive( False ) - self.widgets.get_widget("time_hour").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - self.widgets.get_widget("main_radio3").set_active(True) - elif self.widgets.get_widget("time_freq").get_active()==1: - self.widgets.get_widget("time_min").set_sensitive( True ) - self.widgets.get_widget("time_hour").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - elif self.widgets.get_widget("time_freq").get_active()==2: - self.widgets.get_widget("time_min").set_sensitive( True ) - self.widgets.get_widget("time_hour").set_sensitive( True ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - elif self.widgets.get_widget("time_freq").get_active()==3: - self.widgets.get_widget("time_min").set_sensitive( True ) - self.widgets.get_widget("time_hour").set_sensitive( True ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( True ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - elif self.widgets.get_widget("time_freq").get_active()==4: - self.widgets.get_widget("time_min").set_sensitive( True ) - self.widgets.get_widget("time_hour").set_sensitive( True ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( True ) - self.widgets.get_widget("ccronline").set_sensitive( False ) - elif self.widgets.get_widget("time_freq").get_active()==5: - self.widgets.get_widget("time_min").set_sensitive( False ) - self.widgets.get_widget("time_hour").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) - self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) - self.widgets.get_widget("ccronline").set_sensitive( True ) - # TODO : put current cronline into the ccronline widget here - - def on_time_maxinc_value_changed(self, *args): - self.conf.set( "general", "maxincrement", str(int(self.widgets.get_widget("time_maxinc").get_value())) ) - - def on_ftype_group_changed(self, *args): - if self.widgets.get_widget("ftype_st").get_active(): - self.widgets.get_widget("ftype_box").set_sensitive( True ) - self.widgets.get_widget("ftype_custom_ex").set_sensitive( False ) - else: - self.widgets.get_widget("ftype_box").set_sensitive( False ) - self.widgets.get_widget("ftype_custom_ex").set_sensitive( True ) - - def on_purge_toggled( self, *args): - if not self.widgets.get_widget("purge").get_active(): - self.widgets.get_widget("purge1").set_sensitive( False ) - self.widgets.get_widget("purge2").set_sensitive( False ) - self.widgets.get_widget("purgedays").set_sensitive( False ) - self.conf.set( "general", "purge", "0" ) - else: - self.widgets.get_widget("purge1").set_sensitive( True ) - self.widgets.get_widget("purge2").set_sensitive( True ) - if self.widgets.get_widget("purge1").get_active(): - self.widgets.get_widget("purgedays").set_sensitive( True ) - try: i = int(self.widgets.get_widget("purgedays").get_text()) - except: i = -1 - if not ( i>0 and i<10000 ): i=30 - self.widgets.get_widget("purgedays").set_text(str(i)) - self.conf.set( "general", "purge", str(i) ) - else: - self.widgets.get_widget("purgedays").set_sensitive( False ) - self.conf.set( "general", "purge", "log" ) - - def on_purge_group_changed( self, *args ): - if self.widgets.get_widget("purge1").get_active(): - self.widgets.get_widget("purgedays").set_sensitive( True ) - try: i = int(self.widgets.get_widget("purgedays").get_text()) - except: i = -1 - if not ( i>0 and i<10000 ): i=30 - self.widgets.get_widget("purgedays").set_text(str(i)) - self.conf.set( "general", "purge", str(i) ) - else: - self.widgets.get_widget("purgedays").set_sensitive( False ) - self.conf.set( "general", "purge", "log" ) - - def on_purgedays_changed( self, *args ): - try: i = int(self.widgets.get_widget("purgedays").get_text()) - except: i = -1 - if not ( i>0 and i<10000 ): i=30 - print i - self.conf.set( "general", "purge", str(i) ) - - def gtk_main_quit( self, *args): - gtk.main_quit() - - -# i18n init -gettext.textdomain("sbackup") - -#Check our user id -if os.geteuid() != 0: sys.exit (_("Currently backup configuration is only runnable by root")) -if __name__ == "__main__": - i = SBConf() - gtk.main() diff -Nru /tmp/Jk5jXWKfRF/sbackup-0.10.3/simple-backup-config.glade /tmp/FlxBzI4QKq/sbackup-0.10.3/simple-backup-config.glade --- /tmp/Jk5jXWKfRF/sbackup-0.10.3/simple-backup-config.glade 2006-10-06 18:44:18.000000000 +0200 +++ /tmp/FlxBzI4QKq/sbackup-0.10.3/simple-backup-config.glade 2007-04-27 07:08:18.000000000 +0200 @@ -183,6 +183,7 @@ + 2 True True Use recommended backup settings @@ -1759,6 +1760,49 @@ + + 4 + True + True + simply + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 0 + False + False + + + + + + 2 + True + True + precisely + True + GTK_RELIEF_NORMAL + True + False + False + True + anacronRadio + + + + 0 + False + False + + + + True at: @@ -2068,7 +2112,7 @@ True True 0 - 0 0 * * * + 0 0 * * * True False @@ -2346,7 +2390,7 @@ True True 0 - 30 + 30 True False @@ -2673,7 +2717,7 @@ True - mp3 + mp3 avi mpeg mpg diff -Nru /tmp/Jk5jXWKfRF/sbackup-0.10.3/simple-backup-config.py /tmp/FlxBzI4QKq/sbackup-0.10.3/simple-backup-config.py --- /tmp/Jk5jXWKfRF/sbackup-0.10.3/simple-backup-config.py 1970-01-01 01:00:00.000000000 +0100 +++ /tmp/FlxBzI4QKq/sbackup-0.10.3/simple-backup-config.py 2007-04-27 07:08:18.000000000 +0200 @@ -0,0 +1,968 @@ +#!/usr/bin/python +# +# Simple Backup suit +# +# Running this command will start a configuration dialog +# +# Author: Aigars Mahinovs +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Imports + +import sys +import os +import pygtk +import gtk +import ConfigParser +import gtk.glade +import gobject +import re +import time +import locale +import gettext +import gnome.ui +from gettext import gettext as _ + +try: + import gnomevfs +except ImportError: + import gnome.vfs as gnomevfs + + +class MyConfigParser(ConfigParser.ConfigParser): + def optionxform(self, option): + return str( option ) + +class SBConf: + def __init__ (self): + # Startup part + + self.conf = MyConfigParser() + + # Default values + self.configfile = "/etc/sbackup.conf" + + self.regex = r"\.mp3,\.avi,\.mpeg,\.mkv,\.ogg,\.iso" + self.dirconfig = [('/etc/', '1'), ('/var/', '1'), ('/home/', '1'), ('/var/cache/', '0'), ('/var/tmp/', '0'), ('/var/spool/', '0'), ('/usr/local/', '1'), ('/media/', '0')] + self.maxsize = str(10*1024*1024) + self.target = "/var/backup" + self.maxincrement = str(7) + self.prefix = "/usr" + good = 0 + + self.known_ftypes = { "mp3": _("MP3 Music"), "avi": _("AVI Video"), "mpeg": _("MPEG Video"), "mpg": _("MPEG Video"), "mkv": _("Matrjoshka Video"), "ogg": _("OGG Multimedia container"), "iso": _("CD Images")} + + self.conf.add_section( "general" ) + self.conf.set( "general", "target", self.target ) + self.conf.set( "general", "lockfile", "sbackup.lock") + self.conf.set( "general", "maxincrement", self.maxincrement ) + self.conf.set( "general", "format", "1" ) + self.conf.set( "general", "purge", "log" ) + self.conf.add_section( "dirconfig" ) + self.conf.add_section( "exclude" ) + self.conf.set( "exclude", "regex", self.regex ) + self.conf.set( "exclude", "maxsize", self.maxsize ) + + self.conf.add_section( "places" ) + self.conf.set( "places", "prefix", self.prefix ) + + # Read the config file only if the file exists + if os.path.exists( self.configfile ) : + self.conf.read( self.configfile ) + self.servicefile = self.conf.get("places", "prefix") + "/share/sbackup/sbackup" + + # Setup glade and signals + gtk.glade.textdomain("sbackup") + self.widgets = gtk.glade.XML(self.conf.get("places", "prefix") + "/share/sbackup/simple-backup-config.glade") + self.widgets.get_widget("backup_properties_dialog").set_icon_from_file(self.conf.get("places", "prefix") + "/share/pixmaps/sbackup-conf.png") + + # Initiate all data structures + # Paths to be included or excluded + self.include = gtk.ListStore( str ) + self.includetv = self.widgets.get_widget("includetv") + self.includetv.set_model( self.include ) + cell = gtk.CellRendererText() + cell.set_property('editable', True) + cell.connect('edited', self.cell_edited_callback, (self.include, "dirconfig", 1)) + column = gtk.TreeViewColumn('Name', cell, text=0) + self.includetv.append_column(column) + + self.ex_paths = gtk.ListStore( str ) + self.ex_pathstv = self.widgets.get_widget("ex_pathstv") + self.ex_pathstv.set_model( self.ex_paths ) + cell1 = gtk.CellRendererText() + cell1.set_property('editable', True) + cell1.connect('edited', self.cell_edited_callback, (self.ex_paths, "dirconfig", 0)) + column1 = gtk.TreeViewColumn('Name', cell1, text=0) + self.ex_pathstv.append_column(column1) + + # Excluded file types and general regular expressions + self.ex_ftype = gtk.ListStore( str, str ) + self.ex_ftypetv = self.widgets.get_widget("ex_ftypetv") + self.ex_ftypetv.set_model( self.ex_ftype ) + cell3 = gtk.CellRendererText() + column3 = gtk.TreeViewColumn('File Type', cell3, text=0) + cell2 = gtk.CellRendererText() + column2 = gtk.TreeViewColumn('Ext.', cell2, text=1) + self.ex_ftypetv.append_column(column3) + self.ex_ftypetv.append_column(column2) + + self.ex_regex = gtk.ListStore( str ) + self.ex_regextv = self.widgets.get_widget("ex_regextv") + self.ex_regextv.set_model( self.ex_regex ) + cell4 = gtk.CellRendererText() + cell4.set_property('editable', True) + cell4.connect('edited', self.cell_regex_edited_callback) + column4 = gtk.TreeViewColumn('Name', cell4, text=0) + self.ex_regextv.append_column(column4) + + # Day of month table + self.time_dom = gtk.ListStore( str ) + self.time_domtv = self.widgets.get_widget("time_domtv") + self.time_domtv.set_model( self.time_dom ) + cell6 = gtk.CellRendererText() + column6 = gtk.TreeViewColumn('Name', cell6, text=0) + self.time_domtv.append_column(column6) + + for i in range(1, 32): + self.time_dom.append( [str(i)] ) + + # Day of week table + self.time_dow = gtk.ListStore( str ) + self.time_dowtv = self.widgets.get_widget("time_dowtv") + self.time_dowtv.set_model( self.time_dow ) + cell7 = gtk.CellRendererText() + column7 = gtk.TreeViewColumn('Name', cell7, text=0) + self.time_dowtv.append_column(column7) + + for i in range(0,7): + self.time_dow.append([ time.strftime( "%A", (2000,1,1,1,1,1,i,1,1)) ]) + + good = self.parse_conf() + + # Set the time information + cronline = False + cronlink = False + try: cronline = open("/etc/cron.d/sbackup", "r").readline() + except: pass + if not cronline: + self.widgets.get_widget("main_radio3").set_active( True ) + self.widgets.get_widget("anacronRadio").set_sensitive( True ) + self.widgets.get_widget("preciselyRadio").set_sensitive( True ) + self.widgets.get_widget("time_min").set_sensitive( False ) + self.widgets.get_widget("time_hour").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + # check if we use anacron + self.widgets.get_widget("anacronRadio").set_active( True ) + # hourly + if os.path.exists("/etc/cron.hourly/sbackup"): + self.widgets.get_widget("time_freq").set_active( 1 ) + cronlink = True + # daily + elif os.path.exists("/etc/cron.daily/sbackup"): + self.widgets.get_widget("time_freq").set_active( 2 ) + cronlink = True + # weekly + elif os.path.exists("/etc/cron.weekly/sbackup"): + self.widgets.get_widget("time_freq").set_active( 3 ) + cronlink = True + # monthly + elif os.path.exists("/local/etc/cron.monthly/sbackup"): + self.widgets.get_widget("time_freq").set_active( 4 ) + cronlink = True + # None has been set + else : + self.widgets.get_widget("time_freq").set_active( 0 ) + self.widgets.get_widget("anacronRadio").set_sensitive( False ) + self.widgets.get_widget("preciselyRadio").set_sensitive( False ) + else: + # /etc/cron.d/sbackup exists, we don't use anacron + self.widgets.get_widget("anacronRadio").set_active( False ) + self.widgets.get_widget("preciselyRadio").set_active( True ) + parsed = False + croninfo = cronline.split() + if croninfo[0] == "@hourly": + self.widgets.get_widget("time_min").set_value( 0 ) + self.widgets.get_widget("time_hour").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + self.widgets.get_widget("time_freq").set_active( 1 ) + elif croninfo[0] == "@daily": + good = good + 1 + self.widgets.get_widget("time_min").set_value( 0 ) + self.widgets.get_widget("time_hour").set_value( 0 ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + self.widgets.get_widget("time_freq").set_active( 2 ) + elif croninfo[0] == "@weekly": + self.widgets.get_widget("time_min").set_value( 0 ) + self.widgets.get_widget("time_hour").set_value( 0 ) + self.widgets.get_widget("time_dowtv").get_selection().select_path( (0) ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + self.widgets.get_widget("time_freq").set_active( 3 ) + elif croninfo[0] == "@monthly": + self.widgets.get_widget("time_min").set_value( 0 ) + self.widgets.get_widget("time_hour").set_value( 0 ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("time_domtv").get_selection().select_path( (0) ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + self.widgets.get_widget("time_freq").set_active( 4 ) + elif croninfo[0][0]=="@": + self.widgets.get_widget("time_min").set_sensitive( False ) + self.widgets.get_widget("time_hour").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( True ) + self.widgets.get_widget("time_freq").set_active( 5 ) + self.widgets.get_widget("ccronline").set_text( croninfo[0] ) + + else: + if croninfo[0].isdigit() and croninfo[1]=="*" and croninfo[2]=="*" and croninfo[3]=="*" and croninfo[4]=="*": + self.widgets.get_widget("time_min").set_value( int(croninfo[0]) ) + self.widgets.get_widget("time_hour").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + self.widgets.get_widget("time_freq").set_active( 1 ) + elif croninfo[0].isdigit() and croninfo[1].isdigit() and croninfo[2]=="*" and croninfo[3]=="*" and croninfo[4]=="*": + self.widgets.get_widget("time_min").set_value( int(croninfo[0]) ) + self.widgets.get_widget("time_hour").set_value( int(croninfo[1]) ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + self.widgets.get_widget("time_freq").set_active( 2 ) + elif croninfo[0].isdigit() and croninfo[1].isdigit() and croninfo[2]=="*" and croninfo[3]=="*" and croninfo[4].isdigit(): + self.widgets.get_widget("time_min").set_value( int(croninfo[0]) ) + self.widgets.get_widget("time_hour").set_value( int(croninfo[1]) ) + self.widgets.get_widget("time_dowtv").get_selection().select_path( (int(croninfo[4])-1) ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + self.widgets.get_widget("time_freq").set_active( 3 ) + elif croninfo[0].isdigit() and croninfo[1].isdigit() and croninfo[2].isdigit() and croninfo[3]=="*" and croninfo[4]=="*": + self.widgets.get_widget("time_min").set_value( int(croninfo[0]) ) + self.widgets.get_widget("time_hour").set_value( int(croninfo[1]) ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("time_domtv").get_selection().select_path( (int(croninfo[2])-1) ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + self.widgets.get_widget("time_freq").set_active( 4 ) + else: + self.widgets.get_widget("time_min").set_sensitive( False ) + self.widgets.get_widget("time_hour").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( True ) + self.widgets.get_widget("time_freq").set_active( 5 ) + self.widgets.get_widget("ccronline").set_text( " ".join(croninfo[0:5]) ) + + # Parse the purge settings + if self.conf.get("general", "purge") == "0": + # Purge disabled + self.widgets.get_widget("purge").set_active( False ) + self.widgets.get_widget("purge1").set_sensitive( False ) + self.widgets.get_widget("purge2").set_sensitive( False ) + self.widgets.get_widget("purgedays").set_sensitive( False ) + elif self.conf.get("general", "purge") == "log": + # Logarithmic purge + good += 1 + self.widgets.get_widget("purge").set_active( True ) + self.widgets.get_widget("purge1").set_sensitive( True ) + self.widgets.get_widget("purge2").set_sensitive( True ) + self.widgets.get_widget("purgedays").set_sensitive( False ) + self.widgets.get_widget("purge2").set_active( True ) + else: + purgedays = int( self.conf.get("general", "purge") ) + if not ( purgedays > 1 and purgedays < 10000 ): + self.widgets.get_widget("purge").set_active( False ) + self.widgets.get_widget("purge1").set_sensitive( False ) + self.widgets.get_widget("purge2").set_sensitive( False ) + self.widgets.get_widget("purgedays").set_sensitive( False ) + else: + # Regular purge + self.widgets.get_widget("purgedays").set_text( str(purgedays) ) + self.widgets.get_widget("purge").set_active( True ) + self.widgets.get_widget("purge1").set_sensitive( True ) + self.widgets.get_widget("purge2").set_sensitive( True ) + self.widgets.get_widget("purgedays").set_sensitive( True ) + self.widgets.get_widget("purge1").set_active( True ) + + + if cronline and good == 6: + self.widgets.get_widget("main_radio1").set_active( True ) + elif cronline or cronlink : + self.widgets.get_widget("main_radio2").set_active( True ) + else: + self.widgets.get_widget("main_radio3").set_active( True ) + + self.widgets.get_widget("eventbox1").set_visible_window(False) + + self.widgets.signal_autoconnect(self) + + gnome.ui.authentication_manager_init() + + + def parse_conf( self, *args ): + good = 0 + + if self.conf.items( "dirconfig" ) == self.dirconfig: + good == good + 1 + + self.include.clear() + self.ex_paths.clear() + + for i,v in self.conf.items( "dirconfig" ): + if v=="1": + self.include.append( [i] ) + else: + self.ex_paths.append( [i] ) + + if self.conf.get("exclude", "regex") == self.regex: + good = good+1 + + self.ex_ftype.clear() + self.ex_regex.clear() + + list = str(self.conf.get( "exclude", "regex" )).split(",") + for i in list: + if re.match( r"\\\.\w+", i ): + if i[2:] in self.known_ftypes: + self.ex_ftype.append( [self.known_ftypes[i[2:]], i[2:]] ) + else: + self.ex_ftype.append( [_("Custom"), i[2:]] ) + else: + self.ex_regex.append( [i] ) + + # Set maximum size limits + self.widgets.get_widget("ex_maxsize").set_value( self.conf.getint("exclude", "maxsize")/(1024*1024) ) + if self.conf.getint("exclude", "maxsize") < 0: + self.widgets.get_widget("ex_maxsize").set_sensitive( False ) + self.widgets.get_widget("ex_max").set_active( False ) + else: + self.widgets.get_widget("ex_maxsize").set_sensitive( True ) + self.widgets.get_widget("ex_max").set_active( True ) + if self.conf.get("exclude", "maxsize" ) == self.maxsize: + good = good + 1 + + # Set the maximum time between full backups + self.widgets.get_widget("time_maxinc").set_value( int(self.conf.get("general", "maxincrement"))) + if self.conf.get("general", "maxincrement" ) == self.maxincrement: + good = good + 1 + + # Parse the target value + + if self.conf.get("general", "target" ) == self.target: + good = good + 1 + ctarget = self.conf.get("general", "target") + + # Checking if the target directory is local or remote + local = True + + try: + if gnomevfs.get_uri_scheme( ctarget ) == "file": + ctarget = gnomevfs.get_local_path_from_uri( ctarget ) + else: + local = False + except: + pass + + + if ctarget == self.target: + self.widgets.get_widget("dest1").set_active( True ) + self.widgets.get_widget("hbox11").set_sensitive( False ) + self.widgets.get_widget("hbox26").set_sensitive( False ) + elif local: + self.widgets.get_widget("dest2").set_active( True ) + self.widgets.get_widget("hbox11").set_sensitive( True ) + self.widgets.get_widget("dest_localpath").set_current_folder( ctarget ) + self.widgets.get_widget("hbox26").set_sensitive( False ) + else: + self.widgets.get_widget("dest3").set_active( True ) + self.widgets.get_widget("hbox11").set_sensitive( False ) + self.widgets.get_widget("hbox26").set_sensitive( True ) + self.widgets.get_widget("dest_remote").set_text( ctarget ) + + return good + + +# Callbacks + + def on_about_clicked(self, *args): + about = gtk.AboutDialog() + about.set_name(_("Simple Backup Suite")) + about.set_version("0.10") + about.set_comments(_("This is a user friendly backup solution for common desktop needs. The project was was sponsored by Google during Google Summer of Code 2005 and mentored by Ubuntu.")) + about.set_transient_for(self.widgets.get_widget("backup_properties_dialog")) + about.set_copyright("Aigars Mahinovs ") + about.set_translator_credits(_("translator-credits")) + about.set_authors(["Aigars Mahinovs ", + "Jonh Wendell "]) + about.set_website("http://sourceforge.net/projects/sbackup/") + about.set_logo(gtk.gdk.pixbuf_new_from_file(self.conf.get("places", "prefix") + "/share/pixmaps/sbackup-conf.png")) + about.run() + about.destroy() + + + def on_backupnow_clicked(self, *args): + pid = os.spawnl( os.P_NOWAIT, self.conf.get("places", "prefix") + "/sbin/sbackupd" ) + dialog = gtk.MessageDialog(flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=gtk.BUTTONS_CLOSE, message_format=_("A backup run is initiated in the background. The process id is: ")+str(pid)+".") + dialog.run() + dialog.destroy() + + def on_save_clicked(self, *args): + + def erase_services(): + try : os.unlink("/etc/cron.hourly/sbackup") + except: pass + try : os.unlink("/etc/cron.daily/sbackup") + except: pass + try : os.unlink("/etc/cron.weekly/sbackup") + except: pass + try : os.unlink("/etc/cron.monthly/sbackup") + except: pass + try : os.remove("/etc/cron.d/sbackup") + except: pass + + self.conf.write( open( "/etc/sbackup.conf", "w" ) ) + + cronline = "" + + cfreq = self.widgets.get_widget("time_freq").get_active() + cmin = int(self.widgets.get_widget("time_min").get_value()) + if self.widgets.get_widget("time_hour").get_property("sensitive"): + chour = int(self.widgets.get_widget("time_hour").get_value()) + else: chour = False + if self.widgets.get_widget("scrolledwindow7").get_property("sensitive"): + cdow = self.widgets.get_widget("time_dowtv").get_selection().get_selected_rows()[1] + try: cdow = cdow[0][0]+1 + except: cdow = 1 + else: cdow = False + if self.widgets.get_widget("scrolledwindow6").get_property("sensitive"): + cdom = self.widgets.get_widget("time_domtv").get_selection().get_selected_rows()[1] + try: cdom = cdom[0][0]+1 + except: cdom = 1 + else: cdom = False + + if cfreq == 0: + erase_services() + cronline == False + else: + if not self.widgets.get_widget("anacronRadio").get_active() : + if cfreq == 1 and cmin == 0: + cronline = "@hourly" + elif cfreq == 2 and cmin == 0 and chour == 0: + cronline = "@daily" + elif cfreq == 3 and cmin == 0 and chour == 0 and cdow == 1: + cronline = "@weekly" + elif cfreq == 4 and cmin == 0 and chour == 0 and cdom == 1: + cronline = "@montly" + elif cfreq == 5: + cronline = self.widgets.get_widget("ccronline").get_text() + else: + # minutes + cronline = str(cmin) + " " + # hours + if not chour == False: cronline = cronline + str(chour) + " " + else: cronline = cronline + "* " + # days of mounth + if not cdom == False: cronline = cronline + str(cdom) + " " + else: cronline = cronline + "* " + # mounth of year + cronline = cronline + "* " + # day of week + if not cdow == False: cronline = cronline + str(cdow) + else: cronline = cronline + "*" + else : + if cfreq == 1 : + erase_services() + os.symlink(self.servicefile,"/etc/cron.hourly/sbackup") + elif cfreq == 2 : + erase_services() + os.symlink(self.servicefile,"/etc/cron.daily/sbackup") + elif cfreq == 3 : + erase_services() + os.symlink(self.servicefile,"/etc/cron.weekly/sbackup") + elif cfreq == 4 : + erase_services() + os.symlink(self.servicefile,"/etc/cron.monthly/sbackup") + + if cronline: + try : + erase_services() + cron = open( "/etc/cron.d/sbackup", "w" ) + tail = "\troot\tif [ -x " + self.conf.get("places", "prefix") + "/sbin/sbackupd ]; then " + self.conf.get("places", "prefix") + "/sbin/sbackupd; fi;" + cronline = cronline + tail + "\n" + except IOError: + print ("Can \'t open file /etc/cron.d/sbackup for writing") + + if cronline and not self.widgets.get_widget("main_radio3").get_active(): + cron.write( cronline ) + cron.close() + + if not cronline: + # We are using anacron or we are not using cron feature at all + try: os.remove("/etc/cron.d/sbackup") + except: pass + dialog = gtk.MessageDialog(flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=gtk.BUTTONS_CLOSE, message_format=_("Configuration save successful")) + dialog.run() + dialog.destroy() + + def on_main_radio_group_changed(self, *args): + if self.widgets.get_widget("main_radio1").get_active(): + # set all values to defaults + + self.conf = ConfigParser.ConfigParser() + self.conf.add_section( "general" ) + self.conf.set( "general", "target", self.target ) + self.conf.set( "general", "lockfile", "sbackup.lock") + self.conf.set( "general", "maxincrement", self.maxincrement ) + self.conf.set( "general", "format", "1" ) + self.conf.add_section( "dirconfig" ) + for i in self.dirconfig: + self.conf.set( "dirconfig", i[0], i[1] ) + self.conf.add_section( "exclude" ) + self.conf.set( "exclude", "regex", self.regex ) + self.conf.set( "exclude", "maxsize", self.maxsize ) + self.conf.add_section( "places" ) + self.conf.set( "places", "prefix", self.prefix ) + + self.parse_conf() + + self.widgets.get_widget("time_freq").set_active( 2 ) + # choose between anacron or cron here (old behaviour has been kept for the moment. + self.widgets.get_widget("preciselyRadio").set_active( True ) + self.widgets.get_widget("anacronRadio").set_active( False ) + + self.widgets.get_widget("time_min").set_sensitive( True ) + self.widgets.get_widget("time_hour").set_sensitive( True ) + self.widgets.get_widget("time_min").set_value( 0 ) + self.widgets.get_widget("time_hour").set_value( 0 ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + + self.widgets.get_widget("purge").set_active( True ) + self.widgets.get_widget("purge1").set_active( 1 ) + self.widgets.get_widget("purgedays").set_sensitive( False ) + + # disable all tabs + self.widgets.get_widget("vbox11").set_sensitive( False ) + self.widgets.get_widget("notebook2").set_sensitive( False ) + self.widgets.get_widget("vbox14").set_sensitive( False ) + self.widgets.get_widget("vbox21").set_sensitive( False ) + + elif self.widgets.get_widget("main_radio2").get_active(): + # enable all tabs + self.widgets.get_widget("vbox11").set_sensitive( True ) + self.widgets.get_widget("notebook2").set_sensitive( True ) + self.widgets.get_widget("vbox14").set_sensitive( True ) + self.widgets.get_widget("vbox21").set_sensitive( True ) + else: + # enable all tabs + self.widgets.get_widget("vbox11").set_sensitive( True ) + self.widgets.get_widget("notebook2").set_sensitive( True ) + self.widgets.get_widget("vbox14").set_sensitive( True ) + # disable Time tab + self.widgets.get_widget("time_freq").set_active( 0 ) + self.widgets.get_widget("time_min").set_sensitive( False ) + self.widgets.get_widget("time_hour").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + # disable regular backups + #try: os.remove("/etc/cron.d/sbackup") + #except: pass + + def on_inc_addfile_clicked(self, *args): + dialog = gtk.FileChooserDialog(_("Include file ..."), None, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) + dialog.set_default_response(gtk.RESPONSE_OK) + filter = gtk.FileFilter() + filter.set_name(_("All files")) + filter.add_pattern("*") + dialog.add_filter(filter) + + response = dialog.run() + if response == gtk.RESPONSE_OK: + self.include.append( [dialog.get_filename()] ) + self.conf.set( "dirconfig", dialog.get_filename(), "1" ) + elif response == gtk.RESPONSE_CANCEL: + pass + dialog.destroy() + + def on_inc_adddir_clicked(self, *args): + dialog = gtk.FileChooserDialog(_("Include folder ..."), None, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) + dialog.set_default_response(gtk.RESPONSE_OK) + + response = dialog.run() + if response == gtk.RESPONSE_OK: + self.include.append( [dialog.get_filename()+"/"] ) + self.conf.set( "dirconfig", dialog.get_filename()+"/", "1" ) + elif response == gtk.RESPONSE_CANCEL: + pass + dialog.destroy() + + def on_inc_del_clicked(self, *args): + (store, iter) = self.includetv.get_selection().get_selected() + if store and iter: + value = store.get_value( iter, 0 ) + self.conf.remove_option( "dirconfig", value ) + store.remove( iter ) + + def on_ex_addfile_clicked(self, *args): + dialog = gtk.FileChooserDialog(_("Exclude file ..."), None, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) + dialog.set_default_response(gtk.RESPONSE_OK) + filter = gtk.FileFilter() + filter.set_name(_("All files")) + filter.add_pattern("*") + dialog.add_filter(filter) + + response = dialog.run() + if response == gtk.RESPONSE_OK: + self.ex_paths.append( [dialog.get_filename()] ) + self.conf.set( "dirconfig", dialog.get_filename(), "0" ) + elif response == gtk.RESPONSE_CANCEL: + pass + dialog.destroy() + + def on_ex_adddir_clicked(self, *args): + dialog = gtk.FileChooserDialog(_("Exclude folder ..."), None, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) + dialog.set_default_response(gtk.RESPONSE_OK) + + response = dialog.run() + if response == gtk.RESPONSE_OK: + self.ex_paths.append( [dialog.get_filename()+"/"] ) + self.conf.set( "dirconfig", dialog.get_filename()+"/", "0" ) + elif response == gtk.RESPONSE_CANCEL: + pass + dialog.destroy() + + def on_ex_delpath_clicked(self, *args): + (store, iter) = self.ex_pathstv.get_selection().get_selected() + if store and iter: + value = store.get_value( iter, 0 ) + self.conf.remove_option( "dirconfig", value ) + store.remove( iter ) + + def on_addftype_clicked(self, *args): + dialog = self.widgets.get_widget("ftypedialog") + response = dialog.run() + dialog.hide() + if response == gtk.RESPONSE_OK: + if self.widgets.get_widget("ftype_st").get_active(): + ftype = self.widgets.get_widget("ftype_box").get_model()[self.widgets.get_widget("ftype_box").get_active()][0] + else: + ftype = self.widgets.get_widget("ftype_custom_ex").get_text() + + if ftype in self.known_ftypes: + self.ex_ftype.append( [self.known_ftypes[ftype], ftype] ) + else: + self.ex_ftype.append( [_("Custom"), ftype] ) + + r = self.conf.get( "exclude", "regex" ) + r = r + r",\." + ftype.strip() + self.conf.set( "exclude", "regex", r ) + elif response == gtk.RESPONSE_CANCEL: + pass + + def on_delftype_clicked(self, *args): + (store, iter) = self.ex_ftypetv.get_selection().get_selected() + if store and iter: + value = store.get_value( iter, 1 ) + r = self.conf.get( "exclude", "regex" ) + r = ","+r+"," + r = re.sub( r",\\."+re.escape(value)+"," , ",", r ) + r = r.lstrip( "," ).rstrip( "," ) + self.conf.set( "exclude", "regex", r ) + store.remove( iter ) + + def on_ex_addregex_clicked(self, *args): + dialog = self.widgets.get_widget("regexdialog") + response = dialog.run() + dialog.hide() + if response == gtk.RESPONSE_OK: + regex = self.widgets.get_widget("regex_box").get_text() + + self.ex_regex.append( [regex] ) + r = self.conf.get( "exclude", "regex" ) + r = r + r"," + regex.strip() + self.conf.set( "exclude", "regex", r ) + elif response == gtk.RESPONSE_CANCEL: + pass + + def on_ex_delregex_clicked(self, *args): + (store, iter) = self.ex_regextv.get_selection().get_selected() + if store and iter: + value = store.get_value( iter, 0 ) + r = self.conf.get( "exclude", "regex" ) + r = re.sub( r","+re.escape(value) , "", r ) + self.conf.set( "exclude", "regex", r ) + store.remove( iter ) + + def cell_regex_edited_callback(self, cell, path, new_text): + # Check if new path is empty + if (new_text == None) or (new_text == ""): + dialog = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=gtk.BUTTONS_CLOSE, message_format=_("Empty expression. Please enter a valid regular expression.")) + dialog.run() + dialog.destroy() + return + + # Remove old expression and add the new one + value = self.ex_regex[path][0] + r = self.conf.get( "exclude", "regex" ) + r = re.sub( r","+re.escape(value) , "", r ) + r = r + r"," + new_text.strip() + self.conf.set( "exclude", "regex", r ) + self.ex_regex[path][0] = new_text + + + def cell_edited_callback(self, cell, path, new_text, data): + # Check if new path is empty + if (new_text == None) or (new_text == ""): + dialog = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=gtk.BUTTONS_CLOSE, message_format=_("Empty filename or path. Please enter a valid filename or path.")) + dialog.run() + dialog.destroy() + return + # Check if new path exists and asks the user if path does not exists + if not os.path.exists(new_text): + dialog = gtk.MessageDialog(type=gtk.MESSAGE_QUESTION, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons=gtk.BUTTONS_YES_NO, message_format=_("It seems the path you entered does not exists. Do you want to add this wrong path?")) + response = dialog.run() + dialog.destroy() + if response == gtk.RESPONSE_NO: + return + + model, section, value = data + self.conf.remove_option(section, model[path][0]) + model[path][0] = new_text + self.conf.set(section, new_text, value) + + def on_ex_max_toggled(self, *args): + if not self.widgets.get_widget("ex_max").get_active(): + self.widgets.get_widget("ex_maxsize").set_sensitive( False ) + self.conf.set( "exclude", "maxsize", "-1" ) + else: + self.widgets.get_widget("ex_maxsize").set_sensitive( True ) + self.conf.set( "exclude", "maxsize", str(int(self.widgets.get_widget("ex_maxsize").get_value())*1024*1024) ) + + def on_ex_maxsize_changed(self, *args): + self.conf.set( "exclude", "maxsize", str(int(self.widgets.get_widget("ex_maxsize").get_value())*1024*1024) ) + + def on_dest_group_changed(self, *args): + if self.widgets.get_widget("dest1").get_active(): + self.widgets.get_widget("hbox11").set_sensitive( False ) + self.widgets.get_widget("hbox26").set_sensitive( False ) + self.widgets.get_widget("dest_unusable").hide() + self.conf.set( "general", "target", self.target ) + elif self.widgets.get_widget("dest2").get_active(): + self.widgets.get_widget("hbox11").set_sensitive( True ) + self.widgets.get_widget("hbox26").set_sensitive( False ) + self.on_dest_localpath_selection_changed() + else: + self.widgets.get_widget("hbox11").set_sensitive( False ) + self.widgets.get_widget("hbox26").set_sensitive( True ) + self.on_dest_remote_changed() + + def on_dest_localpath_selection_changed(self, *args): + t = self.widgets.get_widget("dest_localpath").get_filename() + if (os.path.isdir( t ) and os.access( t, os.R_OK | os.W_OK | os.X_OK ) ): + self.conf.set( "general", "target", t ) + self.widgets.get_widget("dest_unusable").hide() + else: + self.widgets.get_widget("dest_unusable").show() + + + def on_dest_remote_changed(self, *args): + self.widgets.get_widget("dest_remote_light").set_from_stock( gtk.STOCK_DIALOG_WARNING , gtk.ICON_SIZE_BUTTON) + gtk.tooltips_data_get(self.widgets.get_widget("eventbox1"))[0].set_tip(self.widgets.get_widget("eventbox1"), "Please test writability of the target directory by pressing \"Test\" button on the right.") + + def on_dest_remotetest_clicked(self, *args): + t = self.widgets.get_widget("dest_remote").get_text() + ok = -1 + tinfo = False + try: # Get target directory info + tinfo = gnomevfs.get_file_info( t ) + except: + try: # Try to create it, in case, it doesn't exist + gnomevfs.make_directory( t, 0700 ) + tinfo = gnomevfs.get_file_info( t ) + except: + ok = False + + try: + if tinfo.valid_fields == 0: + ok = False + except: + ok = False + + if ok==-1: + # Now try to write to the target dir + try: + test = str( time.time() ) + gnomevfs.make_directory( t+"/"+test, 0700 ) + gnomevfs.remove_directory( t+"/"+test ) + ok = True + except: + ok = False + + if ok: + self.conf.set( "general", "target", t ) + self.widgets.get_widget("dest_unusable").hide() + self.widgets.get_widget("dest_remote_light").set_from_stock( gtk.STOCK_YES , gtk.ICON_SIZE_BUTTON ) + gtk.tooltips_data_get(self.widgets.get_widget("eventbox1"))[0].set_tip(self.widgets.get_widget("eventbox1"), "Target directory is writable.") + else: + self.widgets.get_widget("dest_remote_light").set_from_stock( gtk.STOCK_DIALOG_ERROR , gtk.ICON_SIZE_BUTTON ) + gtk.tooltips_data_get(self.widgets.get_widget("eventbox1"))[0].set_tip(self.widgets.get_widget("eventbox1"), "Please change target directory and test writability of the target directory by pressing \"Test\" button on the right.") + self.widgets.get_widget("dest_unusable").show() + + def on_anacronRadio_toggled(self, *args): + if self.widgets.get_widget("anacronRadio").get_active() : + self.widgets.get_widget("time_min").set_sensitive( False ) + self.widgets.get_widget("time_hour").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + self.widgets.get_widget("anacronRadio").set_sensitive( True ) + self.widgets.get_widget("preciselyRadio").set_sensitive( True ) + elif self.widgets.get_widget("preciselyRadio").get_active() : + self.on_time_freq_changed(self) + + def on_time_freq_changed(self, *args): + if self.widgets.get_widget("time_freq").get_active()==0: + self.widgets.get_widget("time_min").set_sensitive( False ) + self.widgets.get_widget("time_hour").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + self.widgets.get_widget("anacronRadio").set_sensitive( False ) + self.widgets.get_widget("preciselyRadio").set_sensitive( False ) + self.widgets.get_widget("main_radio3").set_active(True) + elif self.widgets.get_widget("time_freq").get_active()==5: + # In custom mode we can't use anacron + self.widgets.get_widget("main_radio3").set_active(False) + self.widgets.get_widget("main_radio2").set_active(True) + self.widgets.get_widget("preciselyRadio").set_active( True ) + self.widgets.get_widget("anacronRadio").set_active( False ) + self.widgets.get_widget("anacronRadio").set_sensitive( False ) + self.widgets.get_widget("preciselyRadio").set_sensitive( False ) + self.widgets.get_widget("time_min").set_sensitive( False ) + self.widgets.get_widget("time_hour").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( True ) + else : + if not self.widgets.get_widget("main_radio1").get_active() : + self.widgets.get_widget("main_radio3").set_active(False) + self.widgets.get_widget("main_radio2").set_active(True) + self.widgets.get_widget("anacronRadio").set_sensitive( True ) + self.widgets.get_widget("preciselyRadio").set_sensitive( True ) + if self.widgets.get_widget("preciselyRadio").get_active() : + if self.widgets.get_widget("time_freq").get_active()==1: + self.widgets.get_widget("time_min").set_sensitive( True ) + self.widgets.get_widget("time_hour").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + elif self.widgets.get_widget("time_freq").get_active()==2: + self.widgets.get_widget("time_min").set_sensitive( True ) + self.widgets.get_widget("time_hour").set_sensitive( True ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + elif self.widgets.get_widget("time_freq").get_active()==3: + self.widgets.get_widget("time_min").set_sensitive( True ) + self.widgets.get_widget("time_hour").set_sensitive( True ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( True ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + elif self.widgets.get_widget("time_freq").get_active()==4: + self.widgets.get_widget("time_min").set_sensitive( True ) + self.widgets.get_widget("time_hour").set_sensitive( True ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( True ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + # TODO : put current cronline into the ccronline widget here + # We are in anacron mode (everything is disable) + else : + self.widgets.get_widget("time_min").set_sensitive( False ) + self.widgets.get_widget("time_hour").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow6").set_sensitive( False ) + self.widgets.get_widget("scrolledwindow7").set_sensitive( False ) + self.widgets.get_widget("ccronline").set_sensitive( False ) + + def on_time_maxinc_value_changed(self, *args): + self.conf.set( "general", "maxincrement", str(int(self.widgets.get_widget("time_maxinc").get_value())) ) + + def on_ftype_group_changed(self, *args): + if self.widgets.get_widget("ftype_st").get_active(): + self.widgets.get_widget("ftype_box").set_sensitive( True ) + self.widgets.get_widget("ftype_custom_ex").set_sensitive( False ) + else: + self.widgets.get_widget("ftype_box").set_sensitive( False ) + self.widgets.get_widget("ftype_custom_ex").set_sensitive( True ) + + def on_purge_toggled( self, *args): + if not self.widgets.get_widget("purge").get_active(): + self.widgets.get_widget("purge1").set_sensitive( False ) + self.widgets.get_widget("purge2").set_sensitive( False ) + self.widgets.get_widget("purgedays").set_sensitive( False ) + self.conf.set( "general", "purge", "0" ) + else: + self.widgets.get_widget("purge1").set_sensitive( True ) + self.widgets.get_widget("purge2").set_sensitive( True ) + if self.widgets.get_widget("purge1").get_active(): + self.widgets.get_widget("purgedays").set_sensitive( True ) + try: i = int(self.widgets.get_widget("purgedays").get_text()) + except: i = -1 + if not ( i>0 and i<10000 ): i=30 + self.widgets.get_widget("purgedays").set_text(str(i)) + self.conf.set( "general", "purge", str(i) ) + else: + self.widgets.get_widget("purgedays").set_sensitive( False ) + self.conf.set( "general", "purge", "log" ) + + def on_purge_group_changed( self, *args ): + if self.widgets.get_widget("purge1").get_active(): + self.widgets.get_widget("purgedays").set_sensitive( True ) + try: i = int(self.widgets.get_widget("purgedays").get_text()) + except: i = -1 + if not ( i>0 and i<10000 ): i=30 + self.widgets.get_widget("purgedays").set_text(str(i)) + self.conf.set( "general", "purge", str(i) ) + else: + self.widgets.get_widget("purgedays").set_sensitive( False ) + self.conf.set( "general", "purge", "log" ) + + def on_purgedays_changed( self, *args ): + try: i = int(self.widgets.get_widget("purgedays").get_text()) + except: i = -1 + if not ( i>0 and i<10000 ): i=30 + print i + self.conf.set( "general", "purge", str(i) ) + + def gtk_main_quit( self, *args): + gtk.main_quit() + + +# i18n init +gettext.textdomain("sbackup") + +#Check our user id +if os.geteuid() != 0: sys.exit (_("Currently backup configuration is only runnable by root")) +if __name__ == "__main__": + i = SBConf() + gtk.main() diff -Nru /tmp/Jk5jXWKfRF/sbackup-0.10.3/simple-restore-gnome /tmp/FlxBzI4QKq/sbackup-0.10.3/simple-restore-gnome --- /tmp/Jk5jXWKfRF/sbackup-0.10.3/simple-restore-gnome 2006-10-06 18:44:18.000000000 +0200 +++ /tmp/FlxBzI4QKq/sbackup-0.10.3/simple-restore-gnome 1970-01-01 01:00:00.000000000 +0100 @@ -1,442 +0,0 @@ -#!/usr/bin/python -# -# Simple Backup Solution - GUI restore tool -# -# Running this command will restore a file or directory from backup. -# -# Author: Aigars Mahinovs -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -import sys -import os -import commands -import re -import ConfigParser -import cPickle -import srestore -import locale -import gettext -from gettext import gettext as _ - -# Attempt to load GTK bindings -try: - import pygtk - pygtk.require("2.0") - import gtk - import gtk.glade - import gobject -except ImportError: - print "Failed to load Python GTK/Gnome bindings. Please check your Gnome installation." - sys.exit(1) -try: - import gnomevfs -except ImportError: - import gnome.vfs as gnomevfs - - - -def error_dialog(message, parent = None): - """ - Displays an error message. - """ - - dialog = gtk.MessageDialog(parent = parent, type = gtk.MESSAGE_ERROR, buttons = gtk.BUTTONS_OK, flags = gtk.DIALOG_MODAL) - dialog.set_markup(message) - - result = dialog.run() - dialog.destroy() - - -class SRestoreGTK: - """ - Main application class. - """ - - default_target = "/var/backup" - target = default_target - versions = [] - - - def __init__(self): - """ - Initializes the application. - """ - - # Load default config - self.load_config() - - # Setup glade and signals - gtk.glade.textdomain("sbackup") - self.signals = {"gtk_main_quit": gtk.main_quit, - "on_customsrc_toggled": self.enable_custom, - "on_treeview1_row_expanded": self.on_expand_row, - "on_backup_changed": self.on_backup_changed, - "on_apply_clicked": self.on_custom_apply, - "on_move_cursor":self.on_selection_change, - "on_restore":self.restore, - "on_restore_as":self.restore_as, - "on_customFolderButton_clicked": self.on_customFolderButton_clicked - } - - self.widgets = gtk.glade.XML(self.conf.get("places", "prefix") + "/share/sbackup/simple-restore.glade") - self.widgets.signal_autoconnect(self.signals) - - # Get handle to window - self.window = self.widgets.get_widget("restore") - - self.widgets.get_widget("labelDefaultSource").set_text(self.default_target) - - # Load the backup tree from the default location - self.init_tree() - self.sel = self.flist_widget.get_selection() - self.sel.set_mode( gtk.SELECTION_SINGLE ) - self.load_tree(self.default_target) - - - # Start the main loop - gtk.main() - - def load_config(self): - """ - Load the default system configuration file and determine - the default backup location - """ - self.conf = ConfigParser.ConfigParser() - - self.conf.add_section( "places" ) - self.conf.set( "places", "prefix", "/usr" ) - - self.conf.read("/etc/sbackup.conf") - if self.conf.has_option( "general", "target" ): - self.default_target = self.conf.get( "general", "target" ) - - def init_tree(self): - """ - Initalizes the tree structure - """ - - self.flist_widget = self.widgets.get_widget("treeview1") - self.treestore = gtk.TreeStore( str ) - - self.flist_widget.set_model( self.treestore ) - - acolumn = gtk.TreeViewColumn( _("Path"), gtk.CellRendererText(), text=0 ) - self.flist_widget.append_column( acolumn ) - - blist_widget = self.widgets.get_widget( "combobox1" ) - self.blist = gtk.ListStore(str) - blist_widget.set_model( self.blist ) - cell = gtk.CellRendererText() - blist_widget.pack_start( cell, True ) - blist_widget.add_attribute( cell, "text", 0) - - - def load_tree(self, target): - """ - Loads the tree information from the target backup directory - """ - - self.treestore.clear() - - # Checking if the target directory is local or remote - local = True - try: - if gnomevfs.URI( target ).is_local: - target = gnomevfs.get_local_path_from_uri( target ) - else: - local = False - except: - pass - - self.local = local - self.target = target - - # Checking if it is a readable directory - if local: - if not (os.path.exists( target ) and os.path.isdir( target ) and os.access( target, os.R_OK | os.X_OK ) ): - self.treestore.append( None, [_("Error: backups directory does not exist!")]) - self.target = False - else: - if not (gnomevfs.exists( target ) and gnomevfs.get_file_info(target).type == 2): - self.treestore.append( None, [_("Error: backups directory does not exist!")]) - self.target = False - - # Get list of backup directories - r = re.compile(r"^(\d{4})-(\d{2})-(\d{2})_(\d{2})[\:\.](\d{2})[\:\.](\d{2})\.\d+\..*?\.(.+)$") - - listing = [] - - if local and self.target: - listing = os.listdir( target ) - listing = filter( r.search, listing ) - elif self.target: - try: - d = gnomevfs.open_directory( target ) - listing = [] - for f in d: - if f.type == 2 and f.name != "." and f.name != ".." and r.search( f.name ): - listing.append( f.name ) - except: pass - - # Check if these directories are complete and remove from the list those that are not - old_dirs = False - for adir in listing[:]: - if str(gnomevfs.read_entire_file( self.target+"/"+adir+"/ver"))[:3] != "1.3": - old_dirs = True - if local and os.access( self.target+"/"+adir+"/flist", os.F_OK ): - continue - if not local and gnomevfs.exists( self.target+"/"+adir+"/flist" ): - continue - listing.remove( adir ) - # Lets check if this is some old type directory - if local and os.access( self.target+"/"+adir+"/tree", os.F_OK ): - old_dirs = True - if not local and gnomevfs.exists( self.target+"/"+adir+"/tree" ): - old_dirs = True - if old_dirs: - # Ask for an upgrade - dialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format=_("Some of your backups are in an old backup format. Do you want to upgrade them?\nIt should take only a few minutes.")) - - response = dialog.run() - dialog.destroy() - if response == gtk.RESPONSE_YES: - # Do upgrade - import upgrade_backups - u = upgrade_backups.SBUpgrade() - u.upgrade_target( target ) - del u - # Reload tree - self.load_tree( target ) - return - - listing.sort() - listing.reverse() - - self.vtree = {} - - if listing == []: - self.treestore.append( None, [_("Error: no backups found in the target directory")]) - self.target = False - else: - for base in listing: - if str(gnomevfs.read_entire_file(target+"/"+base+"/ver"))[:3] == "1.3": - self.vtree[base] = str(gnomevfs.read_entire_file(target+"/"+base+"/flist")).split("\000") - else: - self.vtree[base] = str(gnomevfs.read_entire_file(target+"/"+base+"/flist")).split("\n") - - self.blist.clear() - - for base in listing: - self.blist.append( [base] ) - - self.good = False - self.on_selection_change() - if self.target: - self.treestore.append( None, [_("Select any of the available backups to see list of files that can be restored.")]) - #self.widgets.get_widget("entry1").set_text( target ) - - - def on_customFolderButton_clicked(self, *args): - dialog = gtk.FileChooserDialog(_("Choose a source folder"), None, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) - dialog.set_default_response(gtk.RESPONSE_OK) - dialog.set_local_only(False) - if dialog.run() == gtk.RESPONSE_OK: - self.widgets.get_widget("entry1").set_text(dialog.get_uri()) - dialog.destroy() - - def enable_custom(self, *args): - """ - Enables/Disables input box for the custom backup dir - Reloads default dir on disabling - """ - if self.widgets.get_widget("radiobutton2").get_active(): - self.widgets.get_widget("entry1").set_sensitive(True) - self.widgets.get_widget("customFolderButton").set_sensitive(True) - self.widgets.get_widget("button7").set_sensitive(True) - self.widgets.get_widget("labelDefaultSource").set_sensitive(False) - else: - self.widgets.get_widget("entry1").set_sensitive(False) - self.widgets.get_widget("customFolderButton").set_sensitive(False) - self.widgets.get_widget("button7").set_sensitive(False) - self.widgets.get_widget("labelDefaultSource").set_sensitive(True) - self.load_tree(self.default_target) - - def on_backup_changed( self, combox ): - """ - Reset the file tree view. - """ - self.treestore.clear() - self.treestore.append( None, ["dummy"]) - self.show_dir( "", None ) - - - def on_expand_row( self, tv, iter, path, user_data=None): - """ - When a row in the file tree view is expanded, we populate - it with children (unless they are there already). - """ - if self.treestore.iter_nth_child( iter, 1 ): - return - self.show_dir( self.path_to_dir(path), iter ) - - def path_to_dir( self, path ): - """ - Recievs path in the treestore (as tuple) and returns a directory - path as string. - """ - g = list(path) - p = "" - while g != []: - i = self.treestore.get_iter( tuple(g) ) - p = "/" + self.treestore.get_value( i, 0 ) + p - g = g[:-1] - return p - - def show_dir(self, path, rootiter): - """ - Worker function - adds all files/directories from the filez list - to the treestore at the rootiter. - """ - dummy = self.treestore.iter_children(rootiter) - - self.good = True - - base = self.get_active_text(self.widgets.get_widget("combobox1")) - list2 = [] - list3 = [] - - for item in self.vtree[base]: - m = re.match( re.escape(path)+"/([^/]+/?)", item ) - if m and not list2.count(m.group(1)) and not list3.count(m.group(1)[:-1]): - if m.group(1)[-1] == "/": - if list2.count(m.group(1)[:-1]): - list2.remove(m.group(1)[:-1]) - list3.append(m.group(1)[:-1]) - else: - list2.append( m.group(1) ) - for d in list3: - iter = self.treestore.append( rootiter, [d] ) - self.treestore.append( iter, [_("Loading ...")] ) - for f in list2: - self.treestore.append( rootiter, [f] ) - - self.treestore.remove( dummy ) - - - def get_active_text(self, combobox): - model = combobox.get_model() - active = combobox.get_active() - if active < 0: - return None - return model[active][0] - - def on_custom_apply(self, *args): - """ - Reload all backup info from a custom location - """ - - self.load_tree(self.widgets.get_widget("entry1").get_text()) - - def on_selection_change(self, *args): - """ - Enable/disable restore buttons as selection changes - """ - (model, iter) = self.sel.get_selected() - if iter and self.good: - self.widgets.get_widget("button2").set_sensitive(True) - self.widgets.get_widget("button3").set_sensitive(True) - else: - self.widgets.get_widget("button2").set_sensitive(False) - self.widgets.get_widget("button3").set_sensitive(False) - - - def show_help(self, *args): - """ - Displays the help window. - Called when the 'Help' button is clicked. - """ - - # TODO: Implement - error_dialog(_("Sorry, help is not implemented yet."), self.window) - - def _restore_init( self, *args): - """ - Internal function to prepare for restorin a file - """ - (store, iter) = self.widgets.get_widget("treeview1").get_selection().get_selected() - self.src = self.path_to_dir( store.get_path( iter ) ) - return iter - - def _do_restore( self, src, dst): - """ Internal function to ask for confirmation and call the real restore library func""" - dialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format=_("Do you really want to restore backuped copy of '%s' to '%s' ?") % (src, dst)) - - response = dialog.run() - dialog.destroy() - if response == gtk.RESPONSE_YES: - dialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_NONE, message_format=_("Restoring ...")) - dialog.show() - tdir = self.target+"/"+self.get_active_text(self.widgets.get_widget("combobox1")) - r = srestore.SRestore() - r.restore( tdir, src, dst ) - del r - dialog.destroy() - - def restore( self, *args): - """ Restore selected path to its original location""" - self._restore_init() - self._do_restore( self.src, self.src ) - - def restore_as( self, *args): - """ Restore selected path to a specific location""" - iter = self._restore_init() - if self.treestore.iter_children( iter ): - # is a directory - dialog = gtk.FileChooserDialog(title=_("Select restore location") ,action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) - dialog.set_filename( self.src ) - result = dialog.run() - filename = dialog.get_filename() - dialog.destroy() - - if result == gtk.RESPONSE_OK: - self._do_restore( self.src, filename ) - else: - dialog = gtk.FileChooserDialog(title=_("Select restore location") ,action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) - dialog.set_filename( self.src ) - dialog.set_current_name( self.src ) - result = dialog.run() - filename = dialog.get_filename() - dialog.destroy() - - if result == gtk.RESPONSE_OK: - self._do_restore( self.src, filename ) - - -if __name__ == '__main__': - # Check for root privileges - if os.getuid() != 0: - error_dialog("Root or sudo privileges required!") - sys.exit(1) - - - # i18n init - locale.setlocale(locale.LC_ALL, '') - gettext.textdomain("sbackup") - gettext.install("sbackup", unicode=True) - - # Load GUI - SRestoreGTK() diff -Nru /tmp/Jk5jXWKfRF/sbackup-0.10.3/simple-restore-gnome.py /tmp/FlxBzI4QKq/sbackup-0.10.3/simple-restore-gnome.py --- /tmp/Jk5jXWKfRF/sbackup-0.10.3/simple-restore-gnome.py 1970-01-01 01:00:00.000000000 +0100 +++ /tmp/FlxBzI4QKq/sbackup-0.10.3/simple-restore-gnome.py 2007-04-28 07:44:15.000000000 +0200 @@ -0,0 +1,443 @@ +#!/usr/bin/python +# +# Simple Backup Solution - GUI restore tool +# +# Running this command will restore a file or directory from backup. +# +# Author: Aigars Mahinovs +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import sys +import os +import commands +import re +import ConfigParser +import cPickle +import srestore +import locale +import gettext +from gettext import gettext as _ + +# Attempt to load GTK bindings +try: + import pygtk + pygtk.require("2.0") + import gtk + import gtk.glade + import gobject +except ImportError: + print "Failed to load Python GTK/Gnome bindings. Please check your Gnome installation." + sys.exit(1) +try: + import gnomevfs +except ImportError: + import gnome.vfs as gnomevfs + + + +def error_dialog(message, parent = None): + """ + Displays an error message. + """ + + dialog = gtk.MessageDialog(parent = parent, type = gtk.MESSAGE_ERROR, buttons = gtk.BUTTONS_OK, flags = gtk.DIALOG_MODAL) + dialog.set_markup(message) + + result = dialog.run() + dialog.destroy() + + +class SRestoreGTK: + """ + Main application class. + """ + + default_target = "/var/backup" + target = default_target + versions = [] + + + def __init__(self): + """ + Initializes the application. + """ + + # Load default config + self.load_config() + + # Setup glade and signals + gtk.glade.textdomain("sbackup") + self.signals = {"gtk_main_quit": gtk.main_quit, + "on_customsrc_toggled": self.enable_custom, + "on_treeview1_row_expanded": self.on_expand_row, + "on_backup_changed": self.on_backup_changed, + "on_apply_clicked": self.on_custom_apply, + "on_move_cursor":self.on_selection_change, + "on_restore":self.restore, + "on_restore_as":self.restore_as, + "on_customFolderButton_clicked": self.on_customFolderButton_clicked + } + + self.widgets = gtk.glade.XML(self.conf.get("places", "prefix") + "/share/sbackup/simple-restore.glade") + self.widgets.signal_autoconnect(self.signals) + + # Get handle to window + self.window = self.widgets.get_widget("restore") + + self.widgets.get_widget("labelDefaultSource").set_text(self.default_target) + + # Load the backup tree from the default location + self.init_tree() + self.sel = self.flist_widget.get_selection() + self.sel.set_mode( gtk.SELECTION_SINGLE ) + self.load_tree(self.default_target) + + + # Start the main loop + gtk.main() + + def load_config(self): + """ + Load the default system configuration file and determine + the default backup location + """ + self.conf = ConfigParser.ConfigParser() + + self.conf.add_section( "places" ) + self.conf.set( "places", "prefix", "/usr" ) + + self.conf.read("/etc/sbackup.conf") + if self.conf.has_option( "general", "target" ): + self.default_target = self.conf.get( "general", "target" ) + + def init_tree(self): + """ + Initalizes the tree structure + """ + + self.flist_widget = self.widgets.get_widget("treeview1") + self.treestore = gtk.TreeStore( str ) + + self.flist_widget.set_model( self.treestore ) + + acolumn = gtk.TreeViewColumn( _("Path"), gtk.CellRendererText(), text=0 ) + self.flist_widget.append_column( acolumn ) + + blist_widget = self.widgets.get_widget( "combobox1" ) + self.blist = gtk.ListStore(str) + blist_widget.set_model( self.blist ) + cell = gtk.CellRendererText() + blist_widget.pack_start( cell, True ) + blist_widget.add_attribute( cell, "text", 0) + + + def load_tree(self, target): + """ + Loads the tree information from the target backup directory + """ + + self.treestore.clear() + + # Checking if the target directory is local or remote + local = True + try: + if gnomevfs.URI( target ).is_local: + target = gnomevfs.get_local_path_from_uri( target ) + else: + local = False + except: + pass + + self.local = local + self.target = target + + # Checking if it is a readable directory + if local: + if not (os.path.exists( target ) and os.path.isdir( target ) and os.access( target, os.R_OK | os.X_OK ) ): + self.treestore.append( None, [_("Error: backups directory does not exist!")]) + self.target = False + else: + if not (gnomevfs.exists( target ) and gnomevfs.get_file_info(target).type == 2): + self.treestore.append( None, [_("Error: backups directory does not exist!")]) + self.target = False + + # Get list of backup directories + r = re.compile(r"^(\d{4})-(\d{2})-(\d{2})_(\d{2})[\:\.](\d{2})[\:\.](\d{2})\.\d+\..*?\.(.+)$") + + listing = [] + + if local and self.target: + listing = os.listdir( target ) + listing = filter( r.search, listing ) + elif self.target: + try: + d = gnomevfs.open_directory( target ) + listing = [] + for f in d: + if f.type == 2 and f.name != "." and f.name != ".." and r.search( f.name ): + listing.append( f.name ) + except: pass + + # Check if these directories are complete and remove from the list those that are not + old_dirs = False + for adir in listing[:]: + if str(gnomevfs.read_entire_file( self.target+"/"+adir+"/ver"))[:3] != "1.3": + old_dirs = True + if local and os.access( self.target+"/"+adir+"/flist", os.F_OK ): + continue + if not local and gnomevfs.exists( self.target+"/"+adir+"/flist" ): + continue + listing.remove( adir ) + # Lets check if this is some old type directory + if local and os.access( self.target+"/"+adir+"/tree", os.F_OK ): + old_dirs = True + if not local and gnomevfs.exists( self.target+"/"+adir+"/tree" ): + old_dirs = True + if old_dirs: + # Ask for an upgrade + dialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format=_("Some of your backups are in an old backup format. Do you want to upgrade them?\nIt should take only a few minutes.")) + + response = dialog.run() + dialog.destroy() + if response == gtk.RESPONSE_YES: + # Do upgrade + import upgrade_backups + u = upgrade_backups.SBUpgrade() + u.upgrade_target( target ) + del u + # Reload tree + self.load_tree( target ) + return + + listing.sort() + listing.reverse() + + self.vtree = {} + + if listing == []: + self.treestore.append( None, [_("Error: no backups found in the target directory")]) + self.target = False + else: + for base in listing: + if str(gnomevfs.read_entire_file(target+"/"+base+"/ver"))[:3] == "1.3": + self.vtree[base] = str(gnomevfs.read_entire_file(target+"/"+base+"/flist")).split("\000") + else: + self.vtree[base] = str(gnomevfs.read_entire_file(target+"/"+base+"/flist")).split("\n") + + self.blist.clear() + + for base in listing: + self.blist.append( [base] ) + + self.good = False + self.on_selection_change() + if self.target: + self.treestore.append( None, [_("Select any of the available backups to see list of files that can be restored.")]) + #self.widgets.get_widget("entry1").set_text( target ) + + + def on_customFolderButton_clicked(self, *args): + dialog = gtk.FileChooserDialog(_("Choose a source folder"), None, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) + dialog.set_default_response(gtk.RESPONSE_OK) + dialog.set_local_only(False) + if dialog.run() == gtk.RESPONSE_OK: + self.widgets.get_widget("entry1").set_text(dialog.get_uri()) + dialog.destroy() + + def enable_custom(self, *args): + """ + Enables/Disables input box for the custom backup dir + Reloads default dir on disabling + """ + if self.widgets.get_widget("radiobutton2").get_active(): + self.widgets.get_widget("entry1").set_sensitive(True) + self.widgets.get_widget("customFolderButton").set_sensitive(True) + self.widgets.get_widget("button7").set_sensitive(True) + self.widgets.get_widget("labelDefaultSource").set_sensitive(False) + else: + self.widgets.get_widget("entry1").set_sensitive(False) + self.widgets.get_widget("customFolderButton").set_sensitive(False) + self.widgets.get_widget("button7").set_sensitive(False) + self.widgets.get_widget("labelDefaultSource").set_sensitive(True) + self.load_tree(self.default_target) + + def on_backup_changed( self, combox ): + """ + Reset the file tree view. + """ + self.treestore.clear() + self.treestore.append( None, ["dummy"]) + self.show_dir( "", None ) + + + def on_expand_row( self, tv, iter, path, user_data=None): + """ + When a row in the file tree view is expanded, we populate + it with children (unless they are there already). + """ + if self.treestore.iter_nth_child( iter, 1 ): + return + self.show_dir( self.path_to_dir(path), iter ) + + def path_to_dir( self, path ): + """ + Recievs path in the treestore (as tuple) and returns a directory + path as string. + """ + g = list(path) + p = "" + while g != []: + i = self.treestore.get_iter( tuple(g) ) + p = "/" + self.treestore.get_value( i, 0 ) + p + g = g[:-1] + return p + + def show_dir(self, path, rootiter): + """ + Worker function - adds all files/directories from the filez list + to the treestore at the rootiter. + """ + dummy = self.treestore.iter_children(rootiter) + + self.good = True + + base = self.get_active_text(self.widgets.get_widget("combobox1")) + list2 = [] + list3 = [] + + escapedFullPath = re.escape(path)+"/([^/]+/?)" + for item in self.vtree[base]: + m = re.match( escapedFullPath, item ) + if m and not list2.count(m.group(1)) and not list3.count(m.group(1)[:-1]): + if m.group(1)[-1] == "/": + if list2.count(m.group(1)[:-1]): + list2.remove(m.group(1)[:-1]) + list3.append(m.group(1)[:-1]) + else: + list2.append( m.group(1) ) + for d in list3: + iter = self.treestore.append( rootiter, [d] ) + self.treestore.append( iter, [_("Loading ...")] ) + for f in list2: + self.treestore.append( rootiter, [f] ) + + self.treestore.remove( dummy ) + + + def get_active_text(self, combobox): + model = combobox.get_model() + active = combobox.get_active() + if active < 0: + return None + return model[active][0] + + def on_custom_apply(self, *args): + """ + Reload all backup info from a custom location + """ + + self.load_tree(self.widgets.get_widget("entry1").get_text()) + + def on_selection_change(self, *args): + """ + Enable/disable restore buttons as selection changes + """ + (model, iter) = self.sel.get_selected() + if iter and self.good: + self.widgets.get_widget("button2").set_sensitive(True) + self.widgets.get_widget("button3").set_sensitive(True) + else: + self.widgets.get_widget("button2").set_sensitive(False) + self.widgets.get_widget("button3").set_sensitive(False) + + + def show_help(self, *args): + """ + Displays the help window. + Called when the 'Help' button is clicked. + """ + + # TODO: Implement + error_dialog(_("Sorry, help is not implemented yet."), self.window) + + def _restore_init( self, *args): + """ + Internal function to prepare for restorin a file + """ + (store, iter) = self.widgets.get_widget("treeview1").get_selection().get_selected() + self.src = self.path_to_dir( store.get_path( iter ) ) + return iter + + def _do_restore( self, src, dst): + """ Internal function to ask for confirmation and call the real restore library func""" + dialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format=_("Do you really want to restore backuped copy of '%s' to '%s' ?") % (src, dst)) + + response = dialog.run() + dialog.destroy() + if response == gtk.RESPONSE_YES: + dialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_NONE, message_format=_("Restoring ...")) + dialog.show() + tdir = self.target+"/"+self.get_active_text(self.widgets.get_widget("combobox1")) + r = srestore.SRestore() + r.restore( tdir, src, dst ) + del r + dialog.destroy() + + def restore( self, *args): + """ Restore selected path to its original location""" + self._restore_init() + self._do_restore( self.src, self.src ) + + def restore_as( self, *args): + """ Restore selected path to a specific location""" + iter = self._restore_init() + if self.treestore.iter_children( iter ): + # is a directory + dialog = gtk.FileChooserDialog(title=_("Select restore location") ,action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) + dialog.set_filename( self.src ) + result = dialog.run() + filename = dialog.get_filename() + dialog.destroy() + + if result == gtk.RESPONSE_OK: + self._do_restore( self.src, filename ) + else: + dialog = gtk.FileChooserDialog(title=_("Select restore location") ,action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) + dialog.set_filename( self.src ) + dialog.set_current_name( self.src ) + result = dialog.run() + filename = dialog.get_filename() + dialog.destroy() + + if result == gtk.RESPONSE_OK: + self._do_restore( self.src, filename ) + + +if __name__ == '__main__': + # Check for root privileges + if os.getuid() != 0: + error_dialog("Root or sudo privileges required!") + sys.exit(1) + + + # i18n init + locale.setlocale(locale.LC_ALL, '') + gettext.textdomain("sbackup") + gettext.install("sbackup", unicode=True) + + # Load GUI + SRestoreGTK()