Browse Source

Merge remote-tracking branch 'origin/dev' into beta

Alexandre Alapetite 12 years ago
parent
commit
7b4451912e

+ 2 - 0
CHANGELOG

@@ -12,6 +12,7 @@
 	* Améliorations partage vers Shaarli, Poche, Diaspora*, Facebook, Twitter, Google+, courriel
 	* Améliorations partage vers Shaarli, Poche, Diaspora*, Facebook, Twitter, Google+, courriel
 	* Permet la suppression de tous les articles d’un flux
 	* Permet la suppression de tous les articles d’un flux
 	* Option pour marquer les articles comme lus dès la réception
 	* Option pour marquer les articles comme lus dès la réception
+	* Permet de configurer plus finement le nombre d’articles minimum à conserver par flux
 	* Permet de modifier la description et l’adresse d’un flux RSS ainsi que le site Web associé
 	* Permet de modifier la description et l’adresse d’un flux RSS ainsi que le site Web associé
 	* Nouveau raccourci pour ouvrir/fermer un article (‘c’ par défaut)
 	* Nouveau raccourci pour ouvrir/fermer un article (‘c’ par défaut)
 	* Bouton pour effacer les logs
 	* Bouton pour effacer les logs
@@ -42,6 +43,7 @@
 * PHP :
 * PHP :
 	* Meilleure gestion des caractères spéciaux dans différents cas
 	* Meilleure gestion des caractères spéciaux dans différents cas
 	* Amélioration des performances
 	* Amélioration des performances
+	* Encore plus tolérant pour les flux comportant des erreurs
 	* Chargement automatique des classes
 	* Chargement automatique des classes
 	* Alternative dans le cas d’absence de librairie JSON
 	* Alternative dans le cas d’absence de librairie JSON
 	* Pour le développement, le cache HTTP peut être désactivé en créant un fichier “./no-cache.txt”
 	* Pour le développement, le cache HTTP peut être désactivé en créant un fichier “./no-cache.txt”

+ 2 - 2
README.md

@@ -2,10 +2,10 @@
 FreshRSS est un agrégateur de flux RSS à auto-héberger à l’image de [Leed](http://projet.idleman.fr/leed/) ou de [Kriss Feed](http://tontof.net/kriss/feed/).
 FreshRSS est un agrégateur de flux RSS à auto-héberger à l’image de [Leed](http://projet.idleman.fr/leed/) ou de [Kriss Feed](http://tontof.net/kriss/feed/).
 Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable.
 Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable.
 
 
-* Site officiel : http://marienfressinaud.github.io/FreshRSS/
+* Site officiel : http://freshrss.org
 * Démo : http://marienfressinaud.fr/projets/freshrss/
 * Démo : http://marienfressinaud.fr/projets/freshrss/
 * Développeur : Marien Fressinaud <dev@marienfressinaud.fr>
 * Développeur : Marien Fressinaud <dev@marienfressinaud.fr>
-* Version actuelle : 0.7-beta
+* Version actuelle : 0.7-beta2
 * Date de publication 2014-01-xx
 * Date de publication 2014-01-xx
 * License [GNU AGPL 3](http://www.gnu.org/licenses/agpl-3.0.html)
 * License [GNU AGPL 3](http://www.gnu.org/licenses/agpl-3.0.html)
 
 

+ 4 - 6
app/Controllers/configureController.php

@@ -97,18 +97,13 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 					$description = sanitizeHTML(Minz_Request::param('description', '', true));
 					$description = sanitizeHTML(Minz_Request::param('description', '', true));
 					$website = Minz_Request::param('website', '');
 					$website = Minz_Request::param('website', '');
 					$url = Minz_Request::param('url', '');
 					$url = Minz_Request::param('url', '');
-					$hist = Minz_Request::param ('keep_history', 'no');
+					$keep_history = intval(Minz_Request::param ('keep_history', -2));
 					$cat = Minz_Request::param ('category', 0);
 					$cat = Minz_Request::param ('category', 0);
 					$path = Minz_Request::param ('path_entries', '');
 					$path = Minz_Request::param ('path_entries', '');
 					$priority = Minz_Request::param ('priority', 0);
 					$priority = Minz_Request::param ('priority', 0);
 					$user = Minz_Request::param ('http_user', '');
 					$user = Minz_Request::param ('http_user', '');
 					$pass = Minz_Request::param ('http_pass', '');
 					$pass = Minz_Request::param ('http_pass', '');
 
 
-					$keep_history = false;
-					if ($hist == 'yes') {
-						$keep_history = true;
-					}
-
 					$httpAuth = '';
 					$httpAuth = '';
 					if ($user != '' || $pass != '') {
 					if ($user != '' || $pass != '') {
 						$httpAuth = $user . ':' . $pass;
 						$httpAuth = $user . ':' . $pass;
@@ -165,6 +160,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 			$lazyload = Minz_Request::param ('lazyload', 'no');
 			$lazyload = Minz_Request::param ('lazyload', 'no');
 			$sort = Minz_Request::param ('sort_order', 'DESC');
 			$sort = Minz_Request::param ('sort_order', 'DESC');
 			$old = Minz_Request::param ('old_entries', 3);
 			$old = Minz_Request::param ('old_entries', 3);
+			$keepHistoryDefault = Minz_Request::param('keep_history_default', 0);
 			$mail = Minz_Request::param ('mail_login', false);
 			$mail = Minz_Request::param ('mail_login', false);
 			$anon = Minz_Request::param ('anon_access', 'no');
 			$anon = Minz_Request::param ('anon_access', 'no');
 			$token = Minz_Request::param ('token', $current_token);
 			$token = Minz_Request::param ('token', $current_token);
@@ -194,6 +190,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 			$this->view->conf->_lazyload ($lazyload);
 			$this->view->conf->_lazyload ($lazyload);
 			$this->view->conf->_sortOrder ($sort);
 			$this->view->conf->_sortOrder ($sort);
 			$this->view->conf->_oldEntries ($old);
 			$this->view->conf->_oldEntries ($old);
+			$this->view->conf->_keepHistoryDefault($keepHistoryDefault);
 			$this->view->conf->_mailLogin ($mail);
 			$this->view->conf->_mailLogin ($mail);
 			$this->view->conf->_anonAccess ($anon);
 			$this->view->conf->_anonAccess ($anon);
 			$this->view->conf->_token ($token);
 			$this->view->conf->_token ($token);
@@ -226,6 +223,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 				'lazyload' => $this->view->conf->lazyload (),
 				'lazyload' => $this->view->conf->lazyload (),
 				'sort_order' => $this->view->conf->sortOrder (),
 				'sort_order' => $this->view->conf->sortOrder (),
 				'old_entries' => $this->view->conf->oldEntries (),
 				'old_entries' => $this->view->conf->oldEntries (),
+				'keep_history_default' => $this->view->conf->keepHistoryDefault(),
 				'mail_login' => $this->view->conf->mailLogin (),
 				'mail_login' => $this->view->conf->mailLogin (),
 				'anon_access' => $this->view->conf->anonAccess (),
 				'anon_access' => $this->view->conf->anonAccess (),
 				'token' => $this->view->conf->token (),
 				'token' => $this->view->conf->token (),

+ 41 - 0
app/Controllers/entryController.php

@@ -109,4 +109,45 @@ class FreshRSS_entry_Controller extends Minz_ActionController {
 			'a' => 'display'
 			'a' => 'display'
 		), true);
 		), true);
 	}
 	}
+
+	public function purgeAction() {
+		@set_time_limit(300);
+
+		$nb_month_old = max($this->view->conf->oldEntries(), 1);
+		$date_min = time() - (3600 * 24 * 30 * $nb_month_old);
+
+		$feedDAO = new FreshRSS_FeedDAO();
+		$feeds = $feedDAO->listFeedsOrderUpdate();
+		$nbTotal = 0;
+
+		invalidateHttpCache();
+
+		foreach ($feeds as $feed) {
+			$feedHistory = $feed->keepHistory();
+			if ($feedHistory == -2) {	//default
+				$feedHistory = $this->view->conf->keepHistoryDefault();
+			}
+			if ($feedHistory >= 0) {
+				$nb = $feedDAO->cleanOldEntries($feed->id(), $date_min, $feedHistory);
+				if ($nb > 0) {
+					$nbTotal += $nb;
+					Minz_Log::record($nb . ' old entries cleaned in feed ' . $feed->id(), Minz_Log::DEBUG);
+					$feedDAO->updateLastUpdate($feed->id());
+				}
+			}
+		}
+
+		invalidateHttpCache();
+
+		$notif = array(
+			'type' => 'good',
+			'content' => Minz_Translate::t('purge_completed', $nbTotal)
+		);
+		Minz_Session::_param('notification', $notif);
+
+		Minz_Request::forward(array(
+			'c' => 'configure',
+			'a' => 'display'
+		), true);
+	}
 }
 }

