diff --git a/VERSION b/VERSION
index 2cd3aa1..3eebe6a 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.0 - stable
+1.1.0 - dev
diff --git a/i18n/en.yml b/i18n/en.yml
index 6eecd3c..7805f04 100644
--- a/i18n/en.yml
+++ b/i18n/en.yml
@@ -1,8 +1,6 @@
 ---
 en:
   error:
-    add:
-      name_empty: "You must define a name!"
     config:
       write: "Can't write the config file!"
       check: "Checkconfig failed!"
@@ -18,7 +16,12 @@ en:
       bad_format: "Can't import, the file is badly formated!"
       read: "Can't import, unable to read %{file}!"
     update:
-      id_no_exist: "Can't update the item, the item %{id} doesn't exist!"
+      name_empty: "You must define a name!"
+    sync: 
+      connection: "Connection fail!"
+      no_data: "Nothing data!"
+      not_authorized: "You haven't the access to remote file!"
+      unknown: "An unknown error is occured!" 
   cli:
     option:
       usage: "Usage"
@@ -101,6 +104,8 @@ en:
       port: "Port"
       protocol: "Protocol"
       server: "Server"
+    sync:
+      not_connect: "The server connection fail!"	
   ssh:
     option:
       usage: "Usage"
@@ -111,6 +116,25 @@ en:
     display:
       connect: "Connection to:"
       nothing: "Nothing result!"
+  server:
+    option:
+      usage: "Usage"
+      config: "Specifie the configuration file"
+      checkconfig: "Check the configuration"
+      setup: "Setup a new configuration file"
+      help: "Show this message help"
+    checkconfig:
+      fail: "Checkconfig failed:!"
+      empty: "ERROR: an importe option is missing!"
+      datadir: "ERROR: le data directory doesn't exist!"
+    form:
+      setup:
+        title: "Serveur configuration" 
+        host: "IP listen: "
+        port: "Port listen: "
+        data_dir: "Data directory: "
+        timeout: "Timeout to second: "
+        not_valid: "ERROR: Impossible to write the configuration file!"
   formats:
     default: ! '%Y-%m-%d'
     long: ! '%B %d, %Y'
diff --git a/i18n/fr.yml b/i18n/fr.yml
index ba433fb..9005238 100644
--- a/i18n/fr.yml
+++ b/i18n/fr.yml
@@ -1,8 +1,6 @@
 ---
 fr:
   error:
-    add:
-      name_empty: "Vous devez définir un nom!"
     config:
       write: "Impossible d'écrire le fichier de configuration!"
       check: "Le fichier de configuration est invalide!"
@@ -18,7 +16,12 @@ fr:
       bad_format: "Impossible d'importer le fichier car son format est incorrect!"
       read: "Impossible d'importer le fichier %{file}, car il n'est pas lisible!"
     update:
-      id_no_exist: "Impossible de mettre à jour l'élément %{id}, car il n'existe pas!"
+      name_empty: "Vous devez définir un nom!"
+    sync: 
+      connection: "La connexion n'a pu être établie"
+      no_data: "Aucune data!"
+      not_authorized: "Vous n'avez pas les autorisations d'accès au fichier distant!"
+      unknown: "Une erreur inconnue est survenue!" 
   cli:
     option:
       usage: "Utilisation"
@@ -101,6 +104,8 @@ fr:
       port: "Port"
       protocol: "Protocol"
       server: "Serveur"
+    sync:
+      not_connect: "La connexion au serveur n'a pu être établie!"	
   ssh:
     option:
       usage: "Utilisation"
@@ -111,6 +116,25 @@ fr:
     display:
       connect: "Connexion à:"
       nothing: "Aucun résultat!"
+  server:
+    option:
+      usage: "Utilisation"
+      config: "Spécifie le fichier de configuration"
+      checkconfig: "Vérifie le fichier de configuration"
+      setup: "Permet de générer un nouveau fichier de configuration"
+      help: "Affiche ce message d'aide"
+    checkconfig:
+      fail: "Le fichier de configuration est invalide!"
+      empty: "ERREUR: Une option importante est manquante!"
+      datadir: "ERREUR: Le répertoire des données n'existe pas!"
+    form:
+      setup:
+        title: "Configuration du serveur" 
+        host: "IP d'écoute: "
+        port: "Port d'écoute: "
+        data_dir: "Répertoire des données: "
+        timeout: "Timeout en seconde: "
+        not_valid: "ERREUR: Impossible d'écire le fichier de configuration!"
   formats:
     default: ! '%Y-%m-%d'
     long: ! '%B %d, %Y'
diff --git a/lib/Cli.rb b/lib/Cli.rb
index cc67cd1..31c4a57 100644
--- a/lib/Cli.rb
+++ b/lib/Cli.rb
@@ -8,24 +8,47 @@ require 'highline/import'
 require 'pathname'
 require 'readline'
 require 'i18n'
+require 'yaml'
 
 require "#{APP_ROOT}/lib/MPW.rb"
+require "#{APP_ROOT}/lib/MPWConfig.rb"
+require "#{APP_ROOT}/lib/Sync.rb"
 
 class Cli
 
 	# Constructor
 	# @args: lang -> the operating system language
 	#        config_file -> a specify config file
-	def initialize(lang, config_file=nil)
-		@m = MPW.new(config_file)
-		
-		if not @m.checkconfig()
-			self.setup(lang)
+	def initialize(lang, config)
+		@config = config
+
+		@mpw = MPW.new(@config.file_gpg, @config.key)
+		if not decrypt()
+			puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}"
+			exit 2
 		end
 
