X-Git-Url: https://git.wh0rd.org/?a=blobdiff_plain;ds=sidebyside;f=include%2Ffunctions.php;h=307f662009b14dc83c304a86477f4a5e57c96508;hb=583dbc56953afbad6ccae5e3add15160e23b68e4;hp=2120a96b92bba3c6142ff0dcd6fd0cfa4c4d7a1a;hpb=5035e91ece0a3fc0692e4640200fe9ba3742dd32;p=tt-rss.git diff --git a/include/functions.php b/include/functions.php index 2120a96b..307f6620 100644 --- a/include/functions.php +++ b/include/functions.php @@ -1,8 +1,12 @@ "Detect automatically", "ca_CA" => "Català", + "cs_CZ" => "Česky", "en_US" => "English", "es_ES" => "Español", "de_DE" => "Deutsch", @@ -51,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", @@ -73,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") { + if ($_SESSION["language"] && $_SESSION["language"] != "auto") { $lang = $_SESSION["language"]; } @@ -87,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"); @@ -109,7 +109,6 @@ 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 /** @@ -279,18 +288,27 @@ } } - 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 (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, true); + 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); @@ -324,6 +342,8 @@ $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); @@ -338,11 +358,13 @@ 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]; } @@ -350,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"]; @@ -459,6 +484,8 @@ else $sel = ""; + $v = trim($v); + print ""; } print ""; @@ -472,6 +499,8 @@ else $sel = ""; + $v = trim($v); + print ""; } @@ -500,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"; @@ -528,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 @@ -559,7 +591,6 @@ function authenticate_user($link, $login, $password, $check_only = false) { if (!SINGLE_USER_MODE) { - $user_id = false; global $pluginhost; @@ -574,6 +605,8 @@ } if ($user_id && !$check_only) { + @session_start(); + $_SESSION["uid"] = $user_id; $result = db_query($link, "SELECT login,access_level,pwd_hash FROM ttrss_users @@ -730,10 +763,11 @@ } } - function login_sequence($link, $login_form = 0) { + function login_sequence($link) { $_SESSION["prefs_cache"] = false; if (SINGLE_USER_MODE) { + @session_start(); authenticate_user($link, "admin", null); cache_prefs($link); load_user_plugins($link, $_SESSION["uid"]); @@ -746,12 +780,13 @@ 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) { @@ -762,7 +797,21 @@ if ($_SESSION["uid"]) { cache_prefs($link); load_user_plugins($link, $_SESSION["uid"]); + + /* cleanup ccache */ + + 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"); + + 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"); + } + } } @@ -774,11 +823,6 @@ } } - // Deprecated, TODO: remove - function theme_image($link, $filename) { - return $filename; - } - function convert_timestamp($timestamp, $source_tz, $dest_tz) { try { @@ -900,7 +944,7 @@ } } - if (db_escape_string("testTEST") != "testTEST") { + if (db_escape_string($link, "testTEST") != "testTEST") { $error_code = 12; } @@ -965,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) { @@ -987,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 unread = true AND owner_uid = $owner_uid"); } else if ($feed == -2) { @@ -995,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"); } @@ -1004,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 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"); } @@ -1021,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 unread = true AND owner_uid = $owner_uid"); } @@ -1054,18 +1094,17 @@ 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"); } @@ -1075,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"); @@ -1083,7 +1122,7 @@ 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"); @@ -1272,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 @@ -1307,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); @@ -1401,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; } @@ -1419,7 +1473,7 @@ while ($line = db_fetch_assoc($result)) { - $id = -$line["id"] - 11; + $id = label_to_feed_id($line["id"]); $label_name = $line["caption"]; $count = $line["unread"]; @@ -1508,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; @@ -1726,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 @@ -1764,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")) @@ -1789,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"); @@ -1813,11 +1867,6 @@ function make_init_params($link) { $params = array(); - $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.svg"); - $params["sign_info"] = theme_image($link, "images/sign_info.svg"); - 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", @@ -1832,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"]); @@ -1877,8 +1927,9 @@ "article_scroll_up" => __("Scroll up"), "select_article_cursor" => __("Select article under cursor"), "email_article" => __("Email article"), - "close_article" => __("Close article"), - "toggle_widescreen" => __("Toggle widescreen mode")), + "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"), @@ -1896,7 +1947,8 @@ "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"), @@ -1938,7 +1990,10 @@ "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( @@ -1957,6 +2012,7 @@ "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( @@ -2012,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"); @@ -2051,7 +2110,7 @@ return $data; } - function search_to_sql($link, $search, $match_on) { + function search_to_sql($link, $search) { $search_query_part = ""; @@ -2098,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%'))"); } } @@ -2141,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, $ignore_vfeed_group = 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"]; @@ -2158,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 "; } @@ -2207,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 "; + } } @@ -2226,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; } @@ -2310,7 +2366,9 @@ $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 @@ -2319,7 +2377,10 @@ $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,"; @@ -2341,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 @@ -2371,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) { @@ -2451,12 +2508,11 @@ num_comments, comments, int_id, + 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 @@ -2495,12 +2551,11 @@ "label_cache," . "link," . "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"; @@ -2550,15 +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 ''; - if (get_pref($link, "STRIP_IMAGES", $owner)) { - $res = preg_replace('/]+>/is', '', $res); - } - if (strpos($res, "href=") === false) $res = rewrite_urls($res); @@ -2584,10 +2635,35 @@ $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')); + + $cached_filename = CACHE_DIR . '/images/' . sha1($src) . '.png'; + + if (file_exists($cached_filename)) { + $src = SELF_URL_PATH . '/image.php?hash=' . sha1($src); + } + + $entry->setAttribute('src', $src); + } + + if ($entry->nodeName == 'img') { + if (($owner && get_pref($link, "STRIP_IMAGES", $owner)) || + $force_remove_images || $_SESSION["bw_limit"]) { + + $p = $doc->createElement('p'); + + $a = $doc->createElement('a'); + $a->setAttribute('href', $entry->getAttribute('src')); + + $a->appendChild(new DOMText($entry->getAttribute('src'))); + $a->setAttribute('target', '_blank'); + + $p->appendChild($a); + + $entry->parentNode->replaceChild($p, $entry); + } + } } if (strtolower($entry->nodeName) == "a") { @@ -2595,16 +2671,76 @@ } } - //$node = $doc->getElementsByTagName('body')->item(0); + $entries = $xpath->query('//iframe'); + foreach ($entries as $entry) { + $entry->setAttribute('sandbox', 'allow-scripts'); + + } + + $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) { + $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, $allowed_elements, $disallowed_attributes); $res = $doc->saveHTML(); + return $res; + } - $config = array('safe' => 1, 'deny_attribute' => 'style, width, height, class, id', 'comment' => 1, 'cdata' => 1, 'balance' => 0); - $spec = 'img=width,height'; - $res = htmLawed($res, $config, $spec); + function strip_harmful_tags($doc, $allowed_elements, $disallowed_attributes) { + $entries = $doc->getElementsByTagName("*"); - return $res; + foreach ($entries as $entry) { + if (!in_array($entry->nodeName, $allowed_elements)) { + $entry->parentNode->removeChild($entry); + } + + if ($entry->hasAttributes()) { + $attrs_to_remove = array(); + + foreach ($entry->attributes as $attr) { + + if (strpos($attr->nodeName, 'on') === 0) { + array_push($attrs_to_remove, $attr); + } + + if (in_array($attr->nodeName, $disallowed_attributes)) { + array_push($attrs_to_remove, $attr); + } + } + + foreach ($attrs_to_remove as $attr) { + $entry->removeAttributeNode($attr); + } + } + } + + return $doc; } function check_for_update($link) { @@ -2666,7 +2802,7 @@ 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"]; @@ -2701,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' @@ -2731,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; } @@ -2755,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) { @@ -2792,6 +2921,8 @@ $entry = ""; + $url = htmlspecialchars($url); + if (strpos($ctype, "audio/") === 0) { if ($_SESSION["hasAudio"] && (strpos($ctype, "ogg") !== false || @@ -2818,7 +2949,8 @@ "; } - if ($entry) $entry .= " " . basename($url); + if ($entry) $entry .= "  " . basename($url) . ""; return $entry; @@ -2863,6 +2995,7 @@ $result = db_query($link, "SELECT id,title,link,content,feed_id,comments,int_id, ".SUBSTRING_FOR_DATE."(updated,1,16) as updated, (SELECT site_url FROM ttrss_feeds WHERE id = feed_id) as site_url, + (SELECT hide_images FROM ttrss_feeds WHERE id = feed_id) as hide_images, num_comments, tag_cache, author, @@ -2911,14 +3044,9 @@ Tiny Tiny RSS - ".$line["title"]." - "; + "; } - $title_escaped = htmlspecialchars($line['title']); - - $rv['content'] .= "
" . - strip_tags($line['title']) . "
"; - $rv['content'] .= "
"; $rv['content'] .= "
"; @@ -2939,8 +3067,8 @@ title=\"".htmlspecialchars($line['title'])."\" href=\"" . htmlspecialchars($line["link"]) . "\">" . - $line["title"] . - "$entry_author
"; + $line["title"] . "" . + "$entry_author
"; } else { $rv['content'] .= "
" . $line["title"] . "$entry_author
"; } @@ -2953,7 +3081,7 @@ if (!$entry_comments) $entry_comments = " "; # placeholder $rv['content'] .= "
- Tags "; if (!$zoom_mode) { @@ -3016,35 +3144,10 @@ $rv['content'] .= "
"; - // N-grams - - if (DB_TYPE == "pgsql" and defined('_NGRAM_TITLE_RELATED_THRESHOLD')) { - - $ngram_result = db_query($link, "SELECT id,title FROM - ttrss_entries,ttrss_user_entries - WHERE ref_id = id AND updated >= NOW() - INTERVAL '7 day' - AND similarity(title, '$title_escaped') >= "._NGRAM_TITLE_RELATED_THRESHOLD." - AND title != '$title_escaped' - AND owner_uid = $owner_uid"); - - if (db_num_rows($ngram_result) > 0) { - $rv['content'] .= "
". - "" . __('Related').""; - $rv['content'] .= "
"; - - while ($nline = db_fetch_assoc($ngram_result)) { - $rv['content'] .= "
".$nline['title']."
"; - - } - $rv['content'] .= "

