<?php
define('EXPECTED_CONFIG_VERSION', 26);
- define('SCHEMA_VERSION', 106);
+ define('SCHEMA_VERSION', 111);
+
+ define('LABEL_BASE_INDEX', -1024);
+ define('PLUGIN_FEED_BASE_INDEX', -128);
$fetch_last_error = false;
+ $fetch_last_error_code = false;
$pluginhost = false;
function __autoload($class) {
}
}
- function fetch_file_contents($url, $type = false, $login = false, $pass = false, $post_query = false, $timeout = false) {
- $login = urlencode($login);
- $pass = urlencode($pass);
+ function fetch_file_contents($url, $type = false, $login = false, $pass = false, $post_query = false, $timeout = false, $timestamp = 0) {
global $fetch_last_error;
+ global $fetch_last_error_code;
if (function_exists('curl_init') && !ini_get("open_basedir")) {
$ch = curl_init($url);
}
+ if ($timestamp) {
+ curl_setopt($ch, CURLOPT_HTTPHEADER,
+ array("If-Modified-Since: ".gmdate('D, d M Y H:i:s \G\M\T', $timestamp)));
+ }
+
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout ? $timeout : 15);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout ? $timeout : 45);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, !ini_get("safe_mode"));
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
+ $fetch_last_error_code = $http_code;
+
if ($http_code != 200 || $type && strpos($content_type, "$type") === false) {
if (curl_errno($ch) != 0) {
$fetch_last_error = curl_errno($ch) . " " . curl_error($ch);
return $contents;
} else {
- if ($login && $pass ){
+ if ($login && $pass){
$url_parts = array();
preg_match("/(^[^:]*):\/\/(.*)/", $url, $url_parts);
+ $pass = urlencode($pass);
+
if ($url_parts[1] && $url_parts[2]) {
$url = $url_parts[1] . "://$login:$pass@" . $url_parts[2];
}
if (array_search($line["pref_name"], $active_prefs) === FALSE) {
// print "adding " . $line["pref_name"] . "<br>";
+ $line["def_value"] = db_escape_string($link, $line["def_value"]);
+ $line["pref_name"] = db_escape_string($link, $line["pref_name"]);
+
if (get_schema_version($link) < 63) {
db_query($link, "INSERT INTO ttrss_user_prefs
(owner_uid,pref_name,value) VALUES
function authenticate_user($link, $login, $password, $check_only = false) {
if (!SINGLE_USER_MODE) {
-
$user_id = false;
global $pluginhost;
}
if ($user_id && !$check_only) {
+ @session_start();
+
$_SESSION["uid"] = $user_id;
$result = db_query($link, "SELECT login,access_level,pwd_hash FROM ttrss_users
$_SESSION["prefs_cache"] = false;
if (SINGLE_USER_MODE) {
+ @session_start();
authenticate_user($link, "admin", null);
cache_prefs($link);
load_user_plugins($link, $_SESSION["uid"]);
//if (preg_match("/^-?[0-9][0-9]*$/", $feed) != false) {
- $ref_check_qpart = ($max_id &&
- !get_pref($link, 'REVERSE_HEADLINES')) ? "ref_id <= '$max_id'" : "true";
-
if (is_numeric($feed)) {
if ($cat_view) {
db_query($link, "UPDATE ttrss_user_entries
SET unread = false,last_read = NOW()
WHERE feed_id IN (SELECT id FROM ttrss_feeds WHERE $cat_qpart)
- AND $ref_check_qpart AND unread = true
+ AND unread = true
AND owner_uid = $owner_uid");
} else if ($feed == -2) {
db_query($link, "UPDATE ttrss_user_entries
SET unread = false,last_read = NOW() WHERE (SELECT COUNT(*)
FROM ttrss_user_labels2 WHERE article_id = ref_id) > 0
- AND $ref_check_qpart
AND unread = true AND owner_uid = $owner_uid");
}
db_query($link, "UPDATE ttrss_user_entries
SET unread = false,last_read = NOW()
WHERE feed_id = '$feed'
- AND $ref_check_qpart AND unread = true
+ AND unread = true
AND owner_uid = $owner_uid");
- } else if ($feed < 0 && $feed > -10) { // special, like starred
+ } else if ($feed < 0 && $feed > LABEL_BASE_INDEX) { // special, like starred
if ($feed == -1) {
db_query($link, "UPDATE ttrss_user_entries
SET unread = false,last_read = NOW()
WHERE marked = true
- AND $ref_check_qpart AND unread = true
+ AND unread = true
AND owner_uid = $owner_uid");
}
db_query($link, "UPDATE ttrss_user_entries
SET unread = false,last_read = NOW()
WHERE published = true
- AND $ref_check_qpart AND unread = true
+ AND unread = true
AND owner_uid = $owner_uid");
}
if ($feed == -4) {
db_query($link, "UPDATE ttrss_user_entries
SET unread = false,last_read = NOW()
- WHERE $ref_check_qpart AND unread = true AND
+ WHERE unread = true AND
owner_uid = $owner_uid");
}
- } else if ($feed < -10) { // label
+ } else if ($feed < LABEL_BASE_INDEX) { // label
- $label_id = -$feed - 11;
+ $label_id = feed_to_label_id($feed);
db_query($link, "UPDATE ttrss_user_entries, ttrss_user_labels2
SET unread = false, last_read = NOW()
WHERE label_id = '$label_id' AND unread = true
- AND $ref_check_qpart
AND owner_uid = '$owner_uid' AND ref_id = article_id");
}
while ($line = db_fetch_assoc($result)) {
db_query($link, "UPDATE ttrss_user_entries SET
unread = false, last_read = NOW()
- WHERE $ref_check_qpart AND unread = true
+ WHERE unread = true
AND int_id = " . $line["post_int_id"]);
}
db_query($link, "COMMIT");
$match_part = "feed_id IS NULL";
}
- } else if ($feed < -10) {
+ } else if ($feed < LABEL_BASE_INDEX) {
- $label_id = -$feed - 11;
+ $label_id = feed_to_label_id($feed);
return getLabelUnread($link, $label_id, $owner_uid);
array_push($ret_arr, $cv);
}
+ global $pluginhost;
+
+ if ($pluginhost) {
+ $feeds = $pluginhost->get_feeds(-1);
+
+ if (is_array($feeds)) {
+ foreach ($feeds as $feed) {
+ $cv = array("id" => PluginHost::pfeed_to_feed_id($feed['id']),
+ "counter" => $feed['sender']->get_unread($feed['id']));
+
+ array_push($ret_arr, $cv);
+ }
+ }
+ }
+
return $ret_arr;
}
while ($line = db_fetch_assoc($result)) {
- $id = -$line["id"] - 11;
+ $id = label_to_feed_id($line["id"]);
$label_name = $line["caption"];
$count = $line["unread"];
function getFeedCatTitle($link, $id) {
if ($id == -1) {
return __("Special");
- } else if ($id < -10) {
+ } else if ($id < LABEL_BASE_INDEX) {
return __("Labels");
} else if ($id > 0) {
$result = db_query($link, "SELECT ttrss_feed_categories.title
return "images/recently_read.png";
break;
default:
- if ($id < -10) {
+ if ($id < LABEL_BASE_INDEX) {
return "images/label.png";
} else {
if (file_exists(ICONS_DIR . "/$id.ico"))
return __("Archived articles");
} else if ($id == -6) {
return __("Recently read");
- } else if ($id < -10) {
- $label_id = -$id - 11;
+ } else if ($id < LABEL_BASE_INDEX) {
+ $label_id = feed_to_label_id($id);
$result = db_query($link, "SELECT caption FROM ttrss_labels2 WHERE id = '$label_id'");
if (db_num_rows($result) == 1) {
return db_fetch_result($result, 0, "caption");
$params["default_view_limit"] = (int) get_pref($link, "_DEFAULT_VIEW_LIMIT");
$params["default_view_order_by"] = get_pref($link, "_DEFAULT_VIEW_ORDER_BY");
$params["bw_limit"] = (int) $_SESSION["bw_limit"];
+ $params["label_base_index"] = (int) LABEL_BASE_INDEX;
$result = db_query($link, "SELECT MAX(id) AS mid, COUNT(*) AS nf FROM
ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]);
"feed_debug_update" => __("Debug feed update"),
"catchup_all" => __("Mark all feeds as read"),
"cat_toggle_collapse" => __("Un/collapse current category"),
- "toggle_combined_mode" => __("Toggle combined mode")),
+ "toggle_combined_mode" => __("Toggle combined mode"),
+ "toggle_cdm_expanded" => __("Toggle auto expand in combined mode")),
__("Go to") => array(
"goto_all" => __("All articles"),
"goto_fresh" => __("Fresh"),
"f x" => "feed_reverse",
"f *d" => "feed_debug_update",
"f *c" => "toggle_combined_mode",
+ "f c" => "toggle_cdm_expanded",
"*q" => "catchup_all",
"x" => "cat_toggle_collapse",
// "goto" => array(
$data['cdm_expanded'] = get_pref($link, 'CDM_EXPANDED');
$data['dep_ts'] = calculate_dep_timestamp();
+ $data['reload_on_ts_change'] = !defined('_NO_RELOAD_ON_TS_CHANGE');
if (file_exists(LOCK_DIRECTORY . "/update_daemon.lock")) {
$view_query_part = "";
- if ($view_mode == "adaptive" || $view_query_part == "noscores") {
+ if ($view_mode == "adaptive") {
if ($search) {
$view_query_part = " ";
} else if ($feed != -1) {
+
$unread = getFeedUnread($link, $feed, $cat_view);
if ($cat_view && $feed > 0 && $include_children)
$unread += getCategoryChildrenUnread($link, $feed);
- if ($unread > 0) {
- $view_query_part = " unread = true AND ";
- }
+ if ($unread > 0)
+ $view_query_part = " unread = true AND ";
+
}
}
$view_query_part = " marked = true AND ";
}
+ if ($view_mode == "has_note") {
+ $view_query_part = " (note IS NOT NULL AND note != '') AND ";
+ }
+
if ($view_mode == "published") {
$view_query_part = " published = true AND ";
}
- if ($view_mode == "unread") {
+ if ($view_mode == "unread" && $feed != -6) {
$view_query_part = " unread = true AND ";
}
- if ($view_mode == "updated") {
- $view_query_part = " (last_read is null and unread = false) AND ";
- }
-
if ($limit > 0) {
$limit_query_part = "LIMIT " . $limit;
}
$vfeed_query_part = "ttrss_feeds.title AS feed_title,";
$allow_archived = true;
- if (!$override_order) $override_order = "last_marked DESC, updated DESC";
+ if (!$override_order) {
+ $override_order = "last_marked DESC, date_entered DESC, updated DESC";
+ }
} else if ($feed == -2) { // published virtual feed OR labels category
$vfeed_query_part = "ttrss_feeds.title AS feed_title,";
$allow_archived = true;
- if (!$override_order) $override_order = "last_published DESC, updated DESC";
+ if (!$override_order) {
+ $override_order = "last_published DESC, date_entered DESC, updated DESC";
+ }
+
} else {
$vfeed_query_part = "ttrss_feeds.title AS feed_title,";
$intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE", $owner_uid);
if (DB_TYPE == "pgsql") {
- $query_strategy_part .= " AND updated > NOW() - INTERVAL '$intl hour' ";
+ $query_strategy_part .= " AND date_entered > NOW() - INTERVAL '$intl hour' ";
} else {
- $query_strategy_part .= " AND updated > DATE_SUB(NOW(), INTERVAL $intl HOUR) ";
+ $query_strategy_part .= " AND date_entered > DATE_SUB(NOW(), INTERVAL $intl HOUR) ";
}
$vfeed_query_part = "ttrss_feeds.title AS feed_title,";
} else if ($feed == -4) { // all articles virtual feed
$query_strategy_part = "true";
$vfeed_query_part = "ttrss_feeds.title AS feed_title,";
- } else if ($feed <= -10) { // labels
- $label_id = -$feed - 11;
+ } else if ($feed <= LABEL_BASE_INDEX) { // labels
+ $label_id = feed_to_label_id($feed);
$query_strategy_part = "label_id = '$label_id' AND
ttrss_labels2.id = ttrss_user_labels2.label_id AND
$date_sort_field = "date_entered";
}
- if (get_pref($link, 'REVERSE_HEADLINES', $owner_uid)) {
- $order_by = "$date_sort_field";
- } else {
- $order_by = "$date_sort_field DESC";
- }
+ $order_by = "$date_sort_field DESC, updated DESC";
- if ($view_mode != "noscores") {
- $order_by = "score DESC, $order_by";
+ if ($view_mode == "unread_first") {
+ $order_by = "unread DESC, $order_by";
}
if ($override_order) {
hide_images,
unread,feed_id,marked,published,link,last_read,orig_feed_id,
last_marked, last_published,
- ".SUBSTRING_FOR_DATE."(last_read,1,19) as last_read_noms,
$vfeed_query_part
$content_query_part
- ".SUBSTRING_FOR_DATE."(updated,1,19) as updated_noms,
author,score
FROM
$from_qpart
"last_read," .
"(SELECT hide_images FROM ttrss_feeds WHERE id = feed_id) AS hide_images," .
"last_marked, last_published, " .
- SUBSTRING_FOR_DATE . "(last_read,1,19) as last_read_noms," .
$since_id_part .
$vfeed_query_part .
$content_query_part .
- SUBSTRING_FOR_DATE . "(updated,1,19) as updated_noms," .
"score ";
$feed_kind = "Tags";
if ($entry->nodeName == 'img') {
if (($owner && get_pref($link, "STRIP_IMAGES", $owner)) ||
- $force_remove_images) {
+ $force_remove_images || $_SESSION["bw_limit"]) {
$p = $doc->createElement('p');
}
+ $allowed_elements = array('a', 'address', 'audio', 'article',
+ 'b', 'big', 'blockquote', 'body', 'br', 'cite', 'center',
+ 'code', 'dd', 'del', 'details', 'div', 'dl', 'font',
+ 'dt', 'em', 'footer', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
+ 'header', 'html', 'i', 'img', 'ins', 'kbd',
+ 'li', 'nav', 'noscript', 'ol', 'p', 'pre', 'q', 's','small',
+ 'source', 'span', 'strike', 'strong', 'sub', 'summary',
+ 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead',
+ 'tr', 'track', 'tt', 'u', 'ul', 'var', 'wbr', 'video' );
+
+ if ($_SESSION['hasSandbox']) $allowed_elements[] = 'iframe';
+
+ $disallowed_attributes = array('id', 'style', 'class');
+
global $pluginhost;
if (isset($pluginhost)) {
foreach ($pluginhost->get_hooks($pluginhost::HOOK_SANITIZE) as $plugin) {
- $doc = $plugin->hook_sanitize($doc, $site_url);
+ $retval = $plugin->hook_sanitize($doc, $site_url, $allowed_elements, $disallowed_attributes);
+ if (is_array($retval)) {
+ $doc = $retval[0];
+ $allowed_elements = $retval[1];
+ $disallowed_attributes = $retval[2];
+ } else {
+ $doc = $retval;
+ }
}
}
$doc->removeChild($doc->firstChild); //remove doctype
- $doc = strip_harmful_tags($doc);
+ $doc = strip_harmful_tags($doc, $allowed_elements, $disallowed_attributes);
$res = $doc->saveHTML();
return $res;
}
- function strip_harmful_tags($doc) {
+ function strip_harmful_tags($doc, $allowed_elements, $disallowed_attributes) {
$entries = $doc->getElementsByTagName("*");
- $allowed_elements = array('a', 'address', 'audio', 'article',
- 'b', 'big', 'blockquote', 'body', 'br', 'cite', 'center',
- 'code', 'dd', 'del', 'details', 'div', 'dl', 'font',
- 'dt', 'em', 'footer', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
- 'header', 'html', 'i', 'img', 'ins', 'kbd',
- 'li', 'nav', 'ol', 'p', 'pre', 'q', 's','small',
- 'source', 'span', 'strike', 'strong', 'sub', 'summary',
- 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead',
- 'tr', 'track', 'tt', 'u', 'ul', 'var', 'wbr', 'video' );
-
- if ($_SESSION['hasSandbox']) array_push($allowed_elements, 'iframe');
-
- $disallowed_attributes = array('id', 'style', 'class');
-
foreach ($entries as $entry) {
if (!in_array($entry->nodeName, $allowed_elements)) {
$entry->parentNode->removeChild($entry);
function format_warning($msg, $id = "") {
global $link;
return "<div class=\"warning\" id=\"$id\">
- <img src=\"images/sign_excl.svg\">$msg</div>";
+ <img src=\"images/sign_excl.svg\"><div class='inner'>$msg</div></div>";
}
function format_notice($msg, $id = "") {
global $link;
return "<div class=\"notice\" id=\"$id\">
- <img src=\"images/sign_info.svg\">$msg</div>";
+ <img src=\"images/sign_info.svg\"><div class='inner'>$msg</div></div>";
}
function format_error($msg, $id = "") {
global $link;
return "<div class=\"error\" id=\"$id\">
- <img src=\"images/sign_excl.svg\">$msg</div>";
+ <img src=\"images/sign_excl.svg\"><div class='inner'>$msg</div></div>";
}
function print_notice($msg) {
$filter_id = $line["id"];
$result2 = db_query($link, "SELECT
- r.reg_exp, r.feed_id, r.cat_id, r.cat_filter, t.name AS type_name
+ r.reg_exp, r.inverse, r.feed_id, r.cat_id, r.cat_filter, t.name AS type_name
FROM ttrss_filters2_rules AS r,
ttrss_filter_types AS t
WHERE
$rule = array();
$rule["reg_exp"] = $rule_line["reg_exp"];
$rule["type"] = $rule_line["type_name"];
+ $rule["inverse"] = sql_bool_to_bool($rule_line["inverse"]);
array_push($rules, $rule);
}
$filter = array();
$filter["match_any_rule"] = sql_bool_to_bool($line["match_any_rule"]);
+ $filter["inverse"] = sql_bool_to_bool($line["inverse"]);
$filter["rules"] = $rules;
$filter["actions"] = $actions;
array_push($entries, $entry);
}
- if ($_SESSION['uid'] && !get_pref($link, "STRIP_IMAGES")) {
+ if ($_SESSION['uid'] && !get_pref($link, "STRIP_IMAGES") && !$_SESSION["bw_limit"]) {
if ($always_display_enclosures ||
!preg_match("/<img/i", $article_content)) {
$rv .= "<hr clear='both'/>";
}
- $rv .= "<br/><div dojoType=\"dijit.form.DropDownButton\">".
- "<span>" . __('Attachments')."</span>";
- $rv .= "<div dojoType=\"dijit.Menu\" style=\"display: none;\">";
+ $rv .= "<select class=\"attachments\" onchange=\"openSelectedAttachment(this)\">".
+ "<option value=''>" . __('Attachments')."</option>";
+
+ foreach ($entries as $entry) {
+ $rv .= "<option value=\"".htmlspecialchars($entry["url"])."\">" . htmlspecialchars($entry["filename"]) . "</option>";
- foreach ($entries_html as $entry) { $rv .= $entry; };
+ };
- $rv .= "</div></div>";
+ $rv .= "</select>";
}
return $rv;
if (count($ids) > 0) {
$ids = join(",", $ids);
- print ".";
$tmp_result = db_query($link, "DELETE FROM ttrss_tags WHERE id IN ($ids)");
$tags_deleted += db_affected_rows($link, $tmp_result);
$limit -= $limit_part;
}
- print "\n";
-
return $tags_deleted;
}
$rule['reg_exp'] = db_escape_string($link, $rule['reg_exp']);
- switch ($rule["type"]) {
+ switch ($rule["type"]) {
case "title":
$qpart = "LOWER(ttrss_entries.title) $reg_qpart LOWER('".
$rule['reg_exp'] . "')";
break;
}
+ if (isset($rule['inverse'])) $qpart = "NOT ($qpart)";
+
if (isset($rule["feed_id"]) && $rule["feed_id"] > 0) {
$qpart .= " AND feed_id = " . db_escape_string($link, $rule["feed_id"]);
}
}
if (count($query) > 0) {
- return "(" . join($filter["match_any_rule"] ? "OR" : "AND", $query) . ")";
+ $fullquery = "(" . join($filter["match_any_rule"] ? "OR" : "AND", $query) . ")";
} else {
- return "(false)";
+ $fullquery = "(false)";
}
+
+ if ($filter['inverse']) $fullquery = "(NOT $fullquery)";
+
+ return $fullquery;
}
if (!function_exists('gzdecode')) {
return $max_ts;
}
+ function T_js_decl($s1, $s2) {
+ if ($s1 && $s2) {
+ $s1 = preg_replace("/\n/", "", $s1);
+ $s2 = preg_replace("/\n/", "", $s2);
+
+ $s1 = preg_replace("/\"/", "\\\"", $s1);
+ $s2 = preg_replace("/\"/", "\\\"", $s2);
+
+ return "T_messages[\"$s1\"] = \"$s2\";\n";
+ }
+ }
+
+ function init_js_translations() {
+
+ print 'var T_messages = new Object();
+
+ function __(msg) {
+ if (T_messages[msg]) {
+ return T_messages[msg];
+ } else {
+ return msg;
+ }
+ }
+
+ function ngettext(msg1, msg2, n) {
+ return (parseInt(n) > 1) ? msg2 : msg1;
+ }';
+
+ $l10n = _get_reader();
+
+ for ($i = 0; $i < $l10n->total; $i++) {
+ $orig = $l10n->get_original_string($i);
+ $translation = __($orig);
+
+ print T_js_decl($orig, $translation);
+ }
+ }
+
+ function label_to_feed_id($label) {
+ return LABEL_BASE_INDEX - 1 - abs($label);
+ }
+
+ function feed_to_label_id($feed) {
+ return LABEL_BASE_INDEX - 1 + abs($feed);
+ }
+
?>