-		if not self.decrypt()
-			puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}"
-			exit 2
+		@sync = Sync.new()
+		if @config.sync_host.nil? || @config.sync_port.nil?
+			@sync.disable()
+		elsif !@sync.connect(@config.sync_host, @config.sync_port, @config.key, @config.sync_pwd, @config.sync_suffix)
+			puts "#{I18n.t('cli.sync.not_connect')}:\n#{@sync.error_msg}"
+		end
+	end
+
+	# Destructor
+	def finalize()
+		@sync.close()
+	end
+
+	# Sync the data with the server
+	def sync()
+		begin
+			@mpw.sync(@sync.get(@passwd), @config.last_update)
+			@sync.update(File.open(@config.file_gpg).read)
+			@config.setLastUpdate()
+		rescue Exception => e
+			puts "#{I18n.t('cli.sync.error')}:\n#{e}"
 		end
 	end
 
@@ -44,35 +67,35 @@ class Cli
 		end
 		I18n.locale = language.to_sym
 
-		if @m.setup(key, language, file_gpg, timeout_pwd)
+		if @config.setup(key, language, file_gpg, timeout_pwd)
 			puts I18n.t('cli.form.setup.valid')
 		else
-			puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}"
+			puts "#{I18n.t('cli.display.error')}: #{@config.error_msg}"
 		end
 
-		if not @m.checkconfig()
-			puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}"
+		if not @config.checkconfig()
+			puts "#{I18n.t('cli.display.error')}: #{@config.error_msg}"
 		end
 	end
 
 	# Request the GPG password and decrypt the file
 	def decrypt()
 		@passwd = ask(I18n.t('cli.display.gpg_password')) {|q| q.echo = false}
-		return @m.decrypt(@passwd)
+		return @mpw.decrypt(@passwd)
 	end
 
 	# Display the query's result
 	# @args: search -> the string to search
 	#        protocol -> search from a particular protocol
 	def display(search, protocol=nil, group=nil, format=nil)
-		result = @m.search(search, group, protocol)
+		result = @mpw.search(search, group, protocol)
 
 		if not result.empty?
 			result.each do |r|
 				if format.nil? || !format
-					self.displayFormat(r)
+					displayFormat(r)
 				else
-					self.displayFormatAlt(r)
+					displayFormatAlt(r)
 				end
 			end
 		else
@@ -125,21 +148,21 @@ class Cli
 		port     = ask(I18n.t('cli.form.add.port')).to_s
 		comment  = ask(I18n.t('cli.form.add.comment')).to_s
 
-		if @m.add(name, group, server, protocol, login, passwd, port, comment)
-			if @m.encrypt()
+		if @mpw.update(name, group, server, protocol, login, passwd, port, comment)
+			if @mpw.encrypt()
 				puts I18n.t('cli.form.add.valid')
 			else
-				puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}"
+				puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}"
 			end
 		else
-			puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}"
+			puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}"
 		end
 	end
 
 	# Update an item
 	# @args: id -> the item's id
 	def update(id)
-		row = @m.searchById(id)
+		row = @mpw.searchById(id)
 
 		if not row.empty?
 			puts I18n.t('cli.form.update.title')
@@ -153,14 +176,14 @@ class Cli
 			port     = ask(I18n.t('cli.form.update.port'    , :port => row[MPW::PORT])).to_s
 			comment  = ask(I18n.t('cli.form.update.comment' , :comment => row[MPW::COMMENT])).to_s
 				
-			if @m.update(id, name, group, server, protocol, login, passwd, port, comment)
-				if @m.encrypt()
+			if @mpw.update(name, group, server, protocol, login, passwd, port, comment, id)
+				if @mpw.encrypt()
 					puts I18n.t('cli.form.update.valid')
 				else
-					puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}"
+					puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}"
 				end
 			else
-				puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}"
+				puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}"
 			end
 		else
 			puts I18n.t('cli.display.nothing')
@@ -172,10 +195,10 @@ class Cli
 	#        force -> no resquest a validation
 	def remove(id, force=false)
 		if not force
-			result = @m.searchById(id)		
+			result = @mpw.searchById(id)
 
 			if result.length > 0
-				self.displayFormat(result)
+				displayFormat(result)
 
 				confirm = ask("#{I18n.t('cli.form.delete.ask', :id => id)} (y/N) ").to_s
 				if confirm =~ /^(y|yes|YES|Yes|Y)$/
@@ -187,11 +210,11 @@ class Cli
 		end
 
 		if force
-			if @m.remove(id)
-				if @m.encrypt()
+			if @mpw.remove(id)
+				if @mpw.encrypt()
 					puts I18n.t('cli.form.delete.valid', :id => id)
 				else
-					puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}"
+					puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}"
 				end
 			else
 				puts I18n.t('cli.form.delete.not_valid')
@@ -202,10 +225,10 @@ class Cli
 	# Export the items in a CSV file
 	# @args: file -> the destination file
 	def export(file)
-		if @m.export(file)
+		if @mpw.export(file)
 			puts "The export in #{file} is succesfull!"
 		else
-			puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}"
+			puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}"
 		end
 
 	end
@@ -214,12 +237,12 @@ class Cli
 	# @args: file -> the import file
 	#        force -> no resquest a validation
 	def import(file, force=false)
-		result = @m.importPreview(file)
+		result = @mpw.importPreview(file)
 
 		if not force
 			if result.is_a?(Array) && !result.empty?
 				result.each do |r|
-					self.displayFormat(r)
+					displayFormat(r)
 				end
 
 				confirm = ask("#{I18n.t('cli.form.import.ask', :file => file)} (y/N) ").to_s
@@ -232,10 +255,10 @@ class Cli
 		end
 
 		if force
-			if @m.import(file) && @m.encrypt()
+			if @mpw.import(file) && @mpw.encrypt()
 				puts I18n.t('cli.form.import.valid')
 			else
-				puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}"
+				puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}"
 			end
 		end
 	end
