]> git.wh0rd.org - tt-rss.git/blobdiff - include/functions.php
Merge branch 'master' of git://github.com/richbeales/Tiny-Tiny-RSS into richbeales...
[tt-rss.git] / include / functions.php
index 72d86e0a7c5be273be5aff1990950c8a271cce1a..0e2a922ba1239870bcbbe38cccdef5ad7f58979b 100644 (file)
@@ -1,6 +1,6 @@
 <?php
        define('EXPECTED_CONFIG_VERSION', 26);
-       define('SCHEMA_VERSION', 103);
+       define('SCHEMA_VERSION', 106);
 
        $fetch_last_error = false;
        $pluginhost = false;
@@ -44,6 +44,7 @@
                $tr = array(
                                        "auto"  => "Detect automatically",
                                        "ca_CA" => "Català",
+                                       "cs_CZ" => "Česky",
                                        "en_US" => "English",
                                        "es_ES" => "Español",
                                        "de_DE" => "Deutsch",
@@ -51,6 +52,7 @@
                                        "hu_HU" => "Magyar (Hungarian)",
                                        "it_IT" => "Italiano",
                                        "ja_JP" => "日本語 (Japanese)",
+                                       "lv_LV" => "Latviešu",
                                        "nb_NO" => "Norwegian bokmål",
                                        "pl_PL" => "Polski",
                                        "ru_RU" => "Русский",
                        $lang = _TRANSLATION_OVERRIDE_DEFAULT;
                }
 
-               /* In login action of mobile version */
-               if ($_POST["language"] && defined('MOBILE_VERSION')) {
-                       $lang = $_POST["language"];
-               } else if ($_SESSION["language"] && $_SESSION["language"] != "auto") {
+               if ($_SESSION["language"] && $_SESSION["language"] != "auto") {
                        $lang = $_SESSION["language"];
                }
 
                                _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");
        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');
         * @return void
         */
        function _debug($msg) {
-               if (defined('QUIET') && QUIET) {
-                       return;
-               }
                $ts = strftime("%H:%M:%S", time());
                if (function_exists('posix_getpid')) {
                        $ts = "$ts/" . posix_getpid();
                }
-               print "[$ts] $msg\n";
+
+               if (!(defined('QUIET') && QUIET)) {
+                       print "[$ts] $msg\n";
+               }
+
+               if (defined('LOGFILE'))  {
+                       $fp = fopen(LOGFILE, 'a+');
+
+                       if ($fp) {
+                               fputs($fp, "[$ts] $msg\n");
+                               fclose($fp);
+                       }
+               }
+
        } // function _debug
 
        /**
                if ($debug) {
                        _debug("Purged feed $feed_id ($purge_interval): deleted $rows articles");
                }
+
+               return $rows;
        } // function purge_feed
 
        function feed_purge_interval($link, $feed_id) {
                global $fetch_last_error;
 
                if (function_exists('curl_init') && !ini_get("open_basedir")) {
-                       $ch = curl_init($url);
+
+                       if (ini_get("safe_mode")) {
+                               $ch = curl_init(geturl($url));
+                       } else {
+                               $ch = curl_init($url);
+                       }
 
                        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout ? $timeout : 15);
                        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout ? $timeout : 45);
-                       curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+                       curl_setopt($ch, CURLOPT_FOLLOWLOCATION, !ini_get("safe_mode"));
                        curl_setopt($ch, CURLOPT_MAXREDIRS, 20);
                        curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
                        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
                        $data = @file_get_contents($url);
 
+                       $gzdecoded = gzdecode($data);
+                       if ($gzdecoded) $data = $gzdecoded;
+
                        if (!$data && function_exists('error_get_last')) {
                                $error = error_get_last();
                                $fetch_last_error = $error["message"];
                         else
                                $sel = "";
 
+                       $v = trim($v);
+
                        print "<option value=\"$v\" $sel>$v</option>";
                }
                print "</select>";
                         else
                                $sel = "";
 
+                       $v = trim($v);
+
                        print "<option $sel value=\"$v\">".$values[$v]."</option>";
                }
 
                print "</select>";
        }
 
-       function getmicrotime() {
-               list($usec, $sec) = explode(" ",microtime());
-               return ((float)$usec + (float)$sec);
-       }
-
        function print_radio($id, $default, $true_is, $values, $attributes = "") {
                foreach ($values as $v) {
 
 
        function initialize_user_prefs($link, $uid, $profile = false) {
 
-               $uid = db_escape_string($uid);
+               $uid = db_escape_string($link, $uid);
 
                if (!$profile) {
                        $profile = "NULL";
                }
        }
 
-       function login_sequence($link, $login_form = 0) {
+       function login_sequence($link) {
                $_SESSION["prefs_cache"] = false;
 
                if (SINGLE_USER_MODE) {
                        authenticate_user($link, "admin", null);
+                       cache_prefs($link);
                        load_user_plugins($link, $_SESSION["uid"]);
                } else {
                        if (!$_SESSION["uid"] || !validate_session($link)) {
                                         authenticate_user($link, null, null, true);
                                }
 
-                               if (!$_SESSION["uid"]) render_login_form($link, $login_form);
+                               if (!$_SESSION["uid"]) render_login_form($link);
 
                        } else {
                                /* bump login timestamp */
                        }
 
                        if ($_SESSION["uid"]) {
+                               cache_prefs($link);
                                load_user_plugins($link, $_SESSION["uid"]);
                        }
                }
                }
        }
 
