summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.perl_checker54
-rw-r--r--Makefile66
-rw-r--r--data/Makefile20
-rw-r--r--data/autostart-draksnapshot.desktop.in9
-rw-r--r--data/gnome-autostart-draksnapshot.desktop.in8
-rwxr-xr-xdraksnapshot-applet269
-rw-r--r--draksnapshot-applet.xinit6
-rwxr-xr-xdraksnapshot-config308
-rwxr-xr-xdraksnapshot-restore32
-rw-r--r--draksnapshot.spec60
-rw-r--r--icons/draksnapshot-big.pngbin0 -> 4754 bytes
-rw-r--r--icons/draksnapshot.pngbin0 -> 1353 bytes
-rw-r--r--lib/.perl_checker.cachebin0 -> 3212038 bytes
l---------lib/MDV/Snapshot/.perl_checker1
-rw-r--r--lib/MDV/Snapshot/Common.pm47
-rw-r--r--lib/MDV/Snapshot/Restore.pm210
-rw-r--r--po/Makefile41
-rw-r--r--po/POTFILES.in2
-rw-r--r--po/draksnapshot.pot206
-rw-r--r--po/fr.po204
20 files changed, 1543 insertions, 0 deletions
diff --git a/.perl_checker b/.perl_checker
new file mode 100644
index 0000000..c105aa3
--- /dev/null
+++ b/.perl_checker
@@ -0,0 +1,54 @@
+AutoLoader
+base
+Carp::Heavy
+Compress::Zlib
+Config::IniFiles
+constant
+Cwd
+Date::Manip
+Digest::base
+Digest::Perl::MD5
+Discover
+Encode
+encoding
+feature
+File::Basename
+File::Find
+File::FnMatch
+File::GlobMapper
+File::MimeInfo::Magic
+File::Path
+File::Temp
+Gtk2::Gdk::Keysyms
+Gtk2::Pango
+HTTP::Message
+HTTP::Request
+HTTP::Request::Common
+install::gtk
+install::pkgs
+interactive::http
+IO::Compress::Gzip
+IO::Handle
+IO::Socket::SSL
+IO::Uncompress::Gunzip
+LWP::UserAgent
+LWP::UserlAgent
+Net::DNS
+Net::HTTP
+Net::HTTP::Methods
+Net::Ping
+Net::SSL
+Packdrakeng
+RS::Handy
+Scalar::Util
+SOAP::Lite
+Switch
+Term::ReadKey
+Text::ParseWords
+Time::ZoneInfo
+URI::Escape
+urpm
+urpm::cfg
+urpm::download
+urpm::prompt
+warnings
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ab8fc1c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,66 @@
+PACKAGE = draksnapshot
+VERSION:=0.1
+
+NAME = draksnapshot
+SUBDIRS = data po
+
+PREFIX = /
+DATADIR = $(PREFIX)/usr/share
+ICONSDIR = $(DATADIR)/icons
+PIXDIR = $(DATADIR)/$(NAME)
+SBINDIR = $(PREFIX)/usr/sbin
+BINDIR = $(PREFIX)/usr/bin
+SYSCONFDIR = $(PREFIX)/etc/sysconfig
+SBINREL = ../sbin
+PERL_VENDORLIB=$(DESTDIR)/$(shell perl -V:installvendorlib | perl -pi -e "s/.*=//; s/[;']//g")
+
+localedir = $(PREFIX)/usr/share/locale
+
+override CFLAGS += -DPACKAGE=\"$(NAME)\" -DLOCALEDIR=\"$(localedir)\"
+
+all:
+ for d in $(SUBDIRS); do ( cd $$d ; make $@ ) ; done
+
+clean:
+ $(MAKE) -C po $@
+ rm -f core .#*[0-9]
+ for d in $(SUBDIRS); do ( cd $$d ; make $@ ) ; done
+ find . -name '*~' | xargs rm -f
+
+install:
+ install -d $(PREFIX)/usr/{sbin,bin,share/{mime/packages,$(NAME)/pixmaps,autostart,gnome/autostart,icons/{mini,large}}}
+ install -m755 draksnapshot-config $(SBINDIR)
+ install -m755 draksnapshot-applet $(BINDIR)
+ install -d $(SYSCONFDIR)
+ install -m644 icons/$(NAME).png $(ICONSDIR)/mini/$(NAME).png
+ install -m644 icons/$(NAME).png $(ICONSDIR)/$(NAME).png
+ install -m644 icons/$(NAME)-big.png $(ICONSDIR)/large/$(NAME).png
+ install -m644 icons/*.png $(PIXDIR)/pixmaps
+ for d in $(SUBDIRS); do make -C $$d $@; done
+ mkdir -p $(PREFIX)/etc/X11/xinit.d
+ install -m 755 draksnapshot-applet.xinit $(PREFIX)/etc/X11/xinit.d/
+ mkdir -p $(PERL_VENDORLIB)/MDV/Snapshot
+ install -m 644 lib/MDV/Snapshot/*.pm $(PERL_VENDORLIB)/MDV/Snapshot
+
+cleandist:
+ rm -rf $(PACKAGE)-$(VERSION) ../$(PACKAGE)-$(VERSION).tar.bz2
+
+localcopy: clean
+ mkdir ../$(NAME)-$(VERSION)
+ cp -a . ../$(NAME)-$(VERSION)
+ mv ../$(NAME)-$(VERSION) .
+ #FIXME svn export -q -rBASE . $(NAME)-$(VERSION)
+
+tar:
+ tar cvfY ../$(PACKAGE)-$(VERSION).tar.lzma $(PACKAGE)-$(VERSION)
+ rm -rf $(PACKAGE)-$(VERSION)
+
+dist: cleandist localcopy tar
+
+log:changelog
+
+changelog: ../common/username
+#svn2cl is available in our contrib.
+ svn2cl --authors ../common/username.xml --accum
+ rm -f ChangeLog.bak
+ svn commit -m "Generated by svn2cl the `date '+%c'`" ChangeLog
diff --git a/data/Makefile b/data/Makefile
new file mode 100644
index 0000000..a3206e9
--- /dev/null
+++ b/data/Makefile
@@ -0,0 +1,20 @@
+DATADIR = $(PREFIX)/usr/share
+
+DESKTOP_IN := $(wildcard *.desktop.in)
+DESKTOP = $(DESKTOP_IN:.desktop.in=.desktop)
+
+all: $(DESKTOP)
+
+clean:
+ rm -f $(DESKTOP)
+
+install: all
+ mkdir -p $(DATADIR)/autostart
+ install autostart-draksnapshot.desktop $(DATADIR)/autostart/
+ mkdir -p $(DATADIR)/gnome/autostart
+ install gnome-autostart-draksnapshot.desktop $(DATADIR)/gnome/autostart/
+
+
+%.desktop: %.desktop.in
+ intltool-merge --utf8 ../po $< $@ -d -u -c intltool-merge-cache
+
diff --git a/data/autostart-draksnapshot.desktop.in b/data/autostart-draksnapshot.desktop.in
new file mode 100644
index 0000000..083691c
--- /dev/null
+++ b/data/autostart-draksnapshot.desktop.in
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=DrakSnapshot Applet
+Comment=Applet for DrakSnapshot
+Exec=%{_bindir}/draksnapshot-applet
+Icon=draksnapshot-applet
+Type=Application
+StartupNotify=true
+Categories=X-MandrivaLinux-System-Configuration-Networking;Settings;Network;
+X-KDE-autostart-after=kdesktop
diff --git a/data/gnome-autostart-draksnapshot.desktop.in b/data/gnome-autostart-draksnapshot.desktop.in
new file mode 100644
index 0000000..f61e1e8
--- /dev/null
+++ b/data/gnome-autostart-draksnapshot.desktop.in
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Name=DrakSnapshot Applet
+Comment=Applet for DrakSnapshot
+Exec=%{_bindir}/draksnapshot-applet
+Icon=draksnapshot-applet
+Type=Application
+StartupNotify=true
+Categories=X-MandrivaLinux-System-Configuration-Networking;Settings;Network;
diff --git a/draksnapshot-applet b/draksnapshot-applet
new file mode 100755
index 0000000..60bf89a
--- /dev/null
+++ b/draksnapshot-applet
@@ -0,0 +1,269 @@
+#!/usr/bin/perl
+################################################################################
+# Backup Applet #
+# #
+# Copyright (C) 2008 Mandriva #
+# #
+# Thierry Vignaud <tvignaud at mandriva dot com> #
+# #
+# This program is free software; you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License Version 2 as #
+# published by the Free Software Foundation. #
+# #
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
+################################################################################
+
+use strict;
+use POSIX ":sys_wait_h";
+use Config;
+use lib qw(/usr/lib/libDrakX);
+use standalone; # for explanations
+use interactive;
+use common;
+use run_program;
+use detect_devices;
+use feature 'state';
+
+use Gtk2::Pango;
+
+BEGIN { unshift @::textdomains, 'draksnapshot' }
+
+use mygtk2 qw(gtknew); #- do not import gtkadd which conflicts with ugtk2 version
+use ugtk2 qw(:all);
+use lib qw(/usr/lib/libDrakX/drakfirsttime);
+use Gtk2::Notify '-init', 'draksnapshot';
+
+ugtk2::add_icon_path("/usr/share/draksnapshot/pixmaps/");
+
+my ($menu, $timeout, @discs);
+
+my $localfile = "$ENV{HOME}/.draksnapshot";
+
+my $insensitive_while_running_a_child;
+
+my %state = (
+
+ okay => {
+ menu => [],
+ do_not_use_bubble => 1,
+ },
+ disk_found => {
+ menu => [ 'configure' ],
+ tt => [ N_("USB discs are availlable for backups") ]
+ },
+ config_in_progress => {
+ menu => [],
+ do_not_use_bubble => 1,
+ tt => [ N_("Configurator is currently running") ]
+ },
+ );
+
+
+my %actions = (
+ 'configure' => { name => N("Configure"), launch => \&configure }
+);
+
+my $icon = Gtk2::StatusIcon->new;
+$icon->signal_connect(popup_menu => sub {
+ my ($_icon, $button, $time) = @_;
+ $menu and $menu->popup(undef, undef, undef, undef, $button, $time);
+ });
+$icon->signal_connect(activate => \&configure);
+my ($opt) = @ARGV;
+if ($opt eq '--force' || $opt eq '-f') { setAutoStart('TRUE') }
+
+shouldStart() or die "$localfile should be set to TRUE: please use --force or -f option to launch applet\n";
+
+go2State('okay');
+gtkflush();
+silentCheck();
+Glib::Timeout->add(4000, sub { silentCheck(); 0 });
+setup_cyclic_check();
+
+
+$SIG{USR1} = 'IGNORE';
+$SIG{USR2} = 'IGNORE';
+$SIG{CHLD} = \&harvester;
+
+run_program::raw({ detach => 1 }, 'ionice', '-p', $$, '-n7');
+Gtk2->main;
+
+ugtk2::exit(0);
+
+my $config_pid;
+
+# Signal management
+sub harvester {
+ my ($_signame, $_clean) = @_;
+ my ($childpid, @pids);
+ my $configurator_returned;
+ do {
+ $childpid = waitpid(-1, &WNOHANG);
+ if ($config_pid && $config_pid == $childpid) {
+ undef $config_pid;
+ $configurator_returned = 1;
+ # we should better check it has really been configured indeed.
+ setAutoStart('FALSE');
+ ugtk2::exit(0);
+ }
+ push @pids, $childpid;
+ WIFEXITED($?) and refresh_gui(1);
+ } while $childpid > 0;
+ Glib::Timeout->add(200, sub { silentCheck(); 0 }) if $configurator_returned;
+ return @pids;
+}
+
+sub fork_exec {
+ my $pid = run_program::raw({ detach => 1 }, @_);
+ refresh_gui(1);
+ return $pid;
+}
+
+sub refresh_gui {
+ my ($sens) = @_;
+ #!$conf_launched and silentCheck(); $conf_launched = 0;
+ my $w = $::main_window ? $::main_window->window : undef;
+ $insensitive_while_running_a_child = !$sens;
+ $sens ? gtkset_mousecursor_normal($w) : gtkset_mousecursor_wait($w);
+ gtkflush();
+}
+
+sub configure() {
+ $config_pid = fork_exec('/usr/sbin/draksnapshot-config');
+ go2State('config_in_progress');
+}
+
+sub silentCheck() {
+ return if $config_pid;
+ my $w = $::main_window ? $::main_window->window : undef;
+ gtkset_mousecursor_wait($w);
+
+ # are there any updates ?
+
+ if (@discs = grep { $_->{usb_bus} } detect_devices::hds()) {
+ go2State('disk_found');
+ }
+ gtkset_mousecursor_normal($w) if !$insensitive_while_running_a_child;
+}
+
+sub setup_cyclic_check() {
+ $timeout = Glib::Timeout->add(
+ 5*60 * 1000,
+ sub { # default to 5 minutes
+ my $first_run if 0;
+ if (!$first_run) {
+ $first_run = 1;
+ return 1;
+ }
+ silentCheck();
+ 1;
+ });
+}
+
+sub go2State {
+ my $state = shift;
+ $menu->destroy if $menu;
+ $menu = setState($state);
+}
+
+sub isNetwork() {
+ require network::network;
+ require network::tools;
+ my $net = {};
+ network::network::read_net_conf($net);
+ my ($_gw_intf, $_is_up, $gw_address, $_dns_server) = network::tools::get_internet_connection($net);
+ to_bool($gw_address);
+}
+
+sub shouldStart() {
+ my %p = getVarsFromSh($localfile);
+ to_bool($p{AUTOSTART} ne 'FALSE');
+}
+
+sub setState {
+ my ($state_type) = @_;
+ my $checkme;
+ my $arr = $state{$state_type}{menu};
+ state $pixbuf;
+ if (!$pixbuf) {
+ $pixbuf = gtkcreate_pixbuf('draksnapshot');
+ $icon->set_from_pixbuf($pixbuf);
+ }
+ $icon->set_tooltip(formatAlaTeX(translate($state{$state_type}{tt}[0])));
+ $icon->set_visible($state_type ne 'okay');
+ gtkflush(); # so that bubbles are displayed on right icon
+
+ if ($state{$state_type}{tt}[0] && $icon->isa('Gtk2::StatusIcon') && !$state{$state_type}{do_not_use_bubble}) {
+ my $bubble = Gtk2::Notify->new_with_status_icon(N("Warning"), formatAlaTeX(translate($state{$state_type}{tt}[0])) . "\n",
+ '/usr/share/icons/draksnapshot.png', $icon);
+ $bubble->set_timeout(5000);
+ $bubble->show;
+ }
+
+ my $menu = Gtk2::Menu->new;
+ foreach (@$arr) {
+ $menu->append(gtksignal_connect(gtkshow(Gtk2::MenuItem->new_with_label($actions{$_}{name})), activate => $actions{$_}{launch}));
+ }
+ $menu->append(gtkshow(Gtk2::SeparatorMenuItem->new));
+ $menu->append(
+ gtksignal_connect(
+ gtkshow(Gtk2::MenuItem->new_with_label(N("About..."))),
+ activate => sub {
+ my $ver = 1; # automatically set from spec file
+ my $w = gtknew('AboutDialog', name => N("DrakSnapshot %s", $ver),
+ copyright => N("Copyright (C) %s by Mandriva", '2001-2007'),
+ license => join('', cat_('/usr/share/common-licenses/GPL')),
+ icon => '/usr/share/icons/mini/draksnapshot.png',
+ comments => N("DrakSnapshot enables to backup your machine through periodic snapshots."),
+ website => 'http://www.mandriva.com',
+ website_label => N("Mandriva WebSite"),
+ authors => 'Thierry Vignaud <vignaud@mandriva.com>',
+ translator_credits =>
+ #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith <jsmith@nowhere.com>")
+ N("_: Translator(s) name(s) & email(s)\n"),
+ transient_for => $::main_window, modal => 1, position_policy => 'center-on-parent',
+ );
+
+ $w->show_all;
+ $w->run;
+ return 1;
+
+ }));
+ $menu->append(gtksignal_connect(gtkset_active($checkme = Gtk2::CheckMenuItem->new_with_label(N("Always launch on startup")), shouldStart()), toggled => sub { setAutoStart(uc(bool2text($checkme->get_active))) }));
+ $checkme->show;
+ $menu->append(gtksignal_connect(gtkshow(Gtk2::MenuItem->new_with_label(N("Quit"))), activate => sub { mainQuit() }));
+ $menu;
+
+}
+sub logIt {
+ my $log = shift;
+ log::explanations($log);
+}
+
+sub setVar {
+ my ($file, $var, $st) = @_;
+ my %s = getVarsFromSh($file);
+ $s{$var} = $st;
+ setVarsInSh($file, \%s);
+}
+
+sub setAutoStart {
+ my ($state) = @_;
+ if (-f $localfile) {
+ setVar($localfile, 'AUTOSTART', $state);
+ } else {
+ output_p($localfile, "AUTOSTART=$state\n");
+ }
+}
+
+sub mainQuit() {
+ Glib::Source->remove($timeout) if $timeout;
+ Gtk2->main_quit;
+}
diff --git a/draksnapshot-applet.xinit b/draksnapshot-applet.xinit
new file mode 100644
index 0000000..598cbcf
--- /dev/null
+++ b/draksnapshot-applet.xinit
@@ -0,0 +1,6 @@
+#!/bin/sh
+DESKTOP=$1
+case $DESKTOP in
+ IceWM|Fluxbox|xfce4) exec /usr/bin/draksnapshot-applet;;
+esac
+EOF
diff --git a/draksnapshot-config b/draksnapshot-config
new file mode 100755
index 0000000..18ca4ce
--- /dev/null
+++ b/draksnapshot-config
@@ -0,0 +1,308 @@
+#!/usr/bin/perl
+################################################################################
+# Backup Configuration Tool #
+# #
+# Copyright (C) 2008 Mandriva #
+# #
+# Thierry Vignaud <tvignaud at mandriva dot com> #
+# #
+# This program is free software; you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License Version 2 as #
+# published by the Free Software Foundation. #
+# #
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
+################################################################################
+
+
+use lib qw(/usr/lib/libDrakX);
+use standalone; #- warning, standalone must be loaded very first, for 'explanations'
+use common;
+use interactive;
+use MDV::Snapshot::Common;
+use mygtk2 qw(gtknew); #- do not import gtkadd which conflicts with ugtk2 version
+use ugtk2 qw(:create :dialogs :helpers :wrappers);
+use Gtk2::SimpleList;
+use interactive;
+
+require_root_capability();
+
+ugtk2::add_icon_path("/usr/share/draksnapshot/pixmaps/");
+
+######### read config
+
+my @ordered_intervals = qw(hourly daily weekly monthly);
+
+my ($backup_list, $exclude_list) = map {
+ my $key = $_;
+ my $list = Gtk2::SimpleList->new('' => 'text');
+ # properly size when not embedded:
+ $list->set_size_request($::isEmbedded ? -1 : 500, 100);
+ $list->set_headers_visible(0);
+ @{$list->{data}} = map { [ (split(/\s/, $_, 3))[1] ] } grep { /^$key\s/ } cat_($config_file);
+ $list;
+} qw(backup exclude);
+
+
+my %default_intervals = (
+ map {
+ if (my ($type, $interval) = /^interval\s*(\S*)\s*(\S*)/) {
+ $type => $interval;
+ }
+ } grep { /^interval\s/ } cat_($config_file)
+);
+
+# initialize commented out fields:
+$default_intervals{$_} ||= undef foreach @ordered_intervals;
+
+
+######### GUI
+
+$ugtk2::wm_icon = "draksnapshot-big";
+my $my_win = ugtk2->new(N("Backup snapshots configuration"));
+
+unless ($::isEmbedded) {
+ $my_win->{window}->set_border_width(5);
+ #$my_win->{window}->set_default_size(540,460);
+}
+$my_win->{window}->signal_connect(delete_event => \&quit);
+
+
+### menus definition
+# the menus are not shown
+# but they provides shiny shortcut like C-q
+my @menu_items = (
+ { path => N("/_File"), item_type => '<Branch>' },
+ { path => N("/File/_Quit"), accelerator => N("<control>Q"), callback => \&quit },
+ { path => N("/_Help"), item_type => '<LastBranch>' },
+ { path => N("/Help/_About...") }
+);
+my $_menubar = $::isEmbedded ? create_factory_menu($my_win->{rwindow}, @menu_items) : undef;
+######### menus end
+
+
+my %interval_titles = (
+ 'hourly' => N("Hourly interval"),
+ 'daily' => N("Daily interval"),
+ 'weekly' => N("Weekly interval"),
+ 'monthly' => N("Monthly interval"),
+);
+
+
+my (%entries, $where);
+
+gtkadd($my_win->{window},
+ gtknew('VBox', children => [
+ if_(!$::isEmbedded, 0, Gtk2::Banner->new('draksnapshot-big',
+ N("Backup snapshots configuration"))),
+ 0, gtknew('Title1', label => N("Settings")),
+ 0, gtknew('HBox', spacing => 5, children => [
+ 0, gtknew('Label_Left', text => N("Where to backup")),
+ 1, $where =
+ gtknew('Entry', text => $backup_directory),
+ 0, gtknew('Button', text => N("Browse"),
+ clicked => sub {
+ my $file_dlg;
+ $file_dlg =
+ gtknew('FileSelection', title => N("Path selection"),
+ ok_button => {
+ clicked => sub {
+ $where->set_text($file_dlg->get_filename);
+ $file_dlg->destroy;
+ },
+ },
+ cancel_button => {
+ clicked => sub { $file_dlg->destroy },
+ },
+ );
+ $file_dlg->set_transient_for($my_win->{real_window});
+ $file_dlg->set_modal(1);
+ $file_dlg->set_filename($where->get_text);
+ $file_dlg->show;
+ },
+ ),
+ ]),
+
+ 0, gtknew('Title2', label => N("Intervals")),
+ 0, gtknew('Table', col_spacings => 10, row_spacings => 5, homogeneous => 1, children => [
+ map {
+ [
+ gtknew('Label_Left', text => $interval_titles{$_}),
+ $entries{$_} = gtknew('Entry', text => $default_intervals{$_})
+ ];
+ } @ordered_intervals
+ ]),
+ 0, gtknew('Title2', label => N("Backup list")),
+ 1, format_list($backup_list, 1),
+ 0, gtknew('Title2', label => N("Exclude list")),
+ 1, format_list($exclude_list),
+ 0, gtknew('HButtonBox', layout => 'end', border_width => 5, spacing => 5, children_loose => [
+ gtknew('Button', text => N("Apply"), clicked => \&save),
+ gtknew('Button', text => $::isEmbedded ? N("Cancel") : N("Close"), clicked => sub { save(); quit() })
+ ])
+ ])
+ );
+
+$my_win->{window}->show_all;
+$my_win->main;
+
+
+######### callbacks & helpers
+
+sub format_list {
+ my ($list, $o_check) = @_;
+ gtknew('HBox',
+ children => [
+ 0, gtkset_size_request(Gtk2::Alignment->new(0, 0, 0, 0), 35, 1),
+ 1, gtknew('ScrolledWindow', child => $list),
+ 0, gtknew('VBox', border_width => 5, spacing => 5,
+ children_tight => [
+ # FIXME: add "up" & "down" buttons? "edit" button?
+ gtknew('Button', text => N("Add"), clicked => sub {
+ add($list, $o_check);
+ }),
+ gtknew('Button', text => N("Remove"), clicked => sub {
+ my ($tree, $iter) = $list->get_selection->get_selected;
+ return if !$iter;
+ #my $removed_idx = $tree->get($iter, 5);
+ $tree->remove($iter);
+ #sensitive_buttons(0);
+ #$modified++;
+ }),
+ ]),
+ ],
+ );
+}
+
+sub quit() { ugtk2->exit(0) }
+
+
+sub add {
+ my ($list, $check, $o_iter) = @_;
+ my $model = $list->get_model;
+ my $dlg = gtknew('Dialog', transient_for => $my_win->{real_window}, title => N("Add"));
+ my $browse = gtknew('Button', text => N("browse"));
+ my $file = gtknew('Entry', $o_iter ? (text => $model->get($o_iter, 1)) : ());
+
+ my $alrd_exsts = defined $o_iter;
+
+ $browse->signal_connect(clicked => sub {
+ my $file_dlg = Gtk2::FileSelection->new(N("Path selection"));
+ $file_dlg->set_modal(1);
+ $file_dlg->set_transient_for($dlg);
+ $file_dlg->show;
+ $file_dlg->set_filename($file->get_text);
+ $file_dlg->cancel_button->signal_connect(clicked => sub { $file_dlg->destroy });
+ $file_dlg->ok_button->signal_connect(clicked => sub {
+ $file->set_text($file_dlg->get_filename);
+ $file_dlg->destroy;
+ });
+ });
+
+ gtkpack_($dlg->vbox,
+ 0, gtknew('Title2', label => N("Path")),
+ 0, gtknew('HBox', border_width => 18, children => [
+ 1, $file,
+ 0, $browse
+ ]),
+ );
+
+ #$dlg->set_has_separator(0);
+
+ gtkadd($dlg->action_area,
+ create_okcancel(my $w =
+ {
+ cancel_clicked => sub { $dlg->destroy },
+ ok_clicked => sub {
+ my $path = $file->get_text;
+ if ($check && $path !~ m!^/!) {
+ err_dialog(N("Warning"),
+ N("The first character of the path must be a slash (\"/\"):\n\"%s\"", $path));
+ return 1;
+ }
+ # create new item if needed (that is when adding a new one) at end of list
+ if (!$o_iter) {
+ push @{$list->{data}}, $path;
+ }
+ $dlg->destroy;
+ }
+ },
+ ),
+ );
+
+ $w->{ok}->set_sensitive(!$model->get($o_iter, 0)) if $alrd_exsts;
+ $dlg->show_all;
+
+}
+
+sub save() {
+ save_keyword('interval', map {
+ my $val = $entries{$_}->get_text;
+ if_($val, join("\t", 'interval', $_, $val));
+ } @ordered_intervals);
+
+ save_keyword('backup', map { join("\t", 'backup', @$_[0], 'localhost/') } @{$backup_list->{data}});
+ save_keyword('exclude', map { join("\t", 'exclude', @$_[0]) } @{$exclude_list->{data}});
+ save_keyword('snapshot_root', join("\t", 'snapshot_root', $where->get_text));
+ generate_cron_entry();
+}
+
+sub save_keyword {
+ my ($keyword, @values) = @_;
+ my ($removed, $done);
+ my $new_val = join('', map { "$_\n" }@values);
+ substInFile {
+ if (/^$keyword/) {
+ undef $_;
+ $removed++;
+ }
+ if ($removed == 1 && !$done) {
+ $done++;
+ $_ .= $new_val;
+ }
+ } $config_file;
+ # be safe:
+ append_to_file($config_file, $new_val) if !$done;
+}
+
+
+
+sub generate_cron_entry() {
+ my %minutes = (
+ 'hourly' => 0,
+ 'daily' => 50,
+ 'weekly' => 40,
+ 'monthly' => 30,
+ );
+
+ my $cron_file = "$::prefix/etc/cron.d/rsnapshot";
+
+ output($cron_file,
+ qq(# WARNING: This file is autogenerated from /etc/rsnapshot.conf.
+# WARNING: Please alter /etc/rsnapshot.conf instead of $cron_file
+#
+# $cron_file: crontab fragment for rsnapshot
+
+),
+ (map {
+ if (my ($type, $interval) = /^interval\s*(\S*)\s*(\S*)/) {
+ # crontab: minute hour day_month month day_of_week user command
+ join("\t",
+ $minutes{$type},
+ ($type eq 'hourly' ? "*/" . 24/$interval : 4),
+ ($type eq 'monthly' ? 1 : '*'),
+ '*' ,
+ ($type eq 'weekly' ? 6 : '*'),
+ 'root',
+ "/usr/bin/rsnapshot $type"
+ ), "\n";
+ }
+ } grep { /^interval\s/ } cat_($config_file)),
+ );
+}
diff --git a/draksnapshot-restore b/draksnapshot-restore
new file mode 100755
index 0000000..d59ec21
--- /dev/null
+++ b/draksnapshot-restore
@@ -0,0 +1,32 @@
+#!/usr/bin/perl
+################################################################################
+# Backup Configuration Tool #
+# #
+# Copyright (C) 2008 Mandriva #
+# #
+# Thierry Vignaud <tvignaud at mandriva dot com> #
+# #
+# This program is free software; you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License Version 2 as #
+# published by the Free Software Foundation. #
+# #
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
+################################################################################
+
+
+use lib qw(/usr/lib/libDrakX);
+use standalone; #- warning, standalone must be loaded very first, for 'explanations'
+use interactive;
+use MDV::Snapshot::Restore;
+
+my $in = interactive->vnew('su');
+$ugtk2::wm_icon = "logdrake";
+
+MDV::Snapshot::Restore::main($in);
diff --git a/draksnapshot.spec b/draksnapshot.spec
new file mode 100644
index 0000000..0340958
--- /dev/null
+++ b/draksnapshot.spec
@@ -0,0 +1,60 @@
+Summary: Snapshot utility
+Name: draksnapshot
+Version: 0.1
+Release: %mkrel 1
+Source0: %{name}-%{version}.tar.lzma
+URL: http://www.mandrivalinux.com
+License: GPL
+Group: Archiving/Other
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
+Requires: rsnapshot
+BuildRequires: gettext, perl-MDK-Common-devel
+BuildArch: noarch
+
+
+%description
+This is a backup program that uses rsync to take backup snapshots of
+filesystems. It uses hard links to save space on disk.
+
+%prep
+%setup -q
+
+%build
+%make
+perl -pi -e 's!my \$ver = 1;!my \$ver = '"'%version-%release'"';!' draksnapshot-applet
+
+%install
+rm -rf %{buildroot}
+%makeinstall_std PREFIX=$RPM_BUILD_ROOT
+
+%{find_lang} %{name}
+
+%post
+%{update_desktop_database}
+%{update_mime_database}
+
+%postun
+%{clean_desktop_database}
+%{clean_mime_database}
+
+%clean
+rm -rf %{buildroot}
+
+%files -f %name.lang
+%defattr(-,root,root)
+%defattr(-,root,root)
+%_bindir/*
+%_datadir/%{name}
+%_datadir/autostart/autostart-draksnapshot.desktop
+%_datadir/gnome/autostart/gnome-autostart-draksnapshot.desktop
+%_iconsdir/*.png
+%_liconsdir/*.png
+%_miconsdir/*.png
+%_sbindir/*
+%_sysconfdir/X11/xinit.d/draksnapshot-applet.xinit
+%perl_vendorlib/MDV
+
+
+%changelog
+* Wed Feb 27 2008 Thierry Vignaud <tvignaud@mandriva.com> 0.1-1mdv2008.1
+- initial release
diff --git a/icons/draksnapshot-big.png b/icons/draksnapshot-big.png
new file mode 100644
index 0000000..699ebd8
--- /dev/null
+++ b/icons/draksnapshot-big.png
Binary files differ
diff --git a/icons/draksnapshot.png b/icons/draksnapshot.png
new file mode 100644
index 0000000..eae6250
--- /dev/null
+++ b/icons/draksnapshot.png
Binary files differ
diff --git a/lib/.perl_checker.cache b/lib/.perl_checker.cache
new file mode 100644
index 0000000..9c02a4c
--- /dev/null
+++ b/lib/.perl_checker.cache
Binary files differ
diff --git a/lib/MDV/Snapshot/.perl_checker b/lib/MDV/Snapshot/.perl_checker
new file mode 120000
index 0000000..6246b2f
--- /dev/null
+++ b/lib/MDV/Snapshot/.perl_checker
@@ -0,0 +1 @@
+../../../.perl_checker \ No newline at end of file
diff --git a/lib/MDV/Snapshot/Common.pm b/lib/MDV/Snapshot/Common.pm
new file mode 100644
index 0000000..3ef2d63
--- /dev/null
+++ b/lib/MDV/Snapshot/Common.pm
@@ -0,0 +1,47 @@
+package MDV::Snapshot::Common;
+
+################################################################################
+# Backup Configuration Tool #
+# #
+# Copyright (C) 2008 Mandriva #
+# #
+# Thierry Vignaud <tvignaud at mandriva dot com> #
+# #
+# This program is free software; you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License Version 2 as #
+# published by the Free Software Foundation. #
+# #
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
+################################################################################
+
+
+use lib qw(/usr/lib/libDrakX);
+use common;
+
+use Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw($config_file $backup_directory);
+
+our ($config_file, $backup_directory);
+
+sub init {
+ $config_file = "$::prefix/etc/rsnapshot.conf";
+
+ $backup_directory = "$::prefix/" .
+ (split(/\s/, (find { /^snapshot_root\s/ } cat_($config_file)), 2))[1];
+
+ # normalize for glob():
+ chomp($backup_directory);
+ $backup_directory =~ s!/*$!!;
+}
+
+init();
+
+1;
diff --git a/lib/MDV/Snapshot/Restore.pm b/lib/MDV/Snapshot/Restore.pm
new file mode 100644
index 0000000..0a2a83c
--- /dev/null
+++ b/lib/MDV/Snapshot/Restore.pm
@@ -0,0 +1,210 @@
+package MDV::Snapshot::Restore;
+
+################################################################################
+# Backup Configuration Tool #
+# #
+# Copyright (C) 2008 Mandriva #
+# #
+# Thierry Vignaud <tvignaud at mandriva dot com> #
+# #
+# This program is free software; you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License Version 2 as #
+# published by the Free Software Foundation. #
+# #
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
+################################################################################
+
+
+use lib qw(/usr/lib/libDrakX);
+use c;
+use locale;
+use MDV::Snapshot::Common;
+use common;
+use interactive;
+use POSIX;
+use run_program;
+use fsedit;
+use fs::type;
+use fs;
+use any;
+
+sub get_fstab() {
+ my $all_hds = fsedit::get_hds();
+ fs::get_raw_hds('', $all_hds);
+ fs::get_info_from_fstab($all_hds);
+ [ fs::get::fstab($all_hds) ]; # $fstab
+}
+
+sub get_handle {
+ my ($fstab, $part, $o_rw) = @_;
+ my ($mntpnt) = map { $_->{mntpoint} } grep { $_->{device} eq $part->{device} } @$fstab;
+
+ # do not bother failed to mount with ro b/c already mounted:
+ $mntpnt ? { dir => $mntpnt } : any::inspect($part, $::prefix, $o_rw);
+}
+
+
+sub find_disks_with_rsnapshot {
+ my ($fstab) = @_;
+
+ my @true_fs =
+ grep { isTrueLocalFS($_) &&
+ !member($_->{mntpoint},
+ '/home', grep { $_ ne '/' } fs::type::directories_needed_to_boot());
+ } @$fstab;
+
+ log::l("looking for rsnapshot.conf on partitions " . join(' ', map { $_->{device} } @true_fs));
+
+ my @found;
+ foreach my $part (@true_fs) {
+ my $handle = get_handle($fstab, $part);
+ next if !$handle;
+ next if ! -e "$handle->{dir}/etc/rsnapshot.conf";
+
+ if (my $f = common::release_file($handle->{dir})) {
+ my $h = common::parse_release_file($handle->{dir}, $f, $part);
+ $h->{name} = $h->{release};
+ push @found, $h;
+ }
+ }
+
+ return @found;
+}
+
+sub get_snapshots() {
+ my %backups =
+ map {
+ my $backup = $_;
+ my ($type, $_number) = m!$backup_directory/([^/]*)\.([0-9]*)!;
+ my $raw_date = [ stat($backup) ]->[-4];
+ my $date = POSIX::strftime($type eq 'hourly' ? "%c" : "%x", localtime($raw_date));
+ c::set_tagged_utf8($date);
+ $backup => { raw_date => $raw_date, date => $date, backup => $backup, type => $type };
+ } glob_("$backup_directory/*");
+ %backups;
+}
+
+sub configure {
+ my ($in) = @_;
+ my $backup;
+ my %backups = get_snapshots();
+
+ if (!%backups) {
+ $in->ask_warn(N("Error"), N("No backup found!"));
+ return;
+ }
+
+ my %i18n = (
+ 'hourly' => N("Hourly"),
+ 'daily' => N("Daily"),
+ 'weekly' => N("Weekly"),
+ 'monthly' => N("Monthly"),
+ );
+
+ $in->ask_from_(
+ {
+ title => N("Backup snapshots configuration"),
+ },
+ [
+ { title => 1, label => N("Backup snapshots configuration") },
+ { label => N("Please select the backup you want to restore.") },
+ { val => \$backup, sort => 0, allow_empty_list => 1,
+ format => sub {
+ #-PO: eg: "Daily snapshot done on Sun Feb 4
+ N("%s snapshot done on %s", $i18n{$backups{$_[0]}{type}}, $backups{$_[0]}{date});
+ },
+ list => [ sort { $backups{$a}{raw_date} cmp $backups{$b}{raw_date} } keys %backups ],
+ },
+ ]) or return;
+
+ my $_wait = $in->wait_message(N("Please wait"), N("Restoring backup in progress"));
+ my $backup_dir = $backups{$backup}{backup};
+ # FIXME: add a progress bar
+ foreach (glob_("$backup_dir/localhost/*")) {
+ my $dir = $_;
+ s!^$backup_dir/localhost!!;
+ log::l("would run system('rsync', '-vrlpt', $dir, $::prefix$_)\n") if $::testing;
+ # FIXME: should we use --delete?
+ run_program::run('rsync', '-vrlpt', $dir, "$::prefix$_") if !$::testing;
+ }
+}
+
+
+sub mount_all {
+ my ($in, $fstab) = @_;
+ local $::testing = 0;
+
+ my @errs;
+ foreach my $part (sort { $a->{mntpoint} cmp $b->{mntpoint} }
+ grep { $_->{mntpoint} && maybeFormatted($_) && $_->{device} ne 'none'
+ && !member($_->{fs_type}, 'swap', 'nfs', if_($::isInstall, 'ntfs'));
+ }
+ @$fstab) {
+
+ eval { fs::mount::part($part) };
+ push @errs, $@ if $@;
+ }
+ $in->ask_warn(N("Warning"), N("mount failled:") . join("\n", '', @errs)) if @errs;
+}
+
+sub main {
+ my ($in) = @_;
+
+ my ($system, $fstab, @found);
+ refresh:
+ $fstab = get_fstab();
+ @found = find_disks_with_rsnapshot($fstab);
+
+ $in->ask_from_({ interactive_help_id => 'configureX_chooser',
+ title => N("Restoring Backup"),
+ messages => join("\n",
+ N("Please select the partition of the system to restore."),
+ N("Do not forgot to plug the USB disk that contains your backups."),
+ )
+ },
+ [
+ { label => N("System to restore"), },
+ {
+ val => \$system, list => \@found, allow_empty_list => 1,
+ format => sub {
+ my $dev = $_[0];
+ N("\"%s\" (on %s)", $dev->{name}, $dev->{part}{device});
+ },
+ },
+ {
+ val => N("Refresh"), clicked => sub { goto refresh },
+ },
+ ]);
+
+ my $handle = get_handle($fstab, $system->{part}, 1);
+ local $::prefix = $handle->{dir};
+
+ # reinit paths according to temp mount point:
+ MDV::Snapshot::Common::init();
+
+ my $ch_fstab;
+ if (ref($handle) =~ /before_leaving/) {
+ $ch_fstab = [ fs::read_fstab($::prefix, '/etc/fstab') ];
+ mount_all($in, $ch_fstab);
+ }
+
+ configure($in);
+
+ # make sure everything is umounted:
+ if (ref($handle) =~ /before_leaving/) {
+
+ # reread for {real_mountpoint}:
+ $ch_fstab = [ fs::read_fstab($::prefix, '/etc/fstab') ];
+
+ eval { fs::mount::umount_all($ch_fstab) };
+ }
+}
+
+1;
diff --git a/po/Makefile b/po/Makefile
new file mode 100644
index 0000000..eb2e9c1
--- /dev/null
+++ b/po/Makefile
@@ -0,0 +1,41 @@
+# Installation directories
+localedir = $(PREFIX)/usr/share/locale
+
+PGOAL = draksnapshot
+
+top_srcdir=..
+
+PL_FILES = ../draksnapshot-applet ../draksnapshot-config ../draksnapshot-restore
+
+POFILES = $(shell ls *.po)
+
+POFILES = $(shell ls *.po)
+MOFILES = $(POFILES:%.po=%.mo)
+LANGS = $(POFILES:%.po=%)
+
+GOALS = $(PGOAL).pot $(MOFILES)
+
+all: $(GOALS)
+
+install: all
+ for l in $(LANGS); do \
+ install -d $(localedir)/$$l/LC_MESSAGES; \
+ install -m 644 $$l.mo $(localedir)/$$l/LC_MESSAGES/$(PGOAL).mo; \
+ done
+
+clean:
+ rm -f *~ *.[oas] *.mo TAGS
+
+%.mo: %.po
+ msgfmt -o $@ $<
+
+$(PGOAL).pot: $(PL_FILES)
+ perl_checker -q --generate-pot $(PGOAL).pot $(PL_FILES)
+
+merge: $(PGOAL).pot
+ @for n in $(POFILES); do \
+ echo "Merging $$n"; \
+ msgmerge "$$n" $< > "$$n"t; \
+ mv -f "$$n"t "$$n"; \
+ done
+
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644
index 0000000..2b36578
--- /dev/null
+++ b/po/POTFILES.in
@@ -0,0 +1,2 @@
+data/autostart-draksnapshot.desktop.in
+data/gnome-autostart-draksnapshot.desktop.in
diff --git a/po/draksnapshot.pot b/po/draksnapshot.pot
new file mode 100644
index 0000000..965c535
--- /dev/null
+++ b/po/draksnapshot.pot
@@ -0,0 +1,206 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2008-02-27 18:14+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8-bit\n"
+
+#: ../draksnapshot-applet:59
+#, c-format
+msgid "USB discs are availlable for backups"
+msgstr ""
+
+#: ../draksnapshot-applet:64
+#, c-format
+msgid "Configurator is currently running"
+msgstr ""
+
+#: ../draksnapshot-applet:70
+#, c-format
+msgid "Configure"
+msgstr ""
+
+#: ../draksnapshot-applet:204 ../draksnapshot-config:224
+#, c-format
+msgid "Warning"
+msgstr ""
+
+#: ../draksnapshot-applet:217
+#, c-format
+msgid "About..."
+msgstr ""
+
+#: ../draksnapshot-applet:220
+#, c-format
+msgid "DrakSnapshot %s"
+msgstr ""
+
+#: ../draksnapshot-applet:221
+#, c-format
+msgid "Copyright (C) %s by Mandriva"
+msgstr ""
+
+#: ../draksnapshot-applet:224
+#, c-format
+msgid "DrakSnapshot enables to backup your machine through periodic snapshots."
+msgstr ""
+
+#: ../draksnapshot-applet:226
+#, c-format
+msgid "Mandriva WebSite"
+msgstr ""
+
+#. -PO: put here name(s) and email(s) of translator(s) (eg: "John Smith <jsmith@nowhere.com>")
+#: ../draksnapshot-applet:230
+#, c-format
+msgid ""
+"_: Translator(s) name(s) & email(s)\n"
+""
+msgstr ""
+
+#: ../draksnapshot-applet:239
+#, c-format
+msgid "Always launch on startup"
+msgstr ""
+
+#: ../draksnapshot-applet:241
+#, c-format
+msgid "Quit"
+msgstr ""
+
+#: ../draksnapshot-config:68 ../draksnapshot-config:102
+#, c-format
+msgid "Backup snapshots configuration"
+msgstr ""
+
+#: ../draksnapshot-config:81
+#, c-format
+msgid "/_File"
+msgstr ""
+
+#: ../draksnapshot-config:82
+#, c-format
+msgid "/File/_Quit"
+msgstr ""
+
+#: ../draksnapshot-config:82
+#, c-format
+msgid "<control>Q"
+msgstr ""
+
+#: ../draksnapshot-config:83
+#, c-format
+msgid "/_Help"
+msgstr ""
+
+#: ../draksnapshot-config:84
+#, c-format
+msgid "/Help/_About..."
+msgstr ""
+
+#: ../draksnapshot-config:91
+#, c-format
+msgid "Hourly interval"
+msgstr ""
+
+#: ../draksnapshot-config:92
+#, c-format
+msgid "Daily interval"
+msgstr ""
+
+#: ../draksnapshot-config:93
+#, c-format
+msgid "Weekly interval"
+msgstr ""
+
+#: ../draksnapshot-config:94
+#, c-format
+msgid "Monthly interval"
+msgstr ""
+
+#: ../draksnapshot-config:103
+#, c-format
+msgid "Settings"
+msgstr ""
+
+#: ../draksnapshot-config:105
+#, c-format
+msgid "Where to backup"
+msgstr ""
+
+#: ../draksnapshot-config:108
+#, c-format
+msgid "Browse"
+msgstr ""
+
+#: ../draksnapshot-config:112 ../draksnapshot-config:195
+#, c-format
+msgid "Path selection"
+msgstr ""
+
+#: ../draksnapshot-config:131
+#, c-format
+msgid "Intervals"
+msgstr ""
+
+#: ../draksnapshot-config:140
+#, c-format
+msgid "Backup list"
+msgstr ""
+
+#: ../draksnapshot-config:142
+#, c-format
+msgid "Exclude list"
+msgstr ""
+
+#: ../draksnapshot-config:145
+#, c-format
+msgid "Apply"
+msgstr ""
+
+#: ../draksnapshot-config:146
+#, c-format
+msgid "Cancel"
+msgstr ""
+
+#: ../draksnapshot-config:146
+#, c-format
+msgid "Close"
+msgstr ""
+
+#: ../draksnapshot-config:166 ../draksnapshot-config:188
+#, c-format
+msgid "Add"
+msgstr ""
+
+#: ../draksnapshot-config:169
+#, c-format
+msgid "Remove"
+msgstr ""
+
+#: ../draksnapshot-config:189
+#, c-format
+msgid "browse"
+msgstr ""
+
+#: ../draksnapshot-config:208
+#, c-format
+msgid "Path"
+msgstr ""
+
+#: ../draksnapshot-config:225
+#, c-format
+msgid ""
+"The first character of the path must be a slash (\"/\"):\n"
+"\"%s\""
+msgstr ""
+
diff --git a/po/fr.po b/po/fr.po
new file mode 100644
index 0000000..a695399
--- /dev/null
+++ b/po/fr.po
@@ -0,0 +1,204 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: draksnapshot\n"
+"POT-Creation-Date: 2008-02-27 18:14+0100\n"
+"PO-Revision-Date: 2008-02-27 18:15+0100\n"
+"Last-Translator: Thierry Vignaud <tvignaud@mandriva.com>\n"
+"Language-Team: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8-bit\n"
+
+#: ../draksnapshot-applet:59
+#, c-format
+msgid "USB discs are availlable for backups"
+msgstr ""
+
+#: ../draksnapshot-applet:64
+#, c-format
+msgid "Configurator is currently running"
+msgstr ""
+
+#: ../draksnapshot-applet:70
+#, c-format
+msgid "Configure"
+msgstr "Configurer"
+
+#: ../draksnapshot-applet:204 ../draksnapshot-config:224
+#, c-format
+msgid "Warning"
+msgstr "Attention"
+
+#: ../draksnapshot-applet:217
+#, c-format
+msgid "About..."
+msgstr "À propos ..."
+
+#: ../draksnapshot-applet:220
+#, c-format
+msgid "DrakSnapshot %s"
+msgstr ""
+
+#: ../draksnapshot-applet:221
+#, c-format
+msgid "Copyright (C) %s by Mandriva"
+msgstr "Copyright (C) %s par Mandriva"
+
+#: ../draksnapshot-applet:224
+#, c-format
+msgid "DrakSnapshot enables to backup your machine through periodic snapshots."
+msgstr ""
+
+#: ../draksnapshot-applet:226
+#, c-format
+msgid "Mandriva WebSite"
+msgstr ""
+
+#. -PO: put here name(s) and email(s) of translator(s) (eg: "John Smith <jsmith@nowhere.com>")
+#: ../draksnapshot-applet:230
+#, c-format
+msgid "_: Translator(s) name(s) & email(s)\n"
+msgstr "Thierry Vignaud <tvignaud@mandriva.com>\n"
+
+#: ../draksnapshot-applet:239
+#, c-format
+msgid "Always launch on startup"
+msgstr "Toujours lancer au démarrage"
+
+#: ../draksnapshot-applet:241
+#, c-format
+msgid "Quit"
+msgstr "Quitter"
+
+#: ../draksnapshot-config:68 ../draksnapshot-config:102
+#, c-format
+msgid "Backup snapshots configuration"
+msgstr ""
+
+#: ../draksnapshot-config:81
+#, c-format
+msgid "/_File"
+msgstr "/_Fichier"
+
+#: ../draksnapshot-config:82
+#, c-format
+msgid "/File/_Quit"
+msgstr "/Fichier/_Quitter"
+
+#: ../draksnapshot-config:82
+#, c-format
+msgid "<control>Q"
+msgstr "<control>Q"
+
+#: ../draksnapshot-config:83
+#, c-format
+msgid "/_Help"
+msgstr "/_Aide"
+
+#: ../draksnapshot-config:84
+#, c-format
+msgid "/Help/_About..."
+msgstr "/Aide/_A propos..."
+
+#: ../draksnapshot-config:91
+#, c-format
+msgid "Hourly interval"
+msgstr ""
+
+#: ../draksnapshot-config:92
+#, c-format
+msgid "Daily interval"
+msgstr ""
+
+#: ../draksnapshot-config:93
+#, c-format
+msgid "Weekly interval"
+msgstr ""
+
+#: ../draksnapshot-config:94
+#, c-format
+msgid "Monthly interval"
+msgstr ""
+
+#: ../draksnapshot-config:103
+#, c-format
+msgid "Settings"
+msgstr "Paramètres"
+
+#: ../draksnapshot-config:105
+#, c-format
+msgid "Where to backup"
+msgstr ""
+
+#: ../draksnapshot-config:108
+#, c-format
+msgid "Browse"
+msgstr "Naviguer"
+
+#: ../draksnapshot-config:112 ../draksnapshot-config:195
+#, c-format
+msgid "Path selection"
+msgstr "Sélection du chemin"
+
+#: ../draksnapshot-config:131
+#, c-format
+msgid "Intervals"
+msgstr ""
+
+#: ../draksnapshot-config:140
+#, c-format
+msgid "Backup list"
+msgstr ""
+
+#: ../draksnapshot-config:142
+#, c-format
+msgid "Exclude list"
+msgstr ""
+
+#: ../draksnapshot-config:145
+#, c-format
+msgid "Apply"
+msgstr "Appliquer"
+
+#: ../draksnapshot-config:146
+#, c-format
+msgid "Cancel"
+msgstr "Annuler"
+
+#: ../draksnapshot-config:146
+#, c-format
+msgid "Close"
+msgstr "Fermer"
+
+#: ../draksnapshot-config:166 ../draksnapshot-config:188
+#, c-format
+msgid "Add"
+msgstr "Ajouter"
+
+#: ../draksnapshot-config:169
+#, c-format
+msgid "Remove"
+msgstr "Supprimer"
+
+#: ../draksnapshot-config:189
+#, c-format
+msgid "browse"
+msgstr "naviguer"
+
+#: ../draksnapshot-config:208
+#, c-format
+msgid "Path"
+msgstr "Chemin"
+
+#: ../draksnapshot-config:225
+#, c-format
+msgid ""
+"The first character of the path must be a slash (\"/\"):\n"
+"\"%s\""
+msgstr ""
+"Le premier caractère du chemin doit être un slash (\\\"/\\\"):\n"
+"« %s »"