+ 14 - 13
app/Controllers/feedController.php

@@ -102,14 +102,11 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
 						$feedDAO->beginTransaction ();
 						$feedDAO->beginTransaction ();
 						// on ajoute les articles en masse sans vérification
 						// on ajoute les articles en masse sans vérification
 						foreach ($entries as $entry) {
 						foreach ($entries as $entry) {
-							if ($entry->date (true) >= $date_min ||
-							    $feed->keepHistory ()) {
-								$values = $entry->toArray ();
-								$values['id_feed'] = $feed->id ();
-								$values['id'] = min(time(), $entry->date (true)) . uSecString();
-								$values['is_read'] = $is_read;
-								$entryDAO->addEntry ($values);
-							}
+							$values = $entry->toArray ();
+							$values['id_feed'] = $feed->id ();
+							$values['id'] = min(time(), $entry->date (true)) . uSecString();
+							$values['is_read'] = $is_read;
+							$entryDAO->addEntry ($values);
 						}
 						}
 						$feedDAO->updateLastUpdate ($feed->id ());
 						$feedDAO->updateLastUpdate ($feed->id ());
 						$feedDAO->commit ();
 						$feedDAO->commit ();
@@ -195,7 +192,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
 		}
 		}
 
 
 		// on calcule la date des articles les plus anciens qu'on accepte
 		// on calcule la date des articles les plus anciens qu'on accepte
-		$nb_month_old = $this->view->conf->oldEntries ();
+		$nb_month_old = max($this->view->conf->oldEntries(), 1);
 		$date_min = time () - (3600 * 24 * 30 * $nb_month_old);
 		$date_min = time () - (3600 * 24 * 30 * $nb_month_old);
 
 
 		$i = 0;
 		$i = 0;
@@ -217,8 +214,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
 				$feedDAO->beginTransaction ();
 				$feedDAO->beginTransaction ();
 				foreach ($entries as $entry) {
 				foreach ($entries as $entry) {
 					if ((!isset ($existingGuids[$entry->guid ()])) &&
 					if ((!isset ($existingGuids[$entry->guid ()])) &&
-						($entry->date (true) >= $date_min ||
-						$feed->keepHistory ())) {
+						($entry->date (true) >= $date_min)) {
 						$values = $entry->toArray ();
 						$values = $entry->toArray ();
 						//Use declared date at first import, otherwise use discovery date
 						//Use declared date at first import, otherwise use discovery date
 						$values['id'] = empty($existingGuids) ? min(time(), $entry->date (true)) . uSecString() : uTimeString();
 						$values['id'] = empty($existingGuids) ? min(time(), $entry->date (true)) . uSecString() : uTimeString();
@@ -227,8 +223,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
 					}
 					}
 				}
 				}
 
 