-       // Deprecated, TODO: remove
-       function theme_image($link, $filename) {
-               return $filename;
-       }
-
        function convert_timestamp($timestamp, $source_tz, $dest_tz) {
 
                try {
        }
 
        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;
                        }
                }
 
-               if (db_escape_string("testTEST") != "testTEST") {
+               if (db_escape_string($link, "testTEST") != "testTEST") {
                        $error_code = 12;
                }
 
                                                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 $ref_check_qpart AND unread = true
                                                        AND owner_uid = $owner_uid");
 
                                        } else if ($feed == -2) {
                                        db_query($link, "UPDATE ttrss_user_entries
                                                        SET unread = false,last_read = NOW()
                                                        WHERE feed_id = '$feed'
-                                                       AND $ref_check_qpart
+                                                       AND $ref_check_qpart AND unread = true
                                                        AND owner_uid = $owner_uid");
 
                                } else if ($feed < 0 && $feed > -10) { // special, like starred
                                                db_query($link, "UPDATE ttrss_user_entries
                                                        SET unread = false,last_read = NOW()
                                                        WHERE marked = true
-                                                       AND $ref_check_qpart
+                                                       AND $ref_check_qpart AND unread = true
                                                        AND owner_uid = $owner_uid");
                                        }
 
                                                db_query($link, "UPDATE ttrss_user_entries
                                                        SET unread = false,last_read = NOW()
                                                        WHERE published = true
-                                                       AND $ref_check_qpart
+                                                       AND $ref_check_qpart AND unread = true
                                                        AND owner_uid = $owner_uid");
                                        }
 
                                        if ($feed == -4) {
                                                db_query($link, "UPDATE ttrss_user_entries
                                                        SET unread = false,last_read = NOW()
-                                                       WHERE $ref_check_qpart AND owner_uid = $owner_uid");
+                                                       WHERE $ref_check_qpart AND unread = true AND
+                                                       owner_uid = $owner_uid");
                                        }
 
                                } else if ($feed < -10) { // label
                        } else { // tag
                                db_query($link, "BEGIN");
 
-                               $tag_name = db_escape_string($feed);
+                               $tag_name = db_escape_string($link, $feed);
 
                                $result = db_query($link, "SELECT post_int_id FROM ttrss_tags
                                        WHERE tag_name = '$tag_name' AND owner_uid = $owner_uid");
                                while ($line = db_fetch_assoc($result)) {
                                        db_query($link, "UPDATE ttrss_user_entries SET
                                                unread = false, last_read = NOW()
-                                               WHERE $ref_check_qpart AND int_id = " . $line["post_int_id"]);
+                                               WHERE $ref_check_qpart AND unread = true
+                                               AND int_id = " . $line["post_int_id"]);
                                }
                                db_query($link, "COMMIT");
                        }
                        return 0;
                } else if ($feed != "0" && $n_feed == 0) {
 
-                       $feed = db_escape_string($feed);
+                       $feed = db_escape_string($link, $feed);
 
                        $result = db_query($link, "SELECT SUM((SELECT COUNT(int_id)
                                FROM ttrss_user_entries,ttrss_entries WHERE int_id = post_int_id
 
                $owner_uid = $_SESSION["uid"];
 
-               $result = db_query($link, "SELECT id, caption FROM ttrss_labels2
-                       WHERE owner_uid = '$owner_uid'");
+               $result = db_query($link, "SELECT id,caption,COUNT(unread) AS unread
+                       FROM ttrss_labels2 LEFT JOIN ttrss_user_labels2 ON
+                               (ttrss_labels2.id = label_id)
+                                       LEFT JOIN ttrss_user_entries ON (ref_id = article_id AND unread = true)
+                               WHERE ttrss_labels2.owner_uid = $owner_uid GROUP BY ttrss_labels2.id,
+                                       ttrss_labels2.caption");
 
                while ($line = db_fetch_assoc($result)) {
 
                        $id = -$line["id"] - 11;
 
                        $label_name = $line["caption"];
-                       $count = getFeedUnread($link, $id);
+                       $count = $line["unread"];
 
                        $cv = array("id" => $id,
                                "counter" => (int) $count);
        function make_init_params($link) {
                $params = array();
 
-               $params["sign_progress"] = theme_image($link, "images/indicator_white.gif");
-               $params["sign_progress_tiny"] = theme_image($link, "images/indicator_tiny.gif");
-               $params["sign_excl"] = theme_image($link, "images/sign_excl.svg");
-               $params["sign_info"] = theme_image($link, "images/sign_info.svg");
-
                foreach (array("ON_CATCHUP_SHOW_NEXT_FEED", "HIDE_READ_FEEDS",
                        "ENABLE_FEED_CATS", "FEEDS_SORT_BY_UNREAD", "CONFIRM_FEED_CATCHUP",
                        "CDM_AUTO_CATCHUP", "FRESH_ARTICLE_MAX_AGE", "DEFAULT_ARTICLE_LIMIT",
                                "prev_feed" => __("Open previous feed"),
                                "next_article" => __("Open next article"),
                                "prev_article" => __("Open previous article"),
+                               "next_article_noscroll" => __("Open next article (don't scroll long articles)"),
+                               "prev_article_noscroll" => __("Open previous article (don't scroll long articles)"),
                                "search_dialog" => __("Show search dialog")),
                        __("Article") => array(
                                "toggle_mark" => __("Toggle starred"),
                                "article_scroll_up" => __("Scroll up"),
                                "select_article_cursor" => __("Select article under cursor"),
                                "email_article" => __("Email article"),
-                               "close_article" => __("Close article"),
-                               "toggle_widescreen" => __("Toggle widescreen mode")),
+                               "close_article" => __("Close/collapse article"),
+                               "toggle_widescreen" => __("Toggle widescreen mode"),
+                               "toggle_embed_original" => __("Toggle embed original")),
                        __("Article selection") => array(
                                "select_all" => __("Select all articles"),
                                "select_unread" => __("Select unread"),
                                "feed_reverse" => __("Reverse headlines"),
                                "feed_debug_update" => __("Debug feed update"),
                                "catchup_all" => __("Mark all feeds as read"),
-                               "cat_toggle_collapse" => __("Un/collapse current category")),
+                               "cat_toggle_collapse" => __("Un/collapse current category"),
+                               "toggle_combined_mode" => __("Toggle combined mode")),
                        __("Go to") => array(
                                "goto_all" => __("All articles"),
                                "goto_fresh" => __("Fresh"),
                                "p" => "prev_article",
                                "(38)|up" => "prev_article",
                                "(40)|down" => "next_article",
+//                             "^(38)|Ctrl-up" => "prev_article_noscroll",
+//                             "^(40)|Ctrl-down" => "next_article_noscroll",
                                "(191)|/" => "search_dialog",
 //                     "article" => array(
                                "s" => "toggle_mark",
-                               "S" => "toggle_publ",
+                               "*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",
                                "f e" => "feed_edit",
                                "f q" => "feed_catchup",
                                "f x" => "feed_reverse",
-                               "f D" => "feed_debug_update",
-                               "Q" => "catchup_all",
+                               "f *d" => "feed_debug_update",
+                               "f *c" => "toggle_combined_mode",
+                               "*q" => "catchup_all",
                                "x" => "cat_toggle_collapse",
 //                     "goto" => array(
                                "g a" => "goto_all",
                                "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",
                                "^(191)|Ctrl+/" => "help_dialog",
                        );
 
+               if (get_pref($link, 'COMBINED_DISPLAY_MODE')) {
+                       $hotkeys["^(38)|Ctrl-up"] = "prev_article_noscroll";
+                       $hotkeys["^(40)|Ctrl-down"] = "next_article_noscroll";
+               }
+
                global $pluginhost;
                foreach ($pluginhost->get_hooks($pluginhost::HOOK_HOTKEY_MAP) as $plugin) {
                        $hotkeys = $plugin->hook_hotkey_map($hotkeys);
                $data['last_article_id'] = getLastArticleId($link);
                $data['cdm_expanded'] = get_pref($link, 'CDM_EXPANDED');
 
+               $data['dep_ts'] = calculate_dep_timestamp();
+
                if (file_exists(LOCK_DIRECTORY . "/update_daemon.lock")) {
 
                        $data['daemon_is_running'] = (int) file_is_locked("update_daemon.lock");
                return $data;
        }
 
-       function search_to_sql($link, $search, $match_on) {
+       function search_to_sql($link, $search) {
 
                $search_query_part = "";
 
                                //$k = date("Y-m-d", strtotime(substr($k, 1)));
 
                                array_push($query_keywords, "(".SUBSTRING_FOR_DATE."(updated,1,LENGTH('$k')) $not = '$k')");
-                       } else if ($match_on == "both") {
+                       } else {
                                array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
                                                OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
-                       } else if ($match_on == "title") {
-                               array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%'))");
-                       } else if ($match_on == "content") {
-                               array_push($query_keywords, "(UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
                        }
                }
 
                return $rv;
        }
 
-       function queryFeedHeadlines($link, $feed, $limit, $view_mode, $cat_view, $search, $search_mode, $match_on, $override_order = false, $offset = 0, $owner_uid = 0, $filter = false, $since_id = 0, $include_children = false, $ignore_vfeed_group = false) {
+       function queryFeedHeadlines($link, $feed, $limit, $view_mode, $cat_view, $search, $search_mode, $override_order = false, $offset = 0, $owner_uid = 0, $filter = false, $since_id = 0, $include_children = false, $ignore_vfeed_group = false) {
 
                if (!$owner_uid) $owner_uid = $_SESSION["uid"];
 
                                                $search_query_part = "ref_id = -1 AND ";
 
                                } else {
-                                       $search_query_part = search_to_sql($link, $search, $match_on);
+                                       $search_query_part = search_to_sql($link, $search);
                                        $search_query_part .= " AND ";
                                }
 
                                $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
                                $allow_archived = true;
 
+                               if (!$override_order) $override_order = "last_marked DESC, updated DESC";
+
                        } else if ($feed == -2) { // published virtual feed OR labels category
 
                                if (!$cat_view) {
                                        $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, updated DESC";
                                } else {
                                        $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
 
                                                num_comments,
                                                comments,
                                                int_id,
+                                               hide_images,
                                                unread,feed_id,marked,published,link,last_read,orig_feed_id,
+                                               last_marked, last_published,
                                                ".SUBSTRING_FOR_DATE."(last_read,1,19) as last_read_noms,
                                                $vfeed_query_part
                                                $content_query_part
                                                                "label_cache," .
                                                                "link," .
                                                                "last_read," .
+                                                               "(SELECT hide_images FROM ttrss_feeds WHERE id = feed_id) AS hide_images," .
+                                                               "last_marked, last_published, " .
                                                                SUBSTRING_FOR_DATE . "(last_read,1,19) as last_read_noms," .
                                                                $since_id_part .
                                                                $vfeed_query_part .
 
        }
 
-       function sanitize($link, $str, $force_strip_tags = false, $owner = false, $site_url = false) {
+       function sanitize($link, $str, $force_remove_images = false, $owner = false, $site_url = false) {
                if (!$owner) $owner = $_SESSION["uid"];
 
                $res = trim($str); if (!$res) return '';
 
-               $config = array('safe' => 1, 'deny_attribute' => 'style, width, height, class, id', 'comment' => 1, 'cdata' => 1, 'balance' => 0);
-               $res = htmLawed($res, $config);
-
-               if (get_pref($link, "STRIP_IMAGES", $owner)) {
-                       $res = preg_replace('/<img[^>]+>/is', '', $res);
-               }
-
                if (strpos($res, "href=") === false)
                        $res = rewrite_urls($res);
 
                $xpath = new DOMXPath($doc);
 
                $entries = $xpath->query('(//a[@href]|//img[@src])');
-               $br_inserted = 0;
 
                foreach ($entries as $entry) {
 
                                        $entry->setAttribute('href',
                                                rewrite_relative_url($site_url, $entry->getAttribute('href')));
 
-                               if ($entry->hasAttribute('src'))
-                                       if (preg_match('/^image.php\?i=[a-z0-9]+$/', $entry->getAttribute('src')) == 0)
-                                               $entry->setAttribute('src',
-                                                       rewrite_relative_url($site_url, $entry->getAttribute('src')));
+                               if ($entry->hasAttribute('src')) {
+                                       $src = rewrite_relative_url($site_url, $entry->getAttribute('src'));
+
+                                       $cached_filename = CACHE_DIR . '/images/' . sha1($src) . '.png';
+
+                                       if (file_exists($cached_filename)) {
+                                               $src = SELF_URL_PATH . '/image.php?hash=' . sha1($src);
+                                       }
+
+                                       $entry->setAttribute('src', $src);
+                               }
+
+                               if ($entry->nodeName == 'img') {
+                                       if (($owner && get_pref($link, "STRIP_IMAGES", $owner)) ||
+                                                       $force_remove_images) {
+
+                                               $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") {
                                $entry->setAttribute("target", "_blank");
                        }
+               }
 
-                       if (strtolower($entry->nodeName) == "img" && !$br_inserted) {
-                               $br = $doc->createElement("br");
+               $entries = $xpath->query('//iframe');
+               foreach ($entries as $entry) {
+                       $entry->setAttribute('sandbox', 'allow-scripts');
 
-                               if ($entry->parentNode->nextSibling) {
-                                       $entry->parentNode->insertBefore($br, $entry->nextSibling);
-                                       $br_inserted = 1;
-                               }
+               }
+
+               global $pluginhost;
 
+               if (isset($pluginhost)) {
+                       foreach ($pluginhost->get_hooks($pluginhost::HOOK_SANITIZE) as $plugin) {
+                               $doc = $plugin->hook_sanitize($doc, $site_url);
                        }
                }
 
-               $node = $doc->getElementsByTagName('body')->item(0);
+               $doc->removeChild($doc->firstChild); //remove doctype
+               $doc = strip_harmful_tags($doc);
+               $res = $doc->saveHTML();
+               return $res;
+       }
+
+       function strip_harmful_tags($doc) {
+               $entries = $doc->getElementsByTagName("*");
+
+               $allowed_elements = array('a', 'address', 'audio', 'article',
+                       'b', 'big', 'blockquote', 'body', 'br', 'cite',
+                       'code', 'dd', 'del', 'details', 'div', 'dl', 'font',
+                       'dt', 'em', 'footer', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
+                       'header', 'html', 'i', 'img', 'ins', 'kbd',
+                       'li', 'nav', 'ol', 'p', 'pre', 'q', 's','small',
+                       'source', 'span', 'strike', 'strong', 'sub', 'summary',
+                       'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead',
+                       'tr', 'track', 'tt', 'u', 'ul', 'var', 'wbr', 'video' );
+
+               if ($_SESSION['hasSandbox']) array_push($allowed_elements, 'iframe');
+
+               $disallowed_attributes = array('id', 'style', 'class');
+
+               foreach ($entries as $entry) {
+                       if (!in_array($entry->nodeName, $allowed_elements)) {
+                               $entry->parentNode->removeChild($entry);
+                       }
+
+                       if ($entry->hasAttributes()) {
+                               foreach (iterator_to_array($entry->attributes) as $attr) {
+
+                                       if (strpos($attr->nodeName, 'on') === 0) {
+                                               $entry->removeAttributeNode($attr);
+                                       }
 
-               // http://tt-rss.org/redmine/issues/357
-               return $doc->saveXML($node, LIBXML_NOEMPTYTAG);
+                                       if (in_array($attr->nodeName, $disallowed_attributes)) {
+                                               $entry->removeAttributeNode($attr);
+                                       }
+                               }
+                       }
+               }
+
+               return $doc;
        }
 
        function check_for_update($link) {
                if (CHECK_FOR_NEW_VERSION && $_SESSION['access_level'] >= 10) {
-                       $version_url = "http://tt-rss.org/version.php?ver=" . VERSION;
+                       $version_url = "http://tt-rss.org/version.php?ver=" . VERSION .
+                               "&iid=" . sha1(SELF_URL_PATH);
 
                        $version_data = @fetch_file_contents($version_url);
 
 
        function get_article_tags($link, $id, $owner_uid = 0, $tag_cache = false) {
 
-               $a_id = db_escape_string($id);
+               $a_id = db_escape_string($link, $id);
 
                if (!$owner_uid) $owner_uid = $_SESSION["uid"];
 
 
                        /* update the cache */
 
-                       $tags_str = db_escape_string(join(",", $tags));
+                       $tags_str = db_escape_string($link, join(",", $tags));
 
                        db_query($link, "UPDATE ttrss_user_entries
                                SET tag_cache = '$tags_str' WHERE ref_id = '$id'
                return true;
        }
 
-       function render_login_form($link, $form_id = 0) {
-               switch ($form_id) {
-               case 0:
-                       require_once "login_form.php";
-                       break;
-               case 1:
-                       require_once "mobile/login_form.php";
-                       break;
-               }
+       function render_login_form($link) {
+               require_once "login_form.php";
                exit;
        }
 
        function format_warning($msg, $id = "") {
                global $link;
                return "<div class=\"warning\" id=\"$id\">
-                       <img src=\"".theme_image($link, "images/sign_excl.svg")."\">$msg</div>";
+                       <img src=\"images/sign_excl.svg\">$msg</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>";
+                       <img src=\"images/sign_info.svg\">$msg</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>";
+                       <img src=\"images/sign_excl.svg\">$msg</div>";
        }
 
        function print_notice($msg) {
 
                $entry = "";
 
+               $url = htmlspecialchars($url);
+
                if (strpos($ctype, "audio/") === 0) {
 
                        if ($_SESSION["hasAudio"] && (strpos($ctype, "ogg") !== false ||
 
                                $id = 'AUDIO-' . uniqid();
 
-                               $entry .= "<audio id=\"$id\"\" controls>
+                               $entry .= "<audio id=\"$id\"\" controls style='display : none'>
                                        <source type=\"$ctype\" src=\"$url\"></source>
                                        </audio>";
 
                                        </object>";
                        }
 
-                       if ($entry) $entry .= "&nbsp;" . basename($url);
+                       if ($entry) $entry .= "&nbsp; <a target=\"_blank\"
+                               href=\"$url\">" . basename($url) . "</a>";
 
                        return $entry;
 
 
                //if (!$zoom_mode) { print "<article id='$id'><![CDATA["; };
 
-               $result = db_query($link, "SELECT rtl_content, always_display_enclosures, cache_content FROM ttrss_feeds
-                       WHERE id = '$feed_id' AND owner_uid = $owner_uid");
-
-               if (db_num_rows($result) == 1) {
-                       $rtl_content = sql_bool_to_bool(db_fetch_result($result, 0, "rtl_content"));
-                       $always_display_enclosures = sql_bool_to_bool(db_fetch_result($result, 0, "always_display_enclosures"));
-                       $cache_content = sql_bool_to_bool(db_fetch_result($result, 0, "cache_content"));
-               } else {
-                       $rtl_content = false;
-                       $always_display_enclosures = false;
-                       $cache_content = false;
-               }
-
-               if ($rtl_content) {
-                       $rtl_tag = "dir=\"RTL\"";
-                       $rtl_class = "RTL";
-               } else {
-                       $rtl_tag = "";
-                       $rtl_class = "";
-               }
-
                if ($mark_as_read) {
                        $result = db_query($link, "UPDATE ttrss_user_entries
                                SET unread = false,last_read = NOW()
                $result = db_query($link, "SELECT id,title,link,content,feed_id,comments,int_id,
                        ".SUBSTRING_FOR_DATE."(updated,1,16) as updated,
                        (SELECT site_url FROM ttrss_feeds WHERE id = feed_id) as site_url,
+                       (SELECT hide_images FROM ttrss_feeds WHERE id = feed_id) as hide_images,
                        num_comments,
                        tag_cache,
                        author,
                        $parsed_updated = make_local_datetime($link, $line["updated"], true,
                                $owner_uid, true);
 
-                       $rv['content'] .= "<div class=\"postDate$rtl_class\">$parsed_updated</div>";
+                       $rv['content'] .= "<div class=\"postDate\">$parsed_updated</div>";
 
                        if ($line["link"]) {
                                $rv['content'] .= "<div class='postTitle'><a target='_blank'
                        if (!$entry_comments) $entry_comments = "&nbsp;"; # 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'>&nbsp;";
 
                        if (!$zoom_mode) {
                                }
                        }
 
-                       if ($cache_content && $line["cached_content"] != "") {
-                               $line["content"] =& $line["cached_content"];
-                       }
-
                        $rv['content'] .= $line["content"];
 
                        $rv['content'] .= format_article_enclosures($link, $id,
-                               $always_display_enclosures, $line["content"]);
+                               $always_display_enclosures, $line["content"], $line["hide_images"]);
 
                        $rv['content'] .= "</div>";
 
        }
 
        function print_checkpoint($n, $s) {
-               $ts = getmicrotime();
+               $ts = microtime(true);
                echo sprintf("<!-- CP[$n] %.4f seconds -->", $ts - $s);
                return $ts;
        }
                return $str;
        }
 
-       function toggle_collapse_cat($link, $cat_id, $mode) {
-               if ($cat_id > 0) {
-                       $mode = bool_to_sql_bool($mode);
-
-                       db_query($link, "UPDATE ttrss_feed_categories SET
-                               collapsed = $mode WHERE id = '$cat_id' AND owner_uid = " .
-                               $_SESSION["uid"]);
-               } else {
-                       $pref_name = '';
-
-                       switch ($cat_id) {
-                       case -1:
-                               $pref_name = '_COLLAPSED_SPECIAL';
-                               break;
-                       case -2:
-                               $pref_name = '_COLLAPSED_LABELS';
-                               break;
-                       case 0:
-                               $pref_name = '_COLLAPSED_UNCAT';
-                               break;
-                       }
-
-                       if ($pref_name) {
-                               if ($mode) {
-                                       set_pref($link, $pref_name, 'true');
-                               } else {
-                                       set_pref($link, $pref_name, 'false');
-                               }
-                       }
-               }
-       }
-
 
        function get_feed_category($link, $feed_cat, $parent_cat_id = false) {
                if ($parent_cat_id) {
                if (db_num_rows($result) == 1) {
                        return db_fetch_result($result, 0, "access_key");
                } else {
-                       $key = db_escape_string(sha1(uniqid(rand(), true)));
+                       $key = db_escape_string($link, sha1(uniqid(rand(), true)));
 
                        $result = db_query($link, "INSERT INTO ttrss_access_keys
                                (access_key, feed_id, is_cat, owner_uid)
        }
 
        function format_article_enclosures($link, $id, $always_display_enclosures,
-                                       $article_content) {
+                                       $article_content, $hide_images = false) {
 
                $result = get_article_enclosures($link, $id);
                $rv = '';
                                array_push($entries, $entry);
                        }
 
-                       if (!get_pref($link, "STRIP_IMAGES")) {
+                       if ($_SESSION['uid'] && !get_pref($link, "STRIP_IMAGES")) {
                                if ($always_display_enclosures ||
                                                        !preg_match("/<img/i", $article_content)) {
 
                                                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>";
 
+                                                               }
                                                }
                                        }
                                }
 
                // http://tt-rss.org/forum/viewtopic.php?f=1&t=970
                if ($node)
-                       return $doc->saveXML($node, LIBXML_NOEMPTYTAG);
+                       return $doc->saveXML($node);
                else
                        return $html;
        }
 
                        if ($regexp_valid) {
 
-                               $rule['reg_exp'] = db_escape_string($rule['reg_exp']);
+                               $rule['reg_exp'] = db_escape_string($link, $rule['reg_exp']);
 
                                switch ($rule["type"]) {
                                        case "title":
                                }
 
                                if (isset($rule["feed_id"]) && $rule["feed_id"] > 0) {
-                                       $qpart .= " AND feed_id = " . db_escape_string($rule["feed_id"]);
+                                       $qpart .= " AND feed_id = " . db_escape_string($link, $rule["feed_id"]);
                                }
 
                                if (isset($rule["cat_id"])) {
                return in_array($interface, class_implements($class));
        }
 
+       function geturl($url){
+
+               (function_exists('curl_init')) ? '' : die('cURL Must be installed for geturl function to work. Ask your host to enable it or uncomment extension=php_curl.dll in php.ini');
+
+               $curl = curl_init();
+               $header[0] = "Accept: text/xml,application/xml,application/xhtml+xml,";
+               $header[0] .= "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
+               $header[] = "Cache-Control: max-age=0";
+               $header[] = "Connection: keep-alive";
+               $header[] = "Keep-Alive: 300";
+               $header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7";
+               $header[] = "Accept-Language: en-us,en;q=0.5";
+               $header[] = "Pragma: ";
+
+               curl_setopt($curl, CURLOPT_URL, $url);
+               curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0 Firefox/5.0');
+               curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
+               curl_setopt($curl, CURLOPT_HEADER, true);
+               curl_setopt($curl, CURLOPT_REFERER, $url);
+               curl_setopt($curl, CURLOPT_ENCODING, 'gzip,deflate');
+               curl_setopt($curl, CURLOPT_AUTOREFERER, true);
+               curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+               //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); //CURLOPT_FOLLOWLOCATION Disabled...
+               curl_setopt($curl, CURLOPT_TIMEOUT, 60);
+
+               $html = curl_exec($curl);
+
+               $status = curl_getinfo($curl);
+               curl_close($curl);
+
+               if($status['http_code']!=200){
+                       if($status['http_code'] == 301 || $status['http_code'] == 302) {
+                               list($header) = explode("\r\n\r\n", $html, 2);
+                               $matches = array();
+                               preg_match("/(Location:|URI:)[^(\n)]*/", $header, $matches);
+                               $url = trim(str_replace($matches[1],"",$matches[0]));
+                               $url_parsed = parse_url($url);
+                               return (isset($url_parsed))? geturl($url, $referer):'';
+                       }
+                       $oline='';
+                       foreach($status as $key=>$eline){$oline.='['.$key.']'.$eline.' ';}
+                       $line =$oline." \r\n ".$url."\r\n-----------------\r\n";
+#                      $handle = @fopen('./curl.error.log', 'a');
+#                      fwrite($handle, $line);
+                       return FALSE;
+               }
+               return $url;
+       }
+
+       function get_minified_js($files) {
+               require_once 'lib/jshrink/Minifier.php';
+
+               $rv = '';
+
+               foreach ($files as $js) {
+                       if (!isset($_GET['debug'])) {
+                               $cached_file = CACHE_DIR . "/js/$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 get_site_title() {
+        $original_title = "Tiny Tiny RSS";
+        if (defined("SITE_TITLE")) {
+            return SITE_TITLE;
+        }
+        return $original_title;
+    }
 ?>