diff options
Diffstat (limited to 'include/functions.php')
-rw-r--r-- | include/functions.php | 1744 |
1 files changed, 1034 insertions, 710 deletions
diff --git a/include/functions.php b/include/functions.php index f17828d1d..149809a35 100644 --- a/include/functions.php +++ b/include/functions.php @@ -1,20 +1,16 @@ <?php define('EXPECTED_CONFIG_VERSION', 26); - define('SCHEMA_VERSION', 104); + define('SCHEMA_VERSION', 120); - $fetch_last_error = false; - $pluginhost = false; - - function __autoload($class) { - $class_file = str_replace("_", "/", strtolower(basename($class))); - - $file = dirname(__FILE__)."/../classes/$class_file.php"; + define('LABEL_BASE_INDEX', -1024); + define('PLUGIN_FEED_BASE_INDEX', -128); - if (file_exists($file)) { - require $file; - } + define('COOKIE_LIFETIME_LONG', 86400*365); - } + $fetch_last_error = false; + $fetch_last_error_code = false; + $fetch_last_content_type = false; + $fetch_curl_used = false; mb_internal_encoding("UTF-8"); date_default_timezone_set('UTC'); @@ -26,14 +22,37 @@ require_once 'config.php'; + /** + * Define a constant if not already defined + * + * @param string $name The constant name. + * @param mixed $value The constant value. + * @access public + * @return boolean True if defined successfully or not. + */ + function define_default($name, $value) { + defined($name) or define($name, $value); + } + + ///// Some defaults that you can override in config.php ////// + + define_default('FEED_FETCH_TIMEOUT', 45); + // How may seconds to wait for response when requesting feed from a site + define_default('FEED_FETCH_NO_CACHE_TIMEOUT', 15); + // How may seconds to wait for response when requesting feed from a + // site when that feed wasn't cached before + define_default('FILE_FETCH_TIMEOUT', 45); + // Default timeout when fetching files from remote sites + define_default('FILE_FETCH_CONNECT_TIMEOUT', 15); + // How many seconds to wait for initial response from website when + // fetching files from remote sites + if (DB_TYPE == "pgsql") { define('SUBSTRING_FOR_DATE', 'SUBSTRING_FOR_DATE'); } else { define('SUBSTRING_FOR_DATE', 'SUBSTRING'); } - define('THEME_VERSION_REQUIRED', 1.1); - /** * Return available translations names. * @@ -44,6 +63,7 @@ $tr = array( "auto" => "Detect automatically", "ca_CA" => "Català", + "cs_CZ" => "Česky", "en_US" => "English", "es_ES" => "Español", "de_DE" => "Deutsch", @@ -51,11 +71,15 @@ "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", - "zh_CN" => "Simplified Chinese"); + "zh_CN" => "Simplified Chinese", + "sv_SE" => "Svenska", + "fi_FI" => "Suomi"); return $tr; } @@ -73,11 +97,12 @@ $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"]; + if ($_SESSION["uid"] && get_schema_version() >= 120) { + $pref_lang = get_pref("USER_LANGUAGE", $_SESSION["uid"]); + + if ($pref_lang) { + $lang = $pref_lang; + } } if ($lang) { @@ -87,19 +112,13 @@ _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"); } } - startup_gettext(); - require_once 'db-prefs.php'; require_once 'version.php'; require_once 'ccache.php'; @@ -109,10 +128,7 @@ 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'); $schema_version = false; /** @@ -121,15 +137,26 @@ * @param string $msg The debug message. * @return void */ - function _debug($msg) { - if (defined('QUIET') && QUIET) { - return; - } + function _debug($msg, $show = true) { + $ts = strftime("%H:%M:%S", time()); if (function_exists('posix_getpid')) { $ts = "$ts/" . posix_getpid(); } - print "[$ts] $msg\n"; + + if ($show && !(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 /** @@ -142,13 +169,13 @@ * @access public * @return void */ - function purge_feed($link, $feed_id, $purge_interval, $debug = false) { + function purge_feed($feed_id, $purge_interval, $debug = false) { - if (!$purge_interval) $purge_interval = feed_purge_interval($link, $feed_id); + if (!$purge_interval) $purge_interval = feed_purge_interval($feed_id); $rows = -1; - $result = db_query($link, + $result = db_query( "SELECT owner_uid FROM ttrss_feeds WHERE id = '$feed_id'"); $owner_uid = false; @@ -159,7 +186,7 @@ if ($purge_interval == -1 || !$purge_interval) { if ($owner_uid) { - ccache_update($link, $feed_id, $owner_uid); + ccache_update($feed_id, $owner_uid); } return; } @@ -167,7 +194,7 @@ if (!$owner_uid) return; if (FORCE_ARTICLE_PURGE == 0) { - $purge_unread = get_pref($link, "PURGE_UNREAD_ARTICLES", + $purge_unread = get_pref("PURGE_UNREAD_ARTICLES", $owner_uid, false); } else { $purge_unread = true; @@ -177,11 +204,11 @@ if (!$purge_unread) $query_limit = " unread = false AND "; if (DB_TYPE == "pgsql") { - $pg_version = get_pgsql_version($link); + $pg_version = get_pgsql_version(); if (preg_match("/^7\./", $pg_version) || preg_match("/^8\.0/", $pg_version)) { - $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE + $result = db_query("DELETE FROM ttrss_user_entries WHERE ttrss_entries.id = ref_id AND marked = false AND feed_id = '$feed_id' AND @@ -190,7 +217,7 @@ } else { - $result = db_query($link, "DELETE FROM ttrss_user_entries + $result = db_query("DELETE FROM ttrss_user_entries USING ttrss_entries WHERE ttrss_entries.id = ref_id AND marked = false AND @@ -199,28 +226,25 @@ ttrss_entries.date_updated < NOW() - INTERVAL '$purge_interval days'"); } - $rows = pg_affected_rows($result); - } else { -/* $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE +/* $result = db_query("DELETE FROM ttrss_user_entries WHERE marked = false AND feed_id = '$feed_id' AND (SELECT date_updated FROM ttrss_entries WHERE id = ref_id) < DATE_SUB(NOW(), INTERVAL $purge_interval DAY)"); */ - $result = db_query($link, "DELETE FROM ttrss_user_entries + $result = db_query("DELETE FROM ttrss_user_entries USING ttrss_user_entries, ttrss_entries WHERE ttrss_entries.id = ref_id AND marked = false AND feed_id = '$feed_id' AND $query_limit ttrss_entries.date_updated < DATE_SUB(NOW(), INTERVAL $purge_interval DAY)"); - - $rows = mysql_affected_rows($link); - } - ccache_update($link, $feed_id, $owner_uid); + $rows = db_affected_rows($result); + + ccache_update($feed_id, $owner_uid); if ($debug) { _debug("Purged feed $feed_id ($purge_interval): deleted $rows articles"); @@ -229,16 +253,16 @@ return $rows; } // function purge_feed - function feed_purge_interval($link, $feed_id) { + function feed_purge_interval($feed_id) { - $result = db_query($link, "SELECT purge_interval, owner_uid FROM ttrss_feeds + $result = db_query("SELECT purge_interval, owner_uid FROM ttrss_feeds WHERE id = '$feed_id'"); if (db_num_rows($result) == 1) { $purge_interval = db_fetch_result($result, 0, "purge_interval"); $owner_uid = db_fetch_result($result, 0, "owner_uid"); - if ($purge_interval == 0) $purge_interval = get_pref($link, + if ($purge_interval == 0) $purge_interval = get_pref( 'PURGE_OLD_DAYS', $owner_uid); return $purge_interval; @@ -248,20 +272,20 @@ } } - function purge_orphans($link, $do_output = false) { + function purge_orphans($do_output = false) { // purge orphaned posts in main content table - $result = db_query($link, "DELETE FROM ttrss_entries WHERE + $result = db_query("DELETE FROM ttrss_entries WHERE (SELECT COUNT(int_id) FROM ttrss_user_entries WHERE ref_id = id) = 0"); if ($do_output) { - $rows = db_affected_rows($link, $result); + $rows = db_affected_rows($result); _debug("Purged $rows orphaned posts."); } } - function get_feed_update_interval($link, $feed_id) { - $result = db_query($link, "SELECT owner_uid, update_interval FROM + function get_feed_update_interval($feed_id) { + $result = db_query("SELECT owner_uid, update_interval FROM ttrss_feeds WHERE id = '$feed_id'"); if (db_num_rows($result) == 1) { @@ -271,7 +295,7 @@ if ($update_interval != 0) { return $update_interval; } else { - return get_pref($link, 'DEFAULT_UPDATE_INTERVAL', $owner_uid, false); + return get_pref('DEFAULT_UPDATE_INTERVAL', $owner_uid, false); } } else { @@ -279,25 +303,40 @@ } } - 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; + global $fetch_last_content_type; + global $fetch_curl_used; + + $url = str_replace(' ', '%20', $url); - if (function_exists('curl_init') && !ini_get("open_basedir")) { - $ch = curl_init($url); + if (!defined('NO_CURL') && function_exists('curl_init')) { - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout ? $timeout : 15); - curl_setopt($ch, CURLOPT_TIMEOUT, $timeout ? $timeout : 45); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + $fetch_curl_used = true; + + if (ini_get("safe_mode") || ini_get("open_basedir")) { + $ch = curl_init(geturl($url)); + } else { + $ch = curl_init($url); + } + + if ($timestamp && !$post_query) { + 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 : FILE_FETCH_CONNECT_TIMEOUT); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout ? $timeout : FILE_FETCH_TIMEOUT); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, !ini_get("safe_mode") && !ini_get("open_basedir")); curl_setopt($ch, CURLOPT_MAXREDIRS, 20); curl_setopt($ch, CURLOPT_BINARYTRANSFER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 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_ENCODING, ""); curl_setopt($ch, CURLOPT_REFERER, $url); if ($post_query) { @@ -322,9 +361,11 @@ } $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); + $fetch_last_content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); - if ($http_code != 200 || $type && strpos($content_type, "$type") === false) { + $fetch_last_error_code = $http_code; + + if ($http_code != 200 || $type && strpos($fetch_last_content_type, "$type") === false) { if (curl_errno($ch) != 0) { $fetch_last_error = curl_errno($ch) . " " . curl_error($ch); } else { @@ -338,21 +379,58 @@ return $contents; } else { - if ($login && $pass ){ + + $fetch_curl_used = false; + + 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]; } } - $data = @file_get_contents($url); + if (!$post_query && $timestamp) { + $context = stream_context_create(array( + 'http' => array( + 'method' => 'GET', + 'header' => "If-Modified-Since: ".gmdate("D, d M Y H:i:s \\G\\M\\T\r\n", $timestamp) + ))); + } else { + $context = NULL; + } + + $old_error = error_get_last(); + + $data = @file_get_contents($url, false, $context); + + $fetch_last_content_type = false; // reset if no type was sent from server + if (isset($http_response_header) && is_array($http_response_header)) { + foreach ($http_response_header as $h) { + if (substr(strtolower($h), 0, 13) == 'content-type:') { + $fetch_last_content_type = substr($h, 14); + // don't abort here b/c there might be more than one + // e.g. if we were being redirected -- last one is the right one + } + + if (substr(strtolower($h), 0, 7) == 'http/1.') { + $fetch_last_error_code = (int) substr($h, 9, 3); + } + } + } - if (!$data && function_exists('error_get_last')) { + if (!$data) { $error = error_get_last(); - $fetch_last_error = $error["message"]; + + if ($error['message'] != $old_error['message']) { + $fetch_last_error = $error["message"]; + } else { + $fetch_last_error = "HTTP Code: $fetch_last_error_code"; + } } return $data; } @@ -401,7 +479,7 @@ return $favicon_url; } // function get_favicon_url - function check_feed_favicon($site_url, $feed, $link) { + function check_feed_favicon($site_url, $feed) { # print "FAVICON [$site_url]: $favicon_url\n"; $icon_file = ICONS_DIR . "/$feed.ico"; @@ -448,6 +526,7 @@ } } } + return $icon_file; } } @@ -459,6 +538,8 @@ else $sel = ""; + $v = trim($v); + print "<option value=\"$v\" $sel>$v</option>"; } print "</select>"; @@ -472,6 +553,8 @@ else $sel = ""; + $v = trim($v); + print "<option $sel value=\"$v\">".$values[$v]."</option>"; } @@ -498,7 +581,7 @@ } } - function initialize_user_prefs($link, $uid, $profile = false) { + function initialize_user_prefs($uid, $profile = false) { $uid = db_escape_string($uid); @@ -509,13 +592,13 @@ $profile_qpart = "AND profile = '$profile'"; } - if (get_schema_version($link) < 63) $profile_qpart = ""; + if (get_schema_version() < 63) $profile_qpart = ""; - db_query($link, "BEGIN"); + db_query("BEGIN"); - $result = db_query($link, "SELECT pref_name,def_value FROM ttrss_prefs"); + $result = db_query("SELECT pref_name,def_value FROM ttrss_prefs"); - $u_result = db_query($link, "SELECT pref_name + $u_result = db_query("SELECT pref_name FROM ttrss_user_prefs WHERE owner_uid = '$uid' $profile_qpart"); $active_prefs = array(); @@ -528,13 +611,16 @@ if (array_search($line["pref_name"], $active_prefs) === FALSE) { // print "adding " . $line["pref_name"] . "<br>"; - if (get_schema_version($link) < 63) { - db_query($link, "INSERT INTO ttrss_user_prefs + $line["def_value"] = db_escape_string($line["def_value"]); + $line["pref_name"] = db_escape_string($line["pref_name"]); + + if (get_schema_version() < 63) { + db_query("INSERT INTO ttrss_user_prefs (owner_uid,pref_name,value) VALUES ('$uid', '".$line["pref_name"]."','".$line["def_value"]."')"); } else { - db_query($link, "INSERT INTO ttrss_user_prefs + db_query("INSERT INTO ttrss_user_prefs (owner_uid,pref_name,value, profile) VALUES ('$uid', '".$line["pref_name"]."','".$line["def_value"]."', $profile)"); } @@ -542,7 +628,7 @@ } } - db_query($link, "COMMIT"); + db_query("COMMIT"); } @@ -556,14 +642,12 @@ return ""; } - function authenticate_user($link, $login, $password, $check_only = false) { + function authenticate_user($login, $password, $check_only = false) { if (!SINGLE_USER_MODE) { - $user_id = false; - global $pluginhost; - foreach ($pluginhost->get_hooks($pluginhost::HOOK_AUTH_USER) as $plugin) { + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_AUTH_USER) as $plugin) { $user_id = (int) $plugin->authenticate($login, $password); @@ -574,24 +658,28 @@ } if ($user_id && !$check_only) { + @session_start(); + $_SESSION["uid"] = $user_id; + $_SESSION["version"] = VERSION_STATIC; - $result = db_query($link, "SELECT login,access_level,pwd_hash FROM ttrss_users + $result = db_query("SELECT login,access_level,pwd_hash FROM ttrss_users WHERE id = '$user_id'"); $_SESSION["name"] = db_fetch_result($result, 0, "login"); $_SESSION["access_level"] = db_fetch_result($result, 0, "access_level"); $_SESSION["csrf_token"] = sha1(uniqid(rand(), true)); - db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " . + db_query("UPDATE ttrss_users SET last_login = NOW() WHERE id = " . $_SESSION["uid"]); $_SESSION["ip_address"] = $_SERVER["REMOTE_ADDR"]; + $_SESSION["user_agent"] = sha1($_SERVER['HTTP_USER_AGENT']); $_SESSION["pwd_hash"] = db_fetch_result($result, 0, "pwd_hash"); $_SESSION["last_version_check"] = time(); - initialize_user_prefs($link, $_SESSION["uid"]); + initialize_user_prefs($_SESSION["uid"]); return true; } @@ -615,7 +703,7 @@ $_SESSION["ip_address"] = $_SERVER["REMOTE_ADDR"]; - initialize_user_prefs($link, $_SESSION["uid"]); + initialize_user_prefs($_SESSION["uid"]); return true; } @@ -644,13 +732,13 @@ // user preferences are checked on every login, not here - function initialize_user($link, $uid) { + function initialize_user($uid) { - db_query($link, "insert into ttrss_feeds (owner_uid,title,feed_url) + db_query("insert into ttrss_feeds (owner_uid,title,feed_url) values ('$uid', 'Tiny Tiny RSS: New Releases', 'http://tt-rss.org/releases.rss')"); - db_query($link, "insert into ttrss_feeds (owner_uid,title,feed_url) + db_query("insert into ttrss_feeds (owner_uid,title,feed_url) values ('$uid', 'Tiny Tiny RSS: Forum', 'http://tt-rss.org/forum/rss.php')"); } @@ -666,103 +754,67 @@ return $csrf_token == $_SESSION['csrf_token']; } - function validate_session($link) { - if (SINGLE_USER_MODE) return true; - - $check_ip = $_SESSION['ip_address']; - - switch (SESSION_CHECK_ADDRESS) { - case 0: - $check_ip = ''; - break; - case 1: - $check_ip = substr($check_ip, 0, strrpos($check_ip, '.')+1); - break; - case 2: - $check_ip = substr($check_ip, 0, strrpos($check_ip, '.')); - $check_ip = substr($check_ip, 0, strrpos($check_ip, '.')+1); - break; - }; - - if ($check_ip && strpos($_SERVER['REMOTE_ADDR'], $check_ip) !== 0) { - $_SESSION["login_error_msg"] = - __("Session failed to validate (incorrect IP)"); - return false; - } - - if ($_SESSION["ref_schema_version"] != get_schema_version($link, true)) - return false; - - if ($_SESSION["uid"]) { - - $result = db_query($link, - "SELECT pwd_hash FROM ttrss_users WHERE id = '".$_SESSION["uid"]."'"); - - $pwd_hash = db_fetch_result($result, 0, "pwd_hash"); - - if ($pwd_hash != $_SESSION["pwd_hash"]) { - return false; - } - } - -/* if ($_SESSION["cookie_lifetime"] && $_SESSION["uid"]) { - - //print_r($_SESSION); - - if (time() > $_SESSION["cookie_lifetime"]) { - return false; - } - } */ - - return true; - } - - function load_user_plugins($link, $owner_uid) { + function load_user_plugins($owner_uid) { if ($owner_uid) { - $plugins = get_pref($link, "_ENABLED_PLUGINS", $owner_uid); + $plugins = get_pref("_ENABLED_PLUGINS", $owner_uid); - global $pluginhost; - $pluginhost->load($plugins, $pluginhost::KIND_USER, $owner_uid); + PluginHost::getInstance()->load($plugins, PluginHost::KIND_USER, $owner_uid); - if (get_schema_version($link) > 100) { - $pluginhost->load_data(); + if (get_schema_version() > 100) { + PluginHost::getInstance()->load_data(); } } } - function login_sequence($link, $login_form = 0) { - $_SESSION["prefs_cache"] = false; - + function login_sequence() { if (SINGLE_USER_MODE) { - authenticate_user($link, "admin", null); - cache_prefs($link); - load_user_plugins($link, $_SESSION["uid"]); + @session_start(); + authenticate_user("admin", null); + load_user_plugins($_SESSION["uid"]); } else { - if (!$_SESSION["uid"] || !validate_session($link)) { + if (!validate_session()) $_SESSION["uid"] = false; + + if (!$_SESSION["uid"]) { - if (AUTH_AUTO_LOGIN && authenticate_user($link, null, null)) { - $_SESSION["ref_schema_version"] = get_schema_version($link, true); + if (AUTH_AUTO_LOGIN && authenticate_user(null, null)) { + $_SESSION["ref_schema_version"] = get_schema_version(true); } else { - authenticate_user($link, null, null, true); + authenticate_user(null, null, true); } - if (!$_SESSION["uid"]) render_login_form($link, $login_form); + if (!$_SESSION["uid"]) { + @session_destroy(); + setcookie(session_name(), '', time()-42000, '/'); + + render_login_form(); + exit; + } } else { /* bump login timestamp */ - db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " . + db_query("UPDATE ttrss_users SET last_login = NOW() WHERE id = " . $_SESSION["uid"]); - } - - if ($_SESSION["uid"] && $_SESSION["language"] && SESSION_COOKIE_LIFETIME > 0) { - setcookie("ttrss_lang", $_SESSION["language"], - time() + SESSION_COOKIE_LIFETIME); + $_SESSION["last_login_update"] = time(); } if ($_SESSION["uid"]) { - cache_prefs($link); - load_user_plugins($link, $_SESSION["uid"]); + startup_gettext(); + load_user_plugins($_SESSION["uid"]); + + /* cleanup ccache */ + + db_query("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("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 +826,6 @@ } } - // Deprecated, TODO: remove - function theme_image($link, $filename) { - return $filename; - } - function convert_timestamp($timestamp, $source_tz, $dest_tz) { try { @@ -797,62 +844,68 @@ return $dt->format('U') + $dest_tz->getOffset($dt); } - function make_local_datetime($link, $timestamp, $long, $owner_uid = false, + function make_local_datetime($timestamp, $long, $owner_uid = false, $no_smart_dt = false) { if (!$owner_uid) $owner_uid = $_SESSION['uid']; if (!$timestamp) $timestamp = '1970-01-01 0:00'; global $utc_tz; - global $tz_offset; + global $user_tz; + + if (!$utc_tz) $utc_tz = new DateTimeZone('UTC'); + + $timestamp = substr($timestamp, 0, 19); # We store date in UTC internally $dt = new DateTime($timestamp, $utc_tz); - if ($tz_offset == -1) { + $user_tz_string = get_pref('USER_TIMEZONE', $owner_uid); - $user_tz_string = get_pref($link, 'USER_TIMEZONE', $owner_uid); + if ($user_tz_string != 'Automatic') { try { - $user_tz = new DateTimeZone($user_tz_string); + if (!$user_tz) $user_tz = new DateTimeZone($user_tz_string); } catch (Exception $e) { $user_tz = $utc_tz; } $tz_offset = $user_tz->getOffset($dt); + } else { + $tz_offset = (int) -$_SESSION["clientTzOffset"]; } $user_timestamp = $dt->format('U') + $tz_offset; if (!$no_smart_dt) { - return smart_date_time($link, $user_timestamp, + return smart_date_time($user_timestamp, $tz_offset, $owner_uid); } else { if ($long) - $format = get_pref($link, 'LONG_DATE_FORMAT', $owner_uid); + $format = get_pref('LONG_DATE_FORMAT', $owner_uid); else - $format = get_pref($link, 'SHORT_DATE_FORMAT', $owner_uid); + $format = get_pref('SHORT_DATE_FORMAT', $owner_uid); return date($format, $user_timestamp); } } - function smart_date_time($link, $timestamp, $tz_offset = 0, $owner_uid = false) { + function smart_date_time($timestamp, $tz_offset = 0, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION['uid']; if (date("Y.m.d", $timestamp) == date("Y.m.d", time() + $tz_offset)) { return date("G:i", $timestamp); } else if (date("Y", $timestamp) == date("Y", time() + $tz_offset)) { - $format = get_pref($link, 'SHORT_DATE_FORMAT', $owner_uid); + $format = get_pref('SHORT_DATE_FORMAT', $owner_uid); return date($format, $timestamp); } else { - $format = get_pref($link, 'LONG_DATE_FORMAT', $owner_uid); + $format = get_pref('LONG_DATE_FORMAT', $owner_uid); return date($format, $timestamp); } } 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; @@ -870,11 +923,11 @@ // Session caching removed due to causing wrong redirects to upgrade // script when get_schema_version() is called on an obsolete session // created on a previous schema version. - function get_schema_version($link, $nocache = false) { + function get_schema_version($nocache = false) { global $schema_version; - if (!$schema_version) { - $result = db_query($link, "SELECT schema_version FROM ttrss_version"); + if (!$schema_version && !$nocache) { + $result = db_query("SELECT schema_version FROM ttrss_version"); $version = db_fetch_result($result, 0, "schema_version"); $schema_version = $version; return $version; @@ -883,18 +936,18 @@ } } - function sanity_check($link) { + function sanity_check() { require_once 'errors.php'; $error_code = 0; - $schema_version = get_schema_version($link, true); + $schema_version = get_schema_version(true); if ($schema_version != SCHEMA_VERSION) { $error_code = 5; } if (DB_TYPE == "mysql") { - $result = db_query($link, "SELECT true", false); + $result = db_query("SELECT true", false); if (db_num_rows($result) != 1) { $error_code = 10; } @@ -959,14 +1012,41 @@ } } - function catchup_feed($link, $feed, $cat_view, $owner_uid = false, $max_id = false) { + function catchup_feed($feed, $cat_view, $owner_uid = false, $max_id = false, $mode = 'all') { if (!$owner_uid) $owner_uid = $_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"; + // Todo: all this interval stuff needs some generic generator function + + $date_qpart = "false"; + + switch ($mode) { + case "1day": + if (DB_TYPE == "pgsql") { + $date_qpart = "date_entered < NOW() - INTERVAL '1 day' "; + } else { + $date_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 1 DAY) "; + } + break; + case "1week": + if (DB_TYPE == "pgsql") { + $date_qpart = "date_entered < NOW() - INTERVAL '1 week' "; + } else { + $date_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 1 WEEK) "; + } + break; + case "2weeks": + if (DB_TYPE == "pgsql") { + $date_qpart = "date_entered < NOW() - INTERVAL '2 week' "; + } else { + $date_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 2 WEEK) "; + } + break; + default: + $date_qpart = "true"; + } if (is_numeric($feed)) { if ($cat_view) { @@ -974,7 +1054,7 @@ if ($feed >= 0) { if ($feed > 0) { - $children = getChildCategories($link, $feed, $owner_uid); + $children = getChildCategories($feed, $owner_uid); array_push($children, $feed); $children = join(",", $children); @@ -984,124 +1064,111 @@ $cat_qpart = "cat_id IS NULL"; } - 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"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id + AND owner_uid = $owner_uid AND unread = true AND feed_id IN + (SELECT id FROM ttrss_feeds WHERE $cat_qpart) AND $date_qpart) as tmp)"); } else if ($feed == -2) { - db_query($link, "UPDATE ttrss_user_entries + db_query("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"); + AND unread = true AND $date_qpart AND owner_uid = $owner_uid"); } } else if ($feed > 0) { - 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"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id + AND owner_uid = $owner_uid AND unread = true AND feed_id = $feed AND $date_qpart) as tmp)"); - } 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"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id + AND owner_uid = $owner_uid AND unread = true AND marked = true AND $date_qpart) as tmp)"); } if ($feed == -2) { - 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"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id + AND owner_uid = $owner_uid AND unread = true AND published = true AND $date_qpart) as tmp)"); } if ($feed == -3) { - $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE"); + $intl = get_pref("FRESH_ARTICLE_MAX_AGE"); if (DB_TYPE == "pgsql") { - $match_part = "updated > NOW() - INTERVAL '$intl hour' "; + $match_part = "date_entered > NOW() - INTERVAL '$intl hour' "; } else { - $match_part = "updated > DATE_SUB(NOW(), + $match_part = "date_entered > DATE_SUB(NOW(), INTERVAL $intl HOUR) "; } - $result = db_query($link, "SELECT id FROM ttrss_entries, - ttrss_user_entries WHERE $match_part AND - unread = true AND - ttrss_user_entries.ref_id = ttrss_entries.id AND - owner_uid = $owner_uid"); - - $affected_ids = array(); - - while ($line = db_fetch_assoc($result)) { - array_push($affected_ids, $line["id"]); - } - - catchupArticlesById($link, $affected_ids, 0); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id + AND owner_uid = $owner_uid AND unread = true AND $date_qpart AND $match_part) as tmp)"); } if ($feed == -4) { - db_query($link, "UPDATE ttrss_user_entries - SET unread = false,last_read = NOW() - WHERE $ref_check_qpart AND unread = true AND - owner_uid = $owner_uid"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id + AND owner_uid = $owner_uid AND unread = true AND $date_qpart) as tmp)"); } - } 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"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT ttrss_entries.id FROM ttrss_entries, ttrss_user_entries, ttrss_user_labels2 WHERE ref_id = id + AND label_id = '$label_id' AND ref_id = article_id + AND owner_uid = $owner_uid AND unread = true AND $date_qpart) as tmp)"); } - ccache_update($link, $feed, $owner_uid, $cat_view); + ccache_update($feed, $owner_uid, $cat_view); } else { // tag - db_query($link, "BEGIN"); - - $tag_name = db_escape_string($feed); - - $result = db_query($link, "SELECT post_int_id FROM ttrss_tags - WHERE tag_name = '$tag_name' AND owner_uid = $owner_uid"); + db_query("UPDATE ttrss_user_entries + SET unread = false, last_read = NOW() WHERE ref_id IN + (SELECT id FROM + (SELECT ttrss_entries.id FROM ttrss_entries, ttrss_user_entries, ttrss_tags WHERE ref_id = ttrss_entries.id + AND post_int_id = int_id AND tag_name = '$feed' + AND ttrss_user_entries.owner_uid = $owner_uid AND unread = true AND $date_qpart) as tmp)"); - 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 - AND int_id = " . $line["post_int_id"]); - } - db_query($link, "COMMIT"); } } - function getAllCounters($link) { - $data = getGlobalCounters($link); + function getAllCounters() { + $data = getGlobalCounters(); - $data = array_merge($data, getVirtCounters($link)); - $data = array_merge($data, getLabelCounters($link)); - $data = array_merge($data, getFeedCounters($link, $active_feed)); - $data = array_merge($data, getCategoryCounters($link)); + $data = array_merge($data, getVirtCounters()); + $data = array_merge($data, getLabelCounters()); + $data = array_merge($data, getFeedCounters()); + $data = array_merge($data, getCategoryCounters()); return $data; } - function getCategoryTitle($link, $cat_id) { + function getCategoryTitle($cat_id) { if ($cat_id == -1) { return __("Special"); @@ -1109,7 +1176,7 @@ return __("Labels"); } else { - $result = db_query($link, "SELECT title FROM ttrss_feed_categories WHERE + $result = db_query("SELECT title FROM ttrss_feed_categories WHERE id = '$cat_id'"); if (db_num_rows($result) == 1) { @@ -1121,17 +1188,17 @@ } - function getCategoryCounters($link) { + function getCategoryCounters() { $ret_arr = array(); /* Labels category */ $cv = array("id" => -2, "kind" => "cat", - "counter" => getCategoryUnread($link, -2)); + "counter" => getCategoryUnread(-2)); array_push($ret_arr, $cv); - $result = db_query($link, "SELECT id AS cat_id, value AS unread, + $result = db_query("SELECT id AS cat_id, value AS unread, (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE c2.parent_cat = ttrss_feed_categories.id) AS num_children FROM ttrss_feed_categories, ttrss_cat_counters_cache @@ -1143,7 +1210,7 @@ $line["cat_id"] = (int) $line["cat_id"]; if ($line["num_children"] > 0) { - $child_counter = getCategoryChildrenUnread($link, $line["cat_id"], $_SESSION["uid"]); + $child_counter = getCategoryChildrenUnread($line["cat_id"], $_SESSION["uid"]); } else { $child_counter = 0; } @@ -1157,7 +1224,7 @@ /* Special case: NULL category doesn't actually exist in the DB */ $cv = array("id" => 0, "kind" => "cat", - "counter" => (int) ccache_find($link, 0, $_SESSION["uid"], true)); + "counter" => (int) ccache_find(0, $_SESSION["uid"], true)); array_push($ret_arr, $cv); @@ -1165,23 +1232,23 @@ } // only accepts real cats (>= 0) - function getCategoryChildrenUnread($link, $cat, $owner_uid = false) { + function getCategoryChildrenUnread($cat, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; - $result = db_query($link, "SELECT id FROM ttrss_feed_categories WHERE parent_cat = '$cat' + $result = db_query("SELECT id FROM ttrss_feed_categories WHERE parent_cat = '$cat' AND owner_uid = $owner_uid"); $unread = 0; while ($line = db_fetch_assoc($result)) { - $unread += getCategoryUnread($link, $line["id"], $owner_uid); - $unread += getCategoryChildrenUnread($link, $line["id"], $owner_uid); + $unread += getCategoryUnread($line["id"], $owner_uid); + $unread += getCategoryChildrenUnread($line["id"], $owner_uid); } return $unread; } - function getCategoryUnread($link, $cat, $owner_uid = false) { + function getCategoryUnread($cat, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; @@ -1193,7 +1260,7 @@ $cat_query = "cat_id IS NULL"; } - $result = db_query($link, "SELECT id FROM ttrss_feeds WHERE $cat_query + $result = db_query("SELECT id FROM ttrss_feeds WHERE $cat_query AND owner_uid = " . $owner_uid); $cat_feeds = array(); @@ -1205,7 +1272,7 @@ $match_part = implode(" OR ", $cat_feeds); - $result = db_query($link, "SELECT COUNT(int_id) AS unread + $result = db_query("SELECT COUNT(int_id) AS unread FROM ttrss_user_entries WHERE unread = true AND ($match_part) AND owner_uid = " . $owner_uid); @@ -1219,10 +1286,10 @@ return $unread; } else if ($cat == -1) { - return getFeedUnread($link, -1) + getFeedUnread($link, -2) + getFeedUnread($link, -3) + getFeedUnread($link, 0); + return getFeedUnread(-1) + getFeedUnread(-2) + getFeedUnread(-3) + getFeedUnread(0); } else if ($cat == -2) { - $result = db_query($link, " + $result = db_query(" SELECT COUNT(unread) AS unread FROM ttrss_user_entries, ttrss_user_labels2 WHERE article_id = ref_id AND unread = true @@ -1235,14 +1302,14 @@ } } - function getFeedUnread($link, $feed, $is_cat = false) { - return getFeedArticles($link, $feed, $is_cat, true, $_SESSION["uid"]); + function getFeedUnread($feed, $is_cat = false) { + return getFeedArticles($feed, $is_cat, true, $_SESSION["uid"]); } - function getLabelUnread($link, $label_id, $owner_uid = false) { + function getLabelUnread($label_id, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; - $result = db_query($link, "SELECT COUNT(ref_id) AS unread FROM ttrss_user_entries, ttrss_user_labels2 + $result = db_query("SELECT COUNT(ref_id) AS unread FROM ttrss_user_entries, ttrss_user_labels2 WHERE owner_uid = '$owner_uid' AND unread = true AND label_id = '$label_id' AND article_id = ref_id"); if (db_num_rows($result) != 0) { @@ -1252,7 +1319,7 @@ } } - function getFeedArticles($link, $feed, $is_cat = false, $unread_only = false, + function getFeedArticles($feed, $is_cat = false, $unread_only = false, $owner_uid = false) { $n_feed = (int) $feed; @@ -1267,14 +1334,14 @@ } if ($is_cat) { - return getCategoryUnread($link, $n_feed, $owner_uid); + return getCategoryUnread($n_feed, $owner_uid); } else if ($n_feed == -6) { return 0; } else if ($feed != "0" && $n_feed == 0) { $feed = db_escape_string($feed); - $result = db_query($link, "SELECT SUM((SELECT COUNT(int_id) + $result = db_query("SELECT SUM((SELECT COUNT(int_id) FROM ttrss_user_entries,ttrss_entries WHERE int_id = post_int_id AND ref_id = id AND $unread_qpart)) AS count FROM ttrss_tags WHERE owner_uid = $owner_uid AND tag_name = '$feed'"); @@ -1287,7 +1354,7 @@ } else if ($n_feed == -3) { $match_part = "unread = true AND score >= 0"; - $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE", $owner_uid); + $intl = get_pref("FRESH_ARTICLE_MAX_AGE", $owner_uid); if (DB_TYPE == "pgsql") { $match_part .= " AND updated > NOW() - INTERVAL '$intl hour' "; @@ -1307,11 +1374,11 @@ $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); + return getLabelUnread($label_id, $owner_uid); } @@ -1330,11 +1397,11 @@ //echo "[$feed/$query]\n"; - $result = db_query($link, $query); + $result = db_query($query); } else { - $result = db_query($link, "SELECT COUNT(post_int_id) AS unread + $result = db_query("SELECT COUNT(post_int_id) AS unread FROM ttrss_tags,ttrss_user_entries,ttrss_entries WHERE tag_name = '$feed' AND post_int_id = int_id AND ref_id = ttrss_entries.id AND $unread_qpart AND ttrss_tags.owner_uid = " . $owner_uid); @@ -1345,13 +1412,13 @@ return $unread; } - function getGlobalUnread($link, $user_id = false) { + function getGlobalUnread($user_id = false) { if (!$user_id) { $user_id = $_SESSION["uid"]; } - $result = db_query($link, "SELECT SUM(value) AS c_id FROM ttrss_counters_cache + $result = db_query("SELECT SUM(value) AS c_id FROM ttrss_counters_cache WHERE owner_uid = '$user_id' AND feed_id > 0"); $c_id = db_fetch_result($result, 0, "c_id"); @@ -1359,11 +1426,11 @@ return $c_id; } - function getGlobalCounters($link, $global_unread = -1) { + function getGlobalCounters($global_unread = -1) { $ret_arr = array(); if ($global_unread == -1) { - $global_unread = getGlobalUnread($link); + $global_unread = getGlobalUnread(); } $cv = array("id" => "global-unread", @@ -1371,7 +1438,7 @@ array_push($ret_arr, $cv); - $result = db_query($link, "SELECT COUNT(id) AS fn FROM + $result = db_query("SELECT COUNT(id) AS fn FROM ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]); $subscribed_feeds = db_fetch_result($result, 0, "fn"); @@ -1384,42 +1451,53 @@ return $ret_arr; } - function getVirtCounters($link) { + function getVirtCounters() { $ret_arr = array(); for ($i = 0; $i >= -4; $i--) { - $count = getFeedUnread($link, $i); + $count = getFeedUnread($i); $cv = array("id" => $i, "counter" => (int) $count); -// if (get_pref($link, 'EXTENDED_FEEDLIST')) -// $cv["xmsg"] = getFeedArticles($link, $i)." ".__("total"); +// if (get_pref('EXTENDED_FEEDLIST')) +// $cv["xmsg"] = getFeedArticles($i)." ".__("total"); array_push($ret_arr, $cv); } + $feeds = PluginHost::getInstance()->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; } - function getLabelCounters($link, $descriptions = false) { + function getLabelCounters($descriptions = false) { $ret_arr = array(); $owner_uid = $_SESSION["uid"]; - $result = db_query($link, "SELECT id,caption,COUNT(unread) AS unread + $result = db_query("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) + LEFT JOIN ttrss_user_entries ON (ref_id = article_id AND unread = true + AND ttrss_user_entries.owner_uid = $owner_uid) 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 = $line["unread"]; @@ -1430,8 +1508,8 @@ if ($descriptions) $cv["description"] = $label_name; -// if (get_pref($link, 'EXTENDED_FEEDLIST')) -// $cv["xmsg"] = getFeedArticles($link, $id)." ".__("total"); +// if (get_pref('EXTENDED_FEEDLIST')) +// $cv["xmsg"] = getFeedArticles($id)." ".__("total"); array_push($ret_arr, $cv); } @@ -1439,7 +1517,7 @@ return $ret_arr; } - function getFeedCounters($link, $active_feed = false) { + function getFeedCounters($active_feed = false) { $ret_arr = array(); @@ -1452,7 +1530,7 @@ AND ttrss_counters_cache.owner_uid = ttrss_feeds.owner_uid AND ttrss_counters_cache.feed_id = id"; - $result = db_query($link, $query); + $result = db_query($query); $fctrs_modified = false; while ($line = db_fetch_assoc($result)) { @@ -1461,7 +1539,7 @@ $count = $line["count"]; $last_error = htmlspecialchars($line["last_error"]); - $last_updated = make_local_datetime($link, $line['last_updated'], false); + $last_updated = make_local_datetime($line['last_updated'], false); $has_img = feed_has_icon($id); @@ -1476,8 +1554,8 @@ if ($last_error) $cv["error"] = $last_error; -// if (get_pref($link, 'EXTENDED_FEEDLIST')) -// $cv["xmsg"] = getFeedArticles($link, $id)." ".__("total"); +// if (get_pref('EXTENDED_FEEDLIST')) +// $cv["xmsg"] = getFeedArticles($id)." ".__("total"); if ($active_feed && $id == $active_feed) $cv["title"] = truncate_string($line["title"], 30); @@ -1489,8 +1567,8 @@ return $ret_arr; } - function get_pgsql_version($link) { - $result = db_query($link, "SELECT version() AS version"); + function get_pgsql_version() { + $result = db_query("SELECT version() AS version"); $version = explode(" ", db_fetch_result($result, 0, "version")); return $version[1]; } @@ -1506,9 +1584,10 @@ * Here you should call extractfeedurls in rpc-backend * to get all possible feeds. * 5 - Couldn't download the URL content. + * 6 - Content is an invalid XML. */ - function subscribe_to_feed($link, $url, $cat_id = 0, - $auth_login = '', $auth_pass = '', $need_auth = false) { + function subscribe_to_feed($url, $cat_id = 0, + $auth_login = '', $auth_pass = '') { global $fetch_last_error; @@ -1536,31 +1615,53 @@ $url = key($feedUrls); } + /* libxml_use_internal_errors(true); + $doc = new DOMDocument(); + $doc->loadXML($contents); + $error = libxml_get_last_error(); + libxml_clear_errors(); + + if ($error) { + $error_message = format_libxml_error($error); + + return array("code" => 6, "message" => $error_message); + } */ + if ($cat_id == "0" || !$cat_id) { $cat_qpart = "NULL"; } else { $cat_qpart = "'$cat_id'"; } - $result = db_query($link, + $result = db_query( "SELECT id FROM ttrss_feeds WHERE feed_url = '$url' AND owner_uid = ".$_SESSION["uid"]); + if (strlen(FEED_CRYPT_KEY) > 0) { + require_once "crypt.php"; + $auth_pass = substr(encrypt_string($auth_pass), 0, 250); + $auth_pass_encrypted = 'true'; + } else { + $auth_pass_encrypted = 'false'; + } + + $auth_pass = db_escape_string($auth_pass); + if (db_num_rows($result) == 0) { - $result = db_query($link, + $result = db_query( "INSERT INTO ttrss_feeds - (owner_uid,feed_url,title,cat_id, auth_login,auth_pass,update_method) + (owner_uid,feed_url,title,cat_id, auth_login,auth_pass,update_method,auth_pass_encrypted) VALUES ('".$_SESSION["uid"]."', '$url', - '[Unknown]', $cat_qpart, '$auth_login', '$auth_pass', 0)"); + '[Unknown]', $cat_qpart, '$auth_login', '$auth_pass', 0, $auth_pass_encrypted)"); - $result = db_query($link, + $result = db_query( "SELECT id FROM ttrss_feeds WHERE feed_url = '$url' AND owner_uid = " . $_SESSION["uid"]); $feed_id = db_fetch_result($result, 0, "id"); if ($feed_id) { - update_rss_feed($link, $feed_id, true); + update_rss_feed($feed_id, true); } return array("code" => 1); @@ -1569,7 +1670,7 @@ } } - function print_feed_select($link, $id, $default_id = "", + function print_feed_select($id, $default_id = "", $attributes = "", $include_all_feeds = true, $root_id = false, $nest_level = 0) { @@ -1581,14 +1682,14 @@ } } - if (get_pref($link, 'ENABLE_FEED_CATS')) { + if (get_pref('ENABLE_FEED_CATS')) { if ($root_id) $parent_qpart = "parent_cat = '$root_id'"; else $parent_qpart = "parent_cat IS NULL"; - $result = db_query($link, "SELECT id,title, + $result = db_query("SELECT id,title, (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE c2.parent_cat = ttrss_feed_categories.id) AS num_children FROM ttrss_feed_categories @@ -1605,10 +1706,10 @@ $line["id"], htmlspecialchars($line["title"])); if ($line["num_children"] > 0) - print_feed_select($link, $id, $default_id, $attributes, + print_feed_select($id, $default_id, $attributes, $include_all_feeds, $line["id"], $nest_level+1); - $feed_result = db_query($link, "SELECT id,title FROM ttrss_feeds + $feed_result = db_query("SELECT id,title FROM ttrss_feeds WHERE cat_id = '".$line["id"]."' AND owner_uid = ".$_SESSION["uid"] . " ORDER BY title"); while ($fline = db_fetch_assoc($feed_result)) { @@ -1625,12 +1726,13 @@ } if (!$root_id) { - $is_selected = ($default_id == "CAT:0") ? "selected=\"1\"" : ""; + $default_is_cat = ($default_id == "CAT:0"); + $is_selected = $default_is_cat ? "selected=\"1\"" : ""; printf("<option $is_selected value='CAT:0'>%s</option>", __("Uncategorized")); - $feed_result = db_query($link, "SELECT id,title FROM ttrss_feeds + $feed_result = db_query("SELECT id,title FROM ttrss_feeds WHERE cat_id IS NULL AND owner_uid = ".$_SESSION["uid"] . " ORDER BY title"); while ($fline = db_fetch_assoc($feed_result)) { @@ -1647,7 +1749,7 @@ } } else { - $result = db_query($link, "SELECT id,title FROM ttrss_feeds + $result = db_query("SELECT id,title FROM ttrss_feeds WHERE owner_uid = ".$_SESSION["uid"]." ORDER BY title"); while ($line = db_fetch_assoc($result)) { @@ -1664,7 +1766,7 @@ } } - function print_feed_cat_select($link, $id, $default_id, + function print_feed_cat_select($id, $default_id, $attributes, $include_all_cats = true, $root_id = false, $nest_level = 0) { if (!$root_id) { @@ -1676,7 +1778,7 @@ else $parent_qpart = "parent_cat IS NULL"; - $result = db_query($link, "SELECT id,title, + $result = db_query("SELECT id,title, (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE c2.parent_cat = ttrss_feed_categories.id) AS num_children FROM ttrss_feed_categories @@ -1697,7 +1799,7 @@ $line["id"], htmlspecialchars($line["title"])); if ($line["num_children"] > 0) - print_feed_cat_select($link, $id, $default_id, $attributes, + print_feed_cat_select($id, $default_id, $attributes, $include_all_cats, $line["id"], $nest_level+1); } @@ -1723,13 +1825,13 @@ return ($val == "on") ? "true" : "false"; } - function getFeedCatTitle($link, $id) { + function getFeedCatTitle($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 + $result = db_query("SELECT ttrss_feed_categories.title FROM ttrss_feeds, ttrss_feed_categories WHERE ttrss_feeds.id = '$id' AND cat_id = ttrss_feed_categories.id"); if (db_num_rows($result) == 1) { @@ -1764,7 +1866,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")) @@ -1772,11 +1874,13 @@ } break; } + + return false; } - function getFeedTitle($link, $id, $cat = false) { + function getFeedTitle($id, $cat = false) { if ($cat) { - return getCategoryTitle($link, $id); + return getCategoryTitle($id); } else if ($id == -1) { return __("Starred articles"); } else if ($id == -2) { @@ -1789,9 +1893,9 @@ return __("Archived articles"); } else if ($id == -6) { return __("Recently read"); - } else if ($id < -10) { - $label_id = -$id - 11; - $result = db_query($link, "SELECT caption FROM ttrss_labels2 WHERE id = '$label_id'"); + } else if ($id < LABEL_BASE_INDEX) { + $label_id = feed_to_label_id($id); + $result = db_query("SELECT caption FROM ttrss_labels2 WHERE id = '$label_id'"); if (db_num_rows($result) == 1) { return db_fetch_result($result, 0, "caption"); } else { @@ -1799,7 +1903,7 @@ } } else if (is_numeric($id) && $id > 0) { - $result = db_query($link, "SELECT title FROM ttrss_feeds WHERE id = '$id'"); + $result = db_query("SELECT title FROM ttrss_feeds WHERE id = '$id'"); if (db_num_rows($result) == 1) { return db_fetch_result($result, 0, "title"); } else { @@ -1810,30 +1914,26 @@ } } - function make_init_params($link) { + function make_init_params() { $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", + "CDM_AUTO_CATCHUP", "FRESH_ARTICLE_MAX_AGE", "HIDE_READ_SHOWS_SPECIAL", "COMBINED_DISPLAY_MODE") as $param) { - $params[strtolower($param)] = (int) get_pref($link, $param); + $params[strtolower($param)] = (int) get_pref($param); } $params["icons_url"] = ICONS_URL; $params["cookie_lifetime"] = SESSION_COOKIE_LIFETIME; - $params["default_view_mode"] = get_pref($link, "_DEFAULT_VIEW_MODE"); - $params["default_view_limit"] = (int) get_pref($link, "_DEFAULT_VIEW_LIMIT"); - $params["default_view_order_by"] = get_pref($link, "_DEFAULT_VIEW_ORDER_BY"); + $params["default_view_mode"] = get_pref("_DEFAULT_VIEW_MODE"); + $params["default_view_limit"] = (int) get_pref("_DEFAULT_VIEW_LIMIT"); + $params["default_view_order_by"] = get_pref("_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 + $result = db_query("SELECT MAX(id) AS mid, COUNT(*) AS nf FROM ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]); $max_feed_id = db_fetch_result($result, 0, "mid"); @@ -1842,8 +1942,8 @@ $params["max_feed_id"] = (int) $max_feed_id; $params["num_feeds"] = (int) $num_feeds; - $params["collapsed_feedlist"] = (int) get_pref($link, "_COLLAPSED_FEEDLIST"); - $params["hotkeys"] = get_hotkeys_map($link); + $params["collapsed_feedlist"] = (int) get_pref("_COLLAPSED_FEEDLIST"); + $params["hotkeys"] = get_hotkeys_map(); $params["csrf_token"] = $_SESSION["csrf_token"]; $params["widescreen"] = (int) $_COOKIE["ttrss_widescreen"]; @@ -1853,7 +1953,7 @@ return $params; } - function get_hotkeys_info($link) { + function get_hotkeys_info() { $hotkeys = array( __("Navigation") => array( "next_feed" => __("Open next feed"), @@ -1862,6 +1962,8 @@ "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)"), + "next_article_noexpand" => __("Move to next article (don't expand or mark read)"), + "prev_article_noexpand" => __("Move to previous article (don't expand or mark read)"), "search_dialog" => __("Show search dialog")), __("Article") => array( "toggle_mark" => __("Toggle starred"), @@ -1877,8 +1979,10 @@ "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_expand" => __("Toggle article expansion (combined mode)"), + "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 +2000,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"), @@ -1911,10 +2016,14 @@ "help_dialog" => __("Show help dialog")) ); + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HOTKEY_INFO) as $plugin) { + $hotkeys = $plugin->hook_hotkey_info($hotkeys); + } + return $hotkeys; } - function get_hotkeys_map($link) { + function get_hotkeys_map() { $hotkeys = array( // "navigation" => array( "k" => "next_feed", @@ -1928,23 +2037,26 @@ "(191)|/" => "search_dialog", // "article" => array( "s" => "toggle_mark", - "S" => "toggle_publ", + "*s" => "toggle_publ", "u" => "toggle_unread", - "T" => "edit_tags", - "D" => "dismiss_selected", - "X" => "dismiss_read", + "*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", - "a W" => "toggle_widescreen", + "*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 *u" => "select_marked", "a p" => "select_published", "a i" => "select_invert", "a n" => "select_none", @@ -1955,9 +2067,10 @@ "f e" => "feed_edit", "f q" => "feed_catchup", "f x" => "feed_reverse", - "f D" => "feed_debug_update", - "f C" => "toggle_combined_mode", - "Q" => "catchup_all", + "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", @@ -1965,7 +2078,7 @@ "g s" => "goto_marked", "g p" => "goto_published", "g t" => "goto_tagcloud", - "g P" => "goto_prefs", + "g *p" => "goto_prefs", // "other" => array( "(9)|Tab" => "select_article_cursor", // tab "c l" => "create_label", @@ -1974,13 +2087,12 @@ "^(191)|Ctrl+/" => "help_dialog", ); - if (get_pref($link, 'COMBINED_DISPLAY_MODE')) { + if (get_pref('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) { + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HOTKEY_MAP) as $plugin) { $hotkeys = $plugin->hook_hotkey_map($hotkeys); } @@ -1997,10 +2109,10 @@ return array($prefixes, $hotkeys); } - function make_runtime_info($link) { + function make_runtime_info() { $data = array(); - $result = db_query($link, "SELECT MAX(id) AS mid, COUNT(*) AS nf FROM + $result = db_query("SELECT MAX(id) AS mid, COUNT(*) AS nf FROM ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]); $max_feed_id = db_fetch_result($result, 0, "mid"); @@ -2009,8 +2121,11 @@ $data["max_feed_id"] = (int) $max_feed_id; $data["num_feeds"] = (int) $num_feeds; - $data['last_article_id'] = getLastArticleId($link); - $data['cdm_expanded'] = get_pref($link, 'CDM_EXPANDED'); + $data['last_article_id'] = getLastArticleId(); + $data['cdm_expanded'] = get_pref('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")) { @@ -2040,7 +2155,7 @@ } if ($_SESSION["last_version_check"] + 86400 + rand(-1000, 1000) < time()) { - $new_version_details = @check_for_update($link); + $new_version_details = @check_for_update(); $data['new_version_available'] = (int) ($new_version_details != false); @@ -2051,7 +2166,7 @@ return $data; } - function search_to_sql($link, $search, $match_on) { + function search_to_sql($search) { $search_query_part = ""; @@ -2068,43 +2183,77 @@ $commandpair = explode(":", mb_strtolower($k), 2); - if ($commandpair[0] == "note" && $commandpair[1]) { - - if ($commandpair[1] == "true") - array_push($query_keywords, "($not (note IS NOT NULL AND note != ''))"); - else - array_push($query_keywords, "($not (note IS NULL OR note = ''))"); - - } else if ($commandpair[0] == "star" && $commandpair[1]) { - - if ($commandpair[1] == "true") - array_push($query_keywords, "($not (marked = true))"); - else - array_push($query_keywords, "($not (marked = false))"); - - } else if ($commandpair[0] == "pub" && $commandpair[1]) { + switch ($commandpair[0]) { + case "title": + if ($commandpair[1]) { + array_push($query_keywords, "($not (LOWER(ttrss_entries.title) LIKE '%". + db_escape_string(mb_strtolower($commandpair[1]))."%'))"); + } else { + array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') + OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + } + break; + case "author": + if ($commandpair[1]) { + array_push($query_keywords, "($not (LOWER(author) LIKE '%". + db_escape_string(mb_strtolower($commandpair[1]))."%'))"); + } else { + array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') + OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + } + break; + case "note": + if ($commandpair[1]) { + if ($commandpair[1] == "true") + array_push($query_keywords, "($not (note IS NOT NULL AND note != ''))"); + else if ($commandpair[1] == "false") + array_push($query_keywords, "($not (note IS NULL OR note = ''))"); + else + array_push($query_keywords, "($not (LOWER(note) LIKE '%". + db_escape_string(mb_strtolower($commandpair[1]))."%'))"); + } else { + array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') + OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + } + break; + case "star": - if ($commandpair[1] == "true") - array_push($query_keywords, "($not (published = true))"); - else - array_push($query_keywords, "($not (published = false))"); + if ($commandpair[1]) { + if ($commandpair[1] == "true") + array_push($query_keywords, "($not (marked = true))"); + else + array_push($query_keywords, "($not (marked = false))"); + } else { + array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') + OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + } + break; + case "pub": + if ($commandpair[1]) { + if ($commandpair[1] == "true") + array_push($query_keywords, "($not (published = true))"); + else + array_push($query_keywords, "($not (published = false))"); - } else if (strpos($k, "@") === 0) { + } else { + array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') + OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + } + break; + default: + if (strpos($k, "@") === 0) { - $user_tz_string = get_pref($link, 'USER_TIMEZONE', $_SESSION['uid']); - $orig_ts = strtotime(substr($k, 1)); - $k = date("Y-m-d", convert_timestamp($orig_ts, $user_tz_string, 'UTC')); + $user_tz_string = get_pref('USER_TIMEZONE', $_SESSION['uid']); + $orig_ts = strtotime(substr($k, 1)); + $k = date("Y-m-d", convert_timestamp($orig_ts, $user_tz_string, 'UTC')); - //$k = date("Y-m-d", strtotime(substr($k, 1))); + //$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") { - 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%'))"); + array_push($query_keywords, "(".SUBSTRING_FOR_DATE."(updated,1,LENGTH('$k')) $not = '$k')"); + } else { + array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') + OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))"); + } } } @@ -2113,35 +2262,35 @@ return $search_query_part; } - function getParentCategories($link, $cat, $owner_uid) { + function getParentCategories($cat, $owner_uid) { $rv = array(); - $result = db_query($link, "SELECT parent_cat FROM ttrss_feed_categories + $result = db_query("SELECT parent_cat FROM ttrss_feed_categories WHERE id = '$cat' AND parent_cat IS NOT NULL AND owner_uid = $owner_uid"); while ($line = db_fetch_assoc($result)) { array_push($rv, $line["parent_cat"]); - $rv = array_merge($rv, getParentCategories($link, $line["parent_cat"], $owner_uid)); + $rv = array_merge($rv, getParentCategories($line["parent_cat"], $owner_uid)); } return $rv; } - function getChildCategories($link, $cat, $owner_uid) { + function getChildCategories($cat, $owner_uid) { $rv = array(); - $result = db_query($link, "SELECT id FROM ttrss_feed_categories + $result = db_query("SELECT id FROM ttrss_feed_categories WHERE parent_cat = '$cat' AND owner_uid = $owner_uid"); while ($line = db_fetch_assoc($result)) { array_push($rv, $line["id"]); - $rv = array_merge($rv, getChildCategories($link, $line["id"], $owner_uid)); + $rv = array_merge($rv, getChildCategories($line["id"], $owner_uid)); } 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($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 +2307,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($search); $search_query_part .= " AND "; } @@ -2176,10 +2325,10 @@ $override_order = "updated DESC"; - $filter_query_part = filter_to_sql($link, $filter, $owner_uid); + $filter_query_part = filter_to_sql($filter, $owner_uid); // Try to check if SQL regexp implementation chokes on a valid regexp - $result = db_query($link, "SELECT true AS true_val FROM ttrss_entries, + $result = db_query("SELECT true AS true_val FROM ttrss_entries, ttrss_user_entries, ttrss_feeds, ttrss_feed_categories WHERE $filter_query_part LIMIT 1", false); @@ -2207,18 +2356,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); + + $unread = getFeedUnread($feed, $cat_view); if ($cat_view && $feed > 0 && $include_children) - $unread += getCategoryChildrenUnread($link, $feed); + $unread += getCategoryChildrenUnread($feed); + + if ($unread > 0) + $view_query_part = " unread = true AND "; - if ($unread > 0) { - $view_query_part = " unread = true AND "; - } } } @@ -2226,18 +2376,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; } @@ -2260,7 +2410,7 @@ if ($feed > 0) { if ($include_children) { - $subcats = getChildCategories($link, $feed, $owner_uid); + $subcats = getChildCategories($feed, $owner_uid); array_push($subcats, $feed); $cats_qpart = join(",", $subcats); } else { @@ -2280,7 +2430,7 @@ if ($feed > 0) { if ($include_children) { # sub-cats - $subcats = getChildCategories($link, $feed, $owner_uid); + $subcats = getChildCategories($feed, $owner_uid); array_push($subcats, $feed); $query_strategy_part = "cat_id IN (". @@ -2310,6 +2460,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) { @@ -2317,7 +2471,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,"; @@ -2336,20 +2493,21 @@ } else if ($feed == -3) { // fresh virtual feed $query_strategy_part = "unread = true AND score >= 0"; - $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE", $owner_uid); + $intl = get_pref("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 + $allow_archived = true; $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 @@ -2363,20 +2521,10 @@ $query_strategy_part = "true"; } - if (get_pref($link, "SORT_HEADLINES_BY_FEED_DATE", $owner_uid)) { - $date_sort_field = "updated"; - } else { - $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 = "score DESC, date_entered 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) { @@ -2389,17 +2537,18 @@ $feed_title = T_sprintf("Search results: %s", $search); } else { if ($cat_view) { - $feed_title = getCategoryTitle($link, $feed); + $feed_title = getCategoryTitle($feed); } else { if (is_numeric($feed) && $feed > 0) { - $result = db_query($link, "SELECT title,site_url,last_error + $result = db_query("SELECT title,site_url,last_error,last_updated FROM ttrss_feeds WHERE id = '$feed' AND owner_uid = $owner_uid"); $feed_title = db_fetch_result($result, 0, "title"); $feed_site_url = db_fetch_result($result, 0, "site_url"); $last_error = db_fetch_result($result, 0, "last_error"); + $last_updated = db_fetch_result($result, 0, "last_updated"); } else { - $feed_title = getFeedTitle($link, $feed); + $feed_title = getFeedTitle($feed); } } } @@ -2419,7 +2568,7 @@ } // proper override_order applied above - if ($vfeed_query_part && !$ignore_vfeed_group && get_pref($link, 'VFEED_GROUP_BY_FEED', $owner_uid)) { + if ($vfeed_query_part && !$ignore_vfeed_group && get_pref('VFEED_GROUP_BY_FEED', $owner_uid)) { if (!$override_order) { $order_by = "ttrss_feeds.title, $order_by"; } else { @@ -2436,6 +2585,9 @@ LEFT JOIN ttrss_feeds ON (feed_id = ttrss_feeds.id)"; } + if ($vfeed_query_part) + $vfeed_query_part .= "favicon_avg_color,"; + $query = "SELECT DISTINCT date_entered, guid, @@ -2449,11 +2601,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 @@ -2470,7 +2622,7 @@ if ($_REQUEST["debug"]) print $query; - $result = db_query($link, $query); + $result = db_query($query); } else { // browsing by tag @@ -2492,11 +2644,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"; @@ -2539,26 +2691,18 @@ // $tag_sql = "tag_name = '$feed'"; DEFAULT way // error_log("[". $select_qpart . "][" . $from_qpart . "][" .$where_qpart . "]"); - $result = db_query($link, $select_qpart . $from_qpart . $where_qpart); + $result = db_query($select_qpart . $from_qpart . $where_qpart); } - return array($result, $feed_title, $feed_site_url, $last_error); + return array($result, $feed_title, $feed_site_url, $last_error, $last_updated); } - function sanitize($link, $str, $force_strip_tags = false, $owner = false, $site_url = false) { + function sanitize($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, 'balance' => 0); - $spec = 'img=width,height'; - $res = htmLawed($res, $config, $spec); - - if (get_pref($link, "STRIP_IMAGES", $owner)) { - $res = preg_replace('/<img[^>]+>/is', '', $res); - } - if (strpos($res, "href=") === false) $res = rewrite_urls($res); @@ -2584,10 +2728,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("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,12 +2764,78 @@ } } - $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', 'aside', + 'b', 'bdi', 'bdo', 'big', 'blockquote', 'body', 'br', + 'caption', 'cite', 'center', 'code', 'col', 'colgroup', + 'data', 'dd', 'del', 'details', 'div', 'dl', 'font', + 'dt', 'em', 'footer', 'figure', 'figcaption', + 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'html', 'i', + 'img', 'ins', 'kbd', 'li', 'main', 'mark', 'nav', 'noscript', + 'ol', 'p', 'pre', 'q', 'ruby', 'rp', 'rt', 's', 'samp', 'section', + 'small', 'source', 'span', 'strike', 'strong', 'sub', 'summary', + 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'time', + 'tr', 'track', 'tt', 'u', 'ul', 'var', 'wbr', 'video' ); + + if ($_SESSION['hasSandbox']) $allowed_elements[] = 'iframe'; + + $disallowed_attributes = array('id', 'style', 'class'); + + foreach (PluginHost::getInstance()->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; + } + + function strip_harmful_tags($doc, $allowed_elements, $disallowed_attributes) { + $xpath = new DOMXPath($doc); + $entries = $xpath->query('//*'); + + foreach ($entries as $entry) { + if (!in_array($entry->nodeName, $allowed_elements)) { + $entry->parentNode->removeChild($entry); + } + + if ($entry->hasAttributes()) { + $attrs_to_remove = array(); - return $doc->saveXML($node); + 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) { + function check_for_update() { if (CHECK_FOR_NEW_VERSION && $_SESSION['access_level'] >= 10) { $version_url = "http://tt-rss.org/version.php?ver=" . VERSION . "&iid=" . sha1(SELF_URL_PATH); @@ -2610,8 +2845,7 @@ if ($version_data) { $version_data = json_decode($version_data, true); if ($version_data && $version_data['version']) { - - if (version_compare(VERSION, $version_data['version']) == -1) { + if (version_compare(VERSION_STATIC, $version_data['version']) == -1) { return $version_data; } } @@ -2620,7 +2854,7 @@ return false; } - function catchupArticlesById($link, $ids, $cmode, $owner_uid = false) { + function catchupArticlesById($ids, $cmode, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; if (count($ids) == 0) return; @@ -2634,30 +2868,30 @@ $ids_qpart = join(" OR ", $tmp_ids); if ($cmode == 0) { - db_query($link, "UPDATE ttrss_user_entries SET + db_query("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 + db_query("UPDATE ttrss_user_entries SET unread = true WHERE ($ids_qpart) AND owner_uid = $owner_uid"); } else { - db_query($link, "UPDATE ttrss_user_entries SET + db_query("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 + $result = db_query("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); + ccache_update($line["feed_id"], $owner_uid); } } - function get_article_tags($link, $id, $owner_uid = 0, $tag_cache = false) { + function get_article_tags($id, $owner_uid = 0, $tag_cache = false) { $a_id = db_escape_string($id); @@ -2668,13 +2902,12 @@ ttrss_tags WHERE post_int_id = (SELECT int_id FROM ttrss_user_entries WHERE ref_id = '$a_id' AND owner_uid = '$owner_uid' LIMIT 1) ORDER BY tag_name"; - $obj_id = md5("TAGS:$owner_uid:$id"); $tags = array(); /* check cache first */ if ($tag_cache === false) { - $result = db_query($link, "SELECT tag_cache FROM ttrss_user_entries + $result = db_query("SELECT tag_cache FROM ttrss_user_entries WHERE ref_id = '$id' AND owner_uid = $owner_uid"); $tag_cache = db_fetch_result($result, 0, "tag_cache"); @@ -2686,7 +2919,7 @@ /* do it the hard way */ - $tmp_result = db_query($link, $query); + $tmp_result = db_query($query); while ($tmp_line = db_fetch_assoc($tmp_result)) { array_push($tags, $tmp_line["tag_name"]); @@ -2696,7 +2929,7 @@ $tags_str = db_escape_string(join(",", $tags)); - db_query($link, "UPDATE ttrss_user_entries + db_query("UPDATE ttrss_user_entries SET tag_cache = '$tags_str' WHERE ref_id = '$id' AND owner_uid = $owner_uid"); } @@ -2724,43 +2957,29 @@ 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; - } - exit; - } + function render_login_form() { + header('Cache-Control: public'); - // from http://developer.apple.com/internet/safari/faq.html - function no_cache_incantation() { - header("Expires: Mon, 22 Dec 1980 00:00:00 GMT"); // Happy birthday to me :) - header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified - header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); // HTTP/1.1 - header("Cache-Control: post-check=0, pre-check=0", false); - header("Pragma: no-cache"); // HTTP/1.0 + require_once "login_form.php"; + exit; } function format_warning($msg, $id = "") { global $link; return "<div class=\"warning\" id=\"$id\"> - <img src=\"".theme_image($link, "images/sign_excl.svg")."\">$msg</div>"; + <span><img src=\"images/sign_excl.svg\"></span><span>$msg</span></div>"; } function format_notice($msg, $id = "") { global $link; return "<div class=\"notice\" id=\"$id\"> - <img src=\"".theme_image($link, "images/sign_info.svg")."\">$msg</div>"; + <span><img src=\"images/sign_info.svg\"></span><span>$msg</span></div>"; } function format_error($msg, $id = "") { global $link; return "<div class=\"error\" id=\"$id\"> - <img src=\"".theme_image($link, "images/sign_excl.svg")."\">$msg</div>"; + <span><img src=\"images/sign_excl.svg\"></span><span>$msg</span></div>"; } function print_notice($msg) { @@ -2781,26 +3000,21 @@ return vsprintf(__(array_shift($args)), $args); } - function format_inline_player($link, $url, $ctype) { + function format_inline_player($url, $ctype) { $entry = ""; + $url = htmlspecialchars($url); + if (strpos($ctype, "audio/") === 0) { if ($_SESSION["hasAudio"] && (strpos($ctype, "ogg") !== false || - strpos($_SERVER['HTTP_USER_AGENT'], "Chrome") !== false || - strpos($_SERVER['HTTP_USER_AGENT'], "Safari") !== false )) { - - $id = 'AUDIO-' . uniqid(); + $_SESSION["hasMp3"])) { - $entry .= "<audio id=\"$id\"\" controls style='display : none'> + $entry .= "<audio controls> <source type=\"$ctype\" src=\"$url\"></source> </audio>"; - $entry .= "<span onclick=\"player(this)\" - title=\"".__("Click to play")."\" status=\"0\" - class=\"player\" audio-id=\"$id\">".__("Play")."</span>"; - } else { $entry .= "<object type=\"application/x-shockwave-flash\" @@ -2811,7 +3025,8 @@ </object>"; } - if ($entry) $entry .= " " . basename($url); + if ($entry) $entry .= " <a target=\"_blank\" + href=\"$url\">" . basename($url) . "</a>"; return $entry; @@ -2826,7 +3041,7 @@ } - function format_article($link, $id, $mark_as_read = true, $zoom_mode = false, $owner_uid = false) { + function format_article($id, $mark_as_read = true, $zoom_mode = false, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; $rv = array(); @@ -2834,9 +3049,9 @@ $rv['id'] = $id; /* we can figure out feed_id from article id anyway, why do we - * pass feed_id here? let's ignore the argument :( */ + * pass feed_id here? let's ignore the argument :(*/ - $result = db_query($link, "SELECT feed_id FROM ttrss_user_entries + $result = db_query("SELECT feed_id FROM ttrss_user_entries WHERE ref_id = '$id'"); $feed_id = (int) db_fetch_result($result, 0, "feed_id"); @@ -2846,16 +3061,18 @@ //if (!$zoom_mode) { print "<article id='$id'><![CDATA["; }; if ($mark_as_read) { - $result = db_query($link, "UPDATE ttrss_user_entries + $result = db_query("UPDATE ttrss_user_entries SET unread = false,last_read = NOW() WHERE ref_id = '$id' AND owner_uid = $owner_uid"); - ccache_update($link, $feed_id, $owner_uid); + ccache_update($feed_id, $owner_uid); } - $result = db_query($link, "SELECT id,title,link,content,feed_id,comments,int_id, + $result = db_query("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, + (SELECT always_display_enclosures FROM ttrss_feeds WHERE id = feed_id) as always_display_enclosures, num_comments, tag_cache, author, @@ -2871,14 +3088,12 @@ $tag_cache = $line["tag_cache"]; - $line["tags"] = get_article_tags($link, $id, $owner_uid, $line["tag_cache"]); + $line["tags"] = get_article_tags($id, $owner_uid, $line["tag_cache"]); unset($line["tag_cache"]); - $line["content"] = sanitize($link, $line["content"], false, $owner_uid, $line["site_url"]); + $line["content"] = sanitize($line["content"], false, $owner_uid, $line["site_url"]); - global $pluginhost; - - foreach ($pluginhost->get_hooks($pluginhost::HOOK_RENDER_ARTICLE) as $p) { + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE) as $p) { $line = $p->hook_render_article($line); } @@ -2904,14 +3119,9 @@ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/> <title>Tiny Tiny RSS - ".$line["title"]."</title> <link rel=\"stylesheet\" type=\"text/css\" href=\"tt-rss.css\"> - </head><body>"; + </head><body id=\"ttrssZoom\">"; } - $title_escaped = htmlspecialchars($line['title']); - - $rv['content'] .= "<div id=\"PTITLE-FULL-$id\" style=\"display : none\">" . - strip_tags($line['title']) . "</div>"; - $rv['content'] .= "<div class=\"postReply\" id=\"POST-$id\">"; $rv['content'] .= "<div class=\"postHeader\" id=\"POSTHDR-$id\">"; @@ -2922,7 +3132,7 @@ $entry_author = __(" - ") . $entry_author; } - $parsed_updated = make_local_datetime($link, $line["updated"], true, + $parsed_updated = make_local_datetime($line["updated"], true, $owner_uid, true); $rv['content'] .= "<div class=\"postDate\">$parsed_updated</div>"; @@ -2932,8 +3142,8 @@ title=\"".htmlspecialchars($line['title'])."\" href=\"" . htmlspecialchars($line["link"]) . "\">" . - $line["title"] . - "<span class='author'>$entry_author</span></a></div>"; + $line["title"] . "</a>" . + "<span class='author'>$entry_author</span></div>"; } else { $rv['content'] .= "<div class='postTitle'>" . $line["title"] . "$entry_author</div>"; } @@ -2946,7 +3156,7 @@ if (!$entry_comments) $entry_comments = " "; # placeholder $rv['content'] .= "<div class='postTags' style='float : right'> - <img src='".theme_image($link, 'images/tag.png')."' + <img src='images/tag.png' class='tagsPic' alt='Tags' title='Tags'> "; if (!$zoom_mode) { @@ -2958,23 +3168,26 @@ id=\"ATSTRTIP-$id\" connectId=\"ATSTR-$id\" position=\"below\">$tags_str_full</div>"; - global $pluginhost; - - foreach ($pluginhost->get_hooks($pluginhost::HOOK_ARTICLE_BUTTON) as $p) { + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_ARTICLE_BUTTON) as $p) { $rv['content'] .= $p->hook_article_button($line); } - } else { $tags_str = strip_tags($tags_str); $rv['content'] .= "<span id=\"ATSTR-$id\">$tags_str</span>"; } $rv['content'] .= "</div>"; - $rv['content'] .= "<div clear='both'>$entry_comments</div>"; + $rv['content'] .= "<div clear='both'>"; + + foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_ARTICLE_LEFT_BUTTON) as $p) { + $rv['content'] .= $p->hook_article_left_button($line); + } + + $rv['content'] .= "$entry_comments</div>"; if ($line["orig_feed_id"]) { - $tmp_result = db_query($link, "SELECT * FROM ttrss_archived_feeds + $tmp_result = db_query("SELECT * FROM ttrss_archived_feeds WHERE id = ".$line["orig_feed_id"]); if (db_num_rows($tmp_result) != 0) { @@ -3009,35 +3222,11 @@ $rv['content'] .= "<div class=\"postContent\">"; - // 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'] .= "<div dojoType=\"dijit.form.DropDownButton\">". - "<span>" . __('Related')."</span>"; - $rv['content'] .= "<div dojoType=\"dijit.Menu\" style=\"display: none;\">"; - - while ($nline = db_fetch_assoc($ngram_result)) { - $rv['content'] .= "<div onclick=\"hlOpenInNewTab(null,".$nline['id'].")\" - dojoType=\"dijit.MenuItem\">".$nline['title']."</div>"; - - } - $rv['content'] .= "</div></div><br/"; - } - } - $rv['content'] .= $line["content"]; - - $rv['content'] .= format_article_enclosures($link, $id, - $always_display_enclosures, $line["content"]); + $rv['content'] .= format_article_enclosures($id, + sql_bool_to_bool($line["always_display_enclosures"]), + $line["content"], + sql_bool_to_bool($line["hide_images"])); $rv['content'] .= "</div>"; @@ -3047,7 +3236,7 @@ if ($zoom_mode) { $rv['content'] .= " - <div style=\"text-align : center\"> + <div class='footer'> <button onclick=\"return window.close()\">". __("Close this window")."</button></div>"; $rv['content'] .= "</body></html>"; @@ -3059,7 +3248,7 @@ function print_checkpoint($n, $s) { $ts = microtime(true); - echo sprintf("<!-- CP[$n] %.4f seconds -->", $ts - $s); + echo sprintf("<!-- CP[$n] %.4f seconds -->\n", $ts - $s); return $ts; } @@ -3108,23 +3297,23 @@ } } // function encrypt_password - function load_filters($link, $feed_id, $owner_uid, $action_id = false) { + function load_filters($feed_id, $owner_uid, $action_id = false) { $filters = array(); - $cat_id = (int)getFeedCategory($link, $feed_id); + $cat_id = (int)getFeedCategory($feed_id); - $result = db_query($link, "SELECT * FROM ttrss_filters2 WHERE - owner_uid = $owner_uid AND enabled = true"); + $result = db_query("SELECT * FROM ttrss_filters2 WHERE + owner_uid = $owner_uid AND enabled = true ORDER BY order_id, title"); $check_cats = join(",", array_merge( - getParentCategories($link, $cat_id, $owner_uid), + getParentCategories($cat_id, $owner_uid), array($cat_id))); while ($line = db_fetch_assoc($result)) { $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 + $result2 = db_query("SELECT + 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 @@ -3141,11 +3330,12 @@ $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); } - $result2 = db_query($link, "SELECT a.action_param,t.name AS type_name + $result2 = db_query("SELECT a.action_param,t.name AS type_name FROM ttrss_filters2_actions AS a, ttrss_filter_actions AS t WHERE @@ -3164,6 +3354,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; @@ -3193,80 +3384,35 @@ return is_file(ICONS_DIR . "/$id.ico") && filesize(ICONS_DIR . "/$id.ico") > 0; } - function init_connection($link) { - if ($link) { - - if (DB_TYPE == "pgsql") { - pg_query($link, "set client_encoding = 'UTF-8'"); - pg_set_client_encoding("UNICODE"); - pg_query($link, "set datestyle = 'ISO, european'"); - pg_query($link, "set TIME ZONE 0"); - } else { - db_query($link, "SET time_zone = '+0:0'"); - - if (defined('MYSQL_CHARSET') && MYSQL_CHARSET) { - db_query($link, "SET NAMES " . MYSQL_CHARSET); - } - } + function init_plugins() { + PluginHost::getInstance()->load(PLUGINS, PluginHost::KIND_ALL); - global $pluginhost; - - $pluginhost = new PluginHost($link); - $pluginhost->load(PLUGINS, $pluginhost::KIND_ALL); - - return true; - } else { - print "Unable to connect to database:" . db_last_error(); - return false; - } + return true; } function format_tags_string($tags, $id) { + if (!is_array($tags) || count($tags) == 0) { + return __("no tags"); + } else { + $maxtags = min(5, count($tags)); - $tags_str = ""; - $tags_nolinks_str = ""; - - $num_tags = 0; - - $tag_limit = 6; - - $formatted_tags = array(); - - foreach ($tags as $tag) { - $num_tags++; - $tag_escaped = str_replace("'", "\\'", $tag); - - if (mb_strlen($tag) > 30) { - $tag = truncate_string($tag, 30); + for ($i = 0; $i < $maxtags; $i++) { + $tags_str .= "<a class=\"tag\" href=\"#\" onclick=\"viewfeed('".$tags[$i]."'\")>" . $tags[$i] . "</a>, "; } - $tag_str = "<a href=\"javascript:viewfeed('$tag_escaped')\">$tag</a>"; - - array_push($formatted_tags, $tag_str); + $tags_str = mb_substr($tags_str, 0, mb_strlen($tags_str)-2); - $tmp_tags_str = implode(", ", $formatted_tags); + if (count($tags) > $maxtags) + $tags_str .= ", …"; - if ($num_tags == $tag_limit || mb_strlen($tmp_tags_str) > 150) { - break; - } + return $tags_str; } - - $tags_str = implode(", ", $formatted_tags); - - if ($num_tags < count($tags)) { - $tags_str .= ", …"; - } - - if ($num_tags == 0) { - $tags_str = __("no tags"); - } - - return $tags_str; - } function format_article_labels($labels, $id) { + if (!is_array($labels)) return ''; + $labels_str = ""; foreach ($labels as $l) { @@ -3289,7 +3435,7 @@ } - function get_feed_category($link, $feed_cat, $parent_cat_id = false) { + function get_feed_category($feed_cat, $parent_cat_id = false) { if ($parent_cat_id) { $parent_qpart = "parent_cat = '$parent_cat_id'"; $parent_insert = "'$parent_cat_id'"; @@ -3298,7 +3444,7 @@ $parent_insert = "NULL"; } - $result = db_query($link, + $result = db_query( "SELECT id FROM ttrss_feed_categories WHERE $parent_qpart AND title = '$feed_cat' AND owner_uid = ".$_SESSION["uid"]); @@ -3309,11 +3455,11 @@ } } - function add_feed_category($link, $feed_cat, $parent_cat_id = false) { + function add_feed_category($feed_cat, $parent_cat_id = false) { if (!$feed_cat) return false; - db_query($link, "BEGIN"); + db_query("BEGIN"); if ($parent_cat_id) { $parent_qpart = "parent_cat = '$parent_cat_id'"; @@ -3323,17 +3469,19 @@ $parent_insert = "NULL"; } - $result = db_query($link, + $feed_cat = mb_substr($feed_cat, 0, 250); + + $result = db_query( "SELECT id FROM ttrss_feed_categories WHERE $parent_qpart AND title = '$feed_cat' AND owner_uid = ".$_SESSION["uid"]); if (db_num_rows($result) == 0) { - $result = db_query($link, + $result = db_query( "INSERT INTO ttrss_feed_categories (owner_uid,title,parent_cat) VALUES ('".$_SESSION["uid"]."', '$feed_cat', $parent_insert)"); - db_query($link, "COMMIT"); + db_query("COMMIT"); return true; } @@ -3341,8 +3489,8 @@ return false; } - function getArticleFeed($link, $id) { - $result = db_query($link, "SELECT feed_id FROM ttrss_user_entries + function getArticleFeed($id) { + $result = db_query("SELECT feed_id FROM ttrss_user_entries WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]); if (db_num_rows($result) != 0) { @@ -3387,14 +3535,14 @@ } - function get_article_enclosures($link, $id) { + function get_article_enclosures($id) { $query = "SELECT * FROM ttrss_enclosures WHERE post_id = '$id' AND content_url != ''"; $rv = array(); - $result = db_query($link, $query); + $result = db_query($query); if (db_num_rows($result) > 0) { while ($line = db_fetch_assoc($result)) { @@ -3405,7 +3553,7 @@ return $rv; } - function save_email_address($link, $email) { + function save_email_address($email) { // FIXME: implement persistent storage of emails if (!$_SESSION['stored_emails']) @@ -3416,13 +3564,13 @@ } - function get_feed_access_key($link, $feed_id, $is_cat, $owner_uid = false) { + function get_feed_access_key($feed_id, $is_cat, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; $sql_is_cat = bool_to_sql_bool($is_cat); - $result = db_query($link, "SELECT access_key FROM ttrss_access_keys + $result = db_query("SELECT access_key FROM ttrss_access_keys WHERE feed_id = '$feed_id' AND is_cat = $sql_is_cat AND owner_uid = " . $owner_uid); @@ -3431,7 +3579,7 @@ } else { $key = db_escape_string(sha1(uniqid(rand(), true))); - $result = db_query($link, "INSERT INTO ttrss_access_keys + $result = db_query("INSERT INTO ttrss_access_keys (access_key, feed_id, is_cat, owner_uid) VALUES ('$key', '$feed_id', $sql_is_cat, '$owner_uid')"); @@ -3475,9 +3623,9 @@ return is_html(fetch_file_contents($url, false, $login, $pass)); } - function print_label_select($link, $name, $value, $attributes = "") { + function print_label_select($name, $value, $attributes = "") { - $result = db_query($link, "SELECT caption FROM ttrss_labels2 + $result = db_query("SELECT caption FROM ttrss_labels2 WHERE owner_uid = '".$_SESSION["uid"]."' ORDER BY caption"); print "<select default=\"$value\" name=\"" . htmlspecialchars($name) . @@ -3499,10 +3647,10 @@ } - function format_article_enclosures($link, $id, $always_display_enclosures, - $article_content) { + function format_article_enclosures($id, $always_display_enclosures, + $article_content, $hide_images = false) { - $result = get_article_enclosures($link, $id); + $result = get_article_enclosures($id); $rv = ''; if (count($result) > 0) { @@ -3520,7 +3668,7 @@ $filename = substr($url, strrpos($url, "/")+1); - $player = format_inline_player($link, $url, $ctype); + $player = format_inline_player($url, $ctype); if ($player) array_push($entries_inline, $player); @@ -3541,7 +3689,7 @@ array_push($entries, $entry); } - if (!get_pref($link, "STRIP_IMAGES")) { + if ($_SESSION['uid'] && !get_pref("STRIP_IMAGES") && !$_SESSION["bw_limit"]) { if ($always_display_enclosures || !preg_match("/<img/i", $article_content)) { @@ -3550,10 +3698,16 @@ if (preg_match("/image/", $entry["type"]) || preg_match("/\.(jpg|png|gif|bmp)/i", $entry["filename"])) { - $rv .= "<p><img - alt=\"".htmlspecialchars($entry["filename"])."\" - src=\"" .htmlspecialchars($entry["url"]) . "\"/></p>"; + if (!$hide_images) { + $rv .= "<p><img + alt=\"".htmlspecialchars($entry["filename"])."\" + src=\"" .htmlspecialchars($entry["url"]) . "\"/></p>"; + } else { + $rv .= "<p><a target=\"_blank\" + href=\"".htmlspecialchars($entry["url"])."\" + >" .htmlspecialchars($entry["url"]) . "</a></p>"; + } } } } @@ -3565,20 +3719,22 @@ $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; } - function getLastArticleId($link) { - $result = db_query($link, "SELECT MAX(ref_id) AS id FROM ttrss_user_entries + function getLastArticleId() { + $result = db_query("SELECT MAX(ref_id) AS id FROM ttrss_user_entries WHERE owner_uid = " . $_SESSION["uid"]); if (db_num_rows($result) == 1) { @@ -3636,7 +3792,9 @@ $sphinxClient = new SphinxClient(); - $sphinxClient->SetServer('localhost', 9312); + $sphinxpair = explode(":", SPHINX_SERVER, 2); + + $sphinxClient->SetServer($sphinxpair[0], $sphinxpair[1]); $sphinxClient->SetConnectTimeout(1); $sphinxClient->SetFieldWeights(array('title' => 70, 'content' => 30, @@ -3662,7 +3820,7 @@ return $ids; } - function cleanup_tags($link, $days = 14, $limit = 1000) { + function cleanup_tags($days = 14, $limit = 1000) { if (DB_TYPE == "pgsql") { $interval_query = "date_updated < NOW() - INTERVAL '$days days'"; @@ -3680,7 +3838,7 @@ WHERE post_int_id = int_id AND $interval_query AND ref_id = ttrss_entries.id AND tag_cache != '' LIMIT $limit_part"; - $result = db_query($link, $query); + $result = db_query($query); $ids = array(); @@ -3690,10 +3848,9 @@ 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); + $tmp_result = db_query("DELETE FROM ttrss_tags WHERE id IN ($ids)"); + $tags_deleted += db_affected_rows($tmp_result); } else { break; } @@ -3701,13 +3858,11 @@ $limit -= $limit_part; } - print "\n"; - return $tags_deleted; } - function print_user_stylesheet($link) { - $value = get_pref($link, 'USER_STYLESHEET'); + function print_user_stylesheet() { + $value = get_pref('USER_STYLESHEET'); if ($value) { print "<style type=\"text/css\">"; @@ -3763,7 +3918,7 @@ return $html; } - function filter_to_sql($link, $filter, $owner_uid) { + function filter_to_sql($filter, $owner_uid) { $query = array(); if (DB_TYPE == "pgsql") @@ -3779,7 +3934,7 @@ $rule['reg_exp'] = db_escape_string($rule['reg_exp']); - switch ($rule["type"]) { + switch ($rule["type"]) { case "title": $qpart = "LOWER(ttrss_entries.title) $reg_qpart LOWER('". $rule['reg_exp'] . "')"; @@ -3807,6 +3962,8 @@ 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"]); } @@ -3814,7 +3971,7 @@ if (isset($rule["cat_id"])) { if ($rule["cat_id"] > 0) { - $children = getChildCategories($link, $rule["cat_id"], $owner_uid); + $children = getChildCategories($rule["cat_id"], $owner_uid); array_push($children, $rule["cat_id"]); $children = join(",", $children); @@ -3833,10 +3990,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')) { @@ -3884,8 +4045,8 @@ return $tempname; } - function getFeedCategory($link, $feed) { - $result = db_query($link, "SELECT cat_id FROM ttrss_feeds + function getFeedCategory($feed) { + $result = db_query("SELECT cat_id FROM ttrss_feeds WHERE id = '$feed'"); if (db_num_rows($result) > 0) { @@ -3900,4 +4061,167 @@ return in_array($interface, class_implements($class)); } + function geturl($url){ + + if (!function_exists('curl_init')) + return user_error('CURL Must be installed for geturl function to work. Ask your host to enable it or uncomment extension=php_curl.dll in php.ini', E_USER_ERROR); + + $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):''; + } + $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'; + + $rv = ''; + + foreach ($files as $js) { + if (!isset($_GET['debug'])) { + $cached_file = CACHE_DIR . "/js/".basename($js).".js"; + + if (file_exists($cached_file) && + is_readable($cached_file) && + filemtime($cached_file) >= filemtime("js/$js.js")) { + + $rv .= file_get_contents($cached_file); + + } else { + $minified = JShrink\Minifier::minify(file_get_contents("js/$js.js")); + file_put_contents($cached_file, $minified); + $rv .= $minified; + } + } else { + $rv .= file_get_contents("js/$js.js"); + } + } + + return $rv; + } + + function stylesheet_tag($filename) { + $timestamp = filemtime($filename); + + echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"$filename?$timestamp\"/>\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 "<script type=\"text/javascript\" charset=\"utf-8\" src=\"$filename?$timestamp\"></script>\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); + } + + function format_libxml_error($error) { + return T_sprintf("LibXML error %s at line %d (column %d): %s", + $error->code, $error->line, $error->column, + $error->message); + } + ?> |