@@ -247,7 +270,7 @@ class Cli
 
 		while buf = Readline.readline('<mpw> ', true)
 
-			if @m.timeout_pwd < Time.now.to_i - last_access
+			if @config.timeout_pwd < Time.now.to_i - last_access
 				passwd_confirm = ask(I18n.t('cli.interactive.ask_password')) {|q| q.echo = false}
 
 				if @passwd.eql?(passwd_confirm)
@@ -265,17 +288,17 @@ class Cli
 			case command[0]
 			when 'display', 'show', 'd', 's'
 				if !command[1].nil? && !command[1].empty?
-					self.display(command[1], group, command[2])
+					display(command[1], group, command[2])
 				end
 			when 'add', 'a'
 				add()
 			when 'update', 'u'
 				if !command[1].nil? && !command[1].empty?
-					self.update(command[1])
+					update(command[1])
 				end
 			when 'remove', 'delete', 'r', 'd'
 				if !command[1].nil? && !command[1].empty?
-					self.remove(command[1])
+					remove(command[1])
 				end
 			when 'group', 'g'
 				if !command[1].nil? && !command[1].empty?
diff --git a/lib/MPW.rb b/lib/MPW.rb
index f09f438..6886b85 100644
--- a/lib/MPW.rb
+++ b/lib/MPW.rb
@@ -6,7 +6,6 @@
 require 'rubygems'
 require 'gpgme'
 require 'csv'
-require 'yaml'
 require 'i18n'
 
 class MPW
@@ -20,80 +19,15 @@ class MPW
 	PASSWORD = 6
 	PORT     = 7
 	COMMENT  = 8
+	DATE     = 9
 
 	attr_accessor :error_msg
-	attr_accessor :timeout_pwd
-
+	
 	# Constructor
-	# @args: file_config -> the specify config file
-	def initialize(file_config=nil)
-		@error_msg  = nil
-		@file_config = "#{Dir.home()}/.mpw.cfg"
-
-		if !file_config.nil? && !file_config.empty?
-			@file_config = file_config
-		end
-	end
-
-	# Create a new config file
-	# @args: key -> the gpg key to encrypt
-	#        lang -> the software language
-	#        file_gpg -> the file who is encrypted
-	#        timeout_pwd -> time to save the password 
-	# @rtrn: true if le config file is create
-	def setup(key, lang, file_gpg, timeout_pwd)
-
-		if not key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/
-			@error_msg = I18n.t('error.config.key_bad_format')
-			return false
-		end
-		
-		if file_gpg.empty?
-			file_gpg = "#{Dir.home()}/.mpw.gpg"
-		end
-
-		timeout_pwd.empty? ? (timeout_pwd = 60) : (timeout_pwd = timeout_pwd.to_i)
-
-		config = {'config' => {'key'         => key,
-		                       'lang'        => lang,
-		                       'file_gpg'    => file_gpg,
-		                       'timeout_pwd' => timeout_pwd}}
-
-		begin
-			File.open(@file_config, 'w') do |file|
-				file << config.to_yaml
-			end
-		rescue Exception => e 
-			@error_msg = "#{I18n.t('error.config.write')}\n#{e}"
-			return false
-		end
-
-		return true
-	end
-
-	# Check the config file
-	# @rtrn: true if the config file is correct
-	def checkconfig()
-		begin
-			config = YAML::load_file(@file_config)
-			@key         = config['config']['key']
-			@lang        = config['config']['lang']
-			@file_gpg    = config['config']['file_gpg']
-			@timeout_pwd = config['config']['timeout_pwd'].to_i
-
-			if @key.empty? || @file_gpg.empty? 
-				@error_msg = I18n.t('error.config.check')
-				return false
-			end
-				
-			I18n.locale = @lang.to_sym
-
-		rescue Exception => e 
-			@error_msg = "#{I18n.t('error.config.check')}\n#{e}"
-			return false
-		end
-
-		return true
+	def initialize(file_gpg, key=nil)
+		@error_msg = nil
+		@file_gpg  = file_gpg
+		@key       = key
 	end
 
 	# Decrypt a gpg file
@@ -107,10 +41,8 @@ class MPW
 				crypto = GPGME::Crypto.new(:armor => true)
 				data_decrypt = crypto.decrypt(IO.read(@file_gpg), :password => passwd).read
 
-				id = 0
 				data_decrypt.lines do |line|
-					@data[id] = line.parse_csv.unshift(id)
-					id += 1;
+					@data.push(line.parse_csv)
 				end
 			end
 
@@ -130,7 +62,7 @@ class MPW
 
 			data_to_encrypt = ''
 			@data.each do |row|
-				data_to_encrypt << row.drop(1).to_csv
+				data_to_encrypt << row.to_csv
 			end
 
 			crypto.encrypt(data_to_encrypt, :recipients => @key, :output => file_gpg)
@@ -147,7 +79,7 @@ class MPW
 	# @args: search -> the string to search
 	#        protocol -> the connection protocol (ssh, web, other)
 	# @rtrn: a list with the resultat of the search
-	def search(search, group=nil, protocol=nil)
+	def search(search='', group=nil, protocol=nil)
 		result = Array.new()
 
 		if !search.nil?
@@ -174,57 +106,15 @@ class MPW
 	# @args: id -> the id item
 	# @rtrn: a row with the resultat of the search
 	def searchById(id)
-		if not @data[id.to_i].nil?
-			return @data[id.to_i]
-		else
-			return Array.new
+		@data.each do |row|
+			if row[ID] == id
+				return row
+			end
 		end
+
+		return Array.new()
 	end
 
-	# Add a new item
-	# @args: name -> the item name
-	#        group -> the item group
-	#        server -> the ip or server
-	#        protocol -> the protocol
-	#        login -> the login
-	#        passwd -> the password
-	#        port -> the port
-	#        comment -> a comment
-	# @rtrn: true if it works
-	def add(name, group=nil, server=nil, protocol=nil, login=nil, passwd=nil, port=nil, comment=nil)
-		row = Array.new()
-		
-		if name.nil? || name.empty?
-			@error_msg = I18n.t('error.add.name_empty')
-			return false
-		end
-		
-		if port.to_i <= 0
-			port = nil
-		end
-
-		if not @data.last.nil?
-			id = @data.last
-			id = id[ID].to_i + 1
-		else
-			id = 0
-		end
-
-		row[ID]    = id
-		row[PORT]  = port
-		row[NAME]  = name.force_encoding('ASCII-8BIT')
-		group.nil?    || group.empty?    ? (row[GROUP]    = nil) : (row[GROUP]    = group.force_encoding('ASCII-8BIT'))
-		server.nil?   || server.empty?   ? (row[SERVER]   = nil) : (row[SERVER]   = server.force_encoding('ASCII-8BIT'))
-		protocol.nil? || protocol.empty? ? (row[PROTOCOL] = nil) : (row[PROTOCOL] = protocol.force_encoding('ASCII-8BIT'))
-		login.nil?    || login.empty?    ? (row[LOGIN]    = nil) : (row[LOGIN]    = login.force_encoding('ASCII-8BIT'))
-		passwd.nil?   || passwd.empty?   ? (row[PASSWORD] = nil) : (row[PASSWORD] = passwd.force_encoding('ASCII-8BIT'))
-		comment.nil?  || comment.empty?  ? (row[COMMENT]  = nil) : (row[COMMENT]  = comment.force_encoding('ASCII-8BIT'))
-
-		@data[id] = row
-
-		return true
-	end
-	
 	# Update an item
 	# @args: id -> the item's identifiant
 	#        name -> the item name
@@ -236,46 +126,66 @@ class MPW
 	#        port -> the port
 	#        comment -> a comment
 	# @rtrn: true if the item has been updated
-	def update(id, name=nil, group=nil, server=nil, protocol=nil, login=nil, passwd=nil, port=nil, comment=nil)
-		id = id.to_i
+	def update(name, group, server, protocol, login, passwd, port, comment, id=nil)
+		row    = Array.new()
+		update = false
 
-		if not @data[id].nil?
-
-			if port.to_i <= 0
-				port = nil
+		i  = 0
+		@data.each do |r|
+			if r[ID] == id
+				row    = r
+				update = true
+				break
 			end
+			i += 1
+		end
 
-			row = @data[id]
-			row_update = Array.new()
+		if port.to_i <= 0
+			port = nil
+		end
 
-			name.nil?     || name.empty?     ? (row_update[NAME]     = row[NAME])     : (row_update[NAME]     = name)
-			group.nil?    || group.empty?    ? (row_update[GROUP]    = row[GROUP])    : (row_update[GROUP]    = group)
-			server.nil?   || server.empty?   ? (row_update[SERVER]   = row[SERVER])   : (row_update[SERVER]   = server)
-			protocol.nil? || protocol.empty? ? (row_update[PROTOCOL] = row[PROTOCOL]) : (row_update[PROTOCOL] = protocol)
-			login.nil?    || login.empty?    ? (row_update[LOGIN]    = row[LOGIN])    : (row_update[LOGIN]    = login)
-			passwd.nil?   || passwd.empty?   ? (row_update[PASSWORD] = row[PASSWORD]) : (row_update[PASSWORD] = passwd)
-			port.nil?     || port.empty?     ? (row_update[PORT]     = row[PORT])     : (row_update[PORT]     = port)
-			comment.nil?  || comment.empty?  ? (row_update[COMMENT]  = row[COMMENT])  : (row_update[COMMENT]  = comment)
-			
-			@data[id] = row_update
+		row_update       = Array.new()
+		row_update[DATE] = Time.now.to_i
 
-			return true
-		else
-			@error_msg = I18n.t('error.update.id_no_exist', :id => id)
+		id.nil?	      || id.empty?       ? (row_update[ID]       = MPW.generatePassword(16)) : (row_update[ID]       = row[ID])
+		name.nil?     || name.empty?     ? (row_update[NAME]     = row[NAME])                : (row_update[NAME]     = name)
+		group.nil?    || group.empty?    ? (row_update[GROUP]    = row[GROUP])               : (row_update[GROUP]    = group)
+		server.nil?   || server.empty?   ? (row_update[SERVER]   = row[SERVER])              : (row_update[SERVER]   = server)
+		protocol.nil? || protocol.empty? ? (row_update[PROTOCOL] = row[PROTOCOL])            : (row_update[PROTOCOL] = protocol)
+		login.nil?    || login.empty?    ? (row_update[LOGIN]    = row[LOGIN])               : (row_update[LOGIN]    = login)
+		passwd.nil?   || passwd.empty?   ? (row_update[PASSWORD] = row[PASSWORD])            : (row_update[PASSWORD] = passwd)
+		port.nil?     || port.empty?     ? (row_update[PORT]     = row[PORT])                : (row_update[PORT]     = port)
+		comment.nil?  || comment.empty?  ? (row_update[COMMENT]  = row[COMMENT])             : (row_update[COMMENT]  = comment)
+		
+		if row_update[NAME].nil? || row_update[NAME].empty?
+			@error_msg = I18n.t('error.update.name_empty')
 			return false
 		end
+
+		if update
+			@data[i] = row_update
+		else
+			@data.push(row_update)
+		end
+
+		return true
 	end
 	
 	# Remove an item 
 	# @args: id -> the item's identifiant
 	# @rtrn: true if the item has been deleted
 	def remove(id)
