X-Git-Url: https://git.wh0rd.org/?a=blobdiff_plain;f=include%2Ffunctions.php;h=307f662009b14dc83c304a86477f4a5e57c96508;hb=583dbc56953afbad6ccae5e3add15160e23b68e4;hp=da676798636a2db5eedb6b6629a91cb49f244b6e;hpb=19c7350770788edf3ae0bb1fd6d95876667adbf6;p=tt-rss.git diff --git a/include/functions.php b/include/functions.php index da676798..307f6620 100644 --- a/include/functions.php +++ b/include/functions.php @@ -1,8 +1,13 @@ "Detect automatically", "ca_CA" => "Català", + "cs_CZ" => "Česky", "en_US" => "English", "es_ES" => "Español", "de_DE" => "Deutsch", @@ -50,7 +56,9 @@ "hu_HU" => "Magyar (Hungarian)", "it_IT" => "Italiano", "ja_JP" => "日本語 (Japanese)", + "lv_LV" => "Latviešu", "nb_NO" => "Norwegian bokmål", + "nl_NL" => "Dutch", "pl_PL" => "Polski", "ru_RU" => "Русский", "pt_BR" => "Portuguese/Brazil", @@ -62,6 +70,7 @@ require_once "lib/accept-to-gettext.php"; require_once "lib/gettext/gettext.inc"; + function startup_gettext() { # Get locale from Accept-Language header @@ -71,10 +80,7 @@ $lang = _TRANSLATION_OVERRIDE_DEFAULT; } - /* In login action of mobile version */ - if ($_POST["language"] && defined('MOBILE_VERSION')) { - $lang = $_POST["language"]; - } else { + if ($_SESSION["language"] && $_SESSION["language"] != "auto") { $lang = $_SESSION["language"]; } @@ -85,11 +91,7 @@ _setlocale(LC_ALL, $lang); } - if (defined('MOBILE_VERSION')) { - _bindtextdomain("messages", "../locale"); - } else { - _bindtextdomain("messages", "locale"); - } + _bindtextdomain("messages", "locale"); _textdomain("messages"); _bind_textdomain_codeset("messages", "UTF-8"); @@ -100,16 +102,13 @@ require_once 'db-prefs.php'; require_once 'version.php'; - - define('MAGPIE_OUTPUT_ENCODING', 'UTF-8'); + require_once 'ccache.php'; + require_once 'labels.php'; define('SELF_USER_AGENT', 'Tiny Tiny RSS/' . VERSION . ' (http://tt-rss.org/)'); - define('MAGPIE_USER_AGENT', SELF_USER_AGENT); - ini_set('user_agent', SELF_USER_AGENT); require_once 'lib/pubsubhubbub/publisher.php'; - require_once 'lib/htmLawed.php'; $tz_offset = -1; $utc_tz = new DateTimeZone('UTC'); @@ -122,14 +121,24 @@ * @return void */ function _debug($msg) { - if (defined('QUIET') && QUIET) { - return; - } $ts = strftime("%H:%M:%S", time()); if (function_exists('posix_getpid')) { $ts = "$ts/" . posix_getpid(); } - print "[$ts] $msg\n"; + + if (!(defined('QUIET') && QUIET)) { + print "[$ts] $msg\n"; + } + + if (defined('LOGFILE')) { + $fp = fopen(LOGFILE, 'a+'); + + if ($fp) { + fputs($fp, "[$ts] $msg\n"); + fclose($fp); + } + } + } // function _debug /** @@ -225,6 +234,8 @@ if ($debug) { _debug("Purged feed $feed_id ($purge_interval): deleted $rows articles"); } + + return $rows; } // function purge_feed function feed_purge_interval($link, $feed_id) { @@ -277,18 +288,27 @@ } } - function fetch_file_contents($url, $type = false, $login = false, $pass = false, $post_query = 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); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15); - curl_setopt($ch, CURLOPT_TIMEOUT, 45); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + if (ini_get("safe_mode")) { + $ch = curl_init(geturl($url)); + } else { + $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")); curl_setopt($ch, CURLOPT_MAXREDIRS, 20); curl_setopt($ch, CURLOPT_BINARYTRANSFER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); @@ -296,6 +316,7 @@ curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_setopt($ch, CURLOPT_USERAGENT, SELF_USER_AGENT); curl_setopt($ch, CURLOPT_ENCODING , "gzip"); + curl_setopt($ch, CURLOPT_REFERER, $url); if ($post_query) { curl_setopt($ch, CURLOPT_POST, true); @@ -307,27 +328,43 @@ $contents = @curl_exec($ch); + if (curl_errno($ch) === 23 || curl_errno($ch) === 61) { + curl_setopt($ch, CURLOPT_ENCODING, 'none'); + $contents = @curl_exec($ch); + } + if ($contents === false) { - $fetch_last_error = curl_error($ch); + $fetch_last_error = curl_errno($ch) . " " . curl_error($ch); curl_close($ch); return false; } $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); - curl_close($ch); + + $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); + } else { + $fetch_last_error = "HTTP Code: $http_code"; + } + curl_close($ch); return false; } + curl_close($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]; } @@ -335,6 +372,9 @@ $data = @file_get_contents($url); + @$gzdecoded = gzdecode($data); + if ($gzdecoded) $data = $gzdecoded; + if (!$data && function_exists('error_get_last')) { $error = error_get_last(); $fetch_last_error = $error["message"]; @@ -444,6 +484,8 @@ else $sel = ""; + $v = trim($v); + print ""; } print ""; @@ -457,17 +499,14 @@ else $sel = ""; + $v = trim($v); + print ""; } print ""; } - function getmicrotime() { - list($usec, $sec) = explode(" ",microtime()); - return ((float)$usec + (float)$sec); - } - function print_radio($id, $default, $true_is, $values, $attributes = "") { foreach ($values as $v) { @@ -490,7 +529,7 @@ function initialize_user_prefs($link, $uid, $profile = false) { - $uid = db_escape_string($uid); + $uid = db_escape_string($link, $uid); if (!$profile) { $profile = "NULL"; @@ -518,6 +557,9 @@ if (array_search($line["pref_name"], $active_prefs) === FALSE) { // print "adding " . $line["pref_name"] . "
"; + $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 @@ -549,29 +591,22 @@ function authenticate_user($link, $login, $password, $check_only = false) { if (!SINGLE_USER_MODE) { - $user_id = false; - $modules = explode(",", AUTH_MODULES); - - foreach ($modules as $module) { - $module_class = "auth_$module"; - if (class_exists($module_class)) { - $authenticator = new $module_class($link); - $user_id = (int) $authenticator->authenticate($login, $password); + global $pluginhost; + foreach ($pluginhost->get_hooks($pluginhost::HOOK_AUTH_USER) as $plugin) { - if ($user_id) { - $_SESSION["auth_module"] = $module; - break; - } + $user_id = (int) $plugin->authenticate($login, $password); - } else { - print T_sprintf("Fatal: authentication module %s not found.", $module); - die; + if ($user_id) { + $_SESSION["auth_module"] = strtolower(get_class($plugin)); + break; } } if ($user_id && !$check_only) { + @session_start(); + $_SESSION["uid"] = $user_id; $result = db_query($link, "SELECT login,access_level,pwd_hash FROM ttrss_users @@ -715,9 +750,27 @@ return true; } - function login_sequence($link, $login_form = 0) { + function load_user_plugins($link, $owner_uid) { + if ($owner_uid) { + $plugins = get_pref($link, "_ENABLED_PLUGINS", $owner_uid); + + global $pluginhost; + $pluginhost->load($plugins, $pluginhost::KIND_USER, $owner_uid); + + if (get_schema_version($link) > 100) { + $pluginhost->load_data(); + } + } + } + + function login_sequence($link) { + $_SESSION["prefs_cache"] = false; + if (SINGLE_USER_MODE) { - return authenticate_user($link, "admin", null); + @session_start(); + authenticate_user($link, "admin", null); + cache_prefs($link); + load_user_plugins($link, $_SESSION["uid"]); } else { if (!$_SESSION["uid"] || !validate_session($link)) { @@ -727,138 +780,47 @@ authenticate_user($link, null, null, true); } - if (!$_SESSION["uid"]) render_login_form($link, $login_form); + if (!$_SESSION["uid"]) render_login_form($link); } else { /* bump login timestamp */ db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " . $_SESSION["uid"]); + $_SESSION["last_login_update"] = time(); } if ($_SESSION["uid"] && $_SESSION["language"] && SESSION_COOKIE_LIFETIME > 0) { setcookie("ttrss_lang", $_SESSION["language"], time() + SESSION_COOKIE_LIFETIME); } - } - } - - function truncate_string($str, $max_len, $suffix = '…') { - if (mb_strlen($str, "utf-8") > $max_len - 3) { - return mb_substr($str, 0, $max_len, "utf-8") . $suffix; - } else { - return $str; - } - } - - function theme_image($link, $filename) { - if ($link) { - $theme_path = get_user_theme_path($link); - - if ($theme_path && is_file($theme_path.$filename)) { - return $theme_path.$filename; - } else { - return $filename; - } - } else { - return $filename; - } - } - - function get_user_theme($link) { - - if (get_schema_version($link) >= 63 && $_SESSION["uid"]) { - $theme_name = get_pref($link, "_THEME_ID"); - if (is_dir("themes/$theme_name")) { - return $theme_name; - } else { - return ''; - } - } else { - return ''; - } - - } - - function get_user_theme_path($link) { - $theme_path = ''; - if (get_schema_version($link) >= 63 && $_SESSION["uid"]) { - $theme_name = get_pref($link, "_THEME_ID"); + if ($_SESSION["uid"]) { + cache_prefs($link); + load_user_plugins($link, $_SESSION["uid"]); - if ($theme_name && is_dir("themes/$theme_name")) { - $theme_path = "themes/$theme_name/"; - } else { - $theme_name = ''; - } - } else { - $theme_path = ''; - } + /* cleanup ccache */ - if ($theme_path) { - if (is_file("$theme_path/theme.ini")) { - $ini = parse_ini_file("$theme_path/theme.ini", true); - if ($ini['theme']['version'] >= THEME_VERSION_REQUIRED) { - return $theme_path; - } - } - } - return ''; - } + db_query($link, "DELETE FROM ttrss_counters_cache WHERE owner_uid = ". + $_SESSION["uid"] . " AND + (SELECT COUNT(id) FROM ttrss_feeds WHERE + ttrss_feeds.id = feed_id) = 0"); - function get_user_theme_options($link) { - $t = get_user_theme_path($link); + db_query($link, "DELETE FROM ttrss_cat_counters_cache WHERE owner_uid = ". + $_SESSION["uid"] . " AND + (SELECT COUNT(id) FROM ttrss_feed_categories WHERE + ttrss_feed_categories.id = feed_id) = 0"); - if ($t) { - if (is_file("$t/theme.ini")) { - $ini = parse_ini_file("$t/theme.ini", true); - if ($ini['theme']['version']) { - return $ini['theme']['options']; - } } - } - return ''; - } - - function print_theme_includes($link) { - $t = get_user_theme_path($link); - $time = time(); - - if ($t) { - print ""; - if (file_exists("$t/theme.js")) { - print ""; - } } } - function get_all_themes() { - $themes = glob("themes/*"); - - asort($themes); - - $rv = array(); - - foreach ($themes as $t) { - if (is_file("$t/theme.ini")) { - $ini = parse_ini_file("$t/theme.ini", true); - if ($ini['theme']['version'] >= THEME_VERSION_REQUIRED && - !$ini['theme']['disabled']) { - $entry = array(); - $entry["path"] = $t; - $entry["base"] = basename($t); - $entry["name"] = $ini['theme']['name']; - $entry["version"] = $ini['theme']['version']; - $entry["author"] = $ini['theme']['author']; - $entry["options"] = $ini['theme']['options']; - array_push($rv, $entry); - } - } + function truncate_string($str, $max_len, $suffix = '…') { + if (mb_strlen($str, "utf-8") > $max_len - 3) { + return mb_substr($str, 0, $max_len, "utf-8") . $suffix; + } else { + return $str; } - - return $rv; } function convert_timestamp($timestamp, $source_tz, $dest_tz) { @@ -934,7 +896,7 @@ } function sql_bool_to_bool($s) { - if ($s == "t" || $s == "1" || $s == "true") { + if ($s == "t" || $s == "1" || strtolower($s) == "true") { return true; } else { return false; @@ -982,7 +944,7 @@ } } - if (db_escape_string("testTEST") != "testTEST") { + if (db_escape_string($link, "testTEST") != "testTEST") { $error_code = 12; } @@ -1010,7 +972,7 @@ function make_lockfile($filename) { $fp = fopen(LOCK_DIRECTORY . "/$filename", "w"); - if (flock($fp, LOCK_EX | LOCK_NB)) { + if ($fp && flock($fp, LOCK_EX | LOCK_NB)) { if (function_exists('posix_getpid')) { fwrite($fp, posix_getpid() . "\n"); } @@ -1047,9 +1009,6 @@ //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) { @@ -1069,7 +1028,7 @@ 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 owner_uid = $owner_uid"); } else if ($feed == -2) { @@ -1077,7 +1036,6 @@ 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"); } @@ -1086,16 +1044,16 @@ 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 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 owner_uid = $owner_uid"); } @@ -1103,7 +1061,7 @@ db_query($link, "UPDATE ttrss_user_entries SET unread = false,last_read = NOW() WHERE published = true - AND $ref_check_qpart + AND unread = true AND owner_uid = $owner_uid"); } @@ -1136,17 +1094,17 @@ if ($feed == -4) { db_query($link, "UPDATE ttrss_user_entries SET unread = false,last_read = NOW() - WHERE $ref_check_qpart AND owner_uid = $owner_uid"); + 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"); } @@ -1156,7 +1114,7 @@ } else { // tag db_query($link, "BEGIN"); - $tag_name = db_escape_string($feed); + $tag_name = db_escape_string($link, $feed); $result = db_query($link, "SELECT post_int_id FROM ttrss_tags WHERE tag_name = '$tag_name' AND owner_uid = $owner_uid"); @@ -1164,24 +1122,20 @@ while ($line = db_fetch_assoc($result)) { db_query($link, "UPDATE ttrss_user_entries SET unread = false, last_read = NOW() - WHERE $ref_check_qpart AND int_id = " . $line["post_int_id"]); + WHERE unread = true + AND int_id = " . $line["post_int_id"]); } db_query($link, "COMMIT"); } } - function getAllCounters($link, $omode = "flc", $active_feed = false) { - - if (!$omode) $omode = "flc"; - + function getAllCounters($link) { $data = getGlobalCounters($link); $data = array_merge($data, getVirtCounters($link)); - - if (strchr($omode, "l")) $data = array_merge($data, getLabelCounters($link)); - if (strchr($omode, "f")) $data = array_merge($data, getFeedCounters($link, $active_feed)); - if (strchr($omode, "t")) $data = array_merge($data, getTagCounters($link)); - if (strchr($omode, "c")) $data = array_merge($data, getCategoryCounters($link)); + $data = array_merge($data, getLabelCounters($link)); + $data = array_merge($data, getFeedCounters($link, $active_feed)); + $data = array_merge($data, getCategoryCounters($link)); return $data; } @@ -1357,7 +1311,7 @@ return 0; } else if ($feed != "0" && $n_feed == 0) { - $feed = db_escape_string($feed); + $feed = db_escape_string($link, $feed); $result = db_query($link, "SELECT SUM((SELECT COUNT(int_id) FROM ttrss_user_entries,ttrss_entries WHERE int_id = post_int_id @@ -1392,9 +1346,9 @@ $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); @@ -1469,36 +1423,6 @@ return $ret_arr; } - function getTagCounters($link) { - - $ret_arr = array(); - - $result = db_query($link, "SELECT tag_name,SUM((SELECT COUNT(int_id) - FROM ttrss_user_entries,ttrss_entries WHERE int_id = post_int_id - AND ref_id = id AND unread = true)) AS count FROM ttrss_tags - WHERE owner_uid = ".$_SESSION['uid']." GROUP BY tag_name - ORDER BY count DESC LIMIT 55"); - - $tags = array(); - - while ($line = db_fetch_assoc($result)) { - $tags[$line["tag_name"]] += $line["count"]; - } - - foreach (array_keys($tags) as $tag) { - $unread = $tags[$tag]; - $tag = htmlspecialchars($tag); - - $cv = array("id" => $tag, - "kind" => "tag", - "counter" => $unread); - - array_push($ret_arr, $cv); - } - - return $ret_arr; - } - function getVirtCounters($link) { $ret_arr = array(); @@ -1516,6 +1440,21 @@ 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; } @@ -1525,15 +1464,19 @@ $owner_uid = $_SESSION["uid"]; - $result = db_query($link, "SELECT id, caption FROM ttrss_labels2 - WHERE owner_uid = '$owner_uid'"); + $result = db_query($link, "SELECT id,caption,COUNT(unread) AS unread + FROM ttrss_labels2 LEFT JOIN ttrss_user_labels2 ON + (ttrss_labels2.id = label_id) + LEFT JOIN ttrss_user_entries ON (ref_id = article_id AND unread = true) + WHERE ttrss_labels2.owner_uid = $owner_uid GROUP BY ttrss_labels2.id, + ttrss_labels2.caption"); while ($line = db_fetch_assoc($result)) { - $id = -$line["id"] - 11; + $id = label_to_feed_id($line["id"]); $label_name = $line["caption"]; - $count = getFeedUnread($link, $id); + $count = $line["unread"]; $cv = array("id" => $id, "counter" => (int) $count); @@ -1619,7 +1562,7 @@ * 5 - Couldn't download the URL content. */ function subscribe_to_feed($link, $url, $cat_id = 0, - $auth_login = '', $auth_pass = '', $need_auth = false) { + $auth_login = '', $auth_pass = '') { global $fetch_last_error; @@ -1629,8 +1572,6 @@ if (!$url || !validate_feed_url($url)) return array("code" => 2); - $update_method = 0; - $contents = @fetch_file_contents($url, false, $auth_login, $auth_pass); if (!$contents) { @@ -1664,7 +1605,7 @@ "INSERT INTO ttrss_feeds (owner_uid,feed_url,title,cat_id, auth_login,auth_pass,update_method) VALUES ('".$_SESSION["uid"]."', '$url', - '[Unknown]', $cat_qpart, '$auth_login', '$auth_pass', '$update_method')"); + '[Unknown]', $cat_qpart, '$auth_login', '$auth_pass', 0)"); $result = db_query($link, "SELECT id FROM ttrss_feeds WHERE feed_url = '$url' @@ -1839,7 +1780,7 @@ 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 @@ -1862,10 +1803,10 @@ return "images/archive.png"; break; case -1: - return "images/mark_set.png"; + return "images/mark_set.svg"; break; case -2: - return "images/pub_set.png"; + return "images/pub_set.svg"; break; case -3: return "images/fresh.png"; @@ -1877,7 +1818,7 @@ 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")) @@ -1902,8 +1843,8 @@ 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"); @@ -1926,14 +1867,6 @@ function make_init_params($link) { $params = array(); - $params["theme"] = get_user_theme($link); - $params["theme_options"] = get_user_theme_options($link); - - $params["sign_progress"] = theme_image($link, "images/indicator_white.gif"); - $params["sign_progress_tiny"] = theme_image($link, "images/indicator_tiny.gif"); - $params["sign_excl"] = theme_image($link, "images/sign_excl.png"); - $params["sign_info"] = theme_image($link, "images/sign_info.png"); - foreach (array("ON_CATCHUP_SHOW_NEXT_FEED", "HIDE_READ_FEEDS", "ENABLE_FEED_CATS", "FEEDS_SORT_BY_UNREAD", "CONFIRM_FEED_CATCHUP", "CDM_AUTO_CATCHUP", "FRESH_ARTICLE_MAX_AGE", "DEFAULT_ARTICLE_LIMIT", @@ -1948,6 +1881,7 @@ $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"]); @@ -1959,12 +1893,166 @@ $params["num_feeds"] = (int) $num_feeds; $params["collapsed_feedlist"] = (int) get_pref($link, "_COLLAPSED_FEEDLIST"); + $params["hotkeys"] = get_hotkeys_map($link); $params["csrf_token"] = $_SESSION["csrf_token"]; + $params["widescreen"] = (int) $_COOKIE["ttrss_widescreen"]; + + $params['simple_update'] = defined('SIMPLE_UPDATE_MODE') && SIMPLE_UPDATE_MODE; return $params; } + function get_hotkeys_info($link) { + $hotkeys = array( + __("Navigation") => array( + "next_feed" => __("Open next feed"), + "prev_feed" => __("Open previous feed"), + "next_article" => __("Open next article"), + "prev_article" => __("Open previous article"), + "next_article_noscroll" => __("Open next article (don't scroll long articles)"), + "prev_article_noscroll" => __("Open previous article (don't scroll long articles)"), + "search_dialog" => __("Show search dialog")), + __("Article") => array( + "toggle_mark" => __("Toggle starred"), + "toggle_publ" => __("Toggle published"), + "toggle_unread" => __("Toggle unread"), + "edit_tags" => __("Edit tags"), + "dismiss_selected" => __("Dismiss selected"), + "dismiss_read" => __("Dismiss read"), + "open_in_new_window" => __("Open in new window"), + "catchup_below" => __("Mark below as read"), + "catchup_above" => __("Mark above as read"), + "article_scroll_down" => __("Scroll down"), + "article_scroll_up" => __("Scroll up"), + "select_article_cursor" => __("Select article under cursor"), + "email_article" => __("Email article"), + "close_article" => __("Close/collapse article"), + "toggle_widescreen" => __("Toggle widescreen mode"), + "toggle_embed_original" => __("Toggle embed original")), + __("Article selection") => array( + "select_all" => __("Select all articles"), + "select_unread" => __("Select unread"), + "select_marked" => __("Select starred"), + "select_published" => __("Select published"), + "select_invert" => __("Invert selection"), + "select_none" => __("Deselect everything")), + __("Feed") => array( + "feed_refresh" => __("Refresh current feed"), + "feed_unhide_read" => __("Un/hide read feeds"), + "feed_subscribe" => __("Subscribe to feed"), + "feed_edit" => __("Edit feed"), + "feed_catchup" => __("Mark as read"), + "feed_reverse" => __("Reverse headlines"), + "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_cdm_expanded" => __("Toggle auto expand in combined mode")), + __("Go to") => array( + "goto_all" => __("All articles"), + "goto_fresh" => __("Fresh"), + "goto_marked" => __("Starred"), + "goto_published" => __("Published"), + "goto_tagcloud" => __("Tag cloud"), + "goto_prefs" => __("Preferences")), + __("Other") => array( + "create_label" => __("Create label"), + "create_filter" => __("Create filter"), + "collapse_sidebar" => __("Un/collapse sidebar"), + "help_dialog" => __("Show help dialog")) + ); + + return $hotkeys; + } + + function get_hotkeys_map($link) { + $hotkeys = array( +// "navigation" => array( + "k" => "next_feed", + "j" => "prev_feed", + "n" => "next_article", + "p" => "prev_article", + "(38)|up" => "prev_article", + "(40)|down" => "next_article", +// "^(38)|Ctrl-up" => "prev_article_noscroll", +// "^(40)|Ctrl-down" => "next_article_noscroll", + "(191)|/" => "search_dialog", +// "article" => array( + "s" => "toggle_mark", + "*s" => "toggle_publ", + "u" => "toggle_unread", + "*t" => "edit_tags", + "*d" => "dismiss_selected", + "*x" => "dismiss_read", + "o" => "open_in_new_window", + "c p" => "catchup_below", + "c n" => "catchup_above", + "*n" => "article_scroll_down", + "*p" => "article_scroll_up", + "*(38)|Shift+up" => "article_scroll_up", + "*(40)|Shift+down" => "article_scroll_down", + "a *w" => "toggle_widescreen", + "a e" => "toggle_embed_original", + "e" => "email_article", + "a q" => "close_article", +// "article_selection" => array( + "a a" => "select_all", + "a u" => "select_unread", + "a *u" => "select_marked", + "a p" => "select_published", + "a i" => "select_invert", + "a n" => "select_none", +// "feed" => array( + "f r" => "feed_refresh", + "f a" => "feed_unhide_read", + "f s" => "feed_subscribe", + "f e" => "feed_edit", + "f q" => "feed_catchup", + "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( + "g a" => "goto_all", + "g f" => "goto_fresh", + "g s" => "goto_marked", + "g p" => "goto_published", + "g t" => "goto_tagcloud", + "g *p" => "goto_prefs", +// "other" => array( + "(9)|Tab" => "select_article_cursor", // tab + "c l" => "create_label", + "c f" => "create_filter", + "c s" => "collapse_sidebar", + "^(191)|Ctrl+/" => "help_dialog", + ); + + if (get_pref($link, 'COMBINED_DISPLAY_MODE')) { + $hotkeys["^(38)|Ctrl-up"] = "prev_article_noscroll"; + $hotkeys["^(40)|Ctrl-down"] = "next_article_noscroll"; + } + + global $pluginhost; + foreach ($pluginhost->get_hooks($pluginhost::HOOK_HOTKEY_MAP) as $plugin) { + $hotkeys = $plugin->hook_hotkey_map($hotkeys); + } + + $prefixes = array(); + + foreach (array_keys($hotkeys) as $hotkey) { + $pair = explode(" ", $hotkey, 2); + + if (count($pair) > 1 && !in_array($pair[0], $prefixes)) { + array_push($prefixes, $pair[0]); + } + } + + return array($prefixes, $hotkeys); + } + function make_runtime_info($link) { $data = array(); @@ -1980,6 +2068,9 @@ $data['last_article_id'] = getLastArticleId($link); $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")) { $data['daemon_is_running'] = (int) file_is_locked("update_daemon.lock"); @@ -2019,7 +2110,7 @@ return $data; } - function search_to_sql($link, $search, $match_on) { + function search_to_sql($link, $search) { $search_query_part = ""; @@ -2066,13 +2157,9 @@ //$k = date("Y-m-d", strtotime(substr($k, 1))); array_push($query_keywords, "(".SUBSTRING_FOR_DATE."(updated,1,LENGTH('$k')) $not = '$k')"); - } else if ($match_on == "both") { + } else { array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); - } else if ($match_on == "title") { - array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%'))"); - } else if ($match_on == "content") { - array_push($query_keywords, "(UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); } } @@ -2109,7 +2196,7 @@ return $rv; } - function queryFeedHeadlines($link, $feed, $limit, $view_mode, $cat_view, $search, $search_mode, $match_on, $override_order = false, $offset = 0, $owner_uid = 0, $filter = false, $since_id = 0, $include_children = false) { + function queryFeedHeadlines($link, $feed, $limit, $view_mode, $cat_view, $search, $search_mode, $override_order = false, $offset = 0, $owner_uid = 0, $filter = false, $since_id = 0, $include_children = false, $ignore_vfeed_group = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; @@ -2126,7 +2213,7 @@ $search_query_part = "ref_id = -1 AND "; } else { - $search_query_part = search_to_sql($link, $search, $match_on); + $search_query_part = search_to_sql($link, $search); $search_query_part .= " AND "; } @@ -2147,16 +2234,20 @@ $filter_query_part = filter_to_sql($link, $filter, $owner_uid); // Try to check if SQL regexp implementation chokes on a valid regexp - $result = db_query($link, "SELECT true AS true FROM ttrss_entries, + $result = db_query($link, "SELECT true AS true_val FROM ttrss_entries, ttrss_user_entries, ttrss_feeds, ttrss_feed_categories WHERE $filter_query_part LIMIT 1", false); - $test = db_fetch_result($result, 0, "true"); + if ($result) { + $test = db_fetch_result($result, 0, "true_val"); - if (!$test) { - $filter_query_part = "false AND"; + if (!$test) { + $filter_query_part = "false AND"; + } else { + $filter_query_part .= " AND"; + } } else { - $filter_query_part .= " AND"; + $filter_query_part = "false AND"; } } else { @@ -2171,18 +2262,19 @@ $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 "; + } } @@ -2190,18 +2282,18 @@ $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; } @@ -2274,6 +2366,10 @@ $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; $allow_archived = true; + if (!$override_order) { + $override_order = "last_marked DESC, date_entered DESC, updated DESC"; + } + } else if ($feed == -2) { // published virtual feed OR labels category if (!$cat_view) { @@ -2281,7 +2377,10 @@ $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; $allow_archived = true; - if (!$override_order) $override_order = "last_read 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,"; @@ -2303,17 +2402,17 @@ $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 @@ -2333,14 +2432,10 @@ $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) { @@ -2383,7 +2478,7 @@ } // proper override_order applied above - if ($vfeed_query_part && get_pref($link, 'VFEED_GROUP_BY_FEED', $owner_uid)) { + if ($vfeed_query_part && !$ignore_vfeed_group && get_pref($link, 'VFEED_GROUP_BY_FEED', $owner_uid)) { if (!$override_order) { $order_by = "ttrss_feeds.title, $order_by"; } else { @@ -2413,11 +2508,11 @@ num_comments, comments, int_id, + hide_images, unread,feed_id,marked,published,link,last_read,orig_feed_id, - ".SUBSTRING_FOR_DATE."(last_read,1,19) as last_read_noms, + last_marked, last_published, $vfeed_query_part $content_query_part - ".SUBSTRING_FOR_DATE."(updated,1,19) as updated_noms, author,score FROM $from_qpart @@ -2456,11 +2551,11 @@ "label_cache," . "link," . "last_read," . - SUBSTRING_FOR_DATE . "(last_read,1,19) as last_read_noms," . + "(SELECT hide_images FROM ttrss_feeds WHERE id = feed_id) AS hide_images," . + "last_marked, last_published, " . $since_id_part . $vfeed_query_part . $content_query_part . - SUBSTRING_FOR_DATE . "(updated,1,19) as updated_noms," . "score "; $feed_kind = "Tags"; @@ -2510,18 +2605,11 @@ } - function sanitize($link, $str, $force_strip_tags = false, $owner = false, $site_url = false) { + function sanitize($link, $str, $force_remove_images = false, $owner = false, $site_url = false) { if (!$owner) $owner = $_SESSION["uid"]; $res = trim($str); if (!$res) return ''; - $config = array('safe' => 1, 'deny_attribute' => 'style, width, height, class, id', 'comment' => 1, 'cdata' => 1); - $res = htmLawed($res, $config); - - if (get_pref($link, "STRIP_IMAGES", $owner)) { - $res = preg_replace('/]+>/is', '', $res); - } - if (strpos($res, "href=") === false) $res = rewrite_urls($res); @@ -2538,7 +2626,6 @@ $xpath = new DOMXPath($doc); $entries = $xpath->query('(//a[@href]|//img[@src])'); - $br_inserted = 0; foreach ($entries as $entry) { @@ -2548,250 +2635,118 @@ $entry->setAttribute('href', rewrite_relative_url($site_url, $entry->getAttribute('href'))); - if ($entry->hasAttribute('src')) - if (preg_match('/^image.php\?i=[a-z0-9]+$/', $entry->getAttribute('src')) == 0) - $entry->setAttribute('src', - rewrite_relative_url($site_url, $entry->getAttribute('src'))); - } + if ($entry->hasAttribute('src')) { + $src = rewrite_relative_url($site_url, $entry->getAttribute('src')); - if (strtolower($entry->nodeName) == "a") { - $entry->setAttribute("target", "_blank"); - } + $cached_filename = CACHE_DIR . '/images/' . sha1($src) . '.png'; - if (strtolower($entry->nodeName) == "img" && !$br_inserted) { - $br = $doc->createElement("br"); + if (file_exists($cached_filename)) { + $src = SELF_URL_PATH . '/image.php?hash=' . sha1($src); + } - if ($entry->parentNode->nextSibling) { - $entry->parentNode->insertBefore($br, $entry->nextSibling); - $br_inserted = 1; + $entry->setAttribute('src', $src); } - } - } - - $node = $doc->getElementsByTagName('body')->item(0); + if ($entry->nodeName == 'img') { + if (($owner && get_pref($link, "STRIP_IMAGES", $owner)) || + $force_remove_images || $_SESSION["bw_limit"]) { - return $doc->saveXML($node, LIBXML_NOEMPTYTAG); - } + $p = $doc->createElement('p'); - /** - * Send by mail a digest of last articles. - * - * @param mixed $link The database connection. - * @param integer $limit The maximum number of articles by digest. - * @return boolean Return false if digests are not enabled. - */ - function send_headlines_digests($link, $debug = false) { + $a = $doc->createElement('a'); + $a->setAttribute('href', $entry->getAttribute('src')); - require_once 'lib/phpmailer/class.phpmailer.php'; + $a->appendChild(new DOMText($entry->getAttribute('src'))); + $a->setAttribute('target', '_blank'); - $user_limit = 15; // amount of users to process (e.g. emails to send out) - $limit = 1000; // maximum amount of headlines to include + $p->appendChild($a); - if ($debug) _debug("Sending digests, batch of max $user_limit users, headline limit = $limit"); + $entry->parentNode->replaceChild($p, $entry); + } + } + } - if (DB_TYPE == "pgsql") { - $interval_query = "last_digest_sent < NOW() - INTERVAL '1 days'"; - } else if (DB_TYPE == "mysql") { - $interval_query = "last_digest_sent < DATE_SUB(NOW(), INTERVAL 1 DAY)"; + if (strtolower($entry->nodeName) == "a") { + $entry->setAttribute("target", "_blank"); + } } - $result = db_query($link, "SELECT id,email FROM ttrss_users - WHERE email != '' AND (last_digest_sent IS NULL OR $interval_query)"); - - while ($line = db_fetch_assoc($result)) { - - if (get_pref($link, 'DIGEST_ENABLE', $line['id'], false)) { - $preferred_ts = strtotime(get_pref($link, 'DIGEST_PREFERRED_TIME', $line['id'], '00:00')); - - // try to send digests within 2 hours of preferred time - if ($preferred_ts && time() >= $preferred_ts && - time() - $preferred_ts <= 7200) { - - if ($debug) print "Sending digest for UID:" . $line['id'] . " - " . $line["email"] . " ... "; - - $do_catchup = get_pref($link, 'DIGEST_CATCHUP', $line['id'], false); - - global $tz_offset; - - // reset tz_offset global to prevent tz cache clash between users - $tz_offset = -1; - - $tuple = prepare_headlines_digest($link, $line["id"], 1, $limit); - $digest = $tuple[0]; - $headlines_count = $tuple[1]; - $affected_ids = $tuple[2]; - $digest_text = $tuple[3]; - - if ($headlines_count > 0) { - - $mail = new PHPMailer(); - - $mail->PluginDir = "lib/phpmailer/"; - $mail->SetLanguage("en", "lib/phpmailer/language/"); - - $mail->CharSet = "UTF-8"; - - $mail->From = SMTP_FROM_ADDRESS; - $mail->FromName = SMTP_FROM_NAME; - $mail->AddAddress($line["email"], $line["login"]); - - if (SMTP_HOST) { - $mail->Host = SMTP_HOST; - $mail->Mailer = "smtp"; - $mail->SMTPAuth = SMTP_LOGIN != ''; - $mail->Username = SMTP_LOGIN; - $mail->Password = SMTP_PASSWORD; - } - - $mail->IsHTML(true); - $mail->Subject = DIGEST_SUBJECT; - $mail->Body = $digest; - $mail->AltBody = $digest_text; + $entries = $xpath->query('//iframe'); + foreach ($entries as $entry) { + $entry->setAttribute('sandbox', 'allow-scripts'); - $rc = $mail->Send(); + } - if (!$rc && $debug) print "ERROR: " . $mail->ErrorInfo; + $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 ($debug) print "RC=$rc\n"; + if ($_SESSION['hasSandbox']) $allowed_elements[] = 'iframe'; - if ($rc && $do_catchup) { - if ($debug) print "Marking affected articles as read...\n"; - catchupArticlesById($link, $affected_ids, 0, $line["id"]); - } - } else { - if ($debug) print "No headlines\n"; - } + $disallowed_attributes = array('id', 'style', 'class'); - db_query($link, "UPDATE ttrss_users SET last_digest_sent = NOW() - WHERE id = " . $line["id"]); + global $pluginhost; + if (isset($pluginhost)) { + foreach ($pluginhost->get_hooks($pluginhost::HOOK_SANITIZE) as $plugin) { + $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; } } } - if ($debug) _debug("All done."); - + $doc->removeChild($doc->firstChild); //remove doctype + $doc = strip_harmful_tags($doc, $allowed_elements, $disallowed_attributes); + $res = $doc->saveHTML(); + return $res; } - function prepare_headlines_digest($link, $user_id, $days = 1, $limit = 1000) { - - require_once "lib/MiniTemplator.class.php"; - - $tpl = new MiniTemplator; - $tpl_t = new MiniTemplator; - - $tpl->readTemplateFromFile("templates/digest_template_html.txt"); - $tpl_t->readTemplateFromFile("templates/digest_template.txt"); - - $user_tz_string = get_pref($link, 'USER_TIMEZONE', $user_id); - $local_ts = convert_timestamp(time(), 'UTC', $user_tz_string); - - $tpl->setVariable('CUR_DATE', date('Y/m/d', $local_ts)); - $tpl->setVariable('CUR_TIME', date('G:i', $local_ts)); - - $tpl_t->setVariable('CUR_DATE', date('Y/m/d', $local_ts)); - $tpl_t->setVariable('CUR_TIME', date('G:i', $local_ts)); - - $affected_ids = array(); - - if (DB_TYPE == "pgsql") { - $interval_query = "ttrss_entries.date_updated > NOW() - INTERVAL '$days days'"; - } else if (DB_TYPE == "mysql") { - $interval_query = "ttrss_entries.date_updated > DATE_SUB(NOW(), INTERVAL $days DAY)"; - } - - $result = db_query($link, "SELECT ttrss_entries.title, - ttrss_feeds.title AS feed_title, - COALESCE(ttrss_feed_categories.title, '".__('Uncategorized')."') AS cat_title, - date_updated, - ttrss_user_entries.ref_id, - link, - score, - content, - ".SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated - FROM - ttrss_user_entries,ttrss_entries,ttrss_feeds - LEFT JOIN - ttrss_feed_categories ON (cat_id = ttrss_feed_categories.id) - WHERE - ref_id = ttrss_entries.id AND feed_id = ttrss_feeds.id - AND include_in_digest = true - AND $interval_query - AND ttrss_user_entries.owner_uid = $user_id - AND unread = true - AND score >= 0 - ORDER BY ttrss_feed_categories.title, ttrss_feeds.title, score DESC, date_updated DESC - LIMIT $limit"); - - $cur_feed_title = ""; - - $headlines_count = db_num_rows($result); - - $headlines = array(); - - while ($line = db_fetch_assoc($result)) { - array_push($headlines, $line); - } - - for ($i = 0; $i < sizeof($headlines); $i++) { - - $line = $headlines[$i]; + function strip_harmful_tags($doc, $allowed_elements, $disallowed_attributes) { + $entries = $doc->getElementsByTagName("*"); - array_push($affected_ids, $line["ref_id"]); + foreach ($entries as $entry) { + if (!in_array($entry->nodeName, $allowed_elements)) { + $entry->parentNode->removeChild($entry); + } - $updated = make_local_datetime($link, $line['last_updated'], false, - $user_id); + if ($entry->hasAttributes()) { + $attrs_to_remove = array(); -/* if ($line["score"] != 0) { - if ($line["score"] > 0) $line["score"] = '+' . $line["score"]; + foreach ($entry->attributes as $attr) { - $line["title"] .= " (".$line['score'].")"; - } */ + if (strpos($attr->nodeName, 'on') === 0) { + array_push($attrs_to_remove, $attr); + } - if (get_pref($link, 'ENABLE_FEED_CATS', $user_id)) { - $line['feed_title'] = $line['cat_title'] . " / " . $line['feed_title']; - } + if (in_array($attr->nodeName, $disallowed_attributes)) { + array_push($attrs_to_remove, $attr); + } + } - $tpl->setVariable('FEED_TITLE', $line["feed_title"]); - $tpl->setVariable('ARTICLE_TITLE', $line["title"]); - $tpl->setVariable('ARTICLE_LINK', $line["link"]); - $tpl->setVariable('ARTICLE_UPDATED', $updated); - $tpl->setVariable('ARTICLE_EXCERPT', - truncate_string(strip_tags($line["content"]), 300)); -// $tpl->setVariable('ARTICLE_CONTENT', -// strip_tags($article_content)); - - $tpl->addBlock('article'); - - $tpl_t->setVariable('FEED_TITLE', $line["feed_title"]); - $tpl_t->setVariable('ARTICLE_TITLE', $line["title"]); - $tpl_t->setVariable('ARTICLE_LINK', $line["link"]); - $tpl_t->setVariable('ARTICLE_UPDATED', $updated); -// $tpl_t->setVariable('ARTICLE_EXCERPT', -// truncate_string(strip_tags($line["excerpt"]), 100)); - - $tpl_t->addBlock('article'); - - if ($headlines[$i]['feed_title'] != $headlines[$i+1]['feed_title']) { - $tpl->addBlock('feed'); - $tpl_t->addBlock('feed'); + foreach ($attrs_to_remove as $attr) { + $entry->removeAttributeNode($attr); + } } - } - $tpl->addBlock('digest'); - $tpl->generateOutputToString($tmp); - - $tpl_t->addBlock('digest'); - $tpl_t->generateOutputToString($tmp_t); - - return array($tmp, $headlines_count, $affected_ids, $tmp_t); + return $doc; } function check_for_update($link) { if (CHECK_FOR_NEW_VERSION && $_SESSION['access_level'] >= 10) { - $version_url = "http://tt-rss.org/version.php?ver=" . VERSION; + $version_url = "http://tt-rss.org/version.php?ver=" . VERSION . + "&iid=" . sha1(SELF_URL_PATH); $version_data = @fetch_file_contents($version_url); @@ -2808,7 +2763,10 @@ return false; } - function markArticlesById($link, $ids, $cmode) { + function catchupArticlesById($link, $ids, $cmode, $owner_uid = false) { + + if (!$owner_uid) $owner_uid = $_SESSION["uid"]; + if (count($ids) == 0) return; $tmp_ids = array(); @@ -2820,119 +2778,31 @@ if ($cmode == 0) { db_query($link, "UPDATE ttrss_user_entries SET - marked = false,last_read = NOW() - WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]); + unread = false,last_read = NOW() + WHERE ($ids_qpart) AND owner_uid = $owner_uid"); } else if ($cmode == 1) { db_query($link, "UPDATE ttrss_user_entries SET - marked = true - WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]); + unread = true + WHERE ($ids_qpart) AND owner_uid = $owner_uid"); } else { db_query($link, "UPDATE ttrss_user_entries SET - marked = NOT marked,last_read = NOW() - WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]); + unread = NOT unread,last_read = NOW() + WHERE ($ids_qpart) AND owner_uid = $owner_uid"); } - } - function publishArticlesById($link, $ids, $cmode) { + /* update ccache */ - $tmp_ids = array(); - - foreach ($ids as $id) { - array_push($tmp_ids, "ref_id = '$id'"); - } - - $ids_qpart = join(" OR ", $tmp_ids); - - if ($cmode == 0) { - db_query($link, "UPDATE ttrss_user_entries SET - published = false,last_read = NOW() - WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]); - } else if ($cmode == 1) { - db_query($link, "UPDATE ttrss_user_entries SET - published = true,last_read = NOW() - WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]); - } else { - db_query($link, "UPDATE ttrss_user_entries SET - published = NOT published,last_read = NOW() - WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]); - } - - if (PUBSUBHUBBUB_HUB) { - $rss_link = get_self_url_prefix() . - "/public.php?op=rss&id=-2&key=" . - get_feed_access_key($link, -2, false); - - $p = new Publisher(PUBSUBHUBBUB_HUB); - - $pubsub_result = $p->publish_update($rss_link); - } - } - - function catchupArticlesById($link, $ids, $cmode, $owner_uid = false) { - - if (!$owner_uid) $owner_uid = $_SESSION["uid"]; - if (count($ids) == 0) return; - - $tmp_ids = array(); - - foreach ($ids as $id) { - array_push($tmp_ids, "ref_id = '$id'"); - } - - $ids_qpart = join(" OR ", $tmp_ids); - - if ($cmode == 0) { - db_query($link, "UPDATE ttrss_user_entries SET - unread = false,last_read = NOW() - WHERE ($ids_qpart) AND owner_uid = $owner_uid"); - } else if ($cmode == 1) { - db_query($link, "UPDATE ttrss_user_entries SET - unread = true - WHERE ($ids_qpart) AND owner_uid = $owner_uid"); - } else { - db_query($link, "UPDATE ttrss_user_entries SET - unread = NOT unread,last_read = NOW() - WHERE ($ids_qpart) AND owner_uid = $owner_uid"); - } - - /* update ccache */ - - $result = db_query($link, "SELECT DISTINCT feed_id FROM ttrss_user_entries - WHERE ($ids_qpart) AND owner_uid = $owner_uid"); + $result = db_query($link, "SELECT DISTINCT feed_id FROM ttrss_user_entries + WHERE ($ids_qpart) AND owner_uid = $owner_uid"); while ($line = db_fetch_assoc($result)) { ccache_update($link, $line["feed_id"], $owner_uid); } } - function catchupArticleById($link, $id, $cmode) { - - if ($cmode == 0) { - db_query($link, "UPDATE ttrss_user_entries SET - unread = false,last_read = NOW() - WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]); - } else if ($cmode == 1) { - db_query($link, "UPDATE ttrss_user_entries SET - unread = true - WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]); - } else { - db_query($link, "UPDATE ttrss_user_entries SET - unread = NOT unread,last_read = NOW() - WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]); - } - - $feed_id = getArticleFeed($link, $id); - ccache_update($link, $feed_id, $_SESSION["uid"]); - } - - function make_guid_from_title($title) { - return preg_replace("/[ \"\',.:;]/", "-", - mb_strtolower(strip_tags($title), 'utf-8')); - } - function get_article_tags($link, $id, $owner_uid = 0, $tag_cache = false) { - $a_id = db_escape_string($id); + $a_id = db_escape_string($link, $id); if (!$owner_uid) $owner_uid = $_SESSION["uid"]; @@ -2967,7 +2837,7 @@ /* update the cache */ - $tags_str = db_escape_string(join(",", $tags)); + $tags_str = db_escape_string($link, join(",", $tags)); db_query($link, "UPDATE ttrss_user_entries SET tag_cache = '$tags_str' WHERE ref_id = '$id' @@ -2997,15 +2867,8 @@ return true; } - function render_login_form($link, $form_id = 0) { - switch ($form_id) { - case 0: - require_once "login_form.php"; - break; - case 1: - require_once "mobile/login_form.php"; - break; - } + function render_login_form($link) { + require_once "login_form.php"; exit; } @@ -3021,19 +2884,19 @@ function format_warning($msg, $id = "") { global $link; return "
- $msg
"; +
$msg
"; } function format_notice($msg, $id = "") { global $link; return "
- $msg
"; +
$msg
"; } function format_error($msg, $id = "") { global $link; return "
- $msg
"; +
$msg
"; } function print_notice($msg) { @@ -3058,6 +2921,8 @@ $entry = ""; + $url = htmlspecialchars($url); + if (strpos($ctype, "audio/") === 0) { if ($_SESSION["hasAudio"] && (strpos($ctype, "ogg") !== false || @@ -3066,8 +2931,8 @@ $id = 'AUDIO-' . uniqid(); - $entry .= "