-				if ((!$feed->keepHistory()) && (rand(0, 30) === 1)) {
-					$nb = $feedDAO->cleanOldEntries ($feed->id (), $date_min, count($entries) + 10);
+				$feedHistory = $feed->keepHistory();
+				if ($feedHistory == -2) {	//default
+					$feedHistory = $this->view->conf->keepHistoryDefault();
+				}
+
+				if (($feedHistory >= 0) && (rand(0, 30) === 1)) {
+					$nb = $feedDAO->cleanOldEntries ($feed->id (), $date_min, max($feedHistory, count($entries) + 10));
 					if ($nb > 0) {
 					if ($nb > 0) {
 						Minz_Log::record ($nb . ' old entries cleaned in feed ' . $feed->id (), Minz_Log::DEBUG);
 						Minz_Log::record ($nb . ' old entries cleaned in feed ' . $feed->id (), Minz_Log::DEBUG);
 					}
 					}

+ 3 - 2
app/Controllers/indexController.php

@@ -130,16 +130,17 @@ class FreshRSS_index_Controller extends Minz_ActionController {
 		// on calcule la date des articles les plus anciens qu'on affiche
 		// on calcule la date des articles les plus anciens qu'on affiche
 		$nb_month_old = $this->view->conf->oldEntries ();
 		$nb_month_old = $this->view->conf->oldEntries ();
 		$date_min = $today - (3600 * 24 * 30 * $nb_month_old);	//Do not use a fast changing value such as time() to allow SQL caching
 		$date_min = $today - (3600 * 24 * 30 * $nb_month_old);	//Do not use a fast changing value such as time() to allow SQL caching
+		$keepHistoryDefault = $this->view->conf->keepHistoryDefault();
 
 
 		try {
 		try {
-			$entries = $this->entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter, $date_min);
+			$entries = $this->entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter, $date_min, $keepHistoryDefault);
 
 
 			// Si on a récupéré aucun article "non lus"
 			// Si on a récupéré aucun article "non lus"
 			// on essaye de récupérer tous les articles
 			// on essaye de récupérer tous les articles
 			if ($state === 'not_read' && empty($entries)) {	//TODO: Remove in v0.8
 			if ($state === 'not_read' && empty($entries)) {	//TODO: Remove in v0.8
 				Minz_Log::record ('Conflicting information about nbNotRead!', Minz_Log::DEBUG);
 				Minz_Log::record ('Conflicting information about nbNotRead!', Minz_Log::DEBUG);
 				$this->view->state = 'all';
 				$this->view->state = 'all';
-				$entries = $this->entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min);
+				$entries = $this->entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min, $keepHistoryDefault);
 			}
 			}
 
 
 			if (count($entries) <= $nb) {
 			if (count($entries) <= $nb) {

+ 13 - 1
app/Models/Configuration.php

@@ -14,6 +14,7 @@ class FreshRSS_Configuration extends Minz_Model {
 	private $lazyload;
 	private $lazyload;
 	private $sort_order;
 	private $sort_order;
 	private $old_entries;
 	private $old_entries;
+	private $keep_history_default;
 	private $shortcuts = array ();
 	private $shortcuts = array ();
 	private $mail_login = '';
 	private $mail_login = '';
 	private $mark_when = array ();
 	private $mark_when = array ();
@@ -44,6 +45,7 @@ class FreshRSS_Configuration extends Minz_Model {
 		$this->_lazyload ($confDAO->lazyload);
 		$this->_lazyload ($confDAO->lazyload);
 		$this->_sortOrder ($confDAO->sort_order);
 		$this->_sortOrder ($confDAO->sort_order);
 		$this->_oldEntries ($confDAO->old_entries);
 		$this->_oldEntries ($confDAO->old_entries);
+		$this->_keepHistoryDefault($confDAO->keep_history_default);
 		$this->_shortcuts ($confDAO->shortcuts);
 		$this->_shortcuts ($confDAO->shortcuts);
 		$this->_mailLogin ($confDAO->mail_login);
 		$this->_mailLogin ($confDAO->mail_login);
 		$this->_markWhen ($confDAO->mark_when);
 		$this->_markWhen ($confDAO->mark_when);
@@ -95,6 +97,9 @@ class FreshRSS_Configuration extends Minz_Model {
 	public function oldEntries () {
 	public function oldEntries () {
 		return $this->old_entries;
 		return $this->old_entries;
 	}
 	}
+	public function keepHistoryDefault() {
+		return $this->keep_history_default;
+	}
 	public function shortcuts () {
 	public function shortcuts () {
 		return $this->shortcuts;
 		return $this->shortcuts;
 	}
 	}
@@ -217,11 +222,18 @@ class FreshRSS_Configuration extends Minz_Model {
 	}
 	}
 	public function _oldEntries ($value) {
 	public function _oldEntries ($value) {
 		if (ctype_digit ($value) && $value > 0) {
 		if (ctype_digit ($value) && $value > 0) {
-			$this->old_entries = $value;
+			$this->old_entries = intval($value);
 		} else {
 		} else {
 			$this->old_entries = 3;
 			$this->old_entries = 3;
 		}
 		}
 	}
 	}
+	public function _keepHistoryDefault($value) {
+		if (ctype_digit($value) && $value >= -1) {
+			$this->keep_history_default = intval($value);
+		} else {
+			$this->keep_history_default = 0;
+		}
+	}
 	public function _shortcuts ($values) {
 	public function _shortcuts ($values) {
 		foreach ($values as $key => $value) {
 		foreach ($values as $key => $value) {
 			$this->shortcuts[$key] = $value;
 			$this->shortcuts[$key] = $value;

+ 6 - 2
app/Models/ConfigurationDAO.php

@@ -10,6 +10,7 @@ class FreshRSS_ConfigurationDAO extends Minz_ModelArray {
 	public $lazyload = 'yes';
 	public $lazyload = 'yes';
 	public $sort_order = 'DESC';
 	public $sort_order = 'DESC';
 	public $old_entries = 3;
 	public $old_entries = 3;
+	public $keep_history_default = 0;
 	public $shortcuts = array (
 	public $shortcuts = array (
 		'mark_read' => 'r',
 		'mark_read' => 'r',
 		'mark_favorite' => 'f',
 		'mark_favorite' => 'f',
@@ -62,7 +63,7 @@ class FreshRSS_ConfigurationDAO extends Minz_ModelArray {
 			$this->language = $this->array['language'];
 			$this->language = $this->array['language'];
 		}
 		}
 		if (isset ($this->array['posts_per_page'])) {
 		if (isset ($this->array['posts_per_page'])) {
-			$this->posts_per_page = $this->array['posts_per_page'];
+			$this->posts_per_page = intval($this->array['posts_per_page']);
 		}
 		}
 		if (isset ($this->array['view_mode'])) {
 		if (isset ($this->array['view_mode'])) {
 			$this->view_mode = $this->array['view_mode'];
 			$this->view_mode = $this->array['view_mode'];
@@ -83,7 +84,10 @@ class FreshRSS_ConfigurationDAO extends Minz_ModelArray {
 			$this->sort_order = $this->array['sort_order'];
 			$this->sort_order = $this->array['sort_order'];
 		}
 		}
 		if (isset ($this->array['old_entries'])) {
 		if (isset ($this->array['old_entries'])) {
-			$this->old_entries = $this->array['old_entries'];
+			$this->old_entries = intval($this->array['old_entries']);
+		}
+		if (isset ($this->array['keep_history_default'])) {
+			$this->keep_history_default = intval($this->array['keep_history_default']);
 		}
 		}
 		if (isset ($this->array['shortcuts'])) {
 		if (isset ($this->array['shortcuts'])) {
 			$this->shortcuts = array_merge (
 			$this->shortcuts = array_merge (

+ 6 - 2
app/Models/EntryDAO.php

@@ -260,7 +260,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
 		return isset ($entries[0]) ? $entries[0] : false;
 		return isset ($entries[0]) ? $entries[0] : false;
 	}
 	}
 
 
-	public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) {
+	public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $keepHistoryDefault = 0) {
 		$where = '';
 		$where = '';
 		$joinFeed = false;
 		$joinFeed = false;
 		$values = array();
 		$values = array();
@@ -307,7 +307,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
 			$where .= 'AND e1.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' ';
 			$where .= 'AND e1.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' ';
 		}
 		}
 		if (($date_min > 0) && ($type !== 's')) {
 		if (($date_min > 0) && ($type !== 's')) {
-			$where .= 'AND (e1.id >= ' . $date_min . '000000 OR e1.is_favorite = 1 OR f.keep_history = 1) ';
+			$where .= 'AND (e1.id >= ' . $date_min . '000000 OR e1.is_read = 0 OR e1.is_favorite = 1 OR (f.keep_history <> 0';
+			if (intval($keepHistoryDefault) === 0) {
+				$where .= ' AND f.keep_history <> -2';	//default
+			}
+			$where .= ')) ';
 			$joinFeed = true;
 			$joinFeed = true;
 		}
 		}
 		$search = '';
 		$search = '';

+ 8 - 15
app/Models/Feed.php

@@ -15,7 +15,7 @@ class FreshRSS_Feed extends Minz_Model {
 	private $pathEntries = '';
 	private $pathEntries = '';
 	private $httpAuth = '';
 	private $httpAuth = '';
 	private $error = false;
 	private $error = false;
-	private $keep_history = false;
+	private $keep_history = -2;
 
 
 	public function __construct ($url, $validate=true) {
 	public function __construct ($url, $validate=true) {
 		if ($validate) {
 		if ($validate) {
@@ -163,19 +163,12 @@ class FreshRSS_Feed extends Minz_Model {
 		$this->httpAuth = $value;
 		$this->httpAuth = $value;
 	}
 	}
 	public function _error ($value) {
 	public function _error ($value) {
-		if ($value) {
-			$value = true;
-		} else {
-			$value = false;
-		}
-		$this->error = $value;
+		$this->error = (bool)$value;
 	}
 	}
 	public function _keepHistory ($value) {
 	public function _keepHistory ($value) {
-		if ($value) {
-			$value = true;
-		} else {
-			$value = false;
-		}
+		$value = intval($value);
+		$value = min($value, 1000000);
+		$value = max($value, -2);
 		$this->keep_history = $value;
 		$this->keep_history = $value;
 	}
 	}
 	public function _nbNotRead ($value) {
 	public function _nbNotRead ($value) {
@@ -257,11 +250,11 @@ class FreshRSS_Feed extends Minz_Model {
 					$this->_url ($subscribe_url);
 					$this->_url ($subscribe_url);
 				}
 				}
 
 
-				$title = $feed->get_title ();
+				$title = htmlspecialchars(html_only_entity_decode($feed->get_title()), ENT_COMPAT, 'UTF-8');
 				$this->_name (!is_null ($title) ? $title : $this->url);
 				$this->_name (!is_null ($title) ? $title : $this->url);
 
 
-				$this->_website ($feed->get_link ());
-				$this->_description ($feed->get_description ());
+				$this->_website(html_only_entity_decode($feed->get_link()));
+				$this->_description(html_only_entity_decode($feed->get_description()));
 
 
 				// et on charge les articles du flux
 				// et on charge les articles du flux
 				$this->loadEntries ($feed);
 				$this->loadEntries ($feed);

+ 18 - 15
app/Models/FeedDAO.php

@@ -2,7 +2,7 @@
 
 
 class FreshRSS_FeedDAO extends Minz_ModelPdo {
 class FreshRSS_FeedDAO extends Minz_ModelPdo {
 	public function addFeed ($valuesTmp) {
 	public function addFeed ($valuesTmp) {
-		$sql = 'INSERT INTO `' . $this->prefix . 'feed` (url, category, name, website, description, lastUpdate, priority, httpAuth, error, keep_history) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, 0)';
+		$sql = 'INSERT INTO `' . $this->prefix . 'feed` (url, category, name, website, description, lastUpdate, priority, httpAuth, error, keep_history) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, -2)';
 		$stm = $this->bd->prepare ($sql);
 		$stm = $this->bd->prepare ($sql);
 
 
 		$values = array (
 		$values = array (
@@ -193,7 +193,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
 	}
 	}
 
 
 	public function listFeedsOrderUpdate () {
 	public function listFeedsOrderUpdate () {
-		$sql = 'SELECT * FROM `' . $this->prefix . 'feed` ORDER BY lastUpdate';
+		$sql = 'SELECT id, name, url, pathEntries, httpAuth, keep_history FROM `' . $this->prefix . 'feed` ORDER BY lastUpdate';
 		$stm = $this->bd->prepare ($sql);
 		$stm = $this->bd->prepare ($sql);
 		$stm->execute ();
 		$stm->execute ();
 
 
@@ -315,20 +315,23 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
 			if (isset ($dao['id'])) {
 			if (isset ($dao['id'])) {
 				$key = $dao['id'];
 				$key = $dao['id'];
 			}
 			}
+			if ($catID === null) {
+				$catID = isset($dao['category']) ? $dao['category'] : 0;
+			}
 
 
-			$myFeed = new FreshRSS_Feed (isset($dao['url']) ? $dao['url'] : '', false);
-			$myFeed->_category ($catID === null ? $dao['category'] : $catID);
-			$myFeed->_name ($dao['name']);
-			$myFeed->_website ($dao['website'], false);
-			$myFeed->_description (isset($dao['description']) ? $dao['description'] : '');
-			$myFeed->_lastUpdate (isset($dao['lastUpdate']) ? $dao['lastUpdate'] : 0);
-			$myFeed->_priority ($dao['priority']);
-			$myFeed->_pathEntries (isset($dao['pathEntries']) ? $dao['pathEntries'] : '');
-			$myFeed->_httpAuth (isset($dao['httpAuth']) ? base64_decode ($dao['httpAuth']) : '');
-			$myFeed->_error ($dao['error']);
-			$myFeed->_keepHistory (isset($dao['keep_history']) ? $dao['keep_history'] : '');
-			$myFeed->_nbNotRead ($dao['cache_nbUnreads']);
-			$myFeed->_nbEntries ($dao['cache_nbEntries']);
+			$myFeed = new FreshRSS_Feed(isset($dao['url']) ? $dao['url'] : '', false);
+			$myFeed->_category(intval($catID));
+			$myFeed->_name($dao['name']);
+			$myFeed->_website(isset($dao['website']) ? $dao['website'] : '', false);
+			$myFeed->_description(isset($dao['description']) ? $dao['description'] : '');
+			$myFeed->_lastUpdate(isset($dao['lastUpdate']) ? $dao['lastUpdate'] : 0);
+			$myFeed->_priority(isset($dao['priority']) ? $dao['priority'] : 10);
+			$myFeed->_pathEntries(isset($dao['pathEntries']) ? $dao['pathEntries'] : '');
+			$myFeed->_httpAuth(isset($dao['httpAuth']) ? base64_decode ($dao['httpAuth']) : '');
+			$myFeed->_error(isset($dao['error']) ? $dao['error'] : 0);
+			$myFeed->_keepHistory(isset($dao['keep_history']) ? $dao['keep_history'] : -2);
+			$myFeed->_nbNotRead(isset($dao['cache_nbUnreads']) ? $dao['cache_nbUnreads'] : 0);
+			$myFeed->_nbEntries(isset($dao['cache_nbEntries']) ? $dao['cache_nbEntries'] : 0);
 			if (isset ($dao['id'])) {
 			if (isset ($dao['id'])) {
 				$myFeed->_id ($dao['id']);
 				$myFeed->_id ($dao['id']);
 			}
 			}

+ 10 - 3
app/i18n/en.php

@@ -137,7 +137,9 @@ return array (
 	'feed_url'			=> 'Feed URL',
 	'feed_url'			=> 'Feed URL',
 	'articles'			=> 'articles',
 	'articles'			=> 'articles',
 	'number_articles'		=> 'Number of articles',
 	'number_articles'		=> 'Number of articles',
-	'keep_history'			=> 'Keep old articles?',
+	'by_feed'			=> 'by feed',
+	'by_default'		=> 'By default',
+	'keep_history'			=> 'Minimum number of articles to keep',
 	'categorize'			=> 'Store in a category',
 	'categorize'			=> 'Store in a category',
 	'truncate'			=> 'Delete all articles',
 	'truncate'			=> 'Delete all articles',
 	'advanced'			=> 'Advanced',
 	'advanced'			=> 'Advanced',
@@ -157,14 +159,19 @@ return array (
 
 
 	'general_configuration'		=> 'General configuration',
 	'general_configuration'		=> 'General configuration',
 	'language'			=> 'Language',
 	'language'			=> 'Language',
-	'delete_articles_every'		=> 'Remove articles after',
 	'month'				=> 'months',
 	'month'				=> 'months',
 	'default_user'			=> 'Username of the default user (maximum 16 alphanumeric characters)',
 	'default_user'			=> 'Username of the default user (maximum 16 alphanumeric characters)',
 	'persona_connection_email'	=> 'Login mail address (use <a href="https://persona.org/">Mozilla Persona</a>)',
 	'persona_connection_email'	=> 'Login mail address (use <a href="https://persona.org/">Mozilla Persona</a>)',
 	'allow_anonymous'		=> 'Allow anonymous reading',
 	'allow_anonymous'		=> 'Allow anonymous reading',
 	'auth_token'			=> 'Authentication token',
 	'auth_token'			=> 'Authentication token',
 	'explain_token'			=> 'Allows to access RSS output without authentication.<br />%s?token=%s',
 	'explain_token'			=> 'Allows to access RSS output without authentication.<br />%s?token=%s',
-	'reading_configuration'		=> 'Reading configuration',
+	'login_configuration'	=> 'Login',
+	'archiving_configuration'	=> 'Archiving',
+	'delete_articles_every'	=> 'Remove articles after',
+	'purge_now'			=> 'Purge now',
+	'purge_completed'		=> 'Purge completed (%d articles deleted)',
+	'archiving_configuration_help'	=> 'More options are available in the individual stream settings',
+	'reading_configuration'		=> 'Reading',
 	'articles_per_page'		=> 'Number of articles per page',
 	'articles_per_page'		=> 'Number of articles per page',
 	'default_view'			=> 'Default view',
 	'default_view'			=> 'Default view',
 	'sort_order'			=> 'Sort order',
 	'sort_order'			=> 'Sort order',

+ 11 - 3
app/i18n/fr.php

@@ -137,7 +137,9 @@ return array (
 	'feed_url'			=> 'URL du flux',
 	'feed_url'			=> 'URL du flux',
 	'articles'			=> 'articles',
 	'articles'			=> 'articles',
 	'number_articles'		=> 'Nombre d’articles',
 	'number_articles'		=> 'Nombre d’articles',
-	'keep_history'			=> 'Garder les vieux articles ?',
+	'by_feed'			=> 'par flux',
+	'by_default'		=> 'Par défaut',
+	'keep_history'			=> 'Nombre minimum d’articles à conserver',
 	'categorize'			=> 'Ranger dans une catégorie',
 	'categorize'			=> 'Ranger dans une catégorie',
 	'truncate'			=> 'Supprimer tous les articles',
 	'truncate'			=> 'Supprimer tous les articles',
 	'advanced'			=> 'Avancé',
 	'advanced'			=> 'Avancé',
@@ -157,14 +159,20 @@ return array (
 
 
 	'general_configuration'		=> 'Configuration générale',
 	'general_configuration'		=> 'Configuration générale',
 	'language'			=> 'Langue',
 	'language'			=> 'Langue',
-	'delete_articles_every'		=> 'Supprimer les articles après',
+	
 	'month'				=> 'mois',
 	'month'				=> 'mois',
 	'default_user'			=> 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)',
 	'default_user'			=> 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)',
 	'persona_connection_email'	=> 'Adresse courriel de connexion (utilise <a href="https://persona.org/">Mozilla Persona</a>)',
 	'persona_connection_email'	=> 'Adresse courriel de connexion (utilise <a href="https://persona.org/">Mozilla Persona</a>)',
 	'allow_anonymous'		=> 'Autoriser la lecture anonyme',
 	'allow_anonymous'		=> 'Autoriser la lecture anonyme',
 	'auth_token'			=> 'Jeton d’identification',
 	'auth_token'			=> 'Jeton d’identification',
 	'explain_token'			=> 'Permet d’accéder à la sortie RSS sans besoin de s’authentifier.<br />%s?output=rss&token=%s',
 	'explain_token'			=> 'Permet d’accéder à la sortie RSS sans besoin de s’authentifier.<br />%s?output=rss&token=%s',
-	'reading_configuration'		=> 'Configuration de lecture',
+	'login_configuration'	=> 'Identification',
+	'archiving_configuration'	=> 'Archivage',
+	'delete_articles_every'	=> 'Supprimer les articles après',
+	'purge_now'			=> 'Purger maintenant',
+	'purge_completed'		=> 'Purge effectuée (%d articles supprimés)',
+	'archiving_configuration_help'	=> 'D’autres options sont disponibles dans la configuration individuelle des flux',
+	'reading_configuration'		=> 'Lecture',
 	'articles_per_page'		=> 'Nombre d’articles par page',
 	'articles_per_page'		=> 'Nombre d’articles par page',
 	'default_view'			=> 'Vue par défaut',
 	'default_view'			=> 'Vue par défaut',
 	'sort_order'			=> 'Ordre de tri',
 	'sort_order'			=> 'Ordre de tri',

+ 56 - 12
app/views/configure/display.phtml

@@ -31,13 +31,15 @@
 			</div>
 			</div>
 		</div>
 		</div>
 
 
-		<div class="form-group">
-			<label class="group-name" for="old_entries"><?php echo Minz_Translate::t ('delete_articles_every'); ?></label>
+		<div class="form-group form-actions">
 			<div class="group-controls">
 			<div class="group-controls">
-				<input type="number" id="old_entries" name="old_entries" value="<?php echo $this->conf->oldEntries (); ?>" /> <?php echo Minz_Translate::t ('month'); ?>
+				<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
+				<button type="reset" class="btn"><?php echo Minz_Translate::t ('cancel'); ?></button>
 			</div>
 			</div>
 		</div>
 		</div>
 
 
+		<legend><?php echo Minz_Translate::t ('login_configuration'); ?></legend>
+
 		<div class="form-group">
 		<div class="form-group">
 			<label class="group-name" for="mail_login"><?php echo Minz_Translate::t ('persona_connection_email'); ?></label>
 			<label class="group-name" for="mail_login"><?php echo Minz_Translate::t ('persona_connection_email'); ?></label>
 			<?php $mail = $this->conf->mailLogin (); ?>
 			<?php $mail = $this->conf->mailLogin (); ?>
@@ -59,7 +61,42 @@
 				<?php echo FreshRSS_Themes::icon('help'); ?> <?php echo Minz_Translate::t('explain_token', Minz_Url::display(null, 'html', true), $token); ?>
 				<?php echo FreshRSS_Themes::icon('help'); ?> <?php echo Minz_Translate::t('explain_token', Minz_Url::display(null, 'html', true), $token); ?>
 			</div>
 			</div>
 		</div>
 		</div>
-	
+
+		<div class="form-group form-actions">
+			<div class="group-controls">
+				<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
+				<button type="reset" class="btn"><?php echo Minz_Translate::t ('cancel'); ?></button>
+			</div>
+		</div>
+
+		<legend><?php echo Minz_Translate::t ('archiving_configuration'); ?></legend>
+		<p><?php echo FreshRSS_Themes::icon('help'); ?> <?php echo Minz_Translate::t('archiving_configuration_help'); ?></p>
+		
+		<div class="form-group">
+			<label class="group-name" for="old_entries"><?php echo Minz_Translate::t ('delete_articles_every'); ?></label>
+			<div class="group-controls">
+				<input type="number" id="old_entries" name="old_entries" min="1" max="1200" value="<?php echo $this->conf->oldEntries (); ?>" /> <?php echo Minz_Translate::t ('month'); ?>
+				  <a class="btn confirm" href="<?php echo _url('entry', 'purge'); ?>"><?php echo Minz_Translate::t('purge_now'); ?></a>
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="group-name" for="keep_history_default"><?php echo Minz_Translate::t('keep_history'), ' ', Minz_Translate::t('by_feed'); ?> (<?php echo Minz_Translate::t('by_default'); ?>)</label>
+			<div class="group-controls">
+				<select class="number" name="keep_history_default" id="keep_history_default"><?php
+					foreach (array(-3 => '', 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', -1 => '∞') as $v => $t) {
+						echo '<option value="' . $v . ($this->conf->keepHistoryDefault() == $v ? '" selected="selected' : '') . '">' . $t . ' </option>';
+					}
+				?></select>
+			</div>
+		</div>
+
+		<div class="form-group form-actions">
+			<div class="group-controls">
+				<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
+				<button type="reset" class="btn"><?php echo Minz_Translate::t ('cancel'); ?></button>
+			</div>
+		</div>
+
 		<legend><?php echo Minz_Translate::t ('reading_configuration'); ?></legend>
 		<legend><?php echo Minz_Translate::t ('reading_configuration'); ?></legend>
 
 
 		<div class="form-group">
 		<div class="form-group">
@@ -160,6 +197,13 @@
 			</div>
 			</div>
 		</div>
 		</div>
 
 
+		<div class="form-group form-actions">
+			<div class="group-controls">
+				<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
+				<button type="reset" class="btn"><?php echo Minz_Translate::t ('cancel'); ?></button>
+			</div>
+		</div>
+
 		<legend><?php echo Minz_Translate::t ('reading_icons'); ?></legend>
 		<legend><?php echo Minz_Translate::t ('reading_icons'); ?></legend>
 		<div class="form-group">
 		<div class="form-group">
 			<table>
 			<table>
@@ -193,7 +237,14 @@
 						<td><input type="checkbox" name="bottomline_link" value="yes"<?php echo $this->conf->bottomlineLink () ? ' checked="checked"' : ''; ?> /></td>
 						<td><input type="checkbox" name="bottomline_link" value="yes"<?php echo $this->conf->bottomlineLink () ? ' checked="checked"' : ''; ?> /></td>
 					</tr>
 					</tr>
 				</tbody>
 				</tbody>
-			</table>
+			</table><br />
+		</div>
+
+		<div class="form-group form-actions">
+			<div class="group-controls">
+				<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
+				<button type="reset" class="btn"><?php echo Minz_Translate::t ('cancel'); ?></button>
+			</div>
 		</div>
 		</div>
 
 
 		<legend><?php echo Minz_Translate::t ('advanced'); ?></legend>
 		<legend><?php echo Minz_Translate::t ('advanced'); ?></legend>
@@ -207,12 +258,5 @@
 				<?php echo FreshRSS_Themes::icon('help'); ?> <?php echo Minz_Translate::t('optimize_todo_sometimes'); ?>
 				<?php echo FreshRSS_Themes::icon('help'); ?> <?php echo Minz_Translate::t('optimize_todo_sometimes'); ?>
 			</div>
 			</div>
 		</div>
 		</div>
-
-		<div class="form-group form-actions">
-			<div class="group-controls">
-				<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
-				<button type="reset" class="btn"><?php echo Minz_Translate::t ('cancel'); ?></button>
-			</div>
-		</div>
 	</form>
 	</form>
 </div>
 </div>

+ 45 - 23
app/views/configure/feed.phtml

@@ -52,6 +52,24 @@
 				</select>
 				</select>
 			</div>
 			</div>
 		</div>
 		</div>
+		<div class="form-group">
+			<label class="group-name" for="priority"><?php echo Minz_Translate::t ('show_in_all_flux'); ?></label>
+			<div class="group-controls">
+				<label class="checkbox" for="priority">
+					<input type="checkbox" name="priority" id="priority" value="10"<?php echo $this->flux->priority () > 0 ? ' checked="checked"' : ''; ?> />
+					<?php echo Minz_Translate::t ('yes'); ?>
+				</label>
+			</div>
+		</div>
+		<div class="form-group form-actions">
+			<div class="group-controls">
+				<button class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
+				<button class="btn btn-attention confirm" formmethod="post" formaction="<?php echo Minz_Url::display (array ('c' => 'feed', 'a' => 'delete', 'params' => array ('id' => $this->flux->id ()))); ?>"><?php echo Minz_Translate::t ('delete'); ?></button>
+			</div>
+		</div>
+
+		<legend><?php echo Minz_Translate::t ('archiving_configuration'); ?></legend>
+
 		<div class="form-group">
 		<div class="form-group">
 			<label class="group-name"></label>
 			<label class="group-name"></label>
 			<div class="group-controls">
 			<div class="group-controls">
@@ -64,37 +82,26 @@
 			<label class="group-name"><?php echo Minz_Translate::t ('number_articles'); ?></label>
 			<label class="group-name"><?php echo Minz_Translate::t ('number_articles'); ?></label>
 			<div class="group-controls">
 			<div class="group-controls">
 				<span class="control"><?php echo $this->flux->nbEntries (); ?></span>
 				<span class="control"><?php echo $this->flux->nbEntries (); ?></span>
-				<label class="checkbox" for="keep_history">
-					<input type="checkbox" name="keep_history" id="keep_history" value="yes"<?php echo $this->flux->keepHistory () == 'yes' ? ' checked="checked"' : ''; ?> />
-					<?php echo Minz_Translate::t ('keep_history'); ?>
-				</label>
 			</div>
 			</div>
 		</div>
 		</div>
 		<div class="form-group">
 		<div class="form-group">
-			<label class="group-name"></label>
+			<label class="group-name" for="keep_history"><?php echo Minz_Translate::t ('keep_history'); ?></label>
 			<div class="group-controls">
 			<div class="group-controls">
-				<button class="btn btn-attention confirm" formmethod="post" formaction="<?php echo Minz_Url::display (array ('c' => 'feed', 'a' => 'truncate', 'params' => array ('id' => $this->flux->id ()))); ?>"><?php echo Minz_Translate::t ('truncate'); ?></button>
+				<select class="number" name="keep_history" id="keep_history"><?php
+					foreach (array(-3 => '', -2 => Minz_Translate::t('by_default'), 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', -1 => '∞') as $v => $t) {
+						echo '<option value="' . $v . ($this->flux->keepHistory() === $v ? '" selected="selected' : '') . '">' . $t . '</option>';
+					}
+				?></select>
 			</div>
 			</div>
 		</div>
 		</div>
-
-		<legend><?php echo Minz_Translate::t ('advanced'); ?></legend>
-		<div class="form-group">
-			<label class="group-name" for="priority"><?php echo Minz_Translate::t ('show_in_all_flux'); ?></label>
-			<div class="group-controls">
-				<label class="checkbox" for="priority">
-					<input type="checkbox" name="priority" id="priority" value="10"<?php echo $this->flux->priority () > 0 ? ' checked="checked"' : ''; ?> />
-					<?php echo Minz_Translate::t ('yes'); ?>
-				</label>
-			</div>
-		</div>
-		<div class="form-group">
-			<label class="group-name" for="path_entries"><?php echo Minz_Translate::t ('css_path_on_website'); ?></label>
+		<div class="form-group form-actions">
 			<div class="group-controls">
 			<div class="group-controls">
-				<input type="text" name="path_entries" id="path_entries" value="<?php echo $this->flux->pathEntries (); ?>" placeholder="<?php echo Minz_Translate::t ('blank_to_disable'); ?>" />
-				<?php echo FreshRSS_Themes::icon('help'); ?> <?php echo Minz_Translate::t ('retrieve_truncated_feeds'); ?>
+				<button class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
+				<button class="btn btn-attention confirm" formmethod="post" formaction="<?php echo Minz_Url::display (array ('c' => 'feed', 'a' => 'truncate', 'params' => array ('id' => $this->flux->id ()))); ?>"><?php echo Minz_Translate::t ('truncate'); ?></button>
 			</div>
 			</div>
 		</div>
 		</div>
 
 
+		<legend><?php echo Minz_Translate::t ('login_configuration'); ?></legend>
 		<?php $auth = $this->flux->httpAuth (false); ?>
 		<?php $auth = $this->flux->httpAuth (false); ?>
 		<div class="form-group">
 		<div class="form-group">
 			<label class="group-name" for="http_user"><?php echo Minz_Translate::t ('http_username'); ?></label>
 			<label class="group-name" for="http_user"><?php echo Minz_Translate::t ('http_username'); ?></label>
@@ -109,11 +116,26 @@
 			</div>
 			</div>
 		</div>
 		</div>
 
 
+		<div class="form-group form-actions">
+			<div class="group-controls">
+				<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
+				<button type="reset" class="btn"><?php echo Minz_Translate::t ('cancel'); ?></button>
+			</div>
+		</div>
+
+		<legend><?php echo Minz_Translate::t ('advanced'); ?></legend>
+		<div class="form-group">
+			<label class="group-name" for="path_entries"><?php echo Minz_Translate::t ('css_path_on_website'); ?></label>
+			<div class="group-controls">
+				<input type="text" name="path_entries" id="path_entries" value="<?php echo $this->flux->pathEntries (); ?>" placeholder="<?php echo Minz_Translate::t ('blank_to_disable'); ?>" />
+				<?php echo FreshRSS_Themes::icon('help'); ?> <?php echo Minz_Translate::t ('retrieve_truncated_feeds'); ?>
+			</div>
+		</div>
 
 
 		<div class="form-group form-actions">
 		<div class="form-group form-actions">
 			<div class="group-controls">
 			<div class="group-controls">
-				<button class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
-				<button class="btn btn-attention confirm" formmethod="post" formaction="<?php echo Minz_Url::display (array ('c' => 'feed', 'a' => 'delete', 'params' => array ('id' => $this->flux->id ()))); ?>"><?php echo Minz_Translate::t ('delete'); ?></button>
+				<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
+				<button type="reset" class="btn"><?php echo Minz_Translate::t ('cancel'); ?></button>
 			</div>
 			</div>
 		</div>
 		</div>
 	</form>
 	</form>

+ 3 - 2
constants.php

@@ -1,9 +1,10 @@
 <?php
 <?php
-define('FRESHRSS_VERSION', '0.7-beta');
+define('FRESHRSS_VERSION', '0.7-beta2');
 define('FRESHRSS_WEBSITE', 'http://freshrss.org');
 define('FRESHRSS_WEBSITE', 'http://freshrss.org');
 
 
 // Constantes de chemins
 // Constantes de chemins
-define ('FRESHRSS_PATH', realpath (dirname (__FILE__)));
+define ('FRESHRSS_PATH', dirname(__FILE__));
+
 define ('PUBLIC_PATH', FRESHRSS_PATH . '/public');
 define ('PUBLIC_PATH', FRESHRSS_PATH . '/public');
 define ('DATA_PATH', FRESHRSS_PATH . '/data');
 define ('DATA_PATH', FRESHRSS_PATH . '/data');
 define ('LIB_PATH', FRESHRSS_PATH . '/lib');
 define ('LIB_PATH', FRESHRSS_PATH . '/lib');

+ 7 - 6
lib/SimplePie/SimplePie.php

@@ -1313,7 +1313,7 @@ class SimplePie
 		// First check to see if input has been overridden.
 		// First check to see if input has been overridden.
 		if ($this->input_encoding !== false)
 		if ($this->input_encoding !== false)
 		{
 		{
-			$encodings[] = $this->input_encoding;
+			$encodings[] = strtoupper($this->input_encoding);
 		}
 		}
 
 
 		$application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
 		$application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
@@ -1330,18 +1330,18 @@ class SimplePie
 				}
 				}
 				else
 				else
 				{
 				{
-					$encodings[] = '';	//Let the DOM parser decide first
+					$encodings[] = '';	//FreshRSS: Let the DOM parser decide first
 				}
 				}
 			}
 			}
 			elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
 			elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
 			{
 			{
 				if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
 				if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
 				{
 				{
-					$encodings[] = $charset[1];
+					$encodings[] = strtoupper($charset[1]);
 				}
 				}
 				else
 				else
 				{
 				{
-					$encodings[] = '';
+					$encodings[] = '';	//FreshRSS: Let the DOM parser decide first
 				}
 				}
 				$encodings[] = 'US-ASCII';
 				$encodings[] = 'US-ASCII';
 			}
 			}
@@ -1364,13 +1364,14 @@ class SimplePie
 		foreach ($encodings as $encoding)
 		foreach ($encodings as $encoding)
 		{
 		{
 			// Change the encoding to UTF-8 (as we always use UTF-8 internally)
 			// Change the encoding to UTF-8 (as we always use UTF-8 internally)
-			if ($utf8_data = (empty($encoding) || $encoding === 'UTF-8') ? $this->raw_data : $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
+			if ($utf8_data = (empty($encoding) || $encoding === 'UTF-8') ? $this->raw_data :	//FreshRSS
+				$this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
 			{
 			{
 				// Create new parser
 				// Create new parser
 				$parser = $this->registry->create('Parser');
 				$parser = $this->registry->create('Parser');
 
 
 				// If it's parsed fine
 				// If it's parsed fine
-				if ($parser->parse($utf8_data, 'UTF-8'))
+				if ($parser->parse($utf8_data, empty($encoding) ? '' : 'UTF-8'))	//FreshRSS
 				{
 				{
 					$this->data = $parser->get_data();
 					$this->data = $parser->get_data();
 					if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
 					if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))

+ 20 - 10
lib/SimplePie/SimplePie/Parser.php

@@ -77,6 +77,8 @@ class SimplePie_Parser
 
 
 	public function parse(&$data, $encoding)
 	public function parse(&$data, $encoding)
 	{
 	{
+		$xmlEncoding = '';
+
 		if (!empty($encoding))
 		if (!empty($encoding))
 		{
 		{
 			// Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
 			// Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
@@ -121,6 +123,7 @@ class SimplePie_Parser
 				$declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
 				$declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
 				if ($declaration->parse())
 				if ($declaration->parse())
 				{
 				{
+					$xmlEncoding = strtoupper($declaration->encoding);	//FreshRSS
 					$data = substr($data, $pos + 2);
 					$data = substr($data, $pos + 2);
 					$data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
 					$data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
 				}
 				}
@@ -132,17 +135,24 @@ class SimplePie_Parser
 			}
 			}
 		}
 		}
 
 
-		try	//FreshRSS
-		{
-			$dom = new DOMDocument();
-			$dom->recover = true;
-			$dom->strictErrorChecking = false;
-			$dom->loadXML($data);
-			$this->encoding = $encoding = $dom->encoding = 'UTF-8';
-			$data = $dom->saveXML();
-		}
-		catch (Exception $e)
+		if ($xmlEncoding === '' || $xmlEncoding === 'UTF-8')	//FreshRSS: case of no explicit HTTP encoding, and lax UTF-8
 		{
 		{
+			try
+			{
+				$dom = new DOMDocument();
+				$dom->recover = true;
+				$dom->strictErrorChecking = false;
+				$dom->loadXML($data);
+				$this->encoding = $encoding = $dom->encoding = 'UTF-8';
+				$data2 = $dom->saveXML();
+				if (strlen($data2) > (strlen($data) / 2.0))
+				{
+					$data = $data2;
+				}
+			}
+			catch (Exception $e)
+			{
+			}
 		}
 		}
 
 
 		$return = true;
 		$return = true;

+ 2 - 2
public/install.php

@@ -33,7 +33,7 @@ define ('SQL_FEED', 'CREATE TABLE IF NOT EXISTS `%1$sfeed` (
 	`pathEntries` varchar(511) DEFAULT NULL,
 	`pathEntries` varchar(511) DEFAULT NULL,
 	`httpAuth` varchar(511) DEFAULT NULL,
 	`httpAuth` varchar(511) DEFAULT NULL,
 	`error` boolean DEFAULT 0,
 	`error` boolean DEFAULT 0,
-	`keep_history` MEDIUMINT NOT NULL DEFAULT 0,
+	`keep_history` MEDIUMINT NOT NULL DEFAULT -2,	-- v0.7, -2 = default
 	`cache_nbEntries` int DEFAULT 0,	-- v0.7
 	`cache_nbEntries` int DEFAULT 0,	-- v0.7
 	`cache_nbUnreads` int DEFAULT 0,	-- v0.7
 	`cache_nbUnreads` int DEFAULT 0,	-- v0.7
 	PRIMARY KEY (`id`),
 	PRIMARY KEY (`id`),
@@ -93,7 +93,7 @@ FROM `%1$scategory006`
 ORDER BY id2;
 ORDER BY id2;
 
 
 INSERT IGNORE INTO `%2$sfeed` (url, category, name, website, description, priority, pathEntries, httpAuth, keep_history)
 INSERT IGNORE INTO `%2$sfeed` (url, category, name, website, description, priority, pathEntries, httpAuth, keep_history)
-SELECT url, category2, name, website, description, priority, pathEntries, httpAuth, keep_history
+SELECT url, category2, name, website, description, priority, pathEntries, httpAuth, IF(keep_history = 1, -1, -2)
 FROM `%1$sfeed006`
 FROM `%1$sfeed006`
 ORDER BY id2;
 ORDER BY id2;
 
 

+ 4 - 0
public/themes/default/freshrss.css

@@ -667,6 +667,10 @@
 	padding:.5em;
 	padding:.5em;
 }
 }
 
 
+select.number option {
+	text-align:right;
+}
+
 @media(max-width: 840px) {
 @media(max-width: 840px) {
 	.header,
 	.header,
 	.aside .btn-important,
 	.aside .btn-important,

+ 3 - 0
public/themes/default/global.css

@@ -99,6 +99,9 @@ input, select, textarea {
 	vertical-align: middle;
 	vertical-align: middle;
 	box-shadow: 0 2px 2px #eee inset;
 	box-shadow: 0 2px 2px #eee inset;
 }
 }
+	option {
+		padding:0 .5em 0 .5em;
+	}
 	input[type="radio"],
 	input[type="radio"],
 	input[type="checkbox"] {
 	input[type="checkbox"] {
 		width: 15px !important;
 		width: 15px !important;

+ 4 - 0
public/themes/flat-design/freshrss.css

@@ -662,6 +662,10 @@ body {
 	padding:.5em;
 	padding:.5em;
 }
 }
 
 
+select.number option {
+	text-align:right;
+}
+
 @media(max-width: 840px) {
 @media(max-width: 840px) {
 	.header,
 	.header,
 	.aside .btn-important,
 	.aside .btn-important,

+ 3 - 0
public/themes/flat-design/global.css

@@ -101,6 +101,9 @@ input, select, textarea {
 	vertical-align: middle;
 	vertical-align: middle;
 	border-radius: 5px;
 	border-radius: 5px;
 }
 }
+	option {
+		padding:0 .5em 0 .5em;
+	}
 	input[type="radio"],
 	input[type="radio"],
 	input[type="checkbox"] {
 	input[type="checkbox"] {
 		width: 15px !important;
 		width: 15px !important;