-		if not @data.delete_at(id.to_i).nil?
-			return true
-		else
-			@error_msg = I18n.t('error.delete.id_no_exist', :id => id)
-			return false
+		i = 0
+		@data.each do |row|
+			if row[ID] == id
+				@data.delete_at(i)
+				return true
+			end
+			i += 1
 		end
+
+		@error_msg = I18n.t('error.delete.id_no_exist', :id => id)
+		return false
 	end
 
 	# Export to csv
@@ -285,7 +195,7 @@ class MPW
 		begin
 			File.open(file, 'w+') do |file|
 				@data.each do |row|
-					row.delete_at(ID)
+					row.delete_at(ID).delete_at(DATE)
 					file << row.to_csv
 				end
 			end
@@ -309,7 +219,7 @@ class MPW
 					return false
 				else
 					row = line.parse_csv.unshift(0)
-					if not add(row[NAME], row[GROUP], row[SERVER], row[PROTOCOL], row[LOGIN], row[PASSWORD], row[PORT], row[COMMENT])
+					if not update(row[NAME], row[GROUP], row[SERVER], row[PROTOCOL], row[LOGIN], row[PASSWORD], row[PORT], row[COMMENT])
 						return false
 					end
 				end
@@ -322,7 +232,7 @@ class MPW
 		end
 	end
 
-	# Return 
+	# Return a preview import 
 	# @args: file -> path to file import
 	# @rtrn: an array with the items to import, if there is an error return false
 	def importPreview(file)
@@ -349,6 +259,50 @@ class MPW
 		end
 	end
 
+	# Sync remote data and local data
+	# @args: data_remote -> array with the data remote
+	#        last_update -> last update
+	# @rtrn: false if data_remote is nil
+	def sync(data_remote, last_update)
+		if !data_remote.instance_of?(Array)
+			return false
+		end
+
+		@data.each do |l|
+			j = 0
+			update = false
+
+			# Update item
+			data_remote.each do |r|
+				if l[ID] == r[ID]
+					if l[DATE].to_i < r[DATE].to_i
+						update(r[NAME], r[GROUP], r[SERVER], r[PROTOCOL], r[LOGIN], r[PASSWORD], r[PORT], r[COMMENT], l[ID])
+					end
+					update = true
+					data_remote.delete_at(j)
+					break
+				end
+				j += 1
+			end
+
+			# Delete an old item
+			if !update && l[DATE].to_i < last_update
+				remove(l[ID])
+			end
+		end
+
+		# Add item
+		data_remote.each do |r|
+			if r[DATE].to_i > last_update
+				update(r[NAME], r[GROUP], r[SERVER], r[PROTOCOL], r[LOGIN], r[PASSWORD], r[PORT], r[COMMENT], r[ID])
+			end
+		end
+
+		encrypt()
+
+		return true
+	end
+
 	# Generate a random password
 	# @args: length -> the length password
 	# @rtrn: a random string
@@ -367,7 +321,6 @@ class MPW
 		result << ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(length).join
 
 		return result
-		#return ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]-%w(0 1 I O l i o)).sample(length).join
 	end
-		
+	
 end