+ "; $rv['content'] .= ""; @@ -3131,7 +3234,7 @@ $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 @@ -3148,6 +3251,7 @@ $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); } @@ -3171,6 +3275,7 @@ $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; @@ -3436,7 +3541,7 @@ if (db_num_rows($result) == 1) { return db_fetch_result($result, 0, "access_key"); } else { - $key = db_escape_string(sha1(uniqid(rand(), true))); + $key = db_escape_string($link, sha1(uniqid(rand(), true))); $result = db_query($link, "INSERT INTO ttrss_access_keys (access_key, feed_id, is_cat, owner_uid) @@ -3507,7 +3612,7 @@ } function format_article_enclosures($link, $id, $always_display_enclosures, - $article_content) { + $article_content, $hide_images = false) { $result = get_article_enclosures($link, $id); $rv = ''; @@ -3548,7 +3653,7 @@ array_push($entries, $entry); } - if (!get_pref($link, "STRIP_IMAGES")) { + if ($_SESSION['uid'] && !get_pref($link, "STRIP_IMAGES") && !$_SESSION["bw_limit"]) { if ($always_display_enclosures || !preg_match("/

"; + if (!$hide_images) { + $rv .= "

\"".htmlspecialchars($entry["filename"])."\"

"; + } else { + $rv .= "

" .htmlspecialchars($entry["url"]) . "

"; + } } } } @@ -3572,13 +3683,15 @@ $rv .= "
"; } - $rv .= "
". - "" . __('Attachments').""; - $rv .= "
"; + $rv .= ""; } return $rv; @@ -3697,7 +3810,6 @@ 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); @@ -3708,8 +3820,6 @@ $limit -= $limit_part; } - print "\n"; - return $tags_deleted; } @@ -3784,9 +3894,9 @@ if ($regexp_valid) { - $rule['reg_exp'] = db_escape_string($rule['reg_exp']); + $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'] . "')"; @@ -3814,8 +3924,10 @@ break; } + if (isset($rule['inverse'])) $qpart = "NOT ($qpart)"; + if (isset($rule["feed_id"]) && $rule["feed_id"] > 0) { - $qpart .= " AND feed_id = " . db_escape_string($rule["feed_id"]); + $qpart .= " AND feed_id = " . db_escape_string($link, $rule["feed_id"]); } if (isset($rule["cat_id"])) { @@ -3840,10 +3952,14 @@ } 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')) { @@ -3907,6 +4023,55 @@ return in_array($interface, class_implements($class)); } + function geturl($url){ + + (function_exists('curl_init')) ? '' : die('cURL Must be installed for geturl function to work. Ask your host to enable it or uncomment extension=php_curl.dll in php.ini'); + + $curl = curl_init(); + $header[0] = "Accept: text/xml,application/xml,application/xhtml+xml,"; + $header[0] .= "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; + $header[] = "Cache-Control: max-age=0"; + $header[] = "Connection: keep-alive"; + $header[] = "Keep-Alive: 300"; + $header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7"; + $header[] = "Accept-Language: en-us,en;q=0.5"; + $header[] = "Pragma: "; + + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0 Firefox/5.0'); + curl_setopt($curl, CURLOPT_HTTPHEADER, $header); + curl_setopt($curl, CURLOPT_HEADER, true); + curl_setopt($curl, CURLOPT_REFERER, $url); + curl_setopt($curl, CURLOPT_ENCODING, 'gzip,deflate'); + curl_setopt($curl, CURLOPT_AUTOREFERER, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); //CURLOPT_FOLLOWLOCATION Disabled... + curl_setopt($curl, CURLOPT_TIMEOUT, 60); + + $html = curl_exec($curl); + + $status = curl_getinfo($curl); + curl_close($curl); + + if($status['http_code']!=200){ + if($status['http_code'] == 301 || $status['http_code'] == 302) { + list($header) = explode("\r\n\r\n", $html, 2); + $matches = array(); + preg_match("/(Location:|URI:)[^(\n)]*/", $header, $matches); + $url = trim(str_replace($matches[1],"",$matches[0])); + $url_parsed = parse_url($url); + return (isset($url_parsed))? geturl($url, $referer):''; + } + $oline=''; + foreach($status as $key=>$eline){$oline.='['.$key.']'.$eline.' ';} + $line =$oline." \r\n ".$url."\r\n-----------------\r\n"; +# $handle = @fopen('./curl.error.log', 'a'); +# fwrite($handle, $line); + return FALSE; + } + return $url; + } + function get_minified_js($files) { require_once 'lib/jshrink/Minifier.php'; @@ -3935,4 +4100,83 @@ return $rv; } + function stylesheet_tag($filename) { + $timestamp = filemtime($filename); + + echo "\n"; + } + + function javascript_tag($filename) { + $query = ""; + + if (!(strpos($filename, "?") === FALSE)) { + $query = substr($filename, strpos($filename, "?")+1); + $filename = substr($filename, 0, strpos($filename, "?")); + } + + $timestamp = filemtime($filename); + + if ($query) $timestamp .= "&$query"; + + echo "\n"; + } + + function calculate_dep_timestamp() { + $files = array_merge(glob("js/*.js"), glob("*.css")); + + $max_ts = -1; + + foreach ($files as $file) { + if (filemtime($file) > $max_ts) $max_ts = filemtime($file); + } + + 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); + } + ?>