diff --git a/lib/MPWConfig.rb b/lib/MPWConfig.rb
new file mode 100644
index 0000000..d68d0c7
--- /dev/null
+++ b/lib/MPWConfig.rb
@@ -0,0 +1,130 @@
+#!/usr/bin/ruby
+# author: nishiki
+# mail: nishiki@yaegashi.fr
+# info: a simple script who manage your passwords
+
+require 'rubygems'
+require 'yaml'
+require 'i18n'
+
+class MPWConfig
+	
+	attr_accessor :error_msg
+
+	attr_accessor :key
+	attr_accessor :lang
+	attr_accessor :file_gpg
+	attr_accessor :timeout_pwd
+	attr_accessor :last_update
+	attr_accessor :sync_host
+	attr_accessor :sync_port
+	attr_accessor :sync_pwd
+	attr_accessor :sync_suffix
+	attr_accessor :last_update
+
+	# Constructor
+	# @args: file_config -> the specify config file
+	def initialize(file_config=nil)
+		@error_msg   = nil
+		@file_config = "#{Dir.home()}/.mpw.cfg"
+
+		if !file_config.nil? && !file_config.empty?
+			@file_config = file_config
+		end
+	end
+
+	# Create a new config file
+	# @args: key -> the gpg key to encrypt
+	#        lang -> the software language
+	#        file_gpg -> the file who is encrypted
+	#        timeout_pwd -> time to save the password 
+	# @rtrn: true if le config file is create
+	def setup(key, lang, file_gpg, timeout_pwd)
+
+		if not key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/
+			@error_msg = I18n.t('error.config.key_bad_format')
+			return false
+		end
+		
+		if file_gpg.empty?
+			file_gpg = "#{Dir.home()}/.mpw.gpg"
+		end
+
+		timeout_pwd.empty? ? (timeout_pwd = 60) : (timeout_pwd = timeout_pwd.to_i)
+
+		config = {'config' => {'key'         => key,
+		                       'lang'        => lang,
+		                       'file_gpg'    => file_gpg,
+		                       'timeout_pwd' => timeout_pwd,
+		                       'sync_host'   => host,
+		                       'sync_port'   => port,
+		                       'sync_pwd'    => password,
+		                       'sync_suffix' => suffix,
+		                       'last_update' => 0 }}
+
+		begin
+			File.open(@file_config, 'w') do |file|
+				file << config.to_yaml
+			end
+		rescue Exception => e 
+			@error_msg = "#{I18n.t('error.config.write')}\n#{e}"
+			return false
+		end
+
+		return true
+	end
+
+	# Check the config file
+	# @rtrn: true if the config file is correct
+	def checkconfig()
+		begin
+			config = YAML::load_file(@file_config)
+			@key         = config['config']['key']
+			@lang        = config['config']['lang']
+			@file_gpg    = config['config']['file_gpg']
+			@timeout_pwd = config['config']['timeout_pwd'].to_i
+			@sync_host   = config['config']['sync_host']
+			@sync_port   = config['config']['sync_port']
+			@sync_pwd    = config['config']['sync_pwd']
+			@sync_suffix  = config['config']['sync_suffix']
+			@last_update = config['config']['last_update'].to_i
+
+			if @key.empty? || @file_gpg.empty? 
+				@error_msg = I18n.t('error.config.check')
+				return false
+			end
+
+			I18n.locale = @lang.to_sym
+
+		rescue Exception => e 
+			@error_msg = "#{I18n.t('error.config.check')}\n#{e}"
+			return false
+		end
+
+		return true
+	end
+
+	def setLastUpdate()
+		config = {'config' => {'key'         => @key,
+		                       'lang'        => @lang,
+		                       'file_gpg'    => @file_gpg,
+		                       'timeout_pwd' => @timeout_pwd,
+		                       'sync_host'   => @sync_host,
+		                       'sync_port'   => @sync_port,
+		                       'sync_pwd'    => @sync_pwd,
+		                       'sync_suffix' => @sync_suffix,
+		                       'last_update' => Time.now.to_i }}
+
+		begin
+			File.open(@file_config, 'w') do |file|
+				file << config.to_yaml
+			end
+		rescue Exception => e 
+			@error_msg = "#{I18n.t('error.config.write')}\n#{e}"
+			return false
+		end
+
+		return true
+	end
+	
+end
diff --git a/lib/Server.rb b/lib/Server.rb
new file mode 100644
index 0000000..5b76de7
--- /dev/null
+++ b/lib/Server.rb
@@ -0,0 +1,295 @@
+#!/usr/bin/ruby
+
+require 'socket'
+require 'json'
+require 'highline/import'
+require 'digest'
+
+require "#{APP_ROOT}/lib/MPW.rb"
+
+class Server
+	
+	attr_accessor :error_msg
+
+	# Constructor
+	def initialize()
+		YAML::ENGINE.yamler='syck'
+	end
+
+	# Start the server
+	def start()
+		server = TCPServer.open(@host, @port)
+		loop do
+			Thread.start(server.accept) do |client|
+				while true do
+					msg = getClientMessage(client)
+
+					if !msg
+						next
+					end
+					
+					if msg['gpg_key'].nil? || msg['gpg_key'].empty? || msg['password'].nil? || msg['password'].empty?
+						closeConnection(client)
+						next
+					end
+
+					case msg['action']
+					when 'get'
+						client.puts getFile(msg)
+					when 'update'
+						client.puts updateFile(msg)
+					when 'delete'
+						client.puts deleteFile(msg)
+					when 'close'
+						closeConnection(client)
+					else
+						client.puts 'Unknown command'
+						closeConnection(client)
+					end
+				end
+			end
+		end
+	end
+
+	# Get a gpg file
+	# @args: msg -> message puts by the client
+	# @rtrn: json message
+	def getFile(msg)
+		gpg_key = msg['gpg_key'].sub('@', '_')
+
+		if msg['suffix'].nil? || msg['suffix'].empty?
+			file_gpg = "#{@data_dir}/#{gpg_key}.yml"
+		else
+			file_gpg = "#{@data_dir}/#{gpg_key}-#{msg['suffix']}.yml"
+		end
+
+		if File.exist?(file_gpg)
+			gpg_data    = YAML::load_file(file_gpg)
+			salt        = gpg_data['gpg']['salt']
+			hash        = gpg_data['gpg']['hash']
+			data        = gpg_data['gpg']['data']
+
+			if isAuthorized?(msg['password'], salt, hash)
+				send_msg = {:action      => 'get',
+				            :gpg_key     => msg['gpg_key'],
+				            :msg         => 'done',
+				            :data        => data}
+			else
+				send_msg = {:action  => 'get',
+				            :gpg_key => msg['gpg_key'],
+				            :msg     => 'fail',
+				            :error   => 'not_authorized'}
+			end
+		else
+			send_msg = {:action      => 'get',
+			            :gpg_key     => msg['gpg_key'],
+			            :data        => '',
+			            :msg         => 'fail',
+			            :error       => 'file_not_exist'}
+		end
+
+		return send_msg.to_json
+	end
+
+	# Update a file
+	# @args: msg -> message puts by the client
+	# @rtrn: json message
+	def updateFile(msg)
+		gpg_key = msg['gpg_key'].sub('@', '_')
+		data    = msg['data']
+
+		if data.nil? || data.empty?
+			send_msg = {:action  => 'update',
+			            :gpg_key => msg['gpg_key'],
+			            :msg     => 'fail',
+			            :error   => 'no_data'}
+			
+			return send_msg.to_json
+		end
+
+		if msg['suffix'].nil? || msg['suffix'].empty?
+			file_gpg = "#{@data_dir}/#{gpg_key}.yml"
+		else
+			file_gpg = "#{@data_dir}/#{gpg_key}-#{msg['suffix']}.yml"
+		end
+
+		if File.exist?(file_gpg)
+			gpg_data  = YAML::load_file(file_gpg)
+			salt      = gpg_data['gpg']['salt']
+			hash      = gpg_data['gpg']['hash']
+
+		else
+			salt = MPW.generatePassword(4)
+			hash = Digest::SHA256.hexdigest(salt + msg['password'])
+		end
+
+		if isAuthorized?(msg['password'], salt, hash)
+			begin
+				config = {'gpg' => {'salt'        => salt,
+				                    'hash'        => hash,
+				                    'data'        => data}}
+
+				File.open(file_gpg, 'w+') do |file|
+					file << config.to_yaml
+				end
+
+				send_msg = {:action      => 'update',
+				            :gpg_key     => msg['gpg_key'],
+				            :msg         => 'done'}
+			rescue Exception => e
+				send_msg = {:action  => 'update',
+				            :gpg_key => msg['gpg_key'],
+				            :msg     => 'fail',
+				            :error   => 'server_error'}
+			end
+		else
+			send_msg = {:action  => 'update',
+			            :gpg_key => msg['gpg_key'],
+			            :msg     => 'fail',
+			            :error   => 'not_autorized'}
+		end
+		
+		return send_msg.to_json
+	end
+
+	# Remove a gpg file
+	# @args: msg -> message puts by the client
+	# @rtrn: json message
+	def deleteFile(msg)
+		gpg_key = msg['gpg_key'].sub('@', '_')
+
+		if msg['suffix'].nil? || msg['suffix'].empty?
+			file_gpg = "#{@data_dir}/#{gpg_key}.yml"
+		else
+			file_gpg = "#{@data_dir}/#{gpg_key}-#{msg['suffix']}.yml"
+		end
+
+		if !File.exist?(file_gpg)
+			send_msg = {:action  => 'delete',
+			            :gpg_key => msg['gpg_key'],
+			            :msg     => 'delete_fail',
+			            :error   => 'file_not_exist'}
+
+			return send_msg.to_json
+		end
+
+		gpg_data  = YAML::load_file(file_gpg)
+		salt      = gpg_data['gpg']['salt']
+		hash      = gpg_data['gpg']['hash']
+
+		if isAuthorized?(msg['password'], salt, hash)
+			begin
+				File.unlink(file_gpg)
+
+				send_msg = {:action  => 'delete',
+				            :gpg_key => msg['gpg_key'],
+				            :msg    => 'delete_done'}
+			rescue Exception => e
+				send_msg = {:action  => 'delete',
+				            :gpg_key => msg['gpg_key'],
+				            :msg     => 'delete_fail',
+				            :error   => e}
+			end
+		else
+			send_msg = {:action  => 'delete',
+			            :gpg_key => msg['gpg_key'],
+			            :msg     => 'delete_fail',
+			            :error   => 'not_autorized'}
+		end
+		
+		return send_msg.to_json
+	end
+
+	# Check is the hash equal the password with the salt
+	# @args: password -> the user password
+	#        salt -> the salt
+	#        hash -> the hash of the password with the salt
+	# @rtrn: true is is good, else false
+	def isAuthorized?(password, salt, hash)
+		if hash == Digest::SHA256.hexdigest(salt + password)
+			return true
+		else
+			return false
+		end
+	end
+
+	# Get message to client
+	# @args: client -> client connection
+	# @rtrn: array of the json string, or false if isn't json message
+	def getClientMessage(client)
+		begin
+			msg = client.gets
+			return JSON.parse(msg)
+		rescue
+			closeConnection(client)
+			return false
+		end
+	end
+
+	# Close the client connection
+	# @args: client -> client connection
+	def closeConnection(client)
+			client.puts "Closing the connection. Bye!"
+			client.close
+	end
+
+	# Check the config file
+	# @args: file_config -> the configuration file
+	# @rtrn: true if the config file is correct
+	def checkconfig(file_config)
+		begin
+			config    = YAML::load_file(file_config)
+			@host     = config['config']['host']
+			@port     = config['config']['port'].to_i
+			@data_dir = config['config']['data_dir']
+			@timeout  = config['config']['timeout'].to_i
+
+			if @host.empty? || @port <= 0 || @data_dir.empty? 
+				puts I18n.t('server.checkconfig.fail')
+				puts I18n.t('server.checkconfig.empty')
+				return false
+			end
+
+			if !Dir.exist?(@data_dir)
+				puts I18n.t('server.checkconfig.fail')
+				puts I18n.t('server.checkconfig.datadir')
+				return false
+			end
+
+		rescue Exception => e 
+			puts "#{I18n.t('server.checkconfig.fail')}\n#{e}"
+			return false
+		end
+
+		return true
+	end
+
+	# Create a new config file
+	# @args: file_config -> the configuration file
+	# @rtrn: true if le config file is create
+	def setup(file_config)
+		puts I18n.t('server.form.setup.title')
+		puts '--------------------'
+		host     = ask(I18n.t('server.form.setup.host')).to_s
+		port     = ask(I18n.t('server.form.setup.port')).to_s
+		data_dir = ask(I18n.t('server.form.setup.data_dir')).to_s
+		timeout  = ask(I18n.t('server.form.setup.timeout')).to_s
+
+		config = {'config' => {'host'     => host,
+		                       'port'     => port,
+		                       'data_dir' => data_dir,
+		                       'timeout'  => timeout}}
+
+		begin
+			File.open(file_config, 'w') do |file|
+				file << config.to_yaml
+			end
+		rescue Exception => e 
+			puts "#{I18n.t('server.formsetup.not_valid')}\n#{e}"
+			return false
+		end
+
+		return true
+	end
+
+end
diff --git a/lib/Sync.rb b/lib/Sync.rb
new file mode 100644
index 0000000..0c3ed31
--- /dev/null
+++ b/lib/Sync.rb
@@ -0,0 +1,133 @@
+#!/usr/bin/ruby
+# author: nishiki
+# mail: nishiki@yaegashi.fr
+# info: a simple script who manage your passwords
+
+require 'rubygems'
+require 'i18n'
+require 'socket'
+require 'json'
+
+require "#{APP_ROOT}/lib/MPW.rb"
+
+class Sync
+
+	attr_accessor :error_msg
+
+	# Constructor
+	def initialize()
+		@error_msg = nil
+	end
+
+	# Disable the sync
+	def disable()
+		@sync = false
+	end
+
+	# Connect to server
+	# @args: host -> the server host
+	#        port -> ther connection port
+	#        gpg_key -> the gpg key
+	#        password -> the remote password
+	#        suffix -> the suffix file
+	# @rtrn: false if the connection fail
+	def connect(host, port, gpg_key, password, suffix=nil)
+		@gpg_key  = gpg_key
+		@password = password
+		@suffix   = suffix
+
+		begin
+			@socket= TCPSocket.new(host, port)
+			@sync = true
+		rescue Exception => e
+			@error_msg = "#{I18n.t('error.sync.connection')}\n#{e}"
+			@sync = false
+		end
+
+		return @sync
+	end
+
+	# Get data on server
+	# @args: gpg_password -> the gpg password
+	# @rtrn: nil if nothing data or error
+	def get(gpg_password)
+		if !@sync
+			return nil
+		end
+
+		send_msg = {:action      => 'get',
+		            :gpg_key     => @gpg_key,
+		            :password    => @password,
+		            :suffix      => @suffix}
+		
+		@socket.puts send_msg.to_json
+		msg = JSON.parse(@socket.gets)
+
+		case msg['error']
+		when nil, 'file_not_exist'
+			tmp_file = "/tmp/mpw-#{MPW.generatePassword()}.gpg"
+			File.open(tmp_file, 'w') do |file|
+				file << msg['data']
+			end
+			
+			@mpw = MPW.new(tmp_file)
+			if !@mpw.decrypt(gpg_password)
+				return nil
+			end
+
+			File.unlink(tmp_file)
+			
+			return @mpw.search()
+		when 'not_authorized'
+			@error_msg = "#{I18n.t('error.sync.not_authorized')}\n#{e}"
+		else
+			@error_msg = "#{I18n.t('error.sync.unknown')}\n#{e}"
+		end
+
+		return nil
+	end
+
+	# Update the remote data
+	# @args: data -> the data to send on server
+	# @rtrn: false if there is a problem
+	def update(data)
+		if !@sync
+			return true
+		end
+
+		send_msg = {:action      => 'update',
+		            :gpg_key     => @gpg_key,
+		            :password    => @password,
+		            :suffix      => @suffix,
+		            :data        => data}
+		
+		@socket.puts send_msg.to_json
+		msg = JSON.parse(@socket.gets)
+
+		case msg['error']
+		when nil
+			return true
+		when 'not_authorized'
+			@error_msg = "#{I18n.t('error.sync.not_authorized')}\n#{e}"
+		when 'no_data'
+			@error_msg = "#{I18n.t('error.sync.no_data')}\n#{e}"
+		else
+			@error_msg = "#{I18n.t('error.sync.unknown')}\n#{e}"
+		end
+
+		return false
+	end
+
+	def delete()
+	end
+
+	# Close the connection
+	def close()
+		if !@sync
+			return
+		end
+
+		send_msg = {:action => 'close'}
+		@socket.puts send_msg.to_json
+	end
+end
diff --git a/mpw b/mpw
index a313ed7..80f3344 100755
--- a/mpw
+++ b/mpw
@@ -93,13 +93,17 @@ OptionParser.new do |opts|
 	end
 end.parse!
 
+config      = MPWConfig.new(options[:config])
+check_error = config.checkconfig()
 
-cli = Cli.new(lang, options[:config])
+cli = Cli.new(lang, config)
+cli.sync()
+	
+# Setup a new config 
+if !check_error || !options[:setup].nil?
+	cli.setup(lang)
 
 # Display the item's informations
-if not options[:setup].nil?
-	cli.setup()
-
 elsif not options[:display].nil?
 	cli.display(options[:display], options[:group], options[:type], options[:format])
 
@@ -125,7 +129,16 @@ elsif not options[:import].nil?
 
 # Interactive mode
 else
-	cli.interactive
+	begin
+		cli.interactive()
+	rescue SystemExit, Interrupt
+		cli.sync()
+		cli = nil
+		return 1
+	end
 end
 
+cli.sync()
+cli = nil
+
 exit 0
diff --git a/mpw-server b/mpw-server
new file mode 100755
index 0000000..3143b59
--- /dev/null
+++ b/mpw-server
@@ -0,0 +1,60 @@
+#!/usr/bin/ruby
+# author: nishiki
+# mail: nishiki@yaegashi.fr
+# info: a simple script who manage your passwords
+
+require 'rubygems'
+require 'optparse'
+require 'pathname'
+require 'locale'
+require 'i18n'
+
+APP_ROOT = File.dirname(Pathname.new(__FILE__).realpath)
+require "#{APP_ROOT}/lib/Server.rb"
+
+lang = Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1]
+
+I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
+I18n.load_path = Dir["#{APP_ROOT}/i18n/*.yml"]
+I18n.default_locale = :en
+I18n.locale = lang.to_sym
+
+options = {}
+OptionParser.new do |opts|
+	opts.banner = "#{I18n.t('server.option.usage')}: mpw-server -c CONFIG [options]"
+
+	opts.on("-c", "--config CONFIG", I18n.t('server.option.config')) do |config|
+		options[:config] = config
+	end
+
+	opts.on("-t", "--checkconfig", I18n.t('server.option.checkconfig')) do |b|
+		options[:checkconfig] = b
+	end
+
+	opts.on("-s", "--setup", I18n.t('server.option.setup')) do |b|
+		options[:setup] = b
+	end
+
+	opts.on("-h", "--help", I18n.t('server.option.help')) do |b|
+		puts opts
+		exit 0
+	end
+end.parse!
+
+if options[:config].nil? || options[:config].empty?
+	puts "#{I18n.t('server.option.usage')}: mpw-server -c CONFIG [options]"
+	exit 2
+end
+
+server = Server.new
+
+if options[:checkconfig]
+	server.checkconfig(options[:config])
+elsif options[:setup]
+	server.setup(options[:config])
+else
+	server.checkconfig(options[:config])
+	server.start()
+end
+
+exit 0