+++ /dev/null
-dojo.provide("fox.FeedTree");
-dojo.provide("fox.FeedStoreModel");
-
-dojo.require("dijit.Tree");
-dojo.require("dijit.Menu");
-
-dojo.declare("fox.FeedStoreModel", dijit.tree.ForestStoreModel, {
- getItemsInCategory: function (id) {
- if (!this.store._itemsByIdentity) return undefined;
-
- cat = this.store._itemsByIdentity['CAT:' + id];
-
- if (cat && cat.items)
- return cat.items;
- else
- return undefined;
-
- },
- getItemById: function(id) {
- return this.store._itemsByIdentity[id];
- },
- getFeedValue: function(feed, is_cat, key) {
- if (!this.store._itemsByIdentity) return undefined;
-
- if (is_cat)
- treeItem = this.store._itemsByIdentity['CAT:' + feed];
- else
- treeItem = this.store._itemsByIdentity['FEED:' + feed];
-
- if (treeItem)
- return this.store.getValue(treeItem, key);
- },
- getFeedName: function(feed, is_cat) {
- return this.getFeedValue(feed, is_cat, 'name');
- },
- getFeedUnread: function(feed, is_cat) {
- var unread = parseInt(this.getFeedValue(feed, is_cat, 'unread'));
- return (isNaN(unread)) ? 0 : unread;
- },
- setFeedUnread: function(feed, is_cat, unread) {
- return this.setFeedValue(feed, is_cat, 'unread', parseInt(unread));
- },
- setFeedValue: function(feed, is_cat, key, value) {
- if (!value) value = '';
- if (!this.store._itemsByIdentity) return undefined;
-
- if (is_cat)
- treeItem = this.store._itemsByIdentity['CAT:' + feed];
- else
- treeItem = this.store._itemsByIdentity['FEED:' + feed];
-
- if (treeItem)
- return this.store.setValue(treeItem, key, value);
- },
- getNextUnreadFeed: function (feed, is_cat) {
- if (!this.store._itemsByIdentity)
- return null;
-
- if (is_cat) {
- treeItem = this.store._itemsByIdentity['CAT:' + feed];
- items = this.store._arrayOfTopLevelItems;
- } else {
- treeItem = this.store._itemsByIdentity['FEED:' + feed];
- items = this.store._arrayOfAllItems;
- }
-
- for (var i = 0; i < items.length; i++) {
- if (items[i] == treeItem) {
-
- for (var j = i+1; j < items.length; j++) {
- var unread = this.store.getValue(items[j], 'unread');
- var id = this.store.getValue(items[j], 'id');
-
- if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
- }
-
- for (var j = 0; j < i; j++) {
- var unread = this.store.getValue(items[j], 'unread');
- var id = this.store.getValue(items[j], 'id');
-
- if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
- }
- }
- }
-
- return null;
- },
- hasCats: function() {
- if (this.store && this.store._itemsByIdentity)
- return this.store._itemsByIdentity['CAT:-1'] != undefined;
- else
- return false;
- },
-});
-
-dojo.declare("fox.FeedTree", dijit.Tree, {
- _createTreeNode: function(args) {
- var tnode = new dijit._TreeNode(args);
-
- if (args.item.icon)
- tnode.iconNode.src = args.item.icon[0];
-
- var id = args.item.id[0];
- var bare_id = parseInt(id.substr(id.indexOf(':')+1));
-
- if (bare_id < -10) {
- var span = dojo.doc.createElement('span');
- var fg_color = args.item.fg_color[0];
- var bg_color = args.item.bg_color[0];
-
- span.innerHTML = "α";
- span.className = 'labelColorIndicator';
- span.setStyle({
- color: fg_color,
- backgroundColor: bg_color});
-
- dojo.place(span, tnode.iconNode, 'replace');
- }
-
- if (id.match("FEED:") && bare_id > 0) {
- var menu = new dijit.Menu();
- menu.row_id = bare_id;
-
- menu.addChild(new dijit.MenuItem({
- label: __("Mark as read"),
- onClick: function() {
- catchupFeed(this.getParent().row_id);
- }}));
-
- menu.addChild(new dijit.MenuItem({
- label: __("Edit feed"),
- onClick: function() {
- editFeed(this.getParent().row_id, false);
- }}));
-
- menu.addChild(new dijit.MenuItem({
- label: __("Update feed"),
- onClick: function() {
- scheduleFeedUpdate(this.getParent().row_id, false);
- }}));
-
- menu.bindDomNode(tnode.domNode);
- tnode._menu = menu;
- }
-
- if (id.match("CAT:") && bare_id > 0) {
- var menu = new dijit.Menu();
- menu.row_id = bare_id;
-
- menu.addChild(new dijit.MenuItem({
- label: __("Mark as read"),
- onClick: function() {
- catchupFeed(this.getParent().row_id, true);
- }}));
-
- menu.bindDomNode(tnode.domNode);
- tnode._menu = menu;
- }
-
- //tnode.labelNode.innerHTML = args.label;
- return tnode;
- },
- getIconClass: function (item, opened) {
- return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon";
- },
- getLabelClass: function (item, opened) {
- return (item.unread == 0) ? "dijitTreeLabel" : "dijitTreeLabel Unread";
- },
- getRowClass: function (item, opened) {
- return (!item.error || item.error == '') ? "dijitTreeRow" :
- "dijitTreeRow Error";
- },
- getLabel: function(item) {
- var name = String(item.name);
-
- /* Horrible */
- name = name.replace(/"/g, "\"");
- name = name.replace(/&/g, "&");
- name = name.replace(/—/g, "-");
- name = name.replace(/</g, "<");
- name = name.replace(/>/g, ">");
-
- if (item.unread > 0) {
- return name + " (" + item.unread + ")";
- } else {
- return name;
- }
- },
- selectFeed: function(feed, is_cat) {
- if (is_cat)
- treeNode = this._itemNodesMap['CAT:' + feed];
- else
- treeNode = this._itemNodesMap['FEED:' + feed];
-
- if (treeNode) {
- treeNode = treeNode[0];
- if (!is_cat) this._expandNode(treeNode);
- this.set("selectedNodes", [treeNode]);
- }
- },
- setFeedIcon: function(feed, is_cat, src) {
- if (is_cat)
- treeNode = this._itemNodesMap['CAT:' + feed];
- else
- treeNode = this._itemNodesMap['FEED:' + feed];
-
- if (treeNode) {
- treeNode = treeNode[0];
- treeNode.iconNode.src = src;
- return true;
- }
- return false;
- },
- setFeedExpandoIcon: function(feed, is_cat, src) {
- if (is_cat)
- treeNode = this._itemNodesMap['CAT:' + feed];
- else
- treeNode = this._itemNodesMap['FEED:' + feed];
-
- if (treeNode) {
- treeNode = treeNode[0];
- treeNode.expandoNode.src = src;
- return true;
- }
-
- return false;
- },
- hasCats: function() {
- return this.model.hasCats();
- },
- hideRead: function (hide, show_special) {
- if (this.hasCats()) {
-
- var tree = this;
- var cats = this.model.store._arrayOfTopLevelItems;
-
- cats.each(function(cat) {
- var cat_unread = tree.hideReadFeeds(cat.items, hide, show_special);
-
- var id = String(cat.id);
- var node = tree._itemNodesMap[id];
- var bare_id = parseInt(id.substr(id.indexOf(":")+1));
-
- if (node) {
- var check_unread = tree.model.getFeedUnread(bare_id, true);
-
- if (hide && cat_unread == 0 && check_unread == 0) {
- Effect.Fade(node[0].rowNode, {duration : 0.3,
- queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
- } else {
- Element.show(node[0].rowNode);
- ++cat_unread;
- }
- }
- });
-
- } else {
- this.hideReadFeeds(this.model.store._arrayOfTopLevelItems, hide,
- show_special);
- }
- },
- hideReadFeeds: function (items, hide, show_special) {
- var tree = this;
- var cat_unread = 0;
-
- items.each(function(feed) {
- var id = String(feed.id);
- var bare_id = parseInt(feed.bare_id);;
-
- var unread = feed.unread[0];
- var node = tree._itemNodesMap[id];
-
- if (node) {
- if (hide && unread == 0 && (bare_id > 0 || !show_special)) {
- Effect.Fade(node[0].rowNode, {duration : 0.3,
- queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
- } else {
- Element.show(node[0].rowNode);
- ++cat_unread;
- }
- }
- });
-
- return cat_unread;
- },
- collapseCat: function(id) {
- if (!this.model.hasCats()) return;
-
- var tree = this;
-
- var node = tree._itemNodesMap['CAT:' + id][0];
- var item = tree.model.store._itemsByIdentity['CAT:' + id];
-
- if (node && item) {
- var hidden = tree.model.store.getValue(item, 'hidden');
-
- if (hidden)
- tree._expandNode(node);
- else
- tree._collapseNode(node);
-
- tree.model.store.setValue(item, 'hidden', !hidden);
- }
- },
- collapseHiddenCats: function() {
- if (!this.model.hasCats()) return;
-
- var cats = this.model.store._arrayOfTopLevelItems;
- var tree = this;
-
- dojo.forEach(cats, function(cat) {
- var hidden = tree.model.store.getValue(cat, 'hidden');
- var id = tree.model.store.getValue(cat, 'id');
- var node = tree._itemNodesMap[id][0];
-
- if (hidden)
- tree._collapseNode(node);
- else
- tree._expandNode(node);
-
- });
- },
- getVisibleUnreadFeeds: function() {
- var items = this.model.store._arrayOfAllItems;
- var rv = [];
-
- for (var i = 0; i < items.length; i++) {
- var id = String(items[i].id);
- var box = this._itemNodesMap[id];
-
- if (box) {
- var row = box[0].rowNode;
- var cat = false;
-
- try {
- cat = box[0].rowNode.parentNode.parentNode;
- } catch (e) { }
-
- if (row) {
- if (Element.visible(row) && (!cat || Element.visible(cat))) {
- var feed_id = String(items[i].bare_id);
- var is_cat = !id.match('FEED:');
- var unread = this.model.getFeedUnread(feed_id, is_cat);
-
- if (unread > 0)
- rv.push([feed_id, is_cat]);
-
- }
- }
- }
- }
-
- return rv;
- },
- getNextFeed: function (feed, is_cat) {
- if (is_cat) {
- treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
- } else {
- treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
- }
-
- items = this.model.store._arrayOfAllItems;
- var item = items[0];
-
- for (var i = 0; i < items.length; i++) {
- if (items[i] == treeItem) {
-
- for (var j = i+1; j < items.length; j++) {
- var id = String(items[j].id);
- var box = this._itemNodesMap[id];
-
- if (box) {
- var row = box[0].rowNode;
- var cat = box[0].rowNode.parentNode.parentNode;
-
- if (Element.visible(cat) && Element.visible(row)) {
- item = items[j];
- break;
- }
- }
- }
- break;
- }
- }
-
- if (item) {
- return [this.model.store.getValue(item, 'bare_id'),
- !this.model.store.getValue(item, 'id').match('FEED:')];
- } else {
- return false;
- }
- },
- getPreviousFeed: function (feed, is_cat) {
- if (is_cat) {
- treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
- } else {
- treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
- }
-
- items = this.model.store._arrayOfAllItems;
- var item = items[0];
-
- for (var i = 0; i < items.length; i++) {
- if (items[i] == treeItem) {
-
- for (var j = i-1; j > 0; j--) {
- var id = String(items[j].id);
- var box = this._itemNodesMap[id];
-
- if (box) {
- var row = box[0].rowNode;
- var cat = box[0].rowNode.parentNode.parentNode;
-
- if (Element.visible(cat) && Element.visible(row)) {
- item = items[j];
- break;
- }
- }
-
- }
- break;
- }
- }
-
- if (item) {
- return [this.model.store.getValue(item, 'bare_id'),
- !this.model.store.getValue(item, 'id').match('FEED:')];
- } else {
- return false;
- }
-
- },
-
-});
+++ /dev/null
-dojo.provide("fox.PrefFeedTree");
-dojo.provide("fox.PrefFeedStore");
-
-dojo.require("lib.CheckBoxTree");
-dojo.require("dojo.data.ItemFileWriteStore");
-
-dojo.declare("fox.PrefFeedStore", dojo.data.ItemFileWriteStore, {
-
- _saveEverything: function(saveCompleteCallback, saveFailedCallback,
- newFileContentString) {
-
- dojo.xhrPost({
- url: "backend.php",
- content: {op: "pref-feeds", subop: "savefeedorder",
- payload: newFileContentString},
- error: saveFailedCallback,
- load: saveCompleteCallback});
- },
-
-});
-
-dojo.declare("fox.PrefFeedTree", lib.CheckBoxTree, {
- _createTreeNode: function(args) {
- var tnode = this.inherited(arguments);
-
- if (args.item.icon)
- tnode.iconNode.src = args.item.icon[0];
-
- var param = this.model.store.getValue(args.item, 'param');
-
- if (param) {
- param = dojo.doc.createElement('span');
- param.className = 'feedParam';
- param.innerHTML = args.item.param[0];
- dojo.place(param, tnode.labelNode, 'after');
- }
-
- return tnode;
- },
- onDndDrop: function() {
- this.inherited(arguments);
- this.tree.model.store.save();
- },
- getRowClass: function (item, opened) {
- return (!item.error || item.error == '') ? "dijitTreeRow" :
- "dijitTreeRow Error";
- },
- getIconClass: function (item, opened) {
- return (!item || this.model.store.getValue(item, 'type') == 'category') ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon";
- },
- checkItemAcceptance: function(target, source, position) {
- var item = dijit.getEnclosingWidget(target).item;
-
- // disable copying items
- source.copyState = function() { return false; };
-
- var source_item = false;
-
- source.forInSelectedItems(function(node) {
- source_item = node.data.item;
- });
-
- if (!source_item || !item) return false;
-
- var id = this.tree.model.store.getValue(item, 'id');
- var source_id = source.tree.model.store.getValue(source_item, 'id');
-
- //console.log(id + " " + position + " " + source_id);
-
- if (source_id.match("FEED:")) {
- return ((id.match("CAT:") && position == "over") ||
- (id.match("FEED:") && position != "over"));
- } else if (source_id.match("CAT:")) {
- return ((id.match("CAT:") && position != "over") ||
- (id.match("root") && position == "over"));
- }
- },
-});
-
+++ /dev/null
-dojo.provide("fox.PrefFilterTree");
-
-dojo.require("lib.CheckBoxTree");
-
-dojo.declare("fox.PrefFilterTree", lib.CheckBoxTree, {
- _createTreeNode: function(args) {
- var tnode = this.inherited(arguments);
-
- var enabled = this.model.store.getValue(args.item, 'enabled');
- var param = this.model.store.getValue(args.item, 'param');
-
- if (param) {
- param = dojo.doc.createElement('span');
- param.className = (enabled != false) ? 'labelParam' : 'labelParam Disabled';
- param.innerHTML = args.item.param[0];
- dojo.place(param, tnode.labelNode, 'after');
- }
-
- return tnode;
- },
-
- getLabel: function(item) {
- var label = item.name;
-
- var feed = this.model.store.getValue(item, 'feed');
- var inverse = this.model.store.getValue(item, 'inverse');
-
- if (feed)
- label += " (" + __("Feed:") + " " + feed + ")";
-
- if (inverse)
- label += " (" + __("Inverse") + ")";
-
-/* if (item.param)
- label = "<span class=\"labelFixedLength\">" + label +
- "</span>" + item.param[0]; */
-
- return label;
- },
- getIconClass: function (item, opened) {
- return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "invisible";
- },
- getLabelClass: function (item, opened) {
- var enabled = this.model.store.getValue(item, 'enabled');
- return (enabled != false) ? "dijitTreeLabel labelFixedLength" : "dijitTreeLabel labelFixedLength Disabled";
- },
- getRowClass: function (item, opened) {
- return (!item.error || item.error == '') ? "dijitTreeRow" :
- "dijitTreeRow Error";
- },
-});
-
+++ /dev/null
-dojo.provide("fox.PrefLabelTree");
-
-dojo.require("lib.CheckBoxTree");
-dojo.require("dijit.form.DropDownButton");
-
-dojo.declare("fox.PrefLabelTree", lib.CheckBoxTree, {
- setNameById: function (id, name) {
- var item = this.model.store._itemsByIdentity['LABEL:' + id];
-
- if (item)
- this.model.store.setValue(item, 'name', name);
-
- },
- _createTreeNode: function(args) {
- var tnode = this.inherited(arguments);
-
- var fg_color = this.model.store.getValue(args.item, 'fg_color');
- var bg_color = this.model.store.getValue(args.item, 'bg_color');
- var type = this.model.store.getValue(args.item, 'type');
- var bare_id = this.model.store.getValue(args.item, 'bare_id');
-
- if (type == 'label') {
- var span = dojo.doc.createElement('span');
- span.innerHTML = 'α';
- span.className = 'labelColorIndicator2';
- span.id = 'LICID-' + bare_id;
-
- span.setStyle({
- color: fg_color,
- backgroundColor: bg_color});
-
- tnode._labelIconNode = span;
-
- dojo.place(tnode._labelIconNode, tnode.labelNode, 'before');
- }
-
- return tnode;
- },
- getIconClass: function (item, opened) {
- return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "invisible";
- },
-});
-
<?php
+ set_include_path(get_include_path() . PATH_SEPARATOR . "include");
+
/* remove ill effects of magic quotes */
if (get_magic_quotes_gpc()) {
+++ /dev/null
-<?php
- require_once "config.php";
- require_once "db.php";
-
- if (!defined('DISABLE_SESSIONS')) {
- if (!$_SESSION["prefs_cache"])
- $_SESSION["prefs_cache"] = array();
- }
-
- function get_pref($link, $pref_name, $user_id = false, $die_on_error = false) {
-
- $pref_name = db_escape_string($pref_name);
- $prefs_cache = true;
- $profile = false;
-
- if (!$user_id) {
- $user_id = $_SESSION["uid"];
- @$profile = $_SESSION["profile"];
- } else {
- $user_id = sprintf("%d", $user_id);
- //$prefs_cache = false;
- }
-
- if ($prefs_cache && !defined('DISABLE_SESSIONS')) {
- if ($_SESSION["prefs_cache"] && @$_SESSION["prefs_cache"][$pref_name]) {
- $tuple = $_SESSION["prefs_cache"][$pref_name];
- return convert_pref_type($tuple["value"], $tuple["type"]);
- }
- }
-
- if ($profile) {
- $profile_qpart = "profile = '$profile' AND";
- } else {
- $profile_qpart = "profile IS NULL AND";
- }
-
- if (get_schema_version($link) < 63) $profile_qpart = "";
-
- $result = db_query($link, "SELECT
- value,ttrss_prefs_types.type_name as type_name
- FROM
- ttrss_user_prefs,ttrss_prefs,ttrss_prefs_types
- WHERE
- $profile_qpart
- ttrss_user_prefs.pref_name = '$pref_name' AND
- ttrss_prefs_types.id = type_id AND
- owner_uid = '$user_id' AND
- ttrss_user_prefs.pref_name = ttrss_prefs.pref_name");
-
- if (db_num_rows($result) > 0) {
- $value = db_fetch_result($result, 0, "value");
- $type_name = db_fetch_result($result, 0, "type_name");
-
- if (!defined('DISABLE_SESSIONS')) {
- if ($user_id == $_SESSION["uid"]) {
- $_SESSION["prefs_cache"][$pref_name]["type"] = $type_name;
- $_SESSION["prefs_cache"][$pref_name]["value"] = $value;
- }
- }
-
- return convert_pref_type($value, $type_name);
-
- } else {
- if ($die_on_error) {
- die("Fatal error, unknown preferences key: $pref_name");
- } else {
- return null;
- }
- }
- }
-
- function convert_pref_type($value, $type_name) {
- if ($type_name == "bool") {
- return $value == "true";
- } else if ($type_name == "integer") {
- return sprintf("%d", $value);
- } else {
- return $value;
- }
- }
-
- function set_pref($link, $pref_name, $value, $user_id = false) {
- $pref_name = db_escape_string($pref_name);
- $value = db_escape_string($value);
-
- if (!$user_id) {
- $user_id = $_SESSION["uid"];
- @$profile = $_SESSION["profile"];
- } else {
- $user_id = sprintf("%d", $user_id);
- $prefs_cache = false;
- }
-
- if ($profile) {
- $profile_qpart = "AND profile = '$profile'";
- } else {
- $profile_qpart = "AND profile IS NULL";
- }
-
- if (get_schema_version($link) < 63) $profile_qpart = "";
-
- $type_name = "";
- $current_value = "";
-
- if (!defined('DISABLE_SESSIONS')) {
- if ($_SESSION["prefs_cache"] && @$_SESSION["prefs_cache"][$pref_name]) {
- $type_name = $_SESSION["prefs_cache"][$pref_name]["type"];
- $current_value = $_SESSION["prefs_cache"][$pref_name]["value"];
- }
- }
-
- if (!$type_name) {
- $result = db_query($link, "SELECT type_name
- FROM ttrss_prefs,ttrss_prefs_types
- WHERE pref_name = '$pref_name' AND type_id = ttrss_prefs_types.id");
-
- if (db_num_rows($result) > 0)
- $type_name = db_fetch_result($result, 0, "type_name");
- } else if ($current_value == $value) {
- return;
- }
-
- if ($type_name) {
- if ($type_name == "bool") {
- if ($value == "1" || $value == "true") {
- $value = "true";
- } else {
- $value = "false";
- }
- } else if ($type_name == "integer") {
- $value = sprintf("%d", $value);
- }
-
- if ($pref_name == 'DEFAULT_ARTICLE_LIMIT' && $value == 0) {
- $value = 30;
- }
-
- if ($pref_name == 'USER_TIMEZONE' && $value == '') {
- $value = 'UTC';
- }
-
- db_query($link, "UPDATE ttrss_user_prefs SET
- value = '$value' WHERE pref_name = '$pref_name'
- $profile_qpart
- AND owner_uid = " . $_SESSION["uid"]);
-
- if (!defined('DISABLE_SESSIONS')) {
- if ($user_id == $_SESSION["uid"]) {
- $_SESSION["prefs_cache"][$pref_name]["type"] = $type_name;
- $_SESSION["prefs_cache"][$pref_name]["value"] = $value;
- }
- }
- }
- }
-?>
<?php
+ set_include_path(get_include_path() . PATH_SEPARATOR . "include");
+
require_once "functions.php";
require_once "sessions.php";
require_once "sanity_check.php";
} else {
print_notice(__("Tiny Tiny RSS database is up to date."));
- print "<form method=\"GET\" action=\"tt-rss.php\">
+ print "<form method=\"GET\" action=\"index.php\">
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
</form>";
}
+++ /dev/null
-<?php
-
-require_once "config.php";
-
-function db_connect($host, $user, $pass, $db) {
- if (DB_TYPE == "pgsql") {
-
- $string = "dbname=$db user=$user";
-
- if ($pass) {
- $string .= " password=$pass";
- }
-
- if ($host) {
- $string .= " host=$host";
- }
-
- if (defined('DB_PORT')) {
- $string = "$string port=" . DB_PORT;
- }
-
- $link = pg_connect($string);
-
- if (!$link) {
- die("Connection failed: " . pg_last_error($link));
- }
-
- return $link;
-
- } else if (DB_TYPE == "mysql") {
- $link = mysql_connect($host, $user, $pass);
- if ($link) {
- $result = mysql_select_db($db, $link);
- if (!$result) {
- die("Can't select DB: " . mysql_error($link));
- }
- return $link;
- } else {
- die("Connection failed: " . mysql_error($link));
- }
- }
-}
-
-function db_escape_string($s, $strip_tags = true) {
- if ($strip_tags) $s = strip_tags($s);
-
- if (DB_TYPE == "pgsql") {
- return pg_escape_string($s);
- } else {
- return mysql_real_escape_string($s);
- }
-}
-
-function db_query($link, $query, $die_on_error = true) {
- //if ($_REQUEST["qlog"])
- // error_log($_SESSION["uid"] . ":" . $_REQUEST["op"] . "/" . $_REQUEST["subop"] .
- // " $query\n", 3, "/tmp/ttrss-query.log");
-
- if (DB_TYPE == "pgsql") {
- $result = pg_query($link, $query);
- if (!$result) {
- $query = htmlspecialchars($query); // just in case
- if ($die_on_error) {
- die("Query <i>$query</i> failed [$result]: " . pg_last_error($link));
- }
- }
- return $result;
- } else if (DB_TYPE == "mysql") {
- $result = mysql_query($query, $link);
- if (!$result) {
- $query = htmlspecialchars($query);
- if ($die_on_error) {
- die("Query <i>$query</i> failed: " . mysql_error($link));
- }
- }
- return $result;
- }
-}
-
-function db_fetch_assoc($result) {
- if (DB_TYPE == "pgsql") {
- return pg_fetch_assoc($result);
- } else if (DB_TYPE == "mysql") {
- return mysql_fetch_assoc($result);
- }
-}
-
-
-function db_num_rows($result) {
- if (DB_TYPE == "pgsql") {
- return pg_num_rows($result);
- } else if (DB_TYPE == "mysql") {
- return mysql_num_rows($result);
- }
-}
-
-function db_fetch_result($result, $row, $param) {
- if (DB_TYPE == "pgsql") {
- return pg_fetch_result($result, $row, $param);
- } else if (DB_TYPE == "mysql") {
- // I hate incoherent naming of PHP functions
- return mysql_result($result, $row, $param);
- }
-}
-
-function db_unescape_string($str) {
- $tmp = str_replace("\\\"", "\"", $str);
- $tmp = str_replace("\\'", "'", $tmp);
- return $tmp;
-}
-
-function db_close($link) {
- if (DB_TYPE == "pgsql") {
-
- return pg_close($link);
-
- } else if (DB_TYPE == "mysql") {
- return mysql_close($link);
- }
-}
-
-function db_affected_rows($link, $result) {
- if (DB_TYPE == "pgsql") {
- return pg_affected_rows($result);
- } else if (DB_TYPE == "mysql") {
- return mysql_affected_rows($link);
- }
-}
-
-function db_last_error($link) {
- if (DB_TYPE == "pgsql") {
- return pg_last_error($link);
- } else if (DB_TYPE == "mysql") {
- return mysql_error($link);
- }
-}
-
-function db_quote($str){
- return("'$str'");
-}
-
-?>
+++ /dev/null
-function selectTableRow(r, do_select) {
-
- if (do_select) {
- r.addClassName("Selected");
- } else {
- r.removeClassName("Selected");
- }
-}
-
-function selectTableRowById(elem_id, check_id, do_select) {
-
- try {
-
- var row = $(elem_id);
-
- if (row) {
- selectTableRow(row, do_select);
- }
-
- var check = $(check_id);
-
- if (check) {
- check.checked = do_select;
- }
- } catch (e) {
- exception_error("selectTableRowById", e);
- }
-}
-
+++ /dev/null
-var last_feeds = [];
-var init_params = {};
-
-var _active_feed_id = false;
-var _update_timeout = false;
-var _view_update_timeout = false;
-var _feedlist_expanded = false;
-var _update_seq = 1;
-
-function article_appear(article_id) {
- try {
- new Effect.Appear('A-' + article_id);
- } catch (e) {
- exception_error("article_appear", e);
- }
-}
-
-function catchup_feed(feed_id, callback) {
- try {
-
- var fn = find_feed(last_feeds, feed_id).title;
-
- if (confirm(__("Mark all articles in %s as read?").replace("%s", fn))) {
-
- var is_cat = "";
-
- if (feed_id < 0) is_cat = "true"; // KLUDGE
-
- var query = "?op=rpc&subop=catchupFeed&feed_id=" +
- feed_id + "&is_cat=" + is_cat;
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- if (callback) callback(transport);
-
- update();
- } });
- }
-
- } catch (e) {
- exception_error("catchup_article", e);
- }
-}
-
-function get_visible_article_ids() {
- try {
- var elems = $("headlines-content").getElementsByTagName("LI");
- var ids = [];
-
- for (var i = 0; i < elems.length; i++) {
- if (elems[i].id && elems[i].id.match("A-")) {
- ids.push(elems[i].id.replace("A-", ""));
- }
- }
-
- return ids;
-
- } catch (e) {
- exception_error("get_visible_article_ids", e);
- }
-}
-
-function catchup_visible_articles(callback) {
- try {
-
- var ids = get_visible_article_ids();
-
- if (confirm(__("Mark %d displayed articles as read?").replace("%d", ids.length))) {
-
- var query = "?op=rpc&subop=catchupSelected" +
- "&cmode=0&ids=" + param_escape(ids);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- if (callback) callback(transport);
-
- viewfeed(_active_feed_id, 0);
- } });
-
- }
-
- } catch (e) {
- exception_error("catchup_visible_articles", e);
- }
-}
-
-function catchup_article(article_id, callback) {
- try {
- var query = "?op=rpc&subop=catchupSelected" +
- "&cmode=0&ids=" + article_id;
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- if (callback) callback(transport);
- } });
-
- } catch (e) {
- exception_error("catchup_article", e);
- }
-}
-
-function set_selected_article(article_id) {
- try {
- $$("#headlines-content > li[id*=A-]").each(function(article) {
- var id = article.id.replace("A-", "");
-
- var cb = article.getElementsByTagName("INPUT")[0];
-
- if (id == article_id) {
- article.addClassName("selected");
- cb.checked = true;
- } else {
- article.removeClassName("selected");
- cb.checked = false;
- }
-
- });
-
- } catch (e) {
- exception_error("mark_selected_feed", e);
- }
-}
-
-
-function set_selected_feed(feed_id) {
- try {
- var feeds = $("feeds-content").getElementsByTagName("LI");
-
- for (var i = 0; i < feeds.length; i++) {
- if (feeds[i].id == "F-" + feed_id)
- feeds[i].className = "selected";
- else
- feeds[i].className = "";
- }
-
- _active_feed_id = feed_id;
-
- } catch (e) {
- exception_error("mark_selected_feed", e);
- }
-}
-
-function load_more() {
- try {
- var pr = $("H-LOADING-IMG");
-
- if (pr) Element.show(pr);
-
- var offset = $$("#headlines-content > li[id*=A-][class*=fresh],li[id*=A-][class*=unread]").length;
-
- viewfeed(false, offset, false, false, true,
- function() {
- var pr = $("H-LOADING-IMG");
-
- if (pr) Element.hide(pr);
- });
- } catch (e) {
- exception_error("load_more", e);
- }
-}
-
-function update(callback) {
- try {
- console.log('updating feeds...');
-
- window.clearTimeout(_update_timeout);
-
- new Ajax.Request("backend.php", {
- parameters: "?op=rpc&subop=digest-init",
- onComplete: function(transport) {
- fatal_error_check(transport);
- parse_feeds(transport);
- set_selected_feed(_active_feed_id);
-
- if (callback) callback(transport);
- } });
-
- _update_timeout = window.setTimeout('update()', 5*1000);
- } catch (e) {
- exception_error("update", e);
- }
-}
-
-function remove_headline_entry(article_id) {
- try {
- var elem = $('A-' + article_id);
-
- if (elem) {
- elem.parentNode.removeChild(elem);
- }
-
- } catch (e) {
- exception_error("remove_headline_entry", e);
- }
-}
-
-function view_update() {
- try {
- viewfeed(_active_feed_id, _active_feed_offset, false, true, true);
- update();
- } catch (e) {
- exception_error("view_update", e);
- }
-}
-
-function view(article_id) {
- try {
- $("content").addClassName("move");
-
- var a = $("A-" + article_id);
- var h = $("headlines");
-
- setTimeout(function() {
- // below or above viewport, reposition headline
- if (a.offsetTop > h.scrollTop + h.offsetHeight || a.offsetTop+a.offsetHeight < h.scrollTop+a.offsetHeight)
- h.scrollTop = a.offsetTop - (h.offsetHeight/2 - a.offsetHeight/2);
- }, 500);
-
- new Ajax.Request("backend.php", {
- parameters: "?op=rpc&subop=digest-get-contents&article_id=" +
- article_id,
- onComplete: function(transport) {
- fatal_error_check(transport);
-
- var reply = JSON.parse(transport.responseText);
-
- if (reply) {
- var article = reply['article'];
-
- var mark_part = "";
- var publ_part = "";
-
- var tags_part = "";
-
- if (article.tags.length > 0) {
- tags_part = " " + __("in") + " ";
-
- for (var i = 0; i < Math.min(5, article.tags.length); i++) {
- //tags_part += "<a href=\"#\" onclick=\"viewfeed('" +
- // article.tags[i] + "')\">" +
- // article.tags[i] + "</a>, ";
-
- tags_part += article.tags[i] + ", ";
- }
-
- tags_part = tags_part.replace(/, $/, "");
- tags_part = "<span class=\"tags\">" + tags_part + "</span>";
-
- }
-
- if (article.marked)
- mark_part = "<img title='"+ __("Unstar article")+"' onclick=\"toggle_mark(this, "+article.id+")\" src='images/mark_set.png'>";
- else
- mark_part = "<img title='"+__("Star article")+"' onclick=\"toggle_mark(this, "+article.id+")\" src='images/mark_unset.png'>";
-
- if (article.published)
- publ_part = "<img title='"+__("Unpublish article")+"' onclick=\"toggle_pub(this, "+article.id+")\" src='images/pub_set.png'>";
- else
- publ_part = "<img title='"+__("Publish article")+"' onclick=\"toggle_pub(this, "+article.id+")\" src='images/pub_unset.png'>";
-
- var tmp = "<div id=\"toolbar\">" +
- "<a target=\"_blank\" href=\""+article.url+"\">" + __("Original article") + "</a>" +
- "<div style=\"float : right\"><a href=\"#\" onclick=\"close_article()\">" +
- __("Close this panel") + "</a></div></div>" +
- "<div id=\"inner\">" +
- "<div id=\"ops\">" +
- mark_part +
- publ_part +
- "</div>" +
- "<h1>" + article.title + "</h1>" +
- "<div id=\"tags\">" +
- tags_part +
- "</div>" +
- article.content + "</div>";
-
- $("article-content").innerHTML = tmp;
- $("article").addClassName("visible");
-
- set_selected_article(article.id);
-
- catchup_article(article_id,
- function() {
- $("A-" + article_id).addClassName("read");
- });
-
- } else {
- elem.innerHTML = __("Error: unable to load article.");
- }
- }
- });
-
-
- return false;
- } catch (e) {
- exception_error("view", e);
- }
-}
-
-function close_article() {
- $("content").removeClassName("move");
- $("article").removeClassName("visible");
-}
-
-function viewfeed(feed_id, offset, replace, no_effects, no_indicator, callback) {
- try {
-
- if (!feed_id) feed_id = _active_feed_id;
- if (offset == undefined) offset = 0;
- if (replace == undefined) replace = (offset == 0);
-
- _update_seq = _update_seq + 1;
-
- if (!offset) $("headlines").scrollTop = 0;
-
- var query = "backend.php?op=rpc&subop=digest-update&feed_id=" +
- param_escape(feed_id) + "&offset=" + offset +
- "&seq=" + _update_seq;
-
- console.log(query);
-
- var img = false;
-
- if ($("F-" + feed_id)) {
- img = $("F-" + feed_id).getElementsByTagName("IMG")[0];
-
- if (img && !no_indicator) {
- img.setAttribute("orig_src", img.src);
- img.src = 'images/indicator_tiny.gif';
- }
- }
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- Element.hide("overlay");
-
- fatal_error_check(transport);
- parse_headlines(transport, replace, no_effects);
- set_selected_feed(feed_id);
- _active_feed_offset = offset;
-
- if (img && !no_indicator)
- img.src = img.getAttribute("orig_src");
-
- if (callback) callback(transport);
-
- } });
-
- } catch (e) {
- exception_error("view", e);
- }
-}
-
-function find_article(articles, article_id) {
- try {
- for (var i = 0; i < articles.length; i++) {
- if (articles[i].id == article_id)
- return articles[i];
- }
-
- return false;
-
- } catch (e) {
- exception_error("find_article", e);
- }
-}
-
-function find_feed(feeds, feed_id) {
- try {
- for (var i = 0; i < feeds.length; i++) {
- if (feeds[i].id == feed_id)
- return feeds[i];
- }
-
- return false;
-
- } catch (e) {
- exception_error("find_feed", e);
- }
-}
-
-function get_feed_icon(feed) {
- try {
- if (feed.has_icon)
- return getInitParam('icons_url') + "/" + feed.id + '.ico';
-
- if (feed.id == -1)
- return 'images/mark_set.png';
-
- if (feed.id == -2)
- return 'images/pub_set.png';
-
- if (feed.id == -3)
- return 'images/fresh.png';
-
- if (feed.id == -4)
- return 'images/tag.png';
-
- if (feed.id < -10)
- return 'images/label.png';
-
- return 'images/blank_icon.gif';
-
- } catch (e) {
- exception_error("get_feed_icon", e);
- }
-}
-
-function add_feed_entry(feed) {
- try {
- var icon_part = "";
-
- icon_part = "<img src='" + get_feed_icon(feed) + "'/>";
-
- var tmp_html = "<li id=\"F-"+feed.id+"\" onclick=\"viewfeed("+feed.id+")\">" +
- icon_part + feed.title +
- "<div class='unread-ctr'>" + "<span class=\"unread\">" + feed.unread + "</span>" +
- "</div>" + "</li>";
-
- $("feeds-content").innerHTML += tmp_html;
-
-
- } catch (e) {
- exception_error("add_feed_entry", e);
- }
-}
-
-function add_headline_entry(article, feed, no_effects) {
- try {
-
- var icon_part = "";
-
- icon_part = "<img class='icon' src='" + get_feed_icon(feed) + "'/>";
-
-
- var style = "";
-
- //if (!no_effects) style = "style=\"display : none\"";
-
- if (article.excerpt.trim() == "")
- article.excerpt = __("Click to expand article.");
-
- var li_class = "unread";
-
- var fresh_max = getInitParam("fresh_article_max_age") * 60 * 60;
- var d = new Date();
-
- if (d.getTime() / 1000 - article.updated < fresh_max)
- li_class = "fresh";
-
- //"<img title='" + __("Share on Twitter") + "' onclick=\"tweet_article("+article.id+", true)\" src='images/art-tweet.png'>" +
-
- //"<img title='" + __("Mark as read") + "' onclick=\"view("+article.id+", true)\" src='images/digest_checkbox.png'>" +
-
- var checkbox_part = "<input type=\"checkbox\" class=\"cb\" onclick=\"toggle_select_article(this)\"/>";
-
- var date = new Date(article.updated * 1000);
-
- var date_part = date.toString().substring(0,21);
-
- var tmp_html = "<li id=\"A-"+article.id+"\" "+style+" class=\""+li_class+"\">" +
- checkbox_part +
- icon_part +
- "<a target=\"_blank\" href=\""+article.link+"\""+
- "onclick=\"return view("+article.id+")\" class='title'>" +
- article.title + "</a>" +
- "<div class='body'>" +
- "<div onclick=\"view("+article.id+")\" class='excerpt'>" +
- article.excerpt + "</div>" +
- "<div class='info'>";
-
-/* tmp_html += "<a href=\#\" onclick=\"viewfeed("+feed.id+")\">" +
- feed.title + "</a> " + " @ "; */
-
- tmp_html += date_part + "</div>" +
- "</div></li>";
-
- $("headlines-content").innerHTML += tmp_html;
-
- if (!no_effects)
- window.setTimeout('article_appear(' + article.id + ')', 100);
-
- } catch (e) {
- exception_error("add_headline_entry", e);
- }
-}
-
-function expand_feeds() {
- try {
- _feedlist_expanded = true;
-
- redraw_feedlist(last_feeds);
-
- } catch (e) {
- exception_error("expand_feeds", e);
- }
-}
-
-function redraw_feedlist(feeds) {
- try {
-
- $('feeds-content').innerHTML = "";
-
- var limit = 10;
-
- if (_feedlist_expanded) limit = feeds.length;
-
- for (var i = 0; i < Math.min(limit, feeds.length); i++) {
- add_feed_entry(feeds[i]);
- }
-
- if (feeds.length > limit) {
- $('feeds-content').innerHTML += "<li id='F-MORE-PROMPT'>" +
- "<img src='images/blank_icon.gif'>" +
- "<a href=\"#\" onclick=\"expand_feeds()\">" +
- __("%d more...").replace("%d", feeds.length-10) +
- "</a>" + "</li>";
- }
-
- if (feeds.length == 0) {
- $('feeds-content').innerHTML =
- "<div class='insensitive' style='text-align : center'>" +
- __("No unread feeds.") + "</div>";
- }
-
- if (_active_feed_id)
- set_selected_feed(_active_feed_id);
-
- } catch (e) {
- exception_error("redraw_feedlist", e);
- }
-}
-
-function parse_feeds(transport) {
- try {
- var reply = JSON.parse(transport.responseText);
-
- if (!reply) return;
-
- var feeds = reply['feeds'];
-
- if (feeds) {
-
- feeds.sort( function (a,b)
- {
- if (b.unread != a.unread)
- return (b.unread - a.unread);
- else
- if (a.title > b.title)
- return 1;
- else if (a.title < b.title)
- return -1;
- else
- return 0;
- });
-
- var all_articles = find_feed(feeds, -4);
-
- update_title(all_articles.unread);
-
- last_feeds = feeds;
-
- redraw_feedlist(feeds);
- }
-
- } catch (e) {
- exception_error("parse_feeds", e);
- }
-}
-
-function parse_headlines(transport, replace, no_effects) {
- try {
- var reply = JSON.parse(transport.responseText);
- if (!reply) return;
-
- var seq = reply['seq'];
-
- if (seq) {
- if (seq != _update_seq) {
- console.log("parse_headlines: wrong sequence received.");
- return;
- }
- } else {
- return;
- }
-
- var headlines = reply['headlines']['content'];
- var headlines_title = reply['headlines']['title'];
-
- if (headlines && headlines_title) {
-
- if (replace) {
- $('headlines-content').innerHTML = '';
- }
-
- var pr = $('H-MORE-PROMPT');
-
- if (pr) pr.parentNode.removeChild(pr);
-
- var inserted = false;
-
- for (var i = 0; i < headlines.length; i++) {
-
- if (!$('A-' + headlines[i].id)) {
- add_headline_entry(headlines[i],
- find_feed(last_feeds, headlines[i].feed_id), !no_effects);
-
- }
- }
-
- console.log(inserted.id);
-
- var ids = get_visible_article_ids();
-
- if (ids.length > 0) {
- if (pr) {
- $('headlines-content').appendChild(pr);
-
- } else {
- $('headlines-content').innerHTML += "<li id='H-MORE-PROMPT'>" +
- "<div class='body'>" +
- "<a href=\"#\" onclick=\"catchup_visible_articles()\">" +
- __("Mark as read") + "</a> | " +
- "<a href=\"javascript:load_more()\">" +
- __("Load more...") + "</a>" +
- "<img style=\"display : none\" "+
- "id=\"H-LOADING-IMG\" src='images/indicator_tiny.gif'>" +
- "</div></li>";
- }
- } else {
- // FIXME : display some kind of "nothing to see here" prompt here
- }
-
-// if (replace && !no_effects)
-// new Effect.Appear('headlines-content', {duration : 0.3});
-
- //new Effect.Appear('headlines-content');
- }
-
- } catch (e) {
- exception_error("parse_headlines", e);
- }
-}
-
-function init_second_stage() {
- try {
- new Ajax.Request("backend.php", {
- parameters: "backend.php?op=rpc&subop=digest-init",
- onComplete: function(transport) {
- parse_feeds(transport);
- Element.hide("overlay");
-
- window.setTimeout('viewfeed(-4)', 100);
- _update_timeout = window.setTimeout('update()', 5*1000);
- } });
-
- } catch (e) {
- exception_error("init_second_stage", e);
- }
-}
-
-function init() {
- try {
- dojo.require("dijit.Dialog");
-
- new Ajax.Request("backend.php", {
- parameters: "?op=rpc&subop=sanityCheck",
- onComplete: function(transport) {
- backend_sanity_check_callback(transport);
- } });
-
- } catch (e) {
- exception_error("digest_init", e);
- }
-}
-
-function toggle_mark(img, id) {
-
- try {
-
- var query = "?op=rpc&id=" + id + "&subop=mark";
-
- if (!img) return;
-
- if (img.src.match("mark_unset")) {
- img.src = img.src.replace("mark_unset", "mark_set");
- img.alt = __("Unstar article");
- query = query + "&mark=1";
- } else {
- img.src = img.src.replace("mark_set", "mark_unset");
- img.alt = __("Star article");
- query = query + "&mark=0";
- }
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- update();
- } });
-
- } catch (e) {
- exception_error("toggle_mark", e);
- }
-}
-
-function toggle_pub(img, id, note) {
-
- try {
-
- var query = "?op=rpc&id=" + id + "&subop=publ";
-
- if (note != undefined) {
- query = query + "¬e=" + param_escape(note);
- } else {
- query = query + "¬e=undefined";
- }
-
- if (!img) return;
-
- if (img.src.match("pub_unset") || note != undefined) {
- img.src = img.src.replace("pub_unset", "pub_set");
- img.alt = __("Unpublish article");
- query = query + "&pub=1";
-
- } else {
- img.src = img.src.replace("pub_set", "pub_unset");
- img.alt = __("Publish article");
- query = query + "&pub=0";
- }
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- update();
- } });
-
- } catch (e) {
- exception_error("toggle_pub", e);
- }
-}
-
-function fatal_error(code, msg) {
- try {
-
- if (code == 6) {
- window.location.href = "digest.php";
- } else if (code == 5) {
- window.location.href = "db-updater.php";
- } else {
-
- if (msg == "") msg = "Unknown error";
-
- console.error("Fatal error: " + code + "\n" +
- msg);
-
- }
-
- } catch (e) {
- exception_error("fatalError", e);
- }
-}
-
-function fatal_error_check(transport) {
- try {
- if (transport.responseXML) {
- var error = transport.responseXML.getElementsByTagName("error")[0];
-
- if (error) {
- var code = error.getAttribute("error-code");
- var msg = error.getAttribute("error-msg");
- if (code != 0) {
- fatal_error(code, msg);
- return false;
- }
- }
- }
- } catch (e) {
- exception_error("fatal_error_check", e);
- }
- return true;
-}
-
-function update_title(unread) {
- try {
- document.title = "Tiny Tiny RSS";
-
- if (unread > 0)
- document.title += " (" + unread + ")";
-
- } catch (e) {
- exception_error("update_title", e);
- }
-}
-
-function tweet_article(id) {
- try {
-
- var query = "?op=rpc&subop=getTweetInfo&id=" + param_escape(id);
-
- console.log(query);
-
- var d = new Date();
- var ts = d.getTime();
-
- var w = window.open('backend.php?op=loading', 'ttrss_tweet',
- "status=0,toolbar=0,location=0,width=500,height=400,scrollbars=1,menubar=0");
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- var ti = JSON.parse(transport.responseText);
-
- var share_url = "http://twitter.com/share?_=" + ts +
- "&text=" + param_escape(ti.title) +
- "&url=" + param_escape(ti.link);
-
- w.location.href = share_url;
-
- } });
-
- } catch (e) {
- exception_error("tweet_article", e);
- }
-}
-
-function toggle_select_article(elem) {
- try {
- var article = elem.parentNode;
-
- if (article.hasClassName("selected"))
- article.removeClassName("selected");
- else
- article.addClassName("selected");
-
- } catch (e) {
- exception_error("toggle_select_article", e);
- }
-}
<?php
+ set_include_path(get_include_path() . PATH_SEPARATOR . "include");
+
require_once "functions.php";
require_once "sessions.php";
require_once "sanity_check.php";
<script type="text/javascript" src="lib/scriptaculous/scriptaculous.js?load=effects,dragdrop,controls"></script>
<script type="text/javascript" src="lib/dojo/dojo.js" djConfig="parseOnLoad: true"></script>
<script type="text/javascript" charset="utf-8" src="localized_js.php?<?php echo $dt_add ?>"></script>
- <script type="text/javascript" charset="utf-8" src="functions.js?<?php echo $dt_add ?>"></script>
- <script type="text/javascript" src="digest.js"></script>
+ <script type="text/javascript" charset="utf-8" src="js/functions.js?<?php echo $dt_add ?>"></script>
+ <script type="text/javascript" src="js/digest.js"></script>
<script type="text/javascript">
Event.observe(window, 'load', function() {
<?php
+ set_include_path(get_include_path() . PATH_SEPARATOR . "include");
+
require_once "functions.php";
$ERRORS[0] = "";
+++ /dev/null
-var _infscroll_disable = 0;
-var _infscroll_request_sent = 0;
-var _search_query = false;
-
-var counter_timeout_id = false;
-
-var counters_last_request = 0;
-
-function viewCategory(cat) {
- viewfeed(cat, '', true);
- return false;
-}
-
-function loadMoreHeadlines() {
- try {
- console.log("loadMoreHeadlines");
-
- var offset = 0;
-
- var view_mode = document.forms["main_toolbar_form"].view_mode.value;
- var num_unread = $$("#headlines-frame > div[id*=RROW][class*=Unread]").length;
- var num_all = $$("#headlines-frame > div[id*=RROW]").length;
-
- // TODO implement marked & published
-
- if (view_mode == "marked") {
- console.warn("loadMoreHeadlines: marked is not implemented, falling back.");
- offset = num_all;
- } else if (view_mode == "published") {
- console.warn("loadMoreHeadlines: published is not implemented, falling back.");
- offset = num_all;
- } else if (view_mode == "unread") {
- offset = num_unread;
- } else if (view_mode == "adaptive") {
- if (num_unread > 0)
- offset = num_unread;
- else
- offset = num_all;
- } else {
- offset = num_all;
- }
-
- viewfeed(getActiveFeedId(), '', activeFeedIsCat(), offset, false, true);
-
- } catch (e) {
- exception_error("viewNextFeedPage", e);
- }
-}
-
-
-function viewfeed(feed, subop, is_cat, offset, background, infscroll_req) {
- try {
- if (is_cat == undefined)
- is_cat = false;
- else
- is_cat = !!is_cat;
-
- if (subop == undefined) subop = '';
- if (offset == undefined) offset = 0;
- if (background == undefined) background = false;
- if (infscroll_req == undefined) infscroll_req = false;
-
- last_requested_article = 0;
-
- var cached_headlines = false;
-
- if (feed == getActiveFeedId()) {
- cache_delete("feed:" + feed + ":" + is_cat);
- } else {
- cached_headlines = cache_get("feed:" + feed + ":" + is_cat);
-
- // switching to a different feed, we might as well catchup stuff visible
- // in headlines buffer (if any)
- if (!background && getInitParam("cdm_auto_catchup") == 1 && parseInt(getActiveFeedId()) > 0) {
-
- $$("#headlines-frame > div[id*=RROW][class*=Unread]").each(
- function(child) {
- var hf = $("headlines-frame");
-
- if (hf.scrollTop + hf.offsetHeight >=
- child.offsetTop + child.offsetHeight) {
-
- var id = child.id.replace("RROW-", "");
-
- if (catchup_id_batch.indexOf(id) == -1)
- catchup_id_batch.push(id);
-
- }
-
- if (catchup_id_batch.length > 0) {
- window.clearTimeout(catchup_timeout_id);
-
- if (!_infscroll_request_sent) {
- catchup_timeout_id = window.setTimeout('catchupBatchedArticles()',
- 2000);
- }
- }
-
- });
- }
- }
-
- if (offset == 0 && !background)
- dijit.byId("content-tabs").selectChild(
- dijit.byId("content-tabs").getChildren()[0]);
-
- if (!background) {
- if (getActiveFeedId() != feed || offset == 0) {
- active_post_id = 0;
- _infscroll_disable = 0;
- }
-
- if (!offset && !subop && cached_headlines && !background) {
- try {
- render_local_headlines(feed, is_cat, JSON.parse(cached_headlines));
- return;
- } catch (e) {
- console.warn("render_local_headlines failed: " + e);
- }
- }
-
- if (offset != 0 && !subop) {
- var date = new Date();
- var timestamp = Math.round(date.getTime() / 1000);
-
- if (_infscroll_request_sent && _infscroll_request_sent + 30 > timestamp) {
- //console.log("infscroll request in progress, aborting");
- return;
- }
-
- _infscroll_request_sent = timestamp;
- }
-
- hideAuxDlg();
- }
-
- Form.enable("main_toolbar_form");
-
- var toolbar_query = Form.serialize("main_toolbar_form");
-
- var query = "?op=viewfeed&feed=" + feed + "&" +
- toolbar_query + "&subop=" + param_escape(subop);
-
- if (!background) {
- if (_search_query) {
- force_nocache = true;
- query = query + "&" + _search_query;
- _search_query = false;
- }
-
- if (subop == "MarkAllRead") {
-
- var show_next_feed = getInitParam("on_catchup_show_next_feed") == "1";
-
- if (show_next_feed) {
- var nuf = getNextUnreadFeed(feed, is_cat);
-
- if (nuf) {
- var cached_nuf = cache_get("feed:" + nuf + ":false");
-
- if (cached_nuf) {
-
- render_local_headlines(nuf, false, JSON.parse(cached_nuf));
-
- var catchup_query = "?op=rpc&subop=catchupFeed&feed_id=" +
- feed + "&is_cat=" + is_cat;
-
- console.log(catchup_query);
-
- new Ajax.Request("backend.php", {
- parameters: catchup_query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- } });
-
- return;
- } else {
- query += "&nuf=" + param_escape(nuf);
- }
- }
- }
- }
-
- if (offset != 0) {
- query = query + "&skip=" + offset;
-
- // to prevent duplicate feed titles when showing grouped vfeeds
- if (vgroup_last_feed) {
- query = query + "&vgrlf=" + param_escape(vgroup_last_feed);
- }
- }
-
- Form.enable("main_toolbar_form");
-
- if (!offset)
- if (!is_cat) {
- if (!setFeedExpandoIcon(feed, is_cat, 'images/indicator_white.gif'))
- notify_progress("Loading, please wait...", true);
- } else {
- notify_progress("Loading, please wait...", true);
- }
- }
-
- query += "&cat=" + is_cat;
-
- console.log(query);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- setFeedExpandoIcon(feed, is_cat, 'images/blank_icon.gif');
- headlines_callback2(transport, offset, background, infscroll_req);
- } });
-
- } catch (e) {
- exception_error("viewfeed", e);
- }
-}
-
-function feedlist_init() {
- try {
- console.log("in feedlist init");
-
- hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
- document.onkeydown = hotkey_handler;
- setTimeout("hotkey_prefix_timeout()", 5*1000);
-
- if (!getActiveFeedId()) {
- setTimeout("viewfeed(-3)", 100);
- }
-
- console.log("T:" +
- getInitParam("cdm_auto_catchup") + " " + getFeedUnread(-3));
-
- hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
-
- setTimeout("timeout()", 5000);
- setTimeout("precache_headlines_idle()", 3000);
-
- } catch (e) {
- exception_error("feedlist/init", e);
- }
-}
-
-function request_counters_real() {
- try {
- console.log("requesting counters...");
-
- var query = "?op=rpc&subop=getAllCounters&seq=" + next_seq();
-
- query = query + "&omode=flc";
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- try {
- handle_rpc_json(transport);
- } catch (e) {
- exception_error("viewfeed/getcounters", e);
- }
- } });
-
- } catch (e) {
- exception_error("request_counters_real", e);
- }
-}
-
-
-function request_counters() {
-
- try {
-
- if (getInitParam("bw_limit") == "1") return;
-
- var date = new Date();
- var timestamp = Math.round(date.getTime() / 1000);
-
- if (timestamp - counters_last_request > 5) {
- console.log("scheduling request of counters...");
-
- window.clearTimeout(counter_timeout_id);
- counter_timeout_id = window.setTimeout("request_counters_real()", 1000);
-
- counters_last_request = timestamp;
- } else {
- console.log("request_counters: rate limit reached: " + (timestamp - counters_last_request));
- }
-
- } catch (e) {
- exception_error("request_counters", e);
- }
-}
-
-function displayNewContentPrompt(id) {
- try {
-
- var msg = "<a href='#' onclick='viewCurrentFeed()'>" +
- __("New articles available in this feed (click to show)") + "</a>";
-
- msg = msg.replace("%s", getFeedName(id));
-
- $('auxDlg').innerHTML = msg;
-
- new Effect.Appear('auxDlg', {duration : 0.5});
-
- } catch (e) {
- exception_error("displayNewContentPrompt", e);
- }
-}
-
-function parse_counters(elems, scheduled_call) {
- try {
- for (var l = 0; l < elems.length; l++) {
-
- var id = elems[l].id;
- var kind = elems[l].kind;
- var ctr = parseInt(elems[l].counter);
- var error = elems[l].error;
- var has_img = elems[l].has_img;
- var updated = elems[l].updated;
-
- if (id == "global-unread") {
- global_unread = ctr;
- updateTitle();
- continue;
- }
-
- if (id == "subscribed-feeds") {
- feeds_found = ctr;
- continue;
- }
-
- // TODO: enable new content notification for categories
-
- if (!activeFeedIsCat() && id == getActiveFeedId()
- && ctr > getFeedUnread(id) && scheduled_call) {
- displayNewContentPrompt(id);
- }
-
- if (getFeedUnread(id, (kind == "cat")) != ctr)
- cache_delete("feed:" + id + ":" + (kind == "cat"));
-
- setFeedUnread(id, (kind == "cat"), ctr);
-
- if (kind != "cat") {
- setFeedValue(id, false, 'error', error);
- setFeedValue(id, false, 'updated', updated);
-
- if (id > 0) {
- if (has_img) {
- setFeedIcon(id, false,
- getInitParam("icons_url") + "/" + id + ".ico");
- } else {
- setFeedIcon(id, false, 'images/blank_icon.gif');
- }
- }
- }
- }
-
- hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
-
- } catch (e) {
- exception_error("parse_counters", e);
- }
-}
-
-function getFeedUnread(feed, is_cat) {
- try {
- var tree = dijit.byId("feedTree");
-
- if (tree && tree.model)
- return tree.model.getFeedUnread(feed, is_cat);
-
- } catch (e) {
- //
- }
-
- return -1;
-}
-
-function hideOrShowFeeds(hide) {
- var tree = dijit.byId("feedTree");
-
- if (tree)
- return tree.hideRead(hide, getInitParam("hide_read_shows_special"));
-}
-
-function getFeedName(feed, is_cat) {
- var tree = dijit.byId("feedTree");
-
- if (tree && tree.model)
- return tree.model.getFeedValue(feed, is_cat, 'name');
-}
-
-function getFeedValue(feed, is_cat, key) {
- try {
- var tree = dijit.byId("feedTree");
-
- if (tree && tree.model)
- return tree.model.getFeedValue(feed, is_cat, key);
-
- } catch (e) {
- //
- }
- return '';
-}
-
-function setFeedUnread(feed, is_cat, unread) {
- try {
- var tree = dijit.byId("feedTree");
-
- if (tree && tree.model)
- return tree.model.setFeedUnread(feed, is_cat, unread);
-
- } catch (e) {
- exception_error("setFeedUnread", e);
- }
-}
-
-function setFeedValue(feed, is_cat, key, value) {
- try {
- var tree = dijit.byId("feedTree");
-
- if (tree && tree.model)
- return tree.model.setFeedValue(feed, is_cat, key, value);
-
- } catch (e) {
- //
- }
-}
-
-function selectFeed(feed, is_cat) {
- try {
- var tree = dijit.byId("feedTree");
-
- if (tree) return tree.selectFeed(feed, is_cat);
-
- } catch (e) {
- exception_error("selectFeed", e);
- }
-}
-
-function setFeedIcon(feed, is_cat, src) {
- try {
- var tree = dijit.byId("feedTree");
-
- if (tree) return tree.setFeedIcon(feed, is_cat, src);
-
- } catch (e) {
- exception_error("setFeedIcon", e);
- }
-}
-
-function setFeedExpandoIcon(feed, is_cat, src) {
- try {
- var tree = dijit.byId("feedTree");
-
- if (tree) return tree.setFeedExpandoIcon(feed, is_cat, src);
-
- } catch (e) {
- exception_error("setFeedIcon", e);
- }
- return false;
-}
-
-function getNextUnreadFeed(feed, is_cat) {
- try {
- var tree = dijit.byId("feedTree");
- var nuf = tree.model.getNextUnreadFeed(feed, is_cat);
-
- if (nuf)
- return tree.model.store.getValue(nuf, 'bare_id');
-
- } catch (e) {
- exception_error("getNextUnreadFeed", e);
- }
-}
-
-function catchupFeed(feed, is_cat) {
- try {
- var str = __("Mark all articles in %s as read?");
- var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
-
- str = str.replace("%s", fn);
-
- if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
- return;
- }
-
- var catchup_query = "?op=rpc&subop=catchupFeed&feed_id=" +
- feed + "&is_cat=" + is_cat;
-
- notify_progress("Loading, please wait...", true);
-
- new Ajax.Request("backend.php", {
- parameters: catchup_query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- notify("");
- } });
-
- } catch (e) {
- exception_error("catchupFeed", e);
- }
-}
+++ /dev/null
-var notify_silent = false;
-var loading_progress = 0;
-var sanity_check_done = false;
-
-/* add method to remove element from array */
-
-Array.prototype.remove = function(s) {
- for (var i=0; i < this.length; i++) {
- if (s == this[i]) this.splice(i, 1);
- }
-};
-
-/* create console.log if it doesn't exist */
-
-if (!window.console) console = {};
-console.log = console.log || function(msg) { };
-console.warn = console.warn || function(msg) { };
-console.error = console.error || function(msg) { };
-
-function exception_error(location, e, ext_info) {
- var msg = format_exception_error(location, e);
-
- if (!ext_info) ext_info = false;
-
- try {
-
- if (ext_info) {
- if (ext_info.responseText) {
- ext_info = ext_info.responseText;
- }
- }
-
- var content = "<div class=\"fatalError\">" +
- "<pre>" + msg + "</pre>";
-
- content += "<form name=\"exceptionForm\" id=\"exceptionForm\" target=\"_blank\" "+
- "action=\"http://tt-rss.org/report.php\" method=\"POST\">";
-
- content += "<textarea style=\"display : none\" name=\"message\">" + msg + "</textarea>";
- content += "<textarea style=\"display : none\" name=\"params\">N/A</textarea>";
-
- if (ext_info) {
- content += "<div><b>Additional information:</b></div>" +
- "<textarea name=\"xinfo\" readonly=\"1\">" + ext_info + "</textarea>";
- }
-
- content += "<div><b>Stack trace:</b></div>" +
- "<textarea name=\"stack\" readonly=\"1\">" + e.stack + "</textarea>";
-
- content += "</form>";
-
- content += "</div>";
-
- content += "<div class='dlgButtons'>";
-
- content += "<button dojoType=\"dijit.form.Button\""+
- "onclick=\"dijit.byId('exceptionDlg').report()\">" +
- __('Report to tt-rss.org') + "</button> ";
- content += "<button dojoType=\"dijit.form.Button\" "+
- "onclick=\"dijit.byId('exceptionDlg').hide()\">" +
- __('Close') + "</button>";
- content += "</div>";
-
- if (dijit.byId("exceptionDlg"))
- dijit.byId("exceptionDlg").destroyRecursive();
-
- var dialog = new dijit.Dialog({
- id: "exceptionDlg",
- title: "Unhandled exception",
- style: "width: 600px",
- report: function() {
- if (confirm(__("Are you sure to report this exception to tt-rss.org? The report will include your browser information. Your IP would be saved in the database."))) {
-
- document.forms['exceptionForm'].params.value = $H({
- browserName: navigator.appName,
- browserVersion: navigator.appVersion,
- browserPlatform: navigator.platform,
- browserCookies: navigator.cookieEnabled,
- }).toQueryString();
-
- document.forms['exceptionForm'].submit();
-
- }
- },
- content: content});
-
- dialog.show();
-
- } catch (e) {
- alert(msg);
- }
-
-}
-
-function format_exception_error(location, e) {
- var msg;
-
- if (e.fileName) {
- var base_fname = e.fileName.substring(e.fileName.lastIndexOf("/") + 1);
-
- msg = "Exception: " + e.name + ", " + e.message +
- "\nFunction: " + location + "()" +
- "\nLocation: " + base_fname + ":" + e.lineNumber;
-
- } else if (e.description) {
- msg = "Exception: " + e.description + "\nFunction: " + location + "()";
- } else {
- msg = "Exception: " + e + "\nFunction: " + location + "()";
- }
-
- console.error("EXCEPTION: " + msg);
-
- return msg;
-}
-
-function param_escape(arg) {
- if (typeof encodeURIComponent != 'undefined')
- return encodeURIComponent(arg);
- else
- return escape(arg);
-}
-
-function param_unescape(arg) {
- if (typeof decodeURIComponent != 'undefined')
- return decodeURIComponent(arg);
- else
- return unescape(arg);
-}
-
-var notify_hide_timerid = false;
-
-function hide_notify() {
- var n = $("notify");
- if (n) {
- n.style.display = "none";
- }
-}
-
-function notify_silent_next() {
- notify_silent = true;
-}
-
-function notify_real(msg, no_hide, n_type) {
-
- if (notify_silent) {
- notify_silent = false;
- return;
- }
-
- var n = $("notify");
- var nb = $("notify_body");
-
- if (!n || !nb) return;
-
- if (notify_hide_timerid) {
- window.clearTimeout(notify_hide_timerid);
- }
-
- if (msg == "") {
- if (n.style.display == "block") {
- notify_hide_timerid = window.setTimeout("hide_notify()", 0);
- }
- return;
- } else {
- n.style.display = "block";
- }
-
- /* types:
-
- 1 - generic
- 2 - progress
- 3 - error
- 4 - info
-
- */
-
- if (typeof __ != 'undefined') {
- msg = __(msg);
- }
-
- if (n_type == 1) {
- n.className = "notify";
- } else if (n_type == 2) {
- n.className = "notifyProgress";
- msg = "<img src='"+getInitParam("sign_progress")+"'> " + msg;
- } else if (n_type == 3) {
- n.className = "notifyError";
- msg = "<img src='"+getInitParam("sign_excl")+"'> " + msg;
- } else if (n_type == 4) {
- n.className = "notifyInfo";
- msg = "<img src='"+getInitParam("sign_info")+"'> " + msg;
- }
-
-// msg = "<img src='images/live_com_loading.gif'> " + msg;
-
- nb.innerHTML = msg;
-
- if (!no_hide) {
- notify_hide_timerid = window.setTimeout("hide_notify()", 3000);
- }
-}
-
-function notify(msg, no_hide) {
- notify_real(msg, no_hide, 1);
-}
-
-function notify_progress(msg, no_hide) {
- notify_real(msg, no_hide, 2);
-}
-
-function notify_error(msg, no_hide) {
- notify_real(msg, no_hide, 3);
-
-}
-
-function notify_info(msg, no_hide) {
- notify_real(msg, no_hide, 4);
-}
-
-function setCookie(name, value, lifetime, path, domain, secure) {
-
- var d = false;
-
- if (lifetime) {
- d = new Date();
- d.setTime(d.getTime() + (lifetime * 1000));
- }
-
- console.log("setCookie: " + name + " => " + value + ": " + d);
-
- int_setCookie(name, value, d, path, domain, secure);
-
-}
-
-function int_setCookie(name, value, expires, path, domain, secure) {
- document.cookie= name + "=" + escape(value) +
- ((expires) ? "; expires=" + expires.toGMTString() : "") +
- ((path) ? "; path=" + path : "") +
- ((domain) ? "; domain=" + domain : "") +
- ((secure) ? "; secure" : "");
-}
-
-function delCookie(name, path, domain) {
- if (getCookie(name)) {
- document.cookie = name + "=" +
- ((path) ? ";path=" + path : "") +
- ((domain) ? ";domain=" + domain : "" ) +
- ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
- }
-}
-
-
-function getCookie(name) {
-
- var dc = document.cookie;
- var prefix = name + "=";
- var begin = dc.indexOf("; " + prefix);
- if (begin == -1) {
- begin = dc.indexOf(prefix);
- if (begin != 0) return null;
- }
- else {
- begin += 2;
- }
- var end = document.cookie.indexOf(";", begin);
- if (end == -1) {
- end = dc.length;
- }
- return unescape(dc.substring(begin + prefix.length, end));
-}
-
-function gotoPreferences() {
- document.location.href = "prefs.php";
-}
-
-function gotoMain() {
- document.location.href = "tt-rss.php";
-}
-
-function gotoExportOpml(filename, settings) {
- tmp = settings ? 1 : 0;
- document.location.href = "opml.php?op=Export&filename=" + filename + "&settings=" + tmp;
-}
-
-
-/** * @(#)isNumeric.js * * Copyright (c) 2000 by Sundar Dorai-Raj
- * * @author Sundar Dorai-Raj
- * * Email: sdoraira@vt.edu
- * * This program is free software; you can redistribute it and/or
- * * modify it under the terms of the GNU General Public License
- * * as published by the Free Software Foundation; either version 2
- * * of the License, or (at your option) any later version,
- * * provided that any use properly credits the author.
- * * This program is distributed in the hope that it will be useful,
- * * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * * GNU General Public License for more details at http://www.gnu.org * * */
-
- var numbers=".0123456789";
- function isNumeric(x) {
- // is x a String or a character?
- if(x.length>1) {
- // remove negative sign
- x=Math.abs(x)+"";
- for(var j=0;j<x.length;j++) {
- // call isNumeric recursively for each character
- number=isNumeric(x.substring(j,j+1));
- if(!number) return number;
- }
- return number;
- }
- else {
- // if x is number return true
- if(numbers.indexOf(x)>=0) return true;
- return false;
- }
- }
-
-
-function toggleSelectRowById(sender, id) {
- var row = $(id);
- return toggleSelectRow(sender, row);
-}
-
-function toggleSelectListRow(sender) {
- var row = sender.parentNode;
- return toggleSelectRow(sender, row);
-}
-
-/* this is for dijit Checkbox */
-function toggleSelectListRow2(sender) {
- var row = sender.domNode.parentNode;
- return toggleSelectRow(sender, row);
-}
-
-function tSR(sender, row) {
- return toggleSelectRow(sender, row);
-}
-
-/* this is for dijit Checkbox */
-function toggleSelectRow2(sender, row) {
-
- if (!row) row = sender.domNode.parentNode.parentNode;
-
- if (sender.checked && !row.hasClassName('Selected'))
- row.addClassName('Selected');
- else
- row.removeClassName('Selected');
-}
-
-
-function toggleSelectRow(sender, row) {
-
- if (!row) row = sender.parentNode.parentNode;
-
- if (sender.checked && !row.hasClassName('Selected'))
- row.addClassName('Selected');
- else
- row.removeClassName('Selected');
-}
-
-function checkboxToggleElement(elem, id) {
- if (elem.checked) {
- Effect.Appear(id, {duration : 0.5});
- } else {
- Effect.Fade(id, {duration : 0.5});
- }
-}
-
-function dropboxSelect(e, v) {
- for (var i = 0; i < e.length; i++) {
- if (e[i].value == v) {
- e.selectedIndex = i;
- break;
- }
- }
-}
-
-function getURLParam(param){
- return String(window.location.href).parseQuery()[param];
-}
-
-function leading_zero(p) {
- var s = String(p);
- if (s.length == 1) s = "0" + s;
- return s;
-}
-
-function make_timestamp() {
- var d = new Date();
-
- return leading_zero(d.getHours()) + ":" + leading_zero(d.getMinutes()) +
- ":" + leading_zero(d.getSeconds());
-}
-
-
-function closeInfoBox(cleanup) {
- try {
- dialog = dijit.byId("infoBox");
-
- if (dialog) dialog.hide();
-
- } catch (e) {
- //exception_error("closeInfoBox", e);
- }
- return false;
-}
-
-
-function displayDlg(id, param, callback) {
-
- notify_progress("Loading, please wait...", true);
-
- var query = "?op=dlg&id=" +
- param_escape(id) + "¶m=" + param_escape(param);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function (transport) {
- infobox_callback2(transport);
- if (callback) callback(transport);
- } });
-
- return false;
-}
-
-function infobox_callback2(transport) {
- try {
- var dialog = false;
-
- if (dijit.byId("infoBox")) {
- dialog = dijit.byId("infoBox");
- }
-
- //console.log("infobox_callback2");
- notify('');
-
- var title = transport.responseXML.getElementsByTagName("title")[0];
- if (title)
- title = title.firstChild.nodeValue;
-
- var content = transport.responseXML.getElementsByTagName("content")[0];
-
- content = content.firstChild.nodeValue;
-
- if (!dialog) {
- dialog = new dijit.Dialog({
- title: title,
- id: 'infoBox',
- style: "width: 600px",
- onCancel: function() {
- return true;
- },
- onExecute: function() {
- return true;
- },
- onClose: function() {
- return true;
- },
- content: content});
- } else {
- dialog.attr('title', title);
- dialog.attr('content', content);
- }
-
- dialog.show();
-
- notify("");
- } catch (e) {
- exception_error("infobox_callback2", e);
- }
-}
-
-function filterCR(e, f)
-{
- var key;
-
- if(window.event)
- key = window.event.keyCode; //IE
- else
- key = e.which; //firefox
-
- if (key == 13) {
- if (typeof f != 'undefined') {
- f();
- return false;
- } else {
- return false;
- }
- } else {
- return true;
- }
-}
-
-function getInitParam(key) {
- return init_params[key];
-}
-
-function setInitParam(key, value) {
- init_params[key] = value;
-}
-
-function fatalError(code, msg, ext_info) {
- try {
-
- if (code == 6) {
- window.location.href = "tt-rss.php";
- } else if (code == 5) {
- window.location.href = "db-updater.php";
- } else {
-
- if (msg == "") msg = "Unknown error";
-
- if (ext_info) {
- if (ext_info.responseText) {
- ext_info = ext_info.responseText;
- }
- }
-
- if (ERRORS && ERRORS[code] && !msg) {
- msg = ERRORS[code];
- }
-
- var content = "<div><b>Error code:</b> " + code + "</div>" +
- "<p>" + msg + "</p>";
-
- if (ext_info) {
- content = content + "<div><b>Additional information:</b></div>" +
- "<textarea style='width: 100%' readonly=\"1\">" +
- ext_info + "</textarea>";
- }
-
- var dialog = new dijit.Dialog({
- title: "Fatal error",
- style: "width: 600px",
- content: content});
-
- dialog.show();
-
- }
-
- return false;
-
- } catch (e) {
- exception_error("fatalError", e);
- }
-}
-
-function filterDlgCheckType(sender) {
-
- try {
-
- var ftype = sender.value;
-
- // if selected filter type is 5 (Date) enable the modifier dropbox
- if (ftype == 5) {
- Element.show("filterDlg_dateModBox");
- Element.show("filterDlg_dateChkBox");
- } else {
- Element.hide("filterDlg_dateModBox");
- Element.hide("filterDlg_dateChkBox");
-
- }
-
- } catch (e) {
- exception_error("filterDlgCheckType", e);
- }
-
-}
-
-function filterDlgCheckAction(sender) {
-
- try {
-
- var action = sender.value;
-
- var action_param = $("filterDlg_paramBox");
-
- if (!action_param) {
- console.log("filterDlgCheckAction: can't find action param box!");
- return;
- }
-
- // if selected action supports parameters, enable params field
- if (action == 4 || action == 6 || action == 7) {
- new Effect.Appear(action_param, {duration : 0.5});
- if (action != 7) {
- Element.show(dijit.byId("filterDlg_actionParam").domNode);
- Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode);
- } else {
- Element.show(dijit.byId("filterDlg_actionParamLabel").domNode);
- Element.hide(dijit.byId("filterDlg_actionParam").domNode);
- }
- } else {
- Element.hide(action_param);
- }
-
- } catch (e) {
- exception_error("filterDlgCheckAction", e);
- }
-
-}
-
-function filterDlgCheckDate() {
- try {
- var dialog = dijit.byId("filterEditDlg");
-
- var reg_exp = dialog.attr('value').reg_exp;
-
- var query = "?op=rpc&subop=checkDate&date=" + reg_exp;
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
-
- var reply = JSON.parse(transport.responseText);
-
- if (reply['result'] == true) {
- alert(__("Date syntax appears to be correct:") + " " + reply['date']);
- return;
- } else {
- alert(__("Date syntax is incorrect."));
- }
-
- } });
-
-
- } catch (e) {
- exception_error("filterDlgCheckDate", e);
- }
-}
-
-function explainError(code) {
- return displayDlg("explainError", code);
-}
-
-function displayHelpInfobox(topic_id) {
-
- var url = "backend.php?op=help&tid=" + param_escape(topic_id);
-
- window.open(url, "ttrss_help",
- "status=0,toolbar=0,location=0,width=450,height=500,scrollbars=1,menubar=0");
-
-}
-
-function loading_set_progress(p) {
- try {
- loading_progress += p;
-
- if (dijit.byId("loading_bar"))
- dijit.byId("loading_bar").update({progress: loading_progress});
-
- if (loading_progress >= 90)
- remove_splash();
-
- } catch (e) {
- exception_error("loading_set_progress", e);
- }
-}
-
-function remove_splash() {
-
- if (Element.visible("overlay")) {
- console.log("about to remove splash, OMG!");
- Element.hide("overlay");
- console.log("removed splash!");
- }
-}
-
-function transport_error_check(transport) {
- try {
- if (transport.responseXML) {
- var error = transport.responseXML.getElementsByTagName("error")[0];
-
- if (error) {
- var code = error.getAttribute("error-code");
- var msg = error.getAttribute("error-msg");
- if (code != 0) {
- fatalError(code, msg);
- return false;
- }
- }
- }
- } catch (e) {
- exception_error("check_for_error_xml", e);
- }
- return true;
-}
-
-function strip_tags(s) {
- return s.replace(/<\/?[^>]+(>|$)/g, "");
-}
-
-function truncate_string(s, length) {
- if (!length) length = 30;
- var tmp = s.substring(0, length);
- if (s.length > length) tmp += "…";
- return tmp;
-}
-
-function hotkey_prefix_timeout() {
- try {
-
- var date = new Date();
- var ts = Math.round(date.getTime() / 1000);
-
- if (hotkey_prefix_pressed && ts - hotkey_prefix_pressed >= 5) {
- console.log("hotkey_prefix seems to be stuck, aborting");
- hotkey_prefix_pressed = false;
- hotkey_prefix = false;
- Element.hide('cmdline');
- }
-
- setTimeout("hotkey_prefix_timeout()", 1000);
-
- } catch (e) {
- exception_error("hotkey_prefix_timeout", e);
- }
-}
-
-function hideAuxDlg() {
- try {
- Element.hide('auxDlg');
- } catch (e) {
- exception_error("hideAuxDlg", e);
- }
-}
-
-
-function uploadIconHandler(rc) {
- try {
- switch (rc) {
- case 0:
- notify_info("Upload complete.");
- if (inPreferences()) {
- updateFeedList();
- } else {
- setTimeout('updateFeedList(false, false)', 50);
- }
- break;
- case 1:
- notify_error("Upload failed: icon is too big.");
- break;
- case 2:
- notify_error("Upload failed.");
- break;
- }
-
- } catch (e) {
- exception_error("uploadIconHandler", e);
- }
-}
-
-function removeFeedIcon(id) {
-
- try {
-
- if (confirm(__("Remove stored feed icon?"))) {
- var query = "backend.php?op=pref-feeds&subop=removeicon&feed_id=" + param_escape(id);
-
- console.log(query);
-
- notify_progress("Removing feed icon...", true);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify_info("Feed icon removed.");
- if (inPreferences()) {
- updateFeedList();
- } else {
- setTimeout('updateFeedList(false, false)', 50);
- }
- } });
- }
-
- return false;
- } catch (e) {
- exception_error("uploadFeedIcon", e);
- }
-}
-
-function uploadFeedIcon() {
-
- try {
-
- var file = $("icon_file");
-
- if (file.value.length == 0) {
- alert(__("Please select an image file to upload."));
- } else {
- if (confirm(__("Upload new icon for this feed?"))) {
- notify_progress("Uploading, please wait...", true);
- return true;
- }
- }
-
- return false;
-
- } catch (e) {
- exception_error("uploadFeedIcon", e);
- }
-}
-
-function addLabel(select, callback) {
-
- try {
-
- var caption = prompt(__("Please enter label caption:"), "");
-
- if (caption != undefined) {
-
- if (caption == "") {
- alert(__("Can't create label: missing caption."));
- return false;
- }
-
- var query = "?op=pref-labels&subop=add&caption=" +
- param_escape(caption);
-
- if (select)
- query += "&output=select";
-
- notify_progress("Loading, please wait...", true);
-
- if (inPreferences() && !select) active_tab = "labelConfig";
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- if (callback) {
- callback(transport);
- } else if (inPreferences()) {
- updateLabelList();
- } else {
- updateFeedList();
- }
- } });
-
- }
-
- } catch (e) {
- exception_error("addLabel", e);
- }
-}
-
-function quickAddFeed() {
- try {
- var query = "backend.php?op=dlg&id=quickAddFeed";
-
- if (dijit.byId("feedAddDlg"))
- dijit.byId("feedAddDlg").destroyRecursive();
-
- var dialog = new dijit.Dialog({
- id: "feedAddDlg",
- title: __("Subscribe to Feed"),
- style: "width: 600px",
- execute: function() {
- if (this.validate()) {
- console.log(dojo.objectToQuery(this.attr('value')));
-
- var feed_url = this.attr('value').feed;
-
- notify_progress(__("Subscribing to feed..."), true);
-
- new Ajax.Request("backend.php", {
- parameters: dojo.objectToQuery(this.attr('value')),
- onComplete: function(transport) {
- try {
-
- var reply = JSON.parse(transport.responseText);
-
- var rc = parseInt(reply['result']);
-
- notify('');
-
- console.log("GOT RC: " + rc);
-
- switch (rc) {
- case 1:
- dialog.hide();
- notify_info(__("Subscribed to %s").replace("%s", feed_url));
-
- updateFeedList();
- break;
- case 2:
- alert(__("Specified URL seems to be invalid."));
- break;
- case 3:
- alert(__("Specified URL doesn't seem to contain any feeds."));
- break;
- case 4:
- notify_progress("Searching for feed urls...", true);
-
- new Ajax.Request("backend.php", {
- parameters: 'op=rpc&subop=extractfeedurls&url=' + param_escape(feed_url),
- onComplete: function(transport, dialog, feed_url) {
-
- notify('');
-
- var reply = JSON.parse(transport.responseText);
-
- var feeds = reply['urls'];
-
- console.log(transport.responseText);
-
- var select = dijit.byId("feedDlg_feedContainerSelect");
-
- while (select.getOptions().length > 0)
- select.removeOption(0);
-
- var count = 0;
- for (var feedUrl in feeds) {
- select.addOption({value: feedUrl, label: feeds[feedUrl]});
- count++;
- }
-
-// if (count > 5) count = 5;
-// select.size = count;
-
- Effect.Appear('feedDlg_feedsContainer', {duration : 0.5});
- }
- });
- break;
- case 5:
- alert(__("Couldn't download the specified URL."));
- break;
- case 0:
- alert(__("You are already subscribed to this feed."));
- break;
- }
-
- } catch (e) {
- exception_error("subscribeToFeed", e, transport);
- }
-
- } });
-
- }
- },
- href: query});
-
- dialog.show();
- } catch (e) {
- exception_error("quickAddFeed", e);
- }
-}
-
-function quickAddFilter() {
- try {
- var query = "backend.php?op=dlg&id=quickAddFilter";
-
- if (dijit.byId("filterEditDlg"))
- dijit.byId("filterEditDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "filterEditDlg",
- title: __("Create Filter"),
- style: "width: 600px",
- test: function() {
- if (this.validate()) {
-
- if (dijit.byId("filterTestDlg"))
- dijit.byId("filterTestDlg").destroyRecursive();
-
- tdialog = new dijit.Dialog({
- id: "filterTestDlg",
- title: __("Filter Test Results"),
- style: "width: 600px",
- href: "backend.php?savemode=test&" +
- dojo.objectToQuery(dialog.attr('value')),
- });
-
- tdialog.show();
-
- }
- },
- execute: function() {
- if (this.validate()) {
-
- var query = "?op=rpc&subop=verifyRegexp®_exp=" +
- param_escape(dialog.attr('value').reg_exp);
-
- notify_progress("Verifying regular expression...");
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- var reply = JSON.parse(transport.responseText);
-
- if (reply) {
- notify('');
-
- if (!reply['status']) {
- alert("Match regular expression seems to be invalid.");
- return;
- } else {
- notify_progress("Saving data...", true);
-
- console.log(dojo.objectToQuery(dialog.attr('value')));
-
- new Ajax.Request("backend.php", {
- parameters: dojo.objectToQuery(dialog.attr('value')),
- onComplete: function(transport) {
- dialog.hide();
- notify_info(transport.responseText);
- if (inPreferences()) {
- updateFilterList();
- }
- }});
- }
- }
- }});
- }
- },
- href: query});
-
- dialog.show();
- } catch (e) {
- exception_error("quickAddFilter", e);
- }
-}
-
-function resetPubSub(feed_id, title) {
-
- var msg = __("Reset subscription? Tiny Tiny RSS will try to subscribe to the notification hub again on next feed update.").replace("%s", title);
-
- if (title == undefined || confirm(msg)) {
- notify_progress("Loading, please wait...");
-
- var query = "?op=pref-feeds&quiet=1&subop=resetPubSub&ids=" + feed_id;
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- dijit.byId("pubsubReset_Btn").attr('disabled', true);
- notify_info("Subscription reset.");
- } });
- }
-
- return false;
-}
-
-
-function unsubscribeFeed(feed_id, title) {
-
- var msg = __("Unsubscribe from %s?").replace("%s", title);
-
- if (title == undefined || confirm(msg)) {
- notify_progress("Removing feed...");
-
- var query = "?op=pref-feeds&quiet=1&subop=remove&ids=" + feed_id;
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
-
- if (dijit.byId("feedEditDlg")) dijit.byId("feedEditDlg").hide();
-
- if (inPreferences()) {
- updateFeedList();
- } else {
- if (feed_id == getActiveFeedId())
- setTimeout("viewfeed(-5)", 100);
- }
-
- } });
- }
-
- return false;
-}
-
-
-function backend_sanity_check_callback(transport) {
-
- try {
-
- if (sanity_check_done) {
- fatalError(11, "Sanity check request received twice. This can indicate "+
- "presence of Firebug or some other disrupting extension. "+
- "Please disable it and try again.");
- return;
- }
-
- var reply = JSON.parse(transport.responseText);
-
- if (!reply) {
- fatalError(3, "Sanity check: invalid RPC reply", transport.responseText);
- return;
- }
-
- var error_code = reply['error']['code'];
-
- if (error_code && error_code != 0) {
- return fatalError(error_code, reply['error']['message']);
- }
-
- console.log("sanity check ok");
-
- var params = reply['init-params'];
-
- if (params) {
- console.log('reading init-params...');
-
- if (params) {
- for (k in params) {
- var v = params[k];
- console.log("IP: " + k + " => " + v);
- }
- }
-
- init_params = params;
- }
-
- sanity_check_done = true;
-
- init_second_stage();
-
- } catch (e) {
- exception_error("backend_sanity_check_callback", e, transport);
- }
-}
-
-/*function has_local_storage() {
- try {
- return 'sessionStorage' in window && window['sessionStorage'] != null;
- } catch (e) {
- return false;
- }
-} */
-
-function catSelectOnChange(elem) {
- try {
-/* var value = elem[elem.selectedIndex].value;
- var def = elem.getAttribute('default');
-
- if (value == "ADD_CAT") {
-
- if (def)
- dropboxSelect(elem, def);
- else
- elem.selectedIndex = 0;
-
- quickAddCat(elem);
- } */
-
- } catch (e) {
- exception_error("catSelectOnChange", e);
- }
-}
-
-function quickAddCat(elem) {
- try {
- var cat = prompt(__("Please enter category title:"));
-
- if (cat) {
-
- var query = "?op=rpc&subop=quickAddCat&cat=" + param_escape(cat);
-
- notify_progress("Loading, please wait...", true);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function (transport) {
- var response = transport.responseXML;
- var select = response.getElementsByTagName("select")[0];
- var options = select.getElementsByTagName("option");
-
- dropbox_replace_options(elem, options);
-
- notify('');
-
- } });
-
- }
-
- } catch (e) {
- exception_error("quickAddCat", e);
- }
-}
-
-function genUrlChangeKey(feed, is_cat) {
-
- try {
- var ok = confirm(__("Generate new syndication address for this feed?"));
-
- if (ok) {
-
- notify_progress("Trying to change address...", true);
-
- var query = "?op=rpc&subop=regenFeedKey&id=" + param_escape(feed) +
- "&is_cat=" + param_escape(is_cat);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- var reply = JSON.parse(transport.responseText);
- var new_link = reply.link;
-
- var e = $('gen_feed_url');
-
- if (new_link) {
-
- e.innerHTML = e.innerHTML.replace(/\&key=.*$/,
- "&key=" + new_link);
-
- e.href = e.href.replace(/\&key=.*$/,
- "&key=" + new_link);
-
- new Effect.Highlight(e);
-
- notify('');
-
- } else {
- notify_error("Could not change feed URL.");
- }
- } });
- }
- } catch (e) {
- exception_error("genUrlChangeKey", e);
- }
- return false;
-}
-
-function labelSelectOnChange(elem) {
- try {
-/* var value = elem[elem.selectedIndex].value;
- var def = elem.getAttribute('default');
-
- if (value == "ADD_LABEL") {
-
- if (def)
- dropboxSelect(elem, def);
- else
- elem.selectedIndex = 0;
-
- addLabel(elem, function(transport) {
-
- try {
-
- var response = transport.responseXML;
- var select = response.getElementsByTagName("select")[0];
- var options = select.getElementsByTagName("option");
-
- dropbox_replace_options(elem, options);
-
- notify('');
- } catch (e) {
- exception_error("addLabel", e);
- }
- });
- } */
-
- } catch (e) {
- exception_error("labelSelectOnChange", e);
- }
-}
-
-function dropbox_replace_options(elem, options) {
-
- try {
- while (elem.hasChildNodes())
- elem.removeChild(elem.firstChild);
-
- var sel_idx = -1;
-
- for (var i = 0; i < options.length; i++) {
- var text = options[i].firstChild.nodeValue;
- var value = options[i].getAttribute("value");
-
- if (value == undefined) value = text;
-
- var issel = options[i].getAttribute("selected") == "1";
-
- var option = new Option(text, value, issel);
-
- if (options[i].getAttribute("disabled"))
- option.setAttribute("disabled", true);
-
- elem.insert(option);
-
- if (issel) sel_idx = i;
- }
-
- // Chrome doesn't seem to just select stuff when you pass new Option(x, y, true)
- if (sel_idx >= 0) elem.selectedIndex = sel_idx;
-
- } catch (e) {
- exception_error("dropbox_replace_options", e);
- }
-}
-
-// mode = all, none, invert
-function selectTableRows(id, mode) {
- try {
- var rows = $(id).rows;
-
- for (var i = 0; i < rows.length; i++) {
- var row = rows[i];
- var cb = false;
-
- if (row.id && row.className) {
- var bare_id = row.id.replace(/^[A-Z]*?-/, "");
- var inputs = rows[i].getElementsByTagName("input");
-
- for (var j = 0; j < inputs.length; j++) {
- var input = inputs[j];
-
- if (input.getAttribute("type") == "checkbox" &&
- input.id.match(bare_id)) {
-
- cb = input;
- break;
- }
- }
-
- if (cb) {
- var issel = row.hasClassName("Selected");
-
- if (mode == "all" && !issel) {
- row.addClassName("Selected");
- cb.checked = true;
- } else if (mode == "none" && issel) {
- row.removeClassName("Selected");
- cb.checked = false;
- } else if (mode == "invert") {
-
- if (issel) {
- row.removeClassName("Selected");
- cb.checked = false;
- } else {
- row.addClassName("Selected");
- cb.checked = true;
- }
- }
- }
- }
- }
-
- } catch (e) {
- exception_error("selectTableRows", e);
-
- }
-}
-
-function getSelectedTableRowIds(id) {
- var rows = [];
-
- try {
- var elem_rows = $(id).rows;
-
- for (var i = 0; i < elem_rows.length; i++) {
- if (elem_rows[i].hasClassName("Selected")) {
- var bare_id = elem_rows[i].id.replace(/^[A-Z]*?-/, "");
- rows.push(bare_id);
- }
- }
-
- } catch (e) {
- exception_error("getSelectedTableRowIds", e);
- }
-
- return rows;
-}
-
-function editFeed(feed, event) {
- try {
- if (feed <= 0)
- return alert(__("You can't edit this kind of feed."));
-
- var query = "backend.php?op=pref-feeds&subop=editfeed&id=" +
- param_escape(feed);
-
- console.log(query);
-
- if (dijit.byId("feedEditDlg"))
- dijit.byId("feedEditDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "feedEditDlg",
- title: __("Edit Feed"),
- style: "width: 600px",
- execute: function() {
- if (this.validate()) {
-// console.log(dojo.objectToQuery(this.attr('value')));
-
- notify_progress("Saving data...", true);
-
- new Ajax.Request("backend.php", {
- parameters: dojo.objectToQuery(dialog.attr('value')),
- onComplete: function(transport) {
- dialog.hide();
- notify('');
- updateFeedList();
- }});
- }
- },
- href: query});
-
- dialog.show();
-
- } catch (e) {
- exception_error("editFeed", e);
- }
-}
-
-function feedBrowser() {
- try {
- var query = "backend.php?op=dlg&id=feedBrowser";
-
- if (dijit.byId("feedAddDlg"))
- dijit.byId("feedAddDlg").hide();
-
- if (dijit.byId("feedBrowserDlg"))
- dijit.byId("feedBrowserDlg").destroyRecursive();
-
- var dialog = new dijit.Dialog({
- id: "feedBrowserDlg",
- title: __("More Feeds"),
- style: "width: 600px",
- getSelectedFeedIds: function() {
- var list = $$("#browseFeedList li[id*=FBROW]");
- var selected = new Array();
-
- list.each(function(child) {
- var id = child.id.replace("FBROW-", "");
-
- if (child.hasClassName('Selected')) {
- selected.push(id);
- }
- });
-
- return selected;
- },
- getSelectedFeeds: function() {
- var list = $$("#browseFeedList li.Selected");
- var selected = new Array();
-
- list.each(function(child) {
- var title = child.getElementsBySelector("span.fb_feedTitle")[0].innerHTML;
- var url = child.getElementsBySelector("a.fb_feedUrl")[0].href;
-
- selected.push([title,url]);
-
- });
-
- return selected;
- },
-
- subscribe: function() {
- var mode = this.attr('value').mode;
- var selected = [];
-
- if (mode == "1")
- selected = this.getSelectedFeeds();
- else
- selected = this.getSelectedFeedIds();
-
- if (selected.length > 0) {
- dijit.byId("feedBrowserDlg").hide();
-
- notify_progress("Loading, please wait...", true);
-
- // we use dojo.toJson instead of JSON.stringify because
- // it somehow escapes everything TWICE, at least in Chrome 9
-
- var query = "?op=rpc&subop=massSubscribe&payload="+
- param_escape(dojo.toJson(selected)) + "&mode=" + param_escape(mode);
-
- console.log(query);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
- updateFeedList();
- } });
-
- } else {
- alert(__("No feeds are selected."));
- }
-
- },
- update: function() {
- var query = dojo.objectToQuery(dialog.attr('value'));
-
- Element.show('feed_browser_spinner');
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
-
- Element.hide('feed_browser_spinner');
-
- var c = $("browseFeedList");
-
- var reply = JSON.parse(transport.responseText);
-
- var r = reply['content'];
- var mode = reply['mode'];
-
- if (c && r) {
- c.innerHTML = r;
- }
-
- dojo.parser.parse("browseFeedList");
-
- if (mode == 2) {
- Element.show(dijit.byId('feed_archive_remove').domNode);
- } else {
- Element.hide(dijit.byId('feed_archive_remove').domNode);
- }
-
- } });
- },
- removeFromArchive: function() {
- var selected = this.getSelectedFeeds();
-
- if (selected.length > 0) {
-
- var pr = __("Remove selected feeds from the archive? Feeds with stored articles will not be removed.");
-
- if (confirm(pr)) {
- Element.show('feed_browser_spinner');
-
- var query = "?op=rpc&subop=remarchived&ids=" +
- param_escape(selected.toString());;
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- dialog.update();
- } });
- }
- }
- },
- execute: function() {
- if (this.validate()) {
- this.subscribe();
- }
- },
- href: query});
-
- dialog.show();
-
- } catch (e) {
- exception_error("editFeed", e);
- }
-}
-
-function showFeedsWithErrors() {
- try {
- var query = "backend.php?op=dlg&id=feedsWithErrors";
-
- if (dijit.byId("errorFeedsDlg"))
- dijit.byId("errorFeedsDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "errorFeedsDlg",
- title: __("Feeds with update errors"),
- style: "width: 600px",
- getSelectedFeeds: function() {
- return getSelectedTableRowIds("prefErrorFeedList");
- },
- removeSelected: function() {
- var sel_rows = this.getSelectedFeeds();
-
- console.log(sel_rows);
-
- if (sel_rows.length > 0) {
- var ok = confirm(__("Remove selected feeds?"));
-
- if (ok) {
- notify_progress("Removing selected feeds...", true);
-
- var query = "?op=pref-feeds&subop=remove&ids="+
- param_escape(sel_rows.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
- dialog.hide();
- updateFeedList();
- } });
- }
-
- } else {
- alert(__("No feeds are selected."));
- }
- },
- execute: function() {
- if (this.validate()) {
- }
- },
- href: query});
-
- dialog.show();
-
- } catch (e) {
- exception_error("showFeedsWithErrors", e);
- }
-
-}
-
-/* new support functions for SelectByTag */
-
-function get_all_tags(selObj){
- try {
- if( !selObj ) return "";
-
- var result = "";
- var len = selObj.options.length;
-
- for (var i=0; i < len; i++){
- if (selObj.options[i].selected) {
- result += selObj[i].value + "%2C"; // is really a comma
- }
- }
-
- if (result.length > 0){
- result = result.substr(0, result.length-3); // remove trailing %2C
- }
-
- return(result);
-
- } catch (e) {
- exception_error("get_all_tags", e);
- }
-}
-
-function get_radio_checked(radioObj) {
- try {
- if (!radioObj) return "";
-
- var len = radioObj.length;
-
- if (len == undefined){
- if(radioObj.checked){
- return(radioObj.value);
- } else {
- return("");
- }
- }
-
- for( var i=0; i < len; i++ ){
- if( radioObj[i].checked ){
- return( radioObj[i].value);
- }
- }
-
- } catch (e) {
- exception_error("get_radio_checked", e);
- }
- return("");
-}
+++ /dev/null
-<?php
-
- date_default_timezone_set('UTC');
- if (defined('E_DEPRECATED')) {
- error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
- } else {
- error_reporting(E_ALL & ~E_NOTICE);
- }
-
- require_once 'config.php';
-
- 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.
- *
- * @access public
- * @return array A array of available translations.
- */
- function get_translations() {
- $tr = array(
- "auto" => "Detect automatically",
- "ca_CA" => "Català",
- "en_US" => "English",
- "es_ES" => "Español",
- "de_DE" => "Deutsch",
- "fr_FR" => "Français",
- "hu_HU" => "Magyar (Hungarian)",
- "it_IT" => "Italiano",
- "ja_JP" => "日本語 (Japanese)",
- "nb_NO" => "Norwegian bokmål",
- "ru_RU" => "Русский",
- "pt_BR" => "Portuguese/Brazil",
- "zh_CN" => "Simplified Chinese");
-
- return $tr;
- }
-
- require_once "lib/accept-to-gettext.php";
- require_once "lib/gettext/gettext.inc";
-
- function startup_gettext() {
-
- # Get locale from Accept-Language header
- $lang = al2gt(array_keys(get_translations()), "text/html");
-
- if (defined('_TRANSLATION_OVERRIDE_DEFAULT')) {
- $lang = _TRANSLATION_OVERRIDE_DEFAULT;
- }
-
- if ($_COOKIE["ttrss_lang"] && $_COOKIE["ttrss_lang"] != "auto") {
- $lang = $_COOKIE["ttrss_lang"];
- }
-
- /* In login action of mobile version */
- if ($_POST["language"] && defined('MOBILE_VERSION')) {
- $lang = $_POST["language"];
- $_COOKIE["ttrss_lang"] = $lang;
- }
-
- if ($lang) {
- if (defined('LC_MESSAGES')) {
- _setlocale(LC_MESSAGES, $lang);
- } else if (defined('LC_ALL')) {
- _setlocale(LC_ALL, $lang);
- }
-
- if (defined('MOBILE_VERSION')) {
- _bindtextdomain("messages", "../locale");
- } else {
- _bindtextdomain("messages", "locale");
- }
-
- _textdomain("messages");
- _bind_textdomain_codeset("messages", "UTF-8");
- }
- }
-
- startup_gettext();
-
- if (defined('MEMCACHE_SERVER')) {
- $memcache = new Memcache;
- $memcache->connect(MEMCACHE_SERVER, 11211);
- }
-
- require_once 'db-prefs.php';
- require_once 'version.php';
-
- define('MAGPIE_OUTPUT_ENCODING', 'UTF-8');
-
- define('SELF_USER_AGENT', 'Tiny Tiny RSS/' . VERSION . ' (http://tt-rss.org/)');
- define('MAGPIE_USER_AGENT', SELF_USER_AGENT);
-
- ini_set('user_agent', SELF_USER_AGENT);
-
- require_once 'lib/pubsubhubbub/publisher.php';
-
- $purifier = false;
-
- $tz_offset = -1;
- $utc_tz = new DateTimeZone('UTC');
- $schema_version = false;
-
- /**
- * Print a timestamped debug message.
- *
- * @param string $msg The debug message.
- * @return void
- */
- function _debug($msg) {
- $ts = strftime("%H:%M:%S", time());
- if (function_exists('posix_getpid')) {
- $ts = "$ts/" . posix_getpid();
- }
- print "[$ts] $msg\n";
- } // function _debug
-
- /**
- * Purge a feed old posts.
- *
- * @param mixed $link A database connection.
- * @param mixed $feed_id The id of the purged feed.
- * @param mixed $purge_interval Olderness of purged posts.
- * @param boolean $debug Set to True to enable the debug. False by default.
- * @access public
- * @return void
- */
- function purge_feed($link, $feed_id, $purge_interval, $debug = false) {
-
- if (!$purge_interval) $purge_interval = feed_purge_interval($link, $feed_id);
-
- $rows = -1;
-
- $result = db_query($link,
- "SELECT owner_uid FROM ttrss_feeds WHERE id = '$feed_id'");
-
- $owner_uid = false;
-
- if (db_num_rows($result) == 1) {
- $owner_uid = db_fetch_result($result, 0, "owner_uid");
- }
-
- if ($purge_interval == -1 || !$purge_interval) {
- if ($owner_uid) {
- ccache_update($link, $feed_id, $owner_uid);
- }
- return;
- }
-
- if (!$owner_uid) return;
-
- if (FORCE_ARTICLE_PURGE == 0) {
- $purge_unread = get_pref($link, "PURGE_UNREAD_ARTICLES",
- $owner_uid, false);
- } else {
- $purge_unread = true;
- $purge_interval = FORCE_ARTICLE_PURGE;
- }
-
- if (!$purge_unread) $query_limit = " unread = false AND ";
-
- if (DB_TYPE == "pgsql") {
- $pg_version = get_pgsql_version($link);
-
- if (preg_match("/^7\./", $pg_version) || preg_match("/^8\.0/", $pg_version)) {
-
- $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE
- ttrss_entries.id = ref_id AND
- marked = false AND
- feed_id = '$feed_id' AND
- $query_limit
- ttrss_entries.date_updated < NOW() - INTERVAL '$purge_interval days'");
-
- } else {
-
- $result = db_query($link, "DELETE FROM ttrss_user_entries
- USING ttrss_entries
- WHERE ttrss_entries.id = ref_id AND
- marked = false AND
- feed_id = '$feed_id' AND
- $query_limit
- 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
- 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
- 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);
-
- if ($debug) {
- _debug("Purged feed $feed_id ($purge_interval): deleted $rows articles");
- }
- } // function purge_feed
-
- function feed_purge_interval($link, $feed_id) {
-
- $result = db_query($link, "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,
- 'PURGE_OLD_DAYS', $owner_uid);
-
- return $purge_interval;
-
- } else {
- return -1;
- }
- }
-
- function purge_orphans($link, $do_output = false) {
-
- // purge orphaned posts in main content table
- $result = db_query($link, "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);
- _debug("Purged $rows orphaned posts.");
- }
- }
-
- function get_feed_update_interval($link, $feed_id) {
- $result = db_query($link, "SELECT owner_uid, update_interval FROM
- ttrss_feeds WHERE id = '$feed_id'");
-
- if (db_num_rows($result) == 1) {
- $update_interval = db_fetch_result($result, 0, "update_interval");
- $owner_uid = db_fetch_result($result, 0, "owner_uid");
-
- if ($update_interval != 0) {
- return $update_interval;
- } else {
- return get_pref($link, 'DEFAULT_UPDATE_INTERVAL', $owner_uid, false);
- }
-
- } else {
- return -1;
- }
- }
-
- function fetch_file_contents($url, $type = false, $login = false, $pass = false, $post_query = false) {
- $login = urlencode($login);
- $pass = urlencode($pass);
-
- if (function_exists('curl_init') && !ini_get("open_basedir")) {
- $ch = curl_init($url);
-
- curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
- curl_setopt($ch, CURLOPT_TIMEOUT, 45);
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
- 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");
-
- if ($post_query) {
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $post_query);
- }
-
- if ($login && $pass)
- curl_setopt($ch, CURLOPT_USERPWD, "$login:$pass");
-
- $contents = @curl_exec($ch);
-
- if ($contents === false) {
- curl_close($ch);
- return false;
- }
-
- $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
- curl_close($ch);
-
- if ($http_code != 200 || $type && strpos($content_type, "$type") === false) {
- return false;
- }
-
- return $contents;
- } else {
- if ($login && $pass ){
- $url_parts = array();
-
- preg_match("/(^[^:]*):\/\/(.*)/", $url, $url_parts);
-
- if ($url_parts[1] && $url_parts[2]) {
- $url = $url_parts[1] . "://$login:$pass@" . $url_parts[2];
- }
- }
-
- return @file_get_contents($url);
- }
-
- }
-
- /**
- * Try to determine the favicon URL for a feed.
- * adapted from wordpress favicon plugin by Jeff Minard (http://thecodepro.com/)
- * http://dev.wp-plugins.org/file/favatars/trunk/favatars.php
- *
- * @param string $url A feed or page URL
- * @access public
- * @return mixed The favicon URL, or false if none was found.
- */
- function get_favicon_url($url) {
-
- $favicon_url = false;
-
- if ($html = @fetch_file_contents($url)) {
-
- libxml_use_internal_errors(true);
-
- $doc = new DOMDocument();
- $doc->loadHTML($html);
- $xpath = new DOMXPath($doc);
-
- $base = $xpath->query('/html/head/base');
- foreach ($base as $b) {
- $url = $b->getAttribute("href");
- break;
- }
-
- $entries = $xpath->query('/html/head/link[@rel="shortcut icon" or @rel="icon"]');
- if (count($entries) > 0) {
- foreach ($entries as $entry) {
- $favicon_url = rewrite_relative_url($url, $entry->getAttribute("href"));
- break;
- }
- }
- }
-
- if (!$favicon_url)
- $favicon_url = rewrite_relative_url($url, "/favicon.ico");
-
- return $favicon_url;
- } // function get_favicon_url
-
- function check_feed_favicon($site_url, $feed, $link) {
-# print "FAVICON [$site_url]: $favicon_url\n";
-
- $icon_file = ICONS_DIR . "/$feed.ico";
-
- if (!file_exists($icon_file)) {
- $favicon_url = get_favicon_url($site_url);
-
- if ($favicon_url) {
- $contents = fetch_file_contents($favicon_url, "image");
-
- if ($contents) {
- $fp = @fopen($icon_file, "w");
-
- if ($fp) {
- fwrite($fp, $contents);
- fclose($fp);
- chmod($icon_file, 0644);
- }
- }
- }
- }
- }
-
- function update_rss_feed($link, $feed, $ignore_daemon = false, $no_cache = false) {
-
- global $memcache;
-
- /* Update all feeds with the same URL to utilize memcache */
-
- if ($memcache) {
- $result = db_query($link, "SELECT f1.id
- FROM ttrss_feeds AS f1, ttrss_feeds AS f2
- WHERE f2.feed_url = f1.feed_url AND f2.id = '$feed'");
-
- while ($line = db_fetch_assoc($result)) {
- update_rss_feed_real($link, $line["id"], $ignore_daemon, $no_cache);
- }
- } else {
- update_rss_feed_real($link, $feed, $ignore_daemon, $no_cache);
- }
- }
-
- function update_rss_feed_real($link, $feed, $ignore_daemon = false, $no_cache = false,
- $override_url = false) {
-
- require_once "lib/simplepie/simplepie.inc";
- require_once "lib/magpierss/rss_fetch.inc";
- require_once 'lib/magpierss/rss_utils.inc';
-
- global $memcache;
-
- $debug_enabled = defined('DAEMON_EXTENDED_DEBUG') || $_REQUEST['xdebug'];
-
- if (!$_REQUEST["daemon"] && !$ignore_daemon) {
- return false;
- }
-
- if ($debug_enabled) {
- _debug("update_rss_feed: start");
- }
-
- if (!$ignore_daemon) {
-
- if (DB_TYPE == "pgsql") {
- $updstart_thresh_qpart = "(ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < NOW() - INTERVAL '120 seconds')";
- } else {
- $updstart_thresh_qpart = "(ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < DATE_SUB(NOW(), INTERVAL 120 SECOND))";
- }
-
- $result = db_query($link, "SELECT id,update_interval,auth_login,
- auth_pass,cache_images,update_method
- FROM ttrss_feeds WHERE id = '$feed' AND $updstart_thresh_qpart");
-
- } else {
-
- $result = db_query($link, "SELECT id,update_interval,auth_login,
- feed_url,auth_pass,cache_images,update_method,last_updated,
- mark_unread_on_update, owner_uid, update_on_checksum_change,
- pubsub_state
- FROM ttrss_feeds WHERE id = '$feed'");
-
- }
-
- if (db_num_rows($result) == 0) {
- if ($debug_enabled) {
- _debug("update_rss_feed: feed $feed NOT FOUND/SKIPPED");
- }
- return false;
- }
-
- $update_method = db_fetch_result($result, 0, "update_method");
- $last_updated = db_fetch_result($result, 0, "last_updated");
- $owner_uid = db_fetch_result($result, 0, "owner_uid");
- $mark_unread_on_update = sql_bool_to_bool(db_fetch_result($result,
- 0, "mark_unread_on_update"));
- $update_on_checksum_change = sql_bool_to_bool(db_fetch_result($result,
- 0, "update_on_checksum_change"));
- $pubsub_state = db_fetch_result($result, 0, "pubsub_state");
-
- db_query($link, "UPDATE ttrss_feeds SET last_update_started = NOW()
- WHERE id = '$feed'");
-
- $auth_login = db_fetch_result($result, 0, "auth_login");
- $auth_pass = db_fetch_result($result, 0, "auth_pass");
-
- if ($update_method == 0)
- $update_method = DEFAULT_UPDATE_METHOD + 1;
-
- // 1 - Magpie
- // 2 - SimplePie
- // 3 - Twitter OAuth
-
- if ($update_method == 2)
- $use_simplepie = true;
- else
- $use_simplepie = false;
-
- if ($debug_enabled) {
- _debug("update method: $update_method (feed setting: $update_method) (use simplepie: $use_simplepie)\n");
- }
-
- if ($update_method == 1) {
- $auth_login = urlencode($auth_login);
- $auth_pass = urlencode($auth_pass);
- }
-
- $update_interval = db_fetch_result($result, 0, "update_interval");
- $cache_images = sql_bool_to_bool(db_fetch_result($result, 0, "cache_images"));
- $fetch_url = db_fetch_result($result, 0, "feed_url");
-
- if ($update_interval < 0) { return false; }
-
- $feed = db_escape_string($feed);
-
- if ($auth_login && $auth_pass ){
- $url_parts = array();
- preg_match("/(^[^:]*):\/\/(.*)/", $fetch_url, $url_parts);
-
- if ($url_parts[1] && $url_parts[2]) {
- $fetch_url = $url_parts[1] . "://$auth_login:$auth_pass@" . $url_parts[2];
- }
-
- }
-
- if ($override_url)
- $fetch_url = $override_url;
-
- if ($debug_enabled) {
- _debug("update_rss_feed: fetching [$fetch_url]...");
- }
-
- $obj_id = md5("FDATA:$use_simplepie:$fetch_url");
-
- if ($memcache && $obj = $memcache->get($obj_id)) {
-
- if ($debug_enabled) {
- _debug("update_rss_feed: data found in memcache.");
- }
-
- $rss = $obj;
-
- } else {
-
- if ($update_method == 3) {
- $rss = fetch_twitter_rss($link, $fetch_url, $owner_uid);
- } else if ($update_method == 1) {
-
- define('MAGPIE_CACHE_AGE', get_feed_update_interval($link, $feed) * 60);
- define('MAGPIE_CACHE_ON', !$no_cache);
- define('MAGPIE_FETCH_TIME_OUT', 60);
- define('MAGPIE_CACHE_DIR', CACHE_DIR . "/magpie");
-
- $rss = @fetch_rss($fetch_url);
- } else {
- $simplepie_cache_dir = CACHE_DIR . "/simplepie";
-
- if (!is_dir($simplepie_cache_dir)) {
- mkdir($simplepie_cache_dir);
- }
-
- $rss = new SimplePie();
- $rss->set_useragent(SELF_USER_AGENT);
- # $rss->set_timeout(10);
- $rss->set_feed_url($fetch_url);
- $rss->set_output_encoding('UTF-8');
- $rss->force_feed(true);
-
- if (SIMPLEPIE_CACHE_IMAGES && $cache_images) {
-
- if ($debug_enabled) {
- _debug("enabling image cache");
- }
-
- $rss->set_image_handler("image.php", 'i');
- }
-
- if ($debug_enabled) {
- _debug("feed update interval (sec): " .
- get_feed_update_interval($link, $feed)*60);
- }
-
- $rss->enable_cache(!$no_cache);
-
- if (!$no_cache) {
- $rss->set_cache_location($simplepie_cache_dir);
- $rss->set_cache_duration(get_feed_update_interval($link, $feed) * 60);
- }
-
- $rss->init();
- }
-
- if ($memcache && $rss) $memcache->add($obj_id, $rss, 0, 300);
- }
-
-// print_r($rss);
-
- if ($debug_enabled) {
- _debug("update_rss_feed: fetch done, parsing...");
- }
-
- $feed = db_escape_string($feed);
-
- if ($update_method == 2) {
- $fetch_ok = !$rss->error();
- } else {
- $fetch_ok = !!$rss;
- }
-
- if ($fetch_ok) {
-
- if ($debug_enabled) {
- _debug("update_rss_feed: processing feed data...");
- }
-
-// db_query($link, "BEGIN");
-
- $result = db_query($link, "SELECT title,icon_url,site_url,owner_uid
- FROM ttrss_feeds WHERE id = '$feed'");
-
- $registered_title = db_fetch_result($result, 0, "title");
- $orig_icon_url = db_fetch_result($result, 0, "icon_url");
- $orig_site_url = db_fetch_result($result, 0, "site_url");
-
- $owner_uid = db_fetch_result($result, 0, "owner_uid");
-
- if ($use_simplepie) {
- $site_url = $rss->get_link();
- } else {
- $site_url = $rss->channel["link"];
- }
-
- $site_url = rewrite_relative_url($fetch_url, $site_url);
-
- if ($debug_enabled) {
- _debug("update_rss_feed: checking favicon...");
- }
-
- check_feed_favicon($site_url, $feed, $link);
-
- if (!$registered_title || $registered_title == "[Unknown]") {
-
- if ($use_simplepie) {
- $feed_title = db_escape_string($rss->get_title());
- } else {
- $feed_title = db_escape_string($rss->channel["title"]);
- }
-
- if ($debug_enabled) {
- _debug("update_rss_feed: registering title: $feed_title");
- }
-
- db_query($link, "UPDATE ttrss_feeds SET
- title = '$feed_title' WHERE id = '$feed'");
- }
-
- // weird, weird Magpie
- if (!$use_simplepie) {
- if (!$site_url) $site_url = db_escape_string($rss->channel["link_"]);
- }
-
- if ($site_url && $orig_site_url != db_escape_string($site_url)) {
- db_query($link, "UPDATE ttrss_feeds SET
- site_url = '$site_url' WHERE id = '$feed'");
- }
-
-// print "I: " . $rss->channel["image"]["url"];
-
- if (!$use_simplepie) {
- $icon_url = db_escape_string($rss->image["url"]);
- } else {
- $icon_url = db_escape_string($rss->get_image_url());
- }
-
- $icon_url = substr($icon_url, 0, 250);
-
- if ($icon_url && $orig_icon_url != $icon_url) {
- db_query($link, "UPDATE ttrss_feeds SET icon_url = '$icon_url' WHERE id = '$feed'");
- }
-
- if ($debug_enabled) {
- _debug("update_rss_feed: loading filters...");
- }
-
- $filters = load_filters($link, $feed, $owner_uid);
-
-// if ($debug_enabled) {
-// print_r($filters);
-// }
-
- if ($use_simplepie) {
- $iterator = $rss->get_items();
- } else {
- $iterator = $rss->items;
- if (!$iterator || !is_array($iterator)) $iterator = $rss->entries;
- if (!$iterator || !is_array($iterator)) $iterator = $rss;
- }
-
- if (!is_array($iterator)) {
- /* db_query($link, "UPDATE ttrss_feeds
- SET last_error = 'Parse error: can\'t find any articles.'
- WHERE id = '$feed'"); */
-
- // clear any errors and mark feed as updated if fetched okay
- // even if it's blank
-
- if ($debug_enabled) {
- _debug("update_rss_feed: entry iterator is not an array, no articles?");
- }
-
- db_query($link, "UPDATE ttrss_feeds
- SET last_updated = NOW(), last_error = '' WHERE id = '$feed'");
-
- return; // no articles
- }
-
- if ($pubsub_state != 2 && PUBSUBHUBBUB_ENABLED) {
-
- if ($debug_enabled) _debug("update_rss_feed: checking for PUSH hub...");
-
- $feed_hub_url = false;
- if ($use_simplepie) {
- $links = $rss->get_links('hub');
-
- if ($links && is_array($links)) {
- foreach ($links as $l) {
- $feed_hub_url = $l;
- break;
- }
- }
-
- } else {
- $atom = $rss->channel['atom'];
-
- if ($atom) {
- if ($atom['link@rel'] == 'hub') {
- $feed_hub_url = $atom['link@href'];
- }
-
- if (!$feed_hub_url && $atom['link#'] > 1) {
- for ($i = 2; $i <= $atom['link#']; $i++) {
- if ($atom["link#$i@rel"] == 'hub') {
- $feed_hub_url = $atom["link#$i@href"];
- break;
- }
- }
- }
- } else {
- $feed_hub_url = $rss->channel['link_hub'];
- }
- }
-
- if ($debug_enabled) _debug("update_rss_feed: feed hub url: $feed_hub_url");
-
- if ($feed_hub_url && function_exists('curl_init') &&
- !ini_get("open_basedir")) {
-
- require_once 'lib/pubsubhubbub/subscriber.php';
-
- $callback_url = get_self_url_prefix() .
- "/public.php?op=pubsub&id=$feed";
-
- $s = new Subscriber($feed_hub_url, $callback_url);
-
- $rc = $s->subscribe($fetch_url);
-
- if ($debug_enabled)
- _debug("update_rss_feed: feed hub url found, subscribe request sent.");
-
- db_query($link, "UPDATE ttrss_feeds SET pubsub_state = 1
- WHERE id = '$feed'");
- }
- }
-
- if ($debug_enabled) {
- _debug("update_rss_feed: processing articles...");
- }
-
- foreach ($iterator as $item) {
-
- if ($_REQUEST['xdebug'] == 2) {
- print_r($item);
- }
-
- if ($use_simplepie) {
- $entry_guid = $item->get_id();
- if (!$entry_guid) $entry_guid = $item->get_link();
- if (!$entry_guid) $entry_guid = make_guid_from_title($item->get_title());
-
- } else {
-
- $entry_guid = $item["id"];
-
- if (!$entry_guid) $entry_guid = $item["guid"];
- if (!$entry_guid) $entry_guid = $item["about"];
- if (!$entry_guid) $entry_guid = $item["link"];
- if (!$entry_guid) $entry_guid = make_guid_from_title($item["title"]);
- }
-
- if ($debug_enabled) {
- _debug("update_rss_feed: guid $entry_guid");
- }
-
- if (!$entry_guid) continue;
-
- $entry_timestamp = "";
-
- if ($use_simplepie) {
- $entry_timestamp = strtotime($item->get_date());
- } else {
- $rss_2_date = $item['pubdate'];
- $rss_1_date = $item['dc']['date'];
- $atom_date = $item['issued'];
- if (!$atom_date) $atom_date = $item['updated'];
-
- if ($atom_date != "") $entry_timestamp = parse_w3cdtf($atom_date);
- if ($rss_1_date != "") $entry_timestamp = parse_w3cdtf($rss_1_date);
- if ($rss_2_date != "") $entry_timestamp = strtotime($rss_2_date);
-
- }
-
- if ($entry_timestamp == "" || $entry_timestamp == -1 || !$entry_timestamp) {
- $entry_timestamp = time();
- $no_orig_date = 'true';
- } else {
- $no_orig_date = 'false';
- }
-
- $entry_timestamp_fmt = strftime("%Y/%m/%d %H:%M:%S", $entry_timestamp);
-
- if ($debug_enabled) {
- _debug("update_rss_feed: date $entry_timestamp [$entry_timestamp_fmt]");
- }
-
- if ($use_simplepie) {
- $entry_title = $item->get_title();
- } else {
- $entry_title = trim(strip_tags($item["title"]));
- }
-
- if ($use_simplepie) {
- $entry_link = $item->get_link();
- } else {
- // strange Magpie workaround
- $entry_link = $item["link_"];
- if (!$entry_link) $entry_link = $item["link"];
- }
-
- $entry_link = rewrite_relative_url($site_url, $entry_link);
-
- if ($debug_enabled) {
- _debug("update_rss_feed: title $entry_title");
- _debug("update_rss_feed: link $entry_link");
- }
-
- if (!$entry_title) $entry_title = date("Y-m-d H:i:s", $entry_timestamp);;
-
- $entry_link = strip_tags($entry_link);
-
- if ($use_simplepie) {
- $entry_content = $item->get_content();
- if (!$entry_content) $entry_content = $item->get_description();
- } else {
- $entry_content = $item["content:escaped"];
-
- if (!$entry_content) $entry_content = $item["content:encoded"];
- if (!$entry_content) $entry_content = $item["content"]["encoded"];
- if (!$entry_content) $entry_content = $item["content"];
-
- if (is_array($entry_content)) $entry_content = $entry_content[0];
-
- // Magpie bugs are getting ridiculous
- if (trim($entry_content) == "Array") $entry_content = false;
-
- if (!$entry_content) $entry_content = $item["atom_content"];
- if (!$entry_content) $entry_content = $item["summary"];
-
- if (!$entry_content ||
- strlen($entry_content) < strlen($item["description"])) {
- $entry_content = $item["description"];
- };
-
- // WTF
- if (is_array($entry_content)) {
- $entry_content = $entry_content["encoded"];
- if (!$entry_content) $entry_content = $entry_content["escaped"];
- }
- }
-
- if ($_REQUEST["xdebug"] == 2) {
- print "update_rss_feed: content: ";
- print_r(htmlspecialchars($entry_content));
- }
-
- $entry_content_unescaped = $entry_content;
-
- if ($use_simplepie) {
- $entry_comments = strip_tags($item->data["comments"]);
- if ($item->get_author()) {
- $entry_author_item = $item->get_author();
- $entry_author = $entry_author_item->get_name();
- if (!$entry_author) $entry_author = $entry_author_item->get_email();
-
- $entry_author = db_escape_string($entry_author);
- }
- } else {
- $entry_comments = strip_tags($item["comments"]);
-
- $entry_author = db_escape_string(strip_tags($item['dc']['creator']));
-
- if ($item['author']) {
-
- if (is_array($item['author'])) {
-
- if (!$entry_author) {
- $entry_author = db_escape_string(strip_tags($item['author']['name']));
- }
-
- if (!$entry_author) {
- $entry_author = db_escape_string(strip_tags($item['author']['email']));
- }
- }
-
- if (!$entry_author) {
- $entry_author = db_escape_string(strip_tags($item['author']));
- }
- }
- }
-
- if (preg_match('/^[\t\n\r ]*$/', $entry_author)) $entry_author = '';
-
- $entry_guid = db_escape_string(strip_tags($entry_guid));
- $entry_guid = mb_substr($entry_guid, 0, 250);
-
- $result = db_query($link, "SELECT id FROM ttrss_entries
- WHERE guid = '$entry_guid'");
-
- $entry_content = db_escape_string($entry_content, false);
-
- $content_hash = "SHA1:" . sha1(strip_tags($entry_content));
-
- $entry_title = db_escape_string($entry_title);
- $entry_link = db_escape_string($entry_link);
- $entry_comments = mb_substr(db_escape_string($entry_comments), 0, 250);
- $entry_author = mb_substr($entry_author, 0, 250);
-
- if ($use_simplepie) {
- $num_comments = 0; #FIXME#
- } else {
- $num_comments = db_escape_string($item["slash"]["comments"]);
- }
-
- if (!$num_comments) $num_comments = 0;
-
- if ($debug_enabled) {
- _debug("update_rss_feed: looking for tags [1]...");
- }
-
- // parse <category> entries into tags
-
- $additional_tags = array();
-
- if ($use_simplepie) {
-
- $additional_tags_src = $item->get_categories();
-
- if (is_array($additional_tags_src)) {
- foreach ($additional_tags_src as $tobj) {
- array_push($additional_tags, $tobj->get_term());
- }
- }
-
- if ($debug_enabled) {
- _debug("update_rss_feed: category tags:");
- print_r($additional_tags);
- }
-
- } else {
-
- $t_ctr = $item['category#'];
-
- if ($t_ctr == 0) {
- $additional_tags = array();
- } else if ($t_ctr > 0) {
- $additional_tags = array($item['category']);
-
- if ($item['category@term']) {
- array_push($additional_tags, $item['category@term']);
- }
-
- for ($i = 0; $i <= $t_ctr; $i++ ) {
- if ($item["category#$i"]) {
- array_push($additional_tags, $item["category#$i"]);
- }
-
- if ($item["category#$i@term"]) {
- array_push($additional_tags, $item["category#$i@term"]);
- }
- }
- }
-
- // parse <dc:subject> elements
-
- $t_ctr = $item['dc']['subject#'];
-
- if ($t_ctr > 0) {
- array_push($additional_tags, $item['dc']['subject']);
-
- for ($i = 0; $i <= $t_ctr; $i++ ) {
- if ($item['dc']["subject#$i"]) {
- array_push($additional_tags, $item['dc']["subject#$i"]);
- }
- }
- }
- }
-
- if ($debug_enabled) {
- _debug("update_rss_feed: looking for tags [2]...");
- }
-
- /* taaaags */
- // <a href="..." rel="tag">Xorg</a>, //
-
- $entry_tags = null;
-
- preg_match_all("/<a.*?rel=['\"]tag['\"].*?\>([^<]+)<\/a>/i",
- $entry_content_unescaped, $entry_tags);
-
- $entry_tags = $entry_tags[1];
-
- $entry_tags = array_merge($entry_tags, $additional_tags);
- $entry_tags = array_unique($entry_tags);
-
- for ($i = 0; $i < count($entry_tags); $i++)
- $entry_tags[$i] = mb_strtolower($entry_tags[$i], 'utf-8');
-
- if ($debug_enabled) {
- _debug("update_rss_feed: unfiltered tags found:");
- print_r($entry_tags);
- }
-
- # sanitize content
-
- $entry_content = sanitize_article_content($entry_content);
- $entry_title = sanitize_article_content($entry_title);
-
- if ($debug_enabled) {
- _debug("update_rss_feed: done collecting data [TITLE:$entry_title]");
- }
-
- db_query($link, "BEGIN");
-
- if (db_num_rows($result) == 0) {
-
- if ($debug_enabled) {
- _debug("update_rss_feed: base guid not found");
- }
-
- // base post entry does not exist, create it
-
- $result = db_query($link,
- "INSERT INTO ttrss_entries
- (title,
- guid,
- link,
- updated,
- content,
- content_hash,
- no_orig_date,
- date_updated,
- date_entered,
- comments,
- num_comments,
- author)
- VALUES
- ('$entry_title',
- '$entry_guid',
- '$entry_link',
- '$entry_timestamp_fmt',
- '$entry_content',
- '$content_hash',
- $no_orig_date,
- NOW(),
- NOW(),
- '$entry_comments',
- '$num_comments',
- '$entry_author')");
- } else {
- // we keep encountering the entry in feeds, so we need to
- // update date_updated column so that we don't get horrible
- // dupes when the entry gets purged and reinserted again e.g.
- // in the case of SLOW SLOW OMG SLOW updating feeds
-
- $base_entry_id = db_fetch_result($result, 0, "id");
-
- db_query($link, "UPDATE ttrss_entries SET date_updated = NOW()
- WHERE id = '$base_entry_id'");
- }
-
- // now it should exist, if not - bad luck then
-
- $result = db_query($link, "SELECT
- id,content_hash,no_orig_date,title,
- ".SUBSTRING_FOR_DATE."(date_updated,1,19) as date_updated,
- ".SUBSTRING_FOR_DATE."(updated,1,19) as updated,
- num_comments
- FROM
- ttrss_entries
- WHERE guid = '$entry_guid'");
-
- $entry_ref_id = 0;
- $entry_int_id = 0;
-
- if (db_num_rows($result) == 1) {
-
- if ($debug_enabled) {
- _debug("update_rss_feed: base guid found, checking for user record");
- }
-
- // this will be used below in update handler
- $orig_content_hash = db_fetch_result($result, 0, "content_hash");
- $orig_title = db_fetch_result($result, 0, "title");
- $orig_num_comments = db_fetch_result($result, 0, "num_comments");
- $orig_date_updated = strtotime(db_fetch_result($result,
- 0, "date_updated"));
-
- $ref_id = db_fetch_result($result, 0, "id");
- $entry_ref_id = $ref_id;
-
- // check for user post link to main table
-
- // do we allow duplicate posts with same GUID in different feeds?
- if (get_pref($link, "ALLOW_DUPLICATE_POSTS", $owner_uid, false)) {
- $dupcheck_qpart = "AND (feed_id = '$feed' OR feed_id IS NULL)";
- } else {
- $dupcheck_qpart = "";
- }
-
- /* Collect article tags here so we could filter by them: */
-
- $article_filters = get_article_filters($filters, $entry_title,
- $entry_content, $entry_link, $entry_timestamp, $entry_author,
- $entry_tags);
-
- if ($debug_enabled) {
- _debug("update_rss_feed: article filters: ");
- if (count($article_filters) != 0) {
- print_r($article_filters);
- }
- }
-
- if (find_article_filter($article_filters, "filter")) {
- db_query($link, "COMMIT"); // close transaction in progress
- continue;
- }
-
- $score = calculate_article_score($article_filters);
-
- if ($debug_enabled) {
- _debug("update_rss_feed: initial score: $score");
- }
-
- $query = "SELECT ref_id, int_id FROM ttrss_user_entries WHERE
- ref_id = '$ref_id' AND owner_uid = '$owner_uid'
- $dupcheck_qpart";
-
-// if ($_REQUEST["xdebug"]) print "$query\n";
-
- $result = db_query($link, $query);
-
- // okay it doesn't exist - create user entry
- if (db_num_rows($result) == 0) {
-
- if ($debug_enabled) {
- _debug("update_rss_feed: user record not found, creating...");
- }
-
- if ($score >= -500 && !find_article_filter($article_filters, 'catchup')) {
- $unread = 'true';
- $last_read_qpart = 'NULL';
- } else {
- $unread = 'false';
- $last_read_qpart = 'NOW()';
- }
-
- if (find_article_filter($article_filters, 'mark') || $score > 1000) {
- $marked = 'true';
- } else {
- $marked = 'false';
- }
-
- if (find_article_filter($article_filters, 'publish')) {
- $published = 'true';
- } else {
- $published = 'false';
- }
-
- $result = db_query($link,
- "INSERT INTO ttrss_user_entries
- (ref_id, owner_uid, feed_id, unread, last_read, marked,
- published, score, tag_cache, label_cache, uuid)
- VALUES ('$ref_id', '$owner_uid', '$feed', $unread,
- $last_read_qpart, $marked, $published, '$score', '', '', '')");
-
- if (PUBSUBHUBBUB_HUB && $published == 'true') {
- $rss_link = get_self_url_prefix() .
- "/public.php?op=rss&id=-2&key=" .
- get_feed_access_key($link, -2, false, $owner_uid);
-
- $p = new Publisher(PUBSUBHUBBUB_HUB);
-
- $pubsub_result = $p->publish_update($rss_link);
- }
-
- $result = db_query($link,
- "SELECT int_id FROM ttrss_user_entries WHERE
- ref_id = '$ref_id' AND owner_uid = '$owner_uid' AND
- feed_id = '$feed' LIMIT 1");
-
- if (db_num_rows($result) == 1) {
- $entry_int_id = db_fetch_result($result, 0, "int_id");
- }
- } else {
- if ($debug_enabled) {
- _debug("update_rss_feed: user record FOUND");
- }
-
- $entry_ref_id = db_fetch_result($result, 0, "ref_id");
- $entry_int_id = db_fetch_result($result, 0, "int_id");
- }
-
- if ($debug_enabled) {
- _debug("update_rss_feed: RID: $entry_ref_id, IID: $entry_int_id");
- }
-
- $post_needs_update = false;
- $update_insignificant = false;
-
- if ($orig_num_comments != $num_comments) {
- $post_needs_update = true;
- $update_insignificant = true;
- }
-
- if ($content_hash != $orig_content_hash) {
- $post_needs_update = true;
- $update_insignificant = false;
- }
-
- if (db_escape_string($orig_title) != $entry_title) {
- $post_needs_update = true;
- $update_insignificant = false;
- }
-
- // if post needs update, update it and mark all user entries
- // linking to this post as updated
- if ($post_needs_update) {
-
- if (defined('DAEMON_EXTENDED_DEBUG')) {
- _debug("update_rss_feed: post $entry_guid needs update...");
- }
-
-// print "<!-- post $orig_title needs update : $post_needs_update -->";
-
- db_query($link, "UPDATE ttrss_entries
- SET title = '$entry_title', content = '$entry_content',
- content_hash = '$content_hash',
- updated = '$entry_timestamp_fmt',
- num_comments = '$num_comments'
- WHERE id = '$ref_id'");
-
- if (!$update_insignificant) {
- if ($mark_unread_on_update) {
- db_query($link, "UPDATE ttrss_user_entries
- SET last_read = null, unread = true WHERE ref_id = '$ref_id'");
- } else if ($update_on_checksum_change) {
- db_query($link, "UPDATE ttrss_user_entries
- SET last_read = null WHERE ref_id = '$ref_id'
- AND unread = false");
- }
- }
- }
- }
-
- db_query($link, "COMMIT");
-
- if ($debug_enabled) {
- _debug("update_rss_feed: assigning labels...");
- }
-
- assign_article_to_labels($link, $entry_ref_id, $article_filters,
- $owner_uid);
-
- if ($debug_enabled) {
- _debug("update_rss_feed: looking for enclosures...");
- }
-
- // enclosures
-
- $enclosures = array();
-
- if ($use_simplepie) {
- $encs = $item->get_enclosures();
-
- if (is_array($encs)) {
- foreach ($encs as $e) {
- $e_item = array(
- $e->link, $e->type, $e->length);
-
- array_push($enclosures, $e_item);
- }
- }
-
- } else {
- // <enclosure>
-
- $e_ctr = $item['enclosure#'];
-
- if ($e_ctr > 0) {
- $e_item = array($item['enclosure@url'],
- $item['enclosure@type'],
- $item['enclosure@length']);
-
- array_push($enclosures, $e_item);
-
- for ($i = 0; $i <= $e_ctr; $i++ ) {
-
- if ($item["enclosure#$i@url"]) {
- $e_item = array($item["enclosure#$i@url"],
- $item["enclosure#$i@type"],
- $item["enclosure#$i@length"]);
- array_push($enclosures, $e_item);
- }
- }
- }
-
- // <media:content>
- // can there be many of those? yes -fox
-
- $m_ctr = $item['media']['content#'];
-
- if ($m_ctr > 0) {
- $e_item = array($item['media']['content@url'],
- $item['media']['content@medium'],
- $item['media']['content@length']);
-
- array_push($enclosures, $e_item);
-
- for ($i = 0; $i <= $m_ctr; $i++ ) {
-
- if ($item["media"]["content#$i@url"]) {
- $e_item = array($item["media"]["content#$i@url"],
- $item["media"]["content#$i@medium"],
- $item["media"]["content#$i@length"]);
- array_push($enclosures, $e_item);
- }
- }
-
- }
- }
-
-
- if ($debug_enabled) {
- _debug("update_rss_feed: article enclosures:");
- print_r($enclosures);
- }
-
- db_query($link, "BEGIN");
-
- foreach ($enclosures as $enc) {
- $enc_url = db_escape_string($enc[0]);
- $enc_type = db_escape_string($enc[1]);
- $enc_dur = db_escape_string($enc[2]);
-
- $result = db_query($link, "SELECT id FROM ttrss_enclosures
- WHERE content_url = '$enc_url' AND post_id = '$entry_ref_id'");
-
- if (db_num_rows($result) == 0) {
- db_query($link, "INSERT INTO ttrss_enclosures
- (content_url, content_type, title, duration, post_id) VALUES
- ('$enc_url', '$enc_type', '', '$enc_dur', '$entry_ref_id')");
- }
- }
-
- db_query($link, "COMMIT");
-
- // check for manual tags (we have to do it here since they're loaded from filters)
-
- foreach ($article_filters as $f) {
- if ($f[0] == "tag") {
-
- $manual_tags = trim_array(explode(",", $f[1]));
-
- foreach ($manual_tags as $tag) {
- if (tag_is_valid($tag)) {
- array_push($entry_tags, $tag);
- }
- }
- }
- }
-
- // Skip boring tags
-
- $boring_tags = trim_array(explode(",", mb_strtolower(get_pref($link,
- 'BLACKLISTED_TAGS', $owner_uid, ''), 'utf-8')));
-
- $filtered_tags = array();
- $tags_to_cache = array();
-
- if ($entry_tags && is_array($entry_tags)) {
- foreach ($entry_tags as $tag) {
- if (array_search($tag, $boring_tags) === false) {
- array_push($filtered_tags, $tag);
- }
- }
- }
-
- $filtered_tags = array_unique($filtered_tags);
-
- if ($debug_enabled) {
- _debug("update_rss_feed: filtered article tags:");
- print_r($filtered_tags);
- }
-
- // Save article tags in the database
-
- if (count($filtered_tags) > 0) {
-
- db_query($link, "BEGIN");
-
- foreach ($filtered_tags as $tag) {
-
- $tag = sanitize_tag($tag);
- $tag = db_escape_string($tag);
-
- if (!tag_is_valid($tag)) continue;
-
- $result = db_query($link, "SELECT id FROM ttrss_tags
- WHERE tag_name = '$tag' AND post_int_id = '$entry_int_id' AND
- owner_uid = '$owner_uid' LIMIT 1");
-
- if ($result && db_num_rows($result) == 0) {
-
- db_query($link, "INSERT INTO ttrss_tags
- (owner_uid,tag_name,post_int_id)
- VALUES ('$owner_uid','$tag', '$entry_int_id')");
- }
-
- array_push($tags_to_cache, $tag);
- }
-
- /* update the cache */
-
- $tags_to_cache = array_unique($tags_to_cache);
-
- $tags_str = db_escape_string(join(",", $tags_to_cache));
-
- db_query($link, "UPDATE ttrss_user_entries
- SET tag_cache = '$tags_str' WHERE ref_id = '$entry_ref_id'
- AND owner_uid = $owner_uid");
-
- db_query($link, "COMMIT");
- }
-
- if ($debug_enabled) {
- _debug("update_rss_feed: article processed");
- }
- }
-
- if (!$last_updated) {
- if ($debug_enabled) {
- _debug("update_rss_feed: new feed, catching it up...");
- }
- catchup_feed($link, $feed, false, $owner_uid);
- }
-
- if ($debug_enabled) {
- _debug("purging feed...");
- }
-
- purge_feed($link, $feed, 0, $debug_enabled);
-
- db_query($link, "UPDATE ttrss_feeds
- SET last_updated = NOW(), last_error = '' WHERE id = '$feed'");
-
-// db_query($link, "COMMIT");
-
- } else {
-
- if ($use_simplepie) {
- $error_msg = mb_substr($rss->error(), 0, 250);
- } else {
- $error_msg = mb_substr(magpie_error(), 0, 250);
- }
-
- if ($debug_enabled) {
- _debug("update_rss_feed: error fetching feed: $error_msg");
- }
-
- $error_msg = db_escape_string($error_msg);
-
- db_query($link,
- "UPDATE ttrss_feeds SET last_error = '$error_msg',
- last_updated = NOW() WHERE id = '$feed'");
- }
-
- if ($use_simplepie) {
- unset($rss);
- }
-
- if ($debug_enabled) {
- _debug("update_rss_feed: done");
- }
-
- }
-
- function print_select($id, $default, $values, $attributes = "") {
- print "<select name=\"$id\" id=\"$id\" $attributes>";
- foreach ($values as $v) {
- if ($v == $default)
- $sel = "selected=\"1\"";
- else
- $sel = "";
-
- print "<option value=\"$v\" $sel>$v</option>";
- }
- print "</select>";
- }
-
- function print_select_hash($id, $default, $values, $attributes = "") {
- print "<select name=\"$id\" id='$id' $attributes>";
- foreach (array_keys($values) as $v) {
- if ($v == $default)
- $sel = 'selected="selected"';
- else
- $sel = "";
-
- print "<option $sel value=\"$v\">".$values[$v]."</option>";
- }
-
- print "</select>";
- }
-
- function get_article_filters($filters, $title, $content, $link, $timestamp, $author, $tags) {
- $matches = array();
-
- if ($filters["title"]) {
- foreach ($filters["title"] as $filter) {
- $reg_exp = $filter["reg_exp"];
- $inverse = $filter["inverse"];
- if ((!$inverse && @preg_match("/$reg_exp/i", $title)) ||
- ($inverse && !@preg_match("/$reg_exp/i", $title))) {
-
- array_push($matches, array($filter["action"], $filter["action_param"]));
- }
- }
- }
-
- if ($filters["content"]) {
- foreach ($filters["content"] as $filter) {
- $reg_exp = $filter["reg_exp"];
- $inverse = $filter["inverse"];
-
- if ((!$inverse && @preg_match("/$reg_exp/i", $content)) ||
- ($inverse && !@preg_match("/$reg_exp/i", $content))) {
-
- array_push($matches, array($filter["action"], $filter["action_param"]));
- }
- }
- }
-
- if ($filters["both"]) {
- foreach ($filters["both"] as $filter) {
- $reg_exp = $filter["reg_exp"];
- $inverse = $filter["inverse"];
-
- if ($inverse) {
- if (!@preg_match("/$reg_exp/i", $title) && !preg_match("/$reg_exp/i", $content)) {
- array_push($matches, array($filter["action"], $filter["action_param"]));
- }
- } else {
- if (@preg_match("/$reg_exp/i", $title) || preg_match("/$reg_exp/i", $content)) {
- array_push($matches, array($filter["action"], $filter["action_param"]));
- }
- }
- }
- }
-
- if ($filters["link"]) {
- $reg_exp = $filter["reg_exp"];
- foreach ($filters["link"] as $filter) {
- $reg_exp = $filter["reg_exp"];
- $inverse = $filter["inverse"];
-
- if ((!$inverse && @preg_match("/$reg_exp/i", $link)) ||
- ($inverse && !@preg_match("/$reg_exp/i", $link))) {
-
- array_push($matches, array($filter["action"], $filter["action_param"]));
- }
- }
- }
-
- if ($filters["date"]) {
- $reg_exp = $filter["reg_exp"];
- foreach ($filters["date"] as $filter) {
- $date_modifier = $filter["filter_param"];
- $inverse = $filter["inverse"];
- $check_timestamp = strtotime($filter["reg_exp"]);
-
- # no-op when timestamp doesn't parse to prevent misfires
-
- if ($check_timestamp) {
- $match_ok = false;
-
- if ($date_modifier == "before" && $timestamp < $check_timestamp ||
- $date_modifier == "after" && $timestamp > $check_timestamp) {
- $match_ok = true;
- }
-
- if ($inverse) $match_ok = !$match_ok;
-
- if ($match_ok) {
- array_push($matches, array($filter["action"], $filter["action_param"]));
- }
- }
- }
- }
-
- if ($filters["author"]) {
- foreach ($filters["author"] as $filter) {
- $reg_exp = $filter["reg_exp"];
- $inverse = $filter["inverse"];
- if ((!$inverse && @preg_match("/$reg_exp/i", $author)) ||
- ($inverse && !@preg_match("/$reg_exp/i", $author))) {
-
- array_push($matches, array($filter["action"], $filter["action_param"]));
- }
- }
- }
-
- if ($filters["tag"]) {
-
- $tag_string = join(",", $tags);
-
- foreach ($filters["tag"] as $filter) {
- $reg_exp = $filter["reg_exp"];
- $inverse = $filter["inverse"];
-
- if ((!$inverse && @preg_match("/$reg_exp/i", $tag_string)) ||
- ($inverse && !@preg_match("/$reg_exp/i", $tag_string))) {
-
- array_push($matches, array($filter["action"], $filter["action_param"]));
- }
- }
- }
-
-
- return $matches;
- }
-
- function find_article_filter($filters, $filter_name) {
- foreach ($filters as $f) {
- if ($f[0] == $filter_name) {
- return $f;
- };
- }
- return false;
- }
-
- function calculate_article_score($filters) {
- $score = 0;
-
- foreach ($filters as $f) {
- if ($f[0] == "score") {
- $score += $f[1];
- };
- }
- return $score;
- }
-
- function assign_article_to_labels($link, $id, $filters, $owner_uid) {
- foreach ($filters as $f) {
- if ($f[0] == "label") {
- label_add_article($link, $id, $f[1], $owner_uid);
- };
- }
- }
-
- 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) {
-
- if ($v == $default)
- $sel = "checked";
- else
- $sel = "";
-
- if ($v == $true_is) {
- $sel .= " value=\"1\"";
- } else {
- $sel .= " value=\"0\"";
- }
-
- print "<input class=\"noborder\" dojoType=\"dijit.form.RadioButton\"
- type=\"radio\" $sel $attributes name=\"$id\"> $v ";
-
- }
- }
-
- function initialize_user_prefs($link, $uid, $profile = false) {
-
- $uid = db_escape_string($uid);
-
- if (!$profile) {
- $profile = "NULL";
- $profile_qpart = "AND profile IS NULL";
- } else {
- $profile_qpart = "AND profile = '$profile'";
- }
-
- if (get_schema_version($link) < 63) $profile_qpart = "";
-
- db_query($link, "BEGIN");
-
- $result = db_query($link, "SELECT pref_name,def_value FROM ttrss_prefs");
-
- $u_result = db_query($link, "SELECT pref_name
- FROM ttrss_user_prefs WHERE owner_uid = '$uid' $profile_qpart");
-
- $active_prefs = array();
-
- while ($line = db_fetch_assoc($u_result)) {
- array_push($active_prefs, $line["pref_name"]);
- }
-
- while ($line = db_fetch_assoc($result)) {
- 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
- (owner_uid,pref_name,value) VALUES
- ('$uid', '".$line["pref_name"]."','".$line["def_value"]."')");
-
- } else {
- db_query($link, "INSERT INTO ttrss_user_prefs
- (owner_uid,pref_name,value, profile) VALUES
- ('$uid', '".$line["pref_name"]."','".$line["def_value"]."', $profile)");
- }
-
- }
- }
-
- db_query($link, "COMMIT");
-
- }
-
- function get_ssl_certificate_id() {
- if ($_SERVER["REDIRECT_SSL_CLIENT_M_SERIAL"]) {
- return sha1($_SERVER["REDIRECT_SSL_CLIENT_M_SERIAL"] .
- $_SERVER["REDIRECT_SSL_CLIENT_V_START"] .
- $_SERVER["REDIRECT_SSL_CLIENT_V_END"] .
- $_SERVER["REDIRECT_SSL_CLIENT_S_DN"]);
- }
- return "";
- }
-
- function get_login_by_ssl_certificate($link) {
-
- $cert_serial = db_escape_string(get_ssl_certificate_id());
-
- if ($cert_serial) {
- $result = db_query($link, "SELECT login FROM ttrss_user_prefs, ttrss_users
- WHERE pref_name = 'SSL_CERT_SERIAL' AND value = '$cert_serial' AND
- owner_uid = ttrss_users.id");
-
- if (db_num_rows($result) != 0) {
- return db_escape_string(db_fetch_result($result, 0, "login"));
- }
- }
-
- return "";
- }
-
- function get_remote_user($link) {
-
- if (defined('ALLOW_REMOTE_USER_AUTH') && ALLOW_REMOTE_USER_AUTH) {
- return db_escape_string($_SERVER["REMOTE_USER"]);
- }
-
- return db_escape_string(get_login_by_ssl_certificate($link));
- }
-
- function get_remote_fakepass($link) {
- if (get_remote_user($link))
- return "******";
- else
- return "";
- }
-
- function authenticate_user($link, $login, $password, $force_auth = false) {
-
- if (!SINGLE_USER_MODE) {
-
- $pwd_hash1 = encrypt_password($password);
- $pwd_hash2 = encrypt_password($password, $login);
- $login = db_escape_string($login);
-
- $remote_user = get_remote_user($link);
-
- if ($remote_user && $remote_user == $login && $login != "admin") {
-
- $login = $remote_user;
-
- $query = "SELECT id,login,access_level,pwd_hash
- FROM ttrss_users WHERE
- login = '$login'";
-
- if (defined('AUTO_CREATE_USER') && AUTO_CREATE_USER
- && $_SERVER["REMOTE_USER"]) {
- $result = db_query($link, $query);
-
- // First login ?
- if (db_num_rows($result) == 0) {
- $query2 = "INSERT INTO ttrss_users
- (login,access_level,last_login,created)
- VALUES ('$login', 0, null, NOW())";
- db_query($link, $query2);
- }
- }
-
- } else {
- $query = "SELECT id,login,access_level,pwd_hash
- FROM ttrss_users WHERE
- login = '$login' AND (pwd_hash = '$pwd_hash1' OR
- pwd_hash = '$pwd_hash2')";
- }
-
- $result = db_query($link, $query);
-
- if (db_num_rows($result) == 1) {
- $_SESSION["uid"] = db_fetch_result($result, 0, "id");
- $_SESSION["name"] = db_fetch_result($result, 0, "login");
- $_SESSION["access_level"] = db_fetch_result($result, 0, "access_level");
-
- db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " .
- $_SESSION["uid"]);
-
-
- // LemonLDAP can send user informations via HTTP HEADER
- if (defined('AUTO_CREATE_USER') && AUTO_CREATE_USER){
- // update user name
- $fullname = $_SERVER['HTTP_USER_NAME'] ? $_SERVER['HTTP_USER_NAME'] : $_SERVER['AUTHENTICATE_CN'];
- if ($fullname){
- $fullname = db_escape_string($fullname);
- db_query($link, "UPDATE ttrss_users SET full_name = '$fullname' WHERE id = " .
- $_SESSION["uid"]);
- }
- // update user mail
- $email = $_SERVER['HTTP_USER_MAIL'] ? $_SERVER['HTTP_USER_MAIL'] : $_SERVER['AUTHENTICATE_MAIL'];
- if ($email){
- $email = db_escape_string($email);
- db_query($link, "UPDATE ttrss_users SET email = '$email' WHERE id = " .
- $_SESSION["uid"]);
- }
- }
-
- $_SESSION["ip_address"] = $_SERVER["REMOTE_ADDR"];
- $_SESSION["pwd_hash"] = db_fetch_result($result, 0, "pwd_hash");
-
- $_SESSION["last_version_check"] = time();
-
- initialize_user_prefs($link, $_SESSION["uid"]);
-
- return true;
- }
-
- return false;
-
- } else {
-
- $_SESSION["uid"] = 1;
- $_SESSION["name"] = "admin";
-
- $_SESSION["ip_address"] = $_SERVER["REMOTE_ADDR"];
-
- initialize_user_prefs($link, $_SESSION["uid"]);
-
- return true;
- }
- }
-
- function make_password($length = 8) {
-
- $password = "";
- $possible = "0123456789abcdfghjkmnpqrstvwxyzABCDFGHJKMNPQRSTVWXYZ";
-
- $i = 0;
-
- while ($i < $length) {
- $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
-
- if (!strstr($password, $char)) {
- $password .= $char;
- $i++;
- }
- }
- return $password;
- }
-
- // this is called after user is created to initialize default feeds, labels
- // or whatever else
-
- // user preferences are checked on every login, not here
-
- function initialize_user($link, $uid) {
-
- db_query($link, "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)
- values ('$uid', 'Tiny Tiny RSS: Forum',
- 'http://tt-rss.org/forum/rss.php')");
- }
-
- function logout_user() {
- session_destroy();
- if (isset($_COOKIE[session_name()])) {
- setcookie(session_name(), '', time()-42000, '/');
- }
- }
-
- 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 login_sequence($link, $mobile = false) {
- $_SESSION["prefs_cache"] = array();
-
- if (!SINGLE_USER_MODE) {
-
- $login_action = $_POST["login_action"];
-
- # try to authenticate user if called from login form
- if ($login_action == "do_login") {
- $login = db_escape_string($_POST["login"]);
- $password = $_POST["password"];
- $remember_me = $_POST["remember_me"];
-
- if (authenticate_user($link, $login, $password)) {
- $_POST["password"] = "";
-
- $_SESSION["language"] = $_POST["language"];
- $_SESSION["ref_schema_version"] = get_schema_version($link, true);
- $_SESSION["bw_limit"] = !!$_POST["bw_limit"];
-
- if ($_POST["profile"]) {
-
- $profile = db_escape_string($_POST["profile"]);
-
- $result = db_query($link, "SELECT id FROM ttrss_settings_profiles
- WHERE id = '$profile' AND owner_uid = " . $_SESSION["uid"]);
-
- if (db_num_rows($result) != 0) {
- $_SESSION["profile"] = $profile;
- $_SESSION["prefs_cache"] = array();
- }
- }
-
- if ($_REQUEST['return']) {
- header("Location: " . $_REQUEST['return']);
- } else {
- header("Location: " . $_SERVER["REQUEST_URI"]);
- }
-
- exit;
-
- return;
- } else {
- $_SESSION["login_error_msg"] = __("Incorrect username or password");
- }
- }
-
- if (!$_SESSION["uid"] || !validate_session($link)) {
-
- if (get_remote_user($link) && AUTO_LOGIN) {
- authenticate_user($link, get_remote_user($link), null);
- $_SESSION["ref_schema_version"] = get_schema_version($link, true);
- } else {
- render_login_form($link, $mobile);
- //header("Location: login.php");
- exit;
- }
- } else {
- /* bump login timestamp */
- db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " .
- $_SESSION["uid"]);
-
- if ($_SESSION["language"] && SESSION_COOKIE_LIFETIME > 0) {
- setcookie("ttrss_lang", $_SESSION["language"],
- time() + SESSION_COOKIE_LIFETIME);
- }
-
- // try to remove possible duplicates from feed counter cache
-// ccache_cleanup($link, $_SESSION["uid"]);
- }
-
- } else {
- return authenticate_user($link, "admin", null);
- }
- }
-
- function truncate_string($str, $max_len, $suffix = '…') {
- if (mb_strlen($str, "utf-8") > $max_len - 3) {
- return mb_substr($str, 0, $max_len, "utf-8") . $suffix;
- } else {
- return $str;
- }
- }
-
- function theme_image($link, $filename) {
- if ($link) {
- $theme_path = get_user_theme_path($link);
-
- if ($theme_path && is_file($theme_path.$filename)) {
- return $theme_path.$filename;
- } else {
- return $filename;
- }
- } else {
- return $filename;
- }
- }
-
- function get_user_theme($link) {
-
- if (get_schema_version($link) >= 63 && $_SESSION["uid"]) {
- $theme_name = get_pref($link, "_THEME_ID");
- if (is_dir("themes/$theme_name")) {
- return $theme_name;
- } else {
- return '';
- }
- } else {
- return '';
- }
-
- }
-
- function get_user_theme_path($link) {
- $theme_path = '';
-
- if (get_schema_version($link) >= 63 && $_SESSION["uid"]) {
- $theme_name = get_pref($link, "_THEME_ID");
-
- if ($theme_name && is_dir("themes/$theme_name")) {
- $theme_path = "themes/$theme_name/";
- } else {
- $theme_name = '';
- }
- } else {
- $theme_path = '';
- }
-
- if ($theme_path) {
- if (is_file("$theme_path/theme.ini")) {
- $ini = parse_ini_file("$theme_path/theme.ini", true);
- if ($ini['theme']['version'] >= THEME_VERSION_REQUIRED) {
- return $theme_path;
- }
- }
- }
- return '';
- }
-
- function get_user_theme_options($link) {
- $t = get_user_theme_path($link);
-
- if ($t) {
- if (is_file("$t/theme.ini")) {
- $ini = parse_ini_file("$t/theme.ini", true);
- if ($ini['theme']['version']) {
- return $ini['theme']['options'];
- }
- }
- }
- return '';
- }
-
- function print_theme_includes($link) {
-
- $t = get_user_theme_path($link);
- $time = time();
-
- if ($t) {
- print "<link rel=\"stylesheet\" type=\"text/css\"
- href=\"$t/theme.css?$time \">";
- if (file_exists("$t/theme.js")) {
- print "<script type=\"text/javascript\" src=\"$t/theme.js?$time\">
- </script>";
- }
- }
- }
-
- function get_all_themes() {
- $themes = glob("themes/*");
-
- asort($themes);
-
- $rv = array();
-
- foreach ($themes as $t) {
- if (is_file("$t/theme.ini")) {
- $ini = parse_ini_file("$t/theme.ini", true);
- if ($ini['theme']['version'] >= THEME_VERSION_REQUIRED &&
- !$ini['theme']['disabled']) {
- $entry = array();
- $entry["path"] = $t;
- $entry["base"] = basename($t);
- $entry["name"] = $ini['theme']['name'];
- $entry["version"] = $ini['theme']['version'];
- $entry["author"] = $ini['theme']['author'];
- $entry["options"] = $ini['theme']['options'];
- array_push($rv, $entry);
- }
- }
- }
-
- return $rv;
- }
-
- function convert_timestamp($timestamp, $source_tz, $dest_tz) {
-
- try {
- $source_tz = new DateTimeZone($source_tz);
- } catch (Exception $e) {
- $source_tz = new DateTimeZone('UTC');
- }
-
- try {
- $dest_tz = new DateTimeZone($dest_tz);
- } catch (Exception $e) {
- $dest_tz = new DateTimeZone('UTC');
- }
-
- $dt = new DateTime(date('Y-m-d H:i:s', $timestamp), $source_tz);
- return $dt->format('U') + $dest_tz->getOffset($dt);
- }
-
- function make_local_datetime($link, $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;
-
- # We store date in UTC internally
- $dt = new DateTime($timestamp, $utc_tz);
-
- if ($tz_offset == -1) {
-
- $user_tz_string = get_pref($link, 'USER_TIMEZONE', $owner_uid);
-
- try {
- $user_tz = new DateTimeZone($user_tz_string);
- } catch (Exception $e) {
- $user_tz = $utc_tz;
- }
-
- $tz_offset = $user_tz->getOffset($dt);
- }
-
- $user_timestamp = $dt->format('U') + $tz_offset;
-
- if (!$no_smart_dt) {
- return smart_date_time($link, $user_timestamp,
- $tz_offset, $owner_uid);
- } else {
- if ($long)
- $format = get_pref($link, 'LONG_DATE_FORMAT', $owner_uid);
- else
- $format = get_pref($link, 'SHORT_DATE_FORMAT', $owner_uid);
-
- return date($format, $user_timestamp);
- }
- }
-
- function smart_date_time($link, $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);
- return date($format, $timestamp);
- } else {
- $format = get_pref($link, 'LONG_DATE_FORMAT', $owner_uid);
- return date($format, $timestamp);
- }
- }
-
- function sql_bool_to_bool($s) {
- if ($s == "t" || $s == "1" || $s == "true") {
- return true;
- } else {
- return false;
- }
- }
-
- function bool_to_sql_bool($s) {
- if ($s) {
- return "true";
- } else {
- return "false";
- }
- }
-
- // 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) {
- global $schema_version;
-
- if (!$schema_version) {
- $result = db_query($link, "SELECT schema_version FROM ttrss_version");
- $version = db_fetch_result($result, 0, "schema_version");
- $schema_version = $version;
- return $version;
- } else {
- return $schema_version;
- }
- }
-
- function sanity_check($link) {
- require_once 'errors.php';
-
- $error_code = 0;
- $schema_version = get_schema_version($link, true);
-
- if ($schema_version != SCHEMA_VERSION) {
- $error_code = 5;
- }
-
- if (DB_TYPE == "mysql") {
- $result = db_query($link, "SELECT true", false);
- if (db_num_rows($result) != 1) {
- $error_code = 10;
- }
- }
-
- if (db_escape_string("testTEST") != "testTEST") {
- $error_code = 12;
- }
-
- return array("code" => $error_code, "message" => $ERRORS[$error_code]);
- }
-
- function file_is_locked($filename) {
- if (function_exists('flock')) {
- $fp = @fopen(LOCK_DIRECTORY . "/$filename", "r");
- if ($fp) {
- if (flock($fp, LOCK_EX | LOCK_NB)) {
- flock($fp, LOCK_UN);
- fclose($fp);
- return false;
- }
- fclose($fp);
- return true;
- } else {
- return false;
- }
- }
- return true; // consider the file always locked and skip the test
- }
-
- function make_lockfile($filename) {
- $fp = fopen(LOCK_DIRECTORY . "/$filename", "w");
-
- if (flock($fp, LOCK_EX | LOCK_NB)) {
- if (function_exists('posix_getpid')) {
- fwrite($fp, posix_getpid() . "\n");
- }
- return $fp;
- } else {
- return false;
- }
- }
-
- function make_stampfile($filename) {
- $fp = fopen(LOCK_DIRECTORY . "/$filename", "w");
-
- if (flock($fp, LOCK_EX | LOCK_NB)) {
- fwrite($fp, time() . "\n");
- flock($fp, LOCK_UN);
- fclose($fp);
- return true;
- } else {
- return false;
- }
- }
-
- function sql_random_function() {
- if (DB_TYPE == "mysql") {
- return "RAND()";
- } else {
- return "RANDOM()";
- }
- }
-
- function catchup_feed($link, $feed, $cat_view, $owner_uid = false) {
-
- if (!$owner_uid) $owner_uid = $_SESSION['uid'];
-
- //if (preg_match("/^-?[0-9][0-9]*$/", $feed) != false) {
-
- if (is_numeric($feed)) {
- if ($cat_view) {
-
- if ($feed >= 0) {
-
- if ($feed > 0) {
- $cat_qpart = "cat_id = '$feed'";
- } else {
- $cat_qpart = "cat_id IS NULL";
- }
-
- $tmp_result = db_query($link, "SELECT id
- FROM ttrss_feeds WHERE $cat_qpart AND owner_uid = $owner_uid");
-
- while ($tmp_line = db_fetch_assoc($tmp_result)) {
-
- $tmp_feed = $tmp_line["id"];
-
- db_query($link, "UPDATE ttrss_user_entries
- SET unread = false,last_read = NOW()
- WHERE feed_id = '$tmp_feed' AND owner_uid = $owner_uid");
- }
- } else if ($feed == -2) {
-
- db_query($link, "UPDATE ttrss_user_entries
- SET unread = false,last_read = NOW() WHERE (SELECT COUNT(*)
- FROM ttrss_user_labels2 WHERE article_id = ref_id) > 0
- AND unread = true 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 owner_uid = $owner_uid");
-
- } else if ($feed < 0 && $feed > -10) { // special, like starred
-
- if ($feed == -1) {
- db_query($link, "UPDATE ttrss_user_entries
- SET unread = false,last_read = NOW()
- WHERE marked = true AND owner_uid = $owner_uid");
- }
-
- if ($feed == -2) {
- db_query($link, "UPDATE ttrss_user_entries
- SET unread = false,last_read = NOW()
- WHERE published = true AND owner_uid = $owner_uid");
- }
-
- if ($feed == -3) {
-
- $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE");
-
- if (DB_TYPE == "pgsql") {
- $match_part = "updated > NOW() - INTERVAL '$intl hour' ";
- } else {
- $match_part = "updated > 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);
- }
-
- if ($feed == -4) {
- db_query($link, "UPDATE ttrss_user_entries
- SET unread = false,last_read = NOW()
- WHERE owner_uid = $owner_uid");
- }
-
- } else if ($feed < -10) { // label
-
- $label_id = -$feed - 11;
-
- 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 owner_uid = '$owner_uid' AND ref_id = article_id");
-
- }
-
- ccache_update($link, $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");
-
- while ($line = db_fetch_assoc($result)) {
- db_query($link, "UPDATE ttrss_user_entries SET
- unread = false, last_read = NOW()
- WHERE int_id = " . $line["post_int_id"]);
- }
- db_query($link, "COMMIT");
- }
- }
-
- function getAllCounters($link, $omode = "flc", $active_feed = false) {
-
- if (!$omode) $omode = "flc";
-
- $data = getGlobalCounters($link);
-
- $data = array_merge($data, getVirtCounters($link));
-
- if (strchr($omode, "l")) $data = array_merge($data, getLabelCounters($link));
- if (strchr($omode, "f")) $data = array_merge($data, getFeedCounters($link, $active_feed));
- if (strchr($omode, "t")) $data = array_merge($data, getTagCounters($link));
- if (strchr($omode, "c")) $data = array_merge($data, getCategoryCounters($link));
-
- return $data;
- }
-
- function getCategoryCounters($link) {
- $ret_arr = array();
-
- /* Labels category */
-
- $cv = array("id" => -2, "kind" => "cat",
- "counter" => getCategoryUnread($link, -2));
-
- array_push($ret_arr, $cv);
-
- $age_qpart = getMaxAgeSubquery();
-
- $result = db_query($link, "SELECT id AS cat_id, value AS unread
- FROM ttrss_feed_categories, ttrss_cat_counters_cache
- WHERE ttrss_cat_counters_cache.feed_id = id AND
- ttrss_feed_categories.owner_uid = " . $_SESSION["uid"]);
-
- while ($line = db_fetch_assoc($result)) {
- $line["cat_id"] = (int) $line["cat_id"];
-
- $cv = array("id" => $line["cat_id"], "kind" => "cat",
- "counter" => $line["unread"]);
-
- array_push($ret_arr, $cv);
- }
-
- /* Special case: NULL category doesn't actually exist in the DB */
-
- $cv = array("id" => 0, "kind" => "cat",
- "counter" => ccache_find($link, 0, $_SESSION["uid"], true));
-
- array_push($ret_arr, $cv);
-
- return $ret_arr;
- }
-
- function getCategoryUnread($link, $cat, $owner_uid = false) {
-
- if (!$owner_uid) $owner_uid = $_SESSION["uid"];
-
- if ($cat >= 0) {
-
- if ($cat != 0) {
- $cat_query = "cat_id = '$cat'";
- } else {
- $cat_query = "cat_id IS NULL";
- }
-
- $age_qpart = getMaxAgeSubquery();
-
- $result = db_query($link, "SELECT id FROM ttrss_feeds WHERE $cat_query
- AND owner_uid = " . $owner_uid);
-
- $cat_feeds = array();
- while ($line = db_fetch_assoc($result)) {
- array_push($cat_feeds, "feed_id = " . $line["id"]);
- }
-
- if (count($cat_feeds) == 0) return 0;
-
- $match_part = implode(" OR ", $cat_feeds);
-
- $result = db_query($link, "SELECT COUNT(int_id) AS unread
- FROM ttrss_user_entries,ttrss_entries
- WHERE unread = true AND ($match_part) AND id = ref_id
- AND $age_qpart AND owner_uid = " . $owner_uid);
-
- $unread = 0;
-
- # this needs to be rewritten
- while ($line = db_fetch_assoc($result)) {
- $unread += $line["unread"];
- }
-
- return $unread;
- } else if ($cat == -1) {
- return getFeedUnread($link, -1) + getFeedUnread($link, -2) + getFeedUnread($link, -3) + getFeedUnread($link, 0);
- } else if ($cat == -2) {
-
- $result = db_query($link, "
- SELECT COUNT(unread) AS unread FROM
- ttrss_user_entries, ttrss_labels2, ttrss_user_labels2, ttrss_feeds
- WHERE label_id = ttrss_labels2.id AND article_id = ref_id AND
- ttrss_labels2.owner_uid = '$owner_uid'
- AND unread = true AND feed_id = ttrss_feeds.id
- AND ttrss_user_entries.owner_uid = '$owner_uid'");
-
- $unread = db_fetch_result($result, 0, "unread");
-
- return $unread;
-
- }
- }
-
- function getMaxAgeSubquery($days = COUNTERS_MAX_AGE) {
- if (DB_TYPE == "pgsql") {
- return "ttrss_entries.date_updated >
- NOW() - INTERVAL '$days days'";
- } else {
- return "ttrss_entries.date_updated >
- DATE_SUB(NOW(), INTERVAL $days DAY)";
- }
- }
-
- function getFeedUnread($link, $feed, $is_cat = false) {
- return getFeedArticles($link, $feed, $is_cat, true, $_SESSION["uid"]);
- }
-
- function getLabelUnread($link, $label_id, $owner_uid = false) {
- if (!$owner_uid) $owner_uid = $_SESSION["uid"];
-
- $result = db_query($link, "
- SELECT COUNT(unread) AS unread FROM
- ttrss_user_entries, ttrss_labels2, ttrss_user_labels2, ttrss_feeds
- WHERE label_id = ttrss_labels2.id AND article_id = ref_id AND
- ttrss_labels2.owner_uid = '$owner_uid' AND ttrss_labels2.id = '$label_id'
- AND unread = true AND feed_id = ttrss_feeds.id
- AND ttrss_user_entries.owner_uid = '$owner_uid'");
-
- if (db_num_rows($result) != 0) {
- return db_fetch_result($result, 0, "unread");
- } else {
- return 0;
- }
- }
-
- function getFeedArticles($link, $feed, $is_cat = false, $unread_only = false,
- $owner_uid = false) {
-
- $n_feed = (int) $feed;
-
- if (!$owner_uid) $owner_uid = $_SESSION["uid"];
-
- if ($unread_only) {
- $unread_qpart = "unread = true";
- } else {
- $unread_qpart = "true";
- }
-
- $age_qpart = getMaxAgeSubquery();
-
- if ($is_cat) {
- return getCategoryUnread($link, $n_feed, $owner_uid);
- } if ($feed != "0" && $n_feed == 0) {
-
- $feed = db_escape_string($feed);
-
- $result = db_query($link, "SELECT SUM((SELECT COUNT(int_id)
- FROM ttrss_user_entries,ttrss_entries WHERE int_id = post_int_id
- AND ref_id = id AND $age_qpart
- AND $unread_qpart)) AS count FROM ttrss_tags
- WHERE owner_uid = $owner_uid AND tag_name = '$feed'");
- return db_fetch_result($result, 0, "count");
-
- } else if ($n_feed == -1) {
- $match_part = "marked = true";
- } else if ($n_feed == -2) {
- $match_part = "published = true";
- } else if ($n_feed == -3) {
- $match_part = "unread = true AND score >= 0";
-
- $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE", $owner_uid);
-
- if (DB_TYPE == "pgsql") {
- $match_part .= " AND updated > NOW() - INTERVAL '$intl hour' ";
- } else {
- $match_part .= " AND updated > DATE_SUB(NOW(), INTERVAL $intl HOUR) ";
- }
- } else if ($n_feed == -4) {
- $match_part = "true";
- } else if ($n_feed >= 0) {
-
- if ($n_feed != 0) {
- $match_part = "feed_id = '$n_feed'";
- } else {
- $match_part = "feed_id IS NULL";
- }
-
- } else if ($feed < -10) {
-
- $label_id = -$feed - 11;
-
- return getLabelUnread($link, $label_id, $owner_uid);
-
- }
-
- if ($match_part) {
-
- if ($n_feed != 0) {
- $from_qpart = "ttrss_user_entries,ttrss_feeds,ttrss_entries";
- $feeds_qpart = "ttrss_user_entries.feed_id = ttrss_feeds.id AND";
- } else {
- $from_qpart = "ttrss_user_entries,ttrss_entries";
- $feeds_qpart = '';
- }
-
- $query = "SELECT count(int_id) AS unread
- FROM $from_qpart WHERE
- ttrss_user_entries.ref_id = ttrss_entries.id AND
- $age_qpart AND
- $feeds_qpart
- $unread_qpart AND ($match_part) AND ttrss_user_entries.owner_uid = $owner_uid";
-
- $result = db_query($link, $query);
-
- } else {
-
- $result = db_query($link, "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 $age_qpart AND
- ttrss_tags.owner_uid = " . $owner_uid);
- }
-
- $unread = db_fetch_result($result, 0, "unread");
-
- return $unread;
- }
-
- function getGlobalUnread($link, $user_id = false) {
-
- if (!$user_id) {
- $user_id = $_SESSION["uid"];
- }
-
- $result = db_query($link, "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");
-
- return $c_id;
- }
-
- function getGlobalCounters($link, $global_unread = -1) {
- $ret_arr = array();
-
- if ($global_unread == -1) {
- $global_unread = getGlobalUnread($link);
- }
-
- $cv = array("id" => "global-unread",
- "counter" => $global_unread);
-
- array_push($ret_arr, $cv);
-
- $result = db_query($link, "SELECT COUNT(id) AS fn FROM
- ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]);
-
- $subscribed_feeds = db_fetch_result($result, 0, "fn");
-
- $cv = array("id" => "subscribed-feeds",
- "counter" => $subscribed_feeds);
-
- array_push($ret_arr, $cv);
-
- return $ret_arr;
- }
-
- function getTagCounters($link) {
-
- $ret_arr = array();
-
- $age_qpart = getMaxAgeSubquery();
-
- $result = db_query($link, "SELECT tag_name,SUM((SELECT COUNT(int_id)
- FROM ttrss_user_entries,ttrss_entries WHERE int_id = post_int_id
- AND ref_id = id AND $age_qpart
- AND unread = true)) AS count FROM ttrss_tags
- WHERE owner_uid = ".$_SESSION['uid']." GROUP BY tag_name
- ORDER BY count DESC LIMIT 55");
-
- $tags = array();
-
- while ($line = db_fetch_assoc($result)) {
- $tags[$line["tag_name"]] += $line["count"];
- }
-
- foreach (array_keys($tags) as $tag) {
- $unread = $tags[$tag];
- $tag = htmlspecialchars($tag);
-
- $cv = array("id" => $tag,
- "kind" => "tag",
- "counter" => $unread);
-
- array_push($ret_arr, $cv);
- }
-
- return $ret_arr;
- }
-
- function getVirtCounters($link) {
-
- $ret_arr = array();
-
- for ($i = 0; $i >= -4; $i--) {
-
- $count = getFeedUnread($link, $i);
-
- $cv = array("id" => $i,
- "counter" => $count);
-
-// if (get_pref($link, 'EXTENDED_FEEDLIST'))
-// $cv["xmsg"] = getFeedArticles($link, $i)." ".__("total");
-
- array_push($ret_arr, $cv);
- }
-
- return $ret_arr;
- }
-
- function getLabelCounters($link, $descriptions = false) {
-
- $ret_arr = array();
-
- $age_qpart = getMaxAgeSubquery();
-
- $owner_uid = $_SESSION["uid"];
-
- $result = db_query($link, "SELECT id, caption FROM ttrss_labels2
- WHERE owner_uid = '$owner_uid'");
-
- while ($line = db_fetch_assoc($result)) {
-
- $id = -$line["id"] - 11;
-
- $label_name = $line["caption"];
- $count = getFeedUnread($link, $id);
-
- $cv = array("id" => $id,
- "counter" => $count);
-
- if ($descriptions)
- $cv["description"] = $label_name;
-
-// if (get_pref($link, 'EXTENDED_FEEDLIST'))
-// $cv["xmsg"] = getFeedArticles($link, $id)." ".__("total");
-
- array_push($ret_arr, $cv);
- }
-
- return $ret_arr;
- }
-
- function getFeedCounters($link, $active_feed = false) {
-
- $ret_arr = array();
-
- $age_qpart = getMaxAgeSubquery();
-
- $query = "SELECT ttrss_feeds.id,
- ttrss_feeds.title,
- ".SUBSTRING_FOR_DATE."(ttrss_feeds.last_updated,1,19) AS last_updated,
- last_error, value AS count
- FROM ttrss_feeds, ttrss_counters_cache
- WHERE ttrss_feeds.owner_uid = ".$_SESSION["uid"]."
- AND ttrss_counters_cache.feed_id = id";
-
- $result = db_query($link, $query);
- $fctrs_modified = false;
-
- while ($line = db_fetch_assoc($result)) {
-
- $id = $line["id"];
- $count = $line["count"];
- $last_error = htmlspecialchars($line["last_error"]);
-
- $last_updated = make_local_datetime($link, $line['last_updated'], false);
-
- $has_img = feed_has_icon($id);
-
- if (date('Y') - date('Y', strtotime($line['last_updated'])) > 2)
- $last_updated = '';
-
- $cv = array("id" => $id,
- "updated" => $last_updated,
- "counter" => $count,
- "has_img" => (int) $has_img);
-
- if ($last_error)
- $cv["error"] = $last_error;
-
-// if (get_pref($link, 'EXTENDED_FEEDLIST'))
-// $cv["xmsg"] = getFeedArticles($link, $id)." ".__("total");
-
- if ($active_feed && $id == $active_feed)
- $cv["title"] = truncate_string($line["title"], 30);
-
- array_push($ret_arr, $cv);
-
- }
-
- return $ret_arr;
- }
-
- function get_pgsql_version($link) {
- $result = db_query($link, "SELECT version() AS version");
- $version = explode(" ", db_fetch_result($result, 0, "version"));
- return $version[1];
- }
-
- /**
- * Subscribes the user to the given feed
- *
- * @param resource $link Database connection
- * @param string $url Feed URL to subscribe to
- * @param integer $cat_id Category ID the feed shall be added to
- * @param string $auth_login (optional) Feed username
- * @param string $auth_pass (optional) Feed password
- *
- * @return integer Status code:
- * 0 - OK, Feed already exists
- * 1 - OK, Feed added
- * 2 - Invalid URL
- * 3 - URL content is HTML, no feeds available
- * 4 - URL content is HTML which contains multiple feeds.
- * Here you should call extractfeedurls in rpc-backend
- * to get all possible feeds.
- * 5 - Couldn't download the URL content.
- */
- function subscribe_to_feed($link, $url, $cat_id = 0,
- $auth_login = '', $auth_pass = '') {
-
- $url = fix_url($url);
-
- if (!$url || !validate_feed_url($url)) return 2;
-
- $update_method = 0;
-
- $result = db_query($link, "SELECT twitter_oauth FROM ttrss_users
- WHERE id = ".$_SESSION['uid']);
-
- $has_oauth = db_fetch_result($result, 0, 'twitter_oauth');
-
- if (!$has_oauth || strpos($url, '://api.twitter.com') === false) {
- if (!fetch_file_contents($url, false, $auth_login, $auth_pass)) return 5;
-
- if (url_is_html($url, $auth_login, $auth_pass)) {
- $feedUrls = get_feeds_from_html($url, $auth_login, $auth_pass);
- if (count($feedUrls) == 0) {
- return 3;
- } else if (count($feedUrls) > 1) {
- return 4;
- }
- //use feed url as new URL
- $url = key($feedUrls);
- }
-
- } else {
- if (!fetch_twitter_rss($link, $url, $_SESSION['uid']))
- return 5;
-
- $update_method = 3;
- }
- if ($cat_id == "0" || !$cat_id) {
- $cat_qpart = "NULL";
- } else {
- $cat_qpart = "'$cat_id'";
- }
-
- $result = db_query($link,
- "SELECT id FROM ttrss_feeds
- WHERE feed_url = '$url' AND owner_uid = ".$_SESSION["uid"]);
-
- if (db_num_rows($result) == 0) {
- $result = db_query($link,
- "INSERT INTO ttrss_feeds
- (owner_uid,feed_url,title,cat_id, auth_login,auth_pass,update_method)
- VALUES ('".$_SESSION["uid"]."', '$url',
- '[Unknown]', $cat_qpart, '$auth_login', '$auth_pass', '$update_method')");
-
- $result = db_query($link,
- "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);
- }
-
- return 1;
- } else {
- return 0;
- }
- }
-
- function print_feed_select($link, $id, $default_id = "",
- $attributes = "", $include_all_feeds = true) {
-
- print "<select id=\"$id\" name=\"$id\" $attributes>";
- if ($include_all_feeds) {
- print "<option value=\"0\">".__('All feeds')."</option>";
- }
-
- $result = db_query($link, "SELECT id,title FROM ttrss_feeds
- WHERE owner_uid = ".$_SESSION["uid"]." ORDER BY title");
-
- if (db_num_rows($result) > 0 && $include_all_feeds) {
- print "<option disabled>--------</option>";
- }
-
- while ($line = db_fetch_assoc($result)) {
- if ($line["id"] == $default_id) {
- $is_selected = "selected=\"1\"";
- } else {
- $is_selected = "";
- }
-
- $title = truncate_string(htmlspecialchars($line["title"]), 40);
-
- printf("<option $is_selected value='%d'>%s</option>",
- $line["id"], $title);
- }
-
- print "</select>";
- }
-
- function print_feed_cat_select($link, $id, $default_id = "",
- $attributes = "", $include_all_cats = true) {
-
- print "<select id=\"$id\" name=\"$id\" default=\"$default_id\" onchange=\"catSelectOnChange(this)\" $attributes>";
-
- if ($include_all_cats) {
- print "<option value=\"0\">".__('Uncategorized')."</option>";
- }
-
- $result = db_query($link, "SELECT id,title FROM ttrss_feed_categories
- WHERE owner_uid = ".$_SESSION["uid"]." ORDER BY title");
-
- if (db_num_rows($result) > 0 && $include_all_cats) {
- print "<option disabled=\"1\">--------</option>";
- }
-
- while ($line = db_fetch_assoc($result)) {
- if ($line["id"] == $default_id) {
- $is_selected = "selected=\"1\"";
- } else {
- $is_selected = "";
- }
-
- if ($line["title"])
- printf("<option $is_selected value='%d'>%s</option>",
- $line["id"], htmlspecialchars($line["title"]));
- }
-
-# print "<option value=\"ADD_CAT\">" .__("Add category...") . "</option>";
-
- print "</select>";
- }
-
- function checkbox_to_sql_bool($val) {
- return ($val == "on") ? "true" : "false";
- }
-
- function getFeedCatTitle($link, $id) {
- if ($id == -1) {
- return __("Special");
- } else if ($id < -10) {
- return __("Labels");
- } else if ($id > 0) {
- $result = db_query($link, "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) {
- return db_fetch_result($result, 0, "title");
- } else {
- return __("Uncategorized");
- }
- } else {
- return "getFeedCatTitle($id) failed";
- }
-
- }
-
- function getFeedIcon($id) {
- switch ($id) {
- case 0:
- return "images/archive.png";
- break;
- case -1:
- return "images/mark_set.png";
- break;
- case -2:
- return "images/pub_set.png";
- break;
- case -3:
- return "images/fresh.png";
- break;
- case -4:
- return "images/tag.png";
- break;
- default:
- if ($id < -10) {
- return "images/label.png";
- } else {
- if (file_exists(ICONS_DIR . "/$id.ico"))
- return ICONS_URL . "/$id.ico";
- }
- break;
- }
- }
-
- function getFeedTitle($link, $id) {
- if ($id == -1) {
- return __("Starred articles");
- } else if ($id == -2) {
- return __("Published articles");
- } else if ($id == -3) {
- return __("Fresh articles");
- } else if ($id == -4) {
- return __("All articles");
- } else if ($id === 0 || $id === "0") {
- return __("Archived articles");
- } else if ($id < -10) {
- $label_id = -$id - 11;
- $result = db_query($link, "SELECT caption FROM ttrss_labels2 WHERE id = '$label_id'");
- if (db_num_rows($result) == 1) {
- return db_fetch_result($result, 0, "caption");
- } else {
- return "Unknown label ($label_id)";
- }
-
- } else if (is_numeric($id) && $id > 0) {
- $result = db_query($link, "SELECT title FROM ttrss_feeds WHERE id = '$id'");
- if (db_num_rows($result) == 1) {
- return db_fetch_result($result, 0, "title");
- } else {
- return "Unknown feed ($id)";
- }
- } else {
- return $id;
- }
- }
-
- function make_init_params($link) {
- $params = array();
-
- $params["theme"] = get_user_theme($link);
- $params["theme_options"] = get_user_theme_options($link);
-
- $params["sign_progress"] = theme_image($link, "images/indicator_white.gif");
- $params["sign_progress_tiny"] = theme_image($link, "images/indicator_tiny.gif");
- $params["sign_excl"] = theme_image($link, "images/sign_excl.png");
- $params["sign_info"] = theme_image($link, "images/sign_info.png");
-
- foreach (array("ON_CATCHUP_SHOW_NEXT_FEED", "HIDE_READ_FEEDS",
- "ENABLE_FEED_CATS", "FEEDS_SORT_BY_UNREAD", "CONFIRM_FEED_CATCHUP",
- "CDM_AUTO_CATCHUP", "FRESH_ARTICLE_MAX_AGE", "DEFAULT_ARTICLE_LIMIT",
- "HIDE_READ_SHOWS_SPECIAL", "COMBINED_DISPLAY_MODE") as $param) {
-
- $params[strtolower($param)] = (int) get_pref($link, $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["bw_limit"] = (int) $_SESSION["bw_limit"];
-
- $result = db_query($link, "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");
- $num_feeds = db_fetch_result($result, 0, "nf");
-
- $params["max_feed_id"] = (int) $max_feed_id;
- $params["num_feeds"] = (int) $num_feeds;
-
- $params["collapsed_feedlist"] = (int) get_pref($link, "_COLLAPSED_FEEDLIST");
-
- return $params;
- }
-
- function make_runtime_info($link) {
- $data = array();
-
- $result = db_query($link, "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");
- $num_feeds = db_fetch_result($result, 0, "nf");
-
- $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');
-
- if (file_exists(LOCK_DIRECTORY . "/update_daemon.lock")) {
-
- $data['daemon_is_running'] = (int) file_is_locked("update_daemon.lock");
-
- if (time() - $_SESSION["daemon_stamp_check"] > 30) {
-
- $stamp = (int) @file_get_contents(LOCK_DIRECTORY . "/update_daemon.stamp");
-
- if ($stamp) {
- $stamp_delta = time() - $stamp;
-
- if ($stamp_delta > 1800) {
- $stamp_check = 0;
- } else {
- $stamp_check = 1;
- $_SESSION["daemon_stamp_check"] = time();
- }
-
- $data['daemon_stamp_ok'] = $stamp_check;
-
- $stamp_fmt = date("Y.m.d, G:i", $stamp);
-
- $data['daemon_stamp'] = $stamp_fmt;
- }
- }
- }
-
- if ($_SESSION["last_version_check"] + 86400 + rand(-1000, 1000) < time()) {
- $new_version_details = @check_for_update($link);
-
- $data['new_version_available'] = (int) ($new_version_details != false);
-
- $_SESSION["last_version_check"] = time();
- }
-
- return $data;
- }
-
- function search_to_sql($link, $search, $match_on) {
-
- $search_query_part = "";
-
- $keywords = explode(" ", $search);
- $query_keywords = array();
-
- foreach ($keywords as $k) {
- if (strpos($k, "-") === 0) {
- $k = substr($k, 1);
- $not = "NOT";
- } else {
- $not = "";
- }
-
- $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]) {
-
- if ($commandpair[1] == "true")
- array_push($query_keywords, "($not (published = true))");
- else
- array_push($query_keywords, "($not (published = false))");
-
- } else 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'));
-
- //$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%'))");
- }
- }
-
- $search_query_part = implode("AND", $query_keywords);
-
- return $search_query_part;
- }
-
-
- 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) {
-
- if (!$owner_uid) $owner_uid = $_SESSION["uid"];
-
- $ext_tables_part = "";
-
- if ($search) {
-
- if (SPHINX_ENABLED) {
- $ids = join(",", @sphinx_search($search, 0, 500));
-
- if ($ids)
- $search_query_part = "ref_id IN ($ids) AND ";
- else
- $search_query_part = "ref_id = -1 AND ";
-
- } else {
- $search_query_part = search_to_sql($link, $search, $match_on);
- $search_query_part .= " AND ";
- }
-
- } else {
- $search_query_part = "";
- }
-
- if ($filter) {
- $filter_query_part = filter_to_sql($filter);
- } else {
- $filter_query_part = "";
- }
-
- if ($since_id) {
- $since_id_part = "ttrss_entries.id > $since_id AND ";
- } else {
- $since_id_part = "";
- }
-
- $view_query_part = "";
-
- if ($view_mode == "adaptive" || $view_query_part == "noscores") {
- if ($search) {
- $view_query_part = " ";
- } else if ($feed != -1) {
- $unread = getFeedUnread($link, $feed, $cat_view);
- if ($unread > 0) {
- $view_query_part = " unread = true AND ";
- }
- }
- }
-
- if ($view_mode == "marked") {
- $view_query_part = " marked = true AND ";
- }
-
- if ($view_mode == "published") {
- $view_query_part = " published = true AND ";
- }
-
- if ($view_mode == "unread") {
- $view_query_part = " unread = true AND ";
- }
-
- if ($view_mode == "updated") {
- $view_query_part = " (last_read is null and unread = false) AND ";
- }
-
- if ($limit > 0) {
- $limit_query_part = "LIMIT " . $limit;
- }
-
- $vfeed_query_part = "";
-
- // override query strategy and enable feed display when searching globally
- if ($search && $search_mode == "all_feeds") {
- $query_strategy_part = "ttrss_entries.id > 0";
- $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
- /* tags */
- } else if (preg_match("/^-?[0-9][0-9]*$/", $feed) == false) {
- $query_strategy_part = "ttrss_entries.id > 0";
- $vfeed_query_part = "(SELECT title FROM ttrss_feeds WHERE
- id = feed_id) as feed_title,";
- } else if ($feed > 0 && $search && $search_mode == "this_cat") {
-
- $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
-
- $tmp_result = false;
-
- if ($cat_view) {
- $tmp_result = db_query($link, "SELECT id
- FROM ttrss_feeds WHERE cat_id = '$feed'");
- } else {
- $tmp_result = db_query($link, "SELECT id
- FROM ttrss_feeds WHERE cat_id = (SELECT cat_id FROM ttrss_feeds
- WHERE id = '$feed') AND id != '$feed'");
- }
-
- $cat_siblings = array();
-
- if (db_num_rows($tmp_result) > 0) {
- while ($p = db_fetch_assoc($tmp_result)) {
- array_push($cat_siblings, "feed_id = " . $p["id"]);
- }
-
- $query_strategy_part = sprintf("(feed_id = %d OR %s)",
- $feed, implode(" OR ", $cat_siblings));
-
- } else {
- $query_strategy_part = "ttrss_entries.id > 0";
- }
-
- } else if ($feed > 0) {
-
- if ($cat_view) {
-
- if ($feed > 0) {
- $query_strategy_part = "cat_id = '$feed'";
- } else {
- $query_strategy_part = "cat_id IS NULL";
- }
-
- $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
-
- } else {
- $query_strategy_part = "feed_id = '$feed'";
- }
- } else if ($feed == 0 && !$cat_view) { // archive virtual feed
- $query_strategy_part = "feed_id IS NULL";
- } else if ($feed == 0 && $cat_view) { // uncategorized
- $query_strategy_part = "cat_id IS NULL";
- $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
- } else if ($feed == -1) { // starred virtual feed
- $query_strategy_part = "marked = true";
- $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
- } else if ($feed == -2) { // published virtual feed OR labels category
-
- if (!$cat_view) {
- $query_strategy_part = "published = true";
- $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
- } else {
- $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
-
- $ext_tables_part = ",ttrss_labels2,ttrss_user_labels2";
-
- $query_strategy_part = "ttrss_labels2.id = ttrss_user_labels2.label_id AND
- ttrss_user_labels2.article_id = ref_id";
-
- }
-
- } 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);
-
- if (DB_TYPE == "pgsql") {
- $query_strategy_part .= " AND updated > NOW() - INTERVAL '$intl hour' ";
- } else {
- $query_strategy_part .= " AND updated > DATE_SUB(NOW(), INTERVAL $intl HOUR) ";
- }
-
- $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
- } else if ($feed == -4) { // all articles virtual feed
- $query_strategy_part = "true";
- $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
- } else if ($feed <= -10) { // labels
- $label_id = -$feed - 11;
-
- $query_strategy_part = "label_id = '$label_id' AND
- ttrss_labels2.id = ttrss_user_labels2.label_id AND
- ttrss_user_labels2.article_id = ref_id";
-
- $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
- $ext_tables_part = ",ttrss_labels2,ttrss_user_labels2";
-
- } else {
- $query_strategy_part = "id > 0"; // dumb
- }
-
- 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";
- }
-
- if ($view_mode != "noscores") {
- $order_by = "score DESC, $order_by";
- }
-
- if ($override_order) {
- $order_by = $override_order;
- }
-
- $feed_title = "";
-
- if ($search) {
- $feed_title = "Search results";
- } else {
- if ($cat_view) {
- $feed_title = getCategoryTitle($link, $feed);
- } else {
- if (is_numeric($feed) && $feed > 0) {
- $result = db_query($link, "SELECT title,site_url,last_error
- 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");
- } else {
- $feed_title = getFeedTitle($link, $feed);
- }
- }
- }
-
- $content_query_part = "content as content_preview,";
-
- if (preg_match("/^-?[0-9][0-9]*$/", $feed) != false) {
-
- if ($feed >= 0) {
- $feed_kind = "Feeds";
- } else {
- $feed_kind = "Labels";
- }
-
- if ($limit_query_part) {
- $offset_query_part = "OFFSET $offset";
- }
-
- if ($vfeed_query_part && get_pref($link, 'VFEED_GROUP_BY_FEED', $owner_uid)) {
- if (!$override_order) {
- $order_by = "ttrss_feeds.title, $order_by";
- }
- }
-
- if ($feed != "0") {
- $from_qpart = "ttrss_entries,ttrss_user_entries,ttrss_feeds$ext_tables_part";
- $feed_check_qpart = "ttrss_user_entries.feed_id = ttrss_feeds.id AND";
-
- } else {
- $from_qpart = "ttrss_entries,ttrss_user_entries$ext_tables_part
- LEFT JOIN ttrss_feeds ON (feed_id = ttrss_feeds.id)";
- }
-
- $query = "SELECT DISTINCT
- date_entered,
- guid,
- ttrss_entries.id,ttrss_entries.title,
- updated,
- label_cache,
- tag_cache,
- always_display_enclosures,
- site_url,
- note,
- num_comments,
- comments,
- int_id,
- unread,feed_id,marked,published,link,last_read,orig_feed_id,
- ".SUBSTRING_FOR_DATE."(last_read,1,19) as last_read_noms,
- $vfeed_query_part
- $content_query_part
- ".SUBSTRING_FOR_DATE."(updated,1,19) as updated_noms,
- author,score
- FROM
- $from_qpart
- WHERE
- $feed_check_qpart
- ttrss_user_entries.ref_id = ttrss_entries.id AND
- ttrss_user_entries.owner_uid = '$owner_uid' AND
- $search_query_part
- $filter_query_part
- $view_query_part
- $since_id_part
- $query_strategy_part ORDER BY $order_by
- $limit_query_part $offset_query_part";
-
- if ($_REQUEST["debug"]) print $query;
-
- $result = db_query($link, $query);
-
- } else {
- // browsing by tag
-
- $select_qpart = "SELECT DISTINCT " .
- "date_entered," .
- "guid," .
- "note," .
- "ttrss_entries.id as id," .
- "title," .
- "updated," .
- "unread," .
- "feed_id," .
- "orig_feed_id," .
- "site_url," .
- "always_display_enclosures, ".
- "marked," .
- "num_comments, " .
- "comments, " .
- "tag_cache," .
- "label_cache," .
- "link," .
- "last_read," .
- SUBSTRING_FOR_DATE . "(last_read,1,19) as last_read_noms," .
- $since_id_part .
- $vfeed_query_part .
- $content_query_part .
- SUBSTRING_FOR_DATE . "(updated,1,19) as updated_noms," .
- "score ";
-
- $feed_kind = "Tags";
- $all_tags = explode(",", $feed);
- if ($search_mode == 'any') {
- $tag_sql = "tag_name in (" . implode(", ", array_map("db_quote", $all_tags)) . ")";
- $from_qpart = " FROM ttrss_entries,ttrss_user_entries,ttrss_tags ";
- $where_qpart = " WHERE " .
- "ref_id = ttrss_entries.id AND " .
- "ttrss_user_entries.owner_uid = $owner_uid AND " .
- "post_int_id = int_id AND $tag_sql AND " .
- $view_query_part .
- $search_query_part .
- $query_strategy_part . " ORDER BY $order_by " .
- $limit_query_part;
-
- } else {
- $i = 1;
- $sub_selects = array();
- $sub_ands = array();
- foreach ($all_tags as $term) {
- array_push($sub_selects, "(SELECT post_int_id from ttrss_tags WHERE tag_name = " . db_quote($term) . " AND owner_uid = $owner_uid) as A$i");
- $i++;
- }
- if ($i > 2) {
- $x = 1;
- $y = 2;
- do {
- array_push($sub_ands, "A$x.post_int_id = A$y.post_int_id");
- $x++;
- $y++;
- } while ($y < $i);
- }
- array_push($sub_ands, "A1.post_int_id = ttrss_user_entries.int_id and ttrss_user_entries.owner_uid = $owner_uid");
- array_push($sub_ands, "ttrss_user_entries.ref_id = ttrss_entries.id");
- $from_qpart = " FROM " . implode(", ", $sub_selects) . ", ttrss_user_entries, ttrss_entries";
- $where_qpart = " WHERE " . implode(" AND ", $sub_ands);
- }
- // error_log("TAG SQL: " . $tag_sql);
- // $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);
- }
-
- return array($result, $feed_title, $feed_site_url, $last_error);
-
- }
-
- function generate_syndicated_feed($link, $owner_uid, $feed, $is_cat,
- $limit, $search, $search_mode, $match_on, $view_mode = false) {
-
- require_once "lib/MiniTemplator.class.php";
-
- $note_style = "background-color : #fff7d5;
- border-width : 1px; ".
- "padding : 5px; border-style : dashed; border-color : #e7d796;".
- "margin-bottom : 1em; color : #9a8c59;";
-
- if (!$limit) $limit = 30;
-
- if (get_pref($link, "SORT_HEADLINES_BY_FEED_DATE", $owner_uid)) {
- $date_sort_field = "updated";
- } else {
- $date_sort_field = "date_entered";
- }
-
- $qfh_ret = queryFeedHeadlines($link, $feed,
- $limit, $view_mode, $is_cat, $search, $search_mode,
- $match_on, "$date_sort_field DESC", 0, $owner_uid);
-
- $result = $qfh_ret[0];
- $feed_title = htmlspecialchars($qfh_ret[1]);
- $feed_site_url = $qfh_ret[2];
- $last_error = $qfh_ret[3];
-
- $feed_self_url = get_self_url_prefix() .
- "/public.php?op=rss&id=-2&key=" .
- get_feed_access_key($link, -2, false);
-
- if (!$feed_site_url) $feed_site_url = get_self_url_prefix();
-
- $tpl = new MiniTemplator;
-
- $tpl->readTemplateFromFile("templates/generated_feed.txt");
-
- $tpl->setVariable('FEED_TITLE', $feed_title);
- $tpl->setVariable('VERSION', VERSION);
- $tpl->setVariable('FEED_URL', htmlspecialchars($feed_self_url));
-
- if (PUBSUBHUBBUB_HUB && $feed == -2) {
- $tpl->setVariable('HUB_URL', htmlspecialchars(PUBSUBHUBBUB_HUB));
- $tpl->addBlock('feed_hub');
- }
-
- $tpl->setVariable('SELF_URL', htmlspecialchars(get_self_url_prefix()));
-
- while ($line = db_fetch_assoc($result)) {
- $tpl->setVariable('ARTICLE_ID', htmlspecialchars($line['link']));
- $tpl->setVariable('ARTICLE_LINK', htmlspecialchars($line['link']));
- $tpl->setVariable('ARTICLE_TITLE', htmlspecialchars($line['title']));
- $tpl->setVariable('ARTICLE_EXCERPT',
- truncate_string(strip_tags($line["content_preview"]), 100, '...'));
-
- $content = sanitize_rss($link, $line["content_preview"], false, $owner_uid);
-
- if ($line['note']) {
- $content = "<div style=\"$note_style\">Article note: " . $line['note'] . "</div>" .
- $content;
- }
-
- $tpl->setVariable('ARTICLE_CONTENT', $content);
-
- $tpl->setVariable('ARTICLE_UPDATED', date('c', strtotime($line["updated"])));
- $tpl->setVariable('ARTICLE_AUTHOR', htmlspecialchars($line['author']));
-
- $tags = get_article_tags($link, $line["id"], $owner_uid);
-
- foreach ($tags as $tag) {
- $tpl->setVariable('ARTICLE_CATEGORY', htmlspecialchars($tag));
- $tpl->addBlock('category');
- }
-
- $enclosures = get_article_enclosures($link, $line["id"]);
-
- foreach ($enclosures as $e) {
- $type = htmlspecialchars($e['content_type']);
- $url = htmlspecialchars($e['content_url']);
- $length = $e['duration'];
-
- $tpl->setVariable('ARTICLE_ENCLOSURE_URL', $url);
- $tpl->setVariable('ARTICLE_ENCLOSURE_TYPE', $type);
- $tpl->setVariable('ARTICLE_ENCLOSURE_LENGTH', $length);
-
- $tpl->addBlock('enclosure');
- }
-
- $tpl->addBlock('entry');
- }
-
- $tmp = "";
-
- $tpl->addBlock('feed');
- $tpl->generateOutputToString($tmp);
-
- print $tmp;
- }
-
- function getCategoryTitle($link, $cat_id) {
-
- if ($cat_id == -1) {
- return __("Special");
- } else if ($cat_id == -2) {
- return __("Labels");
- } else {
-
- $result = db_query($link, "SELECT title FROM ttrss_feed_categories WHERE
- id = '$cat_id'");
-
- if (db_num_rows($result) == 1) {
- return db_fetch_result($result, 0, "title");
- } else {
- return "Uncategorized";
- }
- }
- }
-
- function sanitize_rss($link, $str, $force_strip_tags = false, $owner = false, $site_url = false) {
- global $purifier;
-
- if (!$owner) $owner = $_SESSION["uid"];
-
- $res = trim($str); if (!$res) return '';
-
- // create global Purifier object if needed
- if (!$purifier) {
- require_once 'lib/htmlpurifier/library/HTMLPurifier.auto.php';
-
- $config = HTMLPurifier_Config::createDefault();
-
- $allowed = "p,a[href],i,em,b,strong,code,pre,blockquote,br,img[src|alt|title],ul,ol,li,h1,h2,h3,h4,s,object[classid|type|id|name|width|height|codebase],param[name|value],table,tr,td";
-
- $config->set('HTML.SafeObject', true);
- @$config->set('HTML', 'Allowed', $allowed);
- $config->set('Output.FlashCompat', true);
- $config->set('Attr.EnableID', true);
- if (!defined('MOBILE_VERSION')) {
- @$config->set('Cache', 'SerializerPath', CACHE_DIR . "/htmlpurifier");
- } else {
- @$config->set('Cache', 'SerializerPath', "../" . CACHE_DIR . "/htmlpurifier");
- }
-
- $purifier = new HTMLPurifier($config);
- }
-
- $res = $purifier->purify($res);
-
- if (get_pref($link, "STRIP_IMAGES", $owner)) {
- $res = preg_replace('/<img[^>]+>/is', '', $res);
- }
-
- if (strpos($res, "href=") === false)
- $res = rewrite_urls($res);
-
- $charset_hack = '<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- </head>';
-
- $res = trim($res); if (!$res) return '';
-
- libxml_use_internal_errors(true);
-
- $doc = new DOMDocument();
- $doc->loadHTML($charset_hack . $res);
- $xpath = new DOMXPath($doc);
-
- $entries = $xpath->query('(//a[@href]|//img[@src])');
- $br_inserted = 0;
-
- foreach ($entries as $entry) {
-
- if ($site_url) {
-
- if ($entry->hasAttribute('href'))
- $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 (strtolower($entry->nodeName) == "a") {
- $entry->setAttribute("target", "_blank");
- }
-
- if (strtolower($entry->nodeName) == "img" && !$br_inserted) {
- $br = $doc->createElement("br");
-
- if ($entry->parentNode->nextSibling) {
- $entry->parentNode->insertBefore($br, $entry->nextSibling);
- $br_inserted = 1;
- }
-
- }
- }
-
- $node = $doc->getElementsByTagName('body')->item(0);
-
- return $doc->saveXML($node);
- }
-
- /**
- * Send by mail a digest of last articles.
- *
- * @param mixed $link The database connection.
- * @param integer $limit The maximum number of articles by digest.
- * @return boolean Return false if digests are not enabled.
- */
- function send_headlines_digests($link, $limit = 100) {
-
- require_once 'lib/phpmailer/class.phpmailer.php';
-
- if (!DIGEST_ENABLE) return false;
-
- $user_limit = DIGEST_EMAIL_LIMIT;
- $days = 1;
-
- print "Sending digests, batch of max $user_limit users, days = $days, headline limit = $limit\n\n";
-
- if (DB_TYPE == "pgsql") {
- $interval_query = "last_digest_sent < NOW() - INTERVAL '$days days'";
- } else if (DB_TYPE == "mysql") {
- $interval_query = "last_digest_sent < DATE_SUB(NOW(), INTERVAL $days DAY)";
- }
-
- $result = db_query($link, "SELECT id,email FROM ttrss_users
- WHERE email != '' AND (last_digest_sent IS NULL OR $interval_query)");
-
- while ($line = db_fetch_assoc($result)) {
-
- if (get_pref($link, 'DIGEST_ENABLE', $line['id'], false)) {
- print "Sending digest for UID:" . $line['id'] . " - " . $line["email"] . " ... ";
-
- $do_catchup = get_pref($link, 'DIGEST_CATCHUP', $line['id'], false);
-
- $tuple = prepare_headlines_digest($link, $line["id"], $days, $limit);
- $digest = $tuple[0];
- $headlines_count = $tuple[1];
- $affected_ids = $tuple[2];
- $digest_text = $tuple[3];
-
- if ($headlines_count > 0) {
-
- $mail = new PHPMailer();
-
- $mail->PluginDir = "lib/phpmailer/";
- $mail->SetLanguage("en", "lib/phpmailer/language/");
-
- $mail->CharSet = "UTF-8";
-
- $mail->From = DIGEST_FROM_ADDRESS;
- $mail->FromName = DIGEST_FROM_NAME;
- $mail->AddAddress($line["email"], $line["login"]);
-
- if (DIGEST_SMTP_HOST) {
- $mail->Host = DIGEST_SMTP_HOST;
- $mail->Mailer = "smtp";
- $mail->SMTPAuth = DIGEST_SMTP_LOGIN != '';
- $mail->Username = DIGEST_SMTP_LOGIN;
- $mail->Password = DIGEST_SMTP_PASSWORD;
- }
-
- $mail->IsHTML(true);
- $mail->Subject = DIGEST_SUBJECT;
- $mail->Body = $digest;
- $mail->AltBody = $digest_text;
-
- $rc = $mail->Send();
-
- if (!$rc) print "ERROR: " . $mail->ErrorInfo;
-
- print "RC=$rc\n";
-
- if ($rc && $do_catchup) {
- print "Marking affected articles as read...\n";
- catchupArticlesById($link, $affected_ids, 0, $line["id"]);
- }
- } else {
- print "No headlines\n";
- }
-
- db_query($link, "UPDATE ttrss_users SET last_digest_sent = NOW()
- WHERE id = " . $line["id"]);
- }
- }
-
- print "All done.\n";
-
- }
-
- function prepare_headlines_digest($link, $user_id, $days = 1, $limit = 100) {
-
- require_once "lib/MiniTemplator.class.php";
-
- $tpl = new MiniTemplator;
- $tpl_t = new MiniTemplator;
-
- $tpl->readTemplateFromFile("templates/digest_template_html.txt");
- $tpl_t->readTemplateFromFile("templates/digest_template.txt");
-
- $tpl->setVariable('CUR_DATE', date('Y/m/d'));
- $tpl->setVariable('CUR_TIME', date('G:i'));
-
- $tpl_t->setVariable('CUR_DATE', date('Y/m/d'));
- $tpl_t->setVariable('CUR_TIME', date('G:i'));
-
- $affected_ids = array();
-
- if (DB_TYPE == "pgsql") {
- $interval_query = "ttrss_entries.date_updated > NOW() - INTERVAL '$days days'";
- } else if (DB_TYPE == "mysql") {
- $interval_query = "ttrss_entries.date_updated > DATE_SUB(NOW(), INTERVAL $days DAY)";
- }
-
- $result = db_query($link, "SELECT ttrss_entries.title,
- ttrss_feeds.title AS feed_title,
- date_updated,
- ttrss_user_entries.ref_id,
- link,
- SUBSTRING(content, 1, 120) AS excerpt,
- ".SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated
- FROM
- ttrss_user_entries,ttrss_entries,ttrss_feeds
- WHERE
- ref_id = ttrss_entries.id AND feed_id = ttrss_feeds.id
- AND include_in_digest = true
- AND $interval_query
- AND ttrss_user_entries.owner_uid = $user_id
- AND unread = true
- ORDER BY ttrss_feeds.title, date_updated DESC
- LIMIT $limit");
-
- $cur_feed_title = "";
-
- $headlines_count = db_num_rows($result);
-
- $headlines = array();
-
- while ($line = db_fetch_assoc($result)) {
- array_push($headlines, $line);
- }
-
- for ($i = 0; $i < sizeof($headlines); $i++) {
-
- $line = $headlines[$i];
-
- array_push($affected_ids, $line["ref_id"]);
-
- $updated = make_local_datetime($link, $line['last_updated'], false,
- $user_id);
-
- $tpl->setVariable('FEED_TITLE', $line["feed_title"]);
- $tpl->setVariable('ARTICLE_TITLE', $line["title"]);
- $tpl->setVariable('ARTICLE_LINK', $line["link"]);
- $tpl->setVariable('ARTICLE_UPDATED', $updated);
- $tpl->setVariable('ARTICLE_EXCERPT',
- truncate_string(strip_tags($line["excerpt"]), 100));
-
- $tpl->addBlock('article');
-
- $tpl_t->setVariable('FEED_TITLE', $line["feed_title"]);
- $tpl_t->setVariable('ARTICLE_TITLE', $line["title"]);
- $tpl_t->setVariable('ARTICLE_LINK', $line["link"]);
- $tpl_t->setVariable('ARTICLE_UPDATED', $updated);
-// $tpl_t->setVariable('ARTICLE_EXCERPT',
-// truncate_string(strip_tags($line["excerpt"]), 100));
-
- $tpl_t->addBlock('article');
-
- if ($headlines[$i]['feed_title'] != $headlines[$i+1]['feed_title']) {
- $tpl->addBlock('feed');
- $tpl_t->addBlock('feed');
- }
-
- }
-
- $tpl->addBlock('digest');
- $tpl->generateOutputToString($tmp);
-
- $tpl_t->addBlock('digest');
- $tpl_t->generateOutputToString($tmp_t);
-
- return array($tmp, $headlines_count, $affected_ids, $tmp_t);
- }
-
- 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_data = @fetch_file_contents($version_url);
-
- if ($version_data) {
- $version_data = json_decode($version_data, true);
- if ($version_data && $version_data['version']) {
-
- if (version_compare(VERSION, $version_data['version']) == -1) {
- return $version_data;
- }
- }
- }
- }
- return false;
- }
-
- function markArticlesById($link, $ids, $cmode) {
-
- $tmp_ids = array();
-
- foreach ($ids as $id) {
- array_push($tmp_ids, "ref_id = '$id'");
- }
-
- $ids_qpart = join(" OR ", $tmp_ids);
-
- if ($cmode == 0) {
- db_query($link, "UPDATE ttrss_user_entries SET
- marked = false,last_read = NOW()
- WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]);
- } else if ($cmode == 1) {
- db_query($link, "UPDATE ttrss_user_entries SET
- marked = true
- WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]);
- } else {
- db_query($link, "UPDATE ttrss_user_entries SET
- marked = NOT marked,last_read = NOW()
- WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]);
- }
- }
-
- function publishArticlesById($link, $ids, $cmode) {
-
- $tmp_ids = array();
-
- foreach ($ids as $id) {
- array_push($tmp_ids, "ref_id = '$id'");
- }
-
- $ids_qpart = join(" OR ", $tmp_ids);
-
- if ($cmode == 0) {
- db_query($link, "UPDATE ttrss_user_entries SET
- published = false,last_read = NOW()
- WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]);
- } else if ($cmode == 1) {
- db_query($link, "UPDATE ttrss_user_entries SET
- published = true
- WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]);
- } else {
- db_query($link, "UPDATE ttrss_user_entries SET
- published = NOT published,last_read = NOW()
- WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]);
- }
-
- if (PUBSUBHUBBUB_HUB) {
- $rss_link = get_self_url_prefix() .
- "/public.php?op=rss&id=-2&key=" .
- get_feed_access_key($link, -2, false);
-
- $p = new Publisher(PUBSUBHUBBUB_HUB);
-
- $pubsub_result = $p->publish_update($rss_link);
- }
- }
-
- function catchupArticlesById($link, $ids, $cmode, $owner_uid = false) {
-
- if (!$owner_uid) $owner_uid = $_SESSION["uid"];
- if (count($ids) == 0) return;
-
- $tmp_ids = array();
-
- foreach ($ids as $id) {
- array_push($tmp_ids, "ref_id = '$id'");
- }
-
- $ids_qpart = join(" OR ", $tmp_ids);
-
- if ($cmode == 0) {
- db_query($link, "UPDATE ttrss_user_entries SET
- unread = false,last_read = NOW()
- WHERE ($ids_qpart) AND owner_uid = $owner_uid");
- } else if ($cmode == 1) {
- db_query($link, "UPDATE ttrss_user_entries SET
- unread = true
- WHERE ($ids_qpart) AND owner_uid = $owner_uid");
- } else {
- db_query($link, "UPDATE ttrss_user_entries SET
- unread = NOT unread,last_read = NOW()
- WHERE ($ids_qpart) AND owner_uid = $owner_uid");
- }
-
- /* update ccache */
-
- $result = db_query($link, "SELECT DISTINCT feed_id FROM ttrss_user_entries
- WHERE ($ids_qpart) AND owner_uid = $owner_uid");
-
- while ($line = db_fetch_assoc($result)) {
- ccache_update($link, $line["feed_id"], $owner_uid);
- }
- }
-
- function catchupArticleById($link, $id, $cmode) {
-
- if ($cmode == 0) {
- db_query($link, "UPDATE ttrss_user_entries SET
- unread = false,last_read = NOW()
- WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
- } else if ($cmode == 1) {
- db_query($link, "UPDATE ttrss_user_entries SET
- unread = true
- WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
- } else {
- db_query($link, "UPDATE ttrss_user_entries SET
- unread = NOT unread,last_read = NOW()
- WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
- }
-
- $feed_id = getArticleFeed($link, $id);
- ccache_update($link, $feed_id, $_SESSION["uid"]);
- }
-
- function make_guid_from_title($title) {
- return preg_replace("/[ \"\',.:;]/", "-",
- mb_strtolower(strip_tags($title), 'utf-8'));
- }
-
- function format_headline_subtoolbar($link, $feed_site_url, $feed_title,
- $feed_id, $is_cat, $search, $match_on,
- $search_mode, $view_mode, $error) {
-
- $page_prev_link = "viewFeedGoPage(-1)";
- $page_next_link = "viewFeedGoPage(1)";
- $page_first_link = "viewFeedGoPage(0)";
-
- $catchup_page_link = "catchupPage()";
- $catchup_feed_link = "catchupCurrentFeed()";
- $catchup_sel_link = "catchupSelection()";
-
- $archive_sel_link = "archiveSelection()";
- $delete_sel_link = "deleteSelection()";
-
- $sel_all_link = "selectArticles('all')";
- $sel_unread_link = "selectArticles('unread')";
- $sel_none_link = "selectArticles('none')";
- $sel_inv_link = "selectArticles('invert')";
-
- $tog_unread_link = "selectionToggleUnread()";
- $tog_marked_link = "selectionToggleMarked()";
- $tog_published_link = "selectionTogglePublished()";
-
- $reply = "<div id=\"subtoolbar_main\">";
-
- $reply .= __('Select:')."
- <a href=\"#\" onclick=\"$sel_all_link\">".__('All')."</a>,
- <a href=\"#\" onclick=\"$sel_unread_link\">".__('Unread')."</a>,
- <a href=\"#\" onclick=\"$sel_inv_link\">".__('Invert')."</a>,
- <a href=\"#\" onclick=\"$sel_none_link\">".__('None')."</a></li>";
-
- $reply .= " ";
-
- $reply .= "<select dojoType=\"dijit.form.Select\"
- onchange=\"headlineActionsChange(this)\">";
- $reply .= "<option value=\"false\">".__('Actions...')."</option>";
-
- $reply .= "<option value=\"0\" disabled=\"1\">".__('Selection toggle:')."</option>";
-
- $reply .= "<option value=\"$tog_unread_link\">".__('Unread')."</option>
- <option value=\"$tog_marked_link\">".__('Starred')."</option>
- <option value=\"$tog_published_link\">".__('Published')."</option>";
-
- $reply .= "<option value=\"0\" disabled=\"1\">".__('Selection:')."</option>";
-
- $reply .= "<option value=\"$catchup_sel_link\">".__('Mark as read')."</option>";
-
- if ($feed_id != "0") {
- $reply .= "<option value=\"$archive_sel_link\">".__('Archive')."</option>";
- } else {
- $reply .= "<option value=\"$archive_sel_link\">".__('Move back')."</option>";
- $reply .= "<option value=\"$delete_sel_link\">".__('Delete')."</option>";
-
- }
-
- $reply .= "<option value=\"emailArticle(false)\">".__('Forward by email').
- "</option>";
-
- if ($is_cat) $cat_q = "&is_cat=$is_cat";
-
- if ($search) {
- $search_q = "&q=$search&m=$match_on&smode=$search_mode";
- } else {
- $search_q = "";
- }
-
- $rss_link = htmlspecialchars(get_self_url_prefix() .
- "/public.php?op=rss&id=$feed_id$cat_q$search_q");
-
- $reply .= "<option value=\"0\" disabled=\"1\">".__('Feed:')."</option>";
-
- $reply .= "<option value=\"catchupPage()\">".__('Mark as read')."</option>";
-
- $reply .= "<option value=\"displayDlg('generatedFeed', '$feed_id:$is_cat:$rss_link')\">".__('View as RSS')."</option>";
-
- $reply .= "</select>";
-
- $reply .= "</div>";
-
- $reply .= "<div id=\"subtoolbar_ftitle\">";
-
- if ($feed_site_url) {
- $target = "target=\"_blank\"";
- $reply .= "<a title=\"".__("Visit the website")."\" $target href=\"$feed_site_url\">".
- truncate_string($feed_title,30)."</a>";
-
- if ($error) {
- $reply .= " (<span class=\"error\" title=\"$error\">Error</span>)";
- }
-
- } else {
- if ($feed_id < -10) {
- $label_id = -11-$feed_id;
-
- $result = db_query($link, "SELECT fg_color, bg_color
- FROM ttrss_labels2 WHERE id = '$label_id' AND owner_uid = " .
- $_SESSION["uid"]);
-
- if (db_num_rows($result) != 0) {
- $fg_color = db_fetch_result($result, 0, "fg_color");
- $bg_color = db_fetch_result($result, 0, "bg_color");
-
- $reply .= "<span style=\"background : $bg_color; color : $fg_color\" >";
- $reply .= $feed_title;
- $reply .= "</span>";
- } else {
- $reply .= $feed_title;
- }
-
- } else {
- $reply .= $feed_title;
- }
- }
-
- $reply .= "
- <a href=\"#\"
- title=\"".__("View as RSS feed")."\"
- onclick=\"displayDlg('generatedFeed', '$feed_id:$is_cat:$rss_link')\">
- <img class=\"noborder\" style=\"vertical-align : middle\" src=\"images/feed-icon-12x12.png\"></a>";
-
- $reply .= "</div>";
-
- return $reply;
- }
-
- function outputFeedList($link, $special = true) {
-
- $feedlist = array();
-
- $enable_cats = get_pref($link, 'ENABLE_FEED_CATS');
-
- $feedlist['identifier'] = 'id';
- $feedlist['label'] = 'name';
- $feedlist['items'] = array();
-
- $owner_uid = $_SESSION["uid"];
-
- /* virtual feeds */
-
- if ($special) {
-
- if ($enable_cats) {
- $cat_hidden = get_pref($link, "_COLLAPSED_SPECIAL");
- $cat = feedlist_init_cat($link, -1, $cat_hidden);
- } else {
- $cat['items'] = array();
- }
-
- foreach (array(-4, -3, -1, -2, 0) as $i) {
- array_push($cat['items'], feedlist_init_feed($link, $i));
- }
-
- if ($enable_cats) {
- array_push($feedlist['items'], $cat);
- } else {
- $feedlist['items'] = array_merge($feedlist['items'], $cat['items']);
- }
-
- $result = db_query($link, "SELECT * FROM
- ttrss_labels2 WHERE owner_uid = '$owner_uid' ORDER by caption");
-
- if (db_num_rows($result) > 0) {
-
- if (get_pref($link, 'ENABLE_FEED_CATS')) {
- $cat_hidden = get_pref($link, "_COLLAPSED_LABELS");
- $cat = feedlist_init_cat($link, -2, $cat_hidden);
- } else {
- $cat['items'] = array();
- }
-
- while ($line = db_fetch_assoc($result)) {
-
- $label_id = -$line['id'] - 11;
- $count = getFeedUnread($link, $label_id);
-
- $feed = feedlist_init_feed($link, $label_id, false, $count);
-
- $feed['fg_color'] = $line['fg_color'];
- $feed['bg_color'] = $line['bg_color'];
-
- array_push($cat['items'], $feed);
- }
-
- if ($enable_cats) {
- array_push($feedlist['items'], $cat);
- } else {
- $feedlist['items'] = array_merge($feedlist['items'], $cat['items']);
- }
- }
- }
-
-/* if (get_pref($link, 'ENABLE_FEED_CATS')) {
- if (get_pref($link, "FEEDS_SORT_BY_UNREAD")) {
- $order_by_qpart = "order_id,category,unread DESC,title";
- } else {
- $order_by_qpart = "order_id,category,title";
- }
- } else {
- if (get_pref($link, "FEEDS_SORT_BY_UNREAD")) {
- $order_by_qpart = "unread DESC,title";
- } else {
- $order_by_qpart = "title";
- }
- } */
-
- /* real feeds */
-
- if ($enable_cats)
- $order_by_qpart = "ttrss_feed_categories.order_id,category,
- ttrss_feeds.order_id,title";
- else
- $order_by_qpart = "title";
-
- $age_qpart = getMaxAgeSubquery();
-
- $query = "SELECT ttrss_feeds.id, ttrss_feeds.title,
- ".SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated_noms,
- cat_id,last_error,
- ttrss_feed_categories.title AS category,
- ttrss_feed_categories.collapsed,
- value AS unread
- FROM ttrss_feeds LEFT JOIN ttrss_feed_categories
- ON (ttrss_feed_categories.id = cat_id)
- LEFT JOIN ttrss_counters_cache
- ON
- (ttrss_feeds.id = feed_id)
- WHERE
- ttrss_feeds.owner_uid = '$owner_uid'
- ORDER BY $order_by_qpart";
-
- $result = db_query($link, $query);
-
- $actid = $_REQUEST["actid"];
-
- if (db_num_rows($result) > 0) {
-
- $category = "";
-
- if (!$enable_cats)
- $cat['items'] = array();
- else
- $cat = false;
-
- while ($line = db_fetch_assoc($result)) {
-
- $feed = htmlspecialchars(trim($line["title"]));
-
- if (!$feed) $feed = "[Untitled]";
-
- $feed_id = $line["id"];
- $unread = $line["unread"];
-
- $cat_id = $line["cat_id"];
- $tmp_category = $line["category"];
- if (!$tmp_category) $tmp_category = __("Uncategorized");
-
- if ($category != $tmp_category && $enable_cats) {
-
- $category = $tmp_category;
-
- $collapsed = sql_bool_to_bool($line["collapsed"]);
-
- // workaround for NULL category
- if ($category == __("Uncategorized")) {
- $collapsed = get_pref($link, "_COLLAPSED_UNCAT");
- }
-
- if ($cat) array_push($feedlist['items'], $cat);
-
- $cat = feedlist_init_cat($link, $cat_id, $collapsed);
- }
-
- $updated = make_local_datetime($link, $line["updated_noms"], false);
-
- array_push($cat['items'], feedlist_init_feed($link, $feed_id,
- $feed, $unread, $line['last_error'], $updated));
- }
-
- if ($enable_cats) {
- array_push($feedlist['items'], $cat);
- } else {
- $feedlist['items'] = array_merge($feedlist['items'], $cat['items']);
- }
-
- }
-
- return $feedlist;
- }
-
- function get_article_tags($link, $id, $owner_uid = 0, $tag_cache = false) {
-
- global $memcache;
-
- $a_id = db_escape_string($id);
-
- if (!$owner_uid) $owner_uid = $_SESSION["uid"];
-
- $query = "SELECT DISTINCT tag_name,
- owner_uid as owner FROM
- 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();
-
- if ($memcache && $obj = $memcache->get($obj_id)) {
- $tags = $obj;
- } else {
- /* check cache first */
-
- if ($tag_cache === false) {
- $result = db_query($link, "SELECT tag_cache FROM ttrss_user_entries
- WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
-
- $tag_cache = db_fetch_result($result, 0, "tag_cache");
- }
-
- if ($tag_cache) {
- $tags = explode(",", $tag_cache);
- } else {
-
- /* do it the hard way */
-
- $tmp_result = db_query($link, $query);
-
- while ($tmp_line = db_fetch_assoc($tmp_result)) {
- array_push($tags, $tmp_line["tag_name"]);
- }
-
- /* update the cache */
-
- $tags_str = db_escape_string(join(",", $tags));
-
- db_query($link, "UPDATE ttrss_user_entries
- SET tag_cache = '$tags_str' WHERE ref_id = '$id'
- AND owner_uid = " . $_SESSION["uid"]);
- }
-
- if ($memcache) $memcache->add($obj_id, $tags, 0, 3600);
- }
-
- return $tags;
- }
-
- function trim_array($array) {
- $tmp = $array;
- array_walk($tmp, 'trim');
- return $tmp;
- }
-
- function tag_is_valid($tag) {
- if ($tag == '') return false;
- if (preg_match("/^[0-9]*$/", $tag)) return false;
- if (mb_strlen($tag) > 250) return false;
-
- if (function_exists('iconv')) {
- $tag = iconv("utf-8", "utf-8", $tag);
- }
-
- if (!$tag) return false;
-
- return true;
- }
-
- function render_login_form($link, $mobile = 0) {
- switch ($mobile) {
- case 0:
- require_once "login_form.php";
- break;
- case 1:
- require_once "mobile/login_form.php";
- break;
- case 2:
- require_once "mobile/classic/login_form.php";
- }
- }
-
- // 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
- }
-
- function format_warning($msg, $id = "") {
- global $link;
- return "<div class=\"warning\" id=\"$id\">
- <img src=\"".theme_image($link, "images/sign_excl.png")."\">$msg</div>";
- }
-
- function format_notice($msg, $id = "") {
- global $link;
- return "<div class=\"notice\" id=\"$id\">
- <img src=\"".theme_image($link, "images/sign_info.png")."\">$msg</div>";
- }
-
- function format_error($msg, $id = "") {
- global $link;
- return "<div class=\"error\" id=\"$id\">
- <img src=\"".theme_image($link, "images/sign_excl.png")."\">$msg</div>";
- }
-
- function print_notice($msg) {
- return print format_notice($msg);
- }
-
- function print_warning($msg) {
- return print format_warning($msg);
- }
-
- function print_error($msg) {
- return print format_error($msg);
- }
-
-
- function T_sprintf() {
- $args = func_get_args();
- return vsprintf(__(array_shift($args)), $args);
- }
-
- function format_inline_player($link, $url, $ctype) {
-
- $entry = "";
-
- 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();
-
- $entry .= "<audio id=\"$id\"\">
- <source 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\"
- data=\"lib/button/musicplayer.swf?song_url=$url\"
- width=\"17\" height=\"17\" style='float : left; margin-right : 5px;'>
- <param name=\"movie\"
- value=\"lib/button/musicplayer.swf?song_url=$url\" />
- </object>";
- }
- }
-
- $filename = substr($url, strrpos($url, "/")+1);
-
- $entry .= " <a target=\"_blank\" href=\"" . htmlspecialchars($url) . "\">" .
- $filename . " (" . $ctype . ")" . "</a>";
-
- return $entry;
- }
-
- function format_article($link, $id, $mark_as_read = true, $zoom_mode = false) {
-
- $rv = array();
-
- $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 :( */
-
- $result = db_query($link, "SELECT feed_id FROM ttrss_user_entries
- WHERE ref_id = '$id'");
-
- $feed_id = (int) db_fetch_result($result, 0, "feed_id");
-
- $rv['feed_id'] = $feed_id;
-
- //if (!$zoom_mode) { print "<article id='$id'><![CDATA["; };
-
- $result = db_query($link, "SELECT rtl_content, always_display_enclosures FROM ttrss_feeds
- WHERE id = '$feed_id' AND owner_uid = " . $_SESSION["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"));
- } else {
- $rtl_content = false;
- $always_display_enclosures = 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()
- WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
-
- ccache_update($link, $feed_id, $_SESSION["uid"]);
- }
-
- $result = db_query($link, "SELECT title,link,content,feed_id,comments,int_id,
- ".SUBSTRING_FOR_DATE."(updated,1,16) as updated,
- (SELECT icon_url FROM ttrss_feeds WHERE id = feed_id) as icon_url,
- (SELECT site_url FROM ttrss_feeds WHERE id = feed_id) as site_url,
- num_comments,
- tag_cache,
- author,
- orig_feed_id,
- note
- FROM ttrss_entries,ttrss_user_entries
- WHERE id = '$id' AND ref_id = id AND owner_uid = " . $_SESSION["uid"]);
-
- if ($result) {
-
- $line = db_fetch_assoc($result);
-
- if ($line["icon_url"]) {
- $feed_icon = "<img src=\"" . $line["icon_url"] . "\">";
- } else {
- $feed_icon = " ";
- }
-
- $feed_site_url = $line['site_url'];
-
- $num_comments = $line["num_comments"];
- $entry_comments = "";
-
- if ($num_comments > 0) {
- if ($line["comments"]) {
- $comments_url = $line["comments"];
- } else {
- $comments_url = $line["link"];
- }
- $entry_comments = "<a target='_blank' href=\"$comments_url\">$num_comments comments</a>";
- } else {
- if ($line["comments"] && $line["link"] != $line["comments"]) {
- $entry_comments = "<a target='_blank' href=\"".$line["comments"]."\">comments</a>";
- }
- }
-
- if ($zoom_mode) {
- header("Content-Type: text/html");
- $rv['content'] .= "<html><head>
- <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>";
- }
-
- $rv['content'] .= "<div id=\"PTITLE-$id\" style=\"display : none\">" .
- truncate_string(strip_tags($line['title']), 15) . "</div>";
-
- $rv['content'] .= "<div class=\"postReply\" id=\"POST-$id\">";
-
- $rv['content'] .= "<div onclick=\"return postClicked(event, $id)\"
- class=\"postHeader\" id=\"POSTHDR-$id\">";
-
- $entry_author = $line["author"];
-
- if ($entry_author) {
- $entry_author = __(" - ") . $entry_author;
- }
-
- $parsed_updated = make_local_datetime($link, $line["updated"], true,
- false, true);
-
- $rv['content'] .= "<div class=\"postDate$rtl_class\">$parsed_updated</div>";
-
- if ($line["link"]) {
- $rv['content'] .= "<div clear='both'><a target='_blank'
- title=\"".htmlspecialchars($line['title'])."\"
- href=\"" .
- $line["link"] . "\">" .
- truncate_string($line["title"], 100) .
- "<span class='author'>$entry_author</span></a></div>";
- } else {
- $rv['content'] .= "<div clear='both'>" . $line["title"] . "$entry_author</div>";
- }
-
- $tag_cache = $line["tag_cache"];
-
- if (!$tag_cache)
- $tags = get_article_tags($link, $id);
- else
- $tags = explode(",", $tag_cache);
-
- $tags_str = format_tags_string($tags, $id);
- $tags_str_full = join(", ", $tags);
-
- if (!$tags_str_full) $tags_str_full = __("no tags");
-
- if (!$entry_comments) $entry_comments = " "; # placeholder
-
- $rv['content'] .= "<div style='float : right'>
- <img src='".theme_image($link, 'images/tag.png')."'
- class='tagsPic' alt='Tags' title='Tags'> ";
-
- if (!$zoom_mode) {
- $rv['content'] .= "<span id=\"ATSTR-$id\">$tags_str</span>
- <a title=\"".__('Edit tags for this article')."\"
- href=\"#\" onclick=\"editArticleTags($id, $feed_id)\">(+)</a>";
-
- $rv['content'] .= "<div dojoType=\"dijit.Tooltip\"
- id=\"ATSTRTIP-$id\" connectId=\"ATSTR-$id\"
- position=\"below\">$tags_str_full</div>";
-
- $rv['content'] .= "<img src=\"".theme_image($link, 'images/art-zoom.png')."\"
- class='tagsPic' style=\"cursor : pointer\"
- onclick=\"postOpenInNewTab(event, $id)\"
- alt='Zoom' title='".__('Open article in new tab')."'>";
-
- //$note_escaped = htmlspecialchars($line['note'], ENT_QUOTES);
-
- $rv['content'] .= "<img src=\"".theme_image($link, 'images/art-pub-note.png')."\"
- class='tagsPic' style=\"cursor : pointer\"
- onclick=\"editArticleNote($id)\"
- alt='PubNote' title='".__('Edit article note')."'>";
-
- if (DIGEST_ENABLE) {
- $rv['content'] .= "<img src=\"".theme_image($link, 'images/art-email.png')."\"
- class='tagsPic' style=\"cursor : pointer\"
- onclick=\"emailArticle($id)\"
- alt='Zoom' title='".__('Forward by email')."'>";
- }
-
- if (ENABLE_TWEET_BUTTON) {
- $rv['content'] .= "<img src=\"".theme_image($link, 'images/art-tweet.png')."\"
- class='tagsPic' style=\"cursor : pointer\"
- onclick=\"tweetArticle($id)\"
- alt='Zoom' title='".__('Share on Twitter')."'>";
- }
-
- $rv['content'] .= "<img src=\"".theme_image($link, 'images/art-share.png')."\"
- class='tagsPic' style=\"cursor : pointer\"
- onclick=\"shareArticle(".$line['int_id'].")\"
- alt='Zoom' title='".__('Share by URL')."'>";
-
- $rv['content'] .= "<img src=\"".theme_image($link, 'images/digest_checkbox.png')."\"
- class='tagsPic' style=\"cursor : pointer\"
- onclick=\"closeArticlePanel($id)\"
- alt='Zoom' title='".__('Close this panel')."'>";
-
- } 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>";
-
- if ($line["orig_feed_id"]) {
-
- $tmp_result = db_query($link, "SELECT * FROM ttrss_archived_feeds
- WHERE id = ".$line["orig_feed_id"]);
-
- if (db_num_rows($tmp_result) != 0) {
-
- $rv['content'] .= "<div clear='both'>";
- $rv['content'] .= __("Originally from:");
-
- $rv['content'] .= " ";
-
- $tmp_line = db_fetch_assoc($tmp_result);
-
- $rv['content'] .= "<a target='_blank'
- href=' " . htmlspecialchars($tmp_line['site_url']) . "'>" .
- $tmp_line['title'] . "</a>";
-
- $rv['content'] .= " ";
-
- $rv['content'] .= "<a target='_blank' href='" . htmlspecialchars($tmp_line['feed_url']) . "'>";
- $rv['content'] .= "<img title='".__('Feed URL')."'class='tinyFeedIcon' src='images/pub_set.gif'></a>";
-
- $rv['content'] .= "</div>";
- }
- }
-
- $rv['content'] .= "</div>";
-
- $rv['content'] .= "<div id=\"POSTNOTE-$id\">";
- if ($line['note']) {
- $rv['content'] .= format_article_note($id, $line['note']);
- }
- $rv['content'] .= "</div>";
-
- $rv['content'] .= "<div class=\"postIcon\">" .
- "<a target=\"_blank\" title=\"".__("Visit the website")."\"$
- href=\"".htmlspecialchars($feed_site_url)."\">".
- $feed_icon . "</a></div>";
-
- $rv['content'] .= "<div class=\"postContent\">";
-
- $article_content = sanitize_rss($link, $line["content"], false, false,
- $feed_site_url);
-
- $rv['content'] .= $article_content;
-
- $rv['content'] .= format_article_enclosures($link, $id,
- $always_display_enclosures, $article_content);
-
- $rv['content'] .= "</div>";
-
- $rv['content'] .= "</div>";
-
- }
-
- if ($zoom_mode) {
- $rv['content'] .= "
- <div style=\"text-align : center\">
- <button onclick=\"return window.close()\">".
- __("Close this window")."</button></div>";
- $rv['content'] .= "</body></html>";
- }
-
- return $rv;
-
- }
-
- function format_headlines_list($link, $feed, $subop, $view_mode, $limit, $cat_view,
- $next_unread_feed, $offset, $vgr_last_feed = false,
- $override_order = false) {
-
- $disable_cache = false;
-
- $reply = array();
-
- $timing_info = getmicrotime();
-
- $topmost_article_ids = array();
-
- if (!$offset) $offset = 0;
- if ($subop == "undefined") $subop = "";
-
- $subop_split = explode(":", $subop);
-
-/* if ($subop == "CatchupSelected") {
- $ids = explode(",", db_escape_string($_REQUEST["ids"]));
- $cmode = sprintf("%d", $_REQUEST["cmode"]);
-
- catchupArticlesById($link, $ids, $cmode);
- } */
-
- if ($subop == "ForceUpdate" && $feed && is_numeric($feed) > 0) {
- update_rss_feed($link, $feed, true);
- }
-
- if ($subop == "MarkAllRead") {
- catchup_feed($link, $feed, $cat_view);
-
- if (get_pref($link, 'ON_CATCHUP_SHOW_NEXT_FEED')) {
- if ($next_unread_feed) {
- $feed = $next_unread_feed;
- }
- }
- }
-
- if ($subop_split[0] == "MarkAllReadGR") {
- catchup_feed($link, $subop_split[1], false);
- }
-
- // FIXME: might break tag display?
-
- if (is_numeric($feed) && $feed > 0 && !$cat_view) {
- $result = db_query($link,
- "SELECT id FROM ttrss_feeds WHERE id = '$feed' LIMIT 1");
-
- if (db_num_rows($result) == 0) {
- $reply['content'] = "<div align='center'>".__('Feed not found.')."</div>";
- }
- }
-
- if (preg_match("/^-?[0-9][0-9]*$/", $feed) != false) {
-
- $result = db_query($link, "SELECT rtl_content FROM ttrss_feeds
- WHERE id = '$feed' AND owner_uid = " . $_SESSION["uid"]);
-
- if (db_num_rows($result) == 1) {
- $rtl_content = sql_bool_to_bool(db_fetch_result($result, 0, "rtl_content"));
- } else {
- $rtl_content = false;
- }
-
- if ($rtl_content) {
- $rtl_tag = "dir=\"RTL\"";
- } else {
- $rtl_tag = "";
- }
- } else {
- $rtl_tag = "";
- $rtl_content = false;
- }
-
- @$search = db_escape_string($_REQUEST["query"]);
-
- if ($search) {
- $disable_cache = true;
- }
-
- @$search_mode = db_escape_string($_REQUEST["search_mode"]);
- @$match_on = db_escape_string($_REQUEST["match_on"]);
-
- if (!$match_on) {
- $match_on = "both";
- }
-
- if ($_REQUEST["debug"]) $timing_info = print_checkpoint("H0", $timing_info);
-
-// error_log("format_headlines_list: [" . $feed . "] subop [" . $subop . "]");
- if( $search_mode == '' && $subop != '' ){
- $search_mode = $subop;
- }
-// error_log("search_mode: " . $search_mode);
- $qfh_ret = queryFeedHeadlines($link, $feed, $limit, $view_mode, $cat_view,
- $search, $search_mode, $match_on, $override_order, $offset);
-
- if ($_REQUEST["debug"]) $timing_info = print_checkpoint("H1", $timing_info);
-
- $result = $qfh_ret[0];
- $feed_title = $qfh_ret[1];
- $feed_site_url = $qfh_ret[2];
- $last_error = $qfh_ret[3];
-
- $vgroup_last_feed = $vgr_last_feed;
-
-// if (!$offset) {
-
- if (db_num_rows($result) > 0) {
- $reply['toolbar'] = format_headline_subtoolbar($link, $feed_site_url,
- $feed_title,
- $feed, $cat_view, $search, $match_on, $search_mode, $view_mode,
- $last_error);
- }
-// }
-
- $headlines_count = db_num_rows($result);
-
- if (db_num_rows($result) > 0) {
-
- $lnum = $offset;
-
- $num_unread = 0;
- $cur_feed_title = '';
-
- $fresh_intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE") * 60 * 60;
-
- if ($_REQUEST["debug"]) $timing_info = print_checkpoint("PS", $timing_info);
-
- while ($line = db_fetch_assoc($result)) {
-
- $class = ($lnum % 2) ? "even" : "odd";
-
- $id = $line["id"];
- $feed_id = $line["feed_id"];
- $label_cache = $line["label_cache"];
- $labels = false;
-
- if ($label_cache) {
- $label_cache = json_decode($label_cache, true);
-
- if ($label_cache) {
- if ($label_cache["no-labels"] == 1)
- $labels = array();
- else
- $labels = $label_cache;
- }
- }
-
- if (!is_array($labels)) $labels = get_article_labels($link, $id);
-
- $labels_str = "<span id=\"HLLCTR-$id\">";
- $labels_str .= format_article_labels($labels, $id);
- $labels_str .= "</span>";
-
- if (count($topmost_article_ids) < 3) {
- array_push($topmost_article_ids, $id);
- }
-
- if ($line["last_read"] == "" && !sql_bool_to_bool($line["unread"])) {
-
- $update_pic = "<img id='FUPDPIC-$id' src=\"".
- theme_image($link, 'images/updated.png')."\"
- alt=\"Updated\">";
- } else {
- $update_pic = "<img id='FUPDPIC-$id' src=\"images/blank_icon.gif\"
- alt=\"Updated\">";
- }
-
- if (sql_bool_to_bool($line["unread"]) &&
- time() - strtotime($line["updated_noms"]) < $fresh_intl) {
-
- $update_pic = "<img id='FUPDPIC-$id' src=\"".
- theme_image($link, 'images/fresh_sign.png')."\" alt=\"Fresh\">";
- }
-
- if ($line["unread"] == "t" || $line["unread"] == "1") {
- $class .= " Unread";
- ++$num_unread;
- $is_unread = true;
- } else {
- $is_unread = false;
- }
-
- if ($line["marked"] == "t" || $line["marked"] == "1") {
- $marked_pic = "<img id=\"FMPIC-$id\"
- src=\"".theme_image($link, 'images/mark_set.png')."\"
- class=\"markedPic\" alt=\"Unstar article\"
- onclick='javascript:toggleMark($id)'>";
- } else {
- $marked_pic = "<img id=\"FMPIC-$id\"
- src=\"".theme_image($link, 'images/mark_unset.png')."\"
- class=\"markedPic\" alt=\"Star article\"
- onclick='javascript:toggleMark($id)'>";
- }
-
- if ($line["published"] == "t" || $line["published"] == "1") {
- $published_pic = "<img id=\"FPPIC-$id\" src=\"".theme_image($link,
- 'images/pub_set.png')."\"
- class=\"markedPic\"
- alt=\"Unpublish article\" onclick='javascript:togglePub($id)'>";
- } else {
- $published_pic = "<img id=\"FPPIC-$id\" src=\"".theme_image($link,
- 'images/pub_unset.png')."\"
- class=\"markedPic\"
- alt=\"Publish article\" onclick='javascript:togglePub($id)'>";
- }
-
-# $content_link = "<a target=\"_blank\" href=\"".$line["link"]."\">" .
-# $line["title"] . "</a>";
-
-# $content_link = "<a
-# href=\"" . htmlspecialchars($line["link"]) . "\"
-# onclick=\"view($id,$feed_id);\">" .
-# $line["title"] . "</a>";
-
-# $content_link = "<a href=\"javascript:viewContentUrl('".$line["link"]."');\">" .
-# $line["title"] . "</a>";
-
- $updated_fmt = make_local_datetime($link, $line["updated_noms"], false);
-
- if (get_pref($link, 'SHOW_CONTENT_PREVIEW')) {
- $content_preview = truncate_string(strip_tags($line["content_preview"]),
- 100);
- }
-
- $score = $line["score"];
-
- $score_pic = theme_image($link,
- "images/" . get_score_pic($score));
-
-/* $score_title = __("(Click to change)");
- $score_pic = "<img class='hlScorePic' src=\"images/$score_pic\"
- onclick=\"adjustArticleScore($id, $score)\" title=\"$score $score_title\">"; */
-
- $score_pic = "<img class='hlScorePic' src=\"$score_pic\"
- title=\"$score\">";
-
- if ($score > 500) {
- $hlc_suffix = "H";
- } else if ($score < -100) {
- $hlc_suffix = "L";
- } else {
- $hlc_suffix = "";
- }
-
- $entry_author = $line["author"];
-
- if ($entry_author) {
- $entry_author = " - $entry_author";
- }
-
- $has_feed_icon = feed_has_icon($feed_id);
-
- if ($has_feed_icon) {
- $feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"".ICONS_URL."/$feed_id.ico\" alt=\"\">";
- } else {
- $feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"images/feed-icon-12x12.png\" alt=\"\">";
- }
-
- if (!get_pref($link, 'COMBINED_DISPLAY_MODE')) {
-
- if (get_pref($link, 'VFEED_GROUP_BY_FEED')) {
- if ($feed_id != $vgroup_last_feed && $line["feed_title"]) {
-
- $cur_feed_title = $line["feed_title"];
- $vgroup_last_feed = $feed_id;
-
- $cur_feed_title = htmlspecialchars($cur_feed_title);
-
- $vf_catchup_link = "(<a onclick='javascript:catchupFeedInGroup($feed_id);' href='#'>".__('mark as read')."</a>)";
-
- $reply['content'] .= "<div class='cdmFeedTitle'>".
- "<div style=\"float : right\">$feed_icon_img</div>".
- "<a href=\"#\" onclick=\"viewfeed($feed_id)\">".
- $line["feed_title"]."</a> $vf_catchup_link</div>";
-
- }
- }
-
- $mouseover_attrs = "onmouseover='postMouseIn($id)'
- onmouseout='postMouseOut($id)'";
-
- $reply['content'] .= "<div class='$class' id='RROW-$id' $mouseover_attrs>";
-
- $reply['content'] .= "<div class='hlUpdPic'>$update_pic</div>";
-
- $reply['content'] .= "<div class='hlLeft'>";
-
- $reply['content'] .= "<input type=\"checkbox\" onclick=\"tSR(this)\"
- id=\"RCHK-$id\">";
-
- $reply['content'] .= "$marked_pic";
- $reply['content'] .= "$published_pic";
-
- $reply['content'] .= "</div>";
-
- $reply['content'] .= "<div onclick='return hlClicked(event, $id)'
- class=\"hlTitle\"><span class='hlContent$hlc_suffix'>";
- $reply['content'] .= "<a id=\"RTITLE-$id\"
- href=\"" . htmlspecialchars($line["link"]) . "\"
- onclick=\"\">" .
- truncate_string($line["title"], 200);
-
- if (get_pref($link, 'SHOW_CONTENT_PREVIEW')) {
- if ($content_preview) {
- $reply['content'] .= "<span class=\"contentPreview\"> - $content_preview</span>";
- }
- }
-
- $reply['content'] .= "</a></span>";
-
- $reply['content'] .= $labels_str;
-
- if (!get_pref($link, 'VFEED_GROUP_BY_FEED') &&
- defined('_SHOW_FEED_TITLE_IN_VFEEDS')) {
- if (@$line["feed_title"]) {
- $reply['content'] .= "<span class=\"hlFeed\">
- (<a href=\"#\" onclick=\"viewfeed($feed_id)\">".
- $line["feed_title"]."</a>)
- </span>";
- }
- }
-
- $reply['content'] .= "</div>";
-
- $reply['content'] .= "<span class=\"hlUpdated\">$updated_fmt</span>";
- $reply['content'] .= "<div class=\"hlRight\">";
-
- $reply['content'] .= $score_pic;
-
- if ($line["feed_title"] && !get_pref($link, 'VFEED_GROUP_BY_FEED')) {
-
- $reply['content'] .= "<span onclick=\"viewfeed($feed_id)\"
- style=\"cursor : pointer\"
- title=\"".htmlspecialchars($line['feed_title'])."\">
- $feed_icon_img<span>";
- }
-
- $reply['content'] .= "</div>";
- $reply['content'] .= "</div>";
-
- } else {
-
- if (get_pref($link, 'VFEED_GROUP_BY_FEED') && $line["feed_title"]) {
- if ($feed_id != $vgroup_last_feed) {
-
- $cur_feed_title = $line["feed_title"];
- $vgroup_last_feed = $feed_id;
-
- $cur_feed_title = htmlspecialchars($cur_feed_title);
-
- $vf_catchup_link = "(<a onclick='javascript:catchupFeedInGroup($feed_id);' href='#'>".__('mark as read')."</a>)";
-
- $has_feed_icon = feed_has_icon($feed_id);
-
- if ($has_feed_icon) {
- $feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"".ICONS_URL."/$feed_id.ico\" alt=\"\">";
- } else {
- //$feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"images/blank_icon.gif\" alt=\"\">";
- }
-
- $reply['content'] .= "<div class='cdmFeedTitle'>".
- "<div style=\"float : right\">$feed_icon_img</div>".
- "<a href=\"#\" onclick=\"viewfeed($feed_id)\">".
- $line["feed_title"]."</a> $vf_catchup_link</div>";
- }
- }
-
- $expand_cdm = get_pref($link, 'CDM_EXPANDED');
-
- $mouseover_attrs = "onmouseover='postMouseIn($id)'
- onmouseout='postMouseOut($id)'";
-
- $reply['content'] .= "<div class=\"$class\"
- id=\"RROW-$id\" $mouseover_attrs'>";
-
- $reply['content'] .= "<div class=\"cdmHeader\">";
-
- $reply['content'] .= "<div>";
-
- $reply['content'] .= "<input type=\"checkbox\" onclick=\"toggleSelectRowById(this,
- 'RROW-$id')\" id=\"RCHK-$id\"/>";
-
- $reply['content'] .= "$marked_pic";
- $reply['content'] .= "$published_pic";
-
- $reply['content'] .= "</div>";
-
- $reply['content'] .= "<span id=\"RTITLE-$id\"
- onclick=\"return cdmClicked(event, $id);\"
- class=\"titleWrap$hlc_suffix\">
- <a class=\"title\"
- title=\"".htmlspecialchars($line['title'])."\"
- target=\"_blank\" href=\"".
- htmlspecialchars($line["link"])."\">".
- truncate_string($line["title"], 100) .
- " $entry_author</a>";
-
- $reply['content'] .= $labels_str;
-
- if (!get_pref($link, 'VFEED_GROUP_BY_FEED') &&
- defined('_SHOW_FEED_TITLE_IN_VFEEDS')) {
- if (@$line["feed_title"]) {
- $reply['content'] .= "<span class=\"hlFeed\">
- (<a href=\"#\" onclick=\"viewfeed($feed_id)\">".
- $line["feed_title"]."</a>)
- </span>";
- }
- }
-
- if (!$expand_cdm)
- $content_hidden = "style=\"display : none\"";
- else
- $excerpt_hidden = "style=\"display : none\"";
-
- $reply['content'] .= "<span $excerpt_hidden
- id=\"CEXC-$id\" class=\"cdmExcerpt\"> - $content_preview</span>";
-
- $reply['content'] .= "</span>";
-
- $reply['content'] .= "<div>";
- $reply['content'] .= "<span class='updated'>$updated_fmt</span>";
- $reply['content'] .= "$score_pic";
-
- if (!get_pref($link, "VFEED_GROUP_BY_FEED") && $line["feed_title"]) {
- $reply['content'] .= "<span style=\"cursor : pointer\"
- title=\"".htmlspecialchars($line["feed_title"])."\"
- onclick=\"viewfeed($feed_id)\">$feed_icon_img</span>";
- }
- $reply['content'] .= "<div class=\"updPic\">$update_pic</div>";
- $reply['content'] .= "</div>";
-
- $reply['content'] .= "</div>";
-
- $reply['content'] .= "<div class=\"cdmContent\" $content_hidden
- onclick=\"return cdmClicked(event, $id);\"
- id=\"CICD-$id\">";
-
- $reply['content'] .= "<div class=\"cdmContentInner\">";
-
- if ($line["orig_feed_id"]) {
-
- $tmp_result = db_query($link, "SELECT * FROM ttrss_archived_feeds
- WHERE id = ".$line["orig_feed_id"]);
-
- if (db_num_rows($tmp_result) != 0) {
-
- $reply['content'] .= "<div clear='both'>";
- $reply['content'] .= __("Originally from:");
-
- $reply['content'] .= " ";
-
- $tmp_line = db_fetch_assoc($tmp_result);
-
- $reply['content'] .= "<a target='_blank'
- href=' " . htmlspecialchars($tmp_line['site_url']) . "'>" .
- $tmp_line['title'] . "</a>";
-
- $reply['content'] .= " ";
-
- $reply['content'] .= "<a target='_blank' href='" . htmlspecialchars($tmp_line['feed_url']) . "'>";
- $reply['content'] .= "<img title='".__('Feed URL')."'class='tinyFeedIcon' src='images/pub_set.gif'></a>";
-
- $reply['content'] .= "</div>";
- }
- }
-
- $feed_site_url = $line["site_url"];
-
- $article_content = sanitize_rss($link, $line["content_preview"],
- false, false, $feed_site_url);
-
- $reply['content'] .= "<div id=\"POSTNOTE-$id\">";
- if ($line['note']) {
- $reply['content'] .= format_article_note($id, $line['note']);
- }
- $reply['content'] .= "</div>";
-
- $reply['content'] .= "<span id=\"CWRAP-$id\">";
- $reply['content'] .= $expand_cdm ? $article_content : '';
- $reply['content'] .= "</span>";
-
-/* $tmp_result = db_query($link, "SELECT always_display_enclosures FROM
- ttrss_feeds WHERE id = ".
- (($line['feed_id'] == null) ? $line['orig_feed_id'] :
- $line['feed_id'])." AND owner_uid = ".$_SESSION["uid"]);
-
- $always_display_enclosures = sql_bool_to_bool(db_fetch_result($tmp_result,
- 0, "always_display_enclosures")); */
-
- $always_display_enclosures = sql_bool_to_bool($line["always_display_enclosures"]);
-
- $reply['content'] .= format_article_enclosures($link, $id, $always_display_enclosures,
- $article_content);
-
- $reply['content'] .= "</div>";
-
- $reply['content'] .= "<div class=\"cdmFooter\">";
-
- $tag_cache = $line["tag_cache"];
-
- $tags_str = format_tags_string(
- get_article_tags($link, $id, $_SESSION["uid"], $tag_cache),
- $id);
-
- $reply['content'] .= "<img src='".theme_image($link,
- 'images/tag.png')."' alt='Tags' title='Tags'>
- <span id=\"ATSTR-$id\">$tags_str</span>
- <a title=\"".__('Edit tags for this article')."\"
- href=\"#\" onclick=\"editArticleTags($id, $feed_id, true)\">(+)</a>";
-
- $num_comments = $line["num_comments"];
- $entry_comments = "";
-
- if ($num_comments > 0) {
- if ($line["comments"]) {
- $comments_url = $line["comments"];
- } else {
- $comments_url = $line["link"];
- }
- $entry_comments = "<a target='_blank' href=\"$comments_url\">$num_comments comments</a>";
- } else {
- if ($line["comments"] && $line["link"] != $line["comments"]) {
- $entry_comments = "<a target='_blank' href=\"".$line["comments"]."\">comments</a>";
- }
- }
-
- if ($entry_comments) $reply['content'] .= " ($entry_comments)";
-
- $reply['content'] .= "<div style=\"float : right\">";
-
- $reply['content'] .= "<img src=\"images/art-zoom.png\"
- onclick=\"zoomToArticle(event, $id)\"
- style=\"cursor : pointer\"
- alt='Zoom'
- title='".__('Open article in new tab')."'>";
-
- //$note_escaped = htmlspecialchars($line['note'], ENT_QUOTES);
-
- $reply['content'] .= "<img src=\"images/art-pub-note.png\"
- style=\"cursor : pointer\" style=\"cursor : pointer\"
- onclick=\"editArticleNote($id)\"
- alt='PubNote' title='".__('Edit article note')."'>";
-
- if (DIGEST_ENABLE) {
- $reply['content'] .= "<img src=\"".theme_image($link, 'images/art-email.png')."\"
- style=\"cursor : pointer\"
- onclick=\"emailArticle($id)\"
- alt='Zoom' title='".__('Forward by email')."'>";
- }
-
- if (ENABLE_TWEET_BUTTON) {
- $reply['content'] .= "<img src=\"".theme_image($link, 'images/art-tweet.png')."\"
- class='tagsPic' style=\"cursor : pointer\"
- onclick=\"tweetArticle($id)\"
- alt='Zoom' title='".__('Share on Twitter')."'>";
- }
-
- $reply['content'] .= "<img src=\"".theme_image($link, 'images/art-share.png')."\"
- class='tagsPic' style=\"cursor : pointer\"
- onclick=\"shareArticle(".$line['int_id'].")\"
- alt='Zoom' title='".__('Share by URL')."'>";
-
- $reply['content'] .= "<img src=\"images/digest_checkbox.png\"
- style=\"cursor : pointer\" style=\"cursor : pointer\"
- onclick=\"dismissArticle($id)\"
- alt='Dismiss' title='".__('Dismiss article')."'>";
-
- $reply['content'] .= "</div>";
- $reply['content'] .= "</div>";
-
- $reply['content'] .= "</div>";
-
- $reply['content'] .= "</div>";
-
- }
-
- ++$lnum;
- }
-
- if ($_REQUEST["debug"]) $timing_info = print_checkpoint("PE", $timing_info);
-
- } else {
- $message = "";
-
- switch ($view_mode) {
- case "unread":
- $message = __("No unread articles found to display.");
- break;
- case "updated":
- $message = __("No updated articles found to display.");
- break;
- case "marked":
- $message = __("No starred articles found to display.");
- break;
- default:
- if ($feed < -10) {
- $message = __("No articles found to display. You can assign articles to labels manually (see the Actions menu above) or use a filter.");
- } else {
- $message = __("No articles found to display.");
- }
- }
-
- if (!$offset && $message) {
- $reply['content'] .= "<div class='whiteBox'>$message";
-
- $reply['content'] .= "<p class=\"small\"><span class=\"insensitive\">";
-
- $result = db_query($link, "SELECT ".SUBSTRING_FOR_DATE."(MAX(last_updated), 1, 19) AS last_updated FROM ttrss_feeds
- WHERE owner_uid = " . $_SESSION['uid']);
-
- $last_updated = db_fetch_result($result, 0, "last_updated");
- $last_updated = make_local_datetime($link, $last_updated, false);
-
- $reply['content'] .= sprintf(__("Feeds last updated at %s"), $last_updated);
-
- $result = db_query($link, "SELECT COUNT(id) AS num_errors
- FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ".$_SESSION["uid"]);
-
- $num_errors = db_fetch_result($result, 0, "num_errors");
-
- if ($num_errors > 0) {
- $reply['content'] .= "<br/>";
- $reply['content'] .= "<a class=\"insensitive\" href=\"#\" onclick=\"showFeedsWithErrors()\">".
- __('Some feeds have update errors (click for details)')."</a>";
- }
- $reply['content'] .= "</span></p></div>";
- }
- }
-
- if ($_REQUEST["debug"]) $timing_info = print_checkpoint("H2", $timing_info);
-
- return array($topmost_article_ids, $headlines_count, $feed, $disable_cache,
- $vgroup_last_feed, $reply);
- }
-
-// from here: http://www.roscripts.com/Create_tag_cloud-71.html
-
- function printTagCloud($link) {
-
- $query = "SELECT tag_name, COUNT(post_int_id) AS count
- FROM ttrss_tags WHERE owner_uid = ".$_SESSION["uid"]."
- GROUP BY tag_name ORDER BY count DESC LIMIT 50";
-
- $result = db_query($link, $query);
-
- $tags = array();
-
- while ($line = db_fetch_assoc($result)) {
- $tags[$line["tag_name"]] = $line["count"];
- }
-
- if( count($tags) == 0 ){ return; }
-
- ksort($tags);
-
- $max_size = 32; // max font size in pixels
- $min_size = 11; // min font size in pixels
-
- // largest and smallest array values
- $max_qty = max(array_values($tags));
- $min_qty = min(array_values($tags));
-
- // find the range of values
- $spread = $max_qty - $min_qty;
- if ($spread == 0) { // we don't want to divide by zero
- $spread = 1;
- }
-
- // set the font-size increment
- $step = ($max_size - $min_size) / ($spread);
-
- // loop through the tag array
- foreach ($tags as $key => $value) {
- // calculate font-size
- // find the $value in excess of $min_qty
- // multiply by the font-size increment ($size)
- // and add the $min_size set above
- $size = round($min_size + (($value - $min_qty) * $step));
-
- $key_escaped = str_replace("'", "\\'", $key);
-
- echo "<a href=\"javascript:viewfeed('$key_escaped') \" style=\"font-size: " .
- $size . "px\" title=\"$value articles tagged with " .
- $key . '">' . $key . '</a> ';
- }
- }
-
- function print_checkpoint($n, $s) {
- $ts = getmicrotime();
- echo sprintf("<!-- CP[$n] %.4f seconds -->", $ts - $s);
- return $ts;
- }
-
- function sanitize_tag($tag) {
- $tag = trim($tag);
-
- $tag = mb_strtolower($tag, 'utf-8');
-
- $tag = preg_replace('/[\'\"\+\>\<]/', "", $tag);
-
-// $tag = str_replace('"', "", $tag);
-// $tag = str_replace("+", " ", $tag);
- $tag = str_replace("technorati tag: ", "", $tag);
-
- return $tag;
- }
-
- function get_self_url_prefix() {
- return SELF_URL_PATH;
- }
-
- function opml_publish_url($link){
-
- $url_path = get_self_url_prefix();
- $url_path .= "/opml.php?op=publish&key=" .
- get_feed_access_key($link, 'OPML:Publish', false, $_SESSION["uid"]);
-
- return $url_path;
- }
-
- /**
- * Purge a feed contents, marked articles excepted.
- *
- * @param mixed $link The database connection.
- * @param integer $id The id of the feed to purge.
- * @return void
- */
- function clear_feed_articles($link, $id) {
-
- if ($id != 0) {
- $result = db_query($link, "DELETE FROM ttrss_user_entries
- WHERE feed_id = '$id' AND marked = false AND owner_uid = " . $_SESSION["uid"]);
- } else {
- $result = db_query($link, "DELETE FROM ttrss_user_entries
- WHERE feed_id IS NULL AND marked = false AND owner_uid = " . $_SESSION["uid"]);
- }
-
- $result = db_query($link, "DELETE FROM ttrss_entries WHERE
- (SELECT COUNT(int_id) FROM ttrss_user_entries WHERE ref_id = id) = 0");
-
- ccache_update($link, $id, $_SESSION['uid']);
- } // function clear_feed_articles
-
- /**
- * Compute the Mozilla Firefox feed adding URL from server HOST and REQUEST_URI.
- *
- * @return string The Mozilla Firefox feed adding URL.
- */
- function add_feed_url() {
- //$url_path = ($_SERVER['HTTPS'] != "on" ? 'http://' : 'https://') . $_SERVER["HTTP_HOST"] . parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
-
- $url_path = get_self_url_prefix() .
- "/backend.php?op=pref-feeds&quiet=1&subop=add&feed_url=%s";
- return $url_path;
- } // function add_feed_url
-
- /**
- * Encrypt a password in SHA1.
- *
- * @param string $pass The password to encrypt.
- * @param string $login A optionnal login.
- * @return string The encrypted password.
- */
- function encrypt_password($pass, $login = '') {
- if ($login) {
- return "SHA1X:" . sha1("$login:$pass");
- } else {
- return "SHA1:" . sha1($pass);
- }
- } // function encrypt_password
-
- /**
- * Update a feed batch.
- * Used by daemons to update n feeds by run.
- * Only update feed needing a update, and not being processed
- * by another process.
- *
- * @param mixed $link Database link
- * @param integer $limit Maximum number of feeds in update batch. Default to DAEMON_FEED_LIMIT.
- * @param boolean $from_http Set to true if you call this function from http to disable cli specific code.
- * @param boolean $debug Set to false to disable debug output. Default to true.
- * @return void
- */
- function update_daemon_common($link, $limit = DAEMON_FEED_LIMIT, $from_http = false, $debug = true) {
- // Process all other feeds using last_updated and interval parameters
-
- // Test if the user has loggued in recently. If not, it does not update its feeds.
- if (DAEMON_UPDATE_LOGIN_LIMIT > 0) {
- if (DB_TYPE == "pgsql") {
- $login_thresh_qpart = "AND ttrss_users.last_login >= NOW() - INTERVAL '".DAEMON_UPDATE_LOGIN_LIMIT." days'";
- } else {
- $login_thresh_qpart = "AND ttrss_users.last_login >= DATE_SUB(NOW(), INTERVAL ".DAEMON_UPDATE_LOGIN_LIMIT." DAY)";
- }
- } else {
- $login_thresh_qpart = "";
- }
-
- // Test if the feed need a update (update interval exceded).
- if (DB_TYPE == "pgsql") {
- $update_limit_qpart = "AND ((
- ttrss_feeds.update_interval = 0
- AND ttrss_feeds.last_updated < NOW() - CAST((ttrss_user_prefs.value || ' minutes') AS INTERVAL)
- ) OR (
- ttrss_feeds.update_interval > 0
- AND ttrss_feeds.last_updated < NOW() - CAST((ttrss_feeds.update_interval || ' minutes') AS INTERVAL)
- ) OR ttrss_feeds.last_updated IS NULL)";
- } else {
- $update_limit_qpart = "AND ((
- ttrss_feeds.update_interval = 0
- AND ttrss_feeds.last_updated < DATE_SUB(NOW(), INTERVAL CONVERT(ttrss_user_prefs.value, SIGNED INTEGER) MINUTE)
- ) OR (
- ttrss_feeds.update_interval > 0
- AND ttrss_feeds.last_updated < DATE_SUB(NOW(), INTERVAL ttrss_feeds.update_interval MINUTE)
- ) OR ttrss_feeds.last_updated IS NULL)";
- }
-
- // Test if feed is currently being updated by another process.
- if (DB_TYPE == "pgsql") {
- $updstart_thresh_qpart = "AND (ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < NOW() - INTERVAL '5 minutes')";
- } else {
- $updstart_thresh_qpart = "AND (ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < DATE_SUB(NOW(), INTERVAL 5 MINUTE))";
- }
-
- // Test if there is a limit to number of updated feeds
- $query_limit = "";
- if($limit) $query_limit = sprintf("LIMIT %d", $limit);
-
- $random_qpart = sql_random_function();
-
- // We search for feed needing update.
- $result = db_query($link, "SELECT ttrss_feeds.feed_url,ttrss_feeds.id, ttrss_feeds.owner_uid,
- ".SUBSTRING_FOR_DATE."(ttrss_feeds.last_updated,1,19) AS last_updated,
- ttrss_feeds.update_interval
- FROM
- ttrss_feeds, ttrss_users, ttrss_user_prefs
- WHERE
- ttrss_feeds.owner_uid = ttrss_users.id
- AND ttrss_users.id = ttrss_user_prefs.owner_uid
- AND ttrss_user_prefs.pref_name = 'DEFAULT_UPDATE_INTERVAL'
- $login_thresh_qpart $update_limit_qpart
- $updstart_thresh_qpart
- ORDER BY $random_qpart $query_limit");
-
- $user_prefs_cache = array();
-
- if($debug) _debug(sprintf("Scheduled %d feeds to update...\n", db_num_rows($result)));
-
- // Here is a little cache magic in order to minimize risk of double feed updates.
- $feeds_to_update = array();
- while ($line = db_fetch_assoc($result)) {
- $feeds_to_update[$line['id']] = $line;
- }
-
- // We update the feed last update started date before anything else.
- // There is no lag due to feed contents downloads
- // It prevent an other process to update the same feed.
- $feed_ids = array_keys($feeds_to_update);
- if($feed_ids) {
- db_query($link, sprintf("UPDATE ttrss_feeds SET last_update_started = NOW()
- WHERE id IN (%s)", implode(',', $feed_ids)));
- }
-
- // For each feed, we call the feed update function.
- while ($line = array_pop($feeds_to_update)) {
-
- if($debug) _debug("Feed: " . $line["feed_url"] . ", " . $line["last_updated"]);
-
- update_rss_feed($link, $line["id"], true);
-
- sleep(1); // prevent flood (FIXME make this an option?)
- }
-
- // Send feed digests by email if needed.
- if (DAEMON_SENDS_DIGESTS) send_headlines_digests($link);
-
- } // function update_daemon_common
-
- function sanitize_article_content($text) {
- # we don't support CDATA sections in articles, they break our own escaping
- $text = preg_replace("/\[\[CDATA/", "", $text);
- $text = preg_replace("/\]\]\>/", "", $text);
- return $text;
- }
-
- function load_filters($link, $feed, $owner_uid, $action_id = false) {
- $filters = array();
-
- global $memcache;
-
- $obj_id = md5("FILTER:$feed:$owner_uid:$action_id");
-
- if ($memcache && $obj = $memcache->get($obj_id)) {
-
- return $obj;
-
- } else {
-
- if ($action_id) $ftype_query_part = "action_id = '$action_id' AND";
-
- $result = db_query($link, "SELECT reg_exp,
- ttrss_filter_types.name AS name,
- ttrss_filter_actions.name AS action,
- inverse,
- action_param,
- filter_param
- FROM ttrss_filters,ttrss_filter_types,ttrss_filter_actions WHERE
- enabled = true AND
- $ftype_query_part
- owner_uid = $owner_uid AND
- ttrss_filter_types.id = filter_type AND
- ttrss_filter_actions.id = action_id AND
- (feed_id IS NULL OR feed_id = '$feed') ORDER BY reg_exp");
-
- while ($line = db_fetch_assoc($result)) {
- if (!$filters[$line["name"]]) $filters[$line["name"]] = array();
- $filter["reg_exp"] = $line["reg_exp"];
- $filter["action"] = $line["action"];
- $filter["action_param"] = $line["action_param"];
- $filter["filter_param"] = $line["filter_param"];
- $filter["inverse"] = sql_bool_to_bool($line["inverse"]);
-
- array_push($filters[$line["name"]], $filter);
- }
-
- if ($memcache) $memcache->add($obj_id, $filters, 0, 3600*8);
-
- return $filters;
- }
- }
-
- function get_score_pic($score) {
- if ($score > 100) {
- return "score_high.png";
- } else if ($score > 0) {
- return "score_half_high.png";
- } else if ($score < -100) {
- return "score_low.png";
- } else if ($score < 0) {
- return "score_half_low.png";
- } else {
- return "score_neutral.png";
- }
- }
-
- function feed_has_icon($id) {
- return is_file(ICONS_DIR . "/$id.ico") && filesize(ICONS_DIR . "/$id.ico") > 0;
- }
-
- function init_connection($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);
- // db_query($link, "SET CHARACTER SET " . MYSQL_CHARSET);
- }
- }
- }
-
- function update_feedbrowser_cache($link) {
-
- $result = db_query($link, "SELECT feed_url, site_url, title, COUNT(id) AS subscribers
- FROM ttrss_feeds WHERE (SELECT COUNT(id) = 0 FROM ttrss_feeds AS tf
- WHERE tf.feed_url = ttrss_feeds.feed_url
- AND (private IS true OR auth_login != '' OR auth_pass != '' OR feed_url LIKE '%:%@%/%'))
- GROUP BY feed_url, site_url, title ORDER BY subscribers DESC LIMIT 1000");
-
- db_query($link, "BEGIN");
-
- db_query($link, "DELETE FROM ttrss_feedbrowser_cache");
-
- $count = 0;
-
- while ($line = db_fetch_assoc($result)) {
- $subscribers = db_escape_string($line["subscribers"]);
- $feed_url = db_escape_string($line["feed_url"]);
- $title = db_escape_string($line["title"]);
- $site_url = db_escape_string($line["site_url"]);
-
- $tmp_result = db_query($link, "SELECT subscribers FROM
- ttrss_feedbrowser_cache WHERE feed_url = '$feed_url'");
-
- if (db_num_rows($tmp_result) == 0) {
-
- db_query($link, "INSERT INTO ttrss_feedbrowser_cache
- (feed_url, site_url, title, subscribers) VALUES ('$feed_url',
- '$site_url', '$title', '$subscribers')");
-
- ++$count;
-
- }
-
- }
-
- db_query($link, "COMMIT");
-
- return $count;
-
- }
-
- /* function ccache_zero($link, $feed_id, $owner_uid) {
- db_query($link, "UPDATE ttrss_counters_cache SET
- value = 0, updated = NOW() WHERE
- feed_id = '$feed_id' AND owner_uid = '$owner_uid'");
- } */
-
- function ccache_zero_all($link, $owner_uid) {
- db_query($link, "UPDATE ttrss_counters_cache SET
- value = 0 WHERE owner_uid = '$owner_uid'");
-
- db_query($link, "UPDATE ttrss_cat_counters_cache SET
- value = 0 WHERE owner_uid = '$owner_uid'");
- }
-
- function ccache_remove($link, $feed_id, $owner_uid, $is_cat = false) {
-
- if (!$is_cat) {
- $table = "ttrss_counters_cache";
- } else {
- $table = "ttrss_cat_counters_cache";
- }
-
- db_query($link, "DELETE FROM $table WHERE
- feed_id = '$feed_id' AND owner_uid = '$owner_uid'");
-
- }
-
- function ccache_update_all($link, $owner_uid) {
-
- if (get_pref($link, 'ENABLE_FEED_CATS', $owner_uid)) {
-
- $result = db_query($link, "SELECT feed_id FROM ttrss_cat_counters_cache
- WHERE feed_id > 0 AND owner_uid = '$owner_uid'");
-
- while ($line = db_fetch_assoc($result)) {
- ccache_update($link, $line["feed_id"], $owner_uid, true);
- }
-
- /* We have to manually include category 0 */
-
- ccache_update($link, 0, $owner_uid, true);
-
- } else {
- $result = db_query($link, "SELECT feed_id FROM ttrss_counters_cache
- WHERE feed_id > 0 AND owner_uid = '$owner_uid'");
-
- while ($line = db_fetch_assoc($result)) {
- print ccache_update($link, $line["feed_id"], $owner_uid);
-
- }
-
- }
- }
-
- function ccache_find($link, $feed_id, $owner_uid, $is_cat = false,
- $no_update = false) {
-
- if (!is_numeric($feed_id)) return;
-
- if (!$is_cat) {
- $table = "ttrss_counters_cache";
- if ($feed_id > 0) {
- $tmp_result = db_query($link, "SELECT owner_uid FROM ttrss_feeds
- WHERE id = '$feed_id'");
- $owner_uid = db_fetch_result($tmp_result, 0, "owner_uid");
- }
- } else {
- $table = "ttrss_cat_counters_cache";
- }
-
- if (DB_TYPE == "pgsql") {
- $date_qpart = "updated > NOW() - INTERVAL '15 minutes'";
- } else if (DB_TYPE == "mysql") {
- $date_qpart = "updated > DATE_SUB(NOW(), INTERVAL 15 MINUTE)";
- }
-
- $result = db_query($link, "SELECT value FROM $table
- WHERE owner_uid = '$owner_uid' AND feed_id = '$feed_id'
- LIMIT 1");
-
- if (db_num_rows($result) == 1) {
- return db_fetch_result($result, 0, "value");
- } else {
- if ($no_update) {
- return -1;
- } else {
- return ccache_update($link, $feed_id, $owner_uid, $is_cat);
- }
- }
-
- }
-
- function ccache_update($link, $feed_id, $owner_uid, $is_cat = false,
- $update_pcat = true) {
-
- if (!is_numeric($feed_id)) return;
-
- if (!$is_cat && $feed_id > 0) {
- $tmp_result = db_query($link, "SELECT owner_uid FROM ttrss_feeds
- WHERE id = '$feed_id'");
- $owner_uid = db_fetch_result($tmp_result, 0, "owner_uid");
- }
-
- $prev_unread = ccache_find($link, $feed_id, $owner_uid, $is_cat, true);
-
- /* When updating a label, all we need to do is recalculate feed counters
- * because labels are not cached */
-
- if ($feed_id < 0) {
- ccache_update_all($link, $owner_uid);
- return;
- }
-
- if (!$is_cat) {
- $table = "ttrss_counters_cache";
- } else {
- $table = "ttrss_cat_counters_cache";
- }
-
- if ($is_cat && $feed_id >= 0) {
- if ($feed_id != 0) {
- $cat_qpart = "cat_id = '$feed_id'";
- } else {
- $cat_qpart = "cat_id IS NULL";
- }
-
- /* Recalculate counters for child feeds */
-
- $result = db_query($link, "SELECT id FROM ttrss_feeds
- WHERE owner_uid = '$owner_uid' AND $cat_qpart");
-
- while ($line = db_fetch_assoc($result)) {
- ccache_update($link, $line["id"], $owner_uid, false, false);
- }
-
- $result = db_query($link, "SELECT SUM(value) AS sv
- FROM ttrss_counters_cache, ttrss_feeds
- WHERE id = feed_id AND $cat_qpart AND
- ttrss_feeds.owner_uid = '$owner_uid'");
-
- $unread = (int) db_fetch_result($result, 0, "sv");
-
- } else {
- $unread = (int) getFeedArticles($link, $feed_id, $is_cat, true, $owner_uid);
- }
-
- db_query($link, "BEGIN");
-
- $result = db_query($link, "SELECT feed_id FROM $table
- WHERE owner_uid = '$owner_uid' AND feed_id = '$feed_id' LIMIT 1");
-
- if (db_num_rows($result) == 1) {
- db_query($link, "UPDATE $table SET
- value = '$unread', updated = NOW() WHERE
- feed_id = '$feed_id' AND owner_uid = '$owner_uid'");
-
- } else {
- db_query($link, "INSERT INTO $table
- (feed_id, value, owner_uid, updated)
- VALUES
- ($feed_id, $unread, $owner_uid, NOW())");
- }
-
- db_query($link, "COMMIT");
-
- if ($feed_id > 0 && $prev_unread != $unread) {
-
- if (!$is_cat) {
-
- /* Update parent category */
-
- if ($update_pcat) {
-
- $result = db_query($link, "SELECT cat_id FROM ttrss_feeds
- WHERE owner_uid = '$owner_uid' AND id = '$feed_id'");
-
- $cat_id = (int) db_fetch_result($result, 0, "cat_id");
-
- ccache_update($link, $cat_id, $owner_uid, true);
-
- }
- }
- } else if ($feed_id < 0) {
- ccache_update_all($link, $owner_uid);
- }
-
- return $unread;
- }
-
- /* function ccache_cleanup($link, $owner_uid) {
-
- if (DB_TYPE == "pgsql") {
- db_query($link, "DELETE FROM ttrss_counters_cache AS c1 WHERE
- (SELECT count(*) FROM ttrss_counters_cache AS c2
- WHERE c1.feed_id = c2.feed_id AND c2.owner_uid = c1.owner_uid) > 1
- AND owner_uid = '$owner_uid'");
-
- db_query($link, "DELETE FROM ttrss_cat_counters_cache AS c1 WHERE
- (SELECT count(*) FROM ttrss_cat_counters_cache AS c2
- WHERE c1.feed_id = c2.feed_id AND c2.owner_uid = c1.owner_uid) > 1
- AND owner_uid = '$owner_uid'");
- } else {
- db_query($link, "DELETE c1 FROM
- ttrss_counters_cache AS c1,
- ttrss_counters_cache AS c2
- WHERE
- c1.owner_uid = '$owner_uid' AND
- c1.owner_uid = c2.owner_uid AND
- c1.feed_id = c2.feed_id");
-
- db_query($link, "DELETE c1 FROM
- ttrss_cat_counters_cache AS c1,
- ttrss_cat_counters_cache AS c2
- WHERE
- c1.owner_uid = '$owner_uid' AND
- c1.owner_uid = c2.owner_uid AND
- c1.feed_id = c2.feed_id");
-
- }
- } */
-
- function label_find_id($link, $label, $owner_uid) {
- $result = db_query($link,
- "SELECT id FROM ttrss_labels2 WHERE caption = '$label'
- AND owner_uid = '$owner_uid' LIMIT 1");
-
- if (db_num_rows($result) == 1) {
- return db_fetch_result($result, 0, "id");
- } else {
- return 0;
- }
- }
-
- function get_article_labels($link, $id) {
- global $memcache;
-
- $obj_id = md5("LABELS:$id:" . $_SESSION["uid"]);
-
- $rv = array();
-
- if ($memcache && $obj = $memcache->get($obj_id)) {
- return $obj;
- } else {
-
- $result = db_query($link, "SELECT label_cache FROM
- ttrss_user_entries WHERE ref_id = '$id' AND owner_uid = " .
- $_SESSION["uid"]);
-
- $label_cache = db_fetch_result($result, 0, "label_cache");
-
- if ($label_cache) {
-
- $label_cache = json_decode($label_cache, true);
-
- if ($label_cache["no-labels"] == 1)
- return $rv;
- else
- return $label_cache;
- }
-
- $result = db_query($link,
- "SELECT DISTINCT label_id,caption,fg_color,bg_color
- FROM ttrss_labels2, ttrss_user_labels2
- WHERE id = label_id
- AND article_id = '$id'
- AND owner_uid = ".$_SESSION["uid"] . "
- ORDER BY caption");
-
- while ($line = db_fetch_assoc($result)) {
- $rk = array($line["label_id"], $line["caption"], $line["fg_color"],
- $line["bg_color"]);
- array_push($rv, $rk);
- }
- if ($memcache) $memcache->add($obj_id, $rv, 0, 3600);
-
- if (count($rv) > 0)
- label_update_cache($link, $id, $rv);
- else
- label_update_cache($link, $id, array("no-labels" => 1));
- }
-
- return $rv;
- }
-
-
- function label_find_caption($link, $label, $owner_uid) {
- $result = db_query($link,
- "SELECT caption FROM ttrss_labels2 WHERE id = '$label'
- AND owner_uid = '$owner_uid' LIMIT 1");
-
- if (db_num_rows($result) == 1) {
- return db_fetch_result($result, 0, "caption");
- } else {
- return "";
- }
- }
-
- function label_update_cache($link, $id, $labels = false, $force = false) {
-
- if ($force)
- label_clear_cache($link, $id);
-
- if (!$labels)
- $labels = get_article_labels($link, $id);
-
- $labels = db_escape_string(json_encode($labels));
-
- db_query($link, "UPDATE ttrss_user_entries SET
- label_cache = '$labels' WHERE ref_id = '$id'");
-
- }
-
- function label_clear_cache($link, $id) {
-
- db_query($link, "UPDATE ttrss_user_entries SET
- label_cache = '' WHERE ref_id = '$id'");
-
- }
-
- function label_remove_article($link, $id, $label, $owner_uid) {
-
- $label_id = label_find_id($link, $label, $owner_uid);
-
- if (!$label_id) return;
-
- $result = db_query($link,
- "DELETE FROM ttrss_user_labels2
- WHERE
- label_id = '$label_id' AND
- article_id = '$id'");
-
- label_clear_cache($link, $id);
- }
-
- function label_add_article($link, $id, $label, $owner_uid) {
-
- global $memcache;
-
- if ($memcache) {
- $obj_id = md5("LABELS:$id:$owner_uid");
- $memcache->delete($obj_id);
- }
-
- $label_id = label_find_id($link, $label, $owner_uid);
-
- if (!$label_id) return;
-
- $result = db_query($link,
- "SELECT
- article_id FROM ttrss_labels2, ttrss_user_labels2
- WHERE
- label_id = id AND
- label_id = '$label_id' AND
- article_id = '$id' AND owner_uid = '$owner_uid'
- LIMIT 1");
-
- if (db_num_rows($result) == 0) {
- db_query($link, "INSERT INTO ttrss_user_labels2
- (label_id, article_id) VALUES ('$label_id', '$id')");
- }
-
- label_clear_cache($link, $id);
-
- }
-
- function label_remove($link, $id, $owner_uid) {
- global $memcache;
-
- if (!$owner_uid) $owner_uid = $_SESSION["uid"];
-
- if ($memcache) {
- $obj_id = md5("LABELS:$id:$owner_uid");
- $memcache->delete($obj_id);
- }
-
- db_query($link, "BEGIN");
-
- $result = db_query($link, "SELECT caption FROM ttrss_labels2
- WHERE id = '$id'");
-
- $caption = db_fetch_result($result, 0, "caption");
-
- $result = db_query($link, "DELETE FROM ttrss_labels2 WHERE id = '$id'
- AND owner_uid = " . $owner_uid);
-
- if (db_affected_rows($link, $result) != 0 && $caption) {
-
- /* Remove access key for the label */
-
- $ext_id = -11 - $id;
-
- db_query($link, "DELETE FROM ttrss_access_keys WHERE
- feed_id = '$ext_id' AND owner_uid = $owner_uid");
-
- /* Disable filters that reference label being removed */
-
- db_query($link, "UPDATE ttrss_filters SET
- enabled = false WHERE action_param = '$caption'
- AND action_id = 7
- AND owner_uid = " . $owner_uid);
-
- /* Remove cached data */
-
- db_query($link, "UPDATE ttrss_user_entries SET label_cache = ''
- WHERE label_cache LIKE '%$caption%' AND owner_uid = " . $owner_uid);
-
- }
-
- db_query($link, "COMMIT");
- }
-
- function label_create($link, $caption) {
-
- db_query($link, "BEGIN");
-
- $result = false;
-
- $result = db_query($link, "SELECT id FROM ttrss_labels2
- WHERE caption = '$caption' AND owner_uid = ". $_SESSION["uid"]);
-
- if (db_num_rows($result) == 0) {
- $result = db_query($link,
- "INSERT INTO ttrss_labels2 (caption,owner_uid)
- VALUES ('$caption', '".$_SESSION["uid"]."')");
-
- $result = db_affected_rows($link, $result) != 0;
- }
-
- db_query($link, "COMMIT");
-
- return $result;
- }
-
- function format_tags_string($tags, $id) {
-
- $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);
- }
-
- $tag_str = "<a href=\"javascript:viewfeed('$tag_escaped')\">$tag</a>";
-
- array_push($formatted_tags, $tag_str);
-
- $tmp_tags_str = implode(", ", $formatted_tags);
-
- if ($num_tags == $tag_limit || mb_strlen($tmp_tags_str) > 150) {
- break;
- }
- }
-
- $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) {
-
- $labels_str = "";
-
- foreach ($labels as $l) {
- $labels_str .= sprintf("<span class='hlLabelRef'
- style='color : %s; background-color : %s'>%s</span>",
- $l[2], $l[3], $l[1]);
- }
-
- return $labels_str;
-
- }
-
- function format_article_note($id, $note) {
-
- $str = "<div class='articleNote' onclick=\"editArticleNote($id)\">
- <div class='noteEdit' onclick=\"editArticleNote($id)\">".
- __('(edit note)')."</div>$note</div>";
-
- 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 remove_feed($link, $id, $owner_uid) {
-
- if ($id > 0) {
-
- /* save starred articles in Archived feed */
-
- db_query($link, "BEGIN");
-
- /* prepare feed if necessary */
-
- $result = db_query($link, "SELECT id FROM ttrss_archived_feeds
- WHERE id = '$id'");
-
- if (db_num_rows($result) == 0) {
- db_query($link, "INSERT INTO ttrss_archived_feeds
- (id, owner_uid, title, feed_url, site_url)
- SELECT id, owner_uid, title, feed_url, site_url from ttrss_feeds
- WHERE id = '$id'");
- }
-
- db_query($link, "UPDATE ttrss_user_entries SET feed_id = NULL,
- orig_feed_id = '$id' WHERE feed_id = '$id' AND
- marked = true AND owner_uid = $owner_uid");
-
- /* Remove access key for the feed */
-
- db_query($link, "DELETE FROM ttrss_access_keys WHERE
- feed_id = '$id' AND owner_uid = $owner_uid");
-
- /* remove the feed */
-
- db_query($link, "DELETE FROM ttrss_feeds
- WHERE id = '$id' AND owner_uid = $owner_uid");
-
- db_query($link, "COMMIT");
-
- if (file_exists(ICONS_DIR . "/$id.ico")) {
- unlink(ICONS_DIR . "/$id.ico");
- }
-
- ccache_remove($link, $id, $owner_uid);
-
- } else {
- label_remove($link, -11-$id, $owner_uid);
- ccache_remove($link, -11-$id, $owner_uid);
- }
- }
-
- function add_feed_category($link, $feed_cat) {
-
- if (!$feed_cat) return false;
-
- db_query($link, "BEGIN");
-
- $result = db_query($link,
- "SELECT id FROM ttrss_feed_categories
- WHERE title = '$feed_cat' AND owner_uid = ".$_SESSION["uid"]);
-
- if (db_num_rows($result) == 0) {
-
- $result = db_query($link,
- "INSERT INTO ttrss_feed_categories (owner_uid,title)
- VALUES ('".$_SESSION["uid"]."', '$feed_cat')");
-
- db_query($link, "COMMIT");
-
- return true;
- }
-
- return false;
- }
-
- function remove_feed_category($link, $id, $owner_uid) {
-
- db_query($link, "DELETE FROM ttrss_feed_categories
- WHERE id = '$id' AND owner_uid = $owner_uid");
-
- ccache_remove($link, $id, $owner_uid, true);
- }
-
- function archive_article($link, $id, $owner_uid) {
- db_query($link, "BEGIN");
-
- $result = db_query($link, "SELECT feed_id FROM ttrss_user_entries
- WHERE ref_id = '$id' AND owner_uid = $owner_uid");
-
- if (db_num_rows($result) != 0) {
-
- /* prepare the archived table */
-
- $feed_id = (int) db_fetch_result($result, 0, "feed_id");
-
- if ($feed_id) {
- $result = db_query($link, "SELECT id FROM ttrss_archived_feeds
- WHERE id = '$feed_id'");
-
- if (db_num_rows($result) == 0) {
- db_query($link, "INSERT INTO ttrss_archived_feeds
- (id, owner_uid, title, feed_url, site_url)
- SELECT id, owner_uid, title, feed_url, site_url from ttrss_feeds
- WHERE id = '$feed_id'");
- }
-
- db_query($link, "UPDATE ttrss_user_entries
- SET orig_feed_id = feed_id, feed_id = NULL
- WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
- }
- }
-
- db_query($link, "COMMIT");
- }
-
- function getArticleFeed($link, $id) {
- $result = db_query($link, "SELECT feed_id FROM ttrss_user_entries
- WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
-
- if (db_num_rows($result) != 0) {
- return db_fetch_result($result, 0, "feed_id");
- } else {
- return 0;
- }
- }
-
- /**
- * Fixes incomplete URLs by prepending "http://".
- * Also replaces feed:// with http://, and
- * prepends a trailing slash if the url is a domain name only.
- *
- * @param string $url Possibly incomplete URL
- *
- * @return string Fixed URL.
- */
- function fix_url($url) {
- if (strpos($url, '://') === false) {
- $url = 'http://' . $url;
- } else if (substr($url, 0, 5) == 'feed:') {
- $url = 'http:' . substr($url, 5);
- }
-
- //prepend slash if the URL has no slash in it
- // "http://www.example" -> "http://www.example/"
- if (strpos($url, '/', strpos($url, ':') + 3) === false) {
- $url .= '/';
- }
-
- if ($url != "http:///")
- return $url;
- else
- return '';
- }
-
- function validate_feed_url($url) {
- $parts = parse_url($url);
-
- return ($parts['scheme'] == 'http' || $parts['scheme'] == 'feed' || $parts['scheme'] == 'https');
-
- }
-
- function get_article_enclosures($link, $id) {
-
- global $memcache;
-
- $query = "SELECT * FROM ttrss_enclosures
- WHERE post_id = '$id' AND content_url != ''";
-
- $obj_id = md5("ENCLOSURES:$id");
-
- $rv = array();
-
- if ($memcache && $obj = $memcache->get($obj_id)) {
- $rv = $obj;
- } else {
- $result = db_query($link, $query);
-
- if (db_num_rows($result) > 0) {
- while ($line = db_fetch_assoc($result)) {
- array_push($rv, $line);
- }
- if ($memcache) $memcache->add($obj_id, $rv, 0, 3600);
- }
- }
-
- return $rv;
- }
-
- function api_get_feeds($link, $cat_id, $unread_only, $limit, $offset) {
-
- $feeds = array();
-
- /* Labels */
-
- if ($cat_id == -4 || $cat_id == -2) {
- $counters = getLabelCounters($link, true);
-
- foreach (array_values($counters) as $cv) {
-
- $unread = $cv["counter"];
-
- if ($unread || !$unread_only) {
-
- $row = array(
- "id" => $cv["id"],
- "title" => $cv["description"],
- "unread" => $cv["counter"],
- "cat_id" => -2,
- );
-
- array_push($feeds, $row);
- }
- }
- }
-
- /* Virtual feeds */
-
- if ($cat_id == -4 || $cat_id == -1) {
- foreach (array(-1, -2, -3, -4, 0) as $i) {
- $unread = getFeedUnread($link, $i);
-
- if ($unread || !$unread_only) {
- $title = getFeedTitle($link, $i);
-
- $row = array(
- "id" => $i,
- "title" => $title,
- "unread" => $unread,
- "cat_id" => -1,
- );
- array_push($feeds, $row);
- }
-
- }
- }
-
- /* Real feeds */
-
- if ($limit) {
- $limit_qpart = "LIMIT $limit OFFSET $offset";
- } else {
- $limit_qpart = "";
- }
-
- if ($cat_id == -4 || $cat_id == -3) {
- $result = db_query($link, "SELECT
- id, feed_url, cat_id, title, ".
- SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated
- FROM ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"] .
- " ORDER BY cat_id, title " . $limit_qpart);
- } else {
-
- if ($cat_id)
- $cat_qpart = "cat_id = '$cat_id'";
- else
- $cat_qpart = "cat_id IS NULL";
-
- $result = db_query($link, "SELECT
- id, feed_url, cat_id, title, ".
- SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated
- FROM ttrss_feeds WHERE
- $cat_qpart AND owner_uid = " . $_SESSION["uid"] .
- " ORDER BY cat_id, title " . $limit_qpart);
- }
-
- while ($line = db_fetch_assoc($result)) {
-
- $unread = getFeedUnread($link, $line["id"]);
-
- $has_icon = feed_has_icon($line['id']);
-
- if ($unread || !$unread_only) {
-
- $row = array(
- "feed_url" => $line["feed_url"],
- "title" => $line["title"],
- "id" => (int)$line["id"],
- "unread" => (int)$unread,
- "has_icon" => $has_icon,
- "cat_id" => (int)$line["cat_id"],
- "last_updated" => strtotime($line["last_updated"])
- );
-
- array_push($feeds, $row);
- }
- }
-
- return $feeds;
- }
-
- function api_get_headlines($link, $feed_id, $limit, $offset,
- $filter, $is_cat, $show_excerpt, $show_content, $view_mode, $order,
- $include_attachments, $since_id) {
-
- /* do not rely on params below */
-
- $search = db_escape_string($_REQUEST["search"]);
- $search_mode = db_escape_string($_REQUEST["search_mode"]);
- $match_on = db_escape_string($_REQUEST["match_on"]);
-
- $qfh_ret = queryFeedHeadlines($link, $feed_id, $limit,
- $view_mode, $is_cat, $search, $search_mode, $match_on,
- $order, $offset, 0, false, $since_id);
-
- $result = $qfh_ret[0];
- $feed_title = $qfh_ret[1];
-
- $headlines = array();
-
- while ($line = db_fetch_assoc($result)) {
- $is_updated = ($line["last_read"] == "" &&
- ($line["unread"] != "t" && $line["unread"] != "1"));
-
- $tags = explode(",", $line["tag_cache"]);
- $labels = json_decode($line["label_cache"], true);
-
- //if (!$tags) $tags = get_article_tags($link, $line["id"]);
- //if (!$labels) $labels = get_article_labels($link, $line["id"]);
-
- $headline_row = array(
- "id" => (int)$line["id"],
- "unread" => sql_bool_to_bool($line["unread"]),
- "marked" => sql_bool_to_bool($line["marked"]),
- "published" => sql_bool_to_bool($line["published"]),
- "updated" => strtotime($line["updated"]),
- "is_updated" => $is_updated,
- "title" => $line["title"],
- "link" => $line["link"],
- "feed_id" => $line["feed_id"],
- "tags" => $tags,
- );
-
- if ($include_attachments)
- $headline_row['attachments'] = get_article_enclosures($link,
- $line['id']);
-
- if ($show_excerpt) {
- $excerpt = truncate_string(strip_tags($line["content_preview"]), 100);
- $headline_row["excerpt"] = $excerpt;
- }
-
- if ($show_content) {
- $headline_row["content"] = $line["content_preview"];
- }
-
- // unify label output to ease parsing
- if ($labels["no-labels"] == 1) $labels = array();
-
- $headline_row["labels"] = $labels;
-
- array_push($headlines, $headline_row);
- }
-
- return $headlines;
- }
-
- function generate_error_feed($link, $error) {
- $reply = array();
-
- $reply['headlines']['id'] = -6;
- $reply['headlines']['is_cat'] = false;
-
- $reply['headlines']['toolbar'] = '';
- $reply['headlines']['content'] = "<div class='whiteBox'>". $error . "</div>";
-
- $reply['headlines-info'] = array("count" => 0,
- "vgroup_last_feed" => '',
- "unread" => 0,
- "disable_cache" => true);
-
- return $reply;
- }
-
-
- function generate_dashboard_feed($link) {
- $reply = array();
-
- $reply['headlines']['id'] = -5;
- $reply['headlines']['is_cat'] = false;
-
- $reply['headlines']['toolbar'] = '';
- $reply['headlines']['content'] = "<div class='whiteBox'>".__('No feed selected.');
-
- $reply['headlines']['content'] .= "<p class=\"small\"><span class=\"insensitive\">";
-
- $result = db_query($link, "SELECT ".SUBSTRING_FOR_DATE."(MAX(last_updated), 1, 19) AS last_updated FROM ttrss_feeds
- WHERE owner_uid = " . $_SESSION['uid']);
-
- $last_updated = db_fetch_result($result, 0, "last_updated");
- $last_updated = make_local_datetime($link, $last_updated, false);
-
- $reply['headlines']['content'] .= sprintf(__("Feeds last updated at %s"), $last_updated);
-
- $result = db_query($link, "SELECT COUNT(id) AS num_errors
- FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ".$_SESSION["uid"]);
-
- $num_errors = db_fetch_result($result, 0, "num_errors");
-
- if ($num_errors > 0) {
- $reply['headlines']['content'] .= "<br/>";
- $reply['headlines']['content'] .= "<a class=\"insensitive\" href=\"#\" onclick=\"showFeedsWithErrors()\">".
- __('Some feeds have update errors (click for details)')."</a>";
- }
- $reply['headlines']['content'] .= "</span></p>";
-
- $reply['headlines-info'] = array("count" => 0,
- "vgroup_last_feed" => '',
- "unread" => 0,
- "disable_cache" => true);
-
- return $reply;
- }
-
- function save_email_address($link, $email) {
- // FIXME: implement persistent storage of emails
-
- if (!$_SESSION['stored_emails'])
- $_SESSION['stored_emails'] = array();
-
- if (!in_array($email, $_SESSION['stored_emails']))
- array_push($_SESSION['stored_emails'], $email);
- }
-
- function update_feed_access_key($link, $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
- WHERE feed_id = '$feed_id' AND is_cat = $sql_is_cat
- AND owner_uid = " . $owner_uid);
-
- if (db_num_rows($result) == 1) {
- $key = db_escape_string(sha1(uniqid(rand(), true)));
-
- db_query($link, "UPDATE ttrss_access_keys SET access_key = '$key'
- WHERE feed_id = '$feed_id' AND is_cat = $sql_is_cat
- AND owner_uid = " . $owner_uid);
-
- return $key;
-
- } else {
- return get_feed_access_key($link, $feed_id, $is_cat, $owner_uid);
- }
- }
-
- function get_feed_access_key($link, $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
- WHERE feed_id = '$feed_id' AND is_cat = $sql_is_cat
- AND owner_uid = " . $owner_uid);
-
- if (db_num_rows($result) == 1) {
- return db_fetch_result($result, 0, "access_key");
- } else {
- $key = db_escape_string(sha1(uniqid(rand(), true)));
-
- $result = db_query($link, "INSERT INTO ttrss_access_keys
- (access_key, feed_id, is_cat, owner_uid)
- VALUES ('$key', '$feed_id', $sql_is_cat, '$owner_uid')");
-
- return $key;
- }
- return false;
- }
-
- /**
- * Extracts RSS/Atom feed URLs from the given HTML URL.
- *
- * @param string $url HTML page URL
- *
- * @return array Array of feeds. Key is the full URL, value the title
- */
- function get_feeds_from_html($url, $login = false, $pass = false)
- {
- $url = fix_url($url);
- $baseUrl = substr($url, 0, strrpos($url, '/') + 1);
-
- libxml_use_internal_errors(true);
-
- $content = @fetch_file_contents($url, false, $login, $pass);
-
- $doc = new DOMDocument();
- $doc->loadHTML($content);
- $xpath = new DOMXPath($doc);
- $entries = $xpath->query('/html/head/link[@rel="alternate"]');
- $feedUrls = array();
- foreach ($entries as $entry) {
- if ($entry->hasAttribute('href')) {
- $title = $entry->getAttribute('title');
- if ($title == '') {
- $title = $entry->getAttribute('type');
- }
- $feedUrl = rewrite_relative_url(
- $baseUrl, $entry->getAttribute('href')
- );
- $feedUrls[$feedUrl] = $title;
- }
- }
- return $feedUrls;
- }
-
- /**
- * Checks if the content behind the given URL is a HTML file
- *
- * @param string $url URL to check
- *
- * @return boolean True if the URL contains HTML content
- */
- function url_is_html($url, $login = false, $pass = false) {
- $content = substr(fetch_file_contents($url, false, $login, $pass), 0, 1000);
-
- if (stripos($content, '<html>') === false
- && stripos($content, '<html ') === false
- ) {
- return false;
- }
-
- return true;
- }
-
- function print_label_select($link, $name, $value, $attributes = "") {
-
- $result = db_query($link, "SELECT caption FROM ttrss_labels2
- WHERE owner_uid = '".$_SESSION["uid"]."' ORDER BY caption");
-
- print "<select default=\"$value\" name=\"" . htmlspecialchars($name) .
- "\" $attributes onchange=\"labelSelectOnChange(this)\" >";
-
- while ($line = db_fetch_assoc($result)) {
-
- $issel = ($line["caption"] == $value) ? "selected=\"1\"" : "";
-
- print "<option value=\"".htmlspecialchars($line["caption"])."\"
- $issel>" . htmlspecialchars($line["caption"]) . "</option>";
-
- }
-
-# print "<option value=\"ADD_LABEL\">" .__("Add label...") . "</option>";
-
- print "</select>";
-
-
- }
-
- function format_article_enclosures($link, $id, $always_display_enclosures,
- $article_content) {
-
- $result = get_article_enclosures($link, $id);
- $rv = '';
-
- if (count($result) > 0) {
-
- $entries_html = array();
- $entries = array();
-
- foreach ($result as $line) {
-
- $url = $line["content_url"];
- $ctype = $line["content_type"];
-
- if (!$ctype) $ctype = __("unknown type");
-
-# $filename = substr($url, strrpos($url, "/")+1);
-
- $entry = format_inline_player($link, $url, $ctype);
-
-# $entry .= " <a target=\"_blank\" href=\"" . htmlspecialchars($url) . "\">" .
-# $filename . " (" . $ctype . ")" . "</a>";
-
- array_push($entries_html, $entry);
-
- $entry = array();
-
- $entry["type"] = $ctype;
- $entry["filename"] = $filename;
- $entry["url"] = $url;
-
- array_push($entries, $entry);
- }
-
- $rv .= "<div class=\"postEnclosures\">";
-
- if (!get_pref($link, "STRIP_IMAGES")) {
- if ($always_display_enclosures ||
- !preg_match("/<img/i", $article_content)) {
-
- foreach ($entries as $entry) {
-
- 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 (count($entries) == 1) {
- $rv .= __("Attachment:") . " ";
- } else {
- $rv .= __("Attachments:") . " ";
- }
-
- $rv .= join(", ", $entries_html);
-
- $rv .= "</div>";
- }
-
- return $rv;
- }
-
- function getLastArticleId($link) {
- $result = db_query($link, "SELECT MAX(ref_id) AS id FROM ttrss_user_entries
- WHERE owner_uid = " . $_SESSION["uid"]);
-
- if (db_num_rows($result) == 1) {
- return db_fetch_result($result, 0, "id");
- } else {
- return -1;
- }
- }
-
- function build_url($parts) {
- return $parts['scheme'] . "://" . $parts['host'] . $parts['path'];
- }
-
- /**
- * Converts a (possibly) relative URL to a absolute one.
- *
- * @param string $url Base URL (i.e. from where the document is)
- * @param string $rel_url Possibly relative URL in the document
- *
- * @return string Absolute URL
- */
- function rewrite_relative_url($url, $rel_url) {
- if (strpos($rel_url, "://") !== false) {
- return $rel_url;
- } else if (strpos($rel_url, "/") === 0)
- {
- $parts = parse_url($url);
- $parts['path'] = $rel_url;
-
- return build_url($parts);
-
- } else {
- $parts = parse_url($url);
- if (!isset($parts['path'])) {
- $parts['path'] = '/';
- }
- $dir = $parts['path'];
- if (substr($dir, -1) !== '/') {
- $dir = dirname($parts['path']);
- $dir !== '/' && $dir .= '/';
- }
- $parts['path'] = $dir . $rel_url;
-
- return build_url($parts);
- }
- }
-
- function sphinx_search($query, $offset = 0, $limit = 30) {
- require_once 'lib/sphinxapi.php';
-
- $sphinxClient = new SphinxClient();
-
- $sphinxClient->SetServer('localhost', 9312);
- $sphinxClient->SetConnectTimeout(1);
-
- $sphinxClient->SetFieldWeights(array('title' => 70, 'content' => 30,
- 'feed_title' => 20));
-
- $sphinxClient->SetMatchMode(SPH_MATCH_EXTENDED2);
- $sphinxClient->SetRankingMode(SPH_RANK_PROXIMITY_BM25);
- $sphinxClient->SetLimits($offset, $limit, 1000);
- $sphinxClient->SetArrayResult(false);
- $sphinxClient->SetFilter('owner_uid', array($_SESSION['uid']));
-
- $result = $sphinxClient->Query($query, SPHINX_INDEX);
-
- $ids = array();
-
- if (is_array($result['matches'])) {
- foreach (array_keys($result['matches']) as $int_id) {
- $ref_id = $result['matches'][$int_id]['attrs']['ref_id'];
- array_push($ids, $ref_id);
- }
- }
-
- return $ids;
- }
-
- function cleanup_tags($link, $days = 14, $limit = 1000) {
-
- if (DB_TYPE == "pgsql") {
- $interval_query = "date_updated < NOW() - INTERVAL '$days days'";
- } else if (DB_TYPE == "mysql") {
- $interval_query = "date_updated < DATE_SUB(NOW(), INTERVAL $days DAY)";
- }
-
- $tags_deleted = 0;
-
- while ($limit > 0) {
- $limit_part = 500;
-
- $query = "SELECT ttrss_tags.id AS id
- FROM ttrss_tags, ttrss_user_entries, ttrss_entries
- 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);
-
- $ids = array();
-
- while ($line = db_fetch_assoc($result)) {
- array_push($ids, $line['id']);
- }
-
- 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);
- } else {
- break;
- }
-
- $limit -= $limit_part;
- }
-
- print "\n";
-
- return $tags_deleted;
- }
-
- function feedlist_init_cat($link, $cat_id, $hidden = false) {
- $obj = array();
- $cat_id = (int) $cat_id;
-
- if ($cat_id > 0) {
- $cat_unread = ccache_find($link, $cat_id, $_SESSION["uid"], true);
- } else if ($cat_id == 0 || $cat_id == -2) {
- $cat_unread = getCategoryUnread($link, $cat_id);
- }
-
- $obj['id'] = 'CAT:' . $cat_id;
- $obj['items'] = array();
- $obj['name'] = getCategoryTitle($link, $cat_id);
- $obj['type'] = 'feed';
- $obj['unread'] = (int) $cat_unread;
- $obj['hidden'] = $hidden;
- $obj['bare_id'] = $cat_id;
-
- return $obj;
- }
-
- function feedlist_init_feed($link, $feed_id, $title = false, $unread = false, $error = '', $updated = '') {
- $obj = array();
- $feed_id = (int) $feed_id;
-
- if (!$title)
- $title = getFeedTitle($link, $feed_id, false);
-
- if ($unread === false)
- $unread = getFeedUnread($link, $feed_id, false);
-
- $obj['id'] = 'FEED:' . $feed_id;
- $obj['name'] = $title;
- $obj['unread'] = (int) $unread;
- $obj['type'] = 'feed';
- $obj['error'] = $error;
- $obj['updated'] = $updated;
- $obj['icon'] = getFeedIcon($feed_id);
- $obj['bare_id'] = $feed_id;
-
- return $obj;
- }
-
-
- function fetch_twitter_rss($link, $url, $owner_uid) {
-
- require_once 'lib/tmhoauth/tmhOAuth.php';
-
- $result = db_query($link, "SELECT twitter_oauth FROM ttrss_users
- WHERE id = $owner_uid");
-
- $access_token = json_decode(db_fetch_result($result, 0, 'twitter_oauth'), true);
- $url_escaped = db_escape_string($url);
-
- if ($access_token) {
-
- $tmhOAuth = new tmhOAuth(array(
- 'consumer_key' => CONSUMER_KEY,
- 'consumer_secret' => CONSUMER_SECRET,
- 'user_token' => $access_token['oauth_token'],
- 'user_secret' => $access_token['oauth_token_secret'],
- ));
-
- $code = $tmhOAuth->request('GET', $url);
-
- if ($code == 200) {
-
- $content = $tmhOAuth->response['response'];
-
- define('MAGPIE_CACHE_ON', false);
-
- $rss = new MagpieRSS($content, MAGPIE_OUTPUT_ENCODING,
- MAGPIE_INPUT_ENCODING, MAGPIE_DETECT_ENCODING );
-
- return $rss;
-
- } else {
-
- db_query($link, "UPDATE ttrss_feeds
- SET last_error = 'OAuth authorization failed ($code).'
- WHERE feed_url = '$url_escaped' AND owner_uid = $owner_uid");
- }
-
- } else {
-
- db_query($link, "UPDATE ttrss_feeds
- SET last_error = 'OAuth information not found.'
- WHERE feed_url = '$url_escaped' AND owner_uid = $owner_uid");
-
- return false;
- }
- }
-
- function print_user_stylesheet($link) {
- $value = get_pref($link, 'USER_STYLESHEET');
-
- if ($value) {
- print "<style type=\"text/css\">";
- print str_replace("<br/>", "\n", $value);
- print "</style>";
- }
-
- }
-
- function rewrite_urls($line) {
- global $url_regex;
-
- $urls = null;
-
- $result = preg_replace("/((?<!=.)((http|https|ftp)+):\/\/[^ ,!]+)/i",
- "<a target=\"_blank\" href=\"\\1\">\\1</a>", $line);
-
- return $result;
- }
-
- function filter_to_sql($filter) {
- $query = "";
-
- if (DB_TYPE == "pgsql")
- $reg_qpart = "~";
- else
- $reg_qpart = "REGEXP";
-
- switch ($filter["type"]) {
- case "title":
- $query = "LOWER(ttrss_entries.title) $reg_qpart LOWER('".
- $filter['reg_exp'] . "')";
- break;
- case "content":
- $query = "LOWER(ttrss_entries.content) $reg_qpart LOWER('".
- $filter['reg_exp'] . "')";
- break;
- case "both":
- $query = "LOWER(ttrss_entries.title) $reg_qpart LOWER('".
- $filter['reg_exp'] . "') OR LOWER(" .
- "ttrss_entries.content) $reg_qpart LOWER('" . $filter['reg_exp'] . "')";
- break;
- case "tag":
- $query = "LOWER(ttrss_user_entries.tag_cache) $reg_qpart LOWER('".
- $filter['reg_exp'] . "')";
- break;
- case "link":
- $query = "LOWER(ttrss_entries.link) $reg_qpart LOWER('".
- $filter['reg_exp'] . "')";
- break;
- case "date":
-
- if ($filter["filter_param"] == "before")
- $cmp_qpart = "<";
- else
- $cmp_qpart = ">=";
-
- $timestamp = date("Y-m-d H:N:s", strtotime($filter["reg_exp"]));
- $query = "ttrss_entries.date_entered $cmp_qpart '$timestamp'";
- break;
- case "author":
- $query = "LOWER(ttrss_entries.author) $reg_qpart LOWER('".
- $filter['reg_exp'] . "')";
- break;
- }
-
- if ($filter["inverse"])
- $query = "NOT ($query)";
-
- if ($query) {
- if (DB_TYPE == "pgsql") {
- $query = " ($query) AND ttrss_entries.date_entered > NOW() - INTERVAL '14 days'";
- } else {
- $query = " ($query) AND ttrss_entries.date_entered > DATE_SUB(NOW(), INTERVAL 14 DAY)";
- }
- $query .= " AND ";
- }
-
-
- return $query;
- }
-
- // Status codes:
- // -1 - never connected
- // 0 - no data received
- // 1 - data received successfully
- // 2 - did not receive valid data
- // >10 - server error, code + 10 (e.g. 16 means server error 6)
-
- function get_linked_feeds($link, $instance_id = false) {
- if ($instance_id)
- $instance_qpart = "id = '$instance_id' AND ";
- else
- $instance_qpart = "";
-
- if (DB_TYPE == "pgsql") {
- $date_qpart = "last_connected < NOW() - INTERVAL '6 hours'";
- } else {
- $date_qpart = "last_connected < DATE_SUB(NOW(), INTERVAL 6 HOUR)";
- }
-
- $result = db_query($link, "SELECT id, access_key, access_url FROM ttrss_linked_instances
- WHERE $instance_qpart $date_qpart ORDER BY last_connected");
-
- while ($line = db_fetch_assoc($result)) {
- $id = $line['id'];
-
- _debug("Updating: " . $line['access_url'] . " ($id)");
-
- $fetch_url = $line['access_url'] . '/public.php?op=fbexport';
- $post_query = 'key=' . $line['access_key'];
-
- $feeds = fetch_file_contents($fetch_url, false, false, false, $post_query);
-
- // try doing it the old way
- if (!$feeds) {
- $fetch_url = $line['access_url'] . '/backend.php?op=fbexport';
- $feeds = fetch_file_contents($fetch_url, false, false, false, $post_query);
- }
-
- if ($feeds) {
- $feeds = json_decode($feeds, true);
-
- if ($feeds) {
- if ($feeds['error']) {
- $status = $feeds['error']['code'] + 10;
- } else {
- $status = 1;
-
- if (count($feeds['feeds']) > 0) {
-
- db_query($link, "DELETE FROM ttrss_linked_feeds
- WHERE instance_id = '$id'");
-
- foreach ($feeds['feeds'] as $feed) {
- $feed_url = db_escape_string($feed['feed_url']);
- $title = db_escape_string($feed['title']);
- $subscribers = db_escape_string($feed['subscribers']);
- $site_url = db_escape_string($feed['site_url']);
-
- db_query($link, "INSERT INTO ttrss_linked_feeds
- (feed_url, site_url, title, subscribers, instance_id, created, updated)
- VALUES
- ('$feed_url', '$site_url', '$title', '$subscribers', '$id', NOW(), NOW())");
- }
- } else {
- // received 0 feeds, this might indicate that
- // the instance on the other hand is rebuilding feedbrowser cache
- // we will try again later
-
- // TODO: maybe perform expiration based on updated here?
- }
-
- _debug("Processed " . count($feeds['feeds']) . " feeds.");
- }
- } else {
- $status = 2;
- }
-
- } else {
- $status = 0;
- }
-
- _debug("Status: $status");
-
- db_query($link, "UPDATE ttrss_linked_instances SET
- last_status_out = '$status', last_connected = NOW() WHERE id = '$id'");
-
- }
- }
-
- function handle_public_request($link, $op) {
- switch ($op) {
-
- case "getUnread":
- $login = db_escape_string($_REQUEST["login"]);
- $fresh = $_REQUEST["fresh"] == "1";
-
- $result = db_query($link, "SELECT id FROM ttrss_users WHERE login = '$login'");
-
- if (db_num_rows($result) == 1) {
- $uid = db_fetch_result($result, 0, "id");
-
- print getGlobalUnread($link, $uid);
-
- if ($fresh) {
- print ";";
- print getFeedArticles($link, -3, false, true, $uid);
- }
-
- } else {
- print "-1;User not found";
- }
-
- break; // getUnread
-
- case "getProfiles":
- $login = db_escape_string($_REQUEST["login"]);
- $password = db_escape_string($_REQUEST["password"]);
-
- if (authenticate_user($link, $login, $password)) {
- $result = db_query($link, "SELECT * FROM ttrss_settings_profiles
- WHERE owner_uid = " . $_SESSION["uid"] . " ORDER BY title");
-
- print "<select style='width: 100%' name='profile'>";
-
- print "<option value='0'>" . __("Default profile") . "</option>";
-
- while ($line = db_fetch_assoc($result)) {
- $id = $line["id"];
- $title = $line["title"];
-
- print "<option value='$id'>$title</option>";
- }
-
- print "</select>";
-
- $_SESSION = array();
- }
- break; // getprofiles
-
- case "pubsub":
- $mode = db_escape_string($_REQUEST['hub_mode']);
- $feed_id = (int) db_escape_string($_REQUEST['id']);
- $feed_url = db_escape_string($_REQUEST['hub_topic']);
-
- if (!PUBSUBHUBBUB_ENABLED) {
- header('HTTP/1.0 404 Not Found');
- echo "404 Not found";
- return;
- }
-
- // TODO: implement hub_verifytoken checking
-
- $result = db_query($link, "SELECT feed_url FROM ttrss_feeds
- WHERE id = '$feed_id'");
-
- if (db_num_rows($result) != 0) {
-
- $check_feed_url = db_fetch_result($result, 0, "feed_url");
-
- if ($check_feed_url && ($check_feed_url == $feed_url || !$feed_url)) {
- if ($mode == "subscribe") {
-
- db_query($link, "UPDATE ttrss_feeds SET pubsub_state = 2
- WHERE id = '$feed_id'");
-
- print $_REQUEST['hub_challenge'];
- return;
-
- } else if ($mode == "unsubscribe") {
-
- db_query($link, "UPDATE ttrss_feeds SET pubsub_state = 0
- WHERE id = '$feed_id'");
-
- print $_REQUEST['hub_challenge'];
- return;
-
- } else if (!$mode) {
-
- // Received update ping, schedule feed update.
- //update_rss_feed($link, $feed_id, true, true);
-
- db_query($link, "UPDATE ttrss_feeds SET
- last_update_started = '1970-01-01',
- last_updated = '1970-01-01' WHERE id = '$feed_id'");
-
- }
- } else {
- header('HTTP/1.0 404 Not Found');
- echo "404 Not found";
- }
- } else {
- header('HTTP/1.0 404 Not Found');
- echo "404 Not found";
- }
-
- break; // pubsub
-
- case "logout":
- logout_user();
- header("Location: tt-rss.php");
- break; // logout
-
- case "fbexport":
-
- $access_key = db_escape_string($_POST["key"]);
-
- // TODO: rate limit checking using last_connected
- $result = db_query($link, "SELECT id FROM ttrss_linked_instances
- WHERE access_key = '$access_key'");
-
- if (db_num_rows($result) == 1) {
-
- $instance_id = db_fetch_result($result, 0, "id");
-
- $result = db_query($link, "SELECT feed_url, site_url, title, subscribers
- FROM ttrss_feedbrowser_cache ORDER BY subscribers DESC LIMIT 100");
-
- $feeds = array();
-
- while ($line = db_fetch_assoc($result)) {
- array_push($feeds, $line);
- }
-
- db_query($link, "UPDATE ttrss_linked_instances SET
- last_status_in = 1 WHERE id = '$instance_id'");
-
- print json_encode(array("feeds" => $feeds));
- } else {
- print json_encode(array("error" => array("code" => 6)));
- }
- break; // fbexport
-
- case "share":
- $uuid = db_escape_string($_REQUEST["key"]);
-
- $result = db_query($link, "SELECT ref_id, owner_uid FROM ttrss_user_entries WHERE
- uuid = '$uuid'");
-
- if (db_num_rows($result) != 0) {
- header("Content-Type: text/html");
-
- $id = db_fetch_result($result, 0, "ref_id");
- $owner_uid = db_fetch_result($result, 0, "owner_uid");
-
- $_SESSION["uid"] = $owner_uid;
- $article = format_article($link, $id, false, true);
- $_SESSION["uid"] = "";
-
- print_r($article['content']);
-
- } else {
- print "Article not found.";
- }
-
- break;
-
- case "rss":
- $feed = db_escape_string($_REQUEST["id"]);
- $key = db_escape_string($_REQUEST["key"]);
- $is_cat = $_REQUEST["is_cat"] != false;
- $limit = (int)db_escape_string($_REQUEST["limit"]);
-
- $search = db_escape_string($_REQUEST["q"]);
- $match_on = db_escape_string($_REQUEST["m"]);
- $search_mode = db_escape_string($_REQUEST["smode"]);
- $view_mode = db_escape_string($_REQUEST["view-mode"]);
-
- if (SINGLE_USER_MODE) {
- authenticate_user($link, "admin", null);
- }
-
- $owner_id = false;
-
- if ($key) {
- $result = db_query($link, "SELECT owner_uid FROM
- ttrss_access_keys WHERE access_key = '$key' AND feed_id = '$feed'");
-
- if (db_num_rows($result) == 1)
- $owner_id = db_fetch_result($result, 0, "owner_uid");
- }
-
- if ($owner_id) {
- $_SESSION['uid'] = $owner_id;
-
- generate_syndicated_feed($link, 0, $feed, $is_cat, $limit,
- $search, $search_mode, $match_on, $view_mode);
- } else {
- header('HTTP/1.1 403 Forbidden');
- }
- break; // rss
-
-
- case "globalUpdateFeeds":
- // Update all feeds needing a update.
- update_daemon_common($link, 0, true, true);
- break; // globalUpdateFeeds
-
-
- default:
- header("Content-Type: text/plain");
- print json_encode(array("error" => array("code" => 7)));
- break; // fallback
-
- }
- }
-?>
<?php
+ set_include_path(get_include_path() . PATH_SEPARATOR . "include");
+
require_once "config.php";
require_once "lib/simplepie/simplepie.inc";
--- /dev/null
+<?php
+ require_once "config.php";
+ require_once "db.php";
+
+ if (!defined('DISABLE_SESSIONS')) {
+ if (!$_SESSION["prefs_cache"])
+ $_SESSION["prefs_cache"] = array();
+ }
+
+ function get_pref($link, $pref_name, $user_id = false, $die_on_error = false) {
+
+ $pref_name = db_escape_string($pref_name);
+ $prefs_cache = true;
+ $profile = false;
+
+ if (!$user_id) {
+ $user_id = $_SESSION["uid"];
+ @$profile = $_SESSION["profile"];
+ } else {
+ $user_id = sprintf("%d", $user_id);
+ //$prefs_cache = false;
+ }
+
+ if ($prefs_cache && !defined('DISABLE_SESSIONS')) {
+ if ($_SESSION["prefs_cache"] && @$_SESSION["prefs_cache"][$pref_name]) {
+ $tuple = $_SESSION["prefs_cache"][$pref_name];
+ return convert_pref_type($tuple["value"], $tuple["type"]);
+ }
+ }
+
+ if ($profile) {
+ $profile_qpart = "profile = '$profile' AND";
+ } else {
+ $profile_qpart = "profile IS NULL AND";
+ }
+
+ if (get_schema_version($link) < 63) $profile_qpart = "";
+
+ $result = db_query($link, "SELECT
+ value,ttrss_prefs_types.type_name as type_name
+ FROM
+ ttrss_user_prefs,ttrss_prefs,ttrss_prefs_types
+ WHERE
+ $profile_qpart
+ ttrss_user_prefs.pref_name = '$pref_name' AND
+ ttrss_prefs_types.id = type_id AND
+ owner_uid = '$user_id' AND
+ ttrss_user_prefs.pref_name = ttrss_prefs.pref_name");
+
+ if (db_num_rows($result) > 0) {
+ $value = db_fetch_result($result, 0, "value");
+ $type_name = db_fetch_result($result, 0, "type_name");
+
+ if (!defined('DISABLE_SESSIONS')) {
+ if ($user_id == $_SESSION["uid"]) {
+ $_SESSION["prefs_cache"][$pref_name]["type"] = $type_name;
+ $_SESSION["prefs_cache"][$pref_name]["value"] = $value;
+ }
+ }
+
+ return convert_pref_type($value, $type_name);
+
+ } else {
+ if ($die_on_error) {
+ die("Fatal error, unknown preferences key: $pref_name");
+ } else {
+ return null;
+ }
+ }
+ }
+
+ function convert_pref_type($value, $type_name) {
+ if ($type_name == "bool") {
+ return $value == "true";
+ } else if ($type_name == "integer") {
+ return sprintf("%d", $value);
+ } else {
+ return $value;
+ }
+ }
+
+ function set_pref($link, $pref_name, $value, $user_id = false) {
+ $pref_name = db_escape_string($pref_name);
+ $value = db_escape_string($value);
+
+ if (!$user_id) {
+ $user_id = $_SESSION["uid"];
+ @$profile = $_SESSION["profile"];
+ } else {
+ $user_id = sprintf("%d", $user_id);
+ $prefs_cache = false;
+ }
+
+ if ($profile) {
+ $profile_qpart = "AND profile = '$profile'";
+ } else {
+ $profile_qpart = "AND profile IS NULL";
+ }
+
+ if (get_schema_version($link) < 63) $profile_qpart = "";
+
+ $type_name = "";
+ $current_value = "";
+
+ if (!defined('DISABLE_SESSIONS')) {
+ if ($_SESSION["prefs_cache"] && @$_SESSION["prefs_cache"][$pref_name]) {
+ $type_name = $_SESSION["prefs_cache"][$pref_name]["type"];
+ $current_value = $_SESSION["prefs_cache"][$pref_name]["value"];
+ }
+ }
+
+ if (!$type_name) {
+ $result = db_query($link, "SELECT type_name
+ FROM ttrss_prefs,ttrss_prefs_types
+ WHERE pref_name = '$pref_name' AND type_id = ttrss_prefs_types.id");
+
+ if (db_num_rows($result) > 0)
+ $type_name = db_fetch_result($result, 0, "type_name");
+ } else if ($current_value == $value) {
+ return;
+ }
+
+ if ($type_name) {
+ if ($type_name == "bool") {
+ if ($value == "1" || $value == "true") {
+ $value = "true";
+ } else {
+ $value = "false";
+ }
+ } else if ($type_name == "integer") {
+ $value = sprintf("%d", $value);
+ }
+
+ if ($pref_name == 'DEFAULT_ARTICLE_LIMIT' && $value == 0) {
+ $value = 30;
+ }
+
+ if ($pref_name == 'USER_TIMEZONE' && $value == '') {
+ $value = 'UTC';
+ }
+
+ db_query($link, "UPDATE ttrss_user_prefs SET
+ value = '$value' WHERE pref_name = '$pref_name'
+ $profile_qpart
+ AND owner_uid = " . $_SESSION["uid"]);
+
+ if (!defined('DISABLE_SESSIONS')) {
+ if ($user_id == $_SESSION["uid"]) {
+ $_SESSION["prefs_cache"][$pref_name]["type"] = $type_name;
+ $_SESSION["prefs_cache"][$pref_name]["value"] = $value;
+ }
+ }
+ }
+ }
+?>
--- /dev/null
+<?php
+
+require_once "config.php";
+
+function db_connect($host, $user, $pass, $db) {
+ if (DB_TYPE == "pgsql") {
+
+ $string = "dbname=$db user=$user";
+
+ if ($pass) {
+ $string .= " password=$pass";
+ }
+
+ if ($host) {
+ $string .= " host=$host";
+ }
+
+ if (defined('DB_PORT')) {
+ $string = "$string port=" . DB_PORT;
+ }
+
+ $link = pg_connect($string);
+
+ if (!$link) {
+ die("Connection failed: " . pg_last_error($link));
+ }
+
+ return $link;
+
+ } else if (DB_TYPE == "mysql") {
+ $link = mysql_connect($host, $user, $pass);
+ if ($link) {
+ $result = mysql_select_db($db, $link);
+ if (!$result) {
+ die("Can't select DB: " . mysql_error($link));
+ }
+ return $link;
+ } else {
+ die("Connection failed: " . mysql_error($link));
+ }
+ }
+}
+
+function db_escape_string($s, $strip_tags = true) {
+ if ($strip_tags) $s = strip_tags($s);
+
+ if (DB_TYPE == "pgsql") {
+ return pg_escape_string($s);
+ } else {
+ return mysql_real_escape_string($s);
+ }
+}
+
+function db_query($link, $query, $die_on_error = true) {
+ //if ($_REQUEST["qlog"])
+ // error_log($_SESSION["uid"] . ":" . $_REQUEST["op"] . "/" . $_REQUEST["subop"] .
+ // " $query\n", 3, "/tmp/ttrss-query.log");
+
+ if (DB_TYPE == "pgsql") {
+ $result = pg_query($link, $query);
+ if (!$result) {
+ $query = htmlspecialchars($query); // just in case
+ if ($die_on_error) {
+ die("Query <i>$query</i> failed [$result]: " . pg_last_error($link));
+ }
+ }
+ return $result;
+ } else if (DB_TYPE == "mysql") {
+ $result = mysql_query($query, $link);
+ if (!$result) {
+ $query = htmlspecialchars($query);
+ if ($die_on_error) {
+ die("Query <i>$query</i> failed: " . mysql_error($link));
+ }
+ }
+ return $result;
+ }
+}
+
+function db_fetch_assoc($result) {
+ if (DB_TYPE == "pgsql") {
+ return pg_fetch_assoc($result);
+ } else if (DB_TYPE == "mysql") {
+ return mysql_fetch_assoc($result);
+ }
+}
+
+
+function db_num_rows($result) {
+ if (DB_TYPE == "pgsql") {
+ return pg_num_rows($result);
+ } else if (DB_TYPE == "mysql") {
+ return mysql_num_rows($result);
+ }
+}
+
+function db_fetch_result($result, $row, $param) {
+ if (DB_TYPE == "pgsql") {
+ return pg_fetch_result($result, $row, $param);
+ } else if (DB_TYPE == "mysql") {
+ // I hate incoherent naming of PHP functions
+ return mysql_result($result, $row, $param);
+ }
+}
+
+function db_unescape_string($str) {
+ $tmp = str_replace("\\\"", "\"", $str);
+ $tmp = str_replace("\\'", "'", $tmp);
+ return $tmp;
+}
+
+function db_close($link) {
+ if (DB_TYPE == "pgsql") {
+
+ return pg_close($link);
+
+ } else if (DB_TYPE == "mysql") {
+ return mysql_close($link);
+ }
+}
+
+function db_affected_rows($link, $result) {
+ if (DB_TYPE == "pgsql") {
+ return pg_affected_rows($result);
+ } else if (DB_TYPE == "mysql") {
+ return mysql_affected_rows($link);
+ }
+}
+
+function db_last_error($link) {
+ if (DB_TYPE == "pgsql") {
+ return pg_last_error($link);
+ } else if (DB_TYPE == "mysql") {
+ return mysql_error($link);
+ }
+}
+
+function db_quote($str){
+ return("'$str'");
+}
+
+?>
--- /dev/null
+<?php
+ date_default_timezone_set('UTC');
+ if (defined('E_DEPRECATED')) {
+ error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
+ } else {
+ error_reporting(E_ALL & ~E_NOTICE);
+ }
+
+ require_once 'config.php';
+
+ 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.
+ *
+ * @access public
+ * @return array A array of available translations.
+ */
+ function get_translations() {
+ $tr = array(
+ "auto" => "Detect automatically",
+ "ca_CA" => "Català",
+ "en_US" => "English",
+ "es_ES" => "Español",
+ "de_DE" => "Deutsch",
+ "fr_FR" => "Français",
+ "hu_HU" => "Magyar (Hungarian)",
+ "it_IT" => "Italiano",
+ "ja_JP" => "日本語 (Japanese)",
+ "nb_NO" => "Norwegian bokmål",
+ "ru_RU" => "Русский",
+ "pt_BR" => "Portuguese/Brazil",
+ "zh_CN" => "Simplified Chinese");
+
+ return $tr;
+ }
+
+ require_once "lib/accept-to-gettext.php";
+ require_once "lib/gettext/gettext.inc";
+
+ function startup_gettext() {
+
+ # Get locale from Accept-Language header
+ $lang = al2gt(array_keys(get_translations()), "text/html");
+
+ if (defined('_TRANSLATION_OVERRIDE_DEFAULT')) {
+ $lang = _TRANSLATION_OVERRIDE_DEFAULT;
+ }
+
+ if ($_COOKIE["ttrss_lang"] && $_COOKIE["ttrss_lang"] != "auto") {
+ $lang = $_COOKIE["ttrss_lang"];
+ }
+
+ /* In login action of mobile version */
+ if ($_POST["language"] && defined('MOBILE_VERSION')) {
+ $lang = $_POST["language"];
+ $_COOKIE["ttrss_lang"] = $lang;
+ }
+
+ if ($lang) {
+ if (defined('LC_MESSAGES')) {
+ _setlocale(LC_MESSAGES, $lang);
+ } else if (defined('LC_ALL')) {
+ _setlocale(LC_ALL, $lang);
+ }
+
+ if (defined('MOBILE_VERSION')) {
+ _bindtextdomain("messages", "../locale");
+ } else {
+ _bindtextdomain("messages", "locale");
+ }
+
+ _textdomain("messages");
+ _bind_textdomain_codeset("messages", "UTF-8");
+ }
+ }
+
+ startup_gettext();
+
+ if (defined('MEMCACHE_SERVER')) {
+ $memcache = new Memcache;
+ $memcache->connect(MEMCACHE_SERVER, 11211);
+ }
+
+ require_once 'db-prefs.php';
+ require_once 'version.php';
+
+ define('MAGPIE_OUTPUT_ENCODING', 'UTF-8');
+
+ define('SELF_USER_AGENT', 'Tiny Tiny RSS/' . VERSION . ' (http://tt-rss.org/)');
+ define('MAGPIE_USER_AGENT', SELF_USER_AGENT);
+
+ ini_set('user_agent', SELF_USER_AGENT);
+
+ require_once 'lib/pubsubhubbub/publisher.php';
+
+ $purifier = false;
+
+ $tz_offset = -1;
+ $utc_tz = new DateTimeZone('UTC');
+ $schema_version = false;
+
+ /**
+ * Print a timestamped debug message.
+ *
+ * @param string $msg The debug message.
+ * @return void
+ */
+ function _debug($msg) {
+ $ts = strftime("%H:%M:%S", time());
+ if (function_exists('posix_getpid')) {
+ $ts = "$ts/" . posix_getpid();
+ }
+ print "[$ts] $msg\n";
+ } // function _debug
+
+ /**
+ * Purge a feed old posts.
+ *
+ * @param mixed $link A database connection.
+ * @param mixed $feed_id The id of the purged feed.
+ * @param mixed $purge_interval Olderness of purged posts.
+ * @param boolean $debug Set to True to enable the debug. False by default.
+ * @access public
+ * @return void
+ */
+ function purge_feed($link, $feed_id, $purge_interval, $debug = false) {
+
+ if (!$purge_interval) $purge_interval = feed_purge_interval($link, $feed_id);
+
+ $rows = -1;
+
+ $result = db_query($link,
+ "SELECT owner_uid FROM ttrss_feeds WHERE id = '$feed_id'");
+
+ $owner_uid = false;
+
+ if (db_num_rows($result) == 1) {
+ $owner_uid = db_fetch_result($result, 0, "owner_uid");
+ }
+
+ if ($purge_interval == -1 || !$purge_interval) {
+ if ($owner_uid) {
+ ccache_update($link, $feed_id, $owner_uid);
+ }
+ return;
+ }
+
+ if (!$owner_uid) return;
+
+ if (FORCE_ARTICLE_PURGE == 0) {
+ $purge_unread = get_pref($link, "PURGE_UNREAD_ARTICLES",
+ $owner_uid, false);
+ } else {
+ $purge_unread = true;
+ $purge_interval = FORCE_ARTICLE_PURGE;
+ }
+
+ if (!$purge_unread) $query_limit = " unread = false AND ";
+
+ if (DB_TYPE == "pgsql") {
+ $pg_version = get_pgsql_version($link);
+
+ if (preg_match("/^7\./", $pg_version) || preg_match("/^8\.0/", $pg_version)) {
+
+ $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE
+ ttrss_entries.id = ref_id AND
+ marked = false AND
+ feed_id = '$feed_id' AND
+ $query_limit
+ ttrss_entries.date_updated < NOW() - INTERVAL '$purge_interval days'");
+
+ } else {
+
+ $result = db_query($link, "DELETE FROM ttrss_user_entries
+ USING ttrss_entries
+ WHERE ttrss_entries.id = ref_id AND
+ marked = false AND
+ feed_id = '$feed_id' AND
+ $query_limit
+ 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
+ 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
+ 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);
+
+ if ($debug) {
+ _debug("Purged feed $feed_id ($purge_interval): deleted $rows articles");
+ }
+ } // function purge_feed
+
+ function feed_purge_interval($link, $feed_id) {
+
+ $result = db_query($link, "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,
+ 'PURGE_OLD_DAYS', $owner_uid);
+
+ return $purge_interval;
+
+ } else {
+ return -1;
+ }
+ }
+
+ function purge_orphans($link, $do_output = false) {
+
+ // purge orphaned posts in main content table
+ $result = db_query($link, "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);
+ _debug("Purged $rows orphaned posts.");
+ }
+ }
+
+ function get_feed_update_interval($link, $feed_id) {
+ $result = db_query($link, "SELECT owner_uid, update_interval FROM
+ ttrss_feeds WHERE id = '$feed_id'");
+
+ if (db_num_rows($result) == 1) {
+ $update_interval = db_fetch_result($result, 0, "update_interval");
+ $owner_uid = db_fetch_result($result, 0, "owner_uid");
+
+ if ($update_interval != 0) {
+ return $update_interval;
+ } else {
+ return get_pref($link, 'DEFAULT_UPDATE_INTERVAL', $owner_uid, false);
+ }
+
+ } else {
+ return -1;
+ }
+ }
+
+ function fetch_file_contents($url, $type = false, $login = false, $pass = false, $post_query = false) {
+ $login = urlencode($login);
+ $pass = urlencode($pass);
+
+ if (function_exists('curl_init') && !ini_get("open_basedir")) {
+ $ch = curl_init($url);
+
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 45);
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+ 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");
+
+ if ($post_query) {
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $post_query);
+ }
+
+ if ($login && $pass)
+ curl_setopt($ch, CURLOPT_USERPWD, "$login:$pass");
+
+ $contents = @curl_exec($ch);
+
+ if ($contents === false) {
+ curl_close($ch);
+ return false;
+ }
+
+ $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
+ curl_close($ch);
+
+ if ($http_code != 200 || $type && strpos($content_type, "$type") === false) {
+ return false;
+ }
+
+ return $contents;
+ } else {
+ if ($login && $pass ){
+ $url_parts = array();
+
+ preg_match("/(^[^:]*):\/\/(.*)/", $url, $url_parts);
+
+ if ($url_parts[1] && $url_parts[2]) {
+ $url = $url_parts[1] . "://$login:$pass@" . $url_parts[2];
+ }
+ }
+
+ return @file_get_contents($url);
+ }
+
+ }
+
+ /**
+ * Try to determine the favicon URL for a feed.
+ * adapted from wordpress favicon plugin by Jeff Minard (http://thecodepro.com/)
+ * http://dev.wp-plugins.org/file/favatars/trunk/favatars.php
+ *
+ * @param string $url A feed or page URL
+ * @access public
+ * @return mixed The favicon URL, or false if none was found.
+ */
+ function get_favicon_url($url) {
+
+ $favicon_url = false;
+
+ if ($html = @fetch_file_contents($url)) {
+
+ libxml_use_internal_errors(true);
+
+ $doc = new DOMDocument();
+ $doc->loadHTML($html);
+ $xpath = new DOMXPath($doc);
+
+ $base = $xpath->query('/html/head/base');
+ foreach ($base as $b) {
+ $url = $b->getAttribute("href");
+ break;
+ }
+
+ $entries = $xpath->query('/html/head/link[@rel="shortcut icon" or @rel="icon"]');
+ if (count($entries) > 0) {
+ foreach ($entries as $entry) {
+ $favicon_url = rewrite_relative_url($url, $entry->getAttribute("href"));
+ break;
+ }
+ }
+ }
+
+ if (!$favicon_url)
+ $favicon_url = rewrite_relative_url($url, "/favicon.ico");
+
+ return $favicon_url;
+ } // function get_favicon_url
+
+ function check_feed_favicon($site_url, $feed, $link) {
+# print "FAVICON [$site_url]: $favicon_url\n";
+
+ $icon_file = ICONS_DIR . "/$feed.ico";
+
+ if (!file_exists($icon_file)) {
+ $favicon_url = get_favicon_url($site_url);
+
+ if ($favicon_url) {
+ $contents = fetch_file_contents($favicon_url, "image");
+
+ if ($contents) {
+ $fp = @fopen($icon_file, "w");
+
+ if ($fp) {
+ fwrite($fp, $contents);
+ fclose($fp);
+ chmod($icon_file, 0644);
+ }
+ }
+ }
+ }
+ }
+
+ function update_rss_feed($link, $feed, $ignore_daemon = false, $no_cache = false) {
+
+ global $memcache;
+
+ /* Update all feeds with the same URL to utilize memcache */
+
+ if ($memcache) {
+ $result = db_query($link, "SELECT f1.id
+ FROM ttrss_feeds AS f1, ttrss_feeds AS f2
+ WHERE f2.feed_url = f1.feed_url AND f2.id = '$feed'");
+
+ while ($line = db_fetch_assoc($result)) {
+ update_rss_feed_real($link, $line["id"], $ignore_daemon, $no_cache);
+ }
+ } else {
+ update_rss_feed_real($link, $feed, $ignore_daemon, $no_cache);
+ }
+ }
+
+ function update_rss_feed_real($link, $feed, $ignore_daemon = false, $no_cache = false,
+ $override_url = false) {
+
+ require_once "lib/simplepie/simplepie.inc";
+ require_once "lib/magpierss/rss_fetch.inc";
+ require_once 'lib/magpierss/rss_utils.inc';
+
+ global $memcache;
+
+ $debug_enabled = defined('DAEMON_EXTENDED_DEBUG') || $_REQUEST['xdebug'];
+
+ if (!$_REQUEST["daemon"] && !$ignore_daemon) {
+ return false;
+ }
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: start");
+ }
+
+ if (!$ignore_daemon) {
+
+ if (DB_TYPE == "pgsql") {
+ $updstart_thresh_qpart = "(ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < NOW() - INTERVAL '120 seconds')";
+ } else {
+ $updstart_thresh_qpart = "(ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < DATE_SUB(NOW(), INTERVAL 120 SECOND))";
+ }
+
+ $result = db_query($link, "SELECT id,update_interval,auth_login,
+ auth_pass,cache_images,update_method
+ FROM ttrss_feeds WHERE id = '$feed' AND $updstart_thresh_qpart");
+
+ } else {
+
+ $result = db_query($link, "SELECT id,update_interval,auth_login,
+ feed_url,auth_pass,cache_images,update_method,last_updated,
+ mark_unread_on_update, owner_uid, update_on_checksum_change,
+ pubsub_state
+ FROM ttrss_feeds WHERE id = '$feed'");
+
+ }
+
+ if (db_num_rows($result) == 0) {
+ if ($debug_enabled) {
+ _debug("update_rss_feed: feed $feed NOT FOUND/SKIPPED");
+ }
+ return false;
+ }
+
+ $update_method = db_fetch_result($result, 0, "update_method");
+ $last_updated = db_fetch_result($result, 0, "last_updated");
+ $owner_uid = db_fetch_result($result, 0, "owner_uid");
+ $mark_unread_on_update = sql_bool_to_bool(db_fetch_result($result,
+ 0, "mark_unread_on_update"));
+ $update_on_checksum_change = sql_bool_to_bool(db_fetch_result($result,
+ 0, "update_on_checksum_change"));
+ $pubsub_state = db_fetch_result($result, 0, "pubsub_state");
+
+ db_query($link, "UPDATE ttrss_feeds SET last_update_started = NOW()
+ WHERE id = '$feed'");
+
+ $auth_login = db_fetch_result($result, 0, "auth_login");
+ $auth_pass = db_fetch_result($result, 0, "auth_pass");
+
+ if ($update_method == 0)
+ $update_method = DEFAULT_UPDATE_METHOD + 1;
+
+ // 1 - Magpie
+ // 2 - SimplePie
+ // 3 - Twitter OAuth
+
+ if ($update_method == 2)
+ $use_simplepie = true;
+ else
+ $use_simplepie = false;
+
+ if ($debug_enabled) {
+ _debug("update method: $update_method (feed setting: $update_method) (use simplepie: $use_simplepie)\n");
+ }
+
+ if ($update_method == 1) {
+ $auth_login = urlencode($auth_login);
+ $auth_pass = urlencode($auth_pass);
+ }
+
+ $update_interval = db_fetch_result($result, 0, "update_interval");
+ $cache_images = sql_bool_to_bool(db_fetch_result($result, 0, "cache_images"));
+ $fetch_url = db_fetch_result($result, 0, "feed_url");
+
+ if ($update_interval < 0) { return false; }
+
+ $feed = db_escape_string($feed);
+
+ if ($auth_login && $auth_pass ){
+ $url_parts = array();
+ preg_match("/(^[^:]*):\/\/(.*)/", $fetch_url, $url_parts);
+
+ if ($url_parts[1] && $url_parts[2]) {
+ $fetch_url = $url_parts[1] . "://$auth_login:$auth_pass@" . $url_parts[2];
+ }
+
+ }
+
+ if ($override_url)
+ $fetch_url = $override_url;
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: fetching [$fetch_url]...");
+ }
+
+ $obj_id = md5("FDATA:$use_simplepie:$fetch_url");
+
+ if ($memcache && $obj = $memcache->get($obj_id)) {
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: data found in memcache.");
+ }
+
+ $rss = $obj;
+
+ } else {
+
+ if ($update_method == 3) {
+ $rss = fetch_twitter_rss($link, $fetch_url, $owner_uid);
+ } else if ($update_method == 1) {
+
+ define('MAGPIE_CACHE_AGE', get_feed_update_interval($link, $feed) * 60);
+ define('MAGPIE_CACHE_ON', !$no_cache);
+ define('MAGPIE_FETCH_TIME_OUT', 60);
+ define('MAGPIE_CACHE_DIR', CACHE_DIR . "/magpie");
+
+ $rss = @fetch_rss($fetch_url);
+ } else {
+ $simplepie_cache_dir = CACHE_DIR . "/simplepie";
+
+ if (!is_dir($simplepie_cache_dir)) {
+ mkdir($simplepie_cache_dir);
+ }
+
+ $rss = new SimplePie();
+ $rss->set_useragent(SELF_USER_AGENT);
+ # $rss->set_timeout(10);
+ $rss->set_feed_url($fetch_url);
+ $rss->set_output_encoding('UTF-8');
+ $rss->force_feed(true);
+
+ if (SIMPLEPIE_CACHE_IMAGES && $cache_images) {
+
+ if ($debug_enabled) {
+ _debug("enabling image cache");
+ }
+
+ $rss->set_image_handler("image.php", 'i');
+ }
+
+ if ($debug_enabled) {
+ _debug("feed update interval (sec): " .
+ get_feed_update_interval($link, $feed)*60);
+ }
+
+ $rss->enable_cache(!$no_cache);
+
+ if (!$no_cache) {
+ $rss->set_cache_location($simplepie_cache_dir);
+ $rss->set_cache_duration(get_feed_update_interval($link, $feed) * 60);
+ }
+
+ $rss->init();
+ }
+
+ if ($memcache && $rss) $memcache->add($obj_id, $rss, 0, 300);
+ }
+
+// print_r($rss);
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: fetch done, parsing...");
+ }
+
+ $feed = db_escape_string($feed);
+
+ if ($update_method == 2) {
+ $fetch_ok = !$rss->error();
+ } else {
+ $fetch_ok = !!$rss;
+ }
+
+ if ($fetch_ok) {
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: processing feed data...");
+ }
+
+// db_query($link, "BEGIN");
+
+ $result = db_query($link, "SELECT title,icon_url,site_url,owner_uid
+ FROM ttrss_feeds WHERE id = '$feed'");
+
+ $registered_title = db_fetch_result($result, 0, "title");
+ $orig_icon_url = db_fetch_result($result, 0, "icon_url");
+ $orig_site_url = db_fetch_result($result, 0, "site_url");
+
+ $owner_uid = db_fetch_result($result, 0, "owner_uid");
+
+ if ($use_simplepie) {
+ $site_url = $rss->get_link();
+ } else {
+ $site_url = $rss->channel["link"];
+ }
+
+ $site_url = rewrite_relative_url($fetch_url, $site_url);
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: checking favicon...");
+ }
+
+ check_feed_favicon($site_url, $feed, $link);
+
+ if (!$registered_title || $registered_title == "[Unknown]") {
+
+ if ($use_simplepie) {
+ $feed_title = db_escape_string($rss->get_title());
+ } else {
+ $feed_title = db_escape_string($rss->channel["title"]);
+ }
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: registering title: $feed_title");
+ }
+
+ db_query($link, "UPDATE ttrss_feeds SET
+ title = '$feed_title' WHERE id = '$feed'");
+ }
+
+ // weird, weird Magpie
+ if (!$use_simplepie) {
+ if (!$site_url) $site_url = db_escape_string($rss->channel["link_"]);
+ }
+
+ if ($site_url && $orig_site_url != db_escape_string($site_url)) {
+ db_query($link, "UPDATE ttrss_feeds SET
+ site_url = '$site_url' WHERE id = '$feed'");
+ }
+
+// print "I: " . $rss->channel["image"]["url"];
+
+ if (!$use_simplepie) {
+ $icon_url = db_escape_string($rss->image["url"]);
+ } else {
+ $icon_url = db_escape_string($rss->get_image_url());
+ }
+
+ $icon_url = substr($icon_url, 0, 250);
+
+ if ($icon_url && $orig_icon_url != $icon_url) {
+ db_query($link, "UPDATE ttrss_feeds SET icon_url = '$icon_url' WHERE id = '$feed'");
+ }
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: loading filters...");
+ }
+
+ $filters = load_filters($link, $feed, $owner_uid);
+
+// if ($debug_enabled) {
+// print_r($filters);
+// }
+
+ if ($use_simplepie) {
+ $iterator = $rss->get_items();
+ } else {
+ $iterator = $rss->items;
+ if (!$iterator || !is_array($iterator)) $iterator = $rss->entries;
+ if (!$iterator || !is_array($iterator)) $iterator = $rss;
+ }
+
+ if (!is_array($iterator)) {
+ /* db_query($link, "UPDATE ttrss_feeds
+ SET last_error = 'Parse error: can\'t find any articles.'
+ WHERE id = '$feed'"); */
+
+ // clear any errors and mark feed as updated if fetched okay
+ // even if it's blank
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: entry iterator is not an array, no articles?");
+ }
+
+ db_query($link, "UPDATE ttrss_feeds
+ SET last_updated = NOW(), last_error = '' WHERE id = '$feed'");
+
+ return; // no articles
+ }
+
+ if ($pubsub_state != 2 && PUBSUBHUBBUB_ENABLED) {
+
+ if ($debug_enabled) _debug("update_rss_feed: checking for PUSH hub...");
+
+ $feed_hub_url = false;
+ if ($use_simplepie) {
+ $links = $rss->get_links('hub');
+
+ if ($links && is_array($links)) {
+ foreach ($links as $l) {
+ $feed_hub_url = $l;
+ break;
+ }
+ }
+
+ } else {
+ $atom = $rss->channel['atom'];
+
+ if ($atom) {
+ if ($atom['link@rel'] == 'hub') {
+ $feed_hub_url = $atom['link@href'];
+ }
+
+ if (!$feed_hub_url && $atom['link#'] > 1) {
+ for ($i = 2; $i <= $atom['link#']; $i++) {
+ if ($atom["link#$i@rel"] == 'hub') {
+ $feed_hub_url = $atom["link#$i@href"];
+ break;
+ }
+ }
+ }
+ } else {
+ $feed_hub_url = $rss->channel['link_hub'];
+ }
+ }
+
+ if ($debug_enabled) _debug("update_rss_feed: feed hub url: $feed_hub_url");
+
+ if ($feed_hub_url && function_exists('curl_init') &&
+ !ini_get("open_basedir")) {
+
+ require_once 'lib/pubsubhubbub/subscriber.php';
+
+ $callback_url = get_self_url_prefix() .
+ "/public.php?op=pubsub&id=$feed";
+
+ $s = new Subscriber($feed_hub_url, $callback_url);
+
+ $rc = $s->subscribe($fetch_url);
+
+ if ($debug_enabled)
+ _debug("update_rss_feed: feed hub url found, subscribe request sent.");
+
+ db_query($link, "UPDATE ttrss_feeds SET pubsub_state = 1
+ WHERE id = '$feed'");
+ }
+ }
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: processing articles...");
+ }
+
+ foreach ($iterator as $item) {
+
+ if ($_REQUEST['xdebug'] == 2) {
+ print_r($item);
+ }
+
+ if ($use_simplepie) {
+ $entry_guid = $item->get_id();
+ if (!$entry_guid) $entry_guid = $item->get_link();
+ if (!$entry_guid) $entry_guid = make_guid_from_title($item->get_title());
+
+ } else {
+
+ $entry_guid = $item["id"];
+
+ if (!$entry_guid) $entry_guid = $item["guid"];
+ if (!$entry_guid) $entry_guid = $item["about"];
+ if (!$entry_guid) $entry_guid = $item["link"];
+ if (!$entry_guid) $entry_guid = make_guid_from_title($item["title"]);
+ }
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: guid $entry_guid");
+ }
+
+ if (!$entry_guid) continue;
+
+ $entry_timestamp = "";
+
+ if ($use_simplepie) {
+ $entry_timestamp = strtotime($item->get_date());
+ } else {
+ $rss_2_date = $item['pubdate'];
+ $rss_1_date = $item['dc']['date'];
+ $atom_date = $item['issued'];
+ if (!$atom_date) $atom_date = $item['updated'];
+
+ if ($atom_date != "") $entry_timestamp = parse_w3cdtf($atom_date);
+ if ($rss_1_date != "") $entry_timestamp = parse_w3cdtf($rss_1_date);
+ if ($rss_2_date != "") $entry_timestamp = strtotime($rss_2_date);
+
+ }
+
+ if ($entry_timestamp == "" || $entry_timestamp == -1 || !$entry_timestamp) {
+ $entry_timestamp = time();
+ $no_orig_date = 'true';
+ } else {
+ $no_orig_date = 'false';
+ }
+
+ $entry_timestamp_fmt = strftime("%Y/%m/%d %H:%M:%S", $entry_timestamp);
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: date $entry_timestamp [$entry_timestamp_fmt]");
+ }
+
+ if ($use_simplepie) {
+ $entry_title = $item->get_title();
+ } else {
+ $entry_title = trim(strip_tags($item["title"]));
+ }
+
+ if ($use_simplepie) {
+ $entry_link = $item->get_link();
+ } else {
+ // strange Magpie workaround
+ $entry_link = $item["link_"];
+ if (!$entry_link) $entry_link = $item["link"];
+ }
+
+ $entry_link = rewrite_relative_url($site_url, $entry_link);
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: title $entry_title");
+ _debug("update_rss_feed: link $entry_link");
+ }
+
+ if (!$entry_title) $entry_title = date("Y-m-d H:i:s", $entry_timestamp);;
+
+ $entry_link = strip_tags($entry_link);
+
+ if ($use_simplepie) {
+ $entry_content = $item->get_content();
+ if (!$entry_content) $entry_content = $item->get_description();
+ } else {
+ $entry_content = $item["content:escaped"];
+
+ if (!$entry_content) $entry_content = $item["content:encoded"];
+ if (!$entry_content) $entry_content = $item["content"]["encoded"];
+ if (!$entry_content) $entry_content = $item["content"];
+
+ if (is_array($entry_content)) $entry_content = $entry_content[0];
+
+ // Magpie bugs are getting ridiculous
+ if (trim($entry_content) == "Array") $entry_content = false;
+
+ if (!$entry_content) $entry_content = $item["atom_content"];
+ if (!$entry_content) $entry_content = $item["summary"];
+
+ if (!$entry_content ||
+ strlen($entry_content) < strlen($item["description"])) {
+ $entry_content = $item["description"];
+ };
+
+ // WTF
+ if (is_array($entry_content)) {
+ $entry_content = $entry_content["encoded"];
+ if (!$entry_content) $entry_content = $entry_content["escaped"];
+ }
+ }
+
+ if ($_REQUEST["xdebug"] == 2) {
+ print "update_rss_feed: content: ";
+ print_r(htmlspecialchars($entry_content));
+ }
+
+ $entry_content_unescaped = $entry_content;
+
+ if ($use_simplepie) {
+ $entry_comments = strip_tags($item->data["comments"]);
+ if ($item->get_author()) {
+ $entry_author_item = $item->get_author();
+ $entry_author = $entry_author_item->get_name();
+ if (!$entry_author) $entry_author = $entry_author_item->get_email();
+
+ $entry_author = db_escape_string($entry_author);
+ }
+ } else {
+ $entry_comments = strip_tags($item["comments"]);
+
+ $entry_author = db_escape_string(strip_tags($item['dc']['creator']));
+
+ if ($item['author']) {
+
+ if (is_array($item['author'])) {
+
+ if (!$entry_author) {
+ $entry_author = db_escape_string(strip_tags($item['author']['name']));
+ }
+
+ if (!$entry_author) {
+ $entry_author = db_escape_string(strip_tags($item['author']['email']));
+ }
+ }
+
+ if (!$entry_author) {
+ $entry_author = db_escape_string(strip_tags($item['author']));
+ }
+ }
+ }
+
+ if (preg_match('/^[\t\n\r ]*$/', $entry_author)) $entry_author = '';
+
+ $entry_guid = db_escape_string(strip_tags($entry_guid));
+ $entry_guid = mb_substr($entry_guid, 0, 250);
+
+ $result = db_query($link, "SELECT id FROM ttrss_entries
+ WHERE guid = '$entry_guid'");
+
+ $entry_content = db_escape_string($entry_content, false);
+
+ $content_hash = "SHA1:" . sha1(strip_tags($entry_content));
+
+ $entry_title = db_escape_string($entry_title);
+ $entry_link = db_escape_string($entry_link);
+ $entry_comments = mb_substr(db_escape_string($entry_comments), 0, 250);
+ $entry_author = mb_substr($entry_author, 0, 250);
+
+ if ($use_simplepie) {
+ $num_comments = 0; #FIXME#
+ } else {
+ $num_comments = db_escape_string($item["slash"]["comments"]);
+ }
+
+ if (!$num_comments) $num_comments = 0;
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: looking for tags [1]...");
+ }
+
+ // parse <category> entries into tags
+
+ $additional_tags = array();
+
+ if ($use_simplepie) {
+
+ $additional_tags_src = $item->get_categories();
+
+ if (is_array($additional_tags_src)) {
+ foreach ($additional_tags_src as $tobj) {
+ array_push($additional_tags, $tobj->get_term());
+ }
+ }
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: category tags:");
+ print_r($additional_tags);
+ }
+
+ } else {
+
+ $t_ctr = $item['category#'];
+
+ if ($t_ctr == 0) {
+ $additional_tags = array();
+ } else if ($t_ctr > 0) {
+ $additional_tags = array($item['category']);
+
+ if ($item['category@term']) {
+ array_push($additional_tags, $item['category@term']);
+ }
+
+ for ($i = 0; $i <= $t_ctr; $i++ ) {
+ if ($item["category#$i"]) {
+ array_push($additional_tags, $item["category#$i"]);
+ }
+
+ if ($item["category#$i@term"]) {
+ array_push($additional_tags, $item["category#$i@term"]);
+ }
+ }
+ }
+
+ // parse <dc:subject> elements
+
+ $t_ctr = $item['dc']['subject#'];
+
+ if ($t_ctr > 0) {
+ array_push($additional_tags, $item['dc']['subject']);
+
+ for ($i = 0; $i <= $t_ctr; $i++ ) {
+ if ($item['dc']["subject#$i"]) {
+ array_push($additional_tags, $item['dc']["subject#$i"]);
+ }
+ }
+ }
+ }
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: looking for tags [2]...");
+ }
+
+ /* taaaags */
+ // <a href="..." rel="tag">Xorg</a>, //
+
+ $entry_tags = null;
+
+ preg_match_all("/<a.*?rel=['\"]tag['\"].*?\>([^<]+)<\/a>/i",
+ $entry_content_unescaped, $entry_tags);
+
+ $entry_tags = $entry_tags[1];
+
+ $entry_tags = array_merge($entry_tags, $additional_tags);
+ $entry_tags = array_unique($entry_tags);
+
+ for ($i = 0; $i < count($entry_tags); $i++)
+ $entry_tags[$i] = mb_strtolower($entry_tags[$i], 'utf-8');
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: unfiltered tags found:");
+ print_r($entry_tags);
+ }
+
+ # sanitize content
+
+ $entry_content = sanitize_article_content($entry_content);
+ $entry_title = sanitize_article_content($entry_title);
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: done collecting data [TITLE:$entry_title]");
+ }
+
+ db_query($link, "BEGIN");
+
+ if (db_num_rows($result) == 0) {
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: base guid not found");
+ }
+
+ // base post entry does not exist, create it
+
+ $result = db_query($link,
+ "INSERT INTO ttrss_entries
+ (title,
+ guid,
+ link,
+ updated,
+ content,
+ content_hash,
+ no_orig_date,
+ date_updated,
+ date_entered,
+ comments,
+ num_comments,
+ author)
+ VALUES
+ ('$entry_title',
+ '$entry_guid',
+ '$entry_link',
+ '$entry_timestamp_fmt',
+ '$entry_content',
+ '$content_hash',
+ $no_orig_date,
+ NOW(),
+ NOW(),
+ '$entry_comments',
+ '$num_comments',
+ '$entry_author')");
+ } else {
+ // we keep encountering the entry in feeds, so we need to
+ // update date_updated column so that we don't get horrible
+ // dupes when the entry gets purged and reinserted again e.g.
+ // in the case of SLOW SLOW OMG SLOW updating feeds
+
+ $base_entry_id = db_fetch_result($result, 0, "id");
+
+ db_query($link, "UPDATE ttrss_entries SET date_updated = NOW()
+ WHERE id = '$base_entry_id'");
+ }
+
+ // now it should exist, if not - bad luck then
+
+ $result = db_query($link, "SELECT
+ id,content_hash,no_orig_date,title,
+ ".SUBSTRING_FOR_DATE."(date_updated,1,19) as date_updated,
+ ".SUBSTRING_FOR_DATE."(updated,1,19) as updated,
+ num_comments
+ FROM
+ ttrss_entries
+ WHERE guid = '$entry_guid'");
+
+ $entry_ref_id = 0;
+ $entry_int_id = 0;
+
+ if (db_num_rows($result) == 1) {
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: base guid found, checking for user record");
+ }
+
+ // this will be used below in update handler
+ $orig_content_hash = db_fetch_result($result, 0, "content_hash");
+ $orig_title = db_fetch_result($result, 0, "title");
+ $orig_num_comments = db_fetch_result($result, 0, "num_comments");
+ $orig_date_updated = strtotime(db_fetch_result($result,
+ 0, "date_updated"));
+
+ $ref_id = db_fetch_result($result, 0, "id");
+ $entry_ref_id = $ref_id;
+
+ // check for user post link to main table
+
+ // do we allow duplicate posts with same GUID in different feeds?
+ if (get_pref($link, "ALLOW_DUPLICATE_POSTS", $owner_uid, false)) {
+ $dupcheck_qpart = "AND (feed_id = '$feed' OR feed_id IS NULL)";
+ } else {
+ $dupcheck_qpart = "";
+ }
+
+ /* Collect article tags here so we could filter by them: */
+
+ $article_filters = get_article_filters($filters, $entry_title,
+ $entry_content, $entry_link, $entry_timestamp, $entry_author,
+ $entry_tags);
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: article filters: ");
+ if (count($article_filters) != 0) {
+ print_r($article_filters);
+ }
+ }
+
+ if (find_article_filter($article_filters, "filter")) {
+ db_query($link, "COMMIT"); // close transaction in progress
+ continue;
+ }
+
+ $score = calculate_article_score($article_filters);
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: initial score: $score");
+ }
+
+ $query = "SELECT ref_id, int_id FROM ttrss_user_entries WHERE
+ ref_id = '$ref_id' AND owner_uid = '$owner_uid'
+ $dupcheck_qpart";
+
+// if ($_REQUEST["xdebug"]) print "$query\n";
+
+ $result = db_query($link, $query);
+
+ // okay it doesn't exist - create user entry
+ if (db_num_rows($result) == 0) {
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: user record not found, creating...");
+ }
+
+ if ($score >= -500 && !find_article_filter($article_filters, 'catchup')) {
+ $unread = 'true';
+ $last_read_qpart = 'NULL';
+ } else {
+ $unread = 'false';
+ $last_read_qpart = 'NOW()';
+ }
+
+ if (find_article_filter($article_filters, 'mark') || $score > 1000) {
+ $marked = 'true';
+ } else {
+ $marked = 'false';
+ }
+
+ if (find_article_filter($article_filters, 'publish')) {
+ $published = 'true';
+ } else {
+ $published = 'false';
+ }
+
+ $result = db_query($link,
+ "INSERT INTO ttrss_user_entries
+ (ref_id, owner_uid, feed_id, unread, last_read, marked,
+ published, score, tag_cache, label_cache, uuid)
+ VALUES ('$ref_id', '$owner_uid', '$feed', $unread,
+ $last_read_qpart, $marked, $published, '$score', '', '', '')");
+
+ if (PUBSUBHUBBUB_HUB && $published == 'true') {
+ $rss_link = get_self_url_prefix() .
+ "/public.php?op=rss&id=-2&key=" .
+ get_feed_access_key($link, -2, false, $owner_uid);
+
+ $p = new Publisher(PUBSUBHUBBUB_HUB);
+
+ $pubsub_result = $p->publish_update($rss_link);
+ }
+
+ $result = db_query($link,
+ "SELECT int_id FROM ttrss_user_entries WHERE
+ ref_id = '$ref_id' AND owner_uid = '$owner_uid' AND
+ feed_id = '$feed' LIMIT 1");
+
+ if (db_num_rows($result) == 1) {
+ $entry_int_id = db_fetch_result($result, 0, "int_id");
+ }
+ } else {
+ if ($debug_enabled) {
+ _debug("update_rss_feed: user record FOUND");
+ }
+
+ $entry_ref_id = db_fetch_result($result, 0, "ref_id");
+ $entry_int_id = db_fetch_result($result, 0, "int_id");
+ }
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: RID: $entry_ref_id, IID: $entry_int_id");
+ }
+
+ $post_needs_update = false;
+ $update_insignificant = false;
+
+ if ($orig_num_comments != $num_comments) {
+ $post_needs_update = true;
+ $update_insignificant = true;
+ }
+
+ if ($content_hash != $orig_content_hash) {
+ $post_needs_update = true;
+ $update_insignificant = false;
+ }
+
+ if (db_escape_string($orig_title) != $entry_title) {
+ $post_needs_update = true;
+ $update_insignificant = false;
+ }
+
+ // if post needs update, update it and mark all user entries
+ // linking to this post as updated
+ if ($post_needs_update) {
+
+ if (defined('DAEMON_EXTENDED_DEBUG')) {
+ _debug("update_rss_feed: post $entry_guid needs update...");
+ }
+
+// print "<!-- post $orig_title needs update : $post_needs_update -->";
+
+ db_query($link, "UPDATE ttrss_entries
+ SET title = '$entry_title', content = '$entry_content',
+ content_hash = '$content_hash',
+ updated = '$entry_timestamp_fmt',
+ num_comments = '$num_comments'
+ WHERE id = '$ref_id'");
+
+ if (!$update_insignificant) {
+ if ($mark_unread_on_update) {
+ db_query($link, "UPDATE ttrss_user_entries
+ SET last_read = null, unread = true WHERE ref_id = '$ref_id'");
+ } else if ($update_on_checksum_change) {
+ db_query($link, "UPDATE ttrss_user_entries
+ SET last_read = null WHERE ref_id = '$ref_id'
+ AND unread = false");
+ }
+ }
+ }
+ }
+
+ db_query($link, "COMMIT");
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: assigning labels...");
+ }
+
+ assign_article_to_labels($link, $entry_ref_id, $article_filters,
+ $owner_uid);
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: looking for enclosures...");
+ }
+
+ // enclosures
+
+ $enclosures = array();
+
+ if ($use_simplepie) {
+ $encs = $item->get_enclosures();
+
+ if (is_array($encs)) {
+ foreach ($encs as $e) {
+ $e_item = array(
+ $e->link, $e->type, $e->length);
+
+ array_push($enclosures, $e_item);
+ }
+ }
+
+ } else {
+ // <enclosure>
+
+ $e_ctr = $item['enclosure#'];
+
+ if ($e_ctr > 0) {
+ $e_item = array($item['enclosure@url'],
+ $item['enclosure@type'],
+ $item['enclosure@length']);
+
+ array_push($enclosures, $e_item);
+
+ for ($i = 0; $i <= $e_ctr; $i++ ) {
+
+ if ($item["enclosure#$i@url"]) {
+ $e_item = array($item["enclosure#$i@url"],
+ $item["enclosure#$i@type"],
+ $item["enclosure#$i@length"]);
+ array_push($enclosures, $e_item);
+ }
+ }
+ }
+
+ // <media:content>
+ // can there be many of those? yes -fox
+
+ $m_ctr = $item['media']['content#'];
+
+ if ($m_ctr > 0) {
+ $e_item = array($item['media']['content@url'],
+ $item['media']['content@medium'],
+ $item['media']['content@length']);
+
+ array_push($enclosures, $e_item);
+
+ for ($i = 0; $i <= $m_ctr; $i++ ) {
+
+ if ($item["media"]["content#$i@url"]) {
+ $e_item = array($item["media"]["content#$i@url"],
+ $item["media"]["content#$i@medium"],
+ $item["media"]["content#$i@length"]);
+ array_push($enclosures, $e_item);
+ }
+ }
+
+ }
+ }
+
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: article enclosures:");
+ print_r($enclosures);
+ }
+
+ db_query($link, "BEGIN");
+
+ foreach ($enclosures as $enc) {
+ $enc_url = db_escape_string($enc[0]);
+ $enc_type = db_escape_string($enc[1]);
+ $enc_dur = db_escape_string($enc[2]);
+
+ $result = db_query($link, "SELECT id FROM ttrss_enclosures
+ WHERE content_url = '$enc_url' AND post_id = '$entry_ref_id'");
+
+ if (db_num_rows($result) == 0) {
+ db_query($link, "INSERT INTO ttrss_enclosures
+ (content_url, content_type, title, duration, post_id) VALUES
+ ('$enc_url', '$enc_type', '', '$enc_dur', '$entry_ref_id')");
+ }
+ }
+
+ db_query($link, "COMMIT");
+
+ // check for manual tags (we have to do it here since they're loaded from filters)
+
+ foreach ($article_filters as $f) {
+ if ($f[0] == "tag") {
+
+ $manual_tags = trim_array(explode(",", $f[1]));
+
+ foreach ($manual_tags as $tag) {
+ if (tag_is_valid($tag)) {
+ array_push($entry_tags, $tag);
+ }
+ }
+ }
+ }
+
+ // Skip boring tags
+
+ $boring_tags = trim_array(explode(",", mb_strtolower(get_pref($link,
+ 'BLACKLISTED_TAGS', $owner_uid, ''), 'utf-8')));
+
+ $filtered_tags = array();
+ $tags_to_cache = array();
+
+ if ($entry_tags && is_array($entry_tags)) {
+ foreach ($entry_tags as $tag) {
+ if (array_search($tag, $boring_tags) === false) {
+ array_push($filtered_tags, $tag);
+ }
+ }
+ }
+
+ $filtered_tags = array_unique($filtered_tags);
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: filtered article tags:");
+ print_r($filtered_tags);
+ }
+
+ // Save article tags in the database
+
+ if (count($filtered_tags) > 0) {
+
+ db_query($link, "BEGIN");
+
+ foreach ($filtered_tags as $tag) {
+
+ $tag = sanitize_tag($tag);
+ $tag = db_escape_string($tag);
+
+ if (!tag_is_valid($tag)) continue;
+
+ $result = db_query($link, "SELECT id FROM ttrss_tags
+ WHERE tag_name = '$tag' AND post_int_id = '$entry_int_id' AND
+ owner_uid = '$owner_uid' LIMIT 1");
+
+ if ($result && db_num_rows($result) == 0) {
+
+ db_query($link, "INSERT INTO ttrss_tags
+ (owner_uid,tag_name,post_int_id)
+ VALUES ('$owner_uid','$tag', '$entry_int_id')");
+ }
+
+ array_push($tags_to_cache, $tag);
+ }
+
+ /* update the cache */
+
+ $tags_to_cache = array_unique($tags_to_cache);
+
+ $tags_str = db_escape_string(join(",", $tags_to_cache));
+
+ db_query($link, "UPDATE ttrss_user_entries
+ SET tag_cache = '$tags_str' WHERE ref_id = '$entry_ref_id'
+ AND owner_uid = $owner_uid");
+
+ db_query($link, "COMMIT");
+ }
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: article processed");
+ }
+ }
+
+ if (!$last_updated) {
+ if ($debug_enabled) {
+ _debug("update_rss_feed: new feed, catching it up...");
+ }
+ catchup_feed($link, $feed, false, $owner_uid);
+ }
+
+ if ($debug_enabled) {
+ _debug("purging feed...");
+ }
+
+ purge_feed($link, $feed, 0, $debug_enabled);
+
+ db_query($link, "UPDATE ttrss_feeds
+ SET last_updated = NOW(), last_error = '' WHERE id = '$feed'");
+
+// db_query($link, "COMMIT");
+
+ } else {
+
+ if ($use_simplepie) {
+ $error_msg = mb_substr($rss->error(), 0, 250);
+ } else {
+ $error_msg = mb_substr(magpie_error(), 0, 250);
+ }
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: error fetching feed: $error_msg");
+ }
+
+ $error_msg = db_escape_string($error_msg);
+
+ db_query($link,
+ "UPDATE ttrss_feeds SET last_error = '$error_msg',
+ last_updated = NOW() WHERE id = '$feed'");
+ }
+
+ if ($use_simplepie) {
+ unset($rss);
+ }
+
+ if ($debug_enabled) {
+ _debug("update_rss_feed: done");
+ }
+
+ }
+
+ function print_select($id, $default, $values, $attributes = "") {
+ print "<select name=\"$id\" id=\"$id\" $attributes>";
+ foreach ($values as $v) {
+ if ($v == $default)
+ $sel = "selected=\"1\"";
+ else
+ $sel = "";
+
+ print "<option value=\"$v\" $sel>$v</option>";
+ }
+ print "</select>";
+ }
+
+ function print_select_hash($id, $default, $values, $attributes = "") {
+ print "<select name=\"$id\" id='$id' $attributes>";
+ foreach (array_keys($values) as $v) {
+ if ($v == $default)
+ $sel = 'selected="selected"';
+ else
+ $sel = "";
+
+ print "<option $sel value=\"$v\">".$values[$v]."</option>";
+ }
+
+ print "</select>";
+ }
+
+ function get_article_filters($filters, $title, $content, $link, $timestamp, $author, $tags) {
+ $matches = array();
+
+ if ($filters["title"]) {
+ foreach ($filters["title"] as $filter) {
+ $reg_exp = $filter["reg_exp"];
+ $inverse = $filter["inverse"];
+ if ((!$inverse && @preg_match("/$reg_exp/i", $title)) ||
+ ($inverse && !@preg_match("/$reg_exp/i", $title))) {
+
+ array_push($matches, array($filter["action"], $filter["action_param"]));
+ }
+ }
+ }
+
+ if ($filters["content"]) {
+ foreach ($filters["content"] as $filter) {
+ $reg_exp = $filter["reg_exp"];
+ $inverse = $filter["inverse"];
+
+ if ((!$inverse && @preg_match("/$reg_exp/i", $content)) ||
+ ($inverse && !@preg_match("/$reg_exp/i", $content))) {
+
+ array_push($matches, array($filter["action"], $filter["action_param"]));
+ }
+ }
+ }
+
+ if ($filters["both"]) {
+ foreach ($filters["both"] as $filter) {
+ $reg_exp = $filter["reg_exp"];
+ $inverse = $filter["inverse"];
+
+ if ($inverse) {
+ if (!@preg_match("/$reg_exp/i", $title) && !preg_match("/$reg_exp/i", $content)) {
+ array_push($matches, array($filter["action"], $filter["action_param"]));
+ }
+ } else {
+ if (@preg_match("/$reg_exp/i", $title) || preg_match("/$reg_exp/i", $content)) {
+ array_push($matches, array($filter["action"], $filter["action_param"]));
+ }
+ }
+ }
+ }
+
+ if ($filters["link"]) {
+ $reg_exp = $filter["reg_exp"];
+ foreach ($filters["link"] as $filter) {
+ $reg_exp = $filter["reg_exp"];
+ $inverse = $filter["inverse"];
+
+ if ((!$inverse && @preg_match("/$reg_exp/i", $link)) ||
+ ($inverse && !@preg_match("/$reg_exp/i", $link))) {
+
+ array_push($matches, array($filter["action"], $filter["action_param"]));
+ }
+ }
+ }
+
+ if ($filters["date"]) {
+ $reg_exp = $filter["reg_exp"];
+ foreach ($filters["date"] as $filter) {
+ $date_modifier = $filter["filter_param"];
+ $inverse = $filter["inverse"];
+ $check_timestamp = strtotime($filter["reg_exp"]);
+
+ # no-op when timestamp doesn't parse to prevent misfires
+
+ if ($check_timestamp) {
+ $match_ok = false;
+
+ if ($date_modifier == "before" && $timestamp < $check_timestamp ||
+ $date_modifier == "after" && $timestamp > $check_timestamp) {
+ $match_ok = true;
+ }
+
+ if ($inverse) $match_ok = !$match_ok;
+
+ if ($match_ok) {
+ array_push($matches, array($filter["action"], $filter["action_param"]));
+ }
+ }
+ }
+ }
+
+ if ($filters["author"]) {
+ foreach ($filters["author"] as $filter) {
+ $reg_exp = $filter["reg_exp"];
+ $inverse = $filter["inverse"];
+ if ((!$inverse && @preg_match("/$reg_exp/i", $author)) ||
+ ($inverse && !@preg_match("/$reg_exp/i", $author))) {
+
+ array_push($matches, array($filter["action"], $filter["action_param"]));
+ }
+ }
+ }
+
+ if ($filters["tag"]) {
+
+ $tag_string = join(",", $tags);
+
+ foreach ($filters["tag"] as $filter) {
+ $reg_exp = $filter["reg_exp"];
+ $inverse = $filter["inverse"];
+
+ if ((!$inverse && @preg_match("/$reg_exp/i", $tag_string)) ||
+ ($inverse && !@preg_match("/$reg_exp/i", $tag_string))) {
+
+ array_push($matches, array($filter["action"], $filter["action_param"]));
+ }
+ }
+ }
+
+
+ return $matches;
+ }
+
+ function find_article_filter($filters, $filter_name) {
+ foreach ($filters as $f) {
+ if ($f[0] == $filter_name) {
+ return $f;
+ };
+ }
+ return false;
+ }
+
+ function calculate_article_score($filters) {
+ $score = 0;
+
+ foreach ($filters as $f) {
+ if ($f[0] == "score") {
+ $score += $f[1];
+ };
+ }
+ return $score;
+ }
+
+ function assign_article_to_labels($link, $id, $filters, $owner_uid) {
+ foreach ($filters as $f) {
+ if ($f[0] == "label") {
+ label_add_article($link, $id, $f[1], $owner_uid);
+ };
+ }
+ }
+
+ 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) {
+
+ if ($v == $default)
+ $sel = "checked";
+ else
+ $sel = "";
+
+ if ($v == $true_is) {
+ $sel .= " value=\"1\"";
+ } else {
+ $sel .= " value=\"0\"";
+ }
+
+ print "<input class=\"noborder\" dojoType=\"dijit.form.RadioButton\"
+ type=\"radio\" $sel $attributes name=\"$id\"> $v ";
+
+ }
+ }
+
+ function initialize_user_prefs($link, $uid, $profile = false) {
+
+ $uid = db_escape_string($uid);
+
+ if (!$profile) {
+ $profile = "NULL";
+ $profile_qpart = "AND profile IS NULL";
+ } else {
+ $profile_qpart = "AND profile = '$profile'";
+ }
+
+ if (get_schema_version($link) < 63) $profile_qpart = "";
+
+ db_query($link, "BEGIN");
+
+ $result = db_query($link, "SELECT pref_name,def_value FROM ttrss_prefs");
+
+ $u_result = db_query($link, "SELECT pref_name
+ FROM ttrss_user_prefs WHERE owner_uid = '$uid' $profile_qpart");
+
+ $active_prefs = array();
+
+ while ($line = db_fetch_assoc($u_result)) {
+ array_push($active_prefs, $line["pref_name"]);
+ }
+
+ while ($line = db_fetch_assoc($result)) {
+ 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
+ (owner_uid,pref_name,value) VALUES
+ ('$uid', '".$line["pref_name"]."','".$line["def_value"]."')");
+
+ } else {
+ db_query($link, "INSERT INTO ttrss_user_prefs
+ (owner_uid,pref_name,value, profile) VALUES
+ ('$uid', '".$line["pref_name"]."','".$line["def_value"]."', $profile)");
+ }
+
+ }
+ }
+
+ db_query($link, "COMMIT");
+
+ }
+
+ function get_ssl_certificate_id() {
+ if ($_SERVER["REDIRECT_SSL_CLIENT_M_SERIAL"]) {
+ return sha1($_SERVER["REDIRECT_SSL_CLIENT_M_SERIAL"] .
+ $_SERVER["REDIRECT_SSL_CLIENT_V_START"] .
+ $_SERVER["REDIRECT_SSL_CLIENT_V_END"] .
+ $_SERVER["REDIRECT_SSL_CLIENT_S_DN"]);
+ }
+ return "";
+ }
+
+ function get_login_by_ssl_certificate($link) {
+
+ $cert_serial = db_escape_string(get_ssl_certificate_id());
+
+ if ($cert_serial) {
+ $result = db_query($link, "SELECT login FROM ttrss_user_prefs, ttrss_users
+ WHERE pref_name = 'SSL_CERT_SERIAL' AND value = '$cert_serial' AND
+ owner_uid = ttrss_users.id");
+
+ if (db_num_rows($result) != 0) {
+ return db_escape_string(db_fetch_result($result, 0, "login"));
+ }
+ }
+
+ return "";
+ }
+
+ function get_remote_user($link) {
+
+ if (defined('ALLOW_REMOTE_USER_AUTH') && ALLOW_REMOTE_USER_AUTH) {
+ return db_escape_string($_SERVER["REMOTE_USER"]);
+ }
+
+ return db_escape_string(get_login_by_ssl_certificate($link));
+ }
+
+ function get_remote_fakepass($link) {
+ if (get_remote_user($link))
+ return "******";
+ else
+ return "";
+ }
+
+ function authenticate_user($link, $login, $password, $force_auth = false) {
+
+ if (!SINGLE_USER_MODE) {
+
+ $pwd_hash1 = encrypt_password($password);
+ $pwd_hash2 = encrypt_password($password, $login);
+ $login = db_escape_string($login);
+
+ $remote_user = get_remote_user($link);
+
+ if ($remote_user && $remote_user == $login && $login != "admin") {
+
+ $login = $remote_user;
+
+ $query = "SELECT id,login,access_level,pwd_hash
+ FROM ttrss_users WHERE
+ login = '$login'";
+
+ if (defined('AUTO_CREATE_USER') && AUTO_CREATE_USER
+ && $_SERVER["REMOTE_USER"]) {
+ $result = db_query($link, $query);
+
+ // First login ?
+ if (db_num_rows($result) == 0) {
+ $query2 = "INSERT INTO ttrss_users
+ (login,access_level,last_login,created)
+ VALUES ('$login', 0, null, NOW())";
+ db_query($link, $query2);
+ }
+ }
+
+ } else {
+ $query = "SELECT id,login,access_level,pwd_hash
+ FROM ttrss_users WHERE
+ login = '$login' AND (pwd_hash = '$pwd_hash1' OR
+ pwd_hash = '$pwd_hash2')";
+ }
+
+ $result = db_query($link, $query);
+
+ if (db_num_rows($result) == 1) {
+ $_SESSION["uid"] = db_fetch_result($result, 0, "id");
+ $_SESSION["name"] = db_fetch_result($result, 0, "login");
+ $_SESSION["access_level"] = db_fetch_result($result, 0, "access_level");
+
+ db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " .
+ $_SESSION["uid"]);
+
+
+ // LemonLDAP can send user informations via HTTP HEADER
+ if (defined('AUTO_CREATE_USER') && AUTO_CREATE_USER){
+ // update user name
+ $fullname = $_SERVER['HTTP_USER_NAME'] ? $_SERVER['HTTP_USER_NAME'] : $_SERVER['AUTHENTICATE_CN'];
+ if ($fullname){
+ $fullname = db_escape_string($fullname);
+ db_query($link, "UPDATE ttrss_users SET full_name = '$fullname' WHERE id = " .
+ $_SESSION["uid"]);
+ }
+ // update user mail
+ $email = $_SERVER['HTTP_USER_MAIL'] ? $_SERVER['HTTP_USER_MAIL'] : $_SERVER['AUTHENTICATE_MAIL'];
+ if ($email){
+ $email = db_escape_string($email);
+ db_query($link, "UPDATE ttrss_users SET email = '$email' WHERE id = " .
+ $_SESSION["uid"]);
+ }
+ }
+
+ $_SESSION["ip_address"] = $_SERVER["REMOTE_ADDR"];
+ $_SESSION["pwd_hash"] = db_fetch_result($result, 0, "pwd_hash");
+
+ $_SESSION["last_version_check"] = time();
+
+ initialize_user_prefs($link, $_SESSION["uid"]);
+
+ return true;
+ }
+
+ return false;
+
+ } else {
+
+ $_SESSION["uid"] = 1;
+ $_SESSION["name"] = "admin";
+
+ $_SESSION["ip_address"] = $_SERVER["REMOTE_ADDR"];
+
+ initialize_user_prefs($link, $_SESSION["uid"]);
+
+ return true;
+ }
+ }
+
+ function make_password($length = 8) {
+
+ $password = "";
+ $possible = "0123456789abcdfghjkmnpqrstvwxyzABCDFGHJKMNPQRSTVWXYZ";
+
+ $i = 0;
+
+ while ($i < $length) {
+ $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
+
+ if (!strstr($password, $char)) {
+ $password .= $char;
+ $i++;
+ }
+ }
+ return $password;
+ }
+
+ // this is called after user is created to initialize default feeds, labels
+ // or whatever else
+
+ // user preferences are checked on every login, not here
+
+ function initialize_user($link, $uid) {
+
+ db_query($link, "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)
+ values ('$uid', 'Tiny Tiny RSS: Forum',
+ 'http://tt-rss.org/forum/rss.php')");
+ }
+
+ function logout_user() {
+ session_destroy();
+ if (isset($_COOKIE[session_name()])) {
+ setcookie(session_name(), '', time()-42000, '/');
+ }
+ }
+
+ 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 login_sequence($link, $mobile = false) {
+ $_SESSION["prefs_cache"] = array();
+
+ if (!SINGLE_USER_MODE) {
+
+ $login_action = $_POST["login_action"];
+
+ # try to authenticate user if called from login form
+ if ($login_action == "do_login") {
+ $login = db_escape_string($_POST["login"]);
+ $password = $_POST["password"];
+ $remember_me = $_POST["remember_me"];
+
+ if (authenticate_user($link, $login, $password)) {
+ $_POST["password"] = "";
+
+ $_SESSION["language"] = $_POST["language"];
+ $_SESSION["ref_schema_version"] = get_schema_version($link, true);
+ $_SESSION["bw_limit"] = !!$_POST["bw_limit"];
+
+ if ($_POST["profile"]) {
+
+ $profile = db_escape_string($_POST["profile"]);
+
+ $result = db_query($link, "SELECT id FROM ttrss_settings_profiles
+ WHERE id = '$profile' AND owner_uid = " . $_SESSION["uid"]);
+
+ if (db_num_rows($result) != 0) {
+ $_SESSION["profile"] = $profile;
+ $_SESSION["prefs_cache"] = array();
+ }
+ }
+
+ if ($_REQUEST['return']) {
+ header("Location: " . $_REQUEST['return']);
+ } else {
+ header("Location: " . $_SERVER["REQUEST_URI"]);
+ }
+
+ exit;
+
+ return;
+ } else {
+ $_SESSION["login_error_msg"] = __("Incorrect username or password");
+ }
+ }
+
+ if (!$_SESSION["uid"] || !validate_session($link)) {
+
+ if (get_remote_user($link) && AUTO_LOGIN) {
+ authenticate_user($link, get_remote_user($link), null);
+ $_SESSION["ref_schema_version"] = get_schema_version($link, true);
+ } else {
+ render_login_form($link, $mobile);
+ //header("Location: login.php");
+ exit;
+ }
+ } else {
+ /* bump login timestamp */
+ db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " .
+ $_SESSION["uid"]);
+
+ if ($_SESSION["language"] && SESSION_COOKIE_LIFETIME > 0) {
+ setcookie("ttrss_lang", $_SESSION["language"],
+ time() + SESSION_COOKIE_LIFETIME);
+ }
+
+ // try to remove possible duplicates from feed counter cache
+// ccache_cleanup($link, $_SESSION["uid"]);
+ }
+
+ } else {
+ return authenticate_user($link, "admin", null);
+ }
+ }
+
+ function truncate_string($str, $max_len, $suffix = '…') {
+ if (mb_strlen($str, "utf-8") > $max_len - 3) {
+ return mb_substr($str, 0, $max_len, "utf-8") . $suffix;
+ } else {
+ return $str;
+ }
+ }
+
+ function theme_image($link, $filename) {
+ if ($link) {
+ $theme_path = get_user_theme_path($link);
+
+ if ($theme_path && is_file($theme_path.$filename)) {
+ return $theme_path.$filename;
+ } else {
+ return $filename;
+ }
+ } else {
+ return $filename;
+ }
+ }
+
+ function get_user_theme($link) {
+
+ if (get_schema_version($link) >= 63 && $_SESSION["uid"]) {
+ $theme_name = get_pref($link, "_THEME_ID");
+ if (is_dir("themes/$theme_name")) {
+ return $theme_name;
+ } else {
+ return '';
+ }
+ } else {
+ return '';
+ }
+
+ }
+
+ function get_user_theme_path($link) {
+ $theme_path = '';
+
+ if (get_schema_version($link) >= 63 && $_SESSION["uid"]) {
+ $theme_name = get_pref($link, "_THEME_ID");
+
+ if ($theme_name && is_dir("themes/$theme_name")) {
+ $theme_path = "themes/$theme_name/";
+ } else {
+ $theme_name = '';
+ }
+ } else {
+ $theme_path = '';
+ }
+
+ if ($theme_path) {
+ if (is_file("$theme_path/theme.ini")) {
+ $ini = parse_ini_file("$theme_path/theme.ini", true);
+ if ($ini['theme']['version'] >= THEME_VERSION_REQUIRED) {
+ return $theme_path;
+ }
+ }
+ }
+ return '';
+ }
+
+ function get_user_theme_options($link) {
+ $t = get_user_theme_path($link);
+
+ if ($t) {
+ if (is_file("$t/theme.ini")) {
+ $ini = parse_ini_file("$t/theme.ini", true);
+ if ($ini['theme']['version']) {
+ return $ini['theme']['options'];
+ }
+ }
+ }
+ return '';
+ }
+
+ function print_theme_includes($link) {
+
+ $t = get_user_theme_path($link);
+ $time = time();
+
+ if ($t) {
+ print "<link rel=\"stylesheet\" type=\"text/css\"
+ href=\"$t/theme.css?$time \">";
+ if (file_exists("$t/theme.js")) {
+ print "<script type=\"text/javascript\" src=\"$t/theme.js?$time\">
+ </script>";
+ }
+ }
+ }
+
+ function get_all_themes() {
+ $themes = glob("themes/*");
+
+ asort($themes);
+
+ $rv = array();
+
+ foreach ($themes as $t) {
+ if (is_file("$t/theme.ini")) {
+ $ini = parse_ini_file("$t/theme.ini", true);
+ if ($ini['theme']['version'] >= THEME_VERSION_REQUIRED &&
+ !$ini['theme']['disabled']) {
+ $entry = array();
+ $entry["path"] = $t;
+ $entry["base"] = basename($t);
+ $entry["name"] = $ini['theme']['name'];
+ $entry["version"] = $ini['theme']['version'];
+ $entry["author"] = $ini['theme']['author'];
+ $entry["options"] = $ini['theme']['options'];
+ array_push($rv, $entry);
+ }
+ }
+ }
+
+ return $rv;
+ }
+
+ function convert_timestamp($timestamp, $source_tz, $dest_tz) {
+
+ try {
+ $source_tz = new DateTimeZone($source_tz);
+ } catch (Exception $e) {
+ $source_tz = new DateTimeZone('UTC');
+ }
+
+ try {
+ $dest_tz = new DateTimeZone($dest_tz);
+ } catch (Exception $e) {
+ $dest_tz = new DateTimeZone('UTC');
+ }
+
+ $dt = new DateTime(date('Y-m-d H:i:s', $timestamp), $source_tz);
+ return $dt->format('U') + $dest_tz->getOffset($dt);
+ }
+
+ function make_local_datetime($link, $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;
+
+ # We store date in UTC internally
+ $dt = new DateTime($timestamp, $utc_tz);
+
+ if ($tz_offset == -1) {
+
+ $user_tz_string = get_pref($link, 'USER_TIMEZONE', $owner_uid);
+
+ try {
+ $user_tz = new DateTimeZone($user_tz_string);
+ } catch (Exception $e) {
+ $user_tz = $utc_tz;
+ }
+
+ $tz_offset = $user_tz->getOffset($dt);
+ }
+
+ $user_timestamp = $dt->format('U') + $tz_offset;
+
+ if (!$no_smart_dt) {
+ return smart_date_time($link, $user_timestamp,
+ $tz_offset, $owner_uid);
+ } else {
+ if ($long)
+ $format = get_pref($link, 'LONG_DATE_FORMAT', $owner_uid);
+ else
+ $format = get_pref($link, 'SHORT_DATE_FORMAT', $owner_uid);
+
+ return date($format, $user_timestamp);
+ }
+ }
+
+ function smart_date_time($link, $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);
+ return date($format, $timestamp);
+ } else {
+ $format = get_pref($link, 'LONG_DATE_FORMAT', $owner_uid);
+ return date($format, $timestamp);
+ }
+ }
+
+ function sql_bool_to_bool($s) {
+ if ($s == "t" || $s == "1" || $s == "true") {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ function bool_to_sql_bool($s) {
+ if ($s) {
+ return "true";
+ } else {
+ return "false";
+ }
+ }
+
+ // 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) {
+ global $schema_version;
+
+ if (!$schema_version) {
+ $result = db_query($link, "SELECT schema_version FROM ttrss_version");
+ $version = db_fetch_result($result, 0, "schema_version");
+ $schema_version = $version;
+ return $version;
+ } else {
+ return $schema_version;
+ }
+ }
+
+ function sanity_check($link) {
+ require_once 'errors.php';
+
+ $error_code = 0;
+ $schema_version = get_schema_version($link, true);
+
+ if ($schema_version != SCHEMA_VERSION) {
+ $error_code = 5;
+ }
+
+ if (DB_TYPE == "mysql") {
+ $result = db_query($link, "SELECT true", false);
+ if (db_num_rows($result) != 1) {
+ $error_code = 10;
+ }
+ }
+
+ if (db_escape_string("testTEST") != "testTEST") {
+ $error_code = 12;
+ }
+
+ return array("code" => $error_code, "message" => $ERRORS[$error_code]);
+ }
+
+ function file_is_locked($filename) {
+ if (function_exists('flock')) {
+ $fp = @fopen(LOCK_DIRECTORY . "/$filename", "r");
+ if ($fp) {
+ if (flock($fp, LOCK_EX | LOCK_NB)) {
+ flock($fp, LOCK_UN);
+ fclose($fp);
+ return false;
+ }
+ fclose($fp);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return true; // consider the file always locked and skip the test
+ }
+
+ function make_lockfile($filename) {
+ $fp = fopen(LOCK_DIRECTORY . "/$filename", "w");
+
+ if (flock($fp, LOCK_EX | LOCK_NB)) {
+ if (function_exists('posix_getpid')) {
+ fwrite($fp, posix_getpid() . "\n");
+ }
+ return $fp;
+ } else {
+ return false;
+ }
+ }
+
+ function make_stampfile($filename) {
+ $fp = fopen(LOCK_DIRECTORY . "/$filename", "w");
+
+ if (flock($fp, LOCK_EX | LOCK_NB)) {
+ fwrite($fp, time() . "\n");
+ flock($fp, LOCK_UN);
+ fclose($fp);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ function sql_random_function() {
+ if (DB_TYPE == "mysql") {
+ return "RAND()";
+ } else {
+ return "RANDOM()";
+ }
+ }
+
+ function catchup_feed($link, $feed, $cat_view, $owner_uid = false) {
+
+ if (!$owner_uid) $owner_uid = $_SESSION['uid'];
+
+ //if (preg_match("/^-?[0-9][0-9]*$/", $feed) != false) {
+
+ if (is_numeric($feed)) {
+ if ($cat_view) {
+
+ if ($feed >= 0) {
+
+ if ($feed > 0) {
+ $cat_qpart = "cat_id = '$feed'";
+ } else {
+ $cat_qpart = "cat_id IS NULL";
+ }
+
+ $tmp_result = db_query($link, "SELECT id
+ FROM ttrss_feeds WHERE $cat_qpart AND owner_uid = $owner_uid");
+
+ while ($tmp_line = db_fetch_assoc($tmp_result)) {
+
+ $tmp_feed = $tmp_line["id"];
+
+ db_query($link, "UPDATE ttrss_user_entries
+ SET unread = false,last_read = NOW()
+ WHERE feed_id = '$tmp_feed' AND owner_uid = $owner_uid");
+ }
+ } else if ($feed == -2) {
+
+ db_query($link, "UPDATE ttrss_user_entries
+ SET unread = false,last_read = NOW() WHERE (SELECT COUNT(*)
+ FROM ttrss_user_labels2 WHERE article_id = ref_id) > 0
+ AND unread = true 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 owner_uid = $owner_uid");
+
+ } else if ($feed < 0 && $feed > -10) { // special, like starred
+
+ if ($feed == -1) {
+ db_query($link, "UPDATE ttrss_user_entries
+ SET unread = false,last_read = NOW()
+ WHERE marked = true AND owner_uid = $owner_uid");
+ }
+
+ if ($feed == -2) {
+ db_query($link, "UPDATE ttrss_user_entries
+ SET unread = false,last_read = NOW()
+ WHERE published = true AND owner_uid = $owner_uid");
+ }
+
+ if ($feed == -3) {
+
+ $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE");
+
+ if (DB_TYPE == "pgsql") {
+ $match_part = "updated > NOW() - INTERVAL '$intl hour' ";
+ } else {
+ $match_part = "updated > 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);
+ }
+
+ if ($feed == -4) {
+ db_query($link, "UPDATE ttrss_user_entries
+ SET unread = false,last_read = NOW()
+ WHERE owner_uid = $owner_uid");
+ }
+
+ } else if ($feed < -10) { // label
+
+ $label_id = -$feed - 11;
+
+ 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 owner_uid = '$owner_uid' AND ref_id = article_id");
+
+ }
+
+ ccache_update($link, $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");
+
+ while ($line = db_fetch_assoc($result)) {
+ db_query($link, "UPDATE ttrss_user_entries SET
+ unread = false, last_read = NOW()
+ WHERE int_id = " . $line["post_int_id"]);
+ }
+ db_query($link, "COMMIT");
+ }
+ }
+
+ function getAllCounters($link, $omode = "flc", $active_feed = false) {
+
+ if (!$omode) $omode = "flc";
+
+ $data = getGlobalCounters($link);
+
+ $data = array_merge($data, getVirtCounters($link));
+
+ if (strchr($omode, "l")) $data = array_merge($data, getLabelCounters($link));
+ if (strchr($omode, "f")) $data = array_merge($data, getFeedCounters($link, $active_feed));
+ if (strchr($omode, "t")) $data = array_merge($data, getTagCounters($link));
+ if (strchr($omode, "c")) $data = array_merge($data, getCategoryCounters($link));
+
+ return $data;
+ }
+
+ function getCategoryCounters($link) {
+ $ret_arr = array();
+
+ /* Labels category */
+
+ $cv = array("id" => -2, "kind" => "cat",
+ "counter" => getCategoryUnread($link, -2));
+
+ array_push($ret_arr, $cv);
+
+ $age_qpart = getMaxAgeSubquery();
+
+ $result = db_query($link, "SELECT id AS cat_id, value AS unread
+ FROM ttrss_feed_categories, ttrss_cat_counters_cache
+ WHERE ttrss_cat_counters_cache.feed_id = id AND
+ ttrss_feed_categories.owner_uid = " . $_SESSION["uid"]);
+
+ while ($line = db_fetch_assoc($result)) {
+ $line["cat_id"] = (int) $line["cat_id"];
+
+ $cv = array("id" => $line["cat_id"], "kind" => "cat",
+ "counter" => $line["unread"]);
+
+ array_push($ret_arr, $cv);
+ }
+
+ /* Special case: NULL category doesn't actually exist in the DB */
+
+ $cv = array("id" => 0, "kind" => "cat",
+ "counter" => ccache_find($link, 0, $_SESSION["uid"], true));
+
+ array_push($ret_arr, $cv);
+
+ return $ret_arr;
+ }
+
+ function getCategoryUnread($link, $cat, $owner_uid = false) {
+
+ if (!$owner_uid) $owner_uid = $_SESSION["uid"];
+
+ if ($cat >= 0) {
+
+ if ($cat != 0) {
+ $cat_query = "cat_id = '$cat'";
+ } else {
+ $cat_query = "cat_id IS NULL";
+ }
+
+ $age_qpart = getMaxAgeSubquery();
+
+ $result = db_query($link, "SELECT id FROM ttrss_feeds WHERE $cat_query
+ AND owner_uid = " . $owner_uid);
+
+ $cat_feeds = array();
+ while ($line = db_fetch_assoc($result)) {
+ array_push($cat_feeds, "feed_id = " . $line["id"]);
+ }
+
+ if (count($cat_feeds) == 0) return 0;
+
+ $match_part = implode(" OR ", $cat_feeds);
+
+ $result = db_query($link, "SELECT COUNT(int_id) AS unread
+ FROM ttrss_user_entries,ttrss_entries
+ WHERE unread = true AND ($match_part) AND id = ref_id
+ AND $age_qpart AND owner_uid = " . $owner_uid);
+
+ $unread = 0;
+
+ # this needs to be rewritten
+ while ($line = db_fetch_assoc($result)) {
+ $unread += $line["unread"];
+ }
+
+ return $unread;
+ } else if ($cat == -1) {
+ return getFeedUnread($link, -1) + getFeedUnread($link, -2) + getFeedUnread($link, -3) + getFeedUnread($link, 0);
+ } else if ($cat == -2) {
+
+ $result = db_query($link, "
+ SELECT COUNT(unread) AS unread FROM
+ ttrss_user_entries, ttrss_labels2, ttrss_user_labels2, ttrss_feeds
+ WHERE label_id = ttrss_labels2.id AND article_id = ref_id AND
+ ttrss_labels2.owner_uid = '$owner_uid'
+ AND unread = true AND feed_id = ttrss_feeds.id
+ AND ttrss_user_entries.owner_uid = '$owner_uid'");
+
+ $unread = db_fetch_result($result, 0, "unread");
+
+ return $unread;
+
+ }
+ }
+
+ function getMaxAgeSubquery($days = COUNTERS_MAX_AGE) {
+ if (DB_TYPE == "pgsql") {
+ return "ttrss_entries.date_updated >
+ NOW() - INTERVAL '$days days'";
+ } else {
+ return "ttrss_entries.date_updated >
+ DATE_SUB(NOW(), INTERVAL $days DAY)";
+ }
+ }
+
+ function getFeedUnread($link, $feed, $is_cat = false) {
+ return getFeedArticles($link, $feed, $is_cat, true, $_SESSION["uid"]);
+ }
+
+ function getLabelUnread($link, $label_id, $owner_uid = false) {
+ if (!$owner_uid) $owner_uid = $_SESSION["uid"];
+
+ $result = db_query($link, "
+ SELECT COUNT(unread) AS unread FROM
+ ttrss_user_entries, ttrss_labels2, ttrss_user_labels2, ttrss_feeds
+ WHERE label_id = ttrss_labels2.id AND article_id = ref_id AND
+ ttrss_labels2.owner_uid = '$owner_uid' AND ttrss_labels2.id = '$label_id'
+ AND unread = true AND feed_id = ttrss_feeds.id
+ AND ttrss_user_entries.owner_uid = '$owner_uid'");
+
+ if (db_num_rows($result) != 0) {
+ return db_fetch_result($result, 0, "unread");
+ } else {
+ return 0;
+ }
+ }
+
+ function getFeedArticles($link, $feed, $is_cat = false, $unread_only = false,
+ $owner_uid = false) {
+
+ $n_feed = (int) $feed;
+
+ if (!$owner_uid) $owner_uid = $_SESSION["uid"];
+
+ if ($unread_only) {
+ $unread_qpart = "unread = true";
+ } else {
+ $unread_qpart = "true";
+ }
+
+ $age_qpart = getMaxAgeSubquery();
+
+ if ($is_cat) {
+ return getCategoryUnread($link, $n_feed, $owner_uid);
+ } if ($feed != "0" && $n_feed == 0) {
+
+ $feed = db_escape_string($feed);
+
+ $result = db_query($link, "SELECT SUM((SELECT COUNT(int_id)
+ FROM ttrss_user_entries,ttrss_entries WHERE int_id = post_int_id
+ AND ref_id = id AND $age_qpart
+ AND $unread_qpart)) AS count FROM ttrss_tags
+ WHERE owner_uid = $owner_uid AND tag_name = '$feed'");
+ return db_fetch_result($result, 0, "count");
+
+ } else if ($n_feed == -1) {
+ $match_part = "marked = true";
+ } else if ($n_feed == -2) {
+ $match_part = "published = true";
+ } else if ($n_feed == -3) {
+ $match_part = "unread = true AND score >= 0";
+
+ $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE", $owner_uid);
+
+ if (DB_TYPE == "pgsql") {
+ $match_part .= " AND updated > NOW() - INTERVAL '$intl hour' ";
+ } else {
+ $match_part .= " AND updated > DATE_SUB(NOW(), INTERVAL $intl HOUR) ";
+ }
+ } else if ($n_feed == -4) {
+ $match_part = "true";
+ } else if ($n_feed >= 0) {
+
+ if ($n_feed != 0) {
+ $match_part = "feed_id = '$n_feed'";
+ } else {
+ $match_part = "feed_id IS NULL";
+ }
+
+ } else if ($feed < -10) {
+
+ $label_id = -$feed - 11;
+
+ return getLabelUnread($link, $label_id, $owner_uid);
+
+ }
+
+ if ($match_part) {
+
+ if ($n_feed != 0) {
+ $from_qpart = "ttrss_user_entries,ttrss_feeds,ttrss_entries";
+ $feeds_qpart = "ttrss_user_entries.feed_id = ttrss_feeds.id AND";
+ } else {
+ $from_qpart = "ttrss_user_entries,ttrss_entries";
+ $feeds_qpart = '';
+ }
+
+ $query = "SELECT count(int_id) AS unread
+ FROM $from_qpart WHERE
+ ttrss_user_entries.ref_id = ttrss_entries.id AND
+ $age_qpart AND
+ $feeds_qpart
+ $unread_qpart AND ($match_part) AND ttrss_user_entries.owner_uid = $owner_uid";
+
+ $result = db_query($link, $query);
+
+ } else {
+
+ $result = db_query($link, "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 $age_qpart AND
+ ttrss_tags.owner_uid = " . $owner_uid);
+ }
+
+ $unread = db_fetch_result($result, 0, "unread");
+
+ return $unread;
+ }
+
+ function getGlobalUnread($link, $user_id = false) {
+
+ if (!$user_id) {
+ $user_id = $_SESSION["uid"];
+ }
+
+ $result = db_query($link, "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");
+
+ return $c_id;
+ }
+
+ function getGlobalCounters($link, $global_unread = -1) {
+ $ret_arr = array();
+
+ if ($global_unread == -1) {
+ $global_unread = getGlobalUnread($link);
+ }
+
+ $cv = array("id" => "global-unread",
+ "counter" => $global_unread);
+
+ array_push($ret_arr, $cv);
+
+ $result = db_query($link, "SELECT COUNT(id) AS fn FROM
+ ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]);
+
+ $subscribed_feeds = db_fetch_result($result, 0, "fn");
+
+ $cv = array("id" => "subscribed-feeds",
+ "counter" => $subscribed_feeds);
+
+ array_push($ret_arr, $cv);
+
+ return $ret_arr;
+ }
+
+ function getTagCounters($link) {
+
+ $ret_arr = array();
+
+ $age_qpart = getMaxAgeSubquery();
+
+ $result = db_query($link, "SELECT tag_name,SUM((SELECT COUNT(int_id)
+ FROM ttrss_user_entries,ttrss_entries WHERE int_id = post_int_id
+ AND ref_id = id AND $age_qpart
+ AND unread = true)) AS count FROM ttrss_tags
+ WHERE owner_uid = ".$_SESSION['uid']." GROUP BY tag_name
+ ORDER BY count DESC LIMIT 55");
+
+ $tags = array();
+
+ while ($line = db_fetch_assoc($result)) {
+ $tags[$line["tag_name"]] += $line["count"];
+ }
+
+ foreach (array_keys($tags) as $tag) {
+ $unread = $tags[$tag];
+ $tag = htmlspecialchars($tag);
+
+ $cv = array("id" => $tag,
+ "kind" => "tag",
+ "counter" => $unread);
+
+ array_push($ret_arr, $cv);
+ }
+
+ return $ret_arr;
+ }
+
+ function getVirtCounters($link) {
+
+ $ret_arr = array();
+
+ for ($i = 0; $i >= -4; $i--) {
+
+ $count = getFeedUnread($link, $i);
+
+ $cv = array("id" => $i,
+ "counter" => $count);
+
+// if (get_pref($link, 'EXTENDED_FEEDLIST'))
+// $cv["xmsg"] = getFeedArticles($link, $i)." ".__("total");
+
+ array_push($ret_arr, $cv);
+ }
+
+ return $ret_arr;
+ }
+
+ function getLabelCounters($link, $descriptions = false) {
+
+ $ret_arr = array();
+
+ $age_qpart = getMaxAgeSubquery();
+
+ $owner_uid = $_SESSION["uid"];
+
+ $result = db_query($link, "SELECT id, caption FROM ttrss_labels2
+ WHERE owner_uid = '$owner_uid'");
+
+ while ($line = db_fetch_assoc($result)) {
+
+ $id = -$line["id"] - 11;
+
+ $label_name = $line["caption"];
+ $count = getFeedUnread($link, $id);
+
+ $cv = array("id" => $id,
+ "counter" => $count);
+
+ if ($descriptions)
+ $cv["description"] = $label_name;
+
+// if (get_pref($link, 'EXTENDED_FEEDLIST'))
+// $cv["xmsg"] = getFeedArticles($link, $id)." ".__("total");
+
+ array_push($ret_arr, $cv);
+ }
+
+ return $ret_arr;
+ }
+
+ function getFeedCounters($link, $active_feed = false) {
+
+ $ret_arr = array();
+
+ $age_qpart = getMaxAgeSubquery();
+
+ $query = "SELECT ttrss_feeds.id,
+ ttrss_feeds.title,
+ ".SUBSTRING_FOR_DATE."(ttrss_feeds.last_updated,1,19) AS last_updated,
+ last_error, value AS count
+ FROM ttrss_feeds, ttrss_counters_cache
+ WHERE ttrss_feeds.owner_uid = ".$_SESSION["uid"]."
+ AND ttrss_counters_cache.feed_id = id";
+
+ $result = db_query($link, $query);
+ $fctrs_modified = false;
+
+ while ($line = db_fetch_assoc($result)) {
+
+ $id = $line["id"];
+ $count = $line["count"];
+ $last_error = htmlspecialchars($line["last_error"]);
+
+ $last_updated = make_local_datetime($link, $line['last_updated'], false);
+
+ $has_img = feed_has_icon($id);
+
+ if (date('Y') - date('Y', strtotime($line['last_updated'])) > 2)
+ $last_updated = '';
+
+ $cv = array("id" => $id,
+ "updated" => $last_updated,
+ "counter" => $count,
+ "has_img" => (int) $has_img);
+
+ if ($last_error)
+ $cv["error"] = $last_error;
+
+// if (get_pref($link, 'EXTENDED_FEEDLIST'))
+// $cv["xmsg"] = getFeedArticles($link, $id)." ".__("total");
+
+ if ($active_feed && $id == $active_feed)
+ $cv["title"] = truncate_string($line["title"], 30);
+
+ array_push($ret_arr, $cv);
+
+ }
+
+ return $ret_arr;
+ }
+
+ function get_pgsql_version($link) {
+ $result = db_query($link, "SELECT version() AS version");
+ $version = explode(" ", db_fetch_result($result, 0, "version"));
+ return $version[1];
+ }
+
+ /**
+ * Subscribes the user to the given feed
+ *
+ * @param resource $link Database connection
+ * @param string $url Feed URL to subscribe to
+ * @param integer $cat_id Category ID the feed shall be added to
+ * @param string $auth_login (optional) Feed username
+ * @param string $auth_pass (optional) Feed password
+ *
+ * @return integer Status code:
+ * 0 - OK, Feed already exists
+ * 1 - OK, Feed added
+ * 2 - Invalid URL
+ * 3 - URL content is HTML, no feeds available
+ * 4 - URL content is HTML which contains multiple feeds.
+ * Here you should call extractfeedurls in rpc-backend
+ * to get all possible feeds.
+ * 5 - Couldn't download the URL content.
+ */
+ function subscribe_to_feed($link, $url, $cat_id = 0,
+ $auth_login = '', $auth_pass = '') {
+
+ $url = fix_url($url);
+
+ if (!$url || !validate_feed_url($url)) return 2;
+
+ $update_method = 0;
+
+ $result = db_query($link, "SELECT twitter_oauth FROM ttrss_users
+ WHERE id = ".$_SESSION['uid']);
+
+ $has_oauth = db_fetch_result($result, 0, 'twitter_oauth');
+
+ if (!$has_oauth || strpos($url, '://api.twitter.com') === false) {
+ if (!fetch_file_contents($url, false, $auth_login, $auth_pass)) return 5;
+
+ if (url_is_html($url, $auth_login, $auth_pass)) {
+ $feedUrls = get_feeds_from_html($url, $auth_login, $auth_pass);
+ if (count($feedUrls) == 0) {
+ return 3;
+ } else if (count($feedUrls) > 1) {
+ return 4;
+ }
+ //use feed url as new URL
+ $url = key($feedUrls);
+ }
+
+ } else {
+ if (!fetch_twitter_rss($link, $url, $_SESSION['uid']))
+ return 5;
+
+ $update_method = 3;
+ }
+ if ($cat_id == "0" || !$cat_id) {
+ $cat_qpart = "NULL";
+ } else {
+ $cat_qpart = "'$cat_id'";
+ }
+
+ $result = db_query($link,
+ "SELECT id FROM ttrss_feeds
+ WHERE feed_url = '$url' AND owner_uid = ".$_SESSION["uid"]);
+
+ if (db_num_rows($result) == 0) {
+ $result = db_query($link,
+ "INSERT INTO ttrss_feeds
+ (owner_uid,feed_url,title,cat_id, auth_login,auth_pass,update_method)
+ VALUES ('".$_SESSION["uid"]."', '$url',
+ '[Unknown]', $cat_qpart, '$auth_login', '$auth_pass', '$update_method')");
+
+ $result = db_query($link,
+ "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);
+ }
+
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ function print_feed_select($link, $id, $default_id = "",
+ $attributes = "", $include_all_feeds = true) {
+
+ print "<select id=\"$id\" name=\"$id\" $attributes>";
+ if ($include_all_feeds) {
+ print "<option value=\"0\">".__('All feeds')."</option>";
+ }
+
+ $result = db_query($link, "SELECT id,title FROM ttrss_feeds
+ WHERE owner_uid = ".$_SESSION["uid"]." ORDER BY title");
+
+ if (db_num_rows($result) > 0 && $include_all_feeds) {
+ print "<option disabled>--------</option>";
+ }
+
+ while ($line = db_fetch_assoc($result)) {
+ if ($line["id"] == $default_id) {
+ $is_selected = "selected=\"1\"";
+ } else {
+ $is_selected = "";
+ }
+
+ $title = truncate_string(htmlspecialchars($line["title"]), 40);
+
+ printf("<option $is_selected value='%d'>%s</option>",
+ $line["id"], $title);
+ }
+
+ print "</select>";
+ }
+
+ function print_feed_cat_select($link, $id, $default_id = "",
+ $attributes = "", $include_all_cats = true) {
+
+ print "<select id=\"$id\" name=\"$id\" default=\"$default_id\" onchange=\"catSelectOnChange(this)\" $attributes>";
+
+ if ($include_all_cats) {
+ print "<option value=\"0\">".__('Uncategorized')."</option>";
+ }
+
+ $result = db_query($link, "SELECT id,title FROM ttrss_feed_categories
+ WHERE owner_uid = ".$_SESSION["uid"]." ORDER BY title");
+
+ if (db_num_rows($result) > 0 && $include_all_cats) {
+ print "<option disabled=\"1\">--------</option>";
+ }
+
+ while ($line = db_fetch_assoc($result)) {
+ if ($line["id"] == $default_id) {
+ $is_selected = "selected=\"1\"";
+ } else {
+ $is_selected = "";
+ }
+
+ if ($line["title"])
+ printf("<option $is_selected value='%d'>%s</option>",
+ $line["id"], htmlspecialchars($line["title"]));
+ }
+
+# print "<option value=\"ADD_CAT\">" .__("Add category...") . "</option>";
+
+ print "</select>";
+ }
+
+ function checkbox_to_sql_bool($val) {
+ return ($val == "on") ? "true" : "false";
+ }
+
+ function getFeedCatTitle($link, $id) {
+ if ($id == -1) {
+ return __("Special");
+ } else if ($id < -10) {
+ return __("Labels");
+ } else if ($id > 0) {
+ $result = db_query($link, "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) {
+ return db_fetch_result($result, 0, "title");
+ } else {
+ return __("Uncategorized");
+ }
+ } else {
+ return "getFeedCatTitle($id) failed";
+ }
+
+ }
+
+ function getFeedIcon($id) {
+ switch ($id) {
+ case 0:
+ return "images/archive.png";
+ break;
+ case -1:
+ return "images/mark_set.png";
+ break;
+ case -2:
+ return "images/pub_set.png";
+ break;
+ case -3:
+ return "images/fresh.png";
+ break;
+ case -4:
+ return "images/tag.png";
+ break;
+ default:
+ if ($id < -10) {
+ return "images/label.png";
+ } else {
+ if (file_exists(ICONS_DIR . "/$id.ico"))
+ return ICONS_URL . "/$id.ico";
+ }
+ break;
+ }
+ }
+
+ function getFeedTitle($link, $id) {
+ if ($id == -1) {
+ return __("Starred articles");
+ } else if ($id == -2) {
+ return __("Published articles");
+ } else if ($id == -3) {
+ return __("Fresh articles");
+ } else if ($id == -4) {
+ return __("All articles");
+ } else if ($id === 0 || $id === "0") {
+ return __("Archived articles");
+ } else if ($id < -10) {
+ $label_id = -$id - 11;
+ $result = db_query($link, "SELECT caption FROM ttrss_labels2 WHERE id = '$label_id'");
+ if (db_num_rows($result) == 1) {
+ return db_fetch_result($result, 0, "caption");
+ } else {
+ return "Unknown label ($label_id)";
+ }
+
+ } else if (is_numeric($id) && $id > 0) {
+ $result = db_query($link, "SELECT title FROM ttrss_feeds WHERE id = '$id'");
+ if (db_num_rows($result) == 1) {
+ return db_fetch_result($result, 0, "title");
+ } else {
+ return "Unknown feed ($id)";
+ }
+ } else {
+ return $id;
+ }
+ }
+
+ function make_init_params($link) {
+ $params = array();
+
+ $params["theme"] = get_user_theme($link);
+ $params["theme_options"] = get_user_theme_options($link);
+
+ $params["sign_progress"] = theme_image($link, "images/indicator_white.gif");
+ $params["sign_progress_tiny"] = theme_image($link, "images/indicator_tiny.gif");
+ $params["sign_excl"] = theme_image($link, "images/sign_excl.png");
+ $params["sign_info"] = theme_image($link, "images/sign_info.png");
+
+ foreach (array("ON_CATCHUP_SHOW_NEXT_FEED", "HIDE_READ_FEEDS",
+ "ENABLE_FEED_CATS", "FEEDS_SORT_BY_UNREAD", "CONFIRM_FEED_CATCHUP",
+ "CDM_AUTO_CATCHUP", "FRESH_ARTICLE_MAX_AGE", "DEFAULT_ARTICLE_LIMIT",
+ "HIDE_READ_SHOWS_SPECIAL", "COMBINED_DISPLAY_MODE") as $param) {
+
+ $params[strtolower($param)] = (int) get_pref($link, $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["bw_limit"] = (int) $_SESSION["bw_limit"];
+
+ $result = db_query($link, "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");
+ $num_feeds = db_fetch_result($result, 0, "nf");
+
+ $params["max_feed_id"] = (int) $max_feed_id;
+ $params["num_feeds"] = (int) $num_feeds;
+
+ $params["collapsed_feedlist"] = (int) get_pref($link, "_COLLAPSED_FEEDLIST");
+
+ return $params;
+ }
+
+ function make_runtime_info($link) {
+ $data = array();
+
+ $result = db_query($link, "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");
+ $num_feeds = db_fetch_result($result, 0, "nf");
+
+ $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');
+
+ if (file_exists(LOCK_DIRECTORY . "/update_daemon.lock")) {
+
+ $data['daemon_is_running'] = (int) file_is_locked("update_daemon.lock");
+
+ if (time() - $_SESSION["daemon_stamp_check"] > 30) {
+
+ $stamp = (int) @file_get_contents(LOCK_DIRECTORY . "/update_daemon.stamp");
+
+ if ($stamp) {
+ $stamp_delta = time() - $stamp;
+
+ if ($stamp_delta > 1800) {
+ $stamp_check = 0;
+ } else {
+ $stamp_check = 1;
+ $_SESSION["daemon_stamp_check"] = time();
+ }
+
+ $data['daemon_stamp_ok'] = $stamp_check;
+
+ $stamp_fmt = date("Y.m.d, G:i", $stamp);
+
+ $data['daemon_stamp'] = $stamp_fmt;
+ }
+ }
+ }
+
+ if ($_SESSION["last_version_check"] + 86400 + rand(-1000, 1000) < time()) {
+ $new_version_details = @check_for_update($link);
+
+ $data['new_version_available'] = (int) ($new_version_details != false);
+
+ $_SESSION["last_version_check"] = time();
+ }
+
+ return $data;
+ }
+
+ function search_to_sql($link, $search, $match_on) {
+
+ $search_query_part = "";
+
+ $keywords = explode(" ", $search);
+ $query_keywords = array();
+
+ foreach ($keywords as $k) {
+ if (strpos($k, "-") === 0) {
+ $k = substr($k, 1);
+ $not = "NOT";
+ } else {
+ $not = "";
+ }
+
+ $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]) {
+
+ if ($commandpair[1] == "true")
+ array_push($query_keywords, "($not (published = true))");
+ else
+ array_push($query_keywords, "($not (published = false))");
+
+ } else 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'));
+
+ //$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%'))");
+ }
+ }
+
+ $search_query_part = implode("AND", $query_keywords);
+
+ return $search_query_part;
+ }
+
+
+ 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) {
+
+ if (!$owner_uid) $owner_uid = $_SESSION["uid"];
+
+ $ext_tables_part = "";
+
+ if ($search) {
+
+ if (SPHINX_ENABLED) {
+ $ids = join(",", @sphinx_search($search, 0, 500));
+
+ if ($ids)
+ $search_query_part = "ref_id IN ($ids) AND ";
+ else
+ $search_query_part = "ref_id = -1 AND ";
+
+ } else {
+ $search_query_part = search_to_sql($link, $search, $match_on);
+ $search_query_part .= " AND ";
+ }
+
+ } else {
+ $search_query_part = "";
+ }
+
+ if ($filter) {
+ $filter_query_part = filter_to_sql($filter);
+ } else {
+ $filter_query_part = "";
+ }
+
+ if ($since_id) {
+ $since_id_part = "ttrss_entries.id > $since_id AND ";
+ } else {
+ $since_id_part = "";
+ }
+
+ $view_query_part = "";
+
+ if ($view_mode == "adaptive" || $view_query_part == "noscores") {
+ if ($search) {
+ $view_query_part = " ";
+ } else if ($feed != -1) {
+ $unread = getFeedUnread($link, $feed, $cat_view);
+ if ($unread > 0) {
+ $view_query_part = " unread = true AND ";
+ }
+ }
+ }
+
+ if ($view_mode == "marked") {
+ $view_query_part = " marked = true AND ";
+ }
+
+ if ($view_mode == "published") {
+ $view_query_part = " published = true AND ";
+ }
+
+ if ($view_mode == "unread") {
+ $view_query_part = " unread = true AND ";
+ }
+
+ if ($view_mode == "updated") {
+ $view_query_part = " (last_read is null and unread = false) AND ";
+ }
+
+ if ($limit > 0) {
+ $limit_query_part = "LIMIT " . $limit;
+ }
+
+ $vfeed_query_part = "";
+
+ // override query strategy and enable feed display when searching globally
+ if ($search && $search_mode == "all_feeds") {
+ $query_strategy_part = "ttrss_entries.id > 0";
+ $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
+ /* tags */
+ } else if (preg_match("/^-?[0-9][0-9]*$/", $feed) == false) {
+ $query_strategy_part = "ttrss_entries.id > 0";
+ $vfeed_query_part = "(SELECT title FROM ttrss_feeds WHERE
+ id = feed_id) as feed_title,";
+ } else if ($feed > 0 && $search && $search_mode == "this_cat") {
+
+ $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
+
+ $tmp_result = false;
+
+ if ($cat_view) {
+ $tmp_result = db_query($link, "SELECT id
+ FROM ttrss_feeds WHERE cat_id = '$feed'");
+ } else {
+ $tmp_result = db_query($link, "SELECT id
+ FROM ttrss_feeds WHERE cat_id = (SELECT cat_id FROM ttrss_feeds
+ WHERE id = '$feed') AND id != '$feed'");
+ }
+
+ $cat_siblings = array();
+
+ if (db_num_rows($tmp_result) > 0) {
+ while ($p = db_fetch_assoc($tmp_result)) {
+ array_push($cat_siblings, "feed_id = " . $p["id"]);
+ }
+
+ $query_strategy_part = sprintf("(feed_id = %d OR %s)",
+ $feed, implode(" OR ", $cat_siblings));
+
+ } else {
+ $query_strategy_part = "ttrss_entries.id > 0";
+ }
+
+ } else if ($feed > 0) {
+
+ if ($cat_view) {
+
+ if ($feed > 0) {
+ $query_strategy_part = "cat_id = '$feed'";
+ } else {
+ $query_strategy_part = "cat_id IS NULL";
+ }
+
+ $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
+
+ } else {
+ $query_strategy_part = "feed_id = '$feed'";
+ }
+ } else if ($feed == 0 && !$cat_view) { // archive virtual feed
+ $query_strategy_part = "feed_id IS NULL";
+ } else if ($feed == 0 && $cat_view) { // uncategorized
+ $query_strategy_part = "cat_id IS NULL";
+ $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
+ } else if ($feed == -1) { // starred virtual feed
+ $query_strategy_part = "marked = true";
+ $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
+ } else if ($feed == -2) { // published virtual feed OR labels category
+
+ if (!$cat_view) {
+ $query_strategy_part = "published = true";
+ $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
+ } else {
+ $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
+
+ $ext_tables_part = ",ttrss_labels2,ttrss_user_labels2";
+
+ $query_strategy_part = "ttrss_labels2.id = ttrss_user_labels2.label_id AND
+ ttrss_user_labels2.article_id = ref_id";
+
+ }
+
+ } 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);
+
+ if (DB_TYPE == "pgsql") {
+ $query_strategy_part .= " AND updated > NOW() - INTERVAL '$intl hour' ";
+ } else {
+ $query_strategy_part .= " AND updated > DATE_SUB(NOW(), INTERVAL $intl HOUR) ";
+ }
+
+ $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
+ } else if ($feed == -4) { // all articles virtual feed
+ $query_strategy_part = "true";
+ $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
+ } else if ($feed <= -10) { // labels
+ $label_id = -$feed - 11;
+
+ $query_strategy_part = "label_id = '$label_id' AND
+ ttrss_labels2.id = ttrss_user_labels2.label_id AND
+ ttrss_user_labels2.article_id = ref_id";
+
+ $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
+ $ext_tables_part = ",ttrss_labels2,ttrss_user_labels2";
+
+ } else {
+ $query_strategy_part = "id > 0"; // dumb
+ }
+
+ 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";
+ }
+
+ if ($view_mode != "noscores") {
+ $order_by = "score DESC, $order_by";
+ }
+
+ if ($override_order) {
+ $order_by = $override_order;
+ }
+
+ $feed_title = "";
+
+ if ($search) {
+ $feed_title = "Search results";
+ } else {
+ if ($cat_view) {
+ $feed_title = getCategoryTitle($link, $feed);
+ } else {
+ if (is_numeric($feed) && $feed > 0) {
+ $result = db_query($link, "SELECT title,site_url,last_error
+ 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");
+ } else {
+ $feed_title = getFeedTitle($link, $feed);
+ }
+ }
+ }
+
+ $content_query_part = "content as content_preview,";
+
+ if (preg_match("/^-?[0-9][0-9]*$/", $feed) != false) {
+
+ if ($feed >= 0) {
+ $feed_kind = "Feeds";
+ } else {
+ $feed_kind = "Labels";
+ }
+
+ if ($limit_query_part) {
+ $offset_query_part = "OFFSET $offset";
+ }
+
+ if ($vfeed_query_part && get_pref($link, 'VFEED_GROUP_BY_FEED', $owner_uid)) {
+ if (!$override_order) {
+ $order_by = "ttrss_feeds.title, $order_by";
+ }
+ }
+
+ if ($feed != "0") {
+ $from_qpart = "ttrss_entries,ttrss_user_entries,ttrss_feeds$ext_tables_part";
+ $feed_check_qpart = "ttrss_user_entries.feed_id = ttrss_feeds.id AND";
+
+ } else {
+ $from_qpart = "ttrss_entries,ttrss_user_entries$ext_tables_part
+ LEFT JOIN ttrss_feeds ON (feed_id = ttrss_feeds.id)";
+ }
+
+ $query = "SELECT DISTINCT
+ date_entered,
+ guid,
+ ttrss_entries.id,ttrss_entries.title,
+ updated,
+ label_cache,
+ tag_cache,
+ always_display_enclosures,
+ site_url,
+ note,
+ num_comments,
+ comments,
+ int_id,
+ unread,feed_id,marked,published,link,last_read,orig_feed_id,
+ ".SUBSTRING_FOR_DATE."(last_read,1,19) as last_read_noms,
+ $vfeed_query_part
+ $content_query_part
+ ".SUBSTRING_FOR_DATE."(updated,1,19) as updated_noms,
+ author,score
+ FROM
+ $from_qpart
+ WHERE
+ $feed_check_qpart
+ ttrss_user_entries.ref_id = ttrss_entries.id AND
+ ttrss_user_entries.owner_uid = '$owner_uid' AND
+ $search_query_part
+ $filter_query_part
+ $view_query_part
+ $since_id_part
+ $query_strategy_part ORDER BY $order_by
+ $limit_query_part $offset_query_part";
+
+ if ($_REQUEST["debug"]) print $query;
+
+ $result = db_query($link, $query);
+
+ } else {
+ // browsing by tag
+
+ $select_qpart = "SELECT DISTINCT " .
+ "date_entered," .
+ "guid," .
+ "note," .
+ "ttrss_entries.id as id," .
+ "title," .
+ "updated," .
+ "unread," .
+ "feed_id," .
+ "orig_feed_id," .
+ "site_url," .
+ "always_display_enclosures, ".
+ "marked," .
+ "num_comments, " .
+ "comments, " .
+ "tag_cache," .
+ "label_cache," .
+ "link," .
+ "last_read," .
+ SUBSTRING_FOR_DATE . "(last_read,1,19) as last_read_noms," .
+ $since_id_part .
+ $vfeed_query_part .
+ $content_query_part .
+ SUBSTRING_FOR_DATE . "(updated,1,19) as updated_noms," .
+ "score ";
+
+ $feed_kind = "Tags";
+ $all_tags = explode(",", $feed);
+ if ($search_mode == 'any') {
+ $tag_sql = "tag_name in (" . implode(", ", array_map("db_quote", $all_tags)) . ")";
+ $from_qpart = " FROM ttrss_entries,ttrss_user_entries,ttrss_tags ";
+ $where_qpart = " WHERE " .
+ "ref_id = ttrss_entries.id AND " .
+ "ttrss_user_entries.owner_uid = $owner_uid AND " .
+ "post_int_id = int_id AND $tag_sql AND " .
+ $view_query_part .
+ $search_query_part .
+ $query_strategy_part . " ORDER BY $order_by " .
+ $limit_query_part;
+
+ } else {
+ $i = 1;
+ $sub_selects = array();
+ $sub_ands = array();
+ foreach ($all_tags as $term) {
+ array_push($sub_selects, "(SELECT post_int_id from ttrss_tags WHERE tag_name = " . db_quote($term) . " AND owner_uid = $owner_uid) as A$i");
+ $i++;
+ }
+ if ($i > 2) {
+ $x = 1;
+ $y = 2;
+ do {
+ array_push($sub_ands, "A$x.post_int_id = A$y.post_int_id");
+ $x++;
+ $y++;
+ } while ($y < $i);
+ }
+ array_push($sub_ands, "A1.post_int_id = ttrss_user_entries.int_id and ttrss_user_entries.owner_uid = $owner_uid");
+ array_push($sub_ands, "ttrss_user_entries.ref_id = ttrss_entries.id");
+ $from_qpart = " FROM " . implode(", ", $sub_selects) . ", ttrss_user_entries, ttrss_entries";
+ $where_qpart = " WHERE " . implode(" AND ", $sub_ands);
+ }
+ // error_log("TAG SQL: " . $tag_sql);
+ // $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);
+ }
+
+ return array($result, $feed_title, $feed_site_url, $last_error);
+
+ }
+
+ function generate_syndicated_feed($link, $owner_uid, $feed, $is_cat,
+ $limit, $search, $search_mode, $match_on, $view_mode = false) {
+
+ require_once "lib/MiniTemplator.class.php";
+
+ $note_style = "background-color : #fff7d5;
+ border-width : 1px; ".
+ "padding : 5px; border-style : dashed; border-color : #e7d796;".
+ "margin-bottom : 1em; color : #9a8c59;";
+
+ if (!$limit) $limit = 30;
+
+ if (get_pref($link, "SORT_HEADLINES_BY_FEED_DATE", $owner_uid)) {
+ $date_sort_field = "updated";
+ } else {
+ $date_sort_field = "date_entered";
+ }
+
+ $qfh_ret = queryFeedHeadlines($link, $feed,
+ $limit, $view_mode, $is_cat, $search, $search_mode,
+ $match_on, "$date_sort_field DESC", 0, $owner_uid);
+
+ $result = $qfh_ret[0];
+ $feed_title = htmlspecialchars($qfh_ret[1]);
+ $feed_site_url = $qfh_ret[2];
+ $last_error = $qfh_ret[3];
+
+ $feed_self_url = get_self_url_prefix() .
+ "/public.php?op=rss&id=-2&key=" .
+ get_feed_access_key($link, -2, false);
+
+ if (!$feed_site_url) $feed_site_url = get_self_url_prefix();
+
+ $tpl = new MiniTemplator;
+
+ $tpl->readTemplateFromFile("templates/generated_feed.txt");
+
+ $tpl->setVariable('FEED_TITLE', $feed_title);
+ $tpl->setVariable('VERSION', VERSION);
+ $tpl->setVariable('FEED_URL', htmlspecialchars($feed_self_url));
+
+ if (PUBSUBHUBBUB_HUB && $feed == -2) {
+ $tpl->setVariable('HUB_URL', htmlspecialchars(PUBSUBHUBBUB_HUB));
+ $tpl->addBlock('feed_hub');
+ }
+
+ $tpl->setVariable('SELF_URL', htmlspecialchars(get_self_url_prefix()));
+
+ while ($line = db_fetch_assoc($result)) {
+ $tpl->setVariable('ARTICLE_ID', htmlspecialchars($line['link']));
+ $tpl->setVariable('ARTICLE_LINK', htmlspecialchars($line['link']));
+ $tpl->setVariable('ARTICLE_TITLE', htmlspecialchars($line['title']));
+ $tpl->setVariable('ARTICLE_EXCERPT',
+ truncate_string(strip_tags($line["content_preview"]), 100, '...'));
+
+ $content = sanitize_rss($link, $line["content_preview"], false, $owner_uid);
+
+ if ($line['note']) {
+ $content = "<div style=\"$note_style\">Article note: " . $line['note'] . "</div>" .
+ $content;
+ }
+
+ $tpl->setVariable('ARTICLE_CONTENT', $content);
+
+ $tpl->setVariable('ARTICLE_UPDATED', date('c', strtotime($line["updated"])));
+ $tpl->setVariable('ARTICLE_AUTHOR', htmlspecialchars($line['author']));
+
+ $tags = get_article_tags($link, $line["id"], $owner_uid);
+
+ foreach ($tags as $tag) {
+ $tpl->setVariable('ARTICLE_CATEGORY', htmlspecialchars($tag));
+ $tpl->addBlock('category');
+ }
+
+ $enclosures = get_article_enclosures($link, $line["id"]);
+
+ foreach ($enclosures as $e) {
+ $type = htmlspecialchars($e['content_type']);
+ $url = htmlspecialchars($e['content_url']);
+ $length = $e['duration'];
+
+ $tpl->setVariable('ARTICLE_ENCLOSURE_URL', $url);
+ $tpl->setVariable('ARTICLE_ENCLOSURE_TYPE', $type);
+ $tpl->setVariable('ARTICLE_ENCLOSURE_LENGTH', $length);
+
+ $tpl->addBlock('enclosure');
+ }
+
+ $tpl->addBlock('entry');
+ }
+
+ $tmp = "";
+
+ $tpl->addBlock('feed');
+ $tpl->generateOutputToString($tmp);
+
+ print $tmp;
+ }
+
+ function getCategoryTitle($link, $cat_id) {
+
+ if ($cat_id == -1) {
+ return __("Special");
+ } else if ($cat_id == -2) {
+ return __("Labels");
+ } else {
+
+ $result = db_query($link, "SELECT title FROM ttrss_feed_categories WHERE
+ id = '$cat_id'");
+
+ if (db_num_rows($result) == 1) {
+ return db_fetch_result($result, 0, "title");
+ } else {
+ return "Uncategorized";
+ }
+ }
+ }
+
+ function sanitize_rss($link, $str, $force_strip_tags = false, $owner = false, $site_url = false) {
+ global $purifier;
+
+ if (!$owner) $owner = $_SESSION["uid"];
+
+ $res = trim($str); if (!$res) return '';
+
+ // create global Purifier object if needed
+ if (!$purifier) {
+ require_once 'lib/htmlpurifier/library/HTMLPurifier.auto.php';
+
+ $config = HTMLPurifier_Config::createDefault();
+
+ $allowed = "p,a[href],i,em,b,strong,code,pre,blockquote,br,img[src|alt|title],ul,ol,li,h1,h2,h3,h4,s,object[classid|type|id|name|width|height|codebase],param[name|value],table,tr,td";
+
+ $config->set('HTML.SafeObject', true);
+ @$config->set('HTML', 'Allowed', $allowed);
+ $config->set('Output.FlashCompat', true);
+ $config->set('Attr.EnableID', true);
+ if (!defined('MOBILE_VERSION')) {
+ @$config->set('Cache', 'SerializerPath', CACHE_DIR . "/htmlpurifier");
+ } else {
+ @$config->set('Cache', 'SerializerPath', "../" . CACHE_DIR . "/htmlpurifier");
+ }
+
+ $purifier = new HTMLPurifier($config);
+ }
+
+ $res = $purifier->purify($res);
+
+ if (get_pref($link, "STRIP_IMAGES", $owner)) {
+ $res = preg_replace('/<img[^>]+>/is', '', $res);
+ }
+
+ if (strpos($res, "href=") === false)
+ $res = rewrite_urls($res);
+
+ $charset_hack = '<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ </head>';
+
+ $res = trim($res); if (!$res) return '';
+
+ libxml_use_internal_errors(true);
+
+ $doc = new DOMDocument();
+ $doc->loadHTML($charset_hack . $res);
+ $xpath = new DOMXPath($doc);
+
+ $entries = $xpath->query('(//a[@href]|//img[@src])');
+ $br_inserted = 0;
+
+ foreach ($entries as $entry) {
+
+ if ($site_url) {
+
+ if ($entry->hasAttribute('href'))
+ $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 (strtolower($entry->nodeName) == "a") {
+ $entry->setAttribute("target", "_blank");
+ }
+
+ if (strtolower($entry->nodeName) == "img" && !$br_inserted) {
+ $br = $doc->createElement("br");
+
+ if ($entry->parentNode->nextSibling) {
+ $entry->parentNode->insertBefore($br, $entry->nextSibling);
+ $br_inserted = 1;
+ }
+
+ }
+ }
+
+ $node = $doc->getElementsByTagName('body')->item(0);
+
+ return $doc->saveXML($node);
+ }
+
+ /**
+ * Send by mail a digest of last articles.
+ *
+ * @param mixed $link The database connection.
+ * @param integer $limit The maximum number of articles by digest.
+ * @return boolean Return false if digests are not enabled.
+ */
+ function send_headlines_digests($link, $limit = 100) {
+
+ require_once 'lib/phpmailer/class.phpmailer.php';
+
+ if (!DIGEST_ENABLE) return false;
+
+ $user_limit = DIGEST_EMAIL_LIMIT;
+ $days = 1;
+
+ print "Sending digests, batch of max $user_limit users, days = $days, headline limit = $limit\n\n";
+
+ if (DB_TYPE == "pgsql") {
+ $interval_query = "last_digest_sent < NOW() - INTERVAL '$days days'";
+ } else if (DB_TYPE == "mysql") {
+ $interval_query = "last_digest_sent < DATE_SUB(NOW(), INTERVAL $days DAY)";
+ }
+
+ $result = db_query($link, "SELECT id,email FROM ttrss_users
+ WHERE email != '' AND (last_digest_sent IS NULL OR $interval_query)");
+
+ while ($line = db_fetch_assoc($result)) {
+
+ if (get_pref($link, 'DIGEST_ENABLE', $line['id'], false)) {
+ print "Sending digest for UID:" . $line['id'] . " - " . $line["email"] . " ... ";
+
+ $do_catchup = get_pref($link, 'DIGEST_CATCHUP', $line['id'], false);
+
+ $tuple = prepare_headlines_digest($link, $line["id"], $days, $limit);
+ $digest = $tuple[0];
+ $headlines_count = $tuple[1];
+ $affected_ids = $tuple[2];
+ $digest_text = $tuple[3];
+
+ if ($headlines_count > 0) {
+
+ $mail = new PHPMailer();
+
+ $mail->PluginDir = "lib/phpmailer/";
+ $mail->SetLanguage("en", "lib/phpmailer/language/");
+
+ $mail->CharSet = "UTF-8";
+
+ $mail->From = DIGEST_FROM_ADDRESS;
+ $mail->FromName = DIGEST_FROM_NAME;
+ $mail->AddAddress($line["email"], $line["login"]);
+
+ if (DIGEST_SMTP_HOST) {
+ $mail->Host = DIGEST_SMTP_HOST;
+ $mail->Mailer = "smtp";
+ $mail->SMTPAuth = DIGEST_SMTP_LOGIN != '';
+ $mail->Username = DIGEST_SMTP_LOGIN;
+ $mail->Password = DIGEST_SMTP_PASSWORD;
+ }
+
+ $mail->IsHTML(true);
+ $mail->Subject = DIGEST_SUBJECT;
+ $mail->Body = $digest;
+ $mail->AltBody = $digest_text;
+
+ $rc = $mail->Send();
+
+ if (!$rc) print "ERROR: " . $mail->ErrorInfo;
+
+ print "RC=$rc\n";
+
+ if ($rc && $do_catchup) {
+ print "Marking affected articles as read...\n";
+ catchupArticlesById($link, $affected_ids, 0, $line["id"]);
+ }
+ } else {
+ print "No headlines\n";
+ }
+
+ db_query($link, "UPDATE ttrss_users SET last_digest_sent = NOW()
+ WHERE id = " . $line["id"]);
+ }
+ }
+
+ print "All done.\n";
+
+ }
+
+ function prepare_headlines_digest($link, $user_id, $days = 1, $limit = 100) {
+
+ require_once "lib/MiniTemplator.class.php";
+
+ $tpl = new MiniTemplator;
+ $tpl_t = new MiniTemplator;
+
+ $tpl->readTemplateFromFile("templates/digest_template_html.txt");
+ $tpl_t->readTemplateFromFile("templates/digest_template.txt");
+
+ $tpl->setVariable('CUR_DATE', date('Y/m/d'));
+ $tpl->setVariable('CUR_TIME', date('G:i'));
+
+ $tpl_t->setVariable('CUR_DATE', date('Y/m/d'));
+ $tpl_t->setVariable('CUR_TIME', date('G:i'));
+
+ $affected_ids = array();
+
+ if (DB_TYPE == "pgsql") {
+ $interval_query = "ttrss_entries.date_updated > NOW() - INTERVAL '$days days'";
+ } else if (DB_TYPE == "mysql") {
+ $interval_query = "ttrss_entries.date_updated > DATE_SUB(NOW(), INTERVAL $days DAY)";
+ }
+
+ $result = db_query($link, "SELECT ttrss_entries.title,
+ ttrss_feeds.title AS feed_title,
+ date_updated,
+ ttrss_user_entries.ref_id,
+ link,
+ SUBSTRING(content, 1, 120) AS excerpt,
+ ".SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated
+ FROM
+ ttrss_user_entries,ttrss_entries,ttrss_feeds
+ WHERE
+ ref_id = ttrss_entries.id AND feed_id = ttrss_feeds.id
+ AND include_in_digest = true
+ AND $interval_query
+ AND ttrss_user_entries.owner_uid = $user_id
+ AND unread = true
+ ORDER BY ttrss_feeds.title, date_updated DESC
+ LIMIT $limit");
+
+ $cur_feed_title = "";
+
+ $headlines_count = db_num_rows($result);
+
+ $headlines = array();
+
+ while ($line = db_fetch_assoc($result)) {
+ array_push($headlines, $line);
+ }
+
+ for ($i = 0; $i < sizeof($headlines); $i++) {
+
+ $line = $headlines[$i];
+
+ array_push($affected_ids, $line["ref_id"]);
+
+ $updated = make_local_datetime($link, $line['last_updated'], false,
+ $user_id);
+
+ $tpl->setVariable('FEED_TITLE', $line["feed_title"]);
+ $tpl->setVariable('ARTICLE_TITLE', $line["title"]);
+ $tpl->setVariable('ARTICLE_LINK', $line["link"]);
+ $tpl->setVariable('ARTICLE_UPDATED', $updated);
+ $tpl->setVariable('ARTICLE_EXCERPT',
+ truncate_string(strip_tags($line["excerpt"]), 100));
+
+ $tpl->addBlock('article');
+
+ $tpl_t->setVariable('FEED_TITLE', $line["feed_title"]);
+ $tpl_t->setVariable('ARTICLE_TITLE', $line["title"]);
+ $tpl_t->setVariable('ARTICLE_LINK', $line["link"]);
+ $tpl_t->setVariable('ARTICLE_UPDATED', $updated);
+// $tpl_t->setVariable('ARTICLE_EXCERPT',
+// truncate_string(strip_tags($line["excerpt"]), 100));
+
+ $tpl_t->addBlock('article');
+
+ if ($headlines[$i]['feed_title'] != $headlines[$i+1]['feed_title']) {
+ $tpl->addBlock('feed');
+ $tpl_t->addBlock('feed');
+ }
+
+ }
+
+ $tpl->addBlock('digest');
+ $tpl->generateOutputToString($tmp);
+
+ $tpl_t->addBlock('digest');
+ $tpl_t->generateOutputToString($tmp_t);
+
+ return array($tmp, $headlines_count, $affected_ids, $tmp_t);
+ }
+
+ 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_data = @fetch_file_contents($version_url);
+
+ if ($version_data) {
+ $version_data = json_decode($version_data, true);
+ if ($version_data && $version_data['version']) {
+
+ if (version_compare(VERSION, $version_data['version']) == -1) {
+ return $version_data;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ function markArticlesById($link, $ids, $cmode) {
+
+ $tmp_ids = array();
+
+ foreach ($ids as $id) {
+ array_push($tmp_ids, "ref_id = '$id'");
+ }
+
+ $ids_qpart = join(" OR ", $tmp_ids);
+
+ if ($cmode == 0) {
+ db_query($link, "UPDATE ttrss_user_entries SET
+ marked = false,last_read = NOW()
+ WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]);
+ } else if ($cmode == 1) {
+ db_query($link, "UPDATE ttrss_user_entries SET
+ marked = true
+ WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]);
+ } else {
+ db_query($link, "UPDATE ttrss_user_entries SET
+ marked = NOT marked,last_read = NOW()
+ WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]);
+ }
+ }
+
+ function publishArticlesById($link, $ids, $cmode) {
+
+ $tmp_ids = array();
+
+ foreach ($ids as $id) {
+ array_push($tmp_ids, "ref_id = '$id'");
+ }
+
+ $ids_qpart = join(" OR ", $tmp_ids);
+
+ if ($cmode == 0) {
+ db_query($link, "UPDATE ttrss_user_entries SET
+ published = false,last_read = NOW()
+ WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]);
+ } else if ($cmode == 1) {
+ db_query($link, "UPDATE ttrss_user_entries SET
+ published = true
+ WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]);
+ } else {
+ db_query($link, "UPDATE ttrss_user_entries SET
+ published = NOT published,last_read = NOW()
+ WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]);
+ }
+
+ if (PUBSUBHUBBUB_HUB) {
+ $rss_link = get_self_url_prefix() .
+ "/public.php?op=rss&id=-2&key=" .
+ get_feed_access_key($link, -2, false);
+
+ $p = new Publisher(PUBSUBHUBBUB_HUB);
+
+ $pubsub_result = $p->publish_update($rss_link);
+ }
+ }
+
+ function catchupArticlesById($link, $ids, $cmode, $owner_uid = false) {
+
+ if (!$owner_uid) $owner_uid = $_SESSION["uid"];
+ if (count($ids) == 0) return;
+
+ $tmp_ids = array();
+
+ foreach ($ids as $id) {
+ array_push($tmp_ids, "ref_id = '$id'");
+ }
+
+ $ids_qpart = join(" OR ", $tmp_ids);
+
+ if ($cmode == 0) {
+ db_query($link, "UPDATE ttrss_user_entries SET
+ unread = false,last_read = NOW()
+ WHERE ($ids_qpart) AND owner_uid = $owner_uid");
+ } else if ($cmode == 1) {
+ db_query($link, "UPDATE ttrss_user_entries SET
+ unread = true
+ WHERE ($ids_qpart) AND owner_uid = $owner_uid");
+ } else {
+ db_query($link, "UPDATE ttrss_user_entries SET
+ unread = NOT unread,last_read = NOW()
+ WHERE ($ids_qpart) AND owner_uid = $owner_uid");
+ }
+
+ /* update ccache */
+
+ $result = db_query($link, "SELECT DISTINCT feed_id FROM ttrss_user_entries
+ WHERE ($ids_qpart) AND owner_uid = $owner_uid");
+
+ while ($line = db_fetch_assoc($result)) {
+ ccache_update($link, $line["feed_id"], $owner_uid);
+ }
+ }
+
+ function catchupArticleById($link, $id, $cmode) {
+
+ if ($cmode == 0) {
+ db_query($link, "UPDATE ttrss_user_entries SET
+ unread = false,last_read = NOW()
+ WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
+ } else if ($cmode == 1) {
+ db_query($link, "UPDATE ttrss_user_entries SET
+ unread = true
+ WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
+ } else {
+ db_query($link, "UPDATE ttrss_user_entries SET
+ unread = NOT unread,last_read = NOW()
+ WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
+ }
+
+ $feed_id = getArticleFeed($link, $id);
+ ccache_update($link, $feed_id, $_SESSION["uid"]);
+ }
+
+ function make_guid_from_title($title) {
+ return preg_replace("/[ \"\',.:;]/", "-",
+ mb_strtolower(strip_tags($title), 'utf-8'));
+ }
+
+ function format_headline_subtoolbar($link, $feed_site_url, $feed_title,
+ $feed_id, $is_cat, $search, $match_on,
+ $search_mode, $view_mode, $error) {
+
+ $page_prev_link = "viewFeedGoPage(-1)";
+ $page_next_link = "viewFeedGoPage(1)";
+ $page_first_link = "viewFeedGoPage(0)";
+
+ $catchup_page_link = "catchupPage()";
+ $catchup_feed_link = "catchupCurrentFeed()";
+ $catchup_sel_link = "catchupSelection()";
+
+ $archive_sel_link = "archiveSelection()";
+ $delete_sel_link = "deleteSelection()";
+
+ $sel_all_link = "selectArticles('all')";
+ $sel_unread_link = "selectArticles('unread')";
+ $sel_none_link = "selectArticles('none')";
+ $sel_inv_link = "selectArticles('invert')";
+
+ $tog_unread_link = "selectionToggleUnread()";
+ $tog_marked_link = "selectionToggleMarked()";
+ $tog_published_link = "selectionTogglePublished()";
+
+ $reply = "<div id=\"subtoolbar_main\">";
+
+ $reply .= __('Select:')."
+ <a href=\"#\" onclick=\"$sel_all_link\">".__('All')."</a>,
+ <a href=\"#\" onclick=\"$sel_unread_link\">".__('Unread')."</a>,
+ <a href=\"#\" onclick=\"$sel_inv_link\">".__('Invert')."</a>,
+ <a href=\"#\" onclick=\"$sel_none_link\">".__('None')."</a></li>";
+
+ $reply .= " ";
+
+ $reply .= "<select dojoType=\"dijit.form.Select\"
+ onchange=\"headlineActionsChange(this)\">";
+ $reply .= "<option value=\"false\">".__('Actions...')."</option>";
+
+ $reply .= "<option value=\"0\" disabled=\"1\">".__('Selection toggle:')."</option>";
+
+ $reply .= "<option value=\"$tog_unread_link\">".__('Unread')."</option>
+ <option value=\"$tog_marked_link\">".__('Starred')."</option>
+ <option value=\"$tog_published_link\">".__('Published')."</option>";
+
+ $reply .= "<option value=\"0\" disabled=\"1\">".__('Selection:')."</option>";
+
+ $reply .= "<option value=\"$catchup_sel_link\">".__('Mark as read')."</option>";
+
+ if ($feed_id != "0") {
+ $reply .= "<option value=\"$archive_sel_link\">".__('Archive')."</option>";
+ } else {
+ $reply .= "<option value=\"$archive_sel_link\">".__('Move back')."</option>";
+ $reply .= "<option value=\"$delete_sel_link\">".__('Delete')."</option>";
+
+ }
+
+ $reply .= "<option value=\"emailArticle(false)\">".__('Forward by email').
+ "</option>";
+
+ if ($is_cat) $cat_q = "&is_cat=$is_cat";
+
+ if ($search) {
+ $search_q = "&q=$search&m=$match_on&smode=$search_mode";
+ } else {
+ $search_q = "";
+ }
+
+ $rss_link = htmlspecialchars(get_self_url_prefix() .
+ "/public.php?op=rss&id=$feed_id$cat_q$search_q");
+
+ $reply .= "<option value=\"0\" disabled=\"1\">".__('Feed:')."</option>";
+
+ $reply .= "<option value=\"catchupPage()\">".__('Mark as read')."</option>";
+
+ $reply .= "<option value=\"displayDlg('generatedFeed', '$feed_id:$is_cat:$rss_link')\">".__('View as RSS')."</option>";
+
+ $reply .= "</select>";
+
+ $reply .= "</div>";
+
+ $reply .= "<div id=\"subtoolbar_ftitle\">";
+
+ if ($feed_site_url) {
+ $target = "target=\"_blank\"";
+ $reply .= "<a title=\"".__("Visit the website")."\" $target href=\"$feed_site_url\">".
+ truncate_string($feed_title,30)."</a>";
+
+ if ($error) {
+ $reply .= " (<span class=\"error\" title=\"$error\">Error</span>)";
+ }
+
+ } else {
+ if ($feed_id < -10) {
+ $label_id = -11-$feed_id;
+
+ $result = db_query($link, "SELECT fg_color, bg_color
+ FROM ttrss_labels2 WHERE id = '$label_id' AND owner_uid = " .
+ $_SESSION["uid"]);
+
+ if (db_num_rows($result) != 0) {
+ $fg_color = db_fetch_result($result, 0, "fg_color");
+ $bg_color = db_fetch_result($result, 0, "bg_color");
+
+ $reply .= "<span style=\"background : $bg_color; color : $fg_color\" >";
+ $reply .= $feed_title;
+ $reply .= "</span>";
+ } else {
+ $reply .= $feed_title;
+ }
+
+ } else {
+ $reply .= $feed_title;
+ }
+ }
+
+ $reply .= "
+ <a href=\"#\"
+ title=\"".__("View as RSS feed")."\"
+ onclick=\"displayDlg('generatedFeed', '$feed_id:$is_cat:$rss_link')\">
+ <img class=\"noborder\" style=\"vertical-align : middle\" src=\"images/feed-icon-12x12.png\"></a>";
+
+ $reply .= "</div>";
+
+ return $reply;
+ }
+
+ function outputFeedList($link, $special = true) {
+
+ $feedlist = array();
+
+ $enable_cats = get_pref($link, 'ENABLE_FEED_CATS');
+
+ $feedlist['identifier'] = 'id';
+ $feedlist['label'] = 'name';
+ $feedlist['items'] = array();
+
+ $owner_uid = $_SESSION["uid"];
+
+ /* virtual feeds */
+
+ if ($special) {
+
+ if ($enable_cats) {
+ $cat_hidden = get_pref($link, "_COLLAPSED_SPECIAL");
+ $cat = feedlist_init_cat($link, -1, $cat_hidden);
+ } else {
+ $cat['items'] = array();
+ }
+
+ foreach (array(-4, -3, -1, -2, 0) as $i) {
+ array_push($cat['items'], feedlist_init_feed($link, $i));
+ }
+
+ if ($enable_cats) {
+ array_push($feedlist['items'], $cat);
+ } else {
+ $feedlist['items'] = array_merge($feedlist['items'], $cat['items']);
+ }
+
+ $result = db_query($link, "SELECT * FROM
+ ttrss_labels2 WHERE owner_uid = '$owner_uid' ORDER by caption");
+
+ if (db_num_rows($result) > 0) {
+
+ if (get_pref($link, 'ENABLE_FEED_CATS')) {
+ $cat_hidden = get_pref($link, "_COLLAPSED_LABELS");
+ $cat = feedlist_init_cat($link, -2, $cat_hidden);
+ } else {
+ $cat['items'] = array();
+ }
+
+ while ($line = db_fetch_assoc($result)) {
+
+ $label_id = -$line['id'] - 11;
+ $count = getFeedUnread($link, $label_id);
+
+ $feed = feedlist_init_feed($link, $label_id, false, $count);
+
+ $feed['fg_color'] = $line['fg_color'];
+ $feed['bg_color'] = $line['bg_color'];
+
+ array_push($cat['items'], $feed);
+ }
+
+ if ($enable_cats) {
+ array_push($feedlist['items'], $cat);
+ } else {
+ $feedlist['items'] = array_merge($feedlist['items'], $cat['items']);
+ }
+ }
+ }
+
+/* if (get_pref($link, 'ENABLE_FEED_CATS')) {
+ if (get_pref($link, "FEEDS_SORT_BY_UNREAD")) {
+ $order_by_qpart = "order_id,category,unread DESC,title";
+ } else {
+ $order_by_qpart = "order_id,category,title";
+ }
+ } else {
+ if (get_pref($link, "FEEDS_SORT_BY_UNREAD")) {
+ $order_by_qpart = "unread DESC,title";
+ } else {
+ $order_by_qpart = "title";
+ }
+ } */
+
+ /* real feeds */
+
+ if ($enable_cats)
+ $order_by_qpart = "ttrss_feed_categories.order_id,category,
+ ttrss_feeds.order_id,title";
+ else
+ $order_by_qpart = "title";
+
+ $age_qpart = getMaxAgeSubquery();
+
+ $query = "SELECT ttrss_feeds.id, ttrss_feeds.title,
+ ".SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated_noms,
+ cat_id,last_error,
+ ttrss_feed_categories.title AS category,
+ ttrss_feed_categories.collapsed,
+ value AS unread
+ FROM ttrss_feeds LEFT JOIN ttrss_feed_categories
+ ON (ttrss_feed_categories.id = cat_id)
+ LEFT JOIN ttrss_counters_cache
+ ON
+ (ttrss_feeds.id = feed_id)
+ WHERE
+ ttrss_feeds.owner_uid = '$owner_uid'
+ ORDER BY $order_by_qpart";
+
+ $result = db_query($link, $query);
+
+ $actid = $_REQUEST["actid"];
+
+ if (db_num_rows($result) > 0) {
+
+ $category = "";
+
+ if (!$enable_cats)
+ $cat['items'] = array();
+ else
+ $cat = false;
+
+ while ($line = db_fetch_assoc($result)) {
+
+ $feed = htmlspecialchars(trim($line["title"]));
+
+ if (!$feed) $feed = "[Untitled]";
+
+ $feed_id = $line["id"];
+ $unread = $line["unread"];
+
+ $cat_id = $line["cat_id"];
+ $tmp_category = $line["category"];
+ if (!$tmp_category) $tmp_category = __("Uncategorized");
+
+ if ($category != $tmp_category && $enable_cats) {
+
+ $category = $tmp_category;
+
+ $collapsed = sql_bool_to_bool($line["collapsed"]);
+
+ // workaround for NULL category
+ if ($category == __("Uncategorized")) {
+ $collapsed = get_pref($link, "_COLLAPSED_UNCAT");
+ }
+
+ if ($cat) array_push($feedlist['items'], $cat);
+
+ $cat = feedlist_init_cat($link, $cat_id, $collapsed);
+ }
+
+ $updated = make_local_datetime($link, $line["updated_noms"], false);
+
+ array_push($cat['items'], feedlist_init_feed($link, $feed_id,
+ $feed, $unread, $line['last_error'], $updated));
+ }
+
+ if ($enable_cats) {
+ array_push($feedlist['items'], $cat);
+ } else {
+ $feedlist['items'] = array_merge($feedlist['items'], $cat['items']);
+ }
+
+ }
+
+ return $feedlist;
+ }
+
+ function get_article_tags($link, $id, $owner_uid = 0, $tag_cache = false) {
+
+ global $memcache;
+
+ $a_id = db_escape_string($id);
+
+ if (!$owner_uid) $owner_uid = $_SESSION["uid"];
+
+ $query = "SELECT DISTINCT tag_name,
+ owner_uid as owner FROM
+ 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();
+
+ if ($memcache && $obj = $memcache->get($obj_id)) {
+ $tags = $obj;
+ } else {
+ /* check cache first */
+
+ if ($tag_cache === false) {
+ $result = db_query($link, "SELECT tag_cache FROM ttrss_user_entries
+ WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
+
+ $tag_cache = db_fetch_result($result, 0, "tag_cache");
+ }
+
+ if ($tag_cache) {
+ $tags = explode(",", $tag_cache);
+ } else {
+
+ /* do it the hard way */
+
+ $tmp_result = db_query($link, $query);
+
+ while ($tmp_line = db_fetch_assoc($tmp_result)) {
+ array_push($tags, $tmp_line["tag_name"]);
+ }
+
+ /* update the cache */
+
+ $tags_str = db_escape_string(join(",", $tags));
+
+ db_query($link, "UPDATE ttrss_user_entries
+ SET tag_cache = '$tags_str' WHERE ref_id = '$id'
+ AND owner_uid = " . $_SESSION["uid"]);
+ }
+
+ if ($memcache) $memcache->add($obj_id, $tags, 0, 3600);
+ }
+
+ return $tags;
+ }
+
+ function trim_array($array) {
+ $tmp = $array;
+ array_walk($tmp, 'trim');
+ return $tmp;
+ }
+
+ function tag_is_valid($tag) {
+ if ($tag == '') return false;
+ if (preg_match("/^[0-9]*$/", $tag)) return false;
+ if (mb_strlen($tag) > 250) return false;
+
+ if (function_exists('iconv')) {
+ $tag = iconv("utf-8", "utf-8", $tag);
+ }
+
+ if (!$tag) return false;
+
+ return true;
+ }
+
+ function render_login_form($link, $mobile = 0) {
+ switch ($mobile) {
+ case 0:
+ require_once "login_form.php";
+ break;
+ case 1:
+ require_once "mobile/login_form.php";
+ break;
+ case 2:
+ require_once "mobile/classic/login_form.php";
+ }
+ }
+
+ // 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
+ }
+
+ function format_warning($msg, $id = "") {
+ global $link;
+ return "<div class=\"warning\" id=\"$id\">
+ <img src=\"".theme_image($link, "images/sign_excl.png")."\">$msg</div>";
+ }
+
+ function format_notice($msg, $id = "") {
+ global $link;
+ return "<div class=\"notice\" id=\"$id\">
+ <img src=\"".theme_image($link, "images/sign_info.png")."\">$msg</div>";
+ }
+
+ function format_error($msg, $id = "") {
+ global $link;
+ return "<div class=\"error\" id=\"$id\">
+ <img src=\"".theme_image($link, "images/sign_excl.png")."\">$msg</div>";
+ }
+
+ function print_notice($msg) {
+ return print format_notice($msg);
+ }
+
+ function print_warning($msg) {
+ return print format_warning($msg);
+ }
+
+ function print_error($msg) {
+ return print format_error($msg);
+ }
+
+
+ function T_sprintf() {
+ $args = func_get_args();
+ return vsprintf(__(array_shift($args)), $args);
+ }
+
+ function format_inline_player($link, $url, $ctype) {
+
+ $entry = "";
+
+ 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();
+
+ $entry .= "<audio id=\"$id\"\">
+ <source 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\"
+ data=\"lib/button/musicplayer.swf?song_url=$url\"
+ width=\"17\" height=\"17\" style='float : left; margin-right : 5px;'>
+ <param name=\"movie\"
+ value=\"lib/button/musicplayer.swf?song_url=$url\" />
+ </object>";
+ }
+ }
+
+ $filename = substr($url, strrpos($url, "/")+1);
+
+ $entry .= " <a target=\"_blank\" href=\"" . htmlspecialchars($url) . "\">" .
+ $filename . " (" . $ctype . ")" . "</a>";
+
+ return $entry;
+ }
+
+ function format_article($link, $id, $mark_as_read = true, $zoom_mode = false) {
+
+ $rv = array();
+
+ $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 :( */
+
+ $result = db_query($link, "SELECT feed_id FROM ttrss_user_entries
+ WHERE ref_id = '$id'");
+
+ $feed_id = (int) db_fetch_result($result, 0, "feed_id");
+
+ $rv['feed_id'] = $feed_id;
+
+ //if (!$zoom_mode) { print "<article id='$id'><![CDATA["; };
+
+ $result = db_query($link, "SELECT rtl_content, always_display_enclosures FROM ttrss_feeds
+ WHERE id = '$feed_id' AND owner_uid = " . $_SESSION["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"));
+ } else {
+ $rtl_content = false;
+ $always_display_enclosures = 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()
+ WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
+
+ ccache_update($link, $feed_id, $_SESSION["uid"]);
+ }
+
+ $result = db_query($link, "SELECT title,link,content,feed_id,comments,int_id,
+ ".SUBSTRING_FOR_DATE."(updated,1,16) as updated,
+ (SELECT icon_url FROM ttrss_feeds WHERE id = feed_id) as icon_url,
+ (SELECT site_url FROM ttrss_feeds WHERE id = feed_id) as site_url,
+ num_comments,
+ tag_cache,
+ author,
+ orig_feed_id,
+ note
+ FROM ttrss_entries,ttrss_user_entries
+ WHERE id = '$id' AND ref_id = id AND owner_uid = " . $_SESSION["uid"]);
+
+ if ($result) {
+
+ $line = db_fetch_assoc($result);
+
+ if ($line["icon_url"]) {
+ $feed_icon = "<img src=\"" . $line["icon_url"] . "\">";
+ } else {
+ $feed_icon = " ";
+ }
+
+ $feed_site_url = $line['site_url'];
+
+ $num_comments = $line["num_comments"];
+ $entry_comments = "";
+
+ if ($num_comments > 0) {
+ if ($line["comments"]) {
+ $comments_url = $line["comments"];
+ } else {
+ $comments_url = $line["link"];
+ }
+ $entry_comments = "<a target='_blank' href=\"$comments_url\">$num_comments comments</a>";
+ } else {
+ if ($line["comments"] && $line["link"] != $line["comments"]) {
+ $entry_comments = "<a target='_blank' href=\"".$line["comments"]."\">comments</a>";
+ }
+ }
+
+ if ($zoom_mode) {
+ header("Content-Type: text/html");
+ $rv['content'] .= "<html><head>
+ <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>";
+ }
+
+ $rv['content'] .= "<div id=\"PTITLE-$id\" style=\"display : none\">" .
+ truncate_string(strip_tags($line['title']), 15) . "</div>";
+
+ $rv['content'] .= "<div class=\"postReply\" id=\"POST-$id\">";
+
+ $rv['content'] .= "<div onclick=\"return postClicked(event, $id)\"
+ class=\"postHeader\" id=\"POSTHDR-$id\">";
+
+ $entry_author = $line["author"];
+
+ if ($entry_author) {
+ $entry_author = __(" - ") . $entry_author;
+ }
+
+ $parsed_updated = make_local_datetime($link, $line["updated"], true,
+ false, true);
+
+ $rv['content'] .= "<div class=\"postDate$rtl_class\">$parsed_updated</div>";
+
+ if ($line["link"]) {
+ $rv['content'] .= "<div clear='both'><a target='_blank'
+ title=\"".htmlspecialchars($line['title'])."\"
+ href=\"" .
+ $line["link"] . "\">" .
+ truncate_string($line["title"], 100) .
+ "<span class='author'>$entry_author</span></a></div>";
+ } else {
+ $rv['content'] .= "<div clear='both'>" . $line["title"] . "$entry_author</div>";
+ }
+
+ $tag_cache = $line["tag_cache"];
+
+ if (!$tag_cache)
+ $tags = get_article_tags($link, $id);
+ else
+ $tags = explode(",", $tag_cache);
+
+ $tags_str = format_tags_string($tags, $id);
+ $tags_str_full = join(", ", $tags);
+
+ if (!$tags_str_full) $tags_str_full = __("no tags");
+
+ if (!$entry_comments) $entry_comments = " "; # placeholder
+
+ $rv['content'] .= "<div style='float : right'>
+ <img src='".theme_image($link, 'images/tag.png')."'
+ class='tagsPic' alt='Tags' title='Tags'> ";
+
+ if (!$zoom_mode) {
+ $rv['content'] .= "<span id=\"ATSTR-$id\">$tags_str</span>
+ <a title=\"".__('Edit tags for this article')."\"
+ href=\"#\" onclick=\"editArticleTags($id, $feed_id)\">(+)</a>";
+
+ $rv['content'] .= "<div dojoType=\"dijit.Tooltip\"
+ id=\"ATSTRTIP-$id\" connectId=\"ATSTR-$id\"
+ position=\"below\">$tags_str_full</div>";
+
+ $rv['content'] .= "<img src=\"".theme_image($link, 'images/art-zoom.png')."\"
+ class='tagsPic' style=\"cursor : pointer\"
+ onclick=\"postOpenInNewTab(event, $id)\"
+ alt='Zoom' title='".__('Open article in new tab')."'>";
+
+ //$note_escaped = htmlspecialchars($line['note'], ENT_QUOTES);
+
+ $rv['content'] .= "<img src=\"".theme_image($link, 'images/art-pub-note.png')."\"
+ class='tagsPic' style=\"cursor : pointer\"
+ onclick=\"editArticleNote($id)\"
+ alt='PubNote' title='".__('Edit article note')."'>";
+
+ if (DIGEST_ENABLE) {
+ $rv['content'] .= "<img src=\"".theme_image($link, 'images/art-email.png')."\"
+ class='tagsPic' style=\"cursor : pointer\"
+ onclick=\"emailArticle($id)\"
+ alt='Zoom' title='".__('Forward by email')."'>";
+ }
+
+ if (ENABLE_TWEET_BUTTON) {
+ $rv['content'] .= "<img src=\"".theme_image($link, 'images/art-tweet.png')."\"
+ class='tagsPic' style=\"cursor : pointer\"
+ onclick=\"tweetArticle($id)\"
+ alt='Zoom' title='".__('Share on Twitter')."'>";
+ }
+
+ $rv['content'] .= "<img src=\"".theme_image($link, 'images/art-share.png')."\"
+ class='tagsPic' style=\"cursor : pointer\"
+ onclick=\"shareArticle(".$line['int_id'].")\"
+ alt='Zoom' title='".__('Share by URL')."'>";
+
+ $rv['content'] .= "<img src=\"".theme_image($link, 'images/digest_checkbox.png')."\"
+ class='tagsPic' style=\"cursor : pointer\"
+ onclick=\"closeArticlePanel($id)\"
+ alt='Zoom' title='".__('Close this panel')."'>";
+
+ } 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>";
+
+ if ($line["orig_feed_id"]) {
+
+ $tmp_result = db_query($link, "SELECT * FROM ttrss_archived_feeds
+ WHERE id = ".$line["orig_feed_id"]);
+
+ if (db_num_rows($tmp_result) != 0) {
+
+ $rv['content'] .= "<div clear='both'>";
+ $rv['content'] .= __("Originally from:");
+
+ $rv['content'] .= " ";
+
+ $tmp_line = db_fetch_assoc($tmp_result);
+
+ $rv['content'] .= "<a target='_blank'
+ href=' " . htmlspecialchars($tmp_line['site_url']) . "'>" .
+ $tmp_line['title'] . "</a>";
+
+ $rv['content'] .= " ";
+
+ $rv['content'] .= "<a target='_blank' href='" . htmlspecialchars($tmp_line['feed_url']) . "'>";
+ $rv['content'] .= "<img title='".__('Feed URL')."'class='tinyFeedIcon' src='images/pub_set.gif'></a>";
+
+ $rv['content'] .= "</div>";
+ }
+ }
+
+ $rv['content'] .= "</div>";
+
+ $rv['content'] .= "<div id=\"POSTNOTE-$id\">";
+ if ($line['note']) {
+ $rv['content'] .= format_article_note($id, $line['note']);
+ }
+ $rv['content'] .= "</div>";
+
+ $rv['content'] .= "<div class=\"postIcon\">" .
+ "<a target=\"_blank\" title=\"".__("Visit the website")."\"$
+ href=\"".htmlspecialchars($feed_site_url)."\">".
+ $feed_icon . "</a></div>";
+
+ $rv['content'] .= "<div class=\"postContent\">";
+
+ $article_content = sanitize_rss($link, $line["content"], false, false,
+ $feed_site_url);
+
+ $rv['content'] .= $article_content;
+
+ $rv['content'] .= format_article_enclosures($link, $id,
+ $always_display_enclosures, $article_content);
+
+ $rv['content'] .= "</div>";
+
+ $rv['content'] .= "</div>";
+
+ }
+
+ if ($zoom_mode) {
+ $rv['content'] .= "
+ <div style=\"text-align : center\">
+ <button onclick=\"return window.close()\">".
+ __("Close this window")."</button></div>";
+ $rv['content'] .= "</body></html>";
+ }
+
+ return $rv;
+
+ }
+
+ function format_headlines_list($link, $feed, $subop, $view_mode, $limit, $cat_view,
+ $next_unread_feed, $offset, $vgr_last_feed = false,
+ $override_order = false) {
+
+ $disable_cache = false;
+
+ $reply = array();
+
+ $timing_info = getmicrotime();
+
+ $topmost_article_ids = array();
+
+ if (!$offset) $offset = 0;
+ if ($subop == "undefined") $subop = "";
+
+ $subop_split = explode(":", $subop);
+
+/* if ($subop == "CatchupSelected") {
+ $ids = explode(",", db_escape_string($_REQUEST["ids"]));
+ $cmode = sprintf("%d", $_REQUEST["cmode"]);
+
+ catchupArticlesById($link, $ids, $cmode);
+ } */
+
+ if ($subop == "ForceUpdate" && $feed && is_numeric($feed) > 0) {
+ update_rss_feed($link, $feed, true);
+ }
+
+ if ($subop == "MarkAllRead") {
+ catchup_feed($link, $feed, $cat_view);
+
+ if (get_pref($link, 'ON_CATCHUP_SHOW_NEXT_FEED')) {
+ if ($next_unread_feed) {
+ $feed = $next_unread_feed;
+ }
+ }
+ }
+
+ if ($subop_split[0] == "MarkAllReadGR") {
+ catchup_feed($link, $subop_split[1], false);
+ }
+
+ // FIXME: might break tag display?
+
+ if (is_numeric($feed) && $feed > 0 && !$cat_view) {
+ $result = db_query($link,
+ "SELECT id FROM ttrss_feeds WHERE id = '$feed' LIMIT 1");
+
+ if (db_num_rows($result) == 0) {
+ $reply['content'] = "<div align='center'>".__('Feed not found.')."</div>";
+ }
+ }
+
+ if (preg_match("/^-?[0-9][0-9]*$/", $feed) != false) {
+
+ $result = db_query($link, "SELECT rtl_content FROM ttrss_feeds
+ WHERE id = '$feed' AND owner_uid = " . $_SESSION["uid"]);
+
+ if (db_num_rows($result) == 1) {
+ $rtl_content = sql_bool_to_bool(db_fetch_result($result, 0, "rtl_content"));
+ } else {
+ $rtl_content = false;
+ }
+
+ if ($rtl_content) {
+ $rtl_tag = "dir=\"RTL\"";
+ } else {
+ $rtl_tag = "";
+ }
+ } else {
+ $rtl_tag = "";
+ $rtl_content = false;
+ }
+
+ @$search = db_escape_string($_REQUEST["query"]);
+
+ if ($search) {
+ $disable_cache = true;
+ }
+
+ @$search_mode = db_escape_string($_REQUEST["search_mode"]);
+ @$match_on = db_escape_string($_REQUEST["match_on"]);
+
+ if (!$match_on) {
+ $match_on = "both";
+ }
+
+ if ($_REQUEST["debug"]) $timing_info = print_checkpoint("H0", $timing_info);
+
+// error_log("format_headlines_list: [" . $feed . "] subop [" . $subop . "]");
+ if( $search_mode == '' && $subop != '' ){
+ $search_mode = $subop;
+ }
+// error_log("search_mode: " . $search_mode);
+ $qfh_ret = queryFeedHeadlines($link, $feed, $limit, $view_mode, $cat_view,
+ $search, $search_mode, $match_on, $override_order, $offset);
+
+ if ($_REQUEST["debug"]) $timing_info = print_checkpoint("H1", $timing_info);
+
+ $result = $qfh_ret[0];
+ $feed_title = $qfh_ret[1];
+ $feed_site_url = $qfh_ret[2];
+ $last_error = $qfh_ret[3];
+
+ $vgroup_last_feed = $vgr_last_feed;
+
+// if (!$offset) {
+
+ if (db_num_rows($result) > 0) {
+ $reply['toolbar'] = format_headline_subtoolbar($link, $feed_site_url,
+ $feed_title,
+ $feed, $cat_view, $search, $match_on, $search_mode, $view_mode,
+ $last_error);
+ }
+// }
+
+ $headlines_count = db_num_rows($result);
+
+ if (db_num_rows($result) > 0) {
+
+ $lnum = $offset;
+
+ $num_unread = 0;
+ $cur_feed_title = '';
+
+ $fresh_intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE") * 60 * 60;
+
+ if ($_REQUEST["debug"]) $timing_info = print_checkpoint("PS", $timing_info);
+
+ while ($line = db_fetch_assoc($result)) {
+
+ $class = ($lnum % 2) ? "even" : "odd";
+
+ $id = $line["id"];
+ $feed_id = $line["feed_id"];
+ $label_cache = $line["label_cache"];
+ $labels = false;
+
+ if ($label_cache) {
+ $label_cache = json_decode($label_cache, true);
+
+ if ($label_cache) {
+ if ($label_cache["no-labels"] == 1)
+ $labels = array();
+ else
+ $labels = $label_cache;
+ }
+ }
+
+ if (!is_array($labels)) $labels = get_article_labels($link, $id);
+
+ $labels_str = "<span id=\"HLLCTR-$id\">";
+ $labels_str .= format_article_labels($labels, $id);
+ $labels_str .= "</span>";
+
+ if (count($topmost_article_ids) < 3) {
+ array_push($topmost_article_ids, $id);
+ }
+
+ if ($line["last_read"] == "" && !sql_bool_to_bool($line["unread"])) {
+
+ $update_pic = "<img id='FUPDPIC-$id' src=\"".
+ theme_image($link, 'images/updated.png')."\"
+ alt=\"Updated\">";
+ } else {
+ $update_pic = "<img id='FUPDPIC-$id' src=\"images/blank_icon.gif\"
+ alt=\"Updated\">";
+ }
+
+ if (sql_bool_to_bool($line["unread"]) &&
+ time() - strtotime($line["updated_noms"]) < $fresh_intl) {
+
+ $update_pic = "<img id='FUPDPIC-$id' src=\"".
+ theme_image($link, 'images/fresh_sign.png')."\" alt=\"Fresh\">";
+ }
+
+ if ($line["unread"] == "t" || $line["unread"] == "1") {
+ $class .= " Unread";
+ ++$num_unread;
+ $is_unread = true;
+ } else {
+ $is_unread = false;
+ }
+
+ if ($line["marked"] == "t" || $line["marked"] == "1") {
+ $marked_pic = "<img id=\"FMPIC-$id\"
+ src=\"".theme_image($link, 'images/mark_set.png')."\"
+ class=\"markedPic\" alt=\"Unstar article\"
+ onclick='javascript:toggleMark($id)'>";
+ } else {
+ $marked_pic = "<img id=\"FMPIC-$id\"
+ src=\"".theme_image($link, 'images/mark_unset.png')."\"
+ class=\"markedPic\" alt=\"Star article\"
+ onclick='javascript:toggleMark($id)'>";
+ }
+
+ if ($line["published"] == "t" || $line["published"] == "1") {
+ $published_pic = "<img id=\"FPPIC-$id\" src=\"".theme_image($link,
+ 'images/pub_set.png')."\"
+ class=\"markedPic\"
+ alt=\"Unpublish article\" onclick='javascript:togglePub($id)'>";
+ } else {
+ $published_pic = "<img id=\"FPPIC-$id\" src=\"".theme_image($link,
+ 'images/pub_unset.png')."\"
+ class=\"markedPic\"
+ alt=\"Publish article\" onclick='javascript:togglePub($id)'>";
+ }
+
+# $content_link = "<a target=\"_blank\" href=\"".$line["link"]."\">" .
+# $line["title"] . "</a>";
+
+# $content_link = "<a
+# href=\"" . htmlspecialchars($line["link"]) . "\"
+# onclick=\"view($id,$feed_id);\">" .
+# $line["title"] . "</a>";
+
+# $content_link = "<a href=\"javascript:viewContentUrl('".$line["link"]."');\">" .
+# $line["title"] . "</a>";
+
+ $updated_fmt = make_local_datetime($link, $line["updated_noms"], false);
+
+ if (get_pref($link, 'SHOW_CONTENT_PREVIEW')) {
+ $content_preview = truncate_string(strip_tags($line["content_preview"]),
+ 100);
+ }
+
+ $score = $line["score"];
+
+ $score_pic = theme_image($link,
+ "images/" . get_score_pic($score));
+
+/* $score_title = __("(Click to change)");
+ $score_pic = "<img class='hlScorePic' src=\"images/$score_pic\"
+ onclick=\"adjustArticleScore($id, $score)\" title=\"$score $score_title\">"; */
+
+ $score_pic = "<img class='hlScorePic' src=\"$score_pic\"
+ title=\"$score\">";
+
+ if ($score > 500) {
+ $hlc_suffix = "H";
+ } else if ($score < -100) {
+ $hlc_suffix = "L";
+ } else {
+ $hlc_suffix = "";
+ }
+
+ $entry_author = $line["author"];
+
+ if ($entry_author) {
+ $entry_author = " - $entry_author";
+ }
+
+ $has_feed_icon = feed_has_icon($feed_id);
+
+ if ($has_feed_icon) {
+ $feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"".ICONS_URL."/$feed_id.ico\" alt=\"\">";
+ } else {
+ $feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"images/feed-icon-12x12.png\" alt=\"\">";
+ }
+
+ if (!get_pref($link, 'COMBINED_DISPLAY_MODE')) {
+
+ if (get_pref($link, 'VFEED_GROUP_BY_FEED')) {
+ if ($feed_id != $vgroup_last_feed && $line["feed_title"]) {
+
+ $cur_feed_title = $line["feed_title"];
+ $vgroup_last_feed = $feed_id;
+
+ $cur_feed_title = htmlspecialchars($cur_feed_title);
+
+ $vf_catchup_link = "(<a onclick='javascript:catchupFeedInGroup($feed_id);' href='#'>".__('mark as read')."</a>)";
+
+ $reply['content'] .= "<div class='cdmFeedTitle'>".
+ "<div style=\"float : right\">$feed_icon_img</div>".
+ "<a href=\"#\" onclick=\"viewfeed($feed_id)\">".
+ $line["feed_title"]."</a> $vf_catchup_link</div>";
+
+ }
+ }
+
+ $mouseover_attrs = "onmouseover='postMouseIn($id)'
+ onmouseout='postMouseOut($id)'";
+
+ $reply['content'] .= "<div class='$class' id='RROW-$id' $mouseover_attrs>";
+
+ $reply['content'] .= "<div class='hlUpdPic'>$update_pic</div>";
+
+ $reply['content'] .= "<div class='hlLeft'>";
+
+ $reply['content'] .= "<input type=\"checkbox\" onclick=\"tSR(this)\"
+ id=\"RCHK-$id\">";
+
+ $reply['content'] .= "$marked_pic";
+ $reply['content'] .= "$published_pic";
+
+ $reply['content'] .= "</div>";
+
+ $reply['content'] .= "<div onclick='return hlClicked(event, $id)'
+ class=\"hlTitle\"><span class='hlContent$hlc_suffix'>";
+ $reply['content'] .= "<a id=\"RTITLE-$id\"
+ href=\"" . htmlspecialchars($line["link"]) . "\"
+ onclick=\"\">" .
+ truncate_string($line["title"], 200);
+
+ if (get_pref($link, 'SHOW_CONTENT_PREVIEW')) {
+ if ($content_preview) {
+ $reply['content'] .= "<span class=\"contentPreview\"> - $content_preview</span>";
+ }
+ }
+
+ $reply['content'] .= "</a></span>";
+
+ $reply['content'] .= $labels_str;
+
+ if (!get_pref($link, 'VFEED_GROUP_BY_FEED') &&
+ defined('_SHOW_FEED_TITLE_IN_VFEEDS')) {
+ if (@$line["feed_title"]) {
+ $reply['content'] .= "<span class=\"hlFeed\">
+ (<a href=\"#\" onclick=\"viewfeed($feed_id)\">".
+ $line["feed_title"]."</a>)
+ </span>";
+ }
+ }
+
+ $reply['content'] .= "</div>";
+
+ $reply['content'] .= "<span class=\"hlUpdated\">$updated_fmt</span>";
+ $reply['content'] .= "<div class=\"hlRight\">";
+
+ $reply['content'] .= $score_pic;
+
+ if ($line["feed_title"] && !get_pref($link, 'VFEED_GROUP_BY_FEED')) {
+
+ $reply['content'] .= "<span onclick=\"viewfeed($feed_id)\"
+ style=\"cursor : pointer\"
+ title=\"".htmlspecialchars($line['feed_title'])."\">
+ $feed_icon_img<span>";
+ }
+
+ $reply['content'] .= "</div>";
+ $reply['content'] .= "</div>";
+
+ } else {
+
+ if (get_pref($link, 'VFEED_GROUP_BY_FEED') && $line["feed_title"]) {
+ if ($feed_id != $vgroup_last_feed) {
+
+ $cur_feed_title = $line["feed_title"];
+ $vgroup_last_feed = $feed_id;
+
+ $cur_feed_title = htmlspecialchars($cur_feed_title);
+
+ $vf_catchup_link = "(<a onclick='javascript:catchupFeedInGroup($feed_id);' href='#'>".__('mark as read')."</a>)";
+
+ $has_feed_icon = feed_has_icon($feed_id);
+
+ if ($has_feed_icon) {
+ $feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"".ICONS_URL."/$feed_id.ico\" alt=\"\">";
+ } else {
+ //$feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"images/blank_icon.gif\" alt=\"\">";
+ }
+
+ $reply['content'] .= "<div class='cdmFeedTitle'>".
+ "<div style=\"float : right\">$feed_icon_img</div>".
+ "<a href=\"#\" onclick=\"viewfeed($feed_id)\">".
+ $line["feed_title"]."</a> $vf_catchup_link</div>";
+ }
+ }
+
+ $expand_cdm = get_pref($link, 'CDM_EXPANDED');
+
+ $mouseover_attrs = "onmouseover='postMouseIn($id)'
+ onmouseout='postMouseOut($id)'";
+
+ $reply['content'] .= "<div class=\"$class\"
+ id=\"RROW-$id\" $mouseover_attrs'>";
+
+ $reply['content'] .= "<div class=\"cdmHeader\">";
+
+ $reply['content'] .= "<div>";
+
+ $reply['content'] .= "<input type=\"checkbox\" onclick=\"toggleSelectRowById(this,
+ 'RROW-$id')\" id=\"RCHK-$id\"/>";
+
+ $reply['content'] .= "$marked_pic";
+ $reply['content'] .= "$published_pic";
+
+ $reply['content'] .= "</div>";
+
+ $reply['content'] .= "<span id=\"RTITLE-$id\"
+ onclick=\"return cdmClicked(event, $id);\"
+ class=\"titleWrap$hlc_suffix\">
+ <a class=\"title\"
+ title=\"".htmlspecialchars($line['title'])."\"
+ target=\"_blank\" href=\"".
+ htmlspecialchars($line["link"])."\">".
+ truncate_string($line["title"], 100) .
+ " $entry_author</a>";
+
+ $reply['content'] .= $labels_str;
+
+ if (!get_pref($link, 'VFEED_GROUP_BY_FEED') &&
+ defined('_SHOW_FEED_TITLE_IN_VFEEDS')) {
+ if (@$line["feed_title"]) {
+ $reply['content'] .= "<span class=\"hlFeed\">
+ (<a href=\"#\" onclick=\"viewfeed($feed_id)\">".
+ $line["feed_title"]."</a>)
+ </span>";
+ }
+ }
+
+ if (!$expand_cdm)
+ $content_hidden = "style=\"display : none\"";
+ else
+ $excerpt_hidden = "style=\"display : none\"";
+
+ $reply['content'] .= "<span $excerpt_hidden
+ id=\"CEXC-$id\" class=\"cdmExcerpt\"> - $content_preview</span>";
+
+ $reply['content'] .= "</span>";
+
+ $reply['content'] .= "<div>";
+ $reply['content'] .= "<span class='updated'>$updated_fmt</span>";
+ $reply['content'] .= "$score_pic";
+
+ if (!get_pref($link, "VFEED_GROUP_BY_FEED") && $line["feed_title"]) {
+ $reply['content'] .= "<span style=\"cursor : pointer\"
+ title=\"".htmlspecialchars($line["feed_title"])."\"
+ onclick=\"viewfeed($feed_id)\">$feed_icon_img</span>";
+ }
+ $reply['content'] .= "<div class=\"updPic\">$update_pic</div>";
+ $reply['content'] .= "</div>";
+
+ $reply['content'] .= "</div>";
+
+ $reply['content'] .= "<div class=\"cdmContent\" $content_hidden
+ onclick=\"return cdmClicked(event, $id);\"
+ id=\"CICD-$id\">";
+
+ $reply['content'] .= "<div class=\"cdmContentInner\">";
+
+ if ($line["orig_feed_id"]) {
+
+ $tmp_result = db_query($link, "SELECT * FROM ttrss_archived_feeds
+ WHERE id = ".$line["orig_feed_id"]);
+
+ if (db_num_rows($tmp_result) != 0) {
+
+ $reply['content'] .= "<div clear='both'>";
+ $reply['content'] .= __("Originally from:");
+
+ $reply['content'] .= " ";
+
+ $tmp_line = db_fetch_assoc($tmp_result);
+
+ $reply['content'] .= "<a target='_blank'
+ href=' " . htmlspecialchars($tmp_line['site_url']) . "'>" .
+ $tmp_line['title'] . "</a>";
+
+ $reply['content'] .= " ";
+
+ $reply['content'] .= "<a target='_blank' href='" . htmlspecialchars($tmp_line['feed_url']) . "'>";
+ $reply['content'] .= "<img title='".__('Feed URL')."'class='tinyFeedIcon' src='images/pub_set.gif'></a>";
+
+ $reply['content'] .= "</div>";
+ }
+ }
+
+ $feed_site_url = $line["site_url"];
+
+ $article_content = sanitize_rss($link, $line["content_preview"],
+ false, false, $feed_site_url);
+
+ $reply['content'] .= "<div id=\"POSTNOTE-$id\">";
+ if ($line['note']) {
+ $reply['content'] .= format_article_note($id, $line['note']);
+ }
+ $reply['content'] .= "</div>";
+
+ $reply['content'] .= "<span id=\"CWRAP-$id\">";
+ $reply['content'] .= $expand_cdm ? $article_content : '';
+ $reply['content'] .= "</span>";
+
+/* $tmp_result = db_query($link, "SELECT always_display_enclosures FROM
+ ttrss_feeds WHERE id = ".
+ (($line['feed_id'] == null) ? $line['orig_feed_id'] :
+ $line['feed_id'])." AND owner_uid = ".$_SESSION["uid"]);
+
+ $always_display_enclosures = sql_bool_to_bool(db_fetch_result($tmp_result,
+ 0, "always_display_enclosures")); */
+
+ $always_display_enclosures = sql_bool_to_bool($line["always_display_enclosures"]);
+
+ $reply['content'] .= format_article_enclosures($link, $id, $always_display_enclosures,
+ $article_content);
+
+ $reply['content'] .= "</div>";
+
+ $reply['content'] .= "<div class=\"cdmFooter\">";
+
+ $tag_cache = $line["tag_cache"];
+
+ $tags_str = format_tags_string(
+ get_article_tags($link, $id, $_SESSION["uid"], $tag_cache),
+ $id);
+
+ $reply['content'] .= "<img src='".theme_image($link,
+ 'images/tag.png')."' alt='Tags' title='Tags'>
+ <span id=\"ATSTR-$id\">$tags_str</span>
+ <a title=\"".__('Edit tags for this article')."\"
+ href=\"#\" onclick=\"editArticleTags($id, $feed_id, true)\">(+)</a>";
+
+ $num_comments = $line["num_comments"];
+ $entry_comments = "";
+
+ if ($num_comments > 0) {
+ if ($line["comments"]) {
+ $comments_url = $line["comments"];
+ } else {
+ $comments_url = $line["link"];
+ }
+ $entry_comments = "<a target='_blank' href=\"$comments_url\">$num_comments comments</a>";
+ } else {
+ if ($line["comments"] && $line["link"] != $line["comments"]) {
+ $entry_comments = "<a target='_blank' href=\"".$line["comments"]."\">comments</a>";
+ }
+ }
+
+ if ($entry_comments) $reply['content'] .= " ($entry_comments)";
+
+ $reply['content'] .= "<div style=\"float : right\">";
+
+ $reply['content'] .= "<img src=\"images/art-zoom.png\"
+ onclick=\"zoomToArticle(event, $id)\"
+ style=\"cursor : pointer\"
+ alt='Zoom'
+ title='".__('Open article in new tab')."'>";
+
+ //$note_escaped = htmlspecialchars($line['note'], ENT_QUOTES);
+
+ $reply['content'] .= "<img src=\"images/art-pub-note.png\"
+ style=\"cursor : pointer\" style=\"cursor : pointer\"
+ onclick=\"editArticleNote($id)\"
+ alt='PubNote' title='".__('Edit article note')."'>";
+
+ if (DIGEST_ENABLE) {
+ $reply['content'] .= "<img src=\"".theme_image($link, 'images/art-email.png')."\"
+ style=\"cursor : pointer\"
+ onclick=\"emailArticle($id)\"
+ alt='Zoom' title='".__('Forward by email')."'>";
+ }
+
+ if (ENABLE_TWEET_BUTTON) {
+ $reply['content'] .= "<img src=\"".theme_image($link, 'images/art-tweet.png')."\"
+ class='tagsPic' style=\"cursor : pointer\"
+ onclick=\"tweetArticle($id)\"
+ alt='Zoom' title='".__('Share on Twitter')."'>";
+ }
+
+ $reply['content'] .= "<img src=\"".theme_image($link, 'images/art-share.png')."\"
+ class='tagsPic' style=\"cursor : pointer\"
+ onclick=\"shareArticle(".$line['int_id'].")\"
+ alt='Zoom' title='".__('Share by URL')."'>";
+
+ $reply['content'] .= "<img src=\"images/digest_checkbox.png\"
+ style=\"cursor : pointer\" style=\"cursor : pointer\"
+ onclick=\"dismissArticle($id)\"
+ alt='Dismiss' title='".__('Dismiss article')."'>";
+
+ $reply['content'] .= "</div>";
+ $reply['content'] .= "</div>";
+
+ $reply['content'] .= "</div>";
+
+ $reply['content'] .= "</div>";
+
+ }
+
+ ++$lnum;
+ }
+
+ if ($_REQUEST["debug"]) $timing_info = print_checkpoint("PE", $timing_info);
+
+ } else {
+ $message = "";
+
+ switch ($view_mode) {
+ case "unread":
+ $message = __("No unread articles found to display.");
+ break;
+ case "updated":
+ $message = __("No updated articles found to display.");
+ break;
+ case "marked":
+ $message = __("No starred articles found to display.");
+ break;
+ default:
+ if ($feed < -10) {
+ $message = __("No articles found to display. You can assign articles to labels manually (see the Actions menu above) or use a filter.");
+ } else {
+ $message = __("No articles found to display.");
+ }
+ }
+
+ if (!$offset && $message) {
+ $reply['content'] .= "<div class='whiteBox'>$message";
+
+ $reply['content'] .= "<p class=\"small\"><span class=\"insensitive\">";
+
+ $result = db_query($link, "SELECT ".SUBSTRING_FOR_DATE."(MAX(last_updated), 1, 19) AS last_updated FROM ttrss_feeds
+ WHERE owner_uid = " . $_SESSION['uid']);
+
+ $last_updated = db_fetch_result($result, 0, "last_updated");
+ $last_updated = make_local_datetime($link, $last_updated, false);
+
+ $reply['content'] .= sprintf(__("Feeds last updated at %s"), $last_updated);
+
+ $result = db_query($link, "SELECT COUNT(id) AS num_errors
+ FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ".$_SESSION["uid"]);
+
+ $num_errors = db_fetch_result($result, 0, "num_errors");
+
+ if ($num_errors > 0) {
+ $reply['content'] .= "<br/>";
+ $reply['content'] .= "<a class=\"insensitive\" href=\"#\" onclick=\"showFeedsWithErrors()\">".
+ __('Some feeds have update errors (click for details)')."</a>";
+ }
+ $reply['content'] .= "</span></p></div>";
+ }
+ }
+
+ if ($_REQUEST["debug"]) $timing_info = print_checkpoint("H2", $timing_info);
+
+ return array($topmost_article_ids, $headlines_count, $feed, $disable_cache,
+ $vgroup_last_feed, $reply);
+ }
+
+// from here: http://www.roscripts.com/Create_tag_cloud-71.html
+
+ function printTagCloud($link) {
+
+ $query = "SELECT tag_name, COUNT(post_int_id) AS count
+ FROM ttrss_tags WHERE owner_uid = ".$_SESSION["uid"]."
+ GROUP BY tag_name ORDER BY count DESC LIMIT 50";
+
+ $result = db_query($link, $query);
+
+ $tags = array();
+
+ while ($line = db_fetch_assoc($result)) {
+ $tags[$line["tag_name"]] = $line["count"];
+ }
+
+ if( count($tags) == 0 ){ return; }
+
+ ksort($tags);
+
+ $max_size = 32; // max font size in pixels
+ $min_size = 11; // min font size in pixels
+
+ // largest and smallest array values
+ $max_qty = max(array_values($tags));
+ $min_qty = min(array_values($tags));
+
+ // find the range of values
+ $spread = $max_qty - $min_qty;
+ if ($spread == 0) { // we don't want to divide by zero
+ $spread = 1;
+ }
+
+ // set the font-size increment
+ $step = ($max_size - $min_size) / ($spread);
+
+ // loop through the tag array
+ foreach ($tags as $key => $value) {
+ // calculate font-size
+ // find the $value in excess of $min_qty
+ // multiply by the font-size increment ($size)
+ // and add the $min_size set above
+ $size = round($min_size + (($value - $min_qty) * $step));
+
+ $key_escaped = str_replace("'", "\\'", $key);
+
+ echo "<a href=\"javascript:viewfeed('$key_escaped') \" style=\"font-size: " .
+ $size . "px\" title=\"$value articles tagged with " .
+ $key . '">' . $key . '</a> ';
+ }
+ }
+
+ function print_checkpoint($n, $s) {
+ $ts = getmicrotime();
+ echo sprintf("<!-- CP[$n] %.4f seconds -->", $ts - $s);
+ return $ts;
+ }
+
+ function sanitize_tag($tag) {
+ $tag = trim($tag);
+
+ $tag = mb_strtolower($tag, 'utf-8');
+
+ $tag = preg_replace('/[\'\"\+\>\<]/', "", $tag);
+
+// $tag = str_replace('"', "", $tag);
+// $tag = str_replace("+", " ", $tag);
+ $tag = str_replace("technorati tag: ", "", $tag);
+
+ return $tag;
+ }
+
+ function get_self_url_prefix() {
+ return SELF_URL_PATH;
+ }
+
+ function opml_publish_url($link){
+
+ $url_path = get_self_url_prefix();
+ $url_path .= "/opml.php?op=publish&key=" .
+ get_feed_access_key($link, 'OPML:Publish', false, $_SESSION["uid"]);
+
+ return $url_path;
+ }
+
+ /**
+ * Purge a feed contents, marked articles excepted.
+ *
+ * @param mixed $link The database connection.
+ * @param integer $id The id of the feed to purge.
+ * @return void
+ */
+ function clear_feed_articles($link, $id) {
+
+ if ($id != 0) {
+ $result = db_query($link, "DELETE FROM ttrss_user_entries
+ WHERE feed_id = '$id' AND marked = false AND owner_uid = " . $_SESSION["uid"]);
+ } else {
+ $result = db_query($link, "DELETE FROM ttrss_user_entries
+ WHERE feed_id IS NULL AND marked = false AND owner_uid = " . $_SESSION["uid"]);
+ }
+
+ $result = db_query($link, "DELETE FROM ttrss_entries WHERE
+ (SELECT COUNT(int_id) FROM ttrss_user_entries WHERE ref_id = id) = 0");
+
+ ccache_update($link, $id, $_SESSION['uid']);
+ } // function clear_feed_articles
+
+ /**
+ * Compute the Mozilla Firefox feed adding URL from server HOST and REQUEST_URI.
+ *
+ * @return string The Mozilla Firefox feed adding URL.
+ */
+ function add_feed_url() {
+ //$url_path = ($_SERVER['HTTPS'] != "on" ? 'http://' : 'https://') . $_SERVER["HTTP_HOST"] . parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
+
+ $url_path = get_self_url_prefix() .
+ "/backend.php?op=pref-feeds&quiet=1&subop=add&feed_url=%s";
+ return $url_path;
+ } // function add_feed_url
+
+ /**
+ * Encrypt a password in SHA1.
+ *
+ * @param string $pass The password to encrypt.
+ * @param string $login A optionnal login.
+ * @return string The encrypted password.
+ */
+ function encrypt_password($pass, $login = '') {
+ if ($login) {
+ return "SHA1X:" . sha1("$login:$pass");
+ } else {
+ return "SHA1:" . sha1($pass);
+ }
+ } // function encrypt_password
+
+ /**
+ * Update a feed batch.
+ * Used by daemons to update n feeds by run.
+ * Only update feed needing a update, and not being processed
+ * by another process.
+ *
+ * @param mixed $link Database link
+ * @param integer $limit Maximum number of feeds in update batch. Default to DAEMON_FEED_LIMIT.
+ * @param boolean $from_http Set to true if you call this function from http to disable cli specific code.
+ * @param boolean $debug Set to false to disable debug output. Default to true.
+ * @return void
+ */
+ function update_daemon_common($link, $limit = DAEMON_FEED_LIMIT, $from_http = false, $debug = true) {
+ // Process all other feeds using last_updated and interval parameters
+
+ // Test if the user has loggued in recently. If not, it does not update its feeds.
+ if (DAEMON_UPDATE_LOGIN_LIMIT > 0) {
+ if (DB_TYPE == "pgsql") {
+ $login_thresh_qpart = "AND ttrss_users.last_login >= NOW() - INTERVAL '".DAEMON_UPDATE_LOGIN_LIMIT." days'";
+ } else {
+ $login_thresh_qpart = "AND ttrss_users.last_login >= DATE_SUB(NOW(), INTERVAL ".DAEMON_UPDATE_LOGIN_LIMIT." DAY)";
+ }
+ } else {
+ $login_thresh_qpart = "";
+ }
+
+ // Test if the feed need a update (update interval exceded).
+ if (DB_TYPE == "pgsql") {
+ $update_limit_qpart = "AND ((
+ ttrss_feeds.update_interval = 0
+ AND ttrss_feeds.last_updated < NOW() - CAST((ttrss_user_prefs.value || ' minutes') AS INTERVAL)
+ ) OR (
+ ttrss_feeds.update_interval > 0
+ AND ttrss_feeds.last_updated < NOW() - CAST((ttrss_feeds.update_interval || ' minutes') AS INTERVAL)
+ ) OR ttrss_feeds.last_updated IS NULL)";
+ } else {
+ $update_limit_qpart = "AND ((
+ ttrss_feeds.update_interval = 0
+ AND ttrss_feeds.last_updated < DATE_SUB(NOW(), INTERVAL CONVERT(ttrss_user_prefs.value, SIGNED INTEGER) MINUTE)
+ ) OR (
+ ttrss_feeds.update_interval > 0
+ AND ttrss_feeds.last_updated < DATE_SUB(NOW(), INTERVAL ttrss_feeds.update_interval MINUTE)
+ ) OR ttrss_feeds.last_updated IS NULL)";
+ }
+
+ // Test if feed is currently being updated by another process.
+ if (DB_TYPE == "pgsql") {
+ $updstart_thresh_qpart = "AND (ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < NOW() - INTERVAL '5 minutes')";
+ } else {
+ $updstart_thresh_qpart = "AND (ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < DATE_SUB(NOW(), INTERVAL 5 MINUTE))";
+ }
+
+ // Test if there is a limit to number of updated feeds
+ $query_limit = "";
+ if($limit) $query_limit = sprintf("LIMIT %d", $limit);
+
+ $random_qpart = sql_random_function();
+
+ // We search for feed needing update.
+ $result = db_query($link, "SELECT ttrss_feeds.feed_url,ttrss_feeds.id, ttrss_feeds.owner_uid,
+ ".SUBSTRING_FOR_DATE."(ttrss_feeds.last_updated,1,19) AS last_updated,
+ ttrss_feeds.update_interval
+ FROM
+ ttrss_feeds, ttrss_users, ttrss_user_prefs
+ WHERE
+ ttrss_feeds.owner_uid = ttrss_users.id
+ AND ttrss_users.id = ttrss_user_prefs.owner_uid
+ AND ttrss_user_prefs.pref_name = 'DEFAULT_UPDATE_INTERVAL'
+ $login_thresh_qpart $update_limit_qpart
+ $updstart_thresh_qpart
+ ORDER BY $random_qpart $query_limit");
+
+ $user_prefs_cache = array();
+
+ if($debug) _debug(sprintf("Scheduled %d feeds to update...\n", db_num_rows($result)));
+
+ // Here is a little cache magic in order to minimize risk of double feed updates.
+ $feeds_to_update = array();
+ while ($line = db_fetch_assoc($result)) {
+ $feeds_to_update[$line['id']] = $line;
+ }
+
+ // We update the feed last update started date before anything else.
+ // There is no lag due to feed contents downloads
+ // It prevent an other process to update the same feed.
+ $feed_ids = array_keys($feeds_to_update);
+ if($feed_ids) {
+ db_query($link, sprintf("UPDATE ttrss_feeds SET last_update_started = NOW()
+ WHERE id IN (%s)", implode(',', $feed_ids)));
+ }
+
+ // For each feed, we call the feed update function.
+ while ($line = array_pop($feeds_to_update)) {
+
+ if($debug) _debug("Feed: " . $line["feed_url"] . ", " . $line["last_updated"]);
+
+ update_rss_feed($link, $line["id"], true);
+
+ sleep(1); // prevent flood (FIXME make this an option?)
+ }
+
+ // Send feed digests by email if needed.
+ if (DAEMON_SENDS_DIGESTS) send_headlines_digests($link);
+
+ } // function update_daemon_common
+
+ function sanitize_article_content($text) {
+ # we don't support CDATA sections in articles, they break our own escaping
+ $text = preg_replace("/\[\[CDATA/", "", $text);
+ $text = preg_replace("/\]\]\>/", "", $text);
+ return $text;
+ }
+
+ function load_filters($link, $feed, $owner_uid, $action_id = false) {
+ $filters = array();
+
+ global $memcache;
+
+ $obj_id = md5("FILTER:$feed:$owner_uid:$action_id");
+
+ if ($memcache && $obj = $memcache->get($obj_id)) {
+
+ return $obj;
+
+ } else {
+
+ if ($action_id) $ftype_query_part = "action_id = '$action_id' AND";
+
+ $result = db_query($link, "SELECT reg_exp,
+ ttrss_filter_types.name AS name,
+ ttrss_filter_actions.name AS action,
+ inverse,
+ action_param,
+ filter_param
+ FROM ttrss_filters,ttrss_filter_types,ttrss_filter_actions WHERE
+ enabled = true AND
+ $ftype_query_part
+ owner_uid = $owner_uid AND
+ ttrss_filter_types.id = filter_type AND
+ ttrss_filter_actions.id = action_id AND
+ (feed_id IS NULL OR feed_id = '$feed') ORDER BY reg_exp");
+
+ while ($line = db_fetch_assoc($result)) {
+ if (!$filters[$line["name"]]) $filters[$line["name"]] = array();
+ $filter["reg_exp"] = $line["reg_exp"];
+ $filter["action"] = $line["action"];
+ $filter["action_param"] = $line["action_param"];
+ $filter["filter_param"] = $line["filter_param"];
+ $filter["inverse"] = sql_bool_to_bool($line["inverse"]);
+
+ array_push($filters[$line["name"]], $filter);
+ }
+
+ if ($memcache) $memcache->add($obj_id, $filters, 0, 3600*8);
+
+ return $filters;
+ }
+ }
+
+ function get_score_pic($score) {
+ if ($score > 100) {
+ return "score_high.png";
+ } else if ($score > 0) {
+ return "score_half_high.png";
+ } else if ($score < -100) {
+ return "score_low.png";
+ } else if ($score < 0) {
+ return "score_half_low.png";
+ } else {
+ return "score_neutral.png";
+ }
+ }
+
+ function feed_has_icon($id) {
+ return is_file(ICONS_DIR . "/$id.ico") && filesize(ICONS_DIR . "/$id.ico") > 0;
+ }
+
+ function init_connection($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);
+ // db_query($link, "SET CHARACTER SET " . MYSQL_CHARSET);
+ }
+ }
+ }
+
+ function update_feedbrowser_cache($link) {
+
+ $result = db_query($link, "SELECT feed_url, site_url, title, COUNT(id) AS subscribers
+ FROM ttrss_feeds WHERE (SELECT COUNT(id) = 0 FROM ttrss_feeds AS tf
+ WHERE tf.feed_url = ttrss_feeds.feed_url
+ AND (private IS true OR auth_login != '' OR auth_pass != '' OR feed_url LIKE '%:%@%/%'))
+ GROUP BY feed_url, site_url, title ORDER BY subscribers DESC LIMIT 1000");
+
+ db_query($link, "BEGIN");
+
+ db_query($link, "DELETE FROM ttrss_feedbrowser_cache");
+
+ $count = 0;
+
+ while ($line = db_fetch_assoc($result)) {
+ $subscribers = db_escape_string($line["subscribers"]);
+ $feed_url = db_escape_string($line["feed_url"]);
+ $title = db_escape_string($line["title"]);
+ $site_url = db_escape_string($line["site_url"]);
+
+ $tmp_result = db_query($link, "SELECT subscribers FROM
+ ttrss_feedbrowser_cache WHERE feed_url = '$feed_url'");
+
+ if (db_num_rows($tmp_result) == 0) {
+
+ db_query($link, "INSERT INTO ttrss_feedbrowser_cache
+ (feed_url, site_url, title, subscribers) VALUES ('$feed_url',
+ '$site_url', '$title', '$subscribers')");
+
+ ++$count;
+
+ }
+
+ }
+
+ db_query($link, "COMMIT");
+
+ return $count;
+
+ }
+
+ /* function ccache_zero($link, $feed_id, $owner_uid) {
+ db_query($link, "UPDATE ttrss_counters_cache SET
+ value = 0, updated = NOW() WHERE
+ feed_id = '$feed_id' AND owner_uid = '$owner_uid'");
+ } */
+
+ function ccache_zero_all($link, $owner_uid) {
+ db_query($link, "UPDATE ttrss_counters_cache SET
+ value = 0 WHERE owner_uid = '$owner_uid'");
+
+ db_query($link, "UPDATE ttrss_cat_counters_cache SET
+ value = 0 WHERE owner_uid = '$owner_uid'");
+ }
+
+ function ccache_remove($link, $feed_id, $owner_uid, $is_cat = false) {
+
+ if (!$is_cat) {
+ $table = "ttrss_counters_cache";
+ } else {
+ $table = "ttrss_cat_counters_cache";
+ }
+
+ db_query($link, "DELETE FROM $table WHERE
+ feed_id = '$feed_id' AND owner_uid = '$owner_uid'");
+
+ }
+
+ function ccache_update_all($link, $owner_uid) {
+
+ if (get_pref($link, 'ENABLE_FEED_CATS', $owner_uid)) {
+
+ $result = db_query($link, "SELECT feed_id FROM ttrss_cat_counters_cache
+ WHERE feed_id > 0 AND owner_uid = '$owner_uid'");
+
+ while ($line = db_fetch_assoc($result)) {
+ ccache_update($link, $line["feed_id"], $owner_uid, true);
+ }
+
+ /* We have to manually include category 0 */
+
+ ccache_update($link, 0, $owner_uid, true);
+
+ } else {
+ $result = db_query($link, "SELECT feed_id FROM ttrss_counters_cache
+ WHERE feed_id > 0 AND owner_uid = '$owner_uid'");
+
+ while ($line = db_fetch_assoc($result)) {
+ print ccache_update($link, $line["feed_id"], $owner_uid);
+
+ }
+
+ }
+ }
+
+ function ccache_find($link, $feed_id, $owner_uid, $is_cat = false,
+ $no_update = false) {
+
+ if (!is_numeric($feed_id)) return;
+
+ if (!$is_cat) {
+ $table = "ttrss_counters_cache";
+ if ($feed_id > 0) {
+ $tmp_result = db_query($link, "SELECT owner_uid FROM ttrss_feeds
+ WHERE id = '$feed_id'");
+ $owner_uid = db_fetch_result($tmp_result, 0, "owner_uid");
+ }
+ } else {
+ $table = "ttrss_cat_counters_cache";
+ }
+
+ if (DB_TYPE == "pgsql") {
+ $date_qpart = "updated > NOW() - INTERVAL '15 minutes'";
+ } else if (DB_TYPE == "mysql") {
+ $date_qpart = "updated > DATE_SUB(NOW(), INTERVAL 15 MINUTE)";
+ }
+
+ $result = db_query($link, "SELECT value FROM $table
+ WHERE owner_uid = '$owner_uid' AND feed_id = '$feed_id'
+ LIMIT 1");
+
+ if (db_num_rows($result) == 1) {
+ return db_fetch_result($result, 0, "value");
+ } else {
+ if ($no_update) {
+ return -1;
+ } else {
+ return ccache_update($link, $feed_id, $owner_uid, $is_cat);
+ }
+ }
+
+ }
+
+ function ccache_update($link, $feed_id, $owner_uid, $is_cat = false,
+ $update_pcat = true) {
+
+ if (!is_numeric($feed_id)) return;
+
+ if (!$is_cat && $feed_id > 0) {
+ $tmp_result = db_query($link, "SELECT owner_uid FROM ttrss_feeds
+ WHERE id = '$feed_id'");
+ $owner_uid = db_fetch_result($tmp_result, 0, "owner_uid");
+ }
+
+ $prev_unread = ccache_find($link, $feed_id, $owner_uid, $is_cat, true);
+
+ /* When updating a label, all we need to do is recalculate feed counters
+ * because labels are not cached */
+
+ if ($feed_id < 0) {
+ ccache_update_all($link, $owner_uid);
+ return;
+ }
+
+ if (!$is_cat) {
+ $table = "ttrss_counters_cache";
+ } else {
+ $table = "ttrss_cat_counters_cache";
+ }
+
+ if ($is_cat && $feed_id >= 0) {
+ if ($feed_id != 0) {
+ $cat_qpart = "cat_id = '$feed_id'";
+ } else {
+ $cat_qpart = "cat_id IS NULL";
+ }
+
+ /* Recalculate counters for child feeds */
+
+ $result = db_query($link, "SELECT id FROM ttrss_feeds
+ WHERE owner_uid = '$owner_uid' AND $cat_qpart");
+
+ while ($line = db_fetch_assoc($result)) {
+ ccache_update($link, $line["id"], $owner_uid, false, false);
+ }
+
+ $result = db_query($link, "SELECT SUM(value) AS sv
+ FROM ttrss_counters_cache, ttrss_feeds
+ WHERE id = feed_id AND $cat_qpart AND
+ ttrss_feeds.owner_uid = '$owner_uid'");
+
+ $unread = (int) db_fetch_result($result, 0, "sv");
+
+ } else {
+ $unread = (int) getFeedArticles($link, $feed_id, $is_cat, true, $owner_uid);
+ }
+
+ db_query($link, "BEGIN");
+
+ $result = db_query($link, "SELECT feed_id FROM $table
+ WHERE owner_uid = '$owner_uid' AND feed_id = '$feed_id' LIMIT 1");
+
+ if (db_num_rows($result) == 1) {
+ db_query($link, "UPDATE $table SET
+ value = '$unread', updated = NOW() WHERE
+ feed_id = '$feed_id' AND owner_uid = '$owner_uid'");
+
+ } else {
+ db_query($link, "INSERT INTO $table
+ (feed_id, value, owner_uid, updated)
+ VALUES
+ ($feed_id, $unread, $owner_uid, NOW())");
+ }
+
+ db_query($link, "COMMIT");
+
+ if ($feed_id > 0 && $prev_unread != $unread) {
+
+ if (!$is_cat) {
+
+ /* Update parent category */
+
+ if ($update_pcat) {
+
+ $result = db_query($link, "SELECT cat_id FROM ttrss_feeds
+ WHERE owner_uid = '$owner_uid' AND id = '$feed_id'");
+
+ $cat_id = (int) db_fetch_result($result, 0, "cat_id");
+
+ ccache_update($link, $cat_id, $owner_uid, true);
+
+ }
+ }
+ } else if ($feed_id < 0) {
+ ccache_update_all($link, $owner_uid);
+ }
+
+ return $unread;
+ }
+
+ /* function ccache_cleanup($link, $owner_uid) {
+
+ if (DB_TYPE == "pgsql") {
+ db_query($link, "DELETE FROM ttrss_counters_cache AS c1 WHERE
+ (SELECT count(*) FROM ttrss_counters_cache AS c2
+ WHERE c1.feed_id = c2.feed_id AND c2.owner_uid = c1.owner_uid) > 1
+ AND owner_uid = '$owner_uid'");
+
+ db_query($link, "DELETE FROM ttrss_cat_counters_cache AS c1 WHERE
+ (SELECT count(*) FROM ttrss_cat_counters_cache AS c2
+ WHERE c1.feed_id = c2.feed_id AND c2.owner_uid = c1.owner_uid) > 1
+ AND owner_uid = '$owner_uid'");
+ } else {
+ db_query($link, "DELETE c1 FROM
+ ttrss_counters_cache AS c1,
+ ttrss_counters_cache AS c2
+ WHERE
+ c1.owner_uid = '$owner_uid' AND
+ c1.owner_uid = c2.owner_uid AND
+ c1.feed_id = c2.feed_id");
+
+ db_query($link, "DELETE c1 FROM
+ ttrss_cat_counters_cache AS c1,
+ ttrss_cat_counters_cache AS c2
+ WHERE
+ c1.owner_uid = '$owner_uid' AND
+ c1.owner_uid = c2.owner_uid AND
+ c1.feed_id = c2.feed_id");
+
+ }
+ } */
+
+ function label_find_id($link, $label, $owner_uid) {
+ $result = db_query($link,
+ "SELECT id FROM ttrss_labels2 WHERE caption = '$label'
+ AND owner_uid = '$owner_uid' LIMIT 1");
+
+ if (db_num_rows($result) == 1) {
+ return db_fetch_result($result, 0, "id");
+ } else {
+ return 0;
+ }
+ }
+
+ function get_article_labels($link, $id) {
+ global $memcache;
+
+ $obj_id = md5("LABELS:$id:" . $_SESSION["uid"]);
+
+ $rv = array();
+
+ if ($memcache && $obj = $memcache->get($obj_id)) {
+ return $obj;
+ } else {
+
+ $result = db_query($link, "SELECT label_cache FROM
+ ttrss_user_entries WHERE ref_id = '$id' AND owner_uid = " .
+ $_SESSION["uid"]);
+
+ $label_cache = db_fetch_result($result, 0, "label_cache");
+
+ if ($label_cache) {
+
+ $label_cache = json_decode($label_cache, true);
+
+ if ($label_cache["no-labels"] == 1)
+ return $rv;
+ else
+ return $label_cache;
+ }
+
+ $result = db_query($link,
+ "SELECT DISTINCT label_id,caption,fg_color,bg_color
+ FROM ttrss_labels2, ttrss_user_labels2
+ WHERE id = label_id
+ AND article_id = '$id'
+ AND owner_uid = ".$_SESSION["uid"] . "
+ ORDER BY caption");
+
+ while ($line = db_fetch_assoc($result)) {
+ $rk = array($line["label_id"], $line["caption"], $line["fg_color"],
+ $line["bg_color"]);
+ array_push($rv, $rk);
+ }
+ if ($memcache) $memcache->add($obj_id, $rv, 0, 3600);
+
+ if (count($rv) > 0)
+ label_update_cache($link, $id, $rv);
+ else
+ label_update_cache($link, $id, array("no-labels" => 1));
+ }
+
+ return $rv;
+ }
+
+
+ function label_find_caption($link, $label, $owner_uid) {
+ $result = db_query($link,
+ "SELECT caption FROM ttrss_labels2 WHERE id = '$label'
+ AND owner_uid = '$owner_uid' LIMIT 1");
+
+ if (db_num_rows($result) == 1) {
+ return db_fetch_result($result, 0, "caption");
+ } else {
+ return "";
+ }
+ }
+
+ function label_update_cache($link, $id, $labels = false, $force = false) {
+
+ if ($force)
+ label_clear_cache($link, $id);
+
+ if (!$labels)
+ $labels = get_article_labels($link, $id);
+
+ $labels = db_escape_string(json_encode($labels));
+
+ db_query($link, "UPDATE ttrss_user_entries SET
+ label_cache = '$labels' WHERE ref_id = '$id'");
+
+ }
+
+ function label_clear_cache($link, $id) {
+
+ db_query($link, "UPDATE ttrss_user_entries SET
+ label_cache = '' WHERE ref_id = '$id'");
+
+ }
+
+ function label_remove_article($link, $id, $label, $owner_uid) {
+
+ $label_id = label_find_id($link, $label, $owner_uid);
+
+ if (!$label_id) return;
+
+ $result = db_query($link,
+ "DELETE FROM ttrss_user_labels2
+ WHERE
+ label_id = '$label_id' AND
+ article_id = '$id'");
+
+ label_clear_cache($link, $id);
+ }
+
+ function label_add_article($link, $id, $label, $owner_uid) {
+
+ global $memcache;
+
+ if ($memcache) {
+ $obj_id = md5("LABELS:$id:$owner_uid");
+ $memcache->delete($obj_id);
+ }
+
+ $label_id = label_find_id($link, $label, $owner_uid);
+
+ if (!$label_id) return;
+
+ $result = db_query($link,
+ "SELECT
+ article_id FROM ttrss_labels2, ttrss_user_labels2
+ WHERE
+ label_id = id AND
+ label_id = '$label_id' AND
+ article_id = '$id' AND owner_uid = '$owner_uid'
+ LIMIT 1");
+
+ if (db_num_rows($result) == 0) {
+ db_query($link, "INSERT INTO ttrss_user_labels2
+ (label_id, article_id) VALUES ('$label_id', '$id')");
+ }
+
+ label_clear_cache($link, $id);
+
+ }
+
+ function label_remove($link, $id, $owner_uid) {
+ global $memcache;
+
+ if (!$owner_uid) $owner_uid = $_SESSION["uid"];
+
+ if ($memcache) {
+ $obj_id = md5("LABELS:$id:$owner_uid");
+ $memcache->delete($obj_id);
+ }
+
+ db_query($link, "BEGIN");
+
+ $result = db_query($link, "SELECT caption FROM ttrss_labels2
+ WHERE id = '$id'");
+
+ $caption = db_fetch_result($result, 0, "caption");
+
+ $result = db_query($link, "DELETE FROM ttrss_labels2 WHERE id = '$id'
+ AND owner_uid = " . $owner_uid);
+
+ if (db_affected_rows($link, $result) != 0 && $caption) {
+
+ /* Remove access key for the label */
+
+ $ext_id = -11 - $id;
+
+ db_query($link, "DELETE FROM ttrss_access_keys WHERE
+ feed_id = '$ext_id' AND owner_uid = $owner_uid");
+
+ /* Disable filters that reference label being removed */
+
+ db_query($link, "UPDATE ttrss_filters SET
+ enabled = false WHERE action_param = '$caption'
+ AND action_id = 7
+ AND owner_uid = " . $owner_uid);
+
+ /* Remove cached data */
+
+ db_query($link, "UPDATE ttrss_user_entries SET label_cache = ''
+ WHERE label_cache LIKE '%$caption%' AND owner_uid = " . $owner_uid);
+
+ }
+
+ db_query($link, "COMMIT");
+ }
+
+ function label_create($link, $caption) {
+
+ db_query($link, "BEGIN");
+
+ $result = false;
+
+ $result = db_query($link, "SELECT id FROM ttrss_labels2
+ WHERE caption = '$caption' AND owner_uid = ". $_SESSION["uid"]);
+
+ if (db_num_rows($result) == 0) {
+ $result = db_query($link,
+ "INSERT INTO ttrss_labels2 (caption,owner_uid)
+ VALUES ('$caption', '".$_SESSION["uid"]."')");
+
+ $result = db_affected_rows($link, $result) != 0;
+ }
+
+ db_query($link, "COMMIT");
+
+ return $result;
+ }
+
+ function format_tags_string($tags, $id) {
+
+ $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);
+ }
+
+ $tag_str = "<a href=\"javascript:viewfeed('$tag_escaped')\">$tag</a>";
+
+ array_push($formatted_tags, $tag_str);
+
+ $tmp_tags_str = implode(", ", $formatted_tags);
+
+ if ($num_tags == $tag_limit || mb_strlen($tmp_tags_str) > 150) {
+ break;
+ }
+ }
+
+ $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) {
+
+ $labels_str = "";
+
+ foreach ($labels as $l) {
+ $labels_str .= sprintf("<span class='hlLabelRef'
+ style='color : %s; background-color : %s'>%s</span>",
+ $l[2], $l[3], $l[1]);
+ }
+
+ return $labels_str;
+
+ }
+
+ function format_article_note($id, $note) {
+
+ $str = "<div class='articleNote' onclick=\"editArticleNote($id)\">
+ <div class='noteEdit' onclick=\"editArticleNote($id)\">".
+ __('(edit note)')."</div>$note</div>";
+
+ 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 remove_feed($link, $id, $owner_uid) {
+
+ if ($id > 0) {
+
+ /* save starred articles in Archived feed */
+
+ db_query($link, "BEGIN");
+
+ /* prepare feed if necessary */
+
+ $result = db_query($link, "SELECT id FROM ttrss_archived_feeds
+ WHERE id = '$id'");
+
+ if (db_num_rows($result) == 0) {
+ db_query($link, "INSERT INTO ttrss_archived_feeds
+ (id, owner_uid, title, feed_url, site_url)
+ SELECT id, owner_uid, title, feed_url, site_url from ttrss_feeds
+ WHERE id = '$id'");
+ }
+
+ db_query($link, "UPDATE ttrss_user_entries SET feed_id = NULL,
+ orig_feed_id = '$id' WHERE feed_id = '$id' AND
+ marked = true AND owner_uid = $owner_uid");
+
+ /* Remove access key for the feed */
+
+ db_query($link, "DELETE FROM ttrss_access_keys WHERE
+ feed_id = '$id' AND owner_uid = $owner_uid");
+
+ /* remove the feed */
+
+ db_query($link, "DELETE FROM ttrss_feeds
+ WHERE id = '$id' AND owner_uid = $owner_uid");
+
+ db_query($link, "COMMIT");
+
+ if (file_exists(ICONS_DIR . "/$id.ico")) {
+ unlink(ICONS_DIR . "/$id.ico");
+ }
+
+ ccache_remove($link, $id, $owner_uid);
+
+ } else {
+ label_remove($link, -11-$id, $owner_uid);
+ ccache_remove($link, -11-$id, $owner_uid);
+ }
+ }
+
+ function add_feed_category($link, $feed_cat) {
+
+ if (!$feed_cat) return false;
+
+ db_query($link, "BEGIN");
+
+ $result = db_query($link,
+ "SELECT id FROM ttrss_feed_categories
+ WHERE title = '$feed_cat' AND owner_uid = ".$_SESSION["uid"]);
+
+ if (db_num_rows($result) == 0) {
+
+ $result = db_query($link,
+ "INSERT INTO ttrss_feed_categories (owner_uid,title)
+ VALUES ('".$_SESSION["uid"]."', '$feed_cat')");
+
+ db_query($link, "COMMIT");
+
+ return true;
+ }
+
+ return false;
+ }
+
+ function remove_feed_category($link, $id, $owner_uid) {
+
+ db_query($link, "DELETE FROM ttrss_feed_categories
+ WHERE id = '$id' AND owner_uid = $owner_uid");
+
+ ccache_remove($link, $id, $owner_uid, true);
+ }
+
+ function archive_article($link, $id, $owner_uid) {
+ db_query($link, "BEGIN");
+
+ $result = db_query($link, "SELECT feed_id FROM ttrss_user_entries
+ WHERE ref_id = '$id' AND owner_uid = $owner_uid");
+
+ if (db_num_rows($result) != 0) {
+
+ /* prepare the archived table */
+
+ $feed_id = (int) db_fetch_result($result, 0, "feed_id");
+
+ if ($feed_id) {
+ $result = db_query($link, "SELECT id FROM ttrss_archived_feeds
+ WHERE id = '$feed_id'");
+
+ if (db_num_rows($result) == 0) {
+ db_query($link, "INSERT INTO ttrss_archived_feeds
+ (id, owner_uid, title, feed_url, site_url)
+ SELECT id, owner_uid, title, feed_url, site_url from ttrss_feeds
+ WHERE id = '$feed_id'");
+ }
+
+ db_query($link, "UPDATE ttrss_user_entries
+ SET orig_feed_id = feed_id, feed_id = NULL
+ WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
+ }
+ }
+
+ db_query($link, "COMMIT");
+ }
+
+ function getArticleFeed($link, $id) {
+ $result = db_query($link, "SELECT feed_id FROM ttrss_user_entries
+ WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
+
+ if (db_num_rows($result) != 0) {
+ return db_fetch_result($result, 0, "feed_id");
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Fixes incomplete URLs by prepending "http://".
+ * Also replaces feed:// with http://, and
+ * prepends a trailing slash if the url is a domain name only.
+ *
+ * @param string $url Possibly incomplete URL
+ *
+ * @return string Fixed URL.
+ */
+ function fix_url($url) {
+ if (strpos($url, '://') === false) {
+ $url = 'http://' . $url;
+ } else if (substr($url, 0, 5) == 'feed:') {
+ $url = 'http:' . substr($url, 5);
+ }
+
+ //prepend slash if the URL has no slash in it
+ // "http://www.example" -> "http://www.example/"
+ if (strpos($url, '/', strpos($url, ':') + 3) === false) {
+ $url .= '/';
+ }
+
+ if ($url != "http:///")
+ return $url;
+ else
+ return '';
+ }
+
+ function validate_feed_url($url) {
+ $parts = parse_url($url);
+
+ return ($parts['scheme'] == 'http' || $parts['scheme'] == 'feed' || $parts['scheme'] == 'https');
+
+ }
+
+ function get_article_enclosures($link, $id) {
+
+ global $memcache;
+
+ $query = "SELECT * FROM ttrss_enclosures
+ WHERE post_id = '$id' AND content_url != ''";
+
+ $obj_id = md5("ENCLOSURES:$id");
+
+ $rv = array();
+
+ if ($memcache && $obj = $memcache->get($obj_id)) {
+ $rv = $obj;
+ } else {
+ $result = db_query($link, $query);
+
+ if (db_num_rows($result) > 0) {
+ while ($line = db_fetch_assoc($result)) {
+ array_push($rv, $line);
+ }
+ if ($memcache) $memcache->add($obj_id, $rv, 0, 3600);
+ }
+ }
+
+ return $rv;
+ }
+
+ function api_get_feeds($link, $cat_id, $unread_only, $limit, $offset) {
+
+ $feeds = array();
+
+ /* Labels */
+
+ if ($cat_id == -4 || $cat_id == -2) {
+ $counters = getLabelCounters($link, true);
+
+ foreach (array_values($counters) as $cv) {
+
+ $unread = $cv["counter"];
+
+ if ($unread || !$unread_only) {
+
+ $row = array(
+ "id" => $cv["id"],
+ "title" => $cv["description"],
+ "unread" => $cv["counter"],
+ "cat_id" => -2,
+ );
+
+ array_push($feeds, $row);
+ }
+ }
+ }
+
+ /* Virtual feeds */
+
+ if ($cat_id == -4 || $cat_id == -1) {
+ foreach (array(-1, -2, -3, -4, 0) as $i) {
+ $unread = getFeedUnread($link, $i);
+
+ if ($unread || !$unread_only) {
+ $title = getFeedTitle($link, $i);
+
+ $row = array(
+ "id" => $i,
+ "title" => $title,
+ "unread" => $unread,
+ "cat_id" => -1,
+ );
+ array_push($feeds, $row);
+ }
+
+ }
+ }
+
+ /* Real feeds */
+
+ if ($limit) {
+ $limit_qpart = "LIMIT $limit OFFSET $offset";
+ } else {
+ $limit_qpart = "";
+ }
+
+ if ($cat_id == -4 || $cat_id == -3) {
+ $result = db_query($link, "SELECT
+ id, feed_url, cat_id, title, ".
+ SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated
+ FROM ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"] .
+ " ORDER BY cat_id, title " . $limit_qpart);
+ } else {
+
+ if ($cat_id)
+ $cat_qpart = "cat_id = '$cat_id'";
+ else
+ $cat_qpart = "cat_id IS NULL";
+
+ $result = db_query($link, "SELECT
+ id, feed_url, cat_id, title, ".
+ SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated
+ FROM ttrss_feeds WHERE
+ $cat_qpart AND owner_uid = " . $_SESSION["uid"] .
+ " ORDER BY cat_id, title " . $limit_qpart);
+ }
+
+ while ($line = db_fetch_assoc($result)) {
+
+ $unread = getFeedUnread($link, $line["id"]);
+
+ $has_icon = feed_has_icon($line['id']);
+
+ if ($unread || !$unread_only) {
+
+ $row = array(
+ "feed_url" => $line["feed_url"],
+ "title" => $line["title"],
+ "id" => (int)$line["id"],
+ "unread" => (int)$unread,
+ "has_icon" => $has_icon,
+ "cat_id" => (int)$line["cat_id"],
+ "last_updated" => strtotime($line["last_updated"])
+ );
+
+ array_push($feeds, $row);
+ }
+ }
+
+ return $feeds;
+ }
+
+ function api_get_headlines($link, $feed_id, $limit, $offset,
+ $filter, $is_cat, $show_excerpt, $show_content, $view_mode, $order,
+ $include_attachments, $since_id) {
+
+ /* do not rely on params below */
+
+ $search = db_escape_string($_REQUEST["search"]);
+ $search_mode = db_escape_string($_REQUEST["search_mode"]);
+ $match_on = db_escape_string($_REQUEST["match_on"]);
+
+ $qfh_ret = queryFeedHeadlines($link, $feed_id, $limit,
+ $view_mode, $is_cat, $search, $search_mode, $match_on,
+ $order, $offset, 0, false, $since_id);
+
+ $result = $qfh_ret[0];
+ $feed_title = $qfh_ret[1];
+
+ $headlines = array();
+
+ while ($line = db_fetch_assoc($result)) {
+ $is_updated = ($line["last_read"] == "" &&
+ ($line["unread"] != "t" && $line["unread"] != "1"));
+
+ $tags = explode(",", $line["tag_cache"]);
+ $labels = json_decode($line["label_cache"], true);
+
+ //if (!$tags) $tags = get_article_tags($link, $line["id"]);
+ //if (!$labels) $labels = get_article_labels($link, $line["id"]);
+
+ $headline_row = array(
+ "id" => (int)$line["id"],
+ "unread" => sql_bool_to_bool($line["unread"]),
+ "marked" => sql_bool_to_bool($line["marked"]),
+ "published" => sql_bool_to_bool($line["published"]),
+ "updated" => strtotime($line["updated"]),
+ "is_updated" => $is_updated,
+ "title" => $line["title"],
+ "link" => $line["link"],
+ "feed_id" => $line["feed_id"],
+ "tags" => $tags,
+ );
+
+ if ($include_attachments)
+ $headline_row['attachments'] = get_article_enclosures($link,
+ $line['id']);
+
+ if ($show_excerpt) {
+ $excerpt = truncate_string(strip_tags($line["content_preview"]), 100);
+ $headline_row["excerpt"] = $excerpt;
+ }
+
+ if ($show_content) {
+ $headline_row["content"] = $line["content_preview"];
+ }
+
+ // unify label output to ease parsing
+ if ($labels["no-labels"] == 1) $labels = array();
+
+ $headline_row["labels"] = $labels;
+
+ array_push($headlines, $headline_row);
+ }
+
+ return $headlines;
+ }
+
+ function generate_error_feed($link, $error) {
+ $reply = array();
+
+ $reply['headlines']['id'] = -6;
+ $reply['headlines']['is_cat'] = false;
+
+ $reply['headlines']['toolbar'] = '';
+ $reply['headlines']['content'] = "<div class='whiteBox'>". $error . "</div>";
+
+ $reply['headlines-info'] = array("count" => 0,
+ "vgroup_last_feed" => '',
+ "unread" => 0,
+ "disable_cache" => true);
+
+ return $reply;
+ }
+
+
+ function generate_dashboard_feed($link) {
+ $reply = array();
+
+ $reply['headlines']['id'] = -5;
+ $reply['headlines']['is_cat'] = false;
+
+ $reply['headlines']['toolbar'] = '';
+ $reply['headlines']['content'] = "<div class='whiteBox'>".__('No feed selected.');
+
+ $reply['headlines']['content'] .= "<p class=\"small\"><span class=\"insensitive\">";
+
+ $result = db_query($link, "SELECT ".SUBSTRING_FOR_DATE."(MAX(last_updated), 1, 19) AS last_updated FROM ttrss_feeds
+ WHERE owner_uid = " . $_SESSION['uid']);
+
+ $last_updated = db_fetch_result($result, 0, "last_updated");
+ $last_updated = make_local_datetime($link, $last_updated, false);
+
+ $reply['headlines']['content'] .= sprintf(__("Feeds last updated at %s"), $last_updated);
+
+ $result = db_query($link, "SELECT COUNT(id) AS num_errors
+ FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ".$_SESSION["uid"]);
+
+ $num_errors = db_fetch_result($result, 0, "num_errors");
+
+ if ($num_errors > 0) {
+ $reply['headlines']['content'] .= "<br/>";
+ $reply['headlines']['content'] .= "<a class=\"insensitive\" href=\"#\" onclick=\"showFeedsWithErrors()\">".
+ __('Some feeds have update errors (click for details)')."</a>";
+ }
+ $reply['headlines']['content'] .= "</span></p>";
+
+ $reply['headlines-info'] = array("count" => 0,
+ "vgroup_last_feed" => '',
+ "unread" => 0,
+ "disable_cache" => true);
+
+ return $reply;
+ }
+
+ function save_email_address($link, $email) {
+ // FIXME: implement persistent storage of emails
+
+ if (!$_SESSION['stored_emails'])
+ $_SESSION['stored_emails'] = array();
+
+ if (!in_array($email, $_SESSION['stored_emails']))
+ array_push($_SESSION['stored_emails'], $email);
+ }
+
+ function update_feed_access_key($link, $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
+ WHERE feed_id = '$feed_id' AND is_cat = $sql_is_cat
+ AND owner_uid = " . $owner_uid);
+
+ if (db_num_rows($result) == 1) {
+ $key = db_escape_string(sha1(uniqid(rand(), true)));
+
+ db_query($link, "UPDATE ttrss_access_keys SET access_key = '$key'
+ WHERE feed_id = '$feed_id' AND is_cat = $sql_is_cat
+ AND owner_uid = " . $owner_uid);
+
+ return $key;
+
+ } else {
+ return get_feed_access_key($link, $feed_id, $is_cat, $owner_uid);
+ }
+ }
+
+ function get_feed_access_key($link, $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
+ WHERE feed_id = '$feed_id' AND is_cat = $sql_is_cat
+ AND owner_uid = " . $owner_uid);
+
+ if (db_num_rows($result) == 1) {
+ return db_fetch_result($result, 0, "access_key");
+ } else {
+ $key = db_escape_string(sha1(uniqid(rand(), true)));
+
+ $result = db_query($link, "INSERT INTO ttrss_access_keys
+ (access_key, feed_id, is_cat, owner_uid)
+ VALUES ('$key', '$feed_id', $sql_is_cat, '$owner_uid')");
+
+ return $key;
+ }
+ return false;
+ }
+
+ /**
+ * Extracts RSS/Atom feed URLs from the given HTML URL.
+ *
+ * @param string $url HTML page URL
+ *
+ * @return array Array of feeds. Key is the full URL, value the title
+ */
+ function get_feeds_from_html($url, $login = false, $pass = false)
+ {
+ $url = fix_url($url);
+ $baseUrl = substr($url, 0, strrpos($url, '/') + 1);
+
+ libxml_use_internal_errors(true);
+
+ $content = @fetch_file_contents($url, false, $login, $pass);
+
+ $doc = new DOMDocument();
+ $doc->loadHTML($content);
+ $xpath = new DOMXPath($doc);
+ $entries = $xpath->query('/html/head/link[@rel="alternate"]');
+ $feedUrls = array();
+ foreach ($entries as $entry) {
+ if ($entry->hasAttribute('href')) {
+ $title = $entry->getAttribute('title');
+ if ($title == '') {
+ $title = $entry->getAttribute('type');
+ }
+ $feedUrl = rewrite_relative_url(
+ $baseUrl, $entry->getAttribute('href')
+ );
+ $feedUrls[$feedUrl] = $title;
+ }
+ }
+ return $feedUrls;
+ }
+
+ /**
+ * Checks if the content behind the given URL is a HTML file
+ *
+ * @param string $url URL to check
+ *
+ * @return boolean True if the URL contains HTML content
+ */
+ function url_is_html($url, $login = false, $pass = false) {
+ $content = substr(fetch_file_contents($url, false, $login, $pass), 0, 1000);
+
+ if (stripos($content, '<html>') === false
+ && stripos($content, '<html ') === false
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ function print_label_select($link, $name, $value, $attributes = "") {
+
+ $result = db_query($link, "SELECT caption FROM ttrss_labels2
+ WHERE owner_uid = '".$_SESSION["uid"]."' ORDER BY caption");
+
+ print "<select default=\"$value\" name=\"" . htmlspecialchars($name) .
+ "\" $attributes onchange=\"labelSelectOnChange(this)\" >";
+
+ while ($line = db_fetch_assoc($result)) {
+
+ $issel = ($line["caption"] == $value) ? "selected=\"1\"" : "";
+
+ print "<option value=\"".htmlspecialchars($line["caption"])."\"
+ $issel>" . htmlspecialchars($line["caption"]) . "</option>";
+
+ }
+
+# print "<option value=\"ADD_LABEL\">" .__("Add label...") . "</option>";
+
+ print "</select>";
+
+
+ }
+
+ function format_article_enclosures($link, $id, $always_display_enclosures,
+ $article_content) {
+
+ $result = get_article_enclosures($link, $id);
+ $rv = '';
+
+ if (count($result) > 0) {
+
+ $entries_html = array();
+ $entries = array();
+
+ foreach ($result as $line) {
+
+ $url = $line["content_url"];
+ $ctype = $line["content_type"];
+
+ if (!$ctype) $ctype = __("unknown type");
+
+# $filename = substr($url, strrpos($url, "/")+1);
+
+ $entry = format_inline_player($link, $url, $ctype);
+
+# $entry .= " <a target=\"_blank\" href=\"" . htmlspecialchars($url) . "\">" .
+# $filename . " (" . $ctype . ")" . "</a>";
+
+ array_push($entries_html, $entry);
+
+ $entry = array();
+
+ $entry["type"] = $ctype;
+ $entry["filename"] = $filename;
+ $entry["url"] = $url;
+
+ array_push($entries, $entry);
+ }
+
+ $rv .= "<div class=\"postEnclosures\">";
+
+ if (!get_pref($link, "STRIP_IMAGES")) {
+ if ($always_display_enclosures ||
+ !preg_match("/<img/i", $article_content)) {
+
+ foreach ($entries as $entry) {
+
+ 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 (count($entries) == 1) {
+ $rv .= __("Attachment:") . " ";
+ } else {
+ $rv .= __("Attachments:") . " ";
+ }
+
+ $rv .= join(", ", $entries_html);
+
+ $rv .= "</div>";
+ }
+
+ return $rv;
+ }
+
+ function getLastArticleId($link) {
+ $result = db_query($link, "SELECT MAX(ref_id) AS id FROM ttrss_user_entries
+ WHERE owner_uid = " . $_SESSION["uid"]);
+
+ if (db_num_rows($result) == 1) {
+ return db_fetch_result($result, 0, "id");
+ } else {
+ return -1;
+ }
+ }
+
+ function build_url($parts) {
+ return $parts['scheme'] . "://" . $parts['host'] . $parts['path'];
+ }
+
+ /**
+ * Converts a (possibly) relative URL to a absolute one.
+ *
+ * @param string $url Base URL (i.e. from where the document is)
+ * @param string $rel_url Possibly relative URL in the document
+ *
+ * @return string Absolute URL
+ */
+ function rewrite_relative_url($url, $rel_url) {
+ if (strpos($rel_url, "://") !== false) {
+ return $rel_url;
+ } else if (strpos($rel_url, "/") === 0)
+ {
+ $parts = parse_url($url);
+ $parts['path'] = $rel_url;
+
+ return build_url($parts);
+
+ } else {
+ $parts = parse_url($url);
+ if (!isset($parts['path'])) {
+ $parts['path'] = '/';
+ }
+ $dir = $parts['path'];
+ if (substr($dir, -1) !== '/') {
+ $dir = dirname($parts['path']);
+ $dir !== '/' && $dir .= '/';
+ }
+ $parts['path'] = $dir . $rel_url;
+
+ return build_url($parts);
+ }
+ }
+
+ function sphinx_search($query, $offset = 0, $limit = 30) {
+ require_once 'lib/sphinxapi.php';
+
+ $sphinxClient = new SphinxClient();
+
+ $sphinxClient->SetServer('localhost', 9312);
+ $sphinxClient->SetConnectTimeout(1);
+
+ $sphinxClient->SetFieldWeights(array('title' => 70, 'content' => 30,
+ 'feed_title' => 20));
+
+ $sphinxClient->SetMatchMode(SPH_MATCH_EXTENDED2);
+ $sphinxClient->SetRankingMode(SPH_RANK_PROXIMITY_BM25);
+ $sphinxClient->SetLimits($offset, $limit, 1000);
+ $sphinxClient->SetArrayResult(false);
+ $sphinxClient->SetFilter('owner_uid', array($_SESSION['uid']));
+
+ $result = $sphinxClient->Query($query, SPHINX_INDEX);
+
+ $ids = array();
+
+ if (is_array($result['matches'])) {
+ foreach (array_keys($result['matches']) as $int_id) {
+ $ref_id = $result['matches'][$int_id]['attrs']['ref_id'];
+ array_push($ids, $ref_id);
+ }
+ }
+
+ return $ids;
+ }
+
+ function cleanup_tags($link, $days = 14, $limit = 1000) {
+
+ if (DB_TYPE == "pgsql") {
+ $interval_query = "date_updated < NOW() - INTERVAL '$days days'";
+ } else if (DB_TYPE == "mysql") {
+ $interval_query = "date_updated < DATE_SUB(NOW(), INTERVAL $days DAY)";
+ }
+
+ $tags_deleted = 0;
+
+ while ($limit > 0) {
+ $limit_part = 500;
+
+ $query = "SELECT ttrss_tags.id AS id
+ FROM ttrss_tags, ttrss_user_entries, ttrss_entries
+ 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);
+
+ $ids = array();
+
+ while ($line = db_fetch_assoc($result)) {
+ array_push($ids, $line['id']);
+ }
+
+ 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);
+ } else {
+ break;
+ }
+
+ $limit -= $limit_part;
+ }
+
+ print "\n";
+
+ return $tags_deleted;
+ }
+
+ function feedlist_init_cat($link, $cat_id, $hidden = false) {
+ $obj = array();
+ $cat_id = (int) $cat_id;
+
+ if ($cat_id > 0) {
+ $cat_unread = ccache_find($link, $cat_id, $_SESSION["uid"], true);
+ } else if ($cat_id == 0 || $cat_id == -2) {
+ $cat_unread = getCategoryUnread($link, $cat_id);
+ }
+
+ $obj['id'] = 'CAT:' . $cat_id;
+ $obj['items'] = array();
+ $obj['name'] = getCategoryTitle($link, $cat_id);
+ $obj['type'] = 'feed';
+ $obj['unread'] = (int) $cat_unread;
+ $obj['hidden'] = $hidden;
+ $obj['bare_id'] = $cat_id;
+
+ return $obj;
+ }
+
+ function feedlist_init_feed($link, $feed_id, $title = false, $unread = false, $error = '', $updated = '') {
+ $obj = array();
+ $feed_id = (int) $feed_id;
+
+ if (!$title)
+ $title = getFeedTitle($link, $feed_id, false);
+
+ if ($unread === false)
+ $unread = getFeedUnread($link, $feed_id, false);
+
+ $obj['id'] = 'FEED:' . $feed_id;
+ $obj['name'] = $title;
+ $obj['unread'] = (int) $unread;
+ $obj['type'] = 'feed';
+ $obj['error'] = $error;
+ $obj['updated'] = $updated;
+ $obj['icon'] = getFeedIcon($feed_id);
+ $obj['bare_id'] = $feed_id;
+
+ return $obj;
+ }
+
+
+ function fetch_twitter_rss($link, $url, $owner_uid) {
+
+ require_once 'lib/tmhoauth/tmhOAuth.php';
+
+ $result = db_query($link, "SELECT twitter_oauth FROM ttrss_users
+ WHERE id = $owner_uid");
+
+ $access_token = json_decode(db_fetch_result($result, 0, 'twitter_oauth'), true);
+ $url_escaped = db_escape_string($url);
+
+ if ($access_token) {
+
+ $tmhOAuth = new tmhOAuth(array(
+ 'consumer_key' => CONSUMER_KEY,
+ 'consumer_secret' => CONSUMER_SECRET,
+ 'user_token' => $access_token['oauth_token'],
+ 'user_secret' => $access_token['oauth_token_secret'],
+ ));
+
+ $code = $tmhOAuth->request('GET', $url);
+
+ if ($code == 200) {
+
+ $content = $tmhOAuth->response['response'];
+
+ define('MAGPIE_CACHE_ON', false);
+
+ $rss = new MagpieRSS($content, MAGPIE_OUTPUT_ENCODING,
+ MAGPIE_INPUT_ENCODING, MAGPIE_DETECT_ENCODING );
+
+ return $rss;
+
+ } else {
+
+ db_query($link, "UPDATE ttrss_feeds
+ SET last_error = 'OAuth authorization failed ($code).'
+ WHERE feed_url = '$url_escaped' AND owner_uid = $owner_uid");
+ }
+
+ } else {
+
+ db_query($link, "UPDATE ttrss_feeds
+ SET last_error = 'OAuth information not found.'
+ WHERE feed_url = '$url_escaped' AND owner_uid = $owner_uid");
+
+ return false;
+ }
+ }
+
+ function print_user_stylesheet($link) {
+ $value = get_pref($link, 'USER_STYLESHEET');
+
+ if ($value) {
+ print "<style type=\"text/css\">";
+ print str_replace("<br/>", "\n", $value);
+ print "</style>";
+ }
+
+ }
+
+ function rewrite_urls($line) {
+ global $url_regex;
+
+ $urls = null;
+
+ $result = preg_replace("/((?<!=.)((http|https|ftp)+):\/\/[^ ,!]+)/i",
+ "<a target=\"_blank\" href=\"\\1\">\\1</a>", $line);
+
+ return $result;
+ }
+
+ function filter_to_sql($filter) {
+ $query = "";
+
+ if (DB_TYPE == "pgsql")
+ $reg_qpart = "~";
+ else
+ $reg_qpart = "REGEXP";
+
+ switch ($filter["type"]) {
+ case "title":
+ $query = "LOWER(ttrss_entries.title) $reg_qpart LOWER('".
+ $filter['reg_exp'] . "')";
+ break;
+ case "content":
+ $query = "LOWER(ttrss_entries.content) $reg_qpart LOWER('".
+ $filter['reg_exp'] . "')";
+ break;
+ case "both":
+ $query = "LOWER(ttrss_entries.title) $reg_qpart LOWER('".
+ $filter['reg_exp'] . "') OR LOWER(" .
+ "ttrss_entries.content) $reg_qpart LOWER('" . $filter['reg_exp'] . "')";
+ break;
+ case "tag":
+ $query = "LOWER(ttrss_user_entries.tag_cache) $reg_qpart LOWER('".
+ $filter['reg_exp'] . "')";
+ break;
+ case "link":
+ $query = "LOWER(ttrss_entries.link) $reg_qpart LOWER('".
+ $filter['reg_exp'] . "')";
+ break;
+ case "date":
+
+ if ($filter["filter_param"] == "before")
+ $cmp_qpart = "<";
+ else
+ $cmp_qpart = ">=";
+
+ $timestamp = date("Y-m-d H:N:s", strtotime($filter["reg_exp"]));
+ $query = "ttrss_entries.date_entered $cmp_qpart '$timestamp'";
+ break;
+ case "author":
+ $query = "LOWER(ttrss_entries.author) $reg_qpart LOWER('".
+ $filter['reg_exp'] . "')";
+ break;
+ }
+
+ if ($filter["inverse"])
+ $query = "NOT ($query)";
+
+ if ($query) {
+ if (DB_TYPE == "pgsql") {
+ $query = " ($query) AND ttrss_entries.date_entered > NOW() - INTERVAL '14 days'";
+ } else {
+ $query = " ($query) AND ttrss_entries.date_entered > DATE_SUB(NOW(), INTERVAL 14 DAY)";
+ }
+ $query .= " AND ";
+ }
+
+
+ return $query;
+ }
+
+ // Status codes:
+ // -1 - never connected
+ // 0 - no data received
+ // 1 - data received successfully
+ // 2 - did not receive valid data
+ // >10 - server error, code + 10 (e.g. 16 means server error 6)
+
+ function get_linked_feeds($link, $instance_id = false) {
+ if ($instance_id)
+ $instance_qpart = "id = '$instance_id' AND ";
+ else
+ $instance_qpart = "";
+
+ if (DB_TYPE == "pgsql") {
+ $date_qpart = "last_connected < NOW() - INTERVAL '6 hours'";
+ } else {
+ $date_qpart = "last_connected < DATE_SUB(NOW(), INTERVAL 6 HOUR)";
+ }
+
+ $result = db_query($link, "SELECT id, access_key, access_url FROM ttrss_linked_instances
+ WHERE $instance_qpart $date_qpart ORDER BY last_connected");
+
+ while ($line = db_fetch_assoc($result)) {
+ $id = $line['id'];
+
+ _debug("Updating: " . $line['access_url'] . " ($id)");
+
+ $fetch_url = $line['access_url'] . '/public.php?op=fbexport';
+ $post_query = 'key=' . $line['access_key'];
+
+ $feeds = fetch_file_contents($fetch_url, false, false, false, $post_query);
+
+ // try doing it the old way
+ if (!$feeds) {
+ $fetch_url = $line['access_url'] . '/backend.php?op=fbexport';
+ $feeds = fetch_file_contents($fetch_url, false, false, false, $post_query);
+ }
+
+ if ($feeds) {
+ $feeds = json_decode($feeds, true);
+
+ if ($feeds) {
+ if ($feeds['error']) {
+ $status = $feeds['error']['code'] + 10;
+ } else {
+ $status = 1;
+
+ if (count($feeds['feeds']) > 0) {
+
+ db_query($link, "DELETE FROM ttrss_linked_feeds
+ WHERE instance_id = '$id'");
+
+ foreach ($feeds['feeds'] as $feed) {
+ $feed_url = db_escape_string($feed['feed_url']);
+ $title = db_escape_string($feed['title']);
+ $subscribers = db_escape_string($feed['subscribers']);
+ $site_url = db_escape_string($feed['site_url']);
+
+ db_query($link, "INSERT INTO ttrss_linked_feeds
+ (feed_url, site_url, title, subscribers, instance_id, created, updated)
+ VALUES
+ ('$feed_url', '$site_url', '$title', '$subscribers', '$id', NOW(), NOW())");
+ }
+ } else {
+ // received 0 feeds, this might indicate that
+ // the instance on the other hand is rebuilding feedbrowser cache
+ // we will try again later
+
+ // TODO: maybe perform expiration based on updated here?
+ }
+
+ _debug("Processed " . count($feeds['feeds']) . " feeds.");
+ }
+ } else {
+ $status = 2;
+ }
+
+ } else {
+ $status = 0;
+ }
+
+ _debug("Status: $status");
+
+ db_query($link, "UPDATE ttrss_linked_instances SET
+ last_status_out = '$status', last_connected = NOW() WHERE id = '$id'");
+
+ }
+ }
+
+ function handle_public_request($link, $op) {
+ switch ($op) {
+
+ case "getUnread":
+ $login = db_escape_string($_REQUEST["login"]);
+ $fresh = $_REQUEST["fresh"] == "1";
+
+ $result = db_query($link, "SELECT id FROM ttrss_users WHERE login = '$login'");
+
+ if (db_num_rows($result) == 1) {
+ $uid = db_fetch_result($result, 0, "id");
+
+ print getGlobalUnread($link, $uid);
+
+ if ($fresh) {
+ print ";";
+ print getFeedArticles($link, -3, false, true, $uid);
+ }
+
+ } else {
+ print "-1;User not found";
+ }
+
+ break; // getUnread
+
+ case "getProfiles":
+ $login = db_escape_string($_REQUEST["login"]);
+ $password = db_escape_string($_REQUEST["password"]);
+
+ if (authenticate_user($link, $login, $password)) {
+ $result = db_query($link, "SELECT * FROM ttrss_settings_profiles
+ WHERE owner_uid = " . $_SESSION["uid"] . " ORDER BY title");
+
+ print "<select style='width: 100%' name='profile'>";
+
+ print "<option value='0'>" . __("Default profile") . "</option>";
+
+ while ($line = db_fetch_assoc($result)) {
+ $id = $line["id"];
+ $title = $line["title"];
+
+ print "<option value='$id'>$title</option>";
+ }
+
+ print "</select>";
+
+ $_SESSION = array();
+ }
+ break; // getprofiles
+
+ case "pubsub":
+ $mode = db_escape_string($_REQUEST['hub_mode']);
+ $feed_id = (int) db_escape_string($_REQUEST['id']);
+ $feed_url = db_escape_string($_REQUEST['hub_topic']);
+
+ if (!PUBSUBHUBBUB_ENABLED) {
+ header('HTTP/1.0 404 Not Found');
+ echo "404 Not found";
+ return;
+ }
+
+ // TODO: implement hub_verifytoken checking
+
+ $result = db_query($link, "SELECT feed_url FROM ttrss_feeds
+ WHERE id = '$feed_id'");
+
+ if (db_num_rows($result) != 0) {
+
+ $check_feed_url = db_fetch_result($result, 0, "feed_url");
+
+ if ($check_feed_url && ($check_feed_url == $feed_url || !$feed_url)) {
+ if ($mode == "subscribe") {
+
+ db_query($link, "UPDATE ttrss_feeds SET pubsub_state = 2
+ WHERE id = '$feed_id'");
+
+ print $_REQUEST['hub_challenge'];
+ return;
+
+ } else if ($mode == "unsubscribe") {
+
+ db_query($link, "UPDATE ttrss_feeds SET pubsub_state = 0
+ WHERE id = '$feed_id'");
+
+ print $_REQUEST['hub_challenge'];
+ return;
+
+ } else if (!$mode) {
+
+ // Received update ping, schedule feed update.
+ //update_rss_feed($link, $feed_id, true, true);
+
+ db_query($link, "UPDATE ttrss_feeds SET
+ last_update_started = '1970-01-01',
+ last_updated = '1970-01-01' WHERE id = '$feed_id'");
+
+ }
+ } else {
+ header('HTTP/1.0 404 Not Found');
+ echo "404 Not found";
+ }
+ } else {
+ header('HTTP/1.0 404 Not Found');
+ echo "404 Not found";
+ }
+
+ break; // pubsub
+
+ case "logout":
+ logout_user();
+ header("Location: index.php");
+ break; // logout
+
+ case "fbexport":
+
+ $access_key = db_escape_string($_POST["key"]);
+
+ // TODO: rate limit checking using last_connected
+ $result = db_query($link, "SELECT id FROM ttrss_linked_instances
+ WHERE access_key = '$access_key'");
+
+ if (db_num_rows($result) == 1) {
+
+ $instance_id = db_fetch_result($result, 0, "id");
+
+ $result = db_query($link, "SELECT feed_url, site_url, title, subscribers
+ FROM ttrss_feedbrowser_cache ORDER BY subscribers DESC LIMIT 100");
+
+ $feeds = array();
+
+ while ($line = db_fetch_assoc($result)) {
+ array_push($feeds, $line);
+ }
+
+ db_query($link, "UPDATE ttrss_linked_instances SET
+ last_status_in = 1 WHERE id = '$instance_id'");
+
+ print json_encode(array("feeds" => $feeds));
+ } else {
+ print json_encode(array("error" => array("code" => 6)));
+ }
+ break; // fbexport
+
+ case "share":
+ $uuid = db_escape_string($_REQUEST["key"]);
+
+ $result = db_query($link, "SELECT ref_id, owner_uid FROM ttrss_user_entries WHERE
+ uuid = '$uuid'");
+
+ if (db_num_rows($result) != 0) {
+ header("Content-Type: text/html");
+
+ $id = db_fetch_result($result, 0, "ref_id");
+ $owner_uid = db_fetch_result($result, 0, "owner_uid");
+
+ $_SESSION["uid"] = $owner_uid;
+ $article = format_article($link, $id, false, true);
+ $_SESSION["uid"] = "";
+
+ print_r($article['content']);
+
+ } else {
+ print "Article not found.";
+ }
+
+ break;
+
+ case "rss":
+ $feed = db_escape_string($_REQUEST["id"]);
+ $key = db_escape_string($_REQUEST["key"]);
+ $is_cat = $_REQUEST["is_cat"] != false;
+ $limit = (int)db_escape_string($_REQUEST["limit"]);
+
+ $search = db_escape_string($_REQUEST["q"]);
+ $match_on = db_escape_string($_REQUEST["m"]);
+ $search_mode = db_escape_string($_REQUEST["smode"]);
+ $view_mode = db_escape_string($_REQUEST["view-mode"]);
+
+ if (SINGLE_USER_MODE) {
+ authenticate_user($link, "admin", null);
+ }
+
+ $owner_id = false;
+
+ if ($key) {
+ $result = db_query($link, "SELECT owner_uid FROM
+ ttrss_access_keys WHERE access_key = '$key' AND feed_id = '$feed'");
+
+ if (db_num_rows($result) == 1)
+ $owner_id = db_fetch_result($result, 0, "owner_uid");
+ }
+
+ if ($owner_id) {
+ $_SESSION['uid'] = $owner_id;
+
+ generate_syndicated_feed($link, 0, $feed, $is_cat, $limit,
+ $search, $search_mode, $match_on, $view_mode);
+ } else {
+ header('HTTP/1.1 403 Forbidden');
+ }
+ break; // rss
+
+
+ case "globalUpdateFeeds":
+ // Update all feeds needing a update.
+ update_daemon_common($link, 0, true, true);
+ break; // globalUpdateFeeds
+
+
+ default:
+ header("Content-Type: text/plain");
+ print json_encode(array("error" => array("code" => 7)));
+ break; // fallback
+
+ }
+ }
+?>
--- /dev/null
+<?php # This file has been generated at: Wed Nov 23 10:40:20 MSK 2011
+
+__("Title");
+__("Title or Content");
+__("Link");
+__("Content");
+__("Article Date");
+
+__("Delete article");
+__("Mark as read");
+__("Set starred");
+__("Publish article");
+__("Assign tags");
+__("Assign label");
+
+__('This option is useful when you are reading several planet-type aggregators with partially colliding userbase. When disabled, it forces same posts from different feeds to appear only once.');
+__('Display expanded list of feed articles, instead of separate displays for headlines and article content');
+__('When "Mark as read" button is clicked in toolbar, automatically open next feed with unread articles.');
+__('This option enables sending daily digest of new (and unread) headlines on your configured e-mail address');
+__('This option enables marking articles as read automatically while you scroll article list.');
+__('Strip all but most common HTML tags when reading articles.');
+__('When auto-detecting tags in articles these tags will not be applied (comma-separated list).');
+__('When this option is enabled, headlines in Special feeds and Labels are grouped by feeds');
+__('Use feed-specified date to sort headlines instead of local import date.');
+__('Customize CSS stylesheet to your liking');
+__('Click to register your SSL client certificate with tt-rss');
+__('Purge old posts after this number of days (0 - disables)');
+__('Default interval between feed updates');
+__('Amount of articles to display at once');
+__('Allow duplicate posts');
+__('Enable feed categories');
+__('Show content preview in headlines list');
+__('Short date format');
+__('Long date format');
+__('Combined feed display');
+__('Hide feeds with no unread messages');
+__('On catchup show next feed');
+__('Sort feeds by unread articles count');
+__('Reverse headline order (oldest first)');
+__('Enable e-mail digest');
+__('Confirm marking feed as read');
+__('Automatically mark articles as read');
+__('Strip unsafe tags from articles');
+__('Blacklisted tags');
+__('Maximum age of fresh articles (in hours)');
+__('Mark articles in e-mail digest as read');
+__('Automatically expand articles in combined mode');
+__('Purge unread articles');
+__('Show special feeds when hiding read feeds');
+__('Group headlines in virtual feeds');
+__('Do not show images in articles');
+__('Enable external API');
+__('User timezone');
+__('Sort headlines by feed date');
+__('Customize stylesheet');
+__('Login with an SSL certificate');
+?>
--- /dev/null
+<html>
+<head>
+ <title>Tiny Tiny RSS : Login</title>
+ <link rel="stylesheet" type="text/css" href="lib/dijit/themes/claro/claro.css"/>
+ <link rel="stylesheet" type="text/css" href="tt-rss.css">
+ <link rel="shortcut icon" type="image/png" href="images/favicon.png">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <script type="text/javascript" src="lib/dojo/dojo.js" djConfig="parseOnLoad: true"></script>
+ <script type="text/javascript" src="lib/prototype.js"></script>
+ <script type="text/javascript" src="lib/scriptaculous/scriptaculous.js?load=effects,dragdrop,controls"></script>
+ <script type="text/javascript" src="functions.js"></script>
+ <script type="text/javascript" charset="utf-8" src="errors.php?mode=js"></script>
+</head>
+
+<body id="ttrssLogin" class="claro">
+
+<script type="text/javascript">
+function init() {
+
+ dojo.require("dijit.Dialog");
+
+ var test = setCookie("ttrss_test", "TEST");
+
+ if (getCookie("ttrss_test") != "TEST") {
+ return fatalError(2);
+ }
+
+ var limit_set = getCookie("ttrss_bwlimit");
+
+ if (limit_set == "true") {
+ document.forms["loginForm"].bw_limit.checked = true;
+ }
+
+ document.forms["loginForm"].login.focus();
+}
+
+function fetchProfiles() {
+ try {
+ var params = Form.serialize('loginForm');
+ var query = "?op=getProfiles&" + params;
+
+ if (query) {
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ if (transport.responseText.match("select")) {
+ $('profile_box').innerHTML = transport.responseText;
+ }
+ } });
+ }
+
+ } catch (e) {
+ exception_error("fetchProfiles", e);
+ }
+}
+
+
+function languageChange(elem) {
+ try {
+ document.forms['loginForm']['click'].disabled = true;
+
+ var lang = elem[elem.selectedIndex].value;
+ setCookie("ttrss_lang", lang, <?php print SESSION_COOKIE_LIFETIME ?>);
+ window.location.reload();
+ } catch (e) {
+ exception_error("languageChange", e);
+ }
+}
+
+function gotoRegForm() {
+ window.location.href = "register.php";
+ return false;
+}
+
+function bwLimitChange(elem) {
+ try {
+ var limit_set = elem.checked;
+
+ setCookie("ttrss_bwlimit", limit_set,
+ <?php print SESSION_COOKIE_LIFETIME ?>);
+
+ } catch (e) {
+ exception_error("bwLimitChange", e);
+ }
+}
+
+function validateLoginForm(f) {
+ try {
+
+ if (f.login.value.length == 0) {
+ new Effect.Highlight(f.login);
+ return false;
+ }
+
+ if (f.password.value.length == 0) {
+ new Effect.Highlight(f.password);
+ return false;
+ }
+
+ document.forms['loginForm']['click'].disabled = true;
+
+ return true;
+ } catch (e) {
+ exception_error("validateLoginForm", e);
+ return true;
+ }
+}
+</script>
+
+<script type="text/javascript">
+ Event.observe(window, 'load', function() {
+ init();
+ });
+</script>
+
+<form action="" method="POST" id="loginForm" name="loginForm" onsubmit="return validateLoginForm(this)">
+<input type="hidden" name="login_action" value="do_login">
+
+<table class="loginForm2">
+<tr>
+ <td class="loginTop" valign="bottom" align="left">
+ <img src="images/logo_wide.png">
+ </td>
+</tr><tr>
+ <td align="center" valign="middle" class="loginMiddle" height="100%">
+ <?php if ($_SESSION['login_error_msg']) { ?>
+ <div class="loginError"><?php echo $_SESSION['login_error_msg'] ?></div>
+ <?php $_SESSION['login_error_msg'] = ""; ?>
+ <?php } ?>
+ <table>
+ <tr><td align="right"><?php echo __("Login:") ?></td>
+ <td align="right"><input name="login"
+ onchange="fetchProfiles()" onfocus="fetchProfiles()"
+ value="<?php echo get_remote_user($link) ?>"></td></tr>
+ <tr><td align="right"><?php echo __("Password:") ?></td>
+ <td align="right"><input type="password" name="password"
+ onchange="fetchProfiles()" onfocus="fetchProfiles()"
+ value="<?php echo get_remote_fakepass($link) ?>"></td></tr>
+ <tr><td align="right"><?php echo __("Language:") ?></td>
+ <td align="right">
+ <?php
+ print_select_hash("language", $_COOKIE["ttrss_lang"], get_translations(),
+ "style='width : 100%' onchange='languageChange(this)'");
+
+ ?>
+ </td></tr>
+
+ <tr><td align="right"><?php echo __("Profile:") ?></td>
+ <td align="right" id="profile_box">
+ <select style='width : 100%' disabled='disabled'>
+ <option><?php echo __("Default profile") ?></option></select>
+ </td></tr>
+
+ <!-- <tr><td colspan="2">
+ <input type="checkbox" name="remember_me" id="remember_me">
+ <label for="remember_me">Remember me on this computer</label>
+ </td></tr> -->
+
+ <tr><td colspan="2" align="right" class="innerLoginCell">
+
+ <button type="submit" name='click'><?php echo __('Log in') ?></button>
+ <?php if (defined('ENABLE_REGISTRATION') && ENABLE_REGISTRATION) { ?>
+ <button onclick="return gotoRegForm()">
+ <?php echo __("Create new account") ?></button>
+ <?php } ?>
+
+ <input type="hidden" name="action" value="login">
+ <input type="hidden" name="rt"
+ value="<?php if ($return_to != 'none') { echo $return_to; } ?>">
+ </td></tr>
+
+ <tr><td colspan="2" align="right" class="innerLoginCell">
+
+ <div class="small">
+ <input name="bw_limit" id="bw_limit" type="checkbox"
+ onchange="bwLimitChange(this)">
+ <label for="bw_limit">
+ <?php echo __("Use less traffic") ?></label></div>
+
+ </td></tr>
+
+
+ </table>
+ </td>
+</tr><tr>
+ <td align="center" class="loginBottom">
+ <a href="http://tt-rss.org/">Tiny Tiny RSS</a>
+ <?php if (!defined('HIDE_VERSION')) { ?>
+ v<?php echo VERSION ?>
+ <?php } ?>
+ © 2005–<?php echo date('Y') ?> <a href="http://fakecake.org/">Andrew Dolgov</a>
+ </td>
+</tr>
+
+</table>
+
+</form>
+
+</body></html>
--- /dev/null
+<?php
+ require_once "functions.php";
+
+ define('EXPECTED_CONFIG_VERSION', 23);
+ define('SCHEMA_VERSION', 86);
+
+ if (!file_exists("config.php")) {
+ print "<b>Fatal Error</b>: You forgot to copy
+ <b>config.php-dist</b> to <b>config.php</b> and edit it.\n";
+ exit;
+ }
+
+ require_once "config.php";
+ require_once "sanity_config.php";
+
+ if (CONFIG_VERSION != EXPECTED_CONFIG_VERSION) {
+ $err_msg = "config: your config file version is incorrect. See config.php-dist.\n";
+ }
+
+ $purifier_cache_dir = CACHE_DIR . "/htmlpurifier";
+
+ if (!is_writable($purifier_cache_dir)) {
+ $err_msg = "config: HTMLPurifier cache directory should be writable by anyone (chmod -R 777 $purifier_cache_dir)";
+ }
+
+ if (GENERATED_CONFIG_CHECK != EXPECTED_CONFIG_VERSION) {
+ $err_msg = "config: your sanity_config.php is outdated, please recreate it using ./utils/regen_config_checks.sh";
+ }
+
+ foreach ($requred_defines as $d) {
+ if (!defined($d)) {
+ $err_msg = "config: required constant $d is not defined. Please check config.php";
+ }
+ }
+
+ if (defined('RSS_BACKEND_TYPE')) {
+ print "<b>Fatal error</b>: RSS_BACKEND_TYPE is deprecated. Please remove this
+ option from config.php\n";
+ exit;
+ }
+
+ if (file_exists("xml-export.php") || file_exists("xml-import.php")) {
+ print "<b>Fatal Error</b>: XML Import/Export tools (<b>xml-export.php</b>
+ and <b>xml-import.php</b>) could be used maliciously. Please remove them
+ from your TT-RSS instance.\n";
+ exit;
+ }
+
+ if (SINGLE_USER_MODE && DAEMON_UPDATE_LOGIN_LIMIT > 0) {
+ print "<b>Fatal Error</b>: Please set DAEMON_UPDATE_LOGIN_LIMIT
+ to 0 in single user mode.\n";
+ exit;
+ }
+
+ if (!defined('SESSION_EXPIRE_TIME')) {
+ $err_msg = "config: SESSION_EXPIRE_TIME is undefined";
+ }
+
+ if (SESSION_EXPIRE_TIME < 60) {
+ $err_msg = "config: SESSION_EXPIRE_TIME is too low (less than 60)";
+ }
+
+ if (SESSION_EXPIRE_TIME < SESSION_COOKIE_LIFETIME) {
+ $err_msg = "config: SESSION_EXPIRE_TIME should be greater or equal to" .
+ "SESSION_COOKIE_LIFETIME";
+ }
+
+/* if (defined('DISABLE_SESSIONS')) {
+ $err_msg = "config: you have enabled DISABLE_SESSIONS. Please disable this option.";
+} */
+
+ if (DATABASE_BACKED_SESSIONS && SINGLE_USER_MODE) {
+ $err_msg = "config: DATABASE_BACKED_SESSIONS is incompatible with SINGLE_USER_MODE";
+ }
+
+ if (DATABASE_BACKED_SESSIONS && DB_TYPE == "mysql") {
+ $err_msg = "config: DATABASE_BACKED_SESSIONS are currently broken with MySQL";
+ }
+
+ if (SINGLE_USER_MODE) {
+ $link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
+
+ if ($link) {
+ $result = db_query($link, "SELECT id FROM ttrss_users WHERE id = 1");
+
+ if (db_num_rows($result) != 1) {
+ $err_msg = "config: SINGLE_USER_MODE is enabled but default admin account (UID=1) is not found.";
+ }
+ }
+ }
+
+ if (defined('MAIL_FROM')) {
+ $err_msg = "config: MAIL_FROM has been split into DIGEST_FROM_NAME and DIGEST_FROM_ADDRESS";
+ }
+
+ if (!defined('COUNTERS_MAX_AGE')) {
+ $err_msg = "config: option COUNTERS_MAX_AGE expected, but not defined";
+ }
+
+ if (defined('DAEMON_REFRESH_ONLY')) {
+ $err_msg = "config: option DAEMON_REFRESH_ONLY is obsolete. Please remove this option and read about other ways to update feeds on the <a href='http://tt-rss.org/wiki/UpdatingFeeds'>wiki</a>.";
+
+ }
+
+ if (defined('ENABLE_SIMPLEPIE')) {
+ $err_msg = "config: ENABLE_SIMPLEPIE is obsolete and replaced with DEFAULT_UPDATE_METHOD. Please adjust your config.php.";
+ }
+
+ if (!defined('DEFAULT_UPDATE_METHOD') || (DEFAULT_UPDATE_METHOD != 0 &&
+ DEFAULT_UPDATE_METHOD != 1)) {
+ $err_msg = "config: DEFAULT_UPDATE_METHOD should be either 0 or 1.";
+ }
+
+ if (SELF_URL_PATH == "http://yourserver/tt-rss/") {
+ $err_msg = "config: please set SELF_URL_PATH to the correct value.";
+ }
+
+ if (!is_writable(ICONS_DIR)) {
+ $err_msg = "config: your ICONS_DIR (" . ICONS_DIR . ") is not writable.\n";
+ }
+
+ if (ini_get("open_basedir")) {
+ $err_msg = "php.ini: open_basedir is not supported.";
+ }
+
+ if (!function_exists("curl_init") && !ini_get("allow_url_fopen")) {
+ $err_msg = "php.ini: either allow_url_fopen or CURL needs to be enabled.";
+ }
+
+ if (!function_exists("json_encode")) {
+ $err_msg = "PHP: json functions not found.";
+ }
+
+ if (DB_TYPE == "mysql" && !function_exists("mysql_connect")) {
+ $err_msg = "PHP: MySQL functions not found.";
+ }
+
+ if (DB_TYPE == "pgsql" && !function_exists("pg_connect")) {
+ $err_msg = "PHP: PostgreSQL functions not found.";
+ }
+
+ if (!function_exists("mb_strlen")) {
+ $err_msg = "PHP: mbstring functions not found.";
+ }
+
+ if (!function_exists("ctype_lower")) {
+ $err_msg = "PHP: ctype functions not found (required for HTMLPurifier).";
+ }
+
+ if (ini_get("safe_mode")) {
+ $err_msg = "php.ini: Safe mode is not supported. If you wish to continue, remove this test from sanity_check.php and proceeed at your own risk. Please note that your bug reports will not be accepted or reviewed.";
+ }
+
+ if ((PUBSUBHUBBUB_HUB || PUBSUBHUBBUB_ENABLED) && !function_exists("curl_init")) {
+ $err_msg = "CURL is required for PubSubHubbub support.";
+ }
+
+ if (!class_exists("DOMDocument")) {
+ $err_msg = "PHP: DOMDocument extension not found.";
+ }
+
+ if (SELF_URL_PATH == "http://local.host/tt-rss") {
+ $err_msg = "config: please set SELF_URL_PATH to the correct value";
+ }
+
+ if (!ISCONFIGURED) {
+ $err_msg = "config: please read config.php completely.";
+ }
+
+ if ($err_msg) {
+ print "<b>Fatal Error</b>: $err_msg\n";
+ exit;
+ }
+
+?>
--- /dev/null
+<?php # This file has been generated at: Tue Apr 26 18:40:48 MSD 2011
+define('GENERATED_CONFIG_CHECK', 23);
+$requred_defines = array( 'DB_TYPE', 'DB_HOST', 'DB_USER', 'DB_NAME', 'DB_PASS', 'SELF_URL_PATH', 'SINGLE_USER_MODE', 'CACHE_DIR', 'SIMPLEPIE_CACHE_IMAGES', 'ICONS_DIR', 'ICONS_URL', 'TMP_DIRECTORY', 'DAEMON_SLEEP_INTERVAL', 'DATABASE_BACKED_SESSIONS', 'SESSION_CHECK_ADDRESS', 'SESSION_COOKIE_LIFETIME', 'SESSION_EXPIRE_TIME', 'DAEMON_UPDATE_LOGIN_LIMIT', 'CHECK_FOR_NEW_VERSION', 'DIGEST_ENABLE', 'DIGEST_EMAIL_LIMIT', 'DAEMON_SENDS_DIGESTS', 'MYSQL_CHARSET', 'DEFAULT_UPDATE_METHOD', 'COUNTERS_MAX_AGE', 'DIGEST_FROM_NAME', 'DIGEST_FROM_ADDRESS', 'DIGEST_SUBJECT', 'DIGEST_SMTP_HOST', 'DIGEST_SMTP_LOGIN', 'DIGEST_SMTP_PASSWORD', 'DAEMON_FEED_LIMIT', 'ALLOW_REMOTE_USER_AUTH', 'AUTO_LOGIN', 'AUTO_CREATE_USER', 'LOCK_DIRECTORY', 'ENABLE_GZIP_OUTPUT', 'PHP_EXECUTABLE', 'ENABLE_REGISTRATION', 'REG_NOTIFY_ADDRESS', 'REG_MAX_USERS', 'FEEDBACK_URL', 'FORCE_ARTICLE_PURGE', 'SPHINX_ENABLED', 'SPHINX_INDEX', 'ENABLE_TWEET_BUTTON', 'CONSUMER_KEY', 'CONSUMER_SECRET', 'PUBSUBHUBBUB_HUB', 'PUBSUBHUBBUB_ENABLED', 'ISCONFIGURED', 'CONFIG_VERSION'); ?>
--- /dev/null
+<?php
+ // Original from http://www.daniweb.com/code/snippet43.html
+
+ require_once "config.php";
+ require_once "db.php";
+
+ $session_expire = SESSION_EXPIRE_TIME; //seconds
+ $session_name = (!defined('TTRSS_SESSION_NAME')) ? "ttrss_sid" : TTRSS_SESSION_NAME;
+
+ if ($_SERVER['HTTPS'] == "on") {
+ $session_name .= "_ssl";
+ ini_set("session.cookie_secure", true);
+ }
+
+ ini_set("session.gc_probability", 50);
+ ini_set("session.name", $session_name);
+ ini_set("session.use_only_cookies", true);
+ ini_set("session.gc_maxlifetime", SESSION_EXPIRE_TIME);
+
+ function ttrss_open ($s, $n) {
+
+ global $session_connection;
+
+ $session_connection = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
+
+ return true;
+ }
+
+ function ttrss_read ($id){
+
+ global $session_connection,$session_read;
+
+ $query = "SELECT data FROM ttrss_sessions WHERE id='$id'";
+
+ $res = db_query($session_connection, $query);
+
+ if (db_num_rows($res) != 1) {
+ return "";
+ } else {
+ $session_read = db_fetch_assoc($res);
+ $session_read["data"] = base64_decode($session_read["data"]);
+ return $session_read["data"];
+ }
+ }
+
+ function ttrss_write ($id, $data) {
+
+ if (! $data) {
+ return false;
+ }
+
+ global $session_connection, $session_read, $session_expire;
+
+ $expire = time() + $session_expire;
+
+ $data = db_escape_string(base64_encode($data), $session_connection);
+
+ if ($session_read) {
+ $query = "UPDATE ttrss_sessions SET data='$data',
+ expire='$expire' WHERE id='$id'";
+ } else {
+ $query = "INSERT INTO ttrss_sessions (id, data, expire)
+ VALUES ('$id', '$data', '$expire')";
+ }
+
+ db_query($session_connection, $query);
+ return true;
+ }
+
+ function ttrss_close () {
+
+ global $session_connection;
+
+ db_close($session_connection);
+
+ return true;
+ }
+
+ function ttrss_destroy ($id) {
+
+ global $session_connection;
+
+ $query = "DELETE FROM ttrss_sessions WHERE id = '$id'";
+
+ db_query($session_connection, $query);
+
+ return true;
+ }
+
+ function ttrss_gc ($expire) {
+
+ global $session_connection;
+
+ $query = "DELETE FROM ttrss_sessions WHERE expire < " . time();
+
+ db_query($session_connection, $query);
+ }
+
+ if (DATABASE_BACKED_SESSIONS) {
+ session_set_save_handler("ttrss_open",
+ "ttrss_close", "ttrss_read", "ttrss_write",
+ "ttrss_destroy", "ttrss_gc");
+ }
+
+ session_set_cookie_params(SESSION_COOKIE_LIFETIME);
+
+ session_start();
+?>
--- /dev/null
+<?php
+ define('VERSION', "1.5.7");
+?>
-<?php header("Location: tt-rss.php"); ?>
+<?php
+ set_include_path(get_include_path() . PATH_SEPARATOR . "include");
+
+ require_once "functions.php";
+ require_once "sessions.php";
+ require_once "sanity_check.php";
+ require_once "version.php";
+ require_once "config.php";
+ require_once "db-prefs.php";
+
+ $link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
+
+ init_connection($link);
+
+ login_sequence($link);
+
+ $dt_add = time();
+
+ no_cache_incantation();
+
+ header('Content-Type: text/html; charset=utf-8');
+
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+ <title>Tiny Tiny RSS</title>
+ <link rel="stylesheet" type="text/css" href="lib/dijit/themes/claro/claro.css"/>
+ <link rel="stylesheet" type="text/css" href="tt-rss.css?<?php echo $dt_add ?>"/>
+ <link rel="stylesheet" type="text/css" href="cdm.css?<?php echo $dt_add ?>"/>
+
+ <?php print_theme_includes($link) ?>
+ <?php print_user_stylesheet($link) ?>
+
+ <link rel="shortcut icon" type="image/png" href="images/favicon.png"/>
+
+ <script type="text/javascript" src="lib/prototype.js"></script>
+ <script type="text/javascript" src="lib/scriptaculous/scriptaculous.js?load=effects,dragdrop,controls"></script>
+ <script type="text/javascript" src="lib/dojo/dojo.js"></script>
+ <script type="text/javascript" src="lib/dijit/dijit.js"></script>
+ <script type="text/javascript" src="lib/dojo/tt-rss-layer.js"></script>
+
+ <script type="text/javascript" charset="utf-8" src="localized_js.php?<?php echo $dt_add ?>"></script>
+ <script type="text/javascript" charset="utf-8" src="js/tt-rss.js?<?php echo $dt_add ?>"></script>
+ <script type="text/javascript" charset="utf-8" src="js/functions.js?<?php echo $dt_add ?>"></script>
+ <script type="text/javascript" charset="utf-8" src="js/feedlist.js?<?php echo $dt_add ?>"></script>
+ <script type="text/javascript" charset="utf-8" src="js/viewfeed.js?<?php echo $dt_add ?>"></script>
+ <script type="text/javascript" charset="utf-8" src="errors.php?mode=js"></script>
+
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+
+ <script type="text/javascript">
+ Event.observe(window, 'load', function() {
+ init();
+ });
+ </script>
+</head>
+
+<body id="ttrssMain" class="claro">
+
+<div id="overlay" style="display : block">
+ <div id="overlay_inner">
+ <div class="insensitive"><?php echo __("Loading, please wait...") ?></div>
+ <div dojoType="dijit.ProgressBar" places="0" style="width : 300px" id="loading_bar"
+ progress="0" maximum="100">
+ </div>
+ <noscript><br/><?php print_error('Javascript is disabled. Please enable it.') ?></noscript>
+ </div>
+</div>
+
+<div id="header">
+ <?php if (!SINGLE_USER_MODE) { ?>
+ <?php echo __('Hello,') ?> <b><?php echo $_SESSION["name"] ?></b> |
+ <?php } ?>
+ <a href="prefs.php"><?php echo __('Preferences') ?></a>
+
+ <?php if (defined('FEEDBACK_URL') && FEEDBACK_URL) { ?>
+ | <a target="_blank" class="feedback" href="<?php echo FEEDBACK_URL ?>">
+ <?php echo __('Comments?') ?></a>
+ <?php } ?>
+
+ <?php if (!SINGLE_USER_MODE) { ?>
+ | <a href="backend.php?op=logout"><?php echo __('Logout') ?></a>
+ <?php } ?>
+
+ <img id="newVersionIcon" style="display:none" onclick="newVersionDlg()"
+ width="13" height="13"
+ src="<?php echo theme_image($link, 'images/new_version.png') ?>"
+ title="<?php echo __('New version of Tiny Tiny RSS is available!') ?>"
+ alt="new_version_icon"/>
+</div>
+
+<div id="hotkey_help_overlay" style="display : none" onclick="Element.hide(this)">
+ <?php include "help/3.php" ?>
+</div>
+
+<div id="notify" class="notify"><span id="notify_body"> </span></div>
+<div id="cmdline" style="display : none"></div>
+<div id="auxDlg" style="display : none"></div>
+<div id="headlines-tmp" style="display : none"></div>
+
+<div id="main" dojoType="dijit.layout.BorderContainer">
+
+<div id="feeds-holder" dojoType="dijit.layout.ContentPane" region="leading" style="width : 20%" splitter="true">
+ <div id="feedlistLoading">
+ <img src='images/indicator_tiny.gif'/>
+ <?php echo __("Loading, please wait..."); ?></div>
+ <div id="feedTree"></div>
+</div>
+
+<div dojoType="dijit.layout.BorderContainer" region="center" id="header-wrap" gutters="false">
+<div dojoType="dijit.layout.TabContainer" region="center" id="content-tabs">
+<div dojoType="dijit.layout.BorderContainer" region="center" id="content-wrap"
+ title="<?php echo __("News") ?>">
+
+<div id="toolbar" dojoType="dijit.layout.ContentPane" region="top">
+ <div id="main-toolbar" dojoType="dijit.Toolbar">
+
+ <form id="main_toolbar_form" action="" onsubmit='return false'>
+
+ <button dojoType="dijit.form.Button" id="collapse_feeds_btn"
+ onclick="collapse_feedlist()"
+ title="<?php echo __('Collapse feedlist') ?>" style="display : inline">
+ <<</button>
+
+ <select name="view_mode" title="<?php echo __('Show articles') ?>"
+ onchange="viewModeChanged()"
+ dojoType="dijit.form.Select">
+ <option selected="selected" value="adaptive"><?php echo __('Adaptive') ?></option>
+ <option value="all_articles"><?php echo __('All Articles') ?></option>
+ <option value="marked"><?php echo __('Starred') ?></option>
+ <option value="published"><?php echo __('Published') ?></option>
+ <option value="unread"><?php echo __('Unread') ?></option>
+ <!-- <option value="noscores"><?php echo __('Ignore Scoring') ?></option> -->
+ <option value="updated"><?php echo __('Updated') ?></option>
+ </select>
+
+ <select title="<?php echo __('Sort articles') ?>"
+ onchange="viewModeChanged()"
+ dojoType="dijit.form.Select" name="order_by">
+ <option selected="selected" value="default"><?php echo __('Default') ?></option>
+ <option value="date"><?php echo __('Date') ?></option>
+ <option value="title"><?php echo __('Title') ?></option>
+ <option value="score"><?php echo __('Score') ?></option>
+ </select>
+
+ <button dojoType="dijit.form.Button" name="update"
+ onclick="scheduleFeedUpdate()">
+ <?php echo __('Update') ?></button>
+
+ <button dojoType="dijit.form.Button"
+ onclick="catchupCurrentFeed()">
+ <?php echo __('Mark as read') ?></button>
+
+ </form>
+
+ <div class="actionChooser">
+ <div dojoType="dijit.form.DropDownButton">
+ <span><?php echo __('Actions...') ?></span>
+ <div dojoType="dijit.Menu" style="display: none">
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcSearch')"><?php echo __('Search...') ?></div>
+ <div dojoType="dijit.MenuItem" disabled="1"><?php echo __('Feed actions:') ?></div>
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcAddFeed')"><?php echo __('Subscribe to feed...') ?></div>
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcEditFeed')"><?php echo __('Edit this feed...') ?></div>
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcRescoreFeed')"><?php echo __('Rescore feed') ?></div>
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcRemoveFeed')"><?php echo __('Unsubscribe') ?></div>
+ <div dojoType="dijit.MenuItem" disabled="1"><?php echo __('All feeds:') ?></div>
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcCatchupAll')"><?php echo __('Mark as read') ?></div>
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcShowOnlyUnread')"><?php echo __('(Un)hide read feeds') ?></div>
+ <div dojoType="dijit.MenuItem" disabled="1"><?php echo __('Other actions:') ?></div>
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcDigest')"><?php echo __('Switch to digest...') ?></div>
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcTagCloud')"><?php echo __('Show tag cloud...') ?></div>
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcTagSelect')"><?php echo __('Select by tags...') ?></div>
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcAddLabel')"><?php echo __('Create label...') ?></div>
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcAddFilter')"><?php echo __('Create filter...') ?></div>
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcHKhelp')"><?php echo __('Keyboard shortcuts help') ?></div>
+ <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcAbout')"><?php echo __('About...') ?></div>
+ </div>
+ </div>
+ </div>
+ </div> <!-- toolbar -->
+</div> <!-- toolbar pane -->
+
+ <div id="headlines-wrap-inner" dojoType="dijit.layout.BorderContainer" region="center">
+
+ <div id="headlines-toolbar" dojoType="dijit.layout.ContentPane" region="top">
+ </div>
+
+ <div id="headlines-frame" dojoType="dijit.layout.ContentPane"
+ onscroll="headlines_scroll_handler(this)" region="center">
+ <div id="headlinesInnerContainer">
+ <div class="whiteBox"><?php echo __('Loading, please wait...') ?></div>
+ </div>
+ </div>
+
+ <?php if (!get_pref($link, 'COMBINED_DISPLAY_MODE')) { ?>
+ <div id="content-insert" dojoType="dijit.layout.ContentPane" region="bottom"
+ style="height : 50%" splitter="true"></div>
+ <?php } ?>
+
+ </div>
+</div>
+</div>
+</div>
+</div>
+
+<?php db_close($link); ?>
+
+</body>
+</html>
--- /dev/null
+dojo.provide("fox.FeedTree");
+dojo.provide("fox.FeedStoreModel");
+
+dojo.require("dijit.Tree");
+dojo.require("dijit.Menu");
+
+dojo.declare("fox.FeedStoreModel", dijit.tree.ForestStoreModel, {
+ getItemsInCategory: function (id) {
+ if (!this.store._itemsByIdentity) return undefined;
+
+ cat = this.store._itemsByIdentity['CAT:' + id];
+
+ if (cat && cat.items)
+ return cat.items;
+ else
+ return undefined;
+
+ },
+ getItemById: function(id) {
+ return this.store._itemsByIdentity[id];
+ },
+ getFeedValue: function(feed, is_cat, key) {
+ if (!this.store._itemsByIdentity) return undefined;
+
+ if (is_cat)
+ treeItem = this.store._itemsByIdentity['CAT:' + feed];
+ else
+ treeItem = this.store._itemsByIdentity['FEED:' + feed];
+
+ if (treeItem)
+ return this.store.getValue(treeItem, key);
+ },
+ getFeedName: function(feed, is_cat) {
+ return this.getFeedValue(feed, is_cat, 'name');
+ },
+ getFeedUnread: function(feed, is_cat) {
+ var unread = parseInt(this.getFeedValue(feed, is_cat, 'unread'));
+ return (isNaN(unread)) ? 0 : unread;
+ },
+ setFeedUnread: function(feed, is_cat, unread) {
+ return this.setFeedValue(feed, is_cat, 'unread', parseInt(unread));
+ },
+ setFeedValue: function(feed, is_cat, key, value) {
+ if (!value) value = '';
+ if (!this.store._itemsByIdentity) return undefined;
+
+ if (is_cat)
+ treeItem = this.store._itemsByIdentity['CAT:' + feed];
+ else
+ treeItem = this.store._itemsByIdentity['FEED:' + feed];
+
+ if (treeItem)
+ return this.store.setValue(treeItem, key, value);
+ },
+ getNextUnreadFeed: function (feed, is_cat) {
+ if (!this.store._itemsByIdentity)
+ return null;
+
+ if (is_cat) {
+ treeItem = this.store._itemsByIdentity['CAT:' + feed];
+ items = this.store._arrayOfTopLevelItems;
+ } else {
+ treeItem = this.store._itemsByIdentity['FEED:' + feed];
+ items = this.store._arrayOfAllItems;
+ }
+
+ for (var i = 0; i < items.length; i++) {
+ if (items[i] == treeItem) {
+
+ for (var j = i+1; j < items.length; j++) {
+ var unread = this.store.getValue(items[j], 'unread');
+ var id = this.store.getValue(items[j], 'id');
+
+ if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
+ }
+
+ for (var j = 0; j < i; j++) {
+ var unread = this.store.getValue(items[j], 'unread');
+ var id = this.store.getValue(items[j], 'id');
+
+ if (unread > 0 && (is_cat || id.match("FEED:"))) return items[j];
+ }
+ }
+ }
+
+ return null;
+ },
+ hasCats: function() {
+ if (this.store && this.store._itemsByIdentity)
+ return this.store._itemsByIdentity['CAT:-1'] != undefined;
+ else
+ return false;
+ },
+});
+
+dojo.declare("fox.FeedTree", dijit.Tree, {
+ _createTreeNode: function(args) {
+ var tnode = new dijit._TreeNode(args);
+
+ if (args.item.icon)
+ tnode.iconNode.src = args.item.icon[0];
+
+ var id = args.item.id[0];
+ var bare_id = parseInt(id.substr(id.indexOf(':')+1));
+
+ if (bare_id < -10) {
+ var span = dojo.doc.createElement('span');
+ var fg_color = args.item.fg_color[0];
+ var bg_color = args.item.bg_color[0];
+
+ span.innerHTML = "α";
+ span.className = 'labelColorIndicator';
+ span.setStyle({
+ color: fg_color,
+ backgroundColor: bg_color});
+
+ dojo.place(span, tnode.iconNode, 'replace');
+ }
+
+ if (id.match("FEED:") && bare_id > 0) {
+ var menu = new dijit.Menu();
+ menu.row_id = bare_id;
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Mark as read"),
+ onClick: function() {
+ catchupFeed(this.getParent().row_id);
+ }}));
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Edit feed"),
+ onClick: function() {
+ editFeed(this.getParent().row_id, false);
+ }}));
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Update feed"),
+ onClick: function() {
+ scheduleFeedUpdate(this.getParent().row_id, false);
+ }}));
+
+ menu.bindDomNode(tnode.domNode);
+ tnode._menu = menu;
+ }
+
+ if (id.match("CAT:") && bare_id > 0) {
+ var menu = new dijit.Menu();
+ menu.row_id = bare_id;
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Mark as read"),
+ onClick: function() {
+ catchupFeed(this.getParent().row_id, true);
+ }}));
+
+ menu.bindDomNode(tnode.domNode);
+ tnode._menu = menu;
+ }
+
+ //tnode.labelNode.innerHTML = args.label;
+ return tnode;
+ },
+ getIconClass: function (item, opened) {
+ return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon";
+ },
+ getLabelClass: function (item, opened) {
+ return (item.unread == 0) ? "dijitTreeLabel" : "dijitTreeLabel Unread";
+ },
+ getRowClass: function (item, opened) {
+ return (!item.error || item.error == '') ? "dijitTreeRow" :
+ "dijitTreeRow Error";
+ },
+ getLabel: function(item) {
+ var name = String(item.name);
+
+ /* Horrible */
+ name = name.replace(/"/g, "\"");
+ name = name.replace(/&/g, "&");
+ name = name.replace(/—/g, "-");
+ name = name.replace(/</g, "<");
+ name = name.replace(/>/g, ">");
+
+ if (item.unread > 0) {
+ return name + " (" + item.unread + ")";
+ } else {
+ return name;
+ }
+ },
+ selectFeed: function(feed, is_cat) {
+ if (is_cat)
+ treeNode = this._itemNodesMap['CAT:' + feed];
+ else
+ treeNode = this._itemNodesMap['FEED:' + feed];
+
+ if (treeNode) {
+ treeNode = treeNode[0];
+ if (!is_cat) this._expandNode(treeNode);
+ this.set("selectedNodes", [treeNode]);
+ }
+ },
+ setFeedIcon: function(feed, is_cat, src) {
+ if (is_cat)
+ treeNode = this._itemNodesMap['CAT:' + feed];
+ else
+ treeNode = this._itemNodesMap['FEED:' + feed];
+
+ if (treeNode) {
+ treeNode = treeNode[0];
+ treeNode.iconNode.src = src;
+ return true;
+ }
+ return false;
+ },
+ setFeedExpandoIcon: function(feed, is_cat, src) {
+ if (is_cat)
+ treeNode = this._itemNodesMap['CAT:' + feed];
+ else
+ treeNode = this._itemNodesMap['FEED:' + feed];
+
+ if (treeNode) {
+ treeNode = treeNode[0];
+ treeNode.expandoNode.src = src;
+ return true;
+ }
+
+ return false;
+ },
+ hasCats: function() {
+ return this.model.hasCats();
+ },
+ hideRead: function (hide, show_special) {
+ if (this.hasCats()) {
+
+ var tree = this;
+ var cats = this.model.store._arrayOfTopLevelItems;
+
+ cats.each(function(cat) {
+ var cat_unread = tree.hideReadFeeds(cat.items, hide, show_special);
+
+ var id = String(cat.id);
+ var node = tree._itemNodesMap[id];
+ var bare_id = parseInt(id.substr(id.indexOf(":")+1));
+
+ if (node) {
+ var check_unread = tree.model.getFeedUnread(bare_id, true);
+
+ if (hide && cat_unread == 0 && check_unread == 0) {
+ Effect.Fade(node[0].rowNode, {duration : 0.3,
+ queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
+ } else {
+ Element.show(node[0].rowNode);
+ ++cat_unread;
+ }
+ }
+ });
+
+ } else {
+ this.hideReadFeeds(this.model.store._arrayOfTopLevelItems, hide,
+ show_special);
+ }
+ },
+ hideReadFeeds: function (items, hide, show_special) {
+ var tree = this;
+ var cat_unread = 0;
+
+ items.each(function(feed) {
+ var id = String(feed.id);
+ var bare_id = parseInt(feed.bare_id);;
+
+ var unread = feed.unread[0];
+ var node = tree._itemNodesMap[id];
+
+ if (node) {
+ if (hide && unread == 0 && (bare_id > 0 || !show_special)) {
+ Effect.Fade(node[0].rowNode, {duration : 0.3,
+ queue: { position: 'end', scope: 'FFADE-' + id, limit: 1 }});
+ } else {
+ Element.show(node[0].rowNode);
+ ++cat_unread;
+ }
+ }
+ });
+
+ return cat_unread;
+ },
+ collapseCat: function(id) {
+ if (!this.model.hasCats()) return;
+
+ var tree = this;
+
+ var node = tree._itemNodesMap['CAT:' + id][0];
+ var item = tree.model.store._itemsByIdentity['CAT:' + id];
+
+ if (node && item) {
+ var hidden = tree.model.store.getValue(item, 'hidden');
+
+ if (hidden)
+ tree._expandNode(node);
+ else
+ tree._collapseNode(node);
+
+ tree.model.store.setValue(item, 'hidden', !hidden);
+ }
+ },
+ collapseHiddenCats: function() {
+ if (!this.model.hasCats()) return;
+
+ var cats = this.model.store._arrayOfTopLevelItems;
+ var tree = this;
+
+ dojo.forEach(cats, function(cat) {
+ var hidden = tree.model.store.getValue(cat, 'hidden');
+ var id = tree.model.store.getValue(cat, 'id');
+ var node = tree._itemNodesMap[id][0];
+
+ if (hidden)
+ tree._collapseNode(node);
+ else
+ tree._expandNode(node);
+
+ });
+ },
+ getVisibleUnreadFeeds: function() {
+ var items = this.model.store._arrayOfAllItems;
+ var rv = [];
+
+ for (var i = 0; i < items.length; i++) {
+ var id = String(items[i].id);
+ var box = this._itemNodesMap[id];
+
+ if (box) {
+ var row = box[0].rowNode;
+ var cat = false;
+
+ try {
+ cat = box[0].rowNode.parentNode.parentNode;
+ } catch (e) { }
+
+ if (row) {
+ if (Element.visible(row) && (!cat || Element.visible(cat))) {
+ var feed_id = String(items[i].bare_id);
+ var is_cat = !id.match('FEED:');
+ var unread = this.model.getFeedUnread(feed_id, is_cat);
+
+ if (unread > 0)
+ rv.push([feed_id, is_cat]);
+
+ }
+ }
+ }
+ }
+
+ return rv;
+ },
+ getNextFeed: function (feed, is_cat) {
+ if (is_cat) {
+ treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
+ } else {
+ treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
+ }
+
+ items = this.model.store._arrayOfAllItems;
+ var item = items[0];
+
+ for (var i = 0; i < items.length; i++) {
+ if (items[i] == treeItem) {
+
+ for (var j = i+1; j < items.length; j++) {
+ var id = String(items[j].id);
+ var box = this._itemNodesMap[id];
+
+ if (box) {
+ var row = box[0].rowNode;
+ var cat = box[0].rowNode.parentNode.parentNode;
+
+ if (Element.visible(cat) && Element.visible(row)) {
+ item = items[j];
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (item) {
+ return [this.model.store.getValue(item, 'bare_id'),
+ !this.model.store.getValue(item, 'id').match('FEED:')];
+ } else {
+ return false;
+ }
+ },
+ getPreviousFeed: function (feed, is_cat) {
+ if (is_cat) {
+ treeItem = this.model.store._itemsByIdentity['CAT:' + feed];
+ } else {
+ treeItem = this.model.store._itemsByIdentity['FEED:' + feed];
+ }
+
+ items = this.model.store._arrayOfAllItems;
+ var item = items[0];
+
+ for (var i = 0; i < items.length; i++) {
+ if (items[i] == treeItem) {
+
+ for (var j = i-1; j > 0; j--) {
+ var id = String(items[j].id);
+ var box = this._itemNodesMap[id];
+
+ if (box) {
+ var row = box[0].rowNode;
+ var cat = box[0].rowNode.parentNode.parentNode;
+
+ if (Element.visible(cat) && Element.visible(row)) {
+ item = items[j];
+ break;
+ }
+ }
+
+ }
+ break;
+ }
+ }
+
+ if (item) {
+ return [this.model.store.getValue(item, 'bare_id'),
+ !this.model.store.getValue(item, 'id').match('FEED:')];
+ } else {
+ return false;
+ }
+
+ },
+
+});
--- /dev/null
+dojo.provide("fox.PrefFeedTree");
+dojo.provide("fox.PrefFeedStore");
+
+dojo.require("lib.CheckBoxTree");
+dojo.require("dojo.data.ItemFileWriteStore");
+
+dojo.declare("fox.PrefFeedStore", dojo.data.ItemFileWriteStore, {
+
+ _saveEverything: function(saveCompleteCallback, saveFailedCallback,
+ newFileContentString) {
+
+ dojo.xhrPost({
+ url: "backend.php",
+ content: {op: "pref-feeds", subop: "savefeedorder",
+ payload: newFileContentString},
+ error: saveFailedCallback,
+ load: saveCompleteCallback});
+ },
+
+});
+
+dojo.declare("fox.PrefFeedTree", lib.CheckBoxTree, {
+ _createTreeNode: function(args) {
+ var tnode = this.inherited(arguments);
+
+ if (args.item.icon)
+ tnode.iconNode.src = args.item.icon[0];
+
+ var param = this.model.store.getValue(args.item, 'param');
+
+ if (param) {
+ param = dojo.doc.createElement('span');
+ param.className = 'feedParam';
+ param.innerHTML = args.item.param[0];
+ dojo.place(param, tnode.labelNode, 'after');
+ }
+
+ return tnode;
+ },
+ onDndDrop: function() {
+ this.inherited(arguments);
+ this.tree.model.store.save();
+ },
+ getRowClass: function (item, opened) {
+ return (!item.error || item.error == '') ? "dijitTreeRow" :
+ "dijitTreeRow Error";
+ },
+ getIconClass: function (item, opened) {
+ return (!item || this.model.store.getValue(item, 'type') == 'category') ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon";
+ },
+ checkItemAcceptance: function(target, source, position) {
+ var item = dijit.getEnclosingWidget(target).item;
+
+ // disable copying items
+ source.copyState = function() { return false; };
+
+ var source_item = false;
+
+ source.forInSelectedItems(function(node) {
+ source_item = node.data.item;
+ });
+
+ if (!source_item || !item) return false;
+
+ var id = this.tree.model.store.getValue(item, 'id');
+ var source_id = source.tree.model.store.getValue(source_item, 'id');
+
+ //console.log(id + " " + position + " " + source_id);
+
+ if (source_id.match("FEED:")) {
+ return ((id.match("CAT:") && position == "over") ||
+ (id.match("FEED:") && position != "over"));
+ } else if (source_id.match("CAT:")) {
+ return ((id.match("CAT:") && position != "over") ||
+ (id.match("root") && position == "over"));
+ }
+ },
+});
+
--- /dev/null
+dojo.provide("fox.PrefFilterTree");
+
+dojo.require("lib.CheckBoxTree");
+
+dojo.declare("fox.PrefFilterTree", lib.CheckBoxTree, {
+ _createTreeNode: function(args) {
+ var tnode = this.inherited(arguments);
+
+ var enabled = this.model.store.getValue(args.item, 'enabled');
+ var param = this.model.store.getValue(args.item, 'param');
+
+ if (param) {
+ param = dojo.doc.createElement('span');
+ param.className = (enabled != false) ? 'labelParam' : 'labelParam Disabled';
+ param.innerHTML = args.item.param[0];
+ dojo.place(param, tnode.labelNode, 'after');
+ }
+
+ return tnode;
+ },
+
+ getLabel: function(item) {
+ var label = item.name;
+
+ var feed = this.model.store.getValue(item, 'feed');
+ var inverse = this.model.store.getValue(item, 'inverse');
+
+ if (feed)
+ label += " (" + __("Feed:") + " " + feed + ")";
+
+ if (inverse)
+ label += " (" + __("Inverse") + ")";
+
+/* if (item.param)
+ label = "<span class=\"labelFixedLength\">" + label +
+ "</span>" + item.param[0]; */
+
+ return label;
+ },
+ getIconClass: function (item, opened) {
+ return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "invisible";
+ },
+ getLabelClass: function (item, opened) {
+ var enabled = this.model.store.getValue(item, 'enabled');
+ return (enabled != false) ? "dijitTreeLabel labelFixedLength" : "dijitTreeLabel labelFixedLength Disabled";
+ },
+ getRowClass: function (item, opened) {
+ return (!item.error || item.error == '') ? "dijitTreeRow" :
+ "dijitTreeRow Error";
+ },
+});
+
--- /dev/null
+dojo.provide("fox.PrefLabelTree");
+
+dojo.require("lib.CheckBoxTree");
+dojo.require("dijit.form.DropDownButton");
+
+dojo.declare("fox.PrefLabelTree", lib.CheckBoxTree, {
+ setNameById: function (id, name) {
+ var item = this.model.store._itemsByIdentity['LABEL:' + id];
+
+ if (item)
+ this.model.store.setValue(item, 'name', name);
+
+ },
+ _createTreeNode: function(args) {
+ var tnode = this.inherited(arguments);
+
+ var fg_color = this.model.store.getValue(args.item, 'fg_color');
+ var bg_color = this.model.store.getValue(args.item, 'bg_color');
+ var type = this.model.store.getValue(args.item, 'type');
+ var bare_id = this.model.store.getValue(args.item, 'bare_id');
+
+ if (type == 'label') {
+ var span = dojo.doc.createElement('span');
+ span.innerHTML = 'α';
+ span.className = 'labelColorIndicator2';
+ span.id = 'LICID-' + bare_id;
+
+ span.setStyle({
+ color: fg_color,
+ backgroundColor: bg_color});
+
+ tnode._labelIconNode = span;
+
+ dojo.place(tnode._labelIconNode, tnode.labelNode, 'before');
+ }
+
+ return tnode;
+ },
+ getIconClass: function (item, opened) {
+ return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "invisible";
+ },
+});
+
--- /dev/null
+function selectTableRow(r, do_select) {
+
+ if (do_select) {
+ r.addClassName("Selected");
+ } else {
+ r.removeClassName("Selected");
+ }
+}
+
+function selectTableRowById(elem_id, check_id, do_select) {
+
+ try {
+
+ var row = $(elem_id);
+
+ if (row) {
+ selectTableRow(row, do_select);
+ }
+
+ var check = $(check_id);
+
+ if (check) {
+ check.checked = do_select;
+ }
+ } catch (e) {
+ exception_error("selectTableRowById", e);
+ }
+}
+
--- /dev/null
+var last_feeds = [];
+var init_params = {};
+
+var _active_feed_id = false;
+var _update_timeout = false;
+var _view_update_timeout = false;
+var _feedlist_expanded = false;
+var _update_seq = 1;
+
+function article_appear(article_id) {
+ try {
+ new Effect.Appear('A-' + article_id);
+ } catch (e) {
+ exception_error("article_appear", e);
+ }
+}
+
+function catchup_feed(feed_id, callback) {
+ try {
+
+ var fn = find_feed(last_feeds, feed_id).title;
+
+ if (confirm(__("Mark all articles in %s as read?").replace("%s", fn))) {
+
+ var is_cat = "";
+
+ if (feed_id < 0) is_cat = "true"; // KLUDGE
+
+ var query = "?op=rpc&subop=catchupFeed&feed_id=" +
+ feed_id + "&is_cat=" + is_cat;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ if (callback) callback(transport);
+
+ update();
+ } });
+ }
+
+ } catch (e) {
+ exception_error("catchup_article", e);
+ }
+}
+
+function get_visible_article_ids() {
+ try {
+ var elems = $("headlines-content").getElementsByTagName("LI");
+ var ids = [];
+
+ for (var i = 0; i < elems.length; i++) {
+ if (elems[i].id && elems[i].id.match("A-")) {
+ ids.push(elems[i].id.replace("A-", ""));
+ }
+ }
+
+ return ids;
+
+ } catch (e) {
+ exception_error("get_visible_article_ids", e);
+ }
+}
+
+function catchup_visible_articles(callback) {
+ try {
+
+ var ids = get_visible_article_ids();
+
+ if (confirm(__("Mark %d displayed articles as read?").replace("%d", ids.length))) {
+
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=0&ids=" + param_escape(ids);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ if (callback) callback(transport);
+
+ viewfeed(_active_feed_id, 0);
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("catchup_visible_articles", e);
+ }
+}
+
+function catchup_article(article_id, callback) {
+ try {
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=0&ids=" + article_id;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ if (callback) callback(transport);
+ } });
+
+ } catch (e) {
+ exception_error("catchup_article", e);
+ }
+}
+
+function set_selected_article(article_id) {
+ try {
+ $$("#headlines-content > li[id*=A-]").each(function(article) {
+ var id = article.id.replace("A-", "");
+
+ var cb = article.getElementsByTagName("INPUT")[0];
+
+ if (id == article_id) {
+ article.addClassName("selected");
+ cb.checked = true;
+ } else {
+ article.removeClassName("selected");
+ cb.checked = false;
+ }
+
+ });
+
+ } catch (e) {
+ exception_error("mark_selected_feed", e);
+ }
+}
+
+
+function set_selected_feed(feed_id) {
+ try {
+ var feeds = $("feeds-content").getElementsByTagName("LI");
+
+ for (var i = 0; i < feeds.length; i++) {
+ if (feeds[i].id == "F-" + feed_id)
+ feeds[i].className = "selected";
+ else
+ feeds[i].className = "";
+ }
+
+ _active_feed_id = feed_id;
+
+ } catch (e) {
+ exception_error("mark_selected_feed", e);
+ }
+}
+
+function load_more() {
+ try {
+ var pr = $("H-LOADING-IMG");
+
+ if (pr) Element.show(pr);
+
+ var offset = $$("#headlines-content > li[id*=A-][class*=fresh],li[id*=A-][class*=unread]").length;
+
+ viewfeed(false, offset, false, false, true,
+ function() {
+ var pr = $("H-LOADING-IMG");
+
+ if (pr) Element.hide(pr);
+ });
+ } catch (e) {
+ exception_error("load_more", e);
+ }
+}
+
+function update(callback) {
+ try {
+ console.log('updating feeds...');
+
+ window.clearTimeout(_update_timeout);
+
+ new Ajax.Request("backend.php", {
+ parameters: "?op=rpc&subop=digest-init",
+ onComplete: function(transport) {
+ fatal_error_check(transport);
+ parse_feeds(transport);
+ set_selected_feed(_active_feed_id);
+
+ if (callback) callback(transport);
+ } });
+
+ _update_timeout = window.setTimeout('update()', 5*1000);
+ } catch (e) {
+ exception_error("update", e);
+ }
+}
+
+function remove_headline_entry(article_id) {
+ try {
+ var elem = $('A-' + article_id);
+
+ if (elem) {
+ elem.parentNode.removeChild(elem);
+ }
+
+ } catch (e) {
+ exception_error("remove_headline_entry", e);
+ }
+}
+
+function view_update() {
+ try {
+ viewfeed(_active_feed_id, _active_feed_offset, false, true, true);
+ update();
+ } catch (e) {
+ exception_error("view_update", e);
+ }
+}
+
+function view(article_id) {
+ try {
+ $("content").addClassName("move");
+
+ var a = $("A-" + article_id);
+ var h = $("headlines");
+
+ setTimeout(function() {
+ // below or above viewport, reposition headline
+ if (a.offsetTop > h.scrollTop + h.offsetHeight || a.offsetTop+a.offsetHeight < h.scrollTop+a.offsetHeight)
+ h.scrollTop = a.offsetTop - (h.offsetHeight/2 - a.offsetHeight/2);
+ }, 500);
+
+ new Ajax.Request("backend.php", {
+ parameters: "?op=rpc&subop=digest-get-contents&article_id=" +
+ article_id,
+ onComplete: function(transport) {
+ fatal_error_check(transport);
+
+ var reply = JSON.parse(transport.responseText);
+
+ if (reply) {
+ var article = reply['article'];
+
+ var mark_part = "";
+ var publ_part = "";
+
+ var tags_part = "";
+
+ if (article.tags.length > 0) {
+ tags_part = " " + __("in") + " ";
+
+ for (var i = 0; i < Math.min(5, article.tags.length); i++) {
+ //tags_part += "<a href=\"#\" onclick=\"viewfeed('" +
+ // article.tags[i] + "')\">" +
+ // article.tags[i] + "</a>, ";
+
+ tags_part += article.tags[i] + ", ";
+ }
+
+ tags_part = tags_part.replace(/, $/, "");
+ tags_part = "<span class=\"tags\">" + tags_part + "</span>";
+
+ }
+
+ if (article.marked)
+ mark_part = "<img title='"+ __("Unstar article")+"' onclick=\"toggle_mark(this, "+article.id+")\" src='images/mark_set.png'>";
+ else
+ mark_part = "<img title='"+__("Star article")+"' onclick=\"toggle_mark(this, "+article.id+")\" src='images/mark_unset.png'>";
+
+ if (article.published)
+ publ_part = "<img title='"+__("Unpublish article")+"' onclick=\"toggle_pub(this, "+article.id+")\" src='images/pub_set.png'>";
+ else
+ publ_part = "<img title='"+__("Publish article")+"' onclick=\"toggle_pub(this, "+article.id+")\" src='images/pub_unset.png'>";
+
+ var tmp = "<div id=\"toolbar\">" +
+ "<a target=\"_blank\" href=\""+article.url+"\">" + __("Original article") + "</a>" +
+ "<div style=\"float : right\"><a href=\"#\" onclick=\"close_article()\">" +
+ __("Close this panel") + "</a></div></div>" +
+ "<div id=\"inner\">" +
+ "<div id=\"ops\">" +
+ mark_part +
+ publ_part +
+ "</div>" +
+ "<h1>" + article.title + "</h1>" +
+ "<div id=\"tags\">" +
+ tags_part +
+ "</div>" +
+ article.content + "</div>";
+
+ $("article-content").innerHTML = tmp;
+ $("article").addClassName("visible");
+
+ set_selected_article(article.id);
+
+ catchup_article(article_id,
+ function() {
+ $("A-" + article_id).addClassName("read");
+ });
+
+ } else {
+ elem.innerHTML = __("Error: unable to load article.");
+ }
+ }
+ });
+
+
+ return false;
+ } catch (e) {
+ exception_error("view", e);
+ }
+}
+
+function close_article() {
+ $("content").removeClassName("move");
+ $("article").removeClassName("visible");
+}
+
+function viewfeed(feed_id, offset, replace, no_effects, no_indicator, callback) {
+ try {
+
+ if (!feed_id) feed_id = _active_feed_id;
+ if (offset == undefined) offset = 0;
+ if (replace == undefined) replace = (offset == 0);
+
+ _update_seq = _update_seq + 1;
+
+ if (!offset) $("headlines").scrollTop = 0;
+
+ var query = "backend.php?op=rpc&subop=digest-update&feed_id=" +
+ param_escape(feed_id) + "&offset=" + offset +
+ "&seq=" + _update_seq;
+
+ console.log(query);
+
+ var img = false;
+
+ if ($("F-" + feed_id)) {
+ img = $("F-" + feed_id).getElementsByTagName("IMG")[0];
+
+ if (img && !no_indicator) {
+ img.setAttribute("orig_src", img.src);
+ img.src = 'images/indicator_tiny.gif';
+ }
+ }
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ Element.hide("overlay");
+
+ fatal_error_check(transport);
+ parse_headlines(transport, replace, no_effects);
+ set_selected_feed(feed_id);
+ _active_feed_offset = offset;
+
+ if (img && !no_indicator)
+ img.src = img.getAttribute("orig_src");
+
+ if (callback) callback(transport);
+
+ } });
+
+ } catch (e) {
+ exception_error("view", e);
+ }
+}
+
+function find_article(articles, article_id) {
+ try {
+ for (var i = 0; i < articles.length; i++) {
+ if (articles[i].id == article_id)
+ return articles[i];
+ }
+
+ return false;
+
+ } catch (e) {
+ exception_error("find_article", e);
+ }
+}
+
+function find_feed(feeds, feed_id) {
+ try {
+ for (var i = 0; i < feeds.length; i++) {
+ if (feeds[i].id == feed_id)
+ return feeds[i];
+ }
+
+ return false;
+
+ } catch (e) {
+ exception_error("find_feed", e);
+ }
+}
+
+function get_feed_icon(feed) {
+ try {
+ if (feed.has_icon)
+ return getInitParam('icons_url') + "/" + feed.id + '.ico';
+
+ if (feed.id == -1)
+ return 'images/mark_set.png';
+
+ if (feed.id == -2)
+ return 'images/pub_set.png';
+
+ if (feed.id == -3)
+ return 'images/fresh.png';
+
+ if (feed.id == -4)
+ return 'images/tag.png';
+
+ if (feed.id < -10)
+ return 'images/label.png';
+
+ return 'images/blank_icon.gif';
+
+ } catch (e) {
+ exception_error("get_feed_icon", e);
+ }
+}
+
+function add_feed_entry(feed) {
+ try {
+ var icon_part = "";
+
+ icon_part = "<img src='" + get_feed_icon(feed) + "'/>";
+
+ var tmp_html = "<li id=\"F-"+feed.id+"\" onclick=\"viewfeed("+feed.id+")\">" +
+ icon_part + feed.title +
+ "<div class='unread-ctr'>" + "<span class=\"unread\">" + feed.unread + "</span>" +
+ "</div>" + "</li>";
+
+ $("feeds-content").innerHTML += tmp_html;
+
+
+ } catch (e) {
+ exception_error("add_feed_entry", e);
+ }
+}
+
+function add_headline_entry(article, feed, no_effects) {
+ try {
+
+ var icon_part = "";
+
+ icon_part = "<img class='icon' src='" + get_feed_icon(feed) + "'/>";
+
+
+ var style = "";
+
+ //if (!no_effects) style = "style=\"display : none\"";
+
+ if (article.excerpt.trim() == "")
+ article.excerpt = __("Click to expand article.");
+
+ var li_class = "unread";
+
+ var fresh_max = getInitParam("fresh_article_max_age") * 60 * 60;
+ var d = new Date();
+
+ if (d.getTime() / 1000 - article.updated < fresh_max)
+ li_class = "fresh";
+
+ //"<img title='" + __("Share on Twitter") + "' onclick=\"tweet_article("+article.id+", true)\" src='images/art-tweet.png'>" +
+
+ //"<img title='" + __("Mark as read") + "' onclick=\"view("+article.id+", true)\" src='images/digest_checkbox.png'>" +
+
+ var checkbox_part = "<input type=\"checkbox\" class=\"cb\" onclick=\"toggle_select_article(this)\"/>";
+
+ var date = new Date(article.updated * 1000);
+
+ var date_part = date.toString().substring(0,21);
+
+ var tmp_html = "<li id=\"A-"+article.id+"\" "+style+" class=\""+li_class+"\">" +
+ checkbox_part +
+ icon_part +
+ "<a target=\"_blank\" href=\""+article.link+"\""+
+ "onclick=\"return view("+article.id+")\" class='title'>" +
+ article.title + "</a>" +
+ "<div class='body'>" +
+ "<div onclick=\"view("+article.id+")\" class='excerpt'>" +
+ article.excerpt + "</div>" +
+ "<div class='info'>";
+
+/* tmp_html += "<a href=\#\" onclick=\"viewfeed("+feed.id+")\">" +
+ feed.title + "</a> " + " @ "; */
+
+ tmp_html += date_part + "</div>" +
+ "</div></li>";
+
+ $("headlines-content").innerHTML += tmp_html;
+
+ if (!no_effects)
+ window.setTimeout('article_appear(' + article.id + ')', 100);
+
+ } catch (e) {
+ exception_error("add_headline_entry", e);
+ }
+}
+
+function expand_feeds() {
+ try {
+ _feedlist_expanded = true;
+
+ redraw_feedlist(last_feeds);
+
+ } catch (e) {
+ exception_error("expand_feeds", e);
+ }
+}
+
+function redraw_feedlist(feeds) {
+ try {
+
+ $('feeds-content').innerHTML = "";
+
+ var limit = 10;
+
+ if (_feedlist_expanded) limit = feeds.length;
+
+ for (var i = 0; i < Math.min(limit, feeds.length); i++) {
+ add_feed_entry(feeds[i]);
+ }
+
+ if (feeds.length > limit) {
+ $('feeds-content').innerHTML += "<li id='F-MORE-PROMPT'>" +
+ "<img src='images/blank_icon.gif'>" +
+ "<a href=\"#\" onclick=\"expand_feeds()\">" +
+ __("%d more...").replace("%d", feeds.length-10) +
+ "</a>" + "</li>";
+ }
+
+ if (feeds.length == 0) {
+ $('feeds-content').innerHTML =
+ "<div class='insensitive' style='text-align : center'>" +
+ __("No unread feeds.") + "</div>";
+ }
+
+ if (_active_feed_id)
+ set_selected_feed(_active_feed_id);
+
+ } catch (e) {
+ exception_error("redraw_feedlist", e);
+ }
+}
+
+function parse_feeds(transport) {
+ try {
+ var reply = JSON.parse(transport.responseText);
+
+ if (!reply) return;
+
+ var feeds = reply['feeds'];
+
+ if (feeds) {
+
+ feeds.sort( function (a,b)
+ {
+ if (b.unread != a.unread)
+ return (b.unread - a.unread);
+ else
+ if (a.title > b.title)
+ return 1;
+ else if (a.title < b.title)
+ return -1;
+ else
+ return 0;
+ });
+
+ var all_articles = find_feed(feeds, -4);
+
+ update_title(all_articles.unread);
+
+ last_feeds = feeds;
+
+ redraw_feedlist(feeds);
+ }
+
+ } catch (e) {
+ exception_error("parse_feeds", e);
+ }
+}
+
+function parse_headlines(transport, replace, no_effects) {
+ try {
+ var reply = JSON.parse(transport.responseText);
+ if (!reply) return;
+
+ var seq = reply['seq'];
+
+ if (seq) {
+ if (seq != _update_seq) {
+ console.log("parse_headlines: wrong sequence received.");
+ return;
+ }
+ } else {
+ return;
+ }
+
+ var headlines = reply['headlines']['content'];
+ var headlines_title = reply['headlines']['title'];
+
+ if (headlines && headlines_title) {
+
+ if (replace) {
+ $('headlines-content').innerHTML = '';
+ }
+
+ var pr = $('H-MORE-PROMPT');
+
+ if (pr) pr.parentNode.removeChild(pr);
+
+ var inserted = false;
+
+ for (var i = 0; i < headlines.length; i++) {
+
+ if (!$('A-' + headlines[i].id)) {
+ add_headline_entry(headlines[i],
+ find_feed(last_feeds, headlines[i].feed_id), !no_effects);
+
+ }
+ }
+
+ console.log(inserted.id);
+
+ var ids = get_visible_article_ids();
+
+ if (ids.length > 0) {
+ if (pr) {
+ $('headlines-content').appendChild(pr);
+
+ } else {
+ $('headlines-content').innerHTML += "<li id='H-MORE-PROMPT'>" +
+ "<div class='body'>" +
+ "<a href=\"#\" onclick=\"catchup_visible_articles()\">" +
+ __("Mark as read") + "</a> | " +
+ "<a href=\"javascript:load_more()\">" +
+ __("Load more...") + "</a>" +
+ "<img style=\"display : none\" "+
+ "id=\"H-LOADING-IMG\" src='images/indicator_tiny.gif'>" +
+ "</div></li>";
+ }
+ } else {
+ // FIXME : display some kind of "nothing to see here" prompt here
+ }
+
+// if (replace && !no_effects)
+// new Effect.Appear('headlines-content', {duration : 0.3});
+
+ //new Effect.Appear('headlines-content');
+ }
+
+ } catch (e) {
+ exception_error("parse_headlines", e);
+ }
+}
+
+function init_second_stage() {
+ try {
+ new Ajax.Request("backend.php", {
+ parameters: "backend.php?op=rpc&subop=digest-init",
+ onComplete: function(transport) {
+ parse_feeds(transport);
+ Element.hide("overlay");
+
+ window.setTimeout('viewfeed(-4)', 100);
+ _update_timeout = window.setTimeout('update()', 5*1000);
+ } });
+
+ } catch (e) {
+ exception_error("init_second_stage", e);
+ }
+}
+
+function init() {
+ try {
+ dojo.require("dijit.Dialog");
+
+ new Ajax.Request("backend.php", {
+ parameters: "?op=rpc&subop=sanityCheck",
+ onComplete: function(transport) {
+ backend_sanity_check_callback(transport);
+ } });
+
+ } catch (e) {
+ exception_error("digest_init", e);
+ }
+}
+
+function toggle_mark(img, id) {
+
+ try {
+
+ var query = "?op=rpc&id=" + id + "&subop=mark";
+
+ if (!img) return;
+
+ if (img.src.match("mark_unset")) {
+ img.src = img.src.replace("mark_unset", "mark_set");
+ img.alt = __("Unstar article");
+ query = query + "&mark=1";
+ } else {
+ img.src = img.src.replace("mark_set", "mark_unset");
+ img.alt = __("Star article");
+ query = query + "&mark=0";
+ }
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ update();
+ } });
+
+ } catch (e) {
+ exception_error("toggle_mark", e);
+ }
+}
+
+function toggle_pub(img, id, note) {
+
+ try {
+
+ var query = "?op=rpc&id=" + id + "&subop=publ";
+
+ if (note != undefined) {
+ query = query + "¬e=" + param_escape(note);
+ } else {
+ query = query + "¬e=undefined";
+ }
+
+ if (!img) return;
+
+ if (img.src.match("pub_unset") || note != undefined) {
+ img.src = img.src.replace("pub_unset", "pub_set");
+ img.alt = __("Unpublish article");
+ query = query + "&pub=1";
+
+ } else {
+ img.src = img.src.replace("pub_set", "pub_unset");
+ img.alt = __("Publish article");
+ query = query + "&pub=0";
+ }
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ update();
+ } });
+
+ } catch (e) {
+ exception_error("toggle_pub", e);
+ }
+}
+
+function fatal_error(code, msg) {
+ try {
+
+ if (code == 6) {
+ window.location.href = "digest.php";
+ } else if (code == 5) {
+ window.location.href = "db-updater.php";
+ } else {
+
+ if (msg == "") msg = "Unknown error";
+
+ console.error("Fatal error: " + code + "\n" +
+ msg);
+
+ }
+
+ } catch (e) {
+ exception_error("fatalError", e);
+ }
+}
+
+function fatal_error_check(transport) {
+ try {
+ if (transport.responseXML) {
+ var error = transport.responseXML.getElementsByTagName("error")[0];
+
+ if (error) {
+ var code = error.getAttribute("error-code");
+ var msg = error.getAttribute("error-msg");
+ if (code != 0) {
+ fatal_error(code, msg);
+ return false;
+ }
+ }
+ }
+ } catch (e) {
+ exception_error("fatal_error_check", e);
+ }
+ return true;
+}
+
+function update_title(unread) {
+ try {
+ document.title = "Tiny Tiny RSS";
+
+ if (unread > 0)
+ document.title += " (" + unread + ")";
+
+ } catch (e) {
+ exception_error("update_title", e);
+ }
+}
+
+function tweet_article(id) {
+ try {
+
+ var query = "?op=rpc&subop=getTweetInfo&id=" + param_escape(id);
+
+ console.log(query);
+
+ var d = new Date();
+ var ts = d.getTime();
+
+ var w = window.open('backend.php?op=loading', 'ttrss_tweet',
+ "status=0,toolbar=0,location=0,width=500,height=400,scrollbars=1,menubar=0");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var ti = JSON.parse(transport.responseText);
+
+ var share_url = "http://twitter.com/share?_=" + ts +
+ "&text=" + param_escape(ti.title) +
+ "&url=" + param_escape(ti.link);
+
+ w.location.href = share_url;
+
+ } });
+
+ } catch (e) {
+ exception_error("tweet_article", e);
+ }
+}
+
+function toggle_select_article(elem) {
+ try {
+ var article = elem.parentNode;
+
+ if (article.hasClassName("selected"))
+ article.removeClassName("selected");
+ else
+ article.addClassName("selected");
+
+ } catch (e) {
+ exception_error("toggle_select_article", e);
+ }
+}
--- /dev/null
+var _infscroll_disable = 0;
+var _infscroll_request_sent = 0;
+var _search_query = false;
+
+var counter_timeout_id = false;
+
+var counters_last_request = 0;
+
+function viewCategory(cat) {
+ viewfeed(cat, '', true);
+ return false;
+}
+
+function loadMoreHeadlines() {
+ try {
+ console.log("loadMoreHeadlines");
+
+ var offset = 0;
+
+ var view_mode = document.forms["main_toolbar_form"].view_mode.value;
+ var num_unread = $$("#headlines-frame > div[id*=RROW][class*=Unread]").length;
+ var num_all = $$("#headlines-frame > div[id*=RROW]").length;
+
+ // TODO implement marked & published
+
+ if (view_mode == "marked") {
+ console.warn("loadMoreHeadlines: marked is not implemented, falling back.");
+ offset = num_all;
+ } else if (view_mode == "published") {
+ console.warn("loadMoreHeadlines: published is not implemented, falling back.");
+ offset = num_all;
+ } else if (view_mode == "unread") {
+ offset = num_unread;
+ } else if (view_mode == "adaptive") {
+ if (num_unread > 0)
+ offset = num_unread;
+ else
+ offset = num_all;
+ } else {
+ offset = num_all;
+ }
+
+ viewfeed(getActiveFeedId(), '', activeFeedIsCat(), offset, false, true);
+
+ } catch (e) {
+ exception_error("viewNextFeedPage", e);
+ }
+}
+
+
+function viewfeed(feed, subop, is_cat, offset, background, infscroll_req) {
+ try {
+ if (is_cat == undefined)
+ is_cat = false;
+ else
+ is_cat = !!is_cat;
+
+ if (subop == undefined) subop = '';
+ if (offset == undefined) offset = 0;
+ if (background == undefined) background = false;
+ if (infscroll_req == undefined) infscroll_req = false;
+
+ last_requested_article = 0;
+
+ var cached_headlines = false;
+
+ if (feed == getActiveFeedId()) {
+ cache_delete("feed:" + feed + ":" + is_cat);
+ } else {
+ cached_headlines = cache_get("feed:" + feed + ":" + is_cat);
+
+ // switching to a different feed, we might as well catchup stuff visible
+ // in headlines buffer (if any)
+ if (!background && getInitParam("cdm_auto_catchup") == 1 && parseInt(getActiveFeedId()) > 0) {
+
+ $$("#headlines-frame > div[id*=RROW][class*=Unread]").each(
+ function(child) {
+ var hf = $("headlines-frame");
+
+ if (hf.scrollTop + hf.offsetHeight >=
+ child.offsetTop + child.offsetHeight) {
+
+ var id = child.id.replace("RROW-", "");
+
+ if (catchup_id_batch.indexOf(id) == -1)
+ catchup_id_batch.push(id);
+
+ }
+
+ if (catchup_id_batch.length > 0) {
+ window.clearTimeout(catchup_timeout_id);
+
+ if (!_infscroll_request_sent) {
+ catchup_timeout_id = window.setTimeout('catchupBatchedArticles()',
+ 2000);
+ }
+ }
+
+ });
+ }
+ }
+
+ if (offset == 0 && !background)
+ dijit.byId("content-tabs").selectChild(
+ dijit.byId("content-tabs").getChildren()[0]);
+
+ if (!background) {
+ if (getActiveFeedId() != feed || offset == 0) {
+ active_post_id = 0;
+ _infscroll_disable = 0;
+ }
+
+ if (!offset && !subop && cached_headlines && !background) {
+ try {
+ render_local_headlines(feed, is_cat, JSON.parse(cached_headlines));
+ return;
+ } catch (e) {
+ console.warn("render_local_headlines failed: " + e);
+ }
+ }
+
+ if (offset != 0 && !subop) {
+ var date = new Date();
+ var timestamp = Math.round(date.getTime() / 1000);
+
+ if (_infscroll_request_sent && _infscroll_request_sent + 30 > timestamp) {
+ //console.log("infscroll request in progress, aborting");
+ return;
+ }
+
+ _infscroll_request_sent = timestamp;
+ }
+
+ hideAuxDlg();
+ }
+
+ Form.enable("main_toolbar_form");
+
+ var toolbar_query = Form.serialize("main_toolbar_form");
+
+ var query = "?op=viewfeed&feed=" + feed + "&" +
+ toolbar_query + "&subop=" + param_escape(subop);
+
+ if (!background) {
+ if (_search_query) {
+ force_nocache = true;
+ query = query + "&" + _search_query;
+ _search_query = false;
+ }
+
+ if (subop == "MarkAllRead") {
+
+ var show_next_feed = getInitParam("on_catchup_show_next_feed") == "1";
+
+ if (show_next_feed) {
+ var nuf = getNextUnreadFeed(feed, is_cat);
+
+ if (nuf) {
+ var cached_nuf = cache_get("feed:" + nuf + ":false");
+
+ if (cached_nuf) {
+
+ render_local_headlines(nuf, false, JSON.parse(cached_nuf));
+
+ var catchup_query = "?op=rpc&subop=catchupFeed&feed_id=" +
+ feed + "&is_cat=" + is_cat;
+
+ console.log(catchup_query);
+
+ new Ajax.Request("backend.php", {
+ parameters: catchup_query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+
+ return;
+ } else {
+ query += "&nuf=" + param_escape(nuf);
+ }
+ }
+ }
+ }
+
+ if (offset != 0) {
+ query = query + "&skip=" + offset;
+
+ // to prevent duplicate feed titles when showing grouped vfeeds
+ if (vgroup_last_feed) {
+ query = query + "&vgrlf=" + param_escape(vgroup_last_feed);
+ }
+ }
+
+ Form.enable("main_toolbar_form");
+
+ if (!offset)
+ if (!is_cat) {
+ if (!setFeedExpandoIcon(feed, is_cat, 'images/indicator_white.gif'))
+ notify_progress("Loading, please wait...", true);
+ } else {
+ notify_progress("Loading, please wait...", true);
+ }
+ }
+
+ query += "&cat=" + is_cat;
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ setFeedExpandoIcon(feed, is_cat, 'images/blank_icon.gif');
+ headlines_callback2(transport, offset, background, infscroll_req);
+ } });
+
+ } catch (e) {
+ exception_error("viewfeed", e);
+ }
+}
+
+function feedlist_init() {
+ try {
+ console.log("in feedlist init");
+
+ hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
+ document.onkeydown = hotkey_handler;
+ setTimeout("hotkey_prefix_timeout()", 5*1000);
+
+ if (!getActiveFeedId()) {
+ setTimeout("viewfeed(-3)", 100);
+ }
+
+ console.log("T:" +
+ getInitParam("cdm_auto_catchup") + " " + getFeedUnread(-3));
+
+ hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
+
+ setTimeout("timeout()", 5000);
+ setTimeout("precache_headlines_idle()", 3000);
+
+ } catch (e) {
+ exception_error("feedlist/init", e);
+ }
+}
+
+function request_counters_real() {
+ try {
+ console.log("requesting counters...");
+
+ var query = "?op=rpc&subop=getAllCounters&seq=" + next_seq();
+
+ query = query + "&omode=flc";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ try {
+ handle_rpc_json(transport);
+ } catch (e) {
+ exception_error("viewfeed/getcounters", e);
+ }
+ } });
+
+ } catch (e) {
+ exception_error("request_counters_real", e);
+ }
+}
+
+
+function request_counters() {
+
+ try {
+
+ if (getInitParam("bw_limit") == "1") return;
+
+ var date = new Date();
+ var timestamp = Math.round(date.getTime() / 1000);
+
+ if (timestamp - counters_last_request > 5) {
+ console.log("scheduling request of counters...");
+
+ window.clearTimeout(counter_timeout_id);
+ counter_timeout_id = window.setTimeout("request_counters_real()", 1000);
+
+ counters_last_request = timestamp;
+ } else {
+ console.log("request_counters: rate limit reached: " + (timestamp - counters_last_request));
+ }
+
+ } catch (e) {
+ exception_error("request_counters", e);
+ }
+}
+
+function displayNewContentPrompt(id) {
+ try {
+
+ var msg = "<a href='#' onclick='viewCurrentFeed()'>" +
+ __("New articles available in this feed (click to show)") + "</a>";
+
+ msg = msg.replace("%s", getFeedName(id));
+
+ $('auxDlg').innerHTML = msg;
+
+ new Effect.Appear('auxDlg', {duration : 0.5});
+
+ } catch (e) {
+ exception_error("displayNewContentPrompt", e);
+ }
+}
+
+function parse_counters(elems, scheduled_call) {
+ try {
+ for (var l = 0; l < elems.length; l++) {
+
+ var id = elems[l].id;
+ var kind = elems[l].kind;
+ var ctr = parseInt(elems[l].counter);
+ var error = elems[l].error;
+ var has_img = elems[l].has_img;
+ var updated = elems[l].updated;
+
+ if (id == "global-unread") {
+ global_unread = ctr;
+ updateTitle();
+ continue;
+ }
+
+ if (id == "subscribed-feeds") {
+ feeds_found = ctr;
+ continue;
+ }
+
+ // TODO: enable new content notification for categories
+
+ if (!activeFeedIsCat() && id == getActiveFeedId()
+ && ctr > getFeedUnread(id) && scheduled_call) {
+ displayNewContentPrompt(id);
+ }
+
+ if (getFeedUnread(id, (kind == "cat")) != ctr)
+ cache_delete("feed:" + id + ":" + (kind == "cat"));
+
+ setFeedUnread(id, (kind == "cat"), ctr);
+
+ if (kind != "cat") {
+ setFeedValue(id, false, 'error', error);
+ setFeedValue(id, false, 'updated', updated);
+
+ if (id > 0) {
+ if (has_img) {
+ setFeedIcon(id, false,
+ getInitParam("icons_url") + "/" + id + ".ico");
+ } else {
+ setFeedIcon(id, false, 'images/blank_icon.gif');
+ }
+ }
+ }
+ }
+
+ hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
+
+ } catch (e) {
+ exception_error("parse_counters", e);
+ }
+}
+
+function getFeedUnread(feed, is_cat) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree && tree.model)
+ return tree.model.getFeedUnread(feed, is_cat);
+
+ } catch (e) {
+ //
+ }
+
+ return -1;
+}
+
+function hideOrShowFeeds(hide) {
+ var tree = dijit.byId("feedTree");
+
+ if (tree)
+ return tree.hideRead(hide, getInitParam("hide_read_shows_special"));
+}
+
+function getFeedName(feed, is_cat) {
+ var tree = dijit.byId("feedTree");
+
+ if (tree && tree.model)
+ return tree.model.getFeedValue(feed, is_cat, 'name');
+}
+
+function getFeedValue(feed, is_cat, key) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree && tree.model)
+ return tree.model.getFeedValue(feed, is_cat, key);
+
+ } catch (e) {
+ //
+ }
+ return '';
+}
+
+function setFeedUnread(feed, is_cat, unread) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree && tree.model)
+ return tree.model.setFeedUnread(feed, is_cat, unread);
+
+ } catch (e) {
+ exception_error("setFeedUnread", e);
+ }
+}
+
+function setFeedValue(feed, is_cat, key, value) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree && tree.model)
+ return tree.model.setFeedValue(feed, is_cat, key, value);
+
+ } catch (e) {
+ //
+ }
+}
+
+function selectFeed(feed, is_cat) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree) return tree.selectFeed(feed, is_cat);
+
+ } catch (e) {
+ exception_error("selectFeed", e);
+ }
+}
+
+function setFeedIcon(feed, is_cat, src) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree) return tree.setFeedIcon(feed, is_cat, src);
+
+ } catch (e) {
+ exception_error("setFeedIcon", e);
+ }
+}
+
+function setFeedExpandoIcon(feed, is_cat, src) {
+ try {
+ var tree = dijit.byId("feedTree");
+
+ if (tree) return tree.setFeedExpandoIcon(feed, is_cat, src);
+
+ } catch (e) {
+ exception_error("setFeedIcon", e);
+ }
+ return false;
+}
+
+function getNextUnreadFeed(feed, is_cat) {
+ try {
+ var tree = dijit.byId("feedTree");
+ var nuf = tree.model.getNextUnreadFeed(feed, is_cat);
+
+ if (nuf)
+ return tree.model.store.getValue(nuf, 'bare_id');
+
+ } catch (e) {
+ exception_error("getNextUnreadFeed", e);
+ }
+}
+
+function catchupFeed(feed, is_cat) {
+ try {
+ var str = __("Mark all articles in %s as read?");
+ var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
+
+ str = str.replace("%s", fn);
+
+ if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
+ return;
+ }
+
+ var catchup_query = "?op=rpc&subop=catchupFeed&feed_id=" +
+ feed + "&is_cat=" + is_cat;
+
+ notify_progress("Loading, please wait...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: catchup_query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ notify("");
+ } });
+
+ } catch (e) {
+ exception_error("catchupFeed", e);
+ }
+}
--- /dev/null
+var notify_silent = false;
+var loading_progress = 0;
+var sanity_check_done = false;
+
+/* add method to remove element from array */
+
+Array.prototype.remove = function(s) {
+ for (var i=0; i < this.length; i++) {
+ if (s == this[i]) this.splice(i, 1);
+ }
+};
+
+/* create console.log if it doesn't exist */
+
+if (!window.console) console = {};
+console.log = console.log || function(msg) { };
+console.warn = console.warn || function(msg) { };
+console.error = console.error || function(msg) { };
+
+function exception_error(location, e, ext_info) {
+ var msg = format_exception_error(location, e);
+
+ if (!ext_info) ext_info = false;
+
+ try {
+
+ if (ext_info) {
+ if (ext_info.responseText) {
+ ext_info = ext_info.responseText;
+ }
+ }
+
+ var content = "<div class=\"fatalError\">" +
+ "<pre>" + msg + "</pre>";
+
+ content += "<form name=\"exceptionForm\" id=\"exceptionForm\" target=\"_blank\" "+
+ "action=\"http://tt-rss.org/report.php\" method=\"POST\">";
+
+ content += "<textarea style=\"display : none\" name=\"message\">" + msg + "</textarea>";
+ content += "<textarea style=\"display : none\" name=\"params\">N/A</textarea>";
+
+ if (ext_info) {
+ content += "<div><b>Additional information:</b></div>" +
+ "<textarea name=\"xinfo\" readonly=\"1\">" + ext_info + "</textarea>";
+ }
+
+ content += "<div><b>Stack trace:</b></div>" +
+ "<textarea name=\"stack\" readonly=\"1\">" + e.stack + "</textarea>";
+
+ content += "</form>";
+
+ content += "</div>";
+
+ content += "<div class='dlgButtons'>";
+
+ content += "<button dojoType=\"dijit.form.Button\""+
+ "onclick=\"dijit.byId('exceptionDlg').report()\">" +
+ __('Report to tt-rss.org') + "</button> ";
+ content += "<button dojoType=\"dijit.form.Button\" "+
+ "onclick=\"dijit.byId('exceptionDlg').hide()\">" +
+ __('Close') + "</button>";
+ content += "</div>";
+
+ if (dijit.byId("exceptionDlg"))
+ dijit.byId("exceptionDlg").destroyRecursive();
+
+ var dialog = new dijit.Dialog({
+ id: "exceptionDlg",
+ title: "Unhandled exception",
+ style: "width: 600px",
+ report: function() {
+ if (confirm(__("Are you sure to report this exception to tt-rss.org? The report will include your browser information. Your IP would be saved in the database."))) {
+
+ document.forms['exceptionForm'].params.value = $H({
+ browserName: navigator.appName,
+ browserVersion: navigator.appVersion,
+ browserPlatform: navigator.platform,
+ browserCookies: navigator.cookieEnabled,
+ }).toQueryString();
+
+ document.forms['exceptionForm'].submit();
+
+ }
+ },
+ content: content});
+
+ dialog.show();
+
+ } catch (e) {
+ alert(msg);
+ }
+
+}
+
+function format_exception_error(location, e) {
+ var msg;
+
+ if (e.fileName) {
+ var base_fname = e.fileName.substring(e.fileName.lastIndexOf("/") + 1);
+
+ msg = "Exception: " + e.name + ", " + e.message +
+ "\nFunction: " + location + "()" +
+ "\nLocation: " + base_fname + ":" + e.lineNumber;
+
+ } else if (e.description) {
+ msg = "Exception: " + e.description + "\nFunction: " + location + "()";
+ } else {
+ msg = "Exception: " + e + "\nFunction: " + location + "()";
+ }
+
+ console.error("EXCEPTION: " + msg);
+
+ return msg;
+}
+
+function param_escape(arg) {
+ if (typeof encodeURIComponent != 'undefined')
+ return encodeURIComponent(arg);
+ else
+ return escape(arg);
+}
+
+function param_unescape(arg) {
+ if (typeof decodeURIComponent != 'undefined')
+ return decodeURIComponent(arg);
+ else
+ return unescape(arg);
+}
+
+var notify_hide_timerid = false;
+
+function hide_notify() {
+ var n = $("notify");
+ if (n) {
+ n.style.display = "none";
+ }
+}
+
+function notify_silent_next() {
+ notify_silent = true;
+}
+
+function notify_real(msg, no_hide, n_type) {
+
+ if (notify_silent) {
+ notify_silent = false;
+ return;
+ }
+
+ var n = $("notify");
+ var nb = $("notify_body");
+
+ if (!n || !nb) return;
+
+ if (notify_hide_timerid) {
+ window.clearTimeout(notify_hide_timerid);
+ }
+
+ if (msg == "") {
+ if (n.style.display == "block") {
+ notify_hide_timerid = window.setTimeout("hide_notify()", 0);
+ }
+ return;
+ } else {
+ n.style.display = "block";
+ }
+
+ /* types:
+
+ 1 - generic
+ 2 - progress
+ 3 - error
+ 4 - info
+
+ */
+
+ if (typeof __ != 'undefined') {
+ msg = __(msg);
+ }
+
+ if (n_type == 1) {
+ n.className = "notify";
+ } else if (n_type == 2) {
+ n.className = "notifyProgress";
+ msg = "<img src='"+getInitParam("sign_progress")+"'> " + msg;
+ } else if (n_type == 3) {
+ n.className = "notifyError";
+ msg = "<img src='"+getInitParam("sign_excl")+"'> " + msg;
+ } else if (n_type == 4) {
+ n.className = "notifyInfo";
+ msg = "<img src='"+getInitParam("sign_info")+"'> " + msg;
+ }
+
+// msg = "<img src='images/live_com_loading.gif'> " + msg;
+
+ nb.innerHTML = msg;
+
+ if (!no_hide) {
+ notify_hide_timerid = window.setTimeout("hide_notify()", 3000);
+ }
+}
+
+function notify(msg, no_hide) {
+ notify_real(msg, no_hide, 1);
+}
+
+function notify_progress(msg, no_hide) {
+ notify_real(msg, no_hide, 2);
+}
+
+function notify_error(msg, no_hide) {
+ notify_real(msg, no_hide, 3);
+
+}
+
+function notify_info(msg, no_hide) {
+ notify_real(msg, no_hide, 4);
+}
+
+function setCookie(name, value, lifetime, path, domain, secure) {
+
+ var d = false;
+
+ if (lifetime) {
+ d = new Date();
+ d.setTime(d.getTime() + (lifetime * 1000));
+ }
+
+ console.log("setCookie: " + name + " => " + value + ": " + d);
+
+ int_setCookie(name, value, d, path, domain, secure);
+
+}
+
+function int_setCookie(name, value, expires, path, domain, secure) {
+ document.cookie= name + "=" + escape(value) +
+ ((expires) ? "; expires=" + expires.toGMTString() : "") +
+ ((path) ? "; path=" + path : "") +
+ ((domain) ? "; domain=" + domain : "") +
+ ((secure) ? "; secure" : "");
+}
+
+function delCookie(name, path, domain) {
+ if (getCookie(name)) {
+ document.cookie = name + "=" +
+ ((path) ? ";path=" + path : "") +
+ ((domain) ? ";domain=" + domain : "" ) +
+ ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
+ }
+}
+
+
+function getCookie(name) {
+
+ var dc = document.cookie;
+ var prefix = name + "=";
+ var begin = dc.indexOf("; " + prefix);
+ if (begin == -1) {
+ begin = dc.indexOf(prefix);
+ if (begin != 0) return null;
+ }
+ else {
+ begin += 2;
+ }
+ var end = document.cookie.indexOf(";", begin);
+ if (end == -1) {
+ end = dc.length;
+ }
+ return unescape(dc.substring(begin + prefix.length, end));
+}
+
+function gotoPreferences() {
+ document.location.href = "prefs.php";
+}
+
+function gotoMain() {
+ document.location.href = "index.php";
+}
+
+function gotoExportOpml(filename, settings) {
+ tmp = settings ? 1 : 0;
+ document.location.href = "opml.php?op=Export&filename=" + filename + "&settings=" + tmp;
+}
+
+
+/** * @(#)isNumeric.js * * Copyright (c) 2000 by Sundar Dorai-Raj
+ * * @author Sundar Dorai-Raj
+ * * Email: sdoraira@vt.edu
+ * * This program is free software; you can redistribute it and/or
+ * * modify it under the terms of the GNU General Public License
+ * * as published by the Free Software Foundation; either version 2
+ * * of the License, or (at your option) any later version,
+ * * provided that any use properly credits the author.
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details at http://www.gnu.org * * */
+
+ var numbers=".0123456789";
+ function isNumeric(x) {
+ // is x a String or a character?
+ if(x.length>1) {
+ // remove negative sign
+ x=Math.abs(x)+"";
+ for(var j=0;j<x.length;j++) {
+ // call isNumeric recursively for each character
+ number=isNumeric(x.substring(j,j+1));
+ if(!number) return number;
+ }
+ return number;
+ }
+ else {
+ // if x is number return true
+ if(numbers.indexOf(x)>=0) return true;
+ return false;
+ }
+ }
+
+
+function toggleSelectRowById(sender, id) {
+ var row = $(id);
+ return toggleSelectRow(sender, row);
+}
+
+function toggleSelectListRow(sender) {
+ var row = sender.parentNode;
+ return toggleSelectRow(sender, row);
+}
+
+/* this is for dijit Checkbox */
+function toggleSelectListRow2(sender) {
+ var row = sender.domNode.parentNode;
+ return toggleSelectRow(sender, row);
+}
+
+function tSR(sender, row) {
+ return toggleSelectRow(sender, row);
+}
+
+/* this is for dijit Checkbox */
+function toggleSelectRow2(sender, row) {
+
+ if (!row) row = sender.domNode.parentNode.parentNode;
+
+ if (sender.checked && !row.hasClassName('Selected'))
+ row.addClassName('Selected');
+ else
+ row.removeClassName('Selected');
+}
+
+
+function toggleSelectRow(sender, row) {
+
+ if (!row) row = sender.parentNode.parentNode;
+
+ if (sender.checked && !row.hasClassName('Selected'))
+ row.addClassName('Selected');
+ else
+ row.removeClassName('Selected');
+}
+
+function checkboxToggleElement(elem, id) {
+ if (elem.checked) {
+ Effect.Appear(id, {duration : 0.5});
+ } else {
+ Effect.Fade(id, {duration : 0.5});
+ }
+}
+
+function dropboxSelect(e, v) {
+ for (var i = 0; i < e.length; i++) {
+ if (e[i].value == v) {
+ e.selectedIndex = i;
+ break;
+ }
+ }
+}
+
+function getURLParam(param){
+ return String(window.location.href).parseQuery()[param];
+}
+
+function leading_zero(p) {
+ var s = String(p);
+ if (s.length == 1) s = "0" + s;
+ return s;
+}
+
+function make_timestamp() {
+ var d = new Date();
+
+ return leading_zero(d.getHours()) + ":" + leading_zero(d.getMinutes()) +
+ ":" + leading_zero(d.getSeconds());
+}
+
+
+function closeInfoBox(cleanup) {
+ try {
+ dialog = dijit.byId("infoBox");
+
+ if (dialog) dialog.hide();
+
+ } catch (e) {
+ //exception_error("closeInfoBox", e);
+ }
+ return false;
+}
+
+
+function displayDlg(id, param, callback) {
+
+ notify_progress("Loading, please wait...", true);
+
+ var query = "?op=dlg&id=" +
+ param_escape(id) + "¶m=" + param_escape(param);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function (transport) {
+ infobox_callback2(transport);
+ if (callback) callback(transport);
+ } });
+
+ return false;
+}
+
+function infobox_callback2(transport) {
+ try {
+ var dialog = false;
+
+ if (dijit.byId("infoBox")) {
+ dialog = dijit.byId("infoBox");
+ }
+
+ //console.log("infobox_callback2");
+ notify('');
+
+ var title = transport.responseXML.getElementsByTagName("title")[0];
+ if (title)
+ title = title.firstChild.nodeValue;
+
+ var content = transport.responseXML.getElementsByTagName("content")[0];
+
+ content = content.firstChild.nodeValue;
+
+ if (!dialog) {
+ dialog = new dijit.Dialog({
+ title: title,
+ id: 'infoBox',
+ style: "width: 600px",
+ onCancel: function() {
+ return true;
+ },
+ onExecute: function() {
+ return true;
+ },
+ onClose: function() {
+ return true;
+ },
+ content: content});
+ } else {
+ dialog.attr('title', title);
+ dialog.attr('content', content);
+ }
+
+ dialog.show();
+
+ notify("");
+ } catch (e) {
+ exception_error("infobox_callback2", e);
+ }
+}
+
+function filterCR(e, f)
+{
+ var key;
+
+ if(window.event)
+ key = window.event.keyCode; //IE
+ else
+ key = e.which; //firefox
+
+ if (key == 13) {
+ if (typeof f != 'undefined') {
+ f();
+ return false;
+ } else {
+ return false;
+ }
+ } else {
+ return true;
+ }
+}
+
+function getInitParam(key) {
+ return init_params[key];
+}
+
+function setInitParam(key, value) {
+ init_params[key] = value;
+}
+
+function fatalError(code, msg, ext_info) {
+ try {
+
+ if (code == 6) {
+ window.location.href = "index.php";
+ } else if (code == 5) {
+ window.location.href = "db-updater.php";
+ } else {
+
+ if (msg == "") msg = "Unknown error";
+
+ if (ext_info) {
+ if (ext_info.responseText) {
+ ext_info = ext_info.responseText;
+ }
+ }
+
+ if (ERRORS && ERRORS[code] && !msg) {
+ msg = ERRORS[code];
+ }
+
+ var content = "<div><b>Error code:</b> " + code + "</div>" +
+ "<p>" + msg + "</p>";
+
+ if (ext_info) {
+ content = content + "<div><b>Additional information:</b></div>" +
+ "<textarea style='width: 100%' readonly=\"1\">" +
+ ext_info + "</textarea>";
+ }
+
+ var dialog = new dijit.Dialog({
+ title: "Fatal error",
+ style: "width: 600px",
+ content: content});
+
+ dialog.show();
+
+ }
+
+ return false;
+
+ } catch (e) {
+ exception_error("fatalError", e);
+ }
+}
+
+function filterDlgCheckType(sender) {
+
+ try {
+
+ var ftype = sender.value;
+
+ // if selected filter type is 5 (Date) enable the modifier dropbox
+ if (ftype == 5) {
+ Element.show("filterDlg_dateModBox");
+ Element.show("filterDlg_dateChkBox");
+ } else {
+ Element.hide("filterDlg_dateModBox");
+ Element.hide("filterDlg_dateChkBox");
+
+ }
+
+ } catch (e) {
+ exception_error("filterDlgCheckType", e);
+ }
+
+}
+
+function filterDlgCheckAction(sender) {
+
+ try {
+
+ var action = sender.value;
+
+ var action_param = $("filterDlg_paramBox");
+
+ if (!action_param) {
+ console.log("filterDlgCheckAction: can't find action param box!");
+ return;
+ }
+
+ // if selected action supports parameters, enable params field
+ if (action == 4 || action == 6 || action == 7) {
+ new Effect.Appear(action_param, {duration : 0.5});
+ if (action != 7) {
+ Element.show(dijit.byId("filterDlg_actionParam").domNode);
+ Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode);
+ } else {
+ Element.show(dijit.byId("filterDlg_actionParamLabel").domNode);
+ Element.hide(dijit.byId("filterDlg_actionParam").domNode);
+ }
+ } else {
+ Element.hide(action_param);
+ }
+
+ } catch (e) {
+ exception_error("filterDlgCheckAction", e);
+ }
+
+}
+
+function filterDlgCheckDate() {
+ try {
+ var dialog = dijit.byId("filterEditDlg");
+
+ var reg_exp = dialog.attr('value').reg_exp;
+
+ var query = "?op=rpc&subop=checkDate&date=" + reg_exp;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+
+ var reply = JSON.parse(transport.responseText);
+
+ if (reply['result'] == true) {
+ alert(__("Date syntax appears to be correct:") + " " + reply['date']);
+ return;
+ } else {
+ alert(__("Date syntax is incorrect."));
+ }
+
+ } });
+
+
+ } catch (e) {
+ exception_error("filterDlgCheckDate", e);
+ }
+}
+
+function explainError(code) {
+ return displayDlg("explainError", code);
+}
+
+function displayHelpInfobox(topic_id) {
+
+ var url = "backend.php?op=help&tid=" + param_escape(topic_id);
+
+ window.open(url, "ttrss_help",
+ "status=0,toolbar=0,location=0,width=450,height=500,scrollbars=1,menubar=0");
+
+}
+
+function loading_set_progress(p) {
+ try {
+ loading_progress += p;
+
+ if (dijit.byId("loading_bar"))
+ dijit.byId("loading_bar").update({progress: loading_progress});
+
+ if (loading_progress >= 90)
+ remove_splash();
+
+ } catch (e) {
+ exception_error("loading_set_progress", e);
+ }
+}
+
+function remove_splash() {
+
+ if (Element.visible("overlay")) {
+ console.log("about to remove splash, OMG!");
+ Element.hide("overlay");
+ console.log("removed splash!");
+ }
+}
+
+function transport_error_check(transport) {
+ try {
+ if (transport.responseXML) {
+ var error = transport.responseXML.getElementsByTagName("error")[0];
+
+ if (error) {
+ var code = error.getAttribute("error-code");
+ var msg = error.getAttribute("error-msg");
+ if (code != 0) {
+ fatalError(code, msg);
+ return false;
+ }
+ }
+ }
+ } catch (e) {
+ exception_error("check_for_error_xml", e);
+ }
+ return true;
+}
+
+function strip_tags(s) {
+ return s.replace(/<\/?[^>]+(>|$)/g, "");
+}
+
+function truncate_string(s, length) {
+ if (!length) length = 30;
+ var tmp = s.substring(0, length);
+ if (s.length > length) tmp += "…";
+ return tmp;
+}
+
+function hotkey_prefix_timeout() {
+ try {
+
+ var date = new Date();
+ var ts = Math.round(date.getTime() / 1000);
+
+ if (hotkey_prefix_pressed && ts - hotkey_prefix_pressed >= 5) {
+ console.log("hotkey_prefix seems to be stuck, aborting");
+ hotkey_prefix_pressed = false;
+ hotkey_prefix = false;
+ Element.hide('cmdline');
+ }
+
+ setTimeout("hotkey_prefix_timeout()", 1000);
+
+ } catch (e) {
+ exception_error("hotkey_prefix_timeout", e);
+ }
+}
+
+function hideAuxDlg() {
+ try {
+ Element.hide('auxDlg');
+ } catch (e) {
+ exception_error("hideAuxDlg", e);
+ }
+}
+
+
+function uploadIconHandler(rc) {
+ try {
+ switch (rc) {
+ case 0:
+ notify_info("Upload complete.");
+ if (inPreferences()) {
+ updateFeedList();
+ } else {
+ setTimeout('updateFeedList(false, false)', 50);
+ }
+ break;
+ case 1:
+ notify_error("Upload failed: icon is too big.");
+ break;
+ case 2:
+ notify_error("Upload failed.");
+ break;
+ }
+
+ } catch (e) {
+ exception_error("uploadIconHandler", e);
+ }
+}
+
+function removeFeedIcon(id) {
+
+ try {
+
+ if (confirm(__("Remove stored feed icon?"))) {
+ var query = "backend.php?op=pref-feeds&subop=removeicon&feed_id=" + param_escape(id);
+
+ console.log(query);
+
+ notify_progress("Removing feed icon...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify_info("Feed icon removed.");
+ if (inPreferences()) {
+ updateFeedList();
+ } else {
+ setTimeout('updateFeedList(false, false)', 50);
+ }
+ } });
+ }
+
+ return false;
+ } catch (e) {
+ exception_error("uploadFeedIcon", e);
+ }
+}
+
+function uploadFeedIcon() {
+
+ try {
+
+ var file = $("icon_file");
+
+ if (file.value.length == 0) {
+ alert(__("Please select an image file to upload."));
+ } else {
+ if (confirm(__("Upload new icon for this feed?"))) {
+ notify_progress("Uploading, please wait...", true);
+ return true;
+ }
+ }
+
+ return false;
+
+ } catch (e) {
+ exception_error("uploadFeedIcon", e);
+ }
+}
+
+function addLabel(select, callback) {
+
+ try {
+
+ var caption = prompt(__("Please enter label caption:"), "");
+
+ if (caption != undefined) {
+
+ if (caption == "") {
+ alert(__("Can't create label: missing caption."));
+ return false;
+ }
+
+ var query = "?op=pref-labels&subop=add&caption=" +
+ param_escape(caption);
+
+ if (select)
+ query += "&output=select";
+
+ notify_progress("Loading, please wait...", true);
+
+ if (inPreferences() && !select) active_tab = "labelConfig";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ if (callback) {
+ callback(transport);
+ } else if (inPreferences()) {
+ updateLabelList();
+ } else {
+ updateFeedList();
+ }
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("addLabel", e);
+ }
+}
+
+function quickAddFeed() {
+ try {
+ var query = "backend.php?op=dlg&id=quickAddFeed";
+
+ if (dijit.byId("feedAddDlg"))
+ dijit.byId("feedAddDlg").destroyRecursive();
+
+ var dialog = new dijit.Dialog({
+ id: "feedAddDlg",
+ title: __("Subscribe to Feed"),
+ style: "width: 600px",
+ execute: function() {
+ if (this.validate()) {
+ console.log(dojo.objectToQuery(this.attr('value')));
+
+ var feed_url = this.attr('value').feed;
+
+ notify_progress(__("Subscribing to feed..."), true);
+
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(this.attr('value')),
+ onComplete: function(transport) {
+ try {
+
+ var reply = JSON.parse(transport.responseText);
+
+ var rc = parseInt(reply['result']);
+
+ notify('');
+
+ console.log("GOT RC: " + rc);
+
+ switch (rc) {
+ case 1:
+ dialog.hide();
+ notify_info(__("Subscribed to %s").replace("%s", feed_url));
+
+ updateFeedList();
+ break;
+ case 2:
+ alert(__("Specified URL seems to be invalid."));
+ break;
+ case 3:
+ alert(__("Specified URL doesn't seem to contain any feeds."));
+ break;
+ case 4:
+ notify_progress("Searching for feed urls...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: 'op=rpc&subop=extractfeedurls&url=' + param_escape(feed_url),
+ onComplete: function(transport, dialog, feed_url) {
+
+ notify('');
+
+ var reply = JSON.parse(transport.responseText);
+
+ var feeds = reply['urls'];
+
+ console.log(transport.responseText);
+
+ var select = dijit.byId("feedDlg_feedContainerSelect");
+
+ while (select.getOptions().length > 0)
+ select.removeOption(0);
+
+ var count = 0;
+ for (var feedUrl in feeds) {
+ select.addOption({value: feedUrl, label: feeds[feedUrl]});
+ count++;
+ }
+
+// if (count > 5) count = 5;
+// select.size = count;
+
+ Effect.Appear('feedDlg_feedsContainer', {duration : 0.5});
+ }
+ });
+ break;
+ case 5:
+ alert(__("Couldn't download the specified URL."));
+ break;
+ case 0:
+ alert(__("You are already subscribed to this feed."));
+ break;
+ }
+
+ } catch (e) {
+ exception_error("subscribeToFeed", e, transport);
+ }
+
+ } });
+
+ }
+ },
+ href: query});
+
+ dialog.show();
+ } catch (e) {
+ exception_error("quickAddFeed", e);
+ }
+}
+
+function quickAddFilter() {
+ try {
+ var query = "backend.php?op=dlg&id=quickAddFilter";
+
+ if (dijit.byId("filterEditDlg"))
+ dijit.byId("filterEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "filterEditDlg",
+ title: __("Create Filter"),
+ style: "width: 600px",
+ test: function() {
+ if (this.validate()) {
+
+ if (dijit.byId("filterTestDlg"))
+ dijit.byId("filterTestDlg").destroyRecursive();
+
+ tdialog = new dijit.Dialog({
+ id: "filterTestDlg",
+ title: __("Filter Test Results"),
+ style: "width: 600px",
+ href: "backend.php?savemode=test&" +
+ dojo.objectToQuery(dialog.attr('value')),
+ });
+
+ tdialog.show();
+
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+
+ var query = "?op=rpc&subop=verifyRegexp®_exp=" +
+ param_escape(dialog.attr('value').reg_exp);
+
+ notify_progress("Verifying regular expression...");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var reply = JSON.parse(transport.responseText);
+
+ if (reply) {
+ notify('');
+
+ if (!reply['status']) {
+ alert("Match regular expression seems to be invalid.");
+ return;
+ } else {
+ notify_progress("Saving data...", true);
+
+ console.log(dojo.objectToQuery(dialog.attr('value')));
+
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(dialog.attr('value')),
+ onComplete: function(transport) {
+ dialog.hide();
+ notify_info(transport.responseText);
+ if (inPreferences()) {
+ updateFilterList();
+ }
+ }});
+ }
+ }
+ }});
+ }
+ },
+ href: query});
+
+ dialog.show();
+ } catch (e) {
+ exception_error("quickAddFilter", e);
+ }
+}
+
+function resetPubSub(feed_id, title) {
+
+ var msg = __("Reset subscription? Tiny Tiny RSS will try to subscribe to the notification hub again on next feed update.").replace("%s", title);
+
+ if (title == undefined || confirm(msg)) {
+ notify_progress("Loading, please wait...");
+
+ var query = "?op=pref-feeds&quiet=1&subop=resetPubSub&ids=" + feed_id;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ dijit.byId("pubsubReset_Btn").attr('disabled', true);
+ notify_info("Subscription reset.");
+ } });
+ }
+
+ return false;
+}
+
+
+function unsubscribeFeed(feed_id, title) {
+
+ var msg = __("Unsubscribe from %s?").replace("%s", title);
+
+ if (title == undefined || confirm(msg)) {
+ notify_progress("Removing feed...");
+
+ var query = "?op=pref-feeds&quiet=1&subop=remove&ids=" + feed_id;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+
+ if (dijit.byId("feedEditDlg")) dijit.byId("feedEditDlg").hide();
+
+ if (inPreferences()) {
+ updateFeedList();
+ } else {
+ if (feed_id == getActiveFeedId())
+ setTimeout("viewfeed(-5)", 100);
+ }
+
+ } });
+ }
+
+ return false;
+}
+
+
+function backend_sanity_check_callback(transport) {
+
+ try {
+
+ if (sanity_check_done) {
+ fatalError(11, "Sanity check request received twice. This can indicate "+
+ "presence of Firebug or some other disrupting extension. "+
+ "Please disable it and try again.");
+ return;
+ }
+
+ var reply = JSON.parse(transport.responseText);
+
+ if (!reply) {
+ fatalError(3, "Sanity check: invalid RPC reply", transport.responseText);
+ return;
+ }
+
+ var error_code = reply['error']['code'];
+
+ if (error_code && error_code != 0) {
+ return fatalError(error_code, reply['error']['message']);
+ }
+
+ console.log("sanity check ok");
+
+ var params = reply['init-params'];
+
+ if (params) {
+ console.log('reading init-params...');
+
+ if (params) {
+ for (k in params) {
+ var v = params[k];
+ console.log("IP: " + k + " => " + v);
+ }
+ }
+
+ init_params = params;
+ }
+
+ sanity_check_done = true;
+
+ init_second_stage();
+
+ } catch (e) {
+ exception_error("backend_sanity_check_callback", e, transport);
+ }
+}
+
+/*function has_local_storage() {
+ try {
+ return 'sessionStorage' in window && window['sessionStorage'] != null;
+ } catch (e) {
+ return false;
+ }
+} */
+
+function catSelectOnChange(elem) {
+ try {
+/* var value = elem[elem.selectedIndex].value;
+ var def = elem.getAttribute('default');
+
+ if (value == "ADD_CAT") {
+
+ if (def)
+ dropboxSelect(elem, def);
+ else
+ elem.selectedIndex = 0;
+
+ quickAddCat(elem);
+ } */
+
+ } catch (e) {
+ exception_error("catSelectOnChange", e);
+ }
+}
+
+function quickAddCat(elem) {
+ try {
+ var cat = prompt(__("Please enter category title:"));
+
+ if (cat) {
+
+ var query = "?op=rpc&subop=quickAddCat&cat=" + param_escape(cat);
+
+ notify_progress("Loading, please wait...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function (transport) {
+ var response = transport.responseXML;
+ var select = response.getElementsByTagName("select")[0];
+ var options = select.getElementsByTagName("option");
+
+ dropbox_replace_options(elem, options);
+
+ notify('');
+
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("quickAddCat", e);
+ }
+}
+
+function genUrlChangeKey(feed, is_cat) {
+
+ try {
+ var ok = confirm(__("Generate new syndication address for this feed?"));
+
+ if (ok) {
+
+ notify_progress("Trying to change address...", true);
+
+ var query = "?op=rpc&subop=regenFeedKey&id=" + param_escape(feed) +
+ "&is_cat=" + param_escape(is_cat);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var reply = JSON.parse(transport.responseText);
+ var new_link = reply.link;
+
+ var e = $('gen_feed_url');
+
+ if (new_link) {
+
+ e.innerHTML = e.innerHTML.replace(/\&key=.*$/,
+ "&key=" + new_link);
+
+ e.href = e.href.replace(/\&key=.*$/,
+ "&key=" + new_link);
+
+ new Effect.Highlight(e);
+
+ notify('');
+
+ } else {
+ notify_error("Could not change feed URL.");
+ }
+ } });
+ }
+ } catch (e) {
+ exception_error("genUrlChangeKey", e);
+ }
+ return false;
+}
+
+function labelSelectOnChange(elem) {
+ try {
+/* var value = elem[elem.selectedIndex].value;
+ var def = elem.getAttribute('default');
+
+ if (value == "ADD_LABEL") {
+
+ if (def)
+ dropboxSelect(elem, def);
+ else
+ elem.selectedIndex = 0;
+
+ addLabel(elem, function(transport) {
+
+ try {
+
+ var response = transport.responseXML;
+ var select = response.getElementsByTagName("select")[0];
+ var options = select.getElementsByTagName("option");
+
+ dropbox_replace_options(elem, options);
+
+ notify('');
+ } catch (e) {
+ exception_error("addLabel", e);
+ }
+ });
+ } */
+
+ } catch (e) {
+ exception_error("labelSelectOnChange", e);
+ }
+}
+
+function dropbox_replace_options(elem, options) {
+
+ try {
+ while (elem.hasChildNodes())
+ elem.removeChild(elem.firstChild);
+
+ var sel_idx = -1;
+
+ for (var i = 0; i < options.length; i++) {
+ var text = options[i].firstChild.nodeValue;
+ var value = options[i].getAttribute("value");
+
+ if (value == undefined) value = text;
+
+ var issel = options[i].getAttribute("selected") == "1";
+
+ var option = new Option(text, value, issel);
+
+ if (options[i].getAttribute("disabled"))
+ option.setAttribute("disabled", true);
+
+ elem.insert(option);
+
+ if (issel) sel_idx = i;
+ }
+
+ // Chrome doesn't seem to just select stuff when you pass new Option(x, y, true)
+ if (sel_idx >= 0) elem.selectedIndex = sel_idx;
+
+ } catch (e) {
+ exception_error("dropbox_replace_options", e);
+ }
+}
+
+// mode = all, none, invert
+function selectTableRows(id, mode) {
+ try {
+ var rows = $(id).rows;
+
+ for (var i = 0; i < rows.length; i++) {
+ var row = rows[i];
+ var cb = false;
+
+ if (row.id && row.className) {
+ var bare_id = row.id.replace(/^[A-Z]*?-/, "");
+ var inputs = rows[i].getElementsByTagName("input");
+
+ for (var j = 0; j < inputs.length; j++) {
+ var input = inputs[j];
+
+ if (input.getAttribute("type") == "checkbox" &&
+ input.id.match(bare_id)) {
+
+ cb = input;
+ break;
+ }
+ }
+
+ if (cb) {
+ var issel = row.hasClassName("Selected");
+
+ if (mode == "all" && !issel) {
+ row.addClassName("Selected");
+ cb.checked = true;
+ } else if (mode == "none" && issel) {
+ row.removeClassName("Selected");
+ cb.checked = false;
+ } else if (mode == "invert") {
+
+ if (issel) {
+ row.removeClassName("Selected");
+ cb.checked = false;
+ } else {
+ row.addClassName("Selected");
+ cb.checked = true;
+ }
+ }
+ }
+ }
+ }
+
+ } catch (e) {
+ exception_error("selectTableRows", e);
+
+ }
+}
+
+function getSelectedTableRowIds(id) {
+ var rows = [];
+
+ try {
+ var elem_rows = $(id).rows;
+
+ for (var i = 0; i < elem_rows.length; i++) {
+ if (elem_rows[i].hasClassName("Selected")) {
+ var bare_id = elem_rows[i].id.replace(/^[A-Z]*?-/, "");
+ rows.push(bare_id);
+ }
+ }
+
+ } catch (e) {
+ exception_error("getSelectedTableRowIds", e);
+ }
+
+ return rows;
+}
+
+function editFeed(feed, event) {
+ try {
+ if (feed <= 0)
+ return alert(__("You can't edit this kind of feed."));
+
+ var query = "backend.php?op=pref-feeds&subop=editfeed&id=" +
+ param_escape(feed);
+
+ console.log(query);
+
+ if (dijit.byId("feedEditDlg"))
+ dijit.byId("feedEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "feedEditDlg",
+ title: __("Edit Feed"),
+ style: "width: 600px",
+ execute: function() {
+ if (this.validate()) {
+// console.log(dojo.objectToQuery(this.attr('value')));
+
+ notify_progress("Saving data...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(dialog.attr('value')),
+ onComplete: function(transport) {
+ dialog.hide();
+ notify('');
+ updateFeedList();
+ }});
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("editFeed", e);
+ }
+}
+
+function feedBrowser() {
+ try {
+ var query = "backend.php?op=dlg&id=feedBrowser";
+
+ if (dijit.byId("feedAddDlg"))
+ dijit.byId("feedAddDlg").hide();
+
+ if (dijit.byId("feedBrowserDlg"))
+ dijit.byId("feedBrowserDlg").destroyRecursive();
+
+ var dialog = new dijit.Dialog({
+ id: "feedBrowserDlg",
+ title: __("More Feeds"),
+ style: "width: 600px",
+ getSelectedFeedIds: function() {
+ var list = $$("#browseFeedList li[id*=FBROW]");
+ var selected = new Array();
+
+ list.each(function(child) {
+ var id = child.id.replace("FBROW-", "");
+
+ if (child.hasClassName('Selected')) {
+ selected.push(id);
+ }
+ });
+
+ return selected;
+ },
+ getSelectedFeeds: function() {
+ var list = $$("#browseFeedList li.Selected");
+ var selected = new Array();
+
+ list.each(function(child) {
+ var title = child.getElementsBySelector("span.fb_feedTitle")[0].innerHTML;
+ var url = child.getElementsBySelector("a.fb_feedUrl")[0].href;
+
+ selected.push([title,url]);
+
+ });
+
+ return selected;
+ },
+
+ subscribe: function() {
+ var mode = this.attr('value').mode;
+ var selected = [];
+
+ if (mode == "1")
+ selected = this.getSelectedFeeds();
+ else
+ selected = this.getSelectedFeedIds();
+
+ if (selected.length > 0) {
+ dijit.byId("feedBrowserDlg").hide();
+
+ notify_progress("Loading, please wait...", true);
+
+ // we use dojo.toJson instead of JSON.stringify because
+ // it somehow escapes everything TWICE, at least in Chrome 9
+
+ var query = "?op=rpc&subop=massSubscribe&payload="+
+ param_escape(dojo.toJson(selected)) + "&mode=" + param_escape(mode);
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ updateFeedList();
+ } });
+
+ } else {
+ alert(__("No feeds are selected."));
+ }
+
+ },
+ update: function() {
+ var query = dojo.objectToQuery(dialog.attr('value'));
+
+ Element.show('feed_browser_spinner');
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+
+ Element.hide('feed_browser_spinner');
+
+ var c = $("browseFeedList");
+
+ var reply = JSON.parse(transport.responseText);
+
+ var r = reply['content'];
+ var mode = reply['mode'];
+
+ if (c && r) {
+ c.innerHTML = r;
+ }
+
+ dojo.parser.parse("browseFeedList");
+
+ if (mode == 2) {
+ Element.show(dijit.byId('feed_archive_remove').domNode);
+ } else {
+ Element.hide(dijit.byId('feed_archive_remove').domNode);
+ }
+
+ } });
+ },
+ removeFromArchive: function() {
+ var selected = this.getSelectedFeeds();
+
+ if (selected.length > 0) {
+
+ var pr = __("Remove selected feeds from the archive? Feeds with stored articles will not be removed.");
+
+ if (confirm(pr)) {
+ Element.show('feed_browser_spinner');
+
+ var query = "?op=rpc&subop=remarchived&ids=" +
+ param_escape(selected.toString());;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ dialog.update();
+ } });
+ }
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+ this.subscribe();
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("editFeed", e);
+ }
+}
+
+function showFeedsWithErrors() {
+ try {
+ var query = "backend.php?op=dlg&id=feedsWithErrors";
+
+ if (dijit.byId("errorFeedsDlg"))
+ dijit.byId("errorFeedsDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "errorFeedsDlg",
+ title: __("Feeds with update errors"),
+ style: "width: 600px",
+ getSelectedFeeds: function() {
+ return getSelectedTableRowIds("prefErrorFeedList");
+ },
+ removeSelected: function() {
+ var sel_rows = this.getSelectedFeeds();
+
+ console.log(sel_rows);
+
+ if (sel_rows.length > 0) {
+ var ok = confirm(__("Remove selected feeds?"));
+
+ if (ok) {
+ notify_progress("Removing selected feeds...", true);
+
+ var query = "?op=pref-feeds&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ dialog.hide();
+ updateFeedList();
+ } });
+ }
+
+ } else {
+ alert(__("No feeds are selected."));
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("showFeedsWithErrors", e);
+ }
+
+}
+
+/* new support functions for SelectByTag */
+
+function get_all_tags(selObj){
+ try {
+ if( !selObj ) return "";
+
+ var result = "";
+ var len = selObj.options.length;
+
+ for (var i=0; i < len; i++){
+ if (selObj.options[i].selected) {
+ result += selObj[i].value + "%2C"; // is really a comma
+ }
+ }
+
+ if (result.length > 0){
+ result = result.substr(0, result.length-3); // remove trailing %2C
+ }
+
+ return(result);
+
+ } catch (e) {
+ exception_error("get_all_tags", e);
+ }
+}
+
+function get_radio_checked(radioObj) {
+ try {
+ if (!radioObj) return "";
+
+ var len = radioObj.length;
+
+ if (len == undefined){
+ if(radioObj.checked){
+ return(radioObj.value);
+ } else {
+ return("");
+ }
+ }
+
+ for( var i=0; i < len; i++ ){
+ if( radioObj[i].checked ){
+ return( radioObj[i].value);
+ }
+ }
+
+ } catch (e) {
+ exception_error("get_radio_checked", e);
+ }
+ return("");
+}
--- /dev/null
+var init_params = new Array();
+
+var hotkey_prefix = false;
+var hotkey_prefix_pressed = false;
+
+var seq = "";
+
+function instancelist_callback2(transport) {
+ try {
+ dijit.byId('instanceConfigTab').attr('content', transport.responseText);
+ selectTab("instanceConfig", true);
+ notify("");
+ } catch (e) {
+ exception_error("instancelist_callback2", e);
+ }
+}
+
+function feedlist_callback2(transport) {
+ try {
+ dijit.byId('feedConfigTab').attr('content', transport.responseText);
+ selectTab("feedConfig", true);
+ notify("");
+ } catch (e) {
+ exception_error("feedlist_callback2", e);
+ }
+}
+
+function filterlist_callback2(transport) {
+ dijit.byId('filterConfigTab').attr('content', transport.responseText);
+ notify("");
+}
+
+function labellist_callback2(transport) {
+ try {
+ dijit.byId('labelConfigTab').attr('content', transport.responseText);
+ notify("");
+ } catch (e) {
+ exception_error("labellist_callback2", e);
+ }
+}
+
+function userlist_callback2(transport) {
+ try {
+ dijit.byId('userConfigTab').attr('content', transport.responseText);
+
+ notify("");
+ } catch (e) {
+ exception_error("userlist_callback2", e);
+ }
+}
+
+function prefslist_callback2(transport) {
+ try {
+ dijit.byId('genConfigTab').attr('content', transport.responseText);
+
+ notify("");
+ } catch (e) {
+ exception_error("prefslist_callback2", e);
+ }
+}
+
+function notify_callback2(transport) {
+ notify_info(transport.responseText);
+}
+
+function updateFeedList(sort_key) {
+
+ var user_search = $("feed_search");
+ var search = "";
+ if (user_search) { search = user_search.value; }
+
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-feeds&search=" + param_escape(search),
+ onComplete: function(transport) {
+ feedlist_callback2(transport);
+ } });
+}
+
+function updateInstanceList(sort_key) {
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-instances&sort=" + param_escape(sort_key),
+ onComplete: function(transport) {
+ instancelist_callback2(transport);
+ } });
+}
+
+function updateUsersList(sort_key) {
+
+ try {
+
+ var user_search = $("user_search");
+ var search = "";
+ if (user_search) { search = user_search.value; }
+
+ var query = "?op=pref-users&sort="
+ + param_escape(sort_key) +
+ "&search=" + param_escape(search);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ userlist_callback2(transport);
+ } });
+
+ } catch (e) {
+ exception_error("updateUsersList", e);
+ }
+}
+
+function addUser() {
+
+ try {
+
+ var login = prompt(__("Please enter login:"), "");
+
+ if (login == null) {
+ return false;
+ }
+
+ if (login == "") {
+ alert(__("Can't create user: no login specified."));
+ return false;
+ }
+
+ notify_progress("Adding user...");
+
+ var query = "?op=pref-users&subop=add&login=" +
+ param_escape(login);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ userlist_callback2(transport);
+ } });
+
+ } catch (e) {
+ exception_error("addUser", e);
+ }
+}
+
+function editUser(id, event) {
+
+ try {
+ if (!event || !event.ctrlKey) {
+
+ notify_progress("Loading, please wait...");
+
+ selectTableRows('prefUserList', 'none');
+ selectTableRowById('UMRR-'+id, 'UMCHK-'+id, true);
+
+ var query = "?op=pref-users&subop=edit&id=" +
+ param_escape(id);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ infobox_callback2(transport);
+ document.forms['user_edit_form'].login.focus();
+ } });
+
+ } else if (event.ctrlKey) {
+ var cb = $('UMCHK-' + id);
+ cb.checked = !cb.checked;
+ toggleSelectRow(cb);
+ }
+
+ } catch (e) {
+ exception_error("editUser", e);
+ }
+
+}
+
+function editFilter(id) {
+ try {
+
+ var query = "backend.php?op=pref-filters&subop=edit&id=" + param_escape(id);
+
+ if (dijit.byId("filterEditDlg"))
+ dijit.byId("filterEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "filterEditDlg",
+ title: __("Edit Filter"),
+ style: "width: 600px",
+ removeFilter: function() {
+ var title = this.attr('value').reg_exp;
+ var msg = __("Remove filter %s?").replace("%s", title);
+
+ if (confirm(msg)) {
+ this.hide();
+
+ notify_progress("Removing filter...");
+
+ var id = this.attr('value').id;
+
+ var query = "?op=pref-filters&subop=remove&ids="+
+ param_escape(id);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ updateFilterList();
+ } });
+ }
+ },
+ test: function() {
+ if (this.validate()) {
+
+ if (dijit.byId("filterTestDlg"))
+ dijit.byId("filterTestDlg").destroyRecursive();
+
+ tdialog = new dijit.Dialog({
+ id: "filterTestDlg",
+ title: __("Filter Test Results"),
+ style: "width: 600px",
+ href: "backend.php?savemode=test&" +
+ dojo.objectToQuery(dialog.attr('value')),
+ });
+
+ tdialog.show();
+
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+
+ var query = "?op=rpc&subop=verifyRegexp®_exp=" +
+ param_escape(dialog.attr('value').reg_exp);
+
+ notify_progress("Verifying regular expression...");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var reply = JSON.parse(transport.responseText);
+
+ if (reply) {
+ notify('');
+
+ if (!reply['status']) {
+ alert("Match regular expression seems to be invalid.");
+ return;
+ } else {
+ notify_progress("Saving data...", true);
+
+ console.log(dojo.objectToQuery(dialog.attr('value')));
+
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(dialog.attr('value')),
+ onComplete: function(transport) {
+ dialog.hide();
+ updateFilterList();
+ }});
+ }
+ }
+ }});
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+
+ } catch (e) {
+ exception_error("editFilter", e);
+ }
+}
+
+function getSelectedLabels() {
+ var tree = dijit.byId("labelTree");
+ var items = tree.model.getCheckedItems();
+ var rv = [];
+
+ items.each(function(item) {
+ rv.push(tree.model.store.getValue(item, 'bare_id'));
+ });
+
+ return rv;
+}
+
+function getSelectedUsers() {
+ return getSelectedTableRowIds("prefUserList");
+}
+
+function getSelectedFeeds() {
+ var tree = dijit.byId("feedTree");
+ var items = tree.model.getCheckedItems();
+ var rv = [];
+
+ items.each(function(item) {
+ if (item.id[0].match("FEED:"))
+ rv.push(tree.model.store.getValue(item, 'bare_id'));
+ });
+
+ return rv;
+}
+
+function getSelectedFilters() {
+ var tree = dijit.byId("filterTree");
+ var items = tree.model.getCheckedItems();
+ var rv = [];
+
+ items.each(function(item) {
+ rv.push(tree.model.store.getValue(item, 'bare_id'));
+ });
+
+ return rv;
+
+}
+
+/* function getSelectedFeedCats() {
+ return getSelectedTableRowIds("prefFeedCatList");
+} */
+
+function removeSelectedLabels() {
+
+ var sel_rows = getSelectedLabels();
+
+ if (sel_rows.length > 0) {
+
+ var ok = confirm(__("Remove selected labels?"));
+
+ if (ok) {
+ notify_progress("Removing selected labels...");
+
+ var query = "?op=pref-labels&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ labellist_callback2(transport);
+ } });
+
+ }
+ } else {
+ alert(__("No labels are selected."));
+ }
+
+ return false;
+}
+
+function removeSelectedUsers() {
+
+ try {
+
+ var sel_rows = getSelectedUsers();
+
+ if (sel_rows.length > 0) {
+
+ var ok = confirm(__("Remove selected users? Neither default admin nor your account will be removed."));
+
+ if (ok) {
+ notify_progress("Removing selected users...");
+
+ var query = "?op=pref-users&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ userlist_callback2(transport);
+ } });
+
+ }
+
+ } else {
+ alert(__("No users are selected."));
+ }
+
+ } catch (e) {
+ exception_error("removeSelectedUsers", e);
+ }
+
+ return false;
+}
+
+function removeSelectedFilters() {
+
+ try {
+
+ var sel_rows = getSelectedFilters();
+
+ if (sel_rows.length > 0) {
+
+ var ok = confirm(__("Remove selected filters?"));
+
+ if (ok) {
+ notify_progress("Removing selected filters...");
+
+ var query = "?op=pref-filters&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ updateFilterList();
+ } });
+ }
+ } else {
+ alert(__("No filters are selected."));
+ }
+
+ } catch (e) {
+ exception_error("removeSelectedFilters", e);
+ }
+
+ return false;
+}
+
+
+function removeSelectedFeeds() {
+
+ try {
+
+ var sel_rows = getSelectedFeeds();
+
+ if (sel_rows.length > 0) {
+
+ var ok = confirm(__("Unsubscribe from selected feeds?"));
+
+ if (ok) {
+
+ notify_progress("Unsubscribing from selected feeds...", true);
+
+ var query = "?op=pref-feeds&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ updateFeedList();
+ } });
+ }
+
+ } else {
+ alert(__("No feeds are selected."));
+ }
+
+ } catch (e) {
+ exception_error("removeSelectedFeeds", e);
+ }
+
+ return false;
+}
+
+function clearSelectedFeeds() {
+
+ var sel_rows = getSelectedFeeds();
+
+ if (sel_rows.length > 1) {
+ alert(__("Please select only one feed."));
+ return;
+ }
+
+ if (sel_rows.length > 0) {
+
+ var ok = confirm(__("Erase all non-starred articles in selected feed?"));
+
+ if (ok) {
+ notify_progress("Clearing selected feed...");
+ clearFeedArticles(sel_rows[0]);
+ }
+
+ } else {
+
+ alert(__("No feeds are selected."));
+
+ }
+
+ return false;
+}
+
+function purgeSelectedFeeds() {
+
+ var sel_rows = getSelectedFeeds();
+
+ if (sel_rows.length > 0) {
+
+ var pr = prompt(__("How many days of articles to keep (0 - use default)?"), "0");
+
+ if (pr != undefined) {
+ notify_progress("Purging selected feed...");
+
+ var query = "?op=rpc&subop=purge&ids="+
+ param_escape(sel_rows.toString()) + "&days=" + pr;
+
+ console.log(query);
+
+ new Ajax.Request("prefs.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ } });
+ }
+
+ } else {
+
+ alert(__("No feeds are selected."));
+
+ }
+
+ return false;
+}
+
+function userEditCancel() {
+ closeInfoBox();
+ return false;
+}
+
+function userEditSave() {
+
+ try {
+
+ var login = document.forms["user_edit_form"].login.value;
+
+ if (login.length == 0) {
+ alert(__("Login field cannot be blank."));
+ return;
+ }
+
+ notify_progress("Saving user...");
+
+ closeInfoBox();
+
+ var query = Form.serialize("user_edit_form");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ userlist_callback2(transport);
+ } });
+
+ } catch (e) {
+ exception_error("userEditSave", e);
+ }
+
+ return false;
+
+}
+
+
+function editSelectedUser() {
+ var rows = getSelectedUsers();
+
+ if (rows.length == 0) {
+ alert(__("No users are selected."));
+ return;
+ }
+
+ if (rows.length > 1) {
+ alert(__("Please select only one user."));
+ return;
+ }
+
+ notify("");
+
+ editUser(rows[0]);
+}
+
+function resetSelectedUserPass() {
+
+ try {
+
+ var rows = getSelectedUsers();
+
+ if (rows.length == 0) {
+ alert(__("No users are selected."));
+ return;
+ }
+
+ if (rows.length > 1) {
+ alert(__("Please select only one user."));
+ return;
+ }
+
+ var ok = confirm(__("Reset password of selected user?"));
+
+ if (ok) {
+ notify_progress("Resetting password for selected user...");
+
+ var id = rows[0];
+
+ var query = "?op=pref-users&subop=resetPass&id=" +
+ param_escape(id);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ userlist_callback2(transport);
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("resetSelectedUserPass", e);
+ }
+}
+
+function selectedUserDetails() {
+
+ try {
+
+ var rows = getSelectedUsers();
+
+ if (rows.length == 0) {
+ alert(__("No users are selected."));
+ return;
+ }
+
+ if (rows.length > 1) {
+ alert(__("Please select only one user."));
+ return;
+ }
+
+ notify_progress("Loading, please wait...");
+
+ var id = rows[0];
+
+ var query = "?op=pref-users&subop=user-details&id=" + id;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ infobox_callback2(transport);
+ } });
+ } catch (e) {
+ exception_error("selectedUserDetails", e);
+ }
+}
+
+
+function editSelectedFilter() {
+ var rows = getSelectedFilters();
+
+ if (rows.length == 0) {
+ alert(__("No filters are selected."));
+ return;
+ }
+
+ if (rows.length > 1) {
+ alert(__("Please select only one filter."));
+ return;
+ }
+
+ notify("");
+
+ editFilter(rows[0]);
+
+}
+
+
+function editSelectedFeed() {
+ var rows = getSelectedFeeds();
+
+ if (rows.length == 0) {
+ alert(__("No feeds are selected."));
+ return;
+ }
+
+ if (rows.length > 1) {
+ return editSelectedFeeds();
+ }
+
+ notify("");
+
+ editFeed(rows[0], {});
+
+}
+
+function editSelectedFeeds() {
+
+ try {
+ var rows = getSelectedFeeds();
+
+ if (rows.length == 0) {
+ alert(__("No feeds are selected."));
+ return;
+ }
+
+ notify_progress("Loading, please wait...");
+
+ var query = "backend.php?op=pref-feeds&subop=editfeeds&ids=" +
+ param_escape(rows.toString());
+
+ console.log(query);
+
+ if (dijit.byId("feedEditDlg"))
+ dijit.byId("feedEditDlg").destroyRecursive();
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+
+ notify("");
+
+ var dialog = new dijit.Dialog({
+ id: "feedEditDlg",
+ title: __("Edit Multiple Feeds"),
+ style: "width: 600px",
+ getChildByName: function (name) {
+ var rv = null;
+ this.getChildren().each(
+ function(child) {
+ if (child.name == name) {
+ rv = child;
+ return;
+ }
+ });
+ return rv;
+ },
+ toggleField: function (checkbox, elem, label) {
+ this.getChildByName(elem).attr('disabled', !checkbox.checked);
+
+ if ($(label))
+ if (checkbox.checked)
+ $(label).removeClassName('insensitive');
+ else
+ $(label).addClassName('insensitive');
+
+ },
+ execute: function() {
+ if (this.validate() && confirm(__("Save changes to selected feeds?"))) {
+ var query = dojo.objectToQuery(this.attr('value'));
+
+ /* Form.serialize ignores unchecked checkboxes */
+
+ if (!query.match("&rtl_content=") &&
+ this.getChildByName('rtl_content').attr('disabled') == false) {
+ query = query + "&rtl_content=false";
+ }
+
+ if (!query.match("&private=") &&
+ this.getChildByName('private').attr('disabled') == false) {
+ query = query + "&private=false";
+ }
+
+ try {
+ if (!query.match("&cache_images=") &&
+ this.getChildByName('cache_images').attr('disabled') == false) {
+ query = query + "&cache_images=false";
+ }
+ } catch (e) { }
+
+ if (!query.match("&include_in_digest=") &&
+ this.getChildByName('include_in_digest').attr('disabled') == false) {
+ query = query + "&include_in_digest=false";
+ }
+
+ if (!query.match("&always_display_enclosures=") &&
+ this.getChildByName('always_display_enclosures').attr('disabled') == false) {
+ query = query + "&always_display_enclosures=false";
+ }
+
+ if (!query.match("&mark_unread_on_update=") &&
+ this.getChildByName('mark_unread_on_update').attr('disabled') == false) {
+ query = query + "&mark_unread_on_update=false";
+ }
+
+ if (!query.match("&update_on_checksum_change=") &&
+ this.getChildByName('update_on_checksum_change').attr('disabled') == false) {
+ query = query + "&update_on_checksum_change=false";
+ }
+
+ console.log(query);
+
+ notify_progress("Saving data...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ dialog.hide();
+ updateFeedList();
+ }});
+ }
+ },
+ content: transport.responseText});
+
+ dialog.show();
+
+ } });
+
+ } catch (e) {
+ exception_error("editSelectedFeeds", e);
+ }
+}
+
+function piggie(enable) {
+ if (enable) {
+ console.log("I LOVEDED IT!");
+ var piggie = $("piggie");
+
+ Element.show(piggie);
+ Position.Center(piggie);
+ Effect.Puff(piggie);
+
+ }
+}
+
+function opmlImportComplete(iframe) {
+ try {
+ if (!iframe.contentDocument.body.innerHTML) return false;
+
+ notify('');
+
+ if (dijit.byId('opmlImportDlg'))
+ dijit.byId('opmlImportDlg').destroyRecursive();
+
+ var content = iframe.contentDocument.body.innerHTML;
+
+ dialog = new dijit.Dialog({
+ id: "opmlImportDlg",
+ title: __("OPML Import"),
+ style: "width: 600px",
+ onCancel: function() {
+ updateFeedList();
+ },
+ content: content});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("opmlImportComplete", e);
+ }
+}
+
+function opmlImport() {
+
+ var opml_file = $("opml_file");
+
+ if (opml_file.value.length == 0) {
+ alert(__("Please choose an OPML file first."));
+ return false;
+ } else {
+ notify_progress("Importing, please wait...", true);
+ return true;
+ }
+}
+
+function updateFilterList() {
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-filters",
+ onComplete: function(transport) {
+ filterlist_callback2(transport);
+ } });
+}
+
+function updateLabelList() {
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-labels",
+ onComplete: function(transport) {
+ labellist_callback2(transport);
+ } });
+}
+
+function updatePrefsList() {
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-prefs",
+ onComplete: function(transport) {
+ prefslist_callback2(transport);
+ } });
+}
+
+function selectTab(id, noupdate, subop) {
+ try {
+ if (!noupdate) {
+ notify_progress("Loading, please wait...");
+
+ if (id == "feedConfig") {
+ updateFeedList();
+ } else if (id == "filterConfig") {
+ updateFilterList();
+ } else if (id == "labelConfig") {
+ updateLabelList();
+ } else if (id == "genConfig") {
+ updatePrefsList();
+ } else if (id == "userConfig") {
+ updateUsersList();
+ }
+
+ var tab = dijit.byId(id + "Tab");
+ dijit.byId("pref-tabs").selectChild(tab);
+
+ }
+
+ } catch (e) {
+ exception_error("selectTab", e);
+ }
+}
+
+function init_second_stage() {
+ try {
+
+ document.onkeydown = pref_hotkey_handler;
+ loading_set_progress(50);
+ notify("");
+
+ dojo.addOnLoad(function() {
+ var tab = getURLParam('tab');
+
+ if (tab) {
+ tab = dijit.byId(tab + "Tab");
+ if (tab) dijit.byId("pref-tabs").selectChild(tab);
+ }
+
+ var subop = getURLParam('subop');
+
+ if (subop == 'editFeed') {
+ var param = getURLParam('subopparam');
+
+ window.setTimeout('editFeed(' + param + ')', 100);
+ }
+ });
+
+ setTimeout("hotkey_prefix_timeout()", 5*1000);
+
+ } catch (e) {
+ exception_error("init_second_stage", e);
+ }
+}
+
+function init() {
+
+ try {
+ dojo.registerModulePath("lib", "..");
+ dojo.registerModulePath("fox", "../../js/");
+
+ dojo.require("lib.CheckBoxTree");
+ dojo.require("fox.PrefFeedTree");
+ dojo.require("fox.PrefFilterTree");
+ dojo.require("fox.PrefLabelTree");
+
+ dojo.parser.parse();
+
+ dojo.addOnLoad(function() {
+ loading_set_progress(50);
+
+ new Ajax.Request("backend.php", {
+ parameters: {op: "rpc", subop: "sanityCheck"},
+ onComplete: function(transport) {
+ backend_sanity_check_callback(transport);
+ } });
+ });
+
+ } catch (e) {
+ exception_error("init", e);
+ }
+}
+
+function validatePrefsReset() {
+ try {
+ var ok = confirm(__("Reset to defaults?"));
+
+ if (ok) {
+
+ query = "?op=pref-prefs&subop=reset-config";
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var msg = transport.responseText;
+ if (msg.match("PREFS_THEME_CHANGED")) {
+ window.location.reload();
+ } else {
+ notify_info(msg);
+ selectTab();
+ }
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("validatePrefsReset", e);
+ }
+
+ return false;
+
+}
+
+
+function pref_hotkey_handler(e) {
+ try {
+ if (e.target.nodeName == "INPUT") return;
+
+ var keycode = false;
+ var shift_key = false;
+
+ var cmdline = $('cmdline');
+
+ try {
+ shift_key = e.shiftKey;
+ } catch (e) {
+
+ }
+
+ if (window.event) {
+ keycode = window.event.keyCode;
+ } else if (e) {
+ keycode = e.which;
+ }
+
+ var keychar = String.fromCharCode(keycode);
+
+ if (keycode == 27) { // escape
+ if (Element.visible("hotkey_help_overlay")) {
+ Element.hide("hotkey_help_overlay");
+ }
+ hotkey_prefix = false;
+ closeInfoBox();
+ }
+
+ if (keycode == 16) return; // ignore lone shift
+ if (keycode == 17) return; // ignore lone ctrl
+
+ if ((keycode == 67 || keycode == 71) && !hotkey_prefix) {
+ hotkey_prefix = keycode;
+
+ var date = new Date();
+ var ts = Math.round(date.getTime() / 1000);
+
+ hotkey_prefix_pressed = ts;
+
+ cmdline.innerHTML = keychar;
+ Element.show(cmdline);
+
+ console.log("KP: PREFIX=" + keycode + " CHAR=" + keychar);
+ return;
+ }
+
+ if (Element.visible("hotkey_help_overlay")) {
+ Element.hide("hotkey_help_overlay");
+ }
+
+ if (keycode == 13 || keycode == 27) {
+ seq = "";
+ } else {
+ seq = seq + "" + keycode;
+ }
+
+ /* Global hotkeys */
+
+ Element.hide(cmdline);
+
+ if (!hotkey_prefix) {
+
+ if ((keycode == 191 || keychar == '?') && shift_key) { // ?
+ if (!Element.visible("hotkey_help_overlay")) {
+ //Element.show("hotkey_help_overlay");
+ Effect.Appear("hotkey_help_overlay", {duration : 0.3, to: 0.9});
+ } else {
+ Element.hide("hotkey_help_overlay");
+ }
+ return false;
+ }
+
+ if (keycode == 191 || keychar == '/') { // /
+ var search_boxes = new Array("label_search",
+ "feed_search", "filter_search", "user_search", "feed_browser_search");
+
+ for (var i = 0; i < search_boxes.length; i++) {
+ var elem = $(search_boxes[i]);
+ if (elem) {
+ $(search_boxes[i]).focus();
+ return false;
+ }
+ }
+ }
+ }
+
+ /* Prefix c */
+
+ if (hotkey_prefix == 67) { // c
+ hotkey_prefix = false;
+
+ if (keycode == 70) { // f
+ quickAddFilter();
+ return false;
+ }
+
+ if (keycode == 83) { // s
+ quickAddFeed();
+ return false;
+ }
+
+ if (keycode == 85) { // u
+ // no-op
+ }
+
+ if (keycode == 67) { // c
+ editFeedCats();
+ return false;
+ }
+
+ if (keycode == 84 && shift_key) { // T
+ feedBrowser();
+ return false;
+ }
+
+ }
+
+ /* Prefix g */
+
+ if (hotkey_prefix == 71) { // g
+
+ hotkey_prefix = false;
+
+ if (keycode == 49 && $("genConfigTab")) { // 1
+ selectTab("genConfig");
+ return false;
+ }
+
+ if (keycode == 50 && $("feedConfigTab")) { // 2
+ selectTab("feedConfig");
+ return false;
+ }
+
+ if (keycode == 51 && $("filterConfigTab")) { // 4
+ selectTab("filterConfig");
+ return false;
+ }
+
+ if (keycode == 52 && $("labelConfigTab")) { // 5
+ selectTab("labelConfig");
+ return false;
+ }
+
+ if (keycode == 53 && $("userConfigTab")) { // 6
+ selectTab("userConfig");
+ return false;
+ }
+
+ if (keycode == 88) { // x
+ return gotoMain();
+ }
+
+ }
+
+ if ($("piggie")) {
+ if (seq.match("8073717369")) {
+ seq = "";
+ piggie(true);
+ } else {
+ piggie(false);
+ }
+ }
+
+ if (hotkey_prefix) {
+ console.log("KP: PREFIX=" + hotkey_prefix + " CODE=" + keycode + " CHAR=" + keychar);
+ } else {
+ console.log("KP: CODE=" + keycode + " CHAR=" + keychar);
+ }
+
+ } catch (e) {
+ exception_error("pref_hotkey_handler", e);
+ }
+}
+
+function editFeedCats() {
+ try {
+ var query = "backend.php?op=pref-feeds&subop=editCats";
+
+ if (dijit.byId("feedCatEditDlg"))
+ dijit.byId("feedCatEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "feedCatEditDlg",
+ title: __("Feed Categories"),
+ style: "width: 600px",
+ getSelectedCategories: function() {
+ return getSelectedTableRowIds("prefFeedCatList");
+ },
+ removeSelected: function() {
+ var sel_rows = this.getSelectedCategories();
+
+ if (sel_rows.length > 0) {
+ var ok = confirm(__("Remove selected categories?"));
+
+ if (ok) {
+ notify_progress("Removing selected categories...", true);
+
+ var query = "?op=pref-feeds&subop=editCats&action=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ dialog.attr('content', transport.responseText);
+ updateFeedList();
+ } });
+
+ }
+
+ } else {
+ alert(__("No categories are selected."));
+ }
+ },
+ addCategory: function() {
+ if (this.validate()) {
+ notify_progress("Creating category...");
+
+ var query = "?op=pref-feeds&subop=editCats&action=add&cat=" +
+ param_escape(this.attr('value').newcat);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ dialog.attr('content', transport.responseText);
+ updateFeedList();
+ } });
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("editFeedCats", e);
+ }
+}
+
+function showInactiveFeeds() {
+ try {
+ var query = "backend.php?op=dlg&id=inactiveFeeds";
+
+ if (dijit.byId("inactiveFeedsDlg"))
+ dijit.byId("inactiveFeedsDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "inactiveFeedsDlg",
+ title: __("Feeds without recent updates"),
+ style: "width: 600px",
+ getSelectedFeeds: function() {
+ return getSelectedTableRowIds("prefInactiveFeedList");
+ },
+ removeSelected: function() {
+ var sel_rows = this.getSelectedFeeds();
+
+ console.log(sel_rows);
+
+ if (sel_rows.length > 0) {
+ var ok = confirm(__("Remove selected feeds?"));
+
+ if (ok) {
+ notify_progress("Removing selected feeds...", true);
+
+ var query = "?op=pref-feeds&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ dialog.hide();
+ updateFeedList();
+ } });
+ }
+
+ } else {
+ alert(__("No feeds are selected."));
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("showInactiveFeeds", e);
+ }
+
+}
+
+function opmlRegenKey() {
+
+ try {
+ var ok = confirm(__("Replace current OPML publishing address with a new one?"));
+
+ if (ok) {
+
+ notify_progress("Trying to change address...", true);
+
+ var query = "?op=rpc&subop=regenOPMLKey";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var reply = JSON.parse(transport.responseText);
+
+ var new_link = reply.link;
+
+ var e = $('pub_opml_url');
+
+ if (new_link) {
+ e.href = new_link;
+ e.innerHTML = new_link;
+
+ new Effect.Highlight(e);
+
+ notify('');
+
+ } else {
+ notify_error("Could not change feed URL.");
+ }
+ } });
+ }
+ } catch (e) {
+ exception_error("opmlRegenKey", e);
+ }
+ return false;
+}
+
+function feedActionChange() {
+ try {
+ var chooser = $("feedActionChooser");
+ var opid = chooser[chooser.selectedIndex].value;
+
+ chooser.selectedIndex = 0;
+ feedActionGo(opid);
+ } catch (e) {
+ exception_error("feedActionChange", e);
+ }
+}
+
+function feedActionGo(op) {
+ try {
+ if (op == "facEdit") {
+
+ var rows = getSelectedFeeds();
+
+ if (rows.length > 1) {
+ editSelectedFeeds();
+ } else {
+ editSelectedFeed();
+ }
+ }
+
+ if (op == "facClear") {
+ clearSelectedFeeds();
+ }
+
+ if (op == "facPurge") {
+ purgeSelectedFeeds();
+ }
+
+ if (op == "facEditCats") {
+ editFeedCats();
+ }
+
+ if (op == "facRescore") {
+ rescoreSelectedFeeds();
+ }
+
+ if (op == "facUnsubscribe") {
+ removeSelectedFeeds();
+ }
+
+ } catch (e) {
+ exception_error("feedActionGo", e);
+
+ }
+}
+
+function clearFeedArticles(feed_id) {
+
+ notify_progress("Clearing feed...");
+
+ var query = "?op=pref-feeds&quiet=1&subop=clear&id=" + feed_id;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ } });
+
+ return false;
+}
+
+function rescoreSelectedFeeds() {
+
+ var sel_rows = getSelectedFeeds();
+
+ if (sel_rows.length > 0) {
+
+ //var ok = confirm(__("Rescore last 100 articles in selected feeds?"));
+ var ok = confirm(__("Rescore articles in selected feeds?"));
+
+ if (ok) {
+ notify_progress("Rescoring selected feeds...", true);
+
+ var query = "?op=pref-feeds&subop=rescore&quiet=1&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify_callback2(transport);
+ } });
+
+ }
+ } else {
+ alert(__("No feeds are selected."));
+ }
+
+ return false;
+}
+
+function rescore_all_feeds() {
+ var ok = confirm(__("Rescore all articles? This operation may take a lot of time."));
+
+ if (ok) {
+ notify_progress("Rescoring feeds...", true);
+
+ var query = "?op=pref-feeds&subop=rescoreAll&quiet=1";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify_callback2(transport);
+ } });
+ }
+}
+
+function labelColorReset() {
+ try {
+ var labels = getSelectedLabels();
+
+ if (labels.length > 0) {
+ var ok = confirm(__("Reset selected labels to default colors?"));
+
+ if (ok) {
+ var query = "?op=pref-labels&subop=color-reset&ids="+
+ param_escape(labels.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ labellist_callback2(transport);
+ } });
+ }
+
+ } else {
+ alert(__("No labels are selected."));
+ }
+
+ } catch (e) {
+ exception_error("labelColorReset", e);
+ }
+}
+
+
+function inPreferences() {
+ return true;
+}
+
+function editProfiles() {
+ try {
+
+ if (dijit.byId("profileEditDlg"))
+ dijit.byId("profileEditDlg").destroyRecursive();
+
+ var query = "backend.php?op=dlg&id=editPrefProfiles";
+
+ dialog = new dijit.Dialog({
+ id: "profileEditDlg",
+ title: __("Settings Profiles"),
+ style: "width: 600px",
+ getSelectedProfiles: function() {
+ return getSelectedTableRowIds("prefFeedProfileList");
+ },
+ removeSelected: function() {
+ var sel_rows = this.getSelectedProfiles();
+
+ if (sel_rows.length > 0) {
+ var ok = confirm(__("Remove selected profiles? Active and default profiles will not be removed."));
+
+ if (ok) {
+ notify_progress("Removing selected profiles...", true);
+
+ var query = "?op=rpc&subop=remprofiles&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ editProfiles();
+ } });
+
+ }
+
+ } else {
+ alert(__("No profiles are selected."));
+ }
+ },
+ activateProfile: function() {
+ var sel_rows = this.getSelectedProfiles();
+
+ if (sel_rows.length == 1) {
+
+ var ok = confirm(__("Activate selected profile?"));
+
+ if (ok) {
+ notify_progress("Loading, please wait...");
+
+ var query = "?op=rpc&subop=setprofile&id="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ window.location.reload();
+ } });
+ }
+
+ } else {
+ alert(__("Please choose a profile to activate."));
+ }
+ },
+ addProfile: function() {
+ if (this.validate()) {
+ notify_progress("Creating profile...", true);
+
+ var query = "?op=rpc&subop=addprofile&title=" +
+ param_escape(dialog.attr('value').newprofile);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ editProfiles();
+ } });
+
+ }
+ },
+ execute: function() {
+ if (this.validate()) {
+ }
+ },
+ href: query});
+
+ dialog.show();
+ } catch (e) {
+ exception_error("editProfiles", e);
+ }
+}
+
+function activatePrefProfile() {
+
+ var sel_rows = getSelectedFeedCats();
+
+ if (sel_rows.length == 1) {
+
+ var ok = confirm(__("Activate selected profile?"));
+
+ if (ok) {
+ notify_progress("Loading, please wait...");
+
+ var query = "?op=rpc&subop=setprofile&id="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ window.location.reload();
+ } });
+ }
+
+ } else {
+ alert(__("Please choose a profile to activate."));
+ }
+
+ return false;
+}
+
+function clearFeedAccessKeys() {
+
+ var ok = confirm(__("This will invalidate all previously generated feed URLs. Continue?"));
+
+ if (ok) {
+ notify_progress("Clearing URLs...");
+
+ var query = "?op=rpc&subop=clearKeys";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify_info("Generated URLs cleared.");
+ } });
+ }
+
+ return false;
+}
+
+function clearArticleAccessKeys() {
+
+ var ok = confirm(__("This will invalidate all previously shared article URLs. Continue?"));
+
+ if (ok) {
+ notify_progress("Clearing URLs...");
+
+ var query = "?op=rpc&subop=clearArticleKeys";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify_info("Shared URLs cleared.");
+ } });
+ }
+
+ return false;
+}
+function resetFeedOrder() {
+ try {
+ notify_progress("Loading, please wait...");
+
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-feeds&subop=feedsortreset",
+ onComplete: function(transport) {
+ updateFeedList();
+ } });
+
+
+ } catch (e) {
+ exception_error("resetFeedOrder");
+ }
+}
+
+function resetCatOrder() {
+ try {
+ notify_progress("Loading, please wait...");
+
+ new Ajax.Request("backend.php", {
+ parameters: "?op=pref-feeds&subop=catsortreset",
+ onComplete: function(transport) {
+ updateFeedList();
+ } });
+
+
+ } catch (e) {
+ exception_error("resetCatOrder");
+ }
+}
+
+function editCat(id, item, event) {
+ try {
+ var new_name = prompt(__('Rename category to:'), item.name);
+
+ if (new_name && new_name != item.name) {
+
+ notify_progress("Loading, please wait...");
+
+ new Ajax.Request("backend.php", {
+ parameters: {
+ op: 'pref-feeds',
+ subop: 'renamecat',
+ id: id,
+ title: new_name,
+ },
+ onComplete: function(transport) {
+ updateFeedList();
+ } });
+ }
+
+ } catch (e) {
+ exception_error("editCat", e);
+ }
+}
+
+function editLabel(id, event) {
+ try {
+ var query = "backend.php?op=pref-labels&subop=edit&id=" +
+ param_escape(id);
+
+ if (dijit.byId("labelEditDlg"))
+ dijit.byId("labelEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "labelEditDlg",
+ title: __("Label Editor"),
+ style: "width: 600px",
+ setLabelColor: function(id, fg, bg) {
+
+ var kind = '';
+ var color = '';
+
+ if (fg && bg) {
+ kind = 'both';
+ } else if (fg) {
+ kind = 'fg';
+ color = fg;
+ } else if (bg) {
+ kind = 'bg';
+ color = bg;
+ }
+
+ var query = "?op=pref-labels&subop=color-set&kind="+kind+
+ "&ids=" + param_escape(id) + "&fg=" + param_escape(fg) +
+ "&bg=" + param_escape(bg) + "&color=" + param_escape(color);
+
+ // console.log(query);
+
+ var e = $("LICID-" + id);
+
+ if (e) {
+ if (fg) e.style.color = fg;
+ if (bg) e.style.backgroundColor = bg;
+ }
+
+ new Ajax.Request("backend.php", { parameters: query });
+
+ updateFilterList();
+ },
+ execute: function() {
+ if (this.validate()) {
+ var caption = this.attr('value').caption;
+ var fg_color = this.attr('value').fg_color;
+ var bg_color = this.attr('value').bg_color;
+ var query = dojo.objectToQuery(this.attr('value'));
+
+ dijit.byId('labelTree').setNameById(id, caption);
+ this.setLabelColor(id, fg_color, bg_color);
+ this.hide();
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ updateFilterList();
+ } });
+ }
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("editLabel", e);
+ }
+}
+
+function clearTwitterCredentials() {
+ try {
+ var ok = confirm(__("This will clear your stored authentication information for Twitter. Continue?"));
+
+ if (ok) {
+ notify_progress("Clearing credentials...");
+
+ var query = "?op=pref-feeds&subop=remtwitterinfo";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify_info("Twitter credentials have been cleared.");
+ updateFeedList();
+ } });
+ }
+
+ } catch (e) {
+ exception_error("clearTwitterCredentials", e);
+ }
+}
+
+function customizeCSS() {
+ try {
+ var query = "backend.php?op=dlg&id=customizeCSS";
+
+ if (dijit.byId("cssEditDlg"))
+ dijit.byId("cssEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "cssEditDlg",
+ title: __("Customize stylesheet"),
+ style: "width: 600px",
+ execute: function() {
+ notify_progress('Saving data...', true);
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(this.attr('value')),
+ onComplete: function(transport) {
+ notify('');
+ window.location.reload();
+ } });
+
+ },
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("customizeCSS", e);
+ }
+}
+
+function insertSSLserial(value) {
+ try {
+ dijit.byId("SSL_CERT_SERIAL").attr('value', value);
+ } catch (e) {
+ exception_error("insertSSLcerial", e);
+ }
+}
+
+function getSelectedInstances() {
+ return getSelectedTableRowIds("prefInstanceList");
+}
+
+function addInstance() {
+ try {
+ var query = "backend.php?op=dlg&id=addInstance";
+
+ if (dijit.byId("instanceAddDlg"))
+ dijit.byId("instanceAddDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "instanceAddDlg",
+ title: __("Link Instance"),
+ style: "width: 600px",
+ regenKey: function() {
+ new Ajax.Request("backend.php", {
+ parameters: "?op=rpc&subop=genHash",
+ onComplete: function(transport) {
+ var reply = JSON.parse(transport.responseText);
+ if (reply)
+ dijit.byId('instance_add_key').attr('value', reply.hash);
+
+ } });
+ },
+ execute: function() {
+ if (this.validate()) {
+ console.warn(dojo.objectToQuery(this.attr('value')));
+
+ notify_progress('Saving data...', true);
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(this.attr('value')),
+ onComplete: function(transport) {
+ dialog.hide();
+ notify('');
+ updateInstanceList();
+ } });
+ }
+ },
+ href: query,
+ });
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("addInstance", e);
+ }
+}
+
+function editInstance(id, event) {
+ try {
+ if (!event || !event.ctrlKey) {
+
+ selectTableRows('prefInstanceList', 'none');
+ selectTableRowById('LIRR-'+id, 'LICHK-'+id, true);
+
+ var query = "backend.php?op=pref-instances&subop=edit&id=" +
+ param_escape(id);
+
+ if (dijit.byId("instanceEditDlg"))
+ dijit.byId("instanceEditDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "instanceEditDlg",
+ title: __("Edit Instance"),
+ style: "width: 600px",
+ regenKey: function() {
+ new Ajax.Request("backend.php", {
+ parameters: "?op=rpc&subop=genHash",
+ onComplete: function(transport) {
+ var reply = JSON.parse(transport.responseText);
+ if (reply)
+ dijit.byId('instance_edit_key').attr('value', reply.hash);
+
+ } });
+ },
+ execute: function() {
+ if (this.validate()) {
+// console.warn(dojo.objectToQuery(this.attr('value')));
+
+ notify_progress('Saving data...', true);
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(this.attr('value')),
+ onComplete: function(transport) {
+ dialog.hide();
+ notify('');
+ updateInstanceList();
+ } });
+ }
+ },
+ href: query,
+ });
+
+ dialog.show();
+
+ } else if (event.ctrlKey) {
+ var cb = $('LICHK-' + id);
+ cb.checked = !cb.checked;
+ toggleSelectRow(cb);
+ }
+
+
+ } catch (e) {
+ exception_error("editInstance", e);
+ }
+}
+
+function removeSelectedInstances() {
+ try {
+ var sel_rows = getSelectedInstances();
+
+ if (sel_rows.length > 0) {
+
+ var ok = confirm(__("Remove selected instances?"));
+
+ if (ok) {
+ notify_progress("Removing selected instances...");
+
+ var query = "?op=pref-instances&subop=remove&ids="+
+ param_escape(sel_rows.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ updateInstanceList();
+ } });
+ }
+
+ } else {
+ alert(__("No instances are selected."));
+ }
+
+ } catch (e) {
+ exception_error("removeInstance", e);
+ }
+}
+
+function editSelectedInstance() {
+ var rows = getSelectedInstances();
+
+ if (rows.length == 0) {
+ alert(__("No instances are selected."));
+ return;
+ }
+
+ if (rows.length > 1) {
+ alert(__("Please select only one instance."));
+ return;
+ }
+
+ notify("");
+
+ editInstance(rows[0]);
+}
+
--- /dev/null
+var total_unread = 0;
+var global_unread = -1;
+var firsttime_update = true;
+var _active_feed_id = 0;
+var _active_feed_is_cat = false;
+var hotkey_prefix = false;
+var hotkey_prefix_pressed = false;
+var init_params = {};
+var _force_scheduled_update = false;
+var last_scheduled_update = false;
+
+var _rpc_seq = 0;
+
+function next_seq() {
+ _rpc_seq += 1;
+ return _rpc_seq;
+}
+
+function get_seq() {
+ return _rpc_seq;
+}
+
+function activeFeedIsCat() {
+ return _active_feed_is_cat;
+}
+
+function getActiveFeedId() {
+ try {
+ //console.log("gAFID: " + _active_feed_id);
+ return _active_feed_id;
+ } catch (e) {
+ exception_error("getActiveFeedId", e);
+ }
+}
+
+function setActiveFeedId(id, is_cat) {
+ try {
+ _active_feed_id = id;
+
+ if (is_cat != undefined) {
+ _active_feed_is_cat = is_cat;
+ }
+
+ selectFeed(id, is_cat);
+
+ } catch (e) {
+ exception_error("setActiveFeedId", e);
+ }
+}
+
+
+function updateFeedList() {
+ try {
+
+// $("feeds-holder").innerHTML = "<div id=\"feedlistLoading\">" +
+// __("Loading, please wait...") + "</div>";
+
+ Element.show("feedlistLoading");
+
+ if (dijit.byId("feedTree")) {
+ dijit.byId("feedTree").destroyRecursive();
+ }
+
+ var store = new dojo.data.ItemFileWriteStore({
+ url: "backend.php?op=feeds"});
+
+ var treeModel = new fox.FeedStoreModel({
+ store: store,
+ query: {
+ "type": "feed"
+ },
+ rootId: "root",
+ rootLabel: "Feeds",
+ childrenAttrs: ["items"]
+ });
+
+ var tree = new fox.FeedTree({
+ persist: false,
+ model: treeModel,
+ onOpen: function (item, node) {
+ var id = String(item.id);
+ var cat_id = id.substr(id.indexOf(":")+1);
+
+ new Ajax.Request("backend.php",
+ { parameters: "backend.php?op=feeds&subop=collapse&cid=" +
+ param_escape(cat_id) + "&mode=0" } );
+ },
+ onClose: function (item, node) {
+ var id = String(item.id);
+ var cat_id = id.substr(id.indexOf(":")+1);
+
+ new Ajax.Request("backend.php",
+ { parameters: "backend.php?op=feeds&subop=collapse&cid=" +
+ param_escape(cat_id) + "&mode=1" } );
+
+ },
+ onClick: function (item, node) {
+ var id = String(item.id);
+ var is_cat = id.match("^CAT:");
+ var feed = id.substr(id.indexOf(":")+1);
+ viewfeed(feed, '', is_cat);
+ return false;
+ },
+ openOnClick: false,
+ showRoot: false,
+ id: "feedTree",
+ }, "feedTree");
+
+/* var menu = new dijit.Menu({id: 'feedMenu'});
+
+ menu.addChild(new dijit.MenuItem({
+ label: "Simple menu item"
+ }));
+
+// menu.bindDomNode(tree.domNode); */
+
+ var tmph = dojo.connect(dijit.byId('feedMenu'), '_openMyself', function (event) {
+ console.log(dijit.getEnclosingWidget(event.target));
+ dojo.disconnect(tmph);
+ });
+
+ $("feeds-holder").appendChild(tree.domNode);
+
+ var tmph = dojo.connect(tree, 'onLoad', function() {
+ dojo.disconnect(tmph);
+ Element.hide("feedlistLoading");
+
+ tree.collapseHiddenCats();
+
+ feedlist_init();
+
+// var node = dijit.byId("feedTree")._itemNodesMap['FEED:-2'][0].domNode
+// menu.bindDomNode(node);
+
+ loading_set_progress(25);
+ });
+
+ tree.startup();
+
+ } catch (e) {
+ exception_error("updateFeedList", e);
+ }
+}
+
+function catchupAllFeeds() {
+
+ var str = __("Mark all articles as read?");
+
+ if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
+
+ var query_str = "backend.php?op=feeds&subop=catchupAll";
+
+ notify_progress("Marking all feeds as read...");
+
+ //console.log("catchupAllFeeds Q=" + query_str);
+
+ new Ajax.Request("backend.php", {
+ parameters: query_str,
+ onComplete: function(transport) {
+ feedlist_callback2(transport);
+ } });
+
+ global_unread = 0;
+ updateTitle("");
+ }
+}
+
+function viewCurrentFeed(subop) {
+
+ if (getActiveFeedId() != undefined) {
+ viewfeed(getActiveFeedId(), subop, activeFeedIsCat());
+ }
+ return false; // block unneeded form submits
+}
+
+function timeout() {
+ if (getInitParam("bw_limit") == "1") return;
+
+ try {
+ var date = new Date();
+ var ts = Math.round(date.getTime() / 1000);
+
+ if (ts - last_scheduled_update > 10 || _force_scheduled_update) {
+
+ //console.log("timeout()");
+
+ window.clearTimeout(counter_timeout_id);
+
+ var query_str = "?op=rpc&subop=getAllCounters&seq=" + next_seq();
+
+ var omode;
+
+ if (firsttime_update && !navigator.userAgent.match("Opera")) {
+ firsttime_update = false;
+ omode = "T";
+ } else {
+ omode = "flc";
+ }
+
+ query_str = query_str + "&omode=" + omode;
+
+ if (!_force_scheduled_update)
+ query_str = query_str + "&last_article_id=" + getInitParam("last_article_id");
+
+ //console.log("[timeout]" + query_str);
+
+ new Ajax.Request("backend.php", {
+ parameters: query_str,
+ onComplete: function(transport) {
+ handle_rpc_json(transport, !_force_scheduled_update);
+ _force_scheduled_update = false;
+ } });
+
+ last_scheduled_update = ts;
+ }
+
+ } catch (e) {
+ exception_error("timeout", e);
+ }
+
+ setTimeout("timeout()", 3000);
+}
+
+function search() {
+ var query = "backend.php?op=dlg&id=search¶m=" +
+ param_escape(getActiveFeedId() + ":" + activeFeedIsCat());
+
+ if (dijit.byId("searchDlg"))
+ dijit.byId("searchDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "searchDlg",
+ title: __("Search"),
+ style: "width: 600px",
+ execute: function() {
+ if (this.validate()) {
+ _search_query = dojo.objectToQuery(this.attr('value'));
+ this.hide();
+ viewCurrentFeed();
+ }
+ },
+ href: query});
+
+ dialog.show();
+}
+
+function updateTitle() {
+ var tmp = "Tiny Tiny RSS";
+
+ if (global_unread > 0) {
+ tmp = tmp + " (" + global_unread + ")";
+ }
+
+ if (window.fluid) {
+ if (global_unread > 0) {
+ window.fluid.dockBadge = global_unread;
+ } else {
+ window.fluid.dockBadge = "";
+ }
+ }
+
+ document.title = tmp;
+}
+
+function genericSanityCheck() {
+ setCookie("ttrss_test", "TEST");
+
+ if (getCookie("ttrss_test") != "TEST") {
+ return fatalError(2);
+ }
+
+ return true;
+}
+
+function init() {
+ try {
+ dojo.registerModulePath("fox", "../../js/");
+
+ dojo.require("fox.FeedTree");
+
+ if (typeof themeBeforeLayout == 'function') {
+ themeBeforeLayout();
+ }
+
+ dojo.parser.parse();
+
+ dojo.addOnLoad(function() {
+ updateFeedList();
+ closeArticlePanel();
+
+ if (typeof themeAfterLayout == 'function') {
+ themeAfterLayout();
+ }
+
+ });
+
+ if (!genericSanityCheck())
+ return false;
+
+ loading_set_progress(20);
+
+ var hasAudio = !!((myAudioTag = document.createElement('audio')).canPlayType);
+
+ new Ajax.Request("backend.php", {
+ parameters: {op: "rpc", subop: "sanityCheck", hasAudio: hasAudio},
+ onComplete: function(transport) {
+ backend_sanity_check_callback(transport);
+ } });
+
+ } catch (e) {
+ exception_error("init", e);
+ }
+}
+
+function init_second_stage() {
+
+ try {
+
+ delCookie("ttrss_test");
+
+ var toolbar = document.forms["main_toolbar_form"];
+
+ dijit.getEnclosingWidget(toolbar.view_mode).attr('value',
+ getInitParam("default_view_mode"));
+
+ dijit.getEnclosingWidget(toolbar.order_by).attr('value',
+ getInitParam("default_view_order_by"));
+
+ feeds_sort_by_unread = getInitParam("feeds_sort_by_unread") == 1;
+
+ loading_set_progress(30);
+
+ // can't use cache_clear() here because viewfeed might not have initialized yet
+ if ('sessionStorage' in window && window['sessionStorage'] !== null)
+ sessionStorage.clear();
+
+ console.log("second stage ok");
+
+ } catch (e) {
+ exception_error("init_second_stage", e);
+ }
+}
+
+function quickMenuGo(opid) {
+ try {
+ if (opid == "qmcPrefs") {
+ gotoPreferences();
+ }
+
+ if (opid == "qmcTagCloud") {
+ displayDlg("printTagCloud");
+ }
+
+ if (opid == "qmcTagSelect") {
+ displayDlg("printTagSelect");
+ }
+
+ if (opid == "qmcSearch") {
+ search();
+ return;
+ }
+
+ if (opid == "qmcAddFeed") {
+ quickAddFeed();
+ return;
+ }
+
+ if (opid == "qmcDigest") {
+ window.location.href = "digest.php";
+ return;
+ }
+
+ if (opid == "qmcEditFeed") {
+ if (activeFeedIsCat())
+ alert(__("You can't edit this kind of feed."));
+ else
+ editFeed(getActiveFeedId());
+ return;
+ }
+
+ if (opid == "qmcRemoveFeed") {
+ var actid = getActiveFeedId();
+
+ if (activeFeedIsCat()) {
+ alert(__("You can't unsubscribe from the category."));
+ return;
+ }
+
+ if (!actid) {
+ alert(__("Please select some feed first."));
+ return;
+ }
+
+ var fn = getFeedName(actid);
+
+ var pr = __("Unsubscribe from %s?").replace("%s", fn);
+
+ if (confirm(pr)) {
+ unsubscribeFeed(actid);
+ }
+
+ return;
+ }
+
+ if (opid == "qmcCatchupAll") {
+ catchupAllFeeds();
+ return;
+ }
+
+ if (opid == "qmcShowOnlyUnread") {
+ toggleDispRead();
+ return;
+ }
+
+ if (opid == "qmcAddFilter") {
+ quickAddFilter();
+ return;
+ }
+
+ if (opid == "qmcAddLabel") {
+ addLabel();
+ return;
+ }
+
+ if (opid == "qmcRescoreFeed") {
+ rescoreCurrentFeed();
+ return;
+ }
+
+ if (opid == "qmcHKhelp") {
+ //Element.show("hotkey_help_overlay");
+ Effect.Appear("hotkey_help_overlay", {duration : 0.3});
+ }
+
+ if (opid == "qmcAbout") {
+ dialog = new dijit.Dialog({
+ title: __("About..."),
+ style: "width: 400px",
+ href: "backend.php?op=dlg&id=about",
+ });
+
+ dialog.show();
+ }
+
+ } catch (e) {
+ exception_error("quickMenuGo", e);
+ }
+}
+
+function toggleDispRead() {
+ try {
+
+ var hide = !(getInitParam("hide_read_feeds") == "1");
+
+ hideOrShowFeeds(hide);
+
+ var query = "?op=rpc&subop=setpref&key=HIDE_READ_FEEDS&value=" +
+ param_escape(hide);
+
+ setInitParam("hide_read_feeds", hide);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ } });
+
+ } catch (e) {
+ exception_error("toggleDispRead", e);
+ }
+}
+
+function parse_runtime_info(data) {
+
+ //console.log("parsing runtime info...");
+
+ for (k in data) {
+ var v = data[k];
+
+// console.log("RI: " + k + " => " + v);
+
+ if (k == "new_version_available") {
+ var icon = $("newVersionIcon");
+ if (icon) {
+ if (v == "1") {
+ icon.style.display = "inline";
+ } else {
+ icon.style.display = "none";
+ }
+ }
+ return;
+ }
+
+ if (k == "daemon_is_running" && v != 1) {
+ notify_error("<span onclick=\"javascript:explainError(1)\">Update daemon is not running.</span>", true);
+ return;
+ }
+
+ if (k == "daemon_stamp_ok" && v != 1) {
+ notify_error("<span onclick=\"javascript:explainError(3)\">Update daemon is not updating feeds.</span>", true);
+ return;
+ }
+
+ if (k == "max_feed_id" || k == "num_feeds") {
+ if (init_params[k] != v) {
+ console.log("feed count changed, need to reload feedlist.");
+ updateFeedList();
+ }
+ }
+
+ init_params[k] = v;
+ notify('');
+ }
+}
+
+function catchupCurrentFeed() {
+
+ var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
+
+ var str = __("Mark all articles in %s as read?").replace("%s", fn);
+
+ if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
+ return viewCurrentFeed('MarkAllRead');
+ }
+}
+
+function catchupFeedInGroup(id) {
+
+ try {
+
+ var title = getFeedName(id);
+
+ var str = __("Mark all articles in %s as read?").replace("%s", title);
+
+ if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
+ return viewCurrentFeed('MarkAllReadGR:' + id);
+ }
+
+ } catch (e) {
+ exception_error("catchupFeedInGroup", e);
+ }
+}
+
+function collapse_feedlist() {
+ try {
+
+ if (!Element.visible('feeds-holder')) {
+ Element.show('feeds-holder');
+ Element.show('feeds-holder_splitter');
+ $("collapse_feeds_btn").innerHTML = "<<";
+ } else {
+ Element.hide('feeds-holder');
+ Element.hide('feeds-holder_splitter');
+ $("collapse_feeds_btn").innerHTML = ">>";
+ }
+
+ dijit.byId("main").resize();
+
+ query = "?op=rpc&subop=setpref&key=_COLLAPSED_FEEDLIST&value=true";
+ new Ajax.Request("backend.php", { parameters: query });
+
+ } catch (e) {
+ exception_error("collapse_feedlist", e);
+ }
+}
+
+function viewModeChanged() {
+ return viewCurrentFeed('');
+}
+
+function viewLimitChanged() {
+ return viewCurrentFeed('');
+}
+
+/* function adjustArticleScore(id, score) {
+ try {
+
+ var pr = prompt(__("Assign score to article:"), score);
+
+ if (pr != undefined) {
+ var query = "?op=rpc&subop=setScore&id=" + id + "&score=" + pr;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ viewCurrentFeed();
+ } });
+
+ }
+ } catch (e) {
+ exception_error("adjustArticleScore", e);
+ }
+} */
+
+function rescoreCurrentFeed() {
+
+ var actid = getActiveFeedId();
+
+ if (activeFeedIsCat() || actid < 0) {
+ alert(__("You can't rescore this kind of feed."));
+ return;
+ }
+
+ if (!actid) {
+ alert(__("Please select some feed first."));
+ return;
+ }
+
+ var fn = getFeedName(actid);
+ var pr = __("Rescore articles in %s?").replace("%s", fn);
+
+ if (confirm(pr)) {
+ notify_progress("Rescoring articles...");
+
+ var query = "?op=pref-feeds&subop=rescore&quiet=1&ids=" + actid;
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ viewCurrentFeed();
+ } });
+ }
+}
+
+function hotkey_handler(e) {
+ try {
+
+ if (e.target.nodeName == "INPUT" || e.target.nodeName == "TEXTAREA") return;
+
+ var keycode = false;
+ var shift_key = false;
+
+ var cmdline = $('cmdline');
+
+ try {
+ shift_key = e.shiftKey;
+ } catch (e) {
+
+ }
+
+ if (window.event) {
+ keycode = window.event.keyCode;
+ } else if (e) {
+ keycode = e.which;
+ }
+
+ var keychar = String.fromCharCode(keycode);
+
+ if (keycode == 27) { // escape
+ if (Element.visible("hotkey_help_overlay")) {
+ Element.hide("hotkey_help_overlay");
+ }
+ hotkey_prefix = false;
+ }
+
+ if (keycode == 16) return; // ignore lone shift
+ if (keycode == 17) return; // ignore lone ctrl
+
+ if ((keycode == 70 || keycode == 67 || keycode == 71 || keycode == 65)
+ && !hotkey_prefix) {
+
+ var date = new Date();
+ var ts = Math.round(date.getTime() / 1000);
+
+ hotkey_prefix = keycode;
+ hotkey_prefix_pressed = ts;
+
+ cmdline.innerHTML = keychar;
+ Element.show(cmdline);
+
+ console.log("KP: PREFIX=" + keycode + " CHAR=" + keychar + " TS=" + ts);
+ return true;
+ }
+
+ if (Element.visible("hotkey_help_overlay")) {
+ Element.hide("hotkey_help_overlay");
+ }
+
+ /* Global hotkeys */
+
+ Element.hide(cmdline);
+
+ if (!hotkey_prefix) {
+
+ if (keycode == 27) { // escape
+ closeArticlePanel();
+ return;
+ }
+
+ if (keycode == 69) { // e
+ var id = getActiveArticleId();
+ emailArticle(id);
+ }
+
+ if ((keycode == 191 || keychar == '?') && shift_key) { // ?
+ if (!Element.visible("hotkey_help_overlay")) {
+ Effect.Appear("hotkey_help_overlay", {duration : 0.3, to : 0.9});
+ } else {
+ Element.hide("hotkey_help_overlay");
+ }
+ return false;
+ }
+
+ if (keycode == 191 || keychar == '/') { // /
+ search();
+ return false;
+ }
+
+ if (keycode == 74 && !shift_key) { // j
+ var rv = dijit.byId("feedTree").getPreviousFeed(
+ getActiveFeedId(), activeFeedIsCat());
+
+ if (rv) viewfeed(rv[0], '', rv[1]);
+
+ return;
+ }
+
+ if (keycode == 75) { // k
+ var rv = dijit.byId("feedTree").getNextFeed(
+ getActiveFeedId(), activeFeedIsCat());
+
+ if (rv) viewfeed(rv[0], '', rv[1]);
+
+ return;
+ }
+
+ if (shift_key && keycode == 40) { // shift-down
+ catchupRelativeToArticle(1);
+ return;
+ }
+
+ if (shift_key && keycode == 38) { // shift-up
+ catchupRelativeToArticle(0);
+ return;
+ }
+
+ if (shift_key && keycode == 78) { // N
+ scrollArticle(50);
+ return;
+ }
+
+ if (shift_key && keycode == 80) { // P
+ scrollArticle(-50);
+ return;
+ }
+
+ if (keycode == 68 && shift_key) { // shift-D
+ dismissSelectedArticles();
+ return;
+ }
+
+ if (keycode == 88 && shift_key) { // shift-X
+ dismissReadArticles();
+ return;
+ }
+
+ if (keycode == 78 || keycode == 40) { // n, down
+ if (typeof moveToPost != 'undefined') {
+ moveToPost('next');
+ return false;
+ }
+ }
+
+ if (keycode == 80 || keycode == 38) { // p, up
+ if (typeof moveToPost != 'undefined') {
+ moveToPost('prev');
+ return false;
+ }
+ }
+
+ if (keycode == 83 && shift_key) { // S
+ selectionTogglePublished(undefined, false, true);
+ return;
+ }
+
+ if (keycode == 83) { // s
+ selectionToggleMarked(undefined, false, true);
+ return;
+ }
+
+ if (keycode == 85) { // u
+ selectionToggleUnread(undefined, false, true);
+ return;
+ }
+
+ if (keycode == 84 && shift_key) { // T
+ var id = getActiveArticleId();
+ if (id) {
+ editArticleTags(id, getActiveFeedId(), isCdmMode());
+ return;
+ }
+ }
+
+ if (keycode == 9) { // tab
+ var id = getArticleUnderPointer();
+ if (id) {
+ var cb = $("RCHK-" + id);
+
+ if (cb) {
+ cb.checked = !cb.checked;
+ toggleSelectRowById(cb, "RROW-" + id);
+ return false;
+ }
+ }
+ }
+
+ if (keycode == 79) { // o
+ if (getActiveArticleId()) {
+ openArticleInNewWindow(getActiveArticleId());
+ return;
+ }
+ }
+
+ if (keycode == 81 && shift_key) { // Q
+ if (typeof catchupAllFeeds != 'undefined') {
+ catchupAllFeeds();
+ return;
+ }
+ }
+
+ if (keycode == 88 && !shift_key) { // x
+ if (activeFeedIsCat()) {
+ dijit.byId("feedTree").collapseCat(getActiveFeedId());
+ return;
+ }
+ }
+ }
+
+ /* Prefix a */
+
+ if (hotkey_prefix == 65) { // a
+ hotkey_prefix = false;
+
+ if (keycode == 65) { // a
+ selectArticles('all');
+ return;
+ }
+
+ if (keycode == 85) { // u
+ selectArticles('unread');
+ return;
+ }
+
+ if (keycode == 73) { // i
+ selectArticles('invert');
+ return;
+ }
+
+ if (keycode == 78) { // n
+ selectArticles('none');
+ return;
+ }
+
+ }
+
+ /* Prefix f */
+
+ if (hotkey_prefix == 70) { // f
+
+ hotkey_prefix = false;
+
+ if (keycode == 81) { // q
+ if (getActiveFeedId()) {
+ catchupCurrentFeed();
+ return;
+ }
+ }
+
+ if (keycode == 82) { // r
+ if (getActiveFeedId()) {
+ viewfeed(getActiveFeedId(), '', activeFeedIsCat());
+ return;
+ }
+ }
+
+ if (keycode == 65) { // a
+ toggleDispRead();
+ return false;
+ }
+
+ if (keycode == 85) { // u
+ if (getActiveFeedId()) {
+ viewfeed(getActiveFeedId(), '');
+ return false;
+ }
+ }
+
+ if (keycode == 69) { // e
+
+ if (activeFeedIsCat())
+ alert(__("You can't edit this kind of feed."));
+ else
+ editFeed(getActiveFeedId());
+ return;
+
+ return false;
+ }
+
+ if (keycode == 83) { // s
+ quickAddFeed();
+ return false;
+ }
+
+ if (keycode == 67 && shift_key) { // C
+ if (typeof catchupAllFeeds != 'undefined') {
+ catchupAllFeeds();
+ return false;
+ }
+ }
+
+ if (keycode == 67) { // c
+ if (getActiveFeedId()) {
+ catchupCurrentFeed();
+ return false;
+ }
+ }
+
+ if (keycode == 88) { // x
+ reverseHeadlineOrder();
+ return;
+ }
+ }
+
+ /* Prefix c */
+
+ if (hotkey_prefix == 67) { // c
+ hotkey_prefix = false;
+
+ if (keycode == 70) { // f
+ quickAddFilter();
+ return false;
+ }
+
+ if (keycode == 76) { // l
+ addLabel();
+ return false;
+ }
+
+ if (keycode == 83) { // s
+ if (typeof collapse_feedlist != 'undefined') {
+ collapse_feedlist();
+ return false;
+ }
+ }
+
+ if (keycode == 77) { // m
+ // TODO: sortable feedlist
+ return;
+ }
+
+ if (keycode == 78) { // n
+ catchupRelativeToArticle(1);
+ return;
+ }
+
+ if (keycode == 80) { // p
+ catchupRelativeToArticle(0);
+ return;
+ }
+
+
+ }
+
+ /* Prefix g */
+
+ if (hotkey_prefix == 71) { // g
+
+ hotkey_prefix = false;
+
+
+ if (keycode == 65) { // a
+ viewfeed(-4);
+ return false;
+ }
+
+ if (keycode == 83) { // s
+ viewfeed(-1);
+ return false;
+ }
+
+ if (keycode == 80 && shift_key) { // P
+ gotoPreferences();
+ return false;
+ }
+
+ if (keycode == 80) { // p
+ viewfeed(-2);
+ return false;
+ }
+
+ if (keycode == 70) { // f
+ viewfeed(-3);
+ return false;
+ }
+
+ if (keycode == 84) { // t
+ displayDlg("printTagCloud");
+ return false;
+ }
+ }
+
+ /* Cmd */
+
+ if (hotkey_prefix == 224 || hotkey_prefix == 91) { // f
+ hotkey_prefix = false;
+ return;
+ }
+
+ if (hotkey_prefix) {
+ console.log("KP: PREFIX=" + hotkey_prefix + " CODE=" + keycode + " CHAR=" + keychar);
+ } else {
+ console.log("KP: CODE=" + keycode + " CHAR=" + keychar);
+ }
+
+
+ } catch (e) {
+ exception_error("hotkey_handler", e);
+ }
+}
+
+function inPreferences() {
+ return false;
+}
+
+function reverseHeadlineOrder() {
+ try {
+
+ var query_str = "?op=rpc&subop=togglepref&key=REVERSE_HEADLINES";
+
+ new Ajax.Request("backend.php", {
+ parameters: query_str,
+ onComplete: function(transport) {
+ viewCurrentFeed();
+ } });
+
+ } catch (e) {
+ exception_error("reverseHeadlineOrder", e);
+ }
+}
+
+function scheduleFeedUpdate(id, is_cat) {
+ try {
+ if (!id) {
+ id = getActiveFeedId();
+ is_cat = activeFeedIsCat();
+ }
+
+ if (!id) {
+ alert(__("Please select some feed first."));
+ return;
+ }
+
+ var query = "?op=rpc&subop=scheduleFeedUpdate&id=" +
+ param_escape(id) +
+ "&is_cat=" + param_escape(is_cat);
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+
+ var reply = JSON.parse(transport.responseText);
+ var message = reply['message'];
+
+ if (message) {
+ notify_info(message);
+ return;
+ }
+
+ } });
+
+
+ } catch (e) {
+ exception_error("scheduleFeedUpdate", e);
+ }
+}
+
+function newVersionDlg() {
+ try {
+ var query = "backend.php?op=dlg&id=newVersion";
+
+ if (dijit.byId("newVersionDlg"))
+ dijit.byId("newVersionDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "newVersionDlg",
+ title: __("New version available!"),
+ style: "width: 600px",
+ href: query,
+ });
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("newVersionDlg", e);
+ }
+}
+
+function handle_rpc_json(transport, scheduled_call) {
+ try {
+ var reply = JSON.parse(transport.responseText);
+
+ if (reply) {
+
+ var error = reply['error'];
+
+ if (error) {
+ var code = error['code'];
+ var msg = error['msg'];
+
+ console.warn("[handle_rpc_json] received fatal error " + code + "/" + msg);
+
+ if (code != 0) {
+ fatalError(code, msg);
+ return false;
+ }
+ }
+
+ var seq = reply['seq'];
+
+ if (seq) {
+ if (get_seq() != seq) {
+ console.log("[handle_rpc_json] sequence mismatch: " + seq +
+ " (want: " + get_seq() + ")");
+ return true;
+ }
+ }
+
+ var message = reply['message'];
+
+ if (message) {
+ if (message == "UPDATE_COUNTERS") {
+ console.log("need to refresh counters...");
+ setInitParam("last_article_id", -1);
+ _force_scheduled_update = true;
+ }
+ }
+
+ var counters = reply['counters'];
+
+ if (counters)
+ parse_counters(counters, scheduled_call);
+
+ var runtime_info = reply['runtime-info'];;
+
+ if (runtime_info)
+ parse_runtime_info(runtime_info);
+
+ hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
+
+ } else {
+ notify_error("Error communicating with server.");
+ }
+
+ } catch (e) {
+ notify_error("Error communicating with server.");
+ console.log(e);
+ //exception_error("handle_rpc_json", e, transport);
+ }
+
+ return true;
+}
+
--- /dev/null
+var active_post_id = false;
+
+var article_cache = new Array();
+
+var vgroup_last_feed = false;
+var post_under_pointer = false;
+
+var last_requested_article = false;
+
+var catchup_id_batch = [];
+var catchup_timeout_id = false;
+var feed_precache_timeout_id = false;
+var precache_idle_timeout_id = false;
+
+var cids_requested = [];
+
+var has_storage = 'sessionStorage' in window && window['sessionStorage'] !== null;
+
+function headlines_callback2(transport, offset, background, infscroll_req) {
+ try {
+ handle_rpc_json(transport);
+
+ loading_set_progress(25);
+
+ console.log("headlines_callback2 [offset=" + offset + "] B:" + background + " I:" + infscroll_req);
+
+ var is_cat = false;
+ var feed_id = false;
+
+ var reply = false;
+
+ try {
+ reply = JSON.parse(transport.responseText);
+ } catch (e) {
+ console.error(e);
+ }
+
+ if (reply) {
+
+ is_cat = reply['headlines']['is_cat'];
+ feed_id = reply['headlines']['id'];
+
+ if (background) {
+ var content = reply['headlines']['content'];
+
+ if (getInitParam("cdm_auto_catchup") == 1) {
+ content = content + "<div id='headlines-spacer'></div>";
+ }
+
+ cache_headlines(feed_id, is_cat, reply['headlines']['toolbar'], content);
+ return;
+ }
+
+ setActiveFeedId(feed_id, is_cat);
+
+ try {
+ if (offset == 0 && infscroll_req == false) {
+ $("headlines-frame").scrollTop = 0;
+ }
+ } catch (e) { };
+
+ var headlines_count = reply['headlines-info']['count'];
+
+ vgroup_last_feed = reply['headlines-info']['vgroup_last_feed'];
+
+ if (parseInt(headlines_count) < getInitParam("default_article_limit")) {
+ _infscroll_disable = 1;
+ } else {
+ _infscroll_disable = 0;
+ }
+
+ var counters = reply['counters'];
+ var articles = reply['articles'];
+ //var runtime_info = reply['runtime-info'];
+
+ if (offset == 0 && infscroll_req == false) {
+ dijit.byId("headlines-frame").attr('content',
+ reply['headlines']['content']);
+
+ dijit.byId("headlines-toolbar").attr('content',
+ reply['headlines']['toolbar']);
+
+
+ if (getInitParam("cdm_auto_catchup") == 1) {
+ var hsp = $("headlines-spacer");
+ if (!hsp) hsp = new Element("DIV", {"id": "headlines-spacer"});
+ dijit.byId('headlines-frame').domNode.appendChild(hsp);
+ }
+
+ initHeadlinesMenu();
+
+ } else {
+
+ if (headlines_count > 0 && feed_id == getActiveFeedId() && is_cat == activeFeedIsCat()) {
+ console.log("adding some more headlines...");
+
+ var c = dijit.byId("headlines-frame");
+ var ids = getSelectedArticleIds2();
+
+ $("headlines-tmp").innerHTML = reply['headlines']['content'];
+
+ var hsp = $("headlines-spacer");
+
+ if (hsp)
+ c.domNode.removeChild(hsp);
+
+ $$("#headlines-tmp > div").each(function(row) {
+ if ($$("#headlines-frame DIV[id="+row.id+"]").length == 0) {
+ row.style.display = 'none';
+ c.domNode.appendChild(row);
+ } else {
+ row.parentNode.removeChild(row);
+ }
+ });
+
+ if (!hsp) hsp = new Element("DIV", {"id": "headlines-spacer"});
+
+ fixHeadlinesOrder(getLoadedArticleIds());
+
+ if (getInitParam("cdm_auto_catchup") == 1) {
+ c.domNode.appendChild(hsp);
+ }
+
+ console.log("restore selected ids: " + ids);
+
+ for (var i = 0; i < ids.length; i++) {
+ markHeadline(ids[i]);
+ }
+
+ initHeadlinesMenu();
+
+ $$("#headlines-frame > div[id*=RROW]").each(
+ function(child) {
+ if (!Element.visible(child))
+ new Effect.Appear(child, { duration : 0.5 });
+ });
+
+ } else {
+ console.log("no new headlines received");
+
+ var hsp = $("headlines-spacer");
+
+ if (hsp) hsp.innerHTML = "";
+ }
+ }
+
+ if (headlines_count > 0)
+ cache_headlines(feed_id, is_cat, reply['headlines']['toolbar'], $("headlines-frame").innerHTML);
+
+ if (articles) {
+ for (var i = 0; i < articles.length; i++) {
+ var a_id = articles[i]['id'];
+ cache_set("article:" + a_id, articles[i]['content']);
+ }
+ } else {
+ console.log("no cached articles received");
+ }
+
+ // do not precache stuff after fresh feed
+ if (feed_id != -3)
+ precache_headlines();
+
+ if (counters)
+ parse_counters(counters);
+ else
+ request_counters();
+
+ } else {
+ console.error("Invalid object received: " + transport.responseText);
+ dijit.byId("headlines-frame").attr('content', "<div class='whiteBox'>" +
+ __('Could not update headlines (invalid object received - see error console for details)') +
+ "</div>");
+ }
+
+ _infscroll_request_sent = 0;
+
+ notify("");
+
+ } catch (e) {
+ exception_error("headlines_callback2", e, transport);
+ }
+}
+
+function render_article(article) {
+ try {
+ dijit.byId("headlines-wrap-inner").addChild(
+ dijit.byId("content-insert"));
+
+ var c = dijit.byId("content-insert");
+
+ try {
+ c.domNode.scrollTop = 0;
+ } catch (e) { };
+
+ c.attr('content', article);
+
+ correctHeadlinesOffset(getActiveArticleId());
+
+ try {
+ c.focus();
+ } catch (e) { };
+
+ } catch (e) {
+ exception_error("render_article", e);
+ }
+}
+
+function showArticleInHeadlines(id) {
+
+ try {
+
+ selectArticles("none");
+
+ var crow = $("RROW-" + id);
+
+ if (!crow) return;
+
+ var article_is_unread = crow.hasClassName("Unread");
+
+ crow.removeClassName("Unread");
+
+ selectArticles('none');
+
+ var upd_img_pic = $("FUPDPIC-" + id);
+
+ var view_mode = false;
+
+ try {
+ view_mode = document.forms['main_toolbar_form'].view_mode;
+ view_mode = view_mode[view_mode.selectedIndex].value;
+ } catch (e) {
+ //
+ }
+
+ if (upd_img_pic && (upd_img_pic.src.match("updated.png") ||
+ upd_img_pic.src.match("fresh_sign.png"))) {
+
+ upd_img_pic.src = "images/blank_icon.gif";
+
+ cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
+
+ } else if (article_is_unread && view_mode == "all_articles") {
+ cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
+ }
+
+ markHeadline(id);
+
+ if (article_is_unread)
+ _force_scheduled_update = true;
+
+ } catch (e) {
+ exception_error("showArticleInHeadlines", e);
+ }
+}
+
+function article_callback2(transport, id) {
+ try {
+ console.log("article_callback2 " + id);
+
+ handle_rpc_json(transport);
+
+ var reply = false;
+
+ try {
+ reply = JSON.parse(transport.responseText);
+ } catch (e) {
+ console.error(e);
+ }
+
+ if (reply) {
+
+ var upic = $('FUPDPIC-' + id);
+
+ if (upic) upic.src = 'images/blank_icon.gif';
+
+ reply.each(function(article) {
+ if (active_post_id == article['id']) {
+ render_article(article['content']);
+ }
+ cids_requested.remove(article['id']);
+
+ cache_set("article:" + article['id'], article['content']);
+ });
+
+// if (id != last_requested_article) {
+// console.log("requested article id is out of sequence, aborting");
+// return;
+// }
+
+ } else {
+ console.error("Invalid object received: " + transport.responseText);
+
+ render_article("<div class='whiteBox'>" +
+ __('Could not display article (invalid object received - see error console for details)') + "</div>");
+ }
+
+ request_counters();
+
+ try {
+ if (!_infscroll_disable &&
+ $$("#headlines-frame > div[id*=RROW]").last().hasClassName("Selected")) {
+
+ loadMoreHeadlines();
+ }
+ } catch (e) {
+ console.warn(e);
+ }
+
+ notify("");
+ } catch (e) {
+ exception_error("article_callback2", e, transport);
+ }
+}
+
+function view(id) {
+ try {
+ console.log("loading article: " + id);
+
+ var cached_article = cache_get("article:" + id);
+
+ console.log("cache check result: " + (cached_article != false));
+
+ hideAuxDlg();
+
+ var query = "?op=view&id=" + param_escape(id);
+
+ var neighbor_ids = getRelativePostIds(id);
+
+ /* only request uncached articles */
+
+ var cids_to_request = [];
+
+ for (var i = 0; i < neighbor_ids.length; i++) {
+ if (cids_requested.indexOf(neighbor_ids[i]) == -1)
+ if (!cache_get("article:" + neighbor_ids[i])) {
+ cids_to_request.push(neighbor_ids[i]);
+ cids_requested.push(neighbor_ids[i]);
+ }
+ }
+
+ console.log("additional ids: " + cids_to_request.toString());
+
+ query = query + "&cids=" + cids_to_request.toString();
+
+ var crow = $("RROW-" + id);
+ var article_is_unread = crow.hasClassName("Unread");
+
+ active_post_id = id;
+ showArticleInHeadlines(id);
+
+ precache_headlines();
+
+ if (!cached_article) {
+
+ var upic = $('FUPDPIC-' + id);
+
+ if (upic) {
+ upic.src = getInitParam("sign_progress");
+ }
+
+ } else if (cached_article && article_is_unread) {
+
+ query = query + "&mode=prefetch";
+
+ render_article(cached_article);
+
+ } else if (cached_article) {
+
+ query = query + "&mode=prefetch_old";
+ render_article(cached_article);
+
+ // if we don't need to request any relative ids, we might as well skip
+ // the server roundtrip altogether
+ if (cids_to_request.length == 0) {
+
+ try {
+ if (!_infscroll_disable &&
+ $$("#headlines-frame > div[id*=RROW]").last().hasClassName("Selected")) {
+
+ loadMoreHeadlines();
+ }
+ } catch (e) {
+ console.warn(e);
+ }
+
+ return;
+ }
+ }
+
+ last_requested_article = id;
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ article_callback2(transport, id);
+ } });
+
+ return false;
+
+ } catch (e) {
+ exception_error("view", e);
+ }
+}
+
+function toggleMark(id, client_only) {
+ try {
+ var query = "?op=rpc&id=" + id + "&subop=mark";
+
+ var img = $("FMPIC-" + id);
+
+ if (!img) return;
+
+ if (img.src.match("mark_unset")) {
+ img.src = img.src.replace("mark_unset", "mark_set");
+ img.alt = __("Unstar article");
+ query = query + "&mark=1";
+
+ } else {
+ img.src = img.src.replace("mark_set", "mark_unset");
+ img.alt = __("Star article");
+ query = query + "&mark=0";
+ }
+
+ cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
+
+ if (!client_only) {
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+ }
+
+ } catch (e) {
+ exception_error("toggleMark", e);
+ }
+}
+
+function togglePub(id, client_only, no_effects, note) {
+ try {
+ var query = "?op=rpc&id=" + id + "&subop=publ";
+
+ if (note != undefined) {
+ query = query + "¬e=" + param_escape(note);
+ } else {
+ query = query + "¬e=undefined";
+ }
+
+ var img = $("FPPIC-" + id);
+
+ if (!img) return;
+
+ if (img.src.match("pub_unset") || note != undefined) {
+ img.src = img.src.replace("pub_unset", "pub_set");
+ img.alt = __("Unpublish article");
+ query = query + "&pub=1";
+
+ } else {
+ img.src = img.src.replace("pub_set", "pub_unset");
+ img.alt = __("Publish article");
+
+ query = query + "&pub=0";
+ }
+
+ cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
+
+ if (!client_only) {
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+ }
+
+ } catch (e) {
+ exception_error("togglePub", e);
+ }
+}
+
+function moveToPost(mode) {
+
+ try {
+
+ var rows = getVisibleArticleIds();
+
+ var prev_id = false;
+ var next_id = false;
+
+ if (!$('RROW-' + active_post_id)) {
+ active_post_id = false;
+ }
+
+ if (active_post_id == false) {
+ next_id = getFirstVisibleHeadlineId();
+ prev_id = getLastVisibleHeadlineId();
+ } else {
+ for (var i = 0; i < rows.length; i++) {
+ if (rows[i] == active_post_id) {
+ prev_id = rows[i-1];
+ next_id = rows[i+1];
+ }
+ }
+ }
+
+ if (mode == "next") {
+ if (next_id) {
+ if (isCdmMode()) {
+
+ cdmExpandArticle(next_id);
+ cdmScrollToArticleId(next_id);
+
+ } else {
+ correctHeadlinesOffset(next_id);
+ view(next_id, getActiveFeedId());
+ }
+ }
+ }
+
+ if (mode == "prev") {
+ if (prev_id) {
+ if (isCdmMode()) {
+ cdmExpandArticle(prev_id);
+ cdmScrollToArticleId(prev_id);
+ } else {
+ correctHeadlinesOffset(prev_id);
+ view(prev_id, getActiveFeedId());
+ }
+ }
+ }
+
+ } catch (e) {
+ exception_error("moveToPost", e);
+ }
+}
+
+function toggleSelected(id, force_on) {
+ try {
+
+ var cb = $("RCHK-" + id);
+ var row = $("RROW-" + id);
+
+ if (row) {
+ if (row.hasClassName('Selected') && !force_on) {
+ row.removeClassName('Selected');
+ if (cb) cb.checked = false;
+ } else {
+ row.addClassName('Selected');
+ if (cb) cb.checked = true;
+ }
+ }
+ } catch (e) {
+ exception_error("toggleSelected", e);
+ }
+}
+
+function toggleUnread_afh(effect) {
+ try {
+
+ var elem = effect.element;
+ elem.style.backgroundColor = "";
+
+ } catch (e) {
+ exception_error("toggleUnread_afh", e);
+ }
+}
+
+function toggleUnread(id, cmode, effect) {
+ try {
+
+ var row = $("RROW-" + id);
+ if (row) {
+ if (cmode == undefined || cmode == 2) {
+ if (row.hasClassName("Unread")) {
+ row.removeClassName("Unread");
+
+ if (effect) {
+ new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
+ afterFinish: toggleUnread_afh,
+ queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
+ }
+
+ } else {
+ row.addClassName("Unread");
+ }
+
+ } else if (cmode == 0) {
+
+ row.removeClassName("Unread");
+
+ if (effect) {
+ new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
+ afterFinish: toggleUnread_afh,
+ queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
+ }
+
+ } else if (cmode == 1) {
+ row.addClassName("Unread");
+ }
+
+ if (cmode == undefined) cmode = 2;
+
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=" + param_escape(cmode) + "&ids=" + param_escape(id);
+
+// notify_progress("Loading, please wait...");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("toggleUnread", e);
+ }
+}
+
+function selectionRemoveLabel(id, ids) {
+ try {
+
+ if (!ids) ids = getSelectedArticleIds2();
+
+ if (ids.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ var query = "?op=rpc&subop=removeFromLabel&ids=" +
+ param_escape(ids.toString()) + "&lid=" + param_escape(id);
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ show_labels_in_headlines(transport);
+ } });
+
+ } catch (e) {
+ exception_error("selectionAssignLabel", e);
+
+ }
+}
+
+function selectionAssignLabel(id, ids) {
+ try {
+
+ if (!ids) ids = getSelectedArticleIds2();
+
+ if (ids.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ var query = "?op=rpc&subop=assignToLabel&ids=" +
+ param_escape(ids.toString()) + "&lid=" + param_escape(id);
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ show_labels_in_headlines(transport);
+ } });
+
+ } catch (e) {
+ exception_error("selectionAssignLabel", e);
+
+ }
+}
+
+function selectionToggleUnread(set_state, callback, no_error) {
+ try {
+ var rows = getSelectedArticleIds2();
+
+ if (rows.length == 0 && !no_error) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ for (var i = 0; i < rows.length; i++) {
+ var row = $("RROW-" + rows[i]);
+ if (row) {
+ if (set_state == undefined) {
+ if (row.hasClassName("Unread")) {
+ row.removeClassName("Unread");
+ } else {
+ row.addClassName("Unread");
+ }
+ }
+
+ if (set_state == false) {
+ row.removeClassName("Unread");
+ }
+
+ if (set_state == true) {
+ row.addClassName("Unread");
+ }
+ }
+ }
+
+ if (rows.length > 0) {
+
+ var cmode = "";
+
+ if (set_state == undefined) {
+ cmode = "2";
+ } else if (set_state == true) {
+ cmode = "1";
+ } else if (set_state == false) {
+ cmode = "0";
+ }
+
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=" + cmode + "&ids=" + param_escape(rows.toString());
+
+ notify_progress("Loading, please wait...");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ if (callback) callback(transport);
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("selectionToggleUnread", e);
+ }
+}
+
+function selectionToggleMarked() {
+ try {
+
+ var rows = getSelectedArticleIds2();
+
+ if (rows.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ for (var i = 0; i < rows.length; i++) {
+ toggleMark(rows[i], true, true);
+ }
+
+ if (rows.length > 0) {
+
+ var query = "?op=rpc&subop=markSelected&ids=" +
+ param_escape(rows.toString()) + "&cmode=2";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("selectionToggleMarked", e);
+ }
+}
+
+function selectionTogglePublished() {
+ try {
+
+ var rows = getSelectedArticleIds2();
+
+ if (rows.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ for (var i = 0; i < rows.length; i++) {
+ togglePub(rows[i], true, true);
+ }
+
+ if (rows.length > 0) {
+
+ var query = "?op=rpc&subop=publishSelected&ids=" +
+ param_escape(rows.toString()) + "&cmode=2";
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+
+ }
+
+ } catch (e) {
+ exception_error("selectionToggleMarked", e);
+ }
+}
+
+function getSelectedArticleIds2() {
+
+ var rv = [];
+
+ $$("#headlines-frame > div[id*=RROW][class*=Selected]").each(
+ function(child) {
+ rv.push(child.id.replace("RROW-", ""));
+ });
+
+ return rv;
+}
+
+function getLoadedArticleIds() {
+ var rv = [];
+
+ var children = $$("#headlines-frame > div[id*=RROW-]");
+
+ children.each(function(child) {
+ rv.push(child.id.replace("RROW-", ""));
+ });
+
+ return rv;
+
+}
+
+// mode = all,none,unread,invert
+function selectArticles(mode) {
+ try {
+
+ var children = $$("#headlines-frame > div[id*=RROW]");
+
+ children.each(function(child) {
+ var id = child.id.replace("RROW-", "");
+ var cb = $("RCHK-" + id);
+
+ if (mode == "all") {
+ child.addClassName("Selected");
+ cb.checked = true;
+ } else if (mode == "unread") {
+ if (child.hasClassName("Unread")) {
+ child.addClassName("Selected");
+ cb.checked = true;
+ } else {
+ child.removeClassName("Selected");
+ cb.checked = false;
+ }
+ } else if (mode == "invert") {
+ if (child.hasClassName("Selected")) {
+ child.removeClassName("Selected");
+ cb.checked = false;
+ } else {
+ child.addClassName("Selected");
+ cb.checked = true;
+ }
+
+ } else {
+ child.removeClassName("Selected");
+ cb.checked = false;
+ }
+ });
+
+ } catch (e) {
+ exception_error("selectArticles", e);
+ }
+}
+
+function catchupPage() {
+
+ var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
+
+ var str = __("Mark all visible articles in %s as read?");
+
+ str = str.replace("%s", fn);
+
+ if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
+ return;
+ }
+
+ selectArticles('all');
+ selectionToggleUnread(false, 'viewCurrentFeed()', true);
+ selectArticles('none');
+}
+
+function deleteSelection() {
+
+ try {
+
+ var rows = getSelectedArticleIds2();
+
+ if (rows.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
+ var str;
+
+ if (getActiveFeedId() != 0) {
+ str = __("Delete %d selected articles in %s?");
+ } else {
+ str = __("Delete %d selected articles?");
+ }
+
+ str = str.replace("%d", rows.length);
+ str = str.replace("%s", fn);
+
+ if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
+ return;
+ }
+
+ query = "?op=rpc&subop=delete&ids=" + param_escape(rows);
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ viewCurrentFeed();
+ } });
+
+ } catch (e) {
+ exception_error("deleteSelection", e);
+ }
+}
+
+function archiveSelection() {
+
+ try {
+
+ var rows = getSelectedArticleIds2();
+
+ if (rows.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
+ var str;
+ var op;
+
+ if (getActiveFeedId() != 0) {
+ str = __("Archive %d selected articles in %s?");
+ op = "archive";
+ } else {
+ str = __("Move %d archived articles back?");
+ op = "unarchive";
+ }
+
+ str = str.replace("%d", rows.length);
+ str = str.replace("%s", fn);
+
+ if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
+ return;
+ }
+
+ query = "?op=rpc&subop="+op+"&ids=" + param_escape(rows);
+
+ console.log(query);
+
+ for (var i = 0; i < rows.length; i++) {
+ cache_delete("article:" + rows[i]);
+ }
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ viewCurrentFeed();
+ } });
+
+ } catch (e) {
+ exception_error("archiveSelection", e);
+ }
+}
+
+function catchupSelection() {
+
+ try {
+
+ var rows = getSelectedArticleIds2();
+
+ if (rows.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
+
+ var str = __("Mark %d selected articles in %s as read?");
+
+ str = str.replace("%d", rows.length);
+ str = str.replace("%s", fn);
+
+ if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
+ return;
+ }
+
+ selectionToggleUnread(false, 'viewCurrentFeed()', true);
+
+ } catch (e) {
+ exception_error("catchupSelection", e);
+ }
+}
+
+function editArticleTags(id) {
+ var query = "backend.php?op=dlg&id=editArticleTags¶m=" + param_escape(id);
+
+ if (dijit.byId("editTagsDlg"))
+ dijit.byId("editTagsDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "editTagsDlg",
+ title: __("Edit article Tags"),
+ style: "width: 600px",
+ execute: function() {
+ if (this.validate()) {
+ var query = dojo.objectToQuery(this.attr('value'));
+
+ notify_progress("Saving article tags...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ dialog.hide();
+
+ var data = JSON.parse(transport.responseText);
+
+ if (data) {
+ var tags_str = article.tags;
+ var id = tags_str.id;
+
+ var tags = $("ATSTR-" + id);
+ var tooltip = dijit.byId("ATSTRTIP-" + id);
+
+ if (tags) tags.innerHTML = tags_str.content;
+ if (tooltip) tooltip.attr('label', tags_str.content_full);
+
+ cache_delete("article:" + id);
+ }
+
+ }});
+ }
+ },
+ href: query,
+ });
+
+ var tmph = dojo.connect(dialog, 'onLoad', function() {
+ dojo.disconnect(tmph);
+
+ new Ajax.Autocompleter('tags_str', 'tags_choices',
+ "backend.php?op=rpc&subop=completeTags",
+ { tokens: ',', paramName: "search" });
+ });
+
+ dialog.show();
+
+}
+
+function cdmScrollToArticleId(id) {
+ try {
+ var ctr = $("headlines-frame");
+ var e = $("RROW-" + id);
+
+ if (!e || !ctr) return;
+
+ ctr.scrollTop = e.offsetTop;
+
+ } catch (e) {
+ exception_error("cdmScrollToArticleId", e);
+ }
+}
+
+function getActiveArticleId() {
+ return active_post_id;
+}
+
+function postMouseIn(id) {
+ post_under_pointer = id;
+}
+
+function postMouseOut(id) {
+ post_under_pointer = false;
+}
+
+function headlines_scroll_handler(e) {
+ try {
+ var hsp = $("headlines-spacer");
+
+ if (!_infscroll_disable) {
+ if (hsp && (e.scrollTop + e.offsetHeight > hsp.offsetTop) ||
+ e.scrollTop + e.offsetHeight > e.scrollHeight - 100) {
+
+ if (hsp)
+ hsp.innerHTML = "<img src='images/indicator_tiny.gif'> " +
+ __("Loading, please wait...");
+
+ loadMoreHeadlines();
+ return;
+
+ }
+ } else {
+ if (hsp) hsp.innerHTML = "";
+ }
+
+ if (getInitParam("cdm_auto_catchup") == 1) {
+
+ $$("#headlines-frame > div[id*=RROW][class*=Unread]").each(
+ function(child) {
+ if ($("headlines-frame").scrollTop >
+ (child.offsetTop + child.offsetHeight/2)) {
+
+ var id = child.id.replace("RROW-", "");
+
+ if (catchup_id_batch.indexOf(id) == -1)
+ catchup_id_batch.push(id);
+
+ //console.log("auto_catchup_batch: " + catchup_id_batch.toString());
+ }
+ });
+
+ if (catchup_id_batch.length > 0) {
+ window.clearTimeout(catchup_timeout_id);
+
+ if (!_infscroll_request_sent) {
+ catchup_timeout_id = window.setTimeout('catchupBatchedArticles()',
+ 2000);
+ }
+ }
+ }
+
+ } catch (e) {
+ console.warn("headlines_scroll_handler: " + e);
+ }
+}
+
+function catchupBatchedArticles() {
+ try {
+ if (catchup_id_batch.length > 0 && !_infscroll_request_sent) {
+
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=0&ids=" + param_escape(catchup_id_batch.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+
+ catchup_id_batch.each(function(id) {
+ var elem = $("RROW-" + id);
+ if (elem) elem.removeClassName("Unread");
+ });
+
+ catchup_id_batch = [];
+ } });
+ }
+
+ } catch (e) {
+ exception_error("catchupBatchedArticles", e);
+ }
+}
+
+function catchupRelativeToArticle(below, id) {
+
+ try {
+
+ if (!id) id = getActiveArticleId();
+
+ if (!id) {
+ alert(__("No article is selected."));
+ return;
+ }
+
+ var visible_ids = getVisibleArticleIds();
+
+ var ids_to_mark = new Array();
+
+ if (!below) {
+ for (var i = 0; i < visible_ids.length; i++) {
+ if (visible_ids[i] != id) {
+ var e = $("RROW-" + visible_ids[i]);
+
+ if (e && e.hasClassName("Unread")) {
+ ids_to_mark.push(visible_ids[i]);
+ }
+ } else {
+ break;
+ }
+ }
+ } else {
+ for (var i = visible_ids.length-1; i >= 0; i--) {
+ if (visible_ids[i] != id) {
+ var e = $("RROW-" + visible_ids[i]);
+
+ if (e && e.hasClassName("Unread")) {
+ ids_to_mark.push(visible_ids[i]);
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (ids_to_mark.length == 0) {
+ alert(__("No articles found to mark"));
+ } else {
+ var msg = __("Mark %d article(s) as read?").replace("%d", ids_to_mark.length);
+
+ if (getInitParam("confirm_feed_catchup") != 1 || confirm(msg)) {
+
+ for (var i = 0; i < ids_to_mark.length; i++) {
+ var e = $("RROW-" + ids_to_mark[i]);
+ e.removeClassName("Unread");
+ }
+
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=0" + "&ids=" + param_escape(ids_to_mark.toString());
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+
+ }
+ }
+
+ } catch (e) {
+ exception_error("catchupRelativeToArticle", e);
+ }
+}
+
+function cdmExpandArticle(id) {
+ try {
+
+ hideAuxDlg();
+
+ var elem = $("CICD-" + active_post_id);
+
+ var upd_img_pic = $("FUPDPIC-" + id);
+
+ if (upd_img_pic && (upd_img_pic.src.match("updated.png") ||
+ upd_img_pic.src.match("fresh_sign.png"))) {
+
+ upd_img_pic.src = "images/blank_icon.gif";
+ }
+
+ if (id == active_post_id && Element.visible(elem))
+ return true;
+
+ selectArticles("none");
+
+ var old_offset = $("RROW-" + id).offsetTop;
+
+ if (active_post_id && elem && !getInitParam("cdm_expanded")) {
+ Element.hide(elem);
+ Element.show("CEXC-" + active_post_id);
+ }
+
+ active_post_id = id;
+
+ elem = $("CICD-" + id);
+
+ if (!Element.visible(elem)) {
+ Element.show(elem);
+ Element.hide("CEXC-" + id);
+
+ if ($("CWRAP-" + id).innerHTML == "") {
+
+ $("FUPDPIC-" + id).src = "images/indicator_tiny.gif";
+
+ $("CWRAP-" + id).innerHTML = "<div class=\"insensitive\">" +
+ __("Loading, please wait...") + "</div>";
+
+ var query = "?op=rpc&subop=cdmGetArticle&id=" + param_escape(id);
+
+ var neighbor_ids = getRelativePostIds(id);
+
+ /* only request uncached articles */
+ var cids_to_request = [];
+
+ for (var i = 0; i < neighbor_ids.length; i++) {
+ if (cids_requested.indexOf(neighbor_ids[i]) == -1)
+ if ($("CWRAP-" + neighbor_ids[i]).innerHTML == "") {
+ cids_to_request.push(neighbor_ids[i]);
+ cids_requested.push(neighbor_ids[i]);
+ }
+ }
+
+ console.log("additional ids: " + cids_to_request.toString());
+
+ query = query + "&cids=" + cids_to_request.toString();
+
+ console.log(query);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+
+ $("FUPDPIC-" + id).src = 'images/blank_icon.gif';
+
+ handle_rpc_json(transport);
+
+ var reply = JSON.parse(transport.responseText);
+
+ reply.each(function(article) {
+ $("CWRAP-" + article['id']).innerHTML = article['content'];
+ cids_requested.remove(article['id']);
+ });
+ }});
+
+ }
+ }
+
+ var new_offset = $("RROW-" + id).offsetTop;
+
+ $("headlines-frame").scrollTop += (new_offset-old_offset);
+
+ if ($("RROW-" + id).offsetTop != old_offset)
+ $("headlines-frame").scrollTop = new_offset;
+
+ toggleUnread(id, 0, true);
+ toggleSelected(id);
+
+ } catch (e) {
+ exception_error("cdmExpandArticle", e);
+ }
+
+ return false;
+}
+
+function fixHeadlinesOrder(ids) {
+ try {
+ for (var i = 0; i < ids.length; i++) {
+ var e = $("RROW-" + ids[i]);
+
+ if (e) {
+ if (i % 2 == 0) {
+ e.removeClassName("even");
+ e.addClassName("odd");
+ } else {
+ e.removeClassName("odd");
+ e.addClassName("even");
+ }
+ }
+ }
+ } catch (e) {
+ exception_error("fixHeadlinesOrder", e);
+ }
+}
+
+function getArticleUnderPointer() {
+ return post_under_pointer;
+}
+
+function zoomToArticle(event, id) {
+ try {
+ var cached_article = cache_get("article: " + id);
+
+ if (dijit.byId("ATAB-" + id))
+ if (!event || !event.shiftKey)
+ return dijit.byId("content-tabs").selectChild(dijit.byId("ATAB-" + id));
+
+ if (dijit.byId("ATSTRTIP-" + id))
+ dijit.byId("ATSTRTIP-" + id).destroyRecursive();
+
+ if (cached_article) {
+ //closeArticlePanel();
+
+ var article_pane = new dijit.layout.ContentPane({
+ title: __("Loading...") , content: cached_article,
+ style: 'padding : 0px;',
+ id: 'ATAB-' + id,
+ closable: true });
+
+ dijit.byId("content-tabs").addChild(article_pane);
+
+ if (!event || !event.shiftKey)
+ dijit.byId("content-tabs").selectChild(article_pane);
+
+ if ($("PTITLE-" + id))
+ article_pane.attr('title', $("PTITLE-" + id).innerHTML);
+
+ } else {
+
+ var query = "?op=rpc&subop=getArticles&ids=" + param_escape(id);
+
+ notify_progress("Loading, please wait...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+
+ var reply = JSON.parse(transport.responseText);
+
+ if (reply) {
+ //closeArticlePanel();
+
+ var content = reply[0]['content'];
+
+ var article_pane = new dijit.layout.ContentPane({
+ title: "article-" + id , content: content,
+ style: 'padding : 0px;',
+ id: 'ATAB-' + id,
+ closable: true });
+
+ dijit.byId("content-tabs").addChild(article_pane);
+
+ if (!event || !event.shiftKey)
+ dijit.byId("content-tabs").selectChild(article_pane);
+
+ if ($("PTITLE-" + id))
+ article_pane.attr('title', $("PTITLE-" + id).innerHTML);
+ }
+
+ } });
+ }
+
+ } catch (e) {
+ exception_error("zoomToArticle", e);
+ }
+}
+
+function scrollArticle(offset) {
+ try {
+ if (!isCdmMode()) {
+ var ci = $("content-insert");
+ if (ci) {
+ ci.scrollTop += offset;
+ }
+ } else {
+ var hi = $("headlines-frame");
+ if (hi) {
+ hi.scrollTop += offset;
+ }
+
+ }
+ } catch (e) {
+ exception_error("scrollArticle", e);
+ }
+}
+
+function show_labels_in_headlines(transport) {
+ try {
+ var data = JSON.parse(transport.responseText);
+
+ if (data) {
+ data['info-for-headlines'].each(function(elem) {
+ var ctr = $("HLLCTR-" + elem.id);
+
+ if (ctr) ctr.innerHTML = elem.labels;
+ });
+
+ cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
+
+ }
+ } catch (e) {
+ exception_error("show_labels_in_headlines", e);
+ }
+}
+
+/* function toggleHeadlineActions() {
+ try {
+ var e = $("headlineActionsBody");
+ var p = $("headlineActionsDrop");
+
+ if (!Element.visible(e)) {
+ Element.show(e);
+ } else {
+ Element.hide(e);
+ }
+
+ e.scrollTop = 0;
+ e.style.left = (p.offsetLeft + 1) + "px";
+ e.style.top = (p.offsetTop + p.offsetHeight + 2) + "px";
+
+ } catch (e) {
+ exception_error("toggleHeadlineActions", e);
+ }
+} */
+
+/* function publishWithNote(id, def_note) {
+ try {
+ if (!def_note) def_note = '';
+
+ var note = prompt(__("Please enter a note for this article:"), def_note);
+
+ if (note != undefined) {
+ togglePub(id, false, false, note);
+ }
+
+ } catch (e) {
+ exception_error("publishWithNote", e);
+ }
+} */
+
+function emailArticle(id) {
+ try {
+ if (!id) {
+ var ids = getSelectedArticleIds2();
+
+ if (ids.length == 0) {
+ alert(__("No articles are selected."));
+ return;
+ }
+
+ id = ids.toString();
+ }
+
+ if (dijit.byId("emailArticleDlg"))
+ dijit.byId("emailArticleDlg").destroyRecursive();
+
+ var query = "backend.php?op=dlg&id=emailArticle¶m=" + param_escape(id);
+
+ dialog = new dijit.Dialog({
+ id: "emailArticleDlg",
+ title: __("Forward article by email"),
+ style: "width: 600px",
+ execute: function() {
+ if (this.validate()) {
+
+ new Ajax.Request("backend.php", {
+ parameters: dojo.objectToQuery(this.attr('value')),
+ onComplete: function(transport) {
+
+ var reply = JSON.parse(transport.responseText);
+
+ var error = reply['error'];
+
+ if (error) {
+ alert(__('Error sending email:') + ' ' + error);
+ } else {
+ notify_info('Your message has been sent.');
+ dialog.hide();
+ }
+
+ } });
+ }
+ },
+ href: query});
+
+ var tmph = dojo.connect(dialog, 'onLoad', function() {
+ dojo.disconnect(tmph);
+
+ new Ajax.Autocompleter('emailArticleDlg_destination', 'emailArticleDlg_dst_choices',
+ "backend.php?op=rpc&subop=completeEmails",
+ { tokens: '', paramName: "search" });
+ });
+
+ dialog.show();
+
+ /* displayDlg('emailArticle', id,
+ function () {
+ document.forms['article_email_form'].destination.focus();
+
+ new Ajax.Autocompleter('destination', 'destination_choices',
+ "backend.php?op=rpc&subop=completeEmails",
+ { tokens: '', paramName: "search" });
+
+ }); */
+
+ } catch (e) {
+ exception_error("emailArticle", e);
+ }
+}
+
+function dismissArticle(id) {
+ try {
+ var elem = $("RROW-" + id);
+
+ toggleUnread(id, 0, true);
+
+ new Effect.Fade(elem, {duration : 0.5});
+
+ active_post_id = false;
+
+ } catch (e) {
+ exception_error("dismissArticle", e);
+ }
+}
+
+function dismissSelectedArticles() {
+ try {
+
+ var ids = getVisibleArticleIds();
+ var tmp = [];
+ var sel = [];
+
+ for (var i = 0; i < ids.length; i++) {
+ var elem = $("RROW-" + ids[i]);
+
+ if (elem.className && elem.hasClassName("Selected") &&
+ ids[i] != active_post_id) {
+ new Effect.Fade(elem, {duration : 0.5});
+ sel.push(ids[i]);
+ } else {
+ tmp.push(ids[i]);
+ }
+ }
+
+ if (sel.length > 0)
+ selectionToggleUnread(false);
+
+ fixHeadlinesOrder(tmp);
+
+ } catch (e) {
+ exception_error("dismissSelectedArticles", e);
+ }
+}
+
+function dismissReadArticles() {
+ try {
+
+ var ids = getVisibleArticleIds();
+ var tmp = [];
+
+ for (var i = 0; i < ids.length; i++) {
+ var elem = $("RROW-" + ids[i]);
+
+ if (elem.className && !elem.hasClassName("Unread") &&
+ !elem.hasClassName("Selected")) {
+
+ new Effect.Fade(elem, {duration : 0.5});
+ } else {
+ tmp.push(ids[i]);
+ }
+ }
+
+ fixHeadlinesOrder(tmp);
+
+ } catch (e) {
+ exception_error("dismissSelectedArticles", e);
+ }
+}
+
+function getVisibleArticleIds() {
+ var ids = [];
+
+ try {
+
+ getLoadedArticleIds().each(function(id) {
+ var elem = $("RROW-" + id);
+ if (elem && Element.visible(elem))
+ ids.push(id);
+ });
+
+ } catch (e) {
+ exception_error("getVisibleArticleIds", e);
+ }
+
+ return ids;
+}
+
+function cdmClicked(event, id) {
+ try {
+ //var shift_key = event.shiftKey;
+
+ hideAuxDlg();
+
+ if (!event.ctrlKey) {
+
+ if (!getInitParam("cdm_expanded")) {
+ return cdmExpandArticle(id);
+ } else {
+
+ selectArticles("none");
+ toggleSelected(id);
+
+ var elem = $("RROW-" + id);
+
+ if (elem)
+ elem.removeClassName("Unread");
+
+ var upd_img_pic = $("FUPDPIC-" + id);
+
+ if (upd_img_pic && (upd_img_pic.src.match("updated.png") ||
+ upd_img_pic.src.match("fresh_sign.png"))) {
+
+ upd_img_pic.src = "images/blank_icon.gif";
+ }
+
+ active_post_id = id;
+
+ var query = "?op=rpc&subop=catchupSelected" +
+ "&cmode=0&ids=" + param_escape(id);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ handle_rpc_json(transport);
+ } });
+
+ return true;
+ }
+
+ } else {
+ toggleSelected(id, true);
+ toggleUnread(id, 0, false);
+ zoomToArticle(event, id);
+ }
+
+ } catch (e) {
+ exception_error("cdmClicked");
+ }
+
+ return false;
+}
+
+function postClicked(event, id) {
+ try {
+
+ if (!event.ctrlKey) {
+ return true;
+ } else {
+ postOpenInNewTab(event, id);
+ return false;
+ }
+
+ } catch (e) {
+ exception_error("postClicked");
+ }
+}
+
+function hlOpenInNewTab(event, id) {
+ toggleUnread(id, 0, false);
+ zoomToArticle(event, id);
+}
+
+function postOpenInNewTab(event, id) {
+ closeArticlePanel(id);
+ zoomToArticle(event, id);
+}
+
+function hlClicked(event, id) {
+ try {
+ if (event.which == 2) {
+ view(id);
+ return true;
+ } else if (event.altKey) {
+ openArticleInNewWindow(id);
+ } else if (!event.ctrlKey) {
+ view(id);
+ return false;
+ } else {
+ toggleSelected(id);
+ toggleUnread(id, 0, false);
+ zoomToArticle(event, id);
+ return false;
+ }
+
+ } catch (e) {
+ exception_error("hlClicked");
+ }
+}
+
+function getFirstVisibleHeadlineId() {
+ var rows = getVisibleArticleIds();
+ return rows[0];
+
+}
+
+function getLastVisibleHeadlineId() {
+ var rows = getVisibleArticleIds();
+ return rows[rows.length-1];
+}
+
+function openArticleInNewWindow(id) {
+ toggleUnread(id, 0, false);
+ window.open("backend.php?op=la&id=" + id);
+}
+
+function isCdmMode() {
+ return getInitParam("combined_display_mode");
+}
+
+function markHeadline(id) {
+ var row = $("RROW-" + id);
+ if (row) {
+ var check = $("RCHK-" + id);
+
+ if (check) {
+ check.checked = true;
+ }
+
+ row.addClassName("Selected");
+ }
+}
+
+function getRelativePostIds(id, limit) {
+
+ var tmp = [];
+
+ try {
+
+ if (!limit) limit = 6; //3
+
+ var ids = getVisibleArticleIds();
+
+ for (var i = 0; i < ids.length; i++) {
+ if (ids[i] == id) {
+ for (var k = 1; k <= limit; k++) {
+ //if (i > k-1) tmp.push(ids[i-k]);
+ if (i < ids.length-k) tmp.push(ids[i+k]);
+ }
+ break;
+ }
+ }
+
+ } catch (e) {
+ exception_error("getRelativePostIds", e);
+ }
+
+ return tmp;
+}
+
+function correctHeadlinesOffset(id) {
+
+ try {
+
+ var container = $("headlines-frame");
+ var row = $("RROW-" + id);
+
+ var viewport = container.offsetHeight;
+
+ var rel_offset_top = row.offsetTop - container.scrollTop;
+ var rel_offset_bottom = row.offsetTop + row.offsetHeight - container.scrollTop;
+
+ //console.log("Rtop: " + rel_offset_top + " Rbtm: " + rel_offset_bottom);
+ //console.log("Vport: " + viewport);
+
+ if (rel_offset_top <= 0 || rel_offset_top > viewport) {
+ container.scrollTop = row.offsetTop;
+ } else if (rel_offset_bottom > viewport) {
+
+ /* doesn't properly work with Opera in some cases because
+ Opera fucks up element scrolling */
+
+ container.scrollTop = row.offsetTop + row.offsetHeight - viewport;
+ }
+
+ } catch (e) {
+ exception_error("correctHeadlinesOffset", e);
+ }
+
+}
+
+function headlineActionsChange(elem) {
+ try {
+ eval(elem.value);
+ elem.attr('value', 'false');
+ } catch (e) {
+ exception_error("headlineActionsChange", e);
+ }
+}
+
+function closeArticlePanel() {
+
+ var tabs = dijit.byId("content-tabs");
+ var child = tabs.selectedChildWidget;
+
+ if (child && tabs.getIndexOfChild(child) > 0) {
+ tabs.removeChild(child);
+ child.destroy();
+ } else {
+ if (dijit.byId("content-insert"))
+ dijit.byId("headlines-wrap-inner").removeChild(
+ dijit.byId("content-insert"));
+ }
+}
+
+function initHeadlinesMenu() {
+ try {
+ if (dijit.byId("headlinesMenu"))
+ dijit.byId("headlinesMenu").destroyRecursive();
+
+ var ids = [];
+
+ if (!isCdmMode()) {
+ nodes = $$("#headlines-frame > div[id*=RROW]");
+ } else {
+ nodes = $$("#headlines-frame span[id*=RTITLE]");
+ }
+
+ nodes.each(function(node) {
+ ids.push(node.id);
+ });
+
+ var menu = new dijit.Menu({
+ id: "headlinesMenu",
+ targetNodeIds: ids,
+ });
+
+ var tmph = dojo.connect(menu, '_openMyself', function (event) {
+ var callerNode = event.target, match = null, tries = 0;
+
+ while (match == null && callerNode && tries <= 3) {
+ match = callerNode.id.match("^[A-Z]+[-]([0-9]+)$");
+ callerNode = callerNode.parentNode;
+ ++tries;
+ }
+
+ if (match) this.callerRowId = parseInt(match[1]);
+
+ });
+
+/* if (!isCdmMode())
+ menu.addChild(new dijit.MenuItem({
+ label: __("View article"),
+ onClick: function(event) {
+ view(this.getParent().callerRowId);
+ }})); */
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Open original article"),
+ onClick: function(event) {
+ openArticleInNewWindow(this.getParent().callerRowId);
+ }}));
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("View in a tt-rss tab"),
+ onClick: function(event) {
+ hlOpenInNewTab(event, this.getParent().callerRowId);
+ }}));
+
+ menu.addChild(new dijit.MenuSeparator());
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Mark above as read"),
+ onClick: function(event) {
+ catchupRelativeToArticle(0, this.getParent().callerRowId);
+ }}));
+
+ menu.addChild(new dijit.MenuItem({
+ label: __("Mark below as read"),
+ onClick: function(event) {
+ catchupRelativeToArticle(1, this.getParent().callerRowId);
+ }}));
+
+
+ var labels = dijit.byId("feedTree").model.getItemsInCategory(-2);
+
+ if (labels) {
+
+ menu.addChild(new dijit.MenuSeparator());
+
+ var labelAddMenu = new dijit.Menu({ownerMenu: menu});
+ var labelDelMenu = new dijit.Menu({ownerMenu: menu});
+
+ labels.each(function(label) {
+ var id = label.id[0];
+ var bare_id = id.substr(id.indexOf(":")+1);
+ var name = label.name[0];
+
+ bare_id = -11-bare_id;
+
+ labelAddMenu.addChild(new dijit.MenuItem({
+ label: name,
+ labelId: bare_id,
+ onClick: function(event) {
+ selectionAssignLabel(this.labelId,
+ [this.getParent().ownerMenu.callerRowId]);
+ }}));
+
+ labelDelMenu.addChild(new dijit.MenuItem({
+ label: name,
+ labelId: bare_id,
+ onClick: function(event) {
+ selectionRemoveLabel(this.labelId,
+ [this.getParent().ownerMenu.callerRowId]);
+ }}));
+
+ });
+
+ menu.addChild(new dijit.PopupMenuItem({
+ label: __("Assign label"),
+ popup: labelAddMenu,
+ }));
+
+ menu.addChild(new dijit.PopupMenuItem({
+ label: __("Remove label"),
+ popup: labelDelMenu,
+ }));
+
+ }
+
+ menu.startup();
+
+ } catch (e) {
+ exception_error("initHeadlinesMenu", e);
+ }
+}
+
+function tweetArticle(id) {
+ try {
+ var query = "?op=rpc&subop=getTweetInfo&id=" + param_escape(id);
+
+ console.log(query);
+
+ var d = new Date();
+ var ts = d.getTime();
+
+ var w = window.open('backend.php?op=loading', 'ttrss_tweet',
+ "status=0,toolbar=0,location=0,width=500,height=400,scrollbars=1,menubar=0");
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ var ti = JSON.parse(transport.responseText);
+
+ var share_url = "http://twitter.com/share?_=" + ts +
+ "&text=" + param_escape(ti.title) +
+ "&url=" + param_escape(ti.link);
+
+ w.location.href = share_url;
+
+ } });
+
+
+ } catch (e) {
+ exception_error("tweetArticle", e);
+ }
+}
+
+function editArticleNote(id) {
+ try {
+
+ var query = "backend.php?op=dlg&id=editArticleNote¶m=" + param_escape(id);
+
+ if (dijit.byId("editNoteDlg"))
+ dijit.byId("editNoteDlg").destroyRecursive();
+
+ dialog = new dijit.Dialog({
+ id: "editNoteDlg",
+ title: __("Edit article note"),
+ style: "width: 600px",
+ execute: function() {
+ if (this.validate()) {
+ var query = dojo.objectToQuery(this.attr('value'));
+
+ notify_progress("Saving article note...", true);
+
+ new Ajax.Request("backend.php", {
+ parameters: query,
+ onComplete: function(transport) {
+ notify('');
+ dialog.hide();
+
+ var reply = JSON.parse(transport.responseText);
+
+ cache_delete("article:" + id);
+
+ var elem = $("POSTNOTE-" + id);
+
+ if (elem) {
+ Element.hide(elem);
+ elem.innerHTML = reply.note;
+
+ if (reply.raw_length != 0)
+ new Effect.Appear(elem);
+ }
+
+ }});
+ }
+ },
+ href: query,
+ });
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("editArticleNote", e);
+ }
+}
+
+function player(elem) {
+ var aid = elem.getAttribute("audio-id");
+ var status = elem.getAttribute("status");
+
+ var audio = $(aid);
+
+ if (audio) {
+ if (status == 0) {
+ audio.play();
+ status = 1;
+ elem.innerHTML = __("Playing...");
+ elem.title = __("Click to pause");
+ elem.addClassName("playing");
+ } else {
+ audio.pause();
+ status = 0;
+ elem.innerHTML = __("Play");
+ elem.title = __("Click to play");
+ elem.removeClassName("playing");
+ }
+
+ elem.setAttribute("status", status);
+ } else {
+ alert("Your browser doesn't seem to support HTML5 audio.");
+ }
+}
+
+function cache_set(id, obj) {
+ //console.log("cache_set: " + id);
+ if (has_storage)
+ try {
+ sessionStorage[id] = obj;
+ } catch (e) {
+ sessionStorage.clear();
+ }
+}
+
+function cache_get(id) {
+ if (has_storage)
+ return sessionStorage[id];
+}
+
+function cache_clear() {
+ if (has_storage)
+ sessionStorage.clear();
+}
+
+function cache_delete(id) {
+ if (has_storage)
+ sessionStorage.removeItem(id);
+}
+
+function cache_headlines(feed, is_cat, toolbar_obj, content_obj) {
+ if (toolbar_obj && content_obj) {
+ cache_set("feed:" + feed + ":" + is_cat,
+ JSON.stringify({toolbar: toolbar_obj, content: content_obj}));
+ } else {
+ try {
+ obj = cache_get("feed:" + feed + ":" + is_cat);
+
+ if (obj) {
+ obj = JSON.parse(obj);
+
+ if (toolbar_obj) obj.toolbar = toolbar_obj;
+ if (content_obj) obj.content = content_obj;
+
+ cache_set("feed:" + feed + ":" + is_cat, JSON.stringify(obj));
+ }
+
+ } catch (e) {
+ console.warn("cache_headlines failed: " + e);
+ }
+ }
+}
+
+function render_local_headlines(feed, is_cat, obj) {
+ try {
+
+ dijit.byId("headlines-toolbar").attr('content',
+ obj.toolbar);
+
+ dijit.byId("headlines-frame").attr('content',
+ obj.content);
+
+ dojo.parser.parse('headlines-toolbar');
+
+ $("headlines-frame").scrollTop = 0;
+ selectArticles('none');
+ setActiveFeedId(feed, is_cat);
+ initHeadlinesMenu();
+
+ precache_headlines();
+
+ } catch (e) {
+ exception_error("render_local_headlines", e);
+ }
+}
+
+function precache_headlines_idle() {
+ try {
+ if (!feed_precache_timeout_id) {
+ var feeds = dijit.byId("feedTree").getVisibleUnreadFeeds();
+ var uncached = [];
+
+ feeds.each(function(item) {
+ if (parseInt(item[0]) > 0 && !cache_get("feed:" + item[0] + ":" + item[1]))
+ uncached.push(item);
+ });
+
+ if (uncached.length > 0) {
+ var rf = uncached[Math.floor(Math.random()*uncached.length)];
+ viewfeed(rf[0], '', rf[1], 0, true);
+ }
+ }
+ precache_idle_timeout_id = setTimeout("precache_headlines_idle()", 1000*30);
+
+ } catch (e) {
+ exception_error("precache_headlines_idle", e);
+ }
+}
+
+function precache_headlines() {
+ try {
+
+ if (!feed_precache_timeout_id) {
+ feed_precache_timeout_id = window.setTimeout(function() {
+ var nuf = getNextUnreadFeed(getActiveFeedId(), activeFeedIsCat());
+ var nf = dijit.byId("feedTree").getNextFeed(getActiveFeedId(), activeFeedIsCat());
+
+ if (nuf && !cache_get("feed:" + nuf + ":" + activeFeedIsCat()))
+ viewfeed(nuf, '', activeFeedIsCat(), 0, true);
+
+ if (nf != nuf && nf && !cache_get("feed:" + nf[0] + ":" + nf[1]))
+ viewfeed(nf[0], '', nf[1], 0, true);
+
+ window.setTimeout(function() {
+ feed_precache_timeout_id = false;
+ }, 3000);
+ }, 1000);
+ }
+
+ } catch (e) {
+ exception_error("precache_headlines", e);
+ }
+}
+
+function shareArticle(id) {
+ try {
+ if (dijit.byId("shareArticleDlg"))
+ dijit.byId("shareArticleDlg").destroyRecursive();
+
+ var query = "backend.php?op=dlg&id=shareArticle¶m=" + param_escape(id);
+
+ dialog = new dijit.Dialog({
+ id: "shareArticleDlg",
+ title: __("Share article by URL"),
+ style: "width: 600px",
+ href: query});
+
+ dialog.show();
+
+ } catch (e) {
+ exception_error("emailArticle", e);
+ }
+}
+
+
<?php
+ set_include_path(get_include_path() . PATH_SEPARATOR . "include");
+
define('DISABLE_SESSIONS', true);
require "functions.php";
+++ /dev/null
-<?php # This file has been generated at: Wed Nov 23 10:40:20 MSK 2011
-
-__("Title");
-__("Title or Content");
-__("Link");
-__("Content");
-__("Article Date");
-
-__("Delete article");
-__("Mark as read");
-__("Set starred");
-__("Publish article");
-__("Assign tags");
-__("Assign label");
-
-__('This option is useful when you are reading several planet-type aggregators with partially colliding userbase. When disabled, it forces same posts from different feeds to appear only once.');
-__('Display expanded list of feed articles, instead of separate displays for headlines and article content');
-__('When "Mark as read" button is clicked in toolbar, automatically open next feed with unread articles.');
-__('This option enables sending daily digest of new (and unread) headlines on your configured e-mail address');
-__('This option enables marking articles as read automatically while you scroll article list.');
-__('Strip all but most common HTML tags when reading articles.');
-__('When auto-detecting tags in articles these tags will not be applied (comma-separated list).');
-__('When this option is enabled, headlines in Special feeds and Labels are grouped by feeds');
-__('Use feed-specified date to sort headlines instead of local import date.');
-__('Customize CSS stylesheet to your liking');
-__('Click to register your SSL client certificate with tt-rss');
-__('Purge old posts after this number of days (0 - disables)');
-__('Default interval between feed updates');
-__('Amount of articles to display at once');
-__('Allow duplicate posts');
-__('Enable feed categories');
-__('Show content preview in headlines list');
-__('Short date format');
-__('Long date format');
-__('Combined feed display');
-__('Hide feeds with no unread messages');
-__('On catchup show next feed');
-__('Sort feeds by unread articles count');
-__('Reverse headline order (oldest first)');
-__('Enable e-mail digest');
-__('Confirm marking feed as read');
-__('Automatically mark articles as read');
-__('Strip unsafe tags from articles');
-__('Blacklisted tags');
-__('Maximum age of fresh articles (in hours)');
-__('Mark articles in e-mail digest as read');
-__('Automatically expand articles in combined mode');
-__('Purge unread articles');
-__('Show special feeds when hiding read feeds');
-__('Group headlines in virtual feeds');
-__('Do not show images in articles');
-__('Enable external API');
-__('User timezone');
-__('Sort headlines by feed date');
-__('Customize stylesheet');
-__('Login with an SSL certificate');
-?>
+++ /dev/null
-<html>
-<head>
- <title>Tiny Tiny RSS : Login</title>
- <link rel="stylesheet" type="text/css" href="lib/dijit/themes/claro/claro.css"/>
- <link rel="stylesheet" type="text/css" href="tt-rss.css">
- <link rel="shortcut icon" type="image/png" href="images/favicon.png">
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <script type="text/javascript" src="lib/dojo/dojo.js" djConfig="parseOnLoad: true"></script>
- <script type="text/javascript" src="lib/prototype.js"></script>
- <script type="text/javascript" src="lib/scriptaculous/scriptaculous.js?load=effects,dragdrop,controls"></script>
- <script type="text/javascript" src="functions.js"></script>
- <script type="text/javascript" charset="utf-8" src="errors.php?mode=js"></script>
-</head>
-
-<body id="ttrssLogin" class="claro">
-
-<script type="text/javascript">
-function init() {
-
- dojo.require("dijit.Dialog");
-
- var test = setCookie("ttrss_test", "TEST");
-
- if (getCookie("ttrss_test") != "TEST") {
- return fatalError(2);
- }
-
- var limit_set = getCookie("ttrss_bwlimit");
-
- if (limit_set == "true") {
- document.forms["loginForm"].bw_limit.checked = true;
- }
-
- document.forms["loginForm"].login.focus();
-}
-
-function fetchProfiles() {
- try {
- var params = Form.serialize('loginForm');
- var query = "?op=getProfiles&" + params;
-
- if (query) {
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- if (transport.responseText.match("select")) {
- $('profile_box').innerHTML = transport.responseText;
- }
- } });
- }
-
- } catch (e) {
- exception_error("fetchProfiles", e);
- }
-}
-
-
-function languageChange(elem) {
- try {
- document.forms['loginForm']['click'].disabled = true;
-
- var lang = elem[elem.selectedIndex].value;
- setCookie("ttrss_lang", lang, <?php print SESSION_COOKIE_LIFETIME ?>);
- window.location.reload();
- } catch (e) {
- exception_error("languageChange", e);
- }
-}
-
-function gotoRegForm() {
- window.location.href = "register.php";
- return false;
-}
-
-function bwLimitChange(elem) {
- try {
- var limit_set = elem.checked;
-
- setCookie("ttrss_bwlimit", limit_set,
- <?php print SESSION_COOKIE_LIFETIME ?>);
-
- } catch (e) {
- exception_error("bwLimitChange", e);
- }
-}
-
-function validateLoginForm(f) {
- try {
-
- if (f.login.value.length == 0) {
- new Effect.Highlight(f.login);
- return false;
- }
-
- if (f.password.value.length == 0) {
- new Effect.Highlight(f.password);
- return false;
- }
-
- document.forms['loginForm']['click'].disabled = true;
-
- return true;
- } catch (e) {
- exception_error("validateLoginForm", e);
- return true;
- }
-}
-</script>
-
-<script type="text/javascript">
- Event.observe(window, 'load', function() {
- init();
- });
-</script>
-
-<form action="" method="POST" id="loginForm" name="loginForm" onsubmit="return validateLoginForm(this)">
-<input type="hidden" name="login_action" value="do_login">
-
-<table class="loginForm2">
-<tr>
- <td class="loginTop" valign="bottom" align="left">
- <img src="images/logo_wide.png">
- </td>
-</tr><tr>
- <td align="center" valign="middle" class="loginMiddle" height="100%">
- <?php if ($_SESSION['login_error_msg']) { ?>
- <div class="loginError"><?php echo $_SESSION['login_error_msg'] ?></div>
- <?php $_SESSION['login_error_msg'] = ""; ?>
- <?php } ?>
- <table>
- <tr><td align="right"><?php echo __("Login:") ?></td>
- <td align="right"><input name="login"
- onchange="fetchProfiles()" onfocus="fetchProfiles()"
- value="<?php echo get_remote_user($link) ?>"></td></tr>
- <tr><td align="right"><?php echo __("Password:") ?></td>
- <td align="right"><input type="password" name="password"
- onchange="fetchProfiles()" onfocus="fetchProfiles()"
- value="<?php echo get_remote_fakepass($link) ?>"></td></tr>
- <tr><td align="right"><?php echo __("Language:") ?></td>
- <td align="right">
- <?php
- print_select_hash("language", $_COOKIE["ttrss_lang"], get_translations(),
- "style='width : 100%' onchange='languageChange(this)'");
-
- ?>
- </td></tr>
-
- <tr><td align="right"><?php echo __("Profile:") ?></td>
- <td align="right" id="profile_box">
- <select style='width : 100%' disabled='disabled'>
- <option><?php echo __("Default profile") ?></option></select>
- </td></tr>
-
- <!-- <tr><td colspan="2">
- <input type="checkbox" name="remember_me" id="remember_me">
- <label for="remember_me">Remember me on this computer</label>
- </td></tr> -->
-
- <tr><td colspan="2" align="right" class="innerLoginCell">
-
- <button type="submit" name='click'><?php echo __('Log in') ?></button>
- <?php if (defined('ENABLE_REGISTRATION') && ENABLE_REGISTRATION) { ?>
- <button onclick="return gotoRegForm()">
- <?php echo __("Create new account") ?></button>
- <?php } ?>
-
- <input type="hidden" name="action" value="login">
- <input type="hidden" name="rt"
- value="<?php if ($return_to != 'none') { echo $return_to; } ?>">
- </td></tr>
-
- <tr><td colspan="2" align="right" class="innerLoginCell">
-
- <div class="small">
- <input name="bw_limit" id="bw_limit" type="checkbox"
- onchange="bwLimitChange(this)">
- <label for="bw_limit">
- <?php echo __("Use less traffic") ?></label></div>
-
- </td></tr>
-
-
- </table>
- </td>
-</tr><tr>
- <td align="center" class="loginBottom">
- <a href="http://tt-rss.org/">Tiny Tiny RSS</a>
- <?php if (!defined('HIDE_VERSION')) { ?>
- v<?php echo VERSION ?>
- <?php } ?>
- © 2005–<?php echo date('Y') ?> <a href="http://fakecake.org/">Andrew Dolgov</a>
- </td>
-</tr>
-
-</table>
-
-</form>
-
-</body></html>
+++ /dev/null
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-11-23 10:40+0400\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"Language: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: backend.php:83
-msgid "Use default"
-msgstr ""
-
-#: backend.php:84
-msgid "Never purge"
-msgstr ""
-
-#: backend.php:85
-msgid "1 week old"
-msgstr ""
-
-#: backend.php:86
-msgid "2 weeks old"
-msgstr ""
-
-#: backend.php:87
-msgid "1 month old"
-msgstr ""
-
-#: backend.php:88
-msgid "2 months old"
-msgstr ""
-
-#: backend.php:89
-msgid "3 months old"
-msgstr ""
-
-#: backend.php:92
-msgid "Default interval"
-msgstr ""
-
-#: backend.php:93 backend.php:103
-msgid "Disable updates"
-msgstr ""
-
-#: backend.php:94 backend.php:104
-msgid "Each 15 minutes"
-msgstr ""
-
-#: backend.php:95 backend.php:105
-msgid "Each 30 minutes"
-msgstr ""
-
-#: backend.php:96 backend.php:106
-msgid "Hourly"
-msgstr ""
-
-#: backend.php:97 backend.php:107
-msgid "Each 4 hours"
-msgstr ""
-
-#: backend.php:98 backend.php:108
-msgid "Each 12 hours"
-msgstr ""
-
-#: backend.php:99 backend.php:109
-msgid "Daily"
-msgstr ""
-
-#: backend.php:100 backend.php:110
-msgid "Weekly"
-msgstr ""
-
-#: backend.php:113 tt-rss.php:140 modules/pref-prefs.php:350
-msgid "Default"
-msgstr ""
-
-#: backend.php:114
-msgid "Magpie"
-msgstr ""
-
-#: backend.php:115
-msgid "SimplePie"
-msgstr ""
-
-#: backend.php:116
-msgid "Twitter OAuth"
-msgstr ""
-
-#: backend.php:125 modules/pref-users.php:131
-msgid "User"
-msgstr ""
-
-#: backend.php:126
-msgid "Power User"
-msgstr ""
-
-#: backend.php:127
-msgid "Administrator"
-msgstr ""
-
-#: backend.php:179 prefs.php:93 modules/pref-feeds.php:45
-#: modules/pref-feeds.php:1278 modules/pref-feeds.php:1348
-msgid "Feeds"
-msgstr ""
-
-#: backend.php:207
-msgid "Article not found."
-msgstr ""
-
-#: backend.php:297 functions.php:5090
-msgid "Feed not found."
-msgstr ""
-
-#: backend.php:457 digest.php:61 prefs.php:66 tt-rss.php:62 tt-rss.php:106
-#: tt-rss.php:191 modules/pref-feeds.php:1401 modules/pref-filters.php:550
-#: modules/pref-labels.php:293 viewfeed.js:1108 viewfeed.js:1278
-msgid "Loading, please wait..."
-msgstr ""
-
-#: db-updater.php:16
-msgid "Your access level is insufficient to run this script."
-msgstr ""
-
-#: db-updater.php:41
-msgid "Database Updater"
-msgstr ""
-
-#: db-updater.php:82
-msgid "Could not update database"
-msgstr ""
-
-#: db-updater.php:85
-msgid "Could not find necessary schema file, need version:"
-msgstr ""
-
-#: db-updater.php:86
-msgid ", found: "
-msgstr ""
-
-#: db-updater.php:89
-msgid "Tiny Tiny RSS database is up to date."
-msgstr ""
-
-#: db-updater.php:91 db-updater.php:158 db-updater.php:171 register.php:189
-#: register.php:234 register.php:247 register.php:262 register.php:280
-#: register.php:365 register.php:375 register.php:387 twitter.php:108
-#: twitter.php:120 modules/pref-feeds.php:1096
-msgid "Return to Tiny Tiny RSS"
-msgstr ""
-
-#: db-updater.php:97
-msgid "Please backup your database before proceeding."
-msgstr ""
-
-#: db-updater.php:99
-#, php-format
-msgid ""
-"Your Tiny Tiny RSS database needs update to the latest version (<b>%d</b> to "
-"<b>%d</b>)."
-msgstr ""
-
-#: db-updater.php:113
-msgid "Perform updates"
-msgstr ""
-
-#: db-updater.php:118
-msgid "Performing updates..."
-msgstr ""
-
-#: db-updater.php:124
-#, php-format
-msgid "Updating to version %d..."
-msgstr ""
-
-#: db-updater.php:137
-msgid "Checking version... "
-msgstr ""
-
-#: db-updater.php:143
-msgid "OK!"
-msgstr ""
-
-#: db-updater.php:145
-msgid "ERROR!"
-msgstr ""
-
-#: db-updater.php:153
-#, php-format
-msgid ""
-"Finished. Performed <b>%d</b> update(s) up to schema\n"
-"\t\t\tversion <b>%d</b>."
-msgstr ""
-
-#: db-updater.php:163
-msgid "Your database schema is from a newer version of Tiny Tiny RSS."
-msgstr ""
-
-#: db-updater.php:165
-#, php-format
-msgid "Found schema version: <b>%d</b>, required: <b>%d</b>."
-msgstr ""
-
-#: db-updater.php:167
-msgid ""
-"Schema upgrade impossible. Please update Tiny Tiny RSS files to the newer "
-"version and continue."
-msgstr ""
-
-#: digest.php:55
-msgid ""
-"Your browser doesn't support Javascript, which is required\n"
-"\t\t\tfor this application to function properly. Please check your\n"
-"\t\t\tbrowser settings."
-msgstr ""
-
-#: digest.php:69 tt-rss.php:72
-msgid "Hello,"
-msgstr ""
-
-#: digest.php:72 tt-rss.php:82 mobile/functions.php:59
-#: mobile/functions.php:234
-msgid "Logout"
-msgstr ""
-
-#: errors.php:6
-msgid ""
-"This program requires XmlHttpRequest to function properly. Your browser "
-"doesn't seem to support it."
-msgstr ""
-
-#: errors.php:9
-msgid ""
-"This program requires cookies to function properly. Your browser doesn't "
-"seem to support them."
-msgstr ""
-
-#: errors.php:12
-msgid "Backend sanity check failed"
-msgstr ""
-
-#: errors.php:14
-msgid "Frontend sanity check failed."
-msgstr ""
-
-#: errors.php:16
-msgid ""
-"Incorrect database schema version. <a href='db-updater.php'>Please "
-"update</a>."
-msgstr ""
-
-#: errors.php:18
-msgid "Request not authorized."
-msgstr ""
-
-#: errors.php:20
-msgid "No operation to perform."
-msgstr ""
-
-#: errors.php:22
-msgid ""
-"Could not display feed: query failed. Please check label match syntax or "
-"local configuration."
-msgstr ""
-
-#: errors.php:24
-msgid "Denied. Your access level is insufficient to access this page."
-msgstr ""
-
-#: errors.php:26
-msgid "Configuration check failed"
-msgstr ""
-
-#: errors.php:28
-msgid ""
-"Your version of MySQL is not currently supported. Please see\n"
-"\t\tofficial site for more information."
-msgstr ""
-
-#: errors.php:33
-msgid "SQL escaping test failed, check your database and PHP configuration"
-msgstr ""
-
-#: functions.php:2073
-msgid "Session failed to validate (incorrect IP)"
-msgstr ""
-
-#: functions.php:2147
-msgid "Incorrect username or password"
-msgstr ""
-
-#: functions.php:3138 modules/popup-dialog.php:394
-msgid "All feeds"
-msgstr ""
-
-#: functions.php:3170 functions.php:3213 functions.php:4568 functions.php:4577
-#: modules/pref-feeds.php:96
-msgid "Uncategorized"
-msgstr ""
-
-#: functions.php:3203 functions.php:3907 mobile/functions.php:168
-msgid "Special"
-msgstr ""
-
-#: functions.php:3205 functions.php:3909 prefs.php:99
-#: modules/pref-labels.php:89 help/4.php:12 mobile/functions.php:195
-msgid "Labels"
-msgstr ""
-
-#: functions.php:3251 help/3.php:71
-msgid "Starred articles"
-msgstr ""
-
-#: functions.php:3253 help/3.php:72
-msgid "Published articles"
-msgstr ""
-
-#: functions.php:3255 help/3.php:70
-msgid "Fresh articles"
-msgstr ""
-
-#: functions.php:3257 help/3.php:69
-msgid "All articles"
-msgstr ""
-
-#: functions.php:3259
-msgid "Archived articles"
-msgstr ""
-
-#: functions.php:4339
-msgid "Select:"
-msgstr ""
-
-#: functions.php:4340 modules/pref-feeds.php:1342 modules/pref-filters.php:525
-#: modules/pref-instances.php:137 modules/pref-labels.php:272
-#: modules/pref-users.php:380
-msgid "All"
-msgstr ""
-
-#: functions.php:4341 functions.php:4353 tt-rss.php:132
-msgid "Unread"
-msgstr ""
-
-#: functions.php:4342
-msgid "Invert"
-msgstr ""
-
-#: functions.php:4343 modules/pref-feeds.php:1344 modules/pref-filters.php:527
-#: modules/pref-instances.php:139 modules/pref-labels.php:274
-#: modules/pref-users.php:382
-msgid "None"
-msgstr ""
-
-#: functions.php:4349 tt-rss.php:158
-msgid "Actions..."
-msgstr ""
-
-#: functions.php:4351
-msgid "Selection toggle:"
-msgstr ""
-
-#: functions.php:4354 tt-rss.php:130
-msgid "Starred"
-msgstr ""
-
-#: functions.php:4355 tt-rss.php:131
-msgid "Published"
-msgstr ""
-
-#: functions.php:4357
-msgid "Selection:"
-msgstr ""
-
-#: functions.php:4359 functions.php:4385 localized_schema.php:10
-#: tt-rss.php:152 tt-rss.php:167 digest.js:624 FeedTree.js:125 FeedTree.js:151
-msgid "Mark as read"
-msgstr ""
-
-#: functions.php:4362
-msgid "Archive"
-msgstr ""
-
-#: functions.php:4364
-msgid "Move back"
-msgstr ""
-
-#: functions.php:4365
-msgid "Delete"
-msgstr ""
-
-#: functions.php:4369 functions.php:4946 functions.php:5590
-msgid "Forward by email"
-msgstr ""
-
-#: functions.php:4383 PrefFilterTree.js:29
-msgid "Feed:"
-msgstr ""
-
-#: functions.php:4387 modules/popup-dialog.php:881
-msgid "View as RSS"
-msgstr ""
-
-#: functions.php:4397 functions.php:5009
-msgid "Visit the website"
-msgstr ""
-
-#: functions.php:4430
-msgid "View as RSS feed"
-msgstr ""
-
-#: functions.php:4757 viewfeed.js:2085
-msgid "Click to play"
-msgstr ""
-
-#: functions.php:4758 viewfeed.js:2084
-msgid "Play"
-msgstr ""
-
-#: functions.php:4884
-msgid " - "
-msgstr ""
-
-#: functions.php:4913 functions.php:6537 modules/backend-rpc.php:381
-msgid "no tags"
-msgstr ""
-
-#: functions.php:4923 functions.php:5550
-msgid "Edit tags for this article"
-msgstr ""
-
-#: functions.php:4933 functions.php:5577
-msgid "Open article in new tab"
-msgstr ""
-
-#: functions.php:4940 functions.php:5584 viewfeed.js:2027
-msgid "Edit article note"
-msgstr ""
-
-#: functions.php:4953 functions.php:5597
-msgid "Share on Twitter"
-msgstr ""
-
-#: functions.php:4959
-msgid "Share by URL"
-msgstr ""
-
-#: functions.php:4964 digest.js:267
-msgid "Close this panel"
-msgstr ""
-
-#: functions.php:4981 functions.php:5490
-msgid "Originally from:"
-msgstr ""
-
-#: functions.php:4994 functions.php:5503 modules/popup-dialog.php:251
-#: modules/pref-feeds.php:319
-msgid "Feed URL"
-msgstr ""
-
-#: functions.php:5033 modules/help.php:21 modules/popup-dialog.php:53
-#: modules/popup-dialog.php:172 modules/popup-dialog.php:196
-#: modules/popup-dialog.php:234 modules/popup-dialog.php:617
-#: modules/popup-dialog.php:679 modules/popup-dialog.php:736
-#: modules/popup-dialog.php:768 modules/popup-dialog.php:904
-#: modules/popup-dialog.php:934 modules/popup-dialog.php:1021
-#: modules/popup-dialog.php:1112 modules/pref-feeds.php:1269
-#: modules/pref-filters.php:405 modules/pref-filters.php:482
-#: modules/pref-users.php:99
-msgid "Close this window"
-msgstr ""
-
-#: functions.php:5311 functions.php:5393
-msgid "mark as read"
-msgstr ""
-
-#: functions.php:5603
-msgid "Dismiss article"
-msgstr ""
-
-#: functions.php:5624
-msgid "No unread articles found to display."
-msgstr ""
-
-#: functions.php:5627
-msgid "No updated articles found to display."
-msgstr ""
-
-#: functions.php:5630
-msgid "No starred articles found to display."
-msgstr ""
-
-#: functions.php:5634
-msgid ""
-"No articles found to display. You can assign articles to labels manually "
-"(see the Actions menu above) or use a filter."
-msgstr ""
-
-#: functions.php:5636
-msgid "No articles found to display."
-msgstr ""
-
-#: functions.php:5651 functions.php:6985
-#, php-format
-msgid "Feeds last updated at %s"
-msgstr ""
-
-#: functions.php:5661 functions.php:6995
-msgid "Some feeds have update errors (click for details)"
-msgstr ""
-
-#: functions.php:6477 tt-rss.php:173
-msgid "Create label..."
-msgstr ""
-
-#: functions.php:6491
-msgid "Remove:"
-msgstr ""
-
-#: functions.php:6495
-msgid "Assign:"
-msgstr ""
-
-#: functions.php:6562
-msgid "(edit note)"
-msgstr ""
-
-#: functions.php:6975
-msgid "No feed selected."
-msgstr ""
-
-#: functions.php:7159
-msgid "unknown type"
-msgstr ""
-
-#: functions.php:7199
-msgid "Attachment:"
-msgstr ""
-
-#: functions.php:7201
-msgid "Attachments:"
-msgstr ""
-
-#: functions.php:7632 login_form.php:151 modules/backend-rpc.php:66
-#: modules/popup-dialog.php:109
-msgid "Default profile"
-msgstr ""
-
-#: localized_schema.php:3 tt-rss.php:142 modules/popup-dialog.php:378
-msgid "Title"
-msgstr ""
-
-#: localized_schema.php:4
-msgid "Title or Content"
-msgstr ""
-
-#: localized_schema.php:5
-msgid "Link"
-msgstr ""
-
-#: localized_schema.php:6 modules/popup-dialog.php:379
-msgid "Content"
-msgstr ""
-
-#: localized_schema.php:7
-msgid "Article Date"
-msgstr ""
-
-#: localized_schema.php:9
-msgid "Delete article"
-msgstr ""
-
-#: localized_schema.php:11
-msgid "Set starred"
-msgstr ""
-
-#: localized_schema.php:12 digest.js:262 digest.js:728 viewfeed.js:470
-msgid "Publish article"
-msgstr ""
-
-#: localized_schema.php:13
-msgid "Assign tags"
-msgstr ""
-
-#: localized_schema.php:14 viewfeed.js:1968
-msgid "Assign label"
-msgstr ""
-
-#: localized_schema.php:16
-msgid ""
-"This option is useful when you are reading several planet-type aggregators "
-"with partially colliding userbase. When disabled, it forces same posts from "
-"different feeds to appear only once."
-msgstr ""
-
-#: localized_schema.php:17
-msgid ""
-"Display expanded list of feed articles, instead of separate displays for "
-"headlines and article content"
-msgstr ""
-
-#: localized_schema.php:18
-msgid ""
-"When \"Mark as read\" button is clicked in toolbar, automatically open next "
-"feed with unread articles."
-msgstr ""
-
-#: localized_schema.php:19
-msgid ""
-"This option enables sending daily digest of new (and unread) headlines on "
-"your configured e-mail address"
-msgstr ""
-
-#: localized_schema.php:20
-msgid ""
-"This option enables marking articles as read automatically while you scroll "
-"article list."
-msgstr ""
-
-#: localized_schema.php:21
-msgid "Strip all but most common HTML tags when reading articles."
-msgstr ""
-
-#: localized_schema.php:22
-msgid ""
-"When auto-detecting tags in articles these tags will not be applied (comma-"
-"separated list)."
-msgstr ""
-
-#: localized_schema.php:23
-msgid ""
-"When this option is enabled, headlines in Special feeds and Labels are "
-"grouped by feeds"
-msgstr ""
-
-#: localized_schema.php:24
-msgid "Use feed-specified date to sort headlines instead of local import date."
-msgstr ""
-
-#: localized_schema.php:25
-msgid "Customize CSS stylesheet to your liking"
-msgstr ""
-
-#: localized_schema.php:26
-msgid "Click to register your SSL client certificate with tt-rss"
-msgstr ""
-
-#: localized_schema.php:27
-msgid "Purge old posts after this number of days (0 - disables)"
-msgstr ""
-
-#: localized_schema.php:28
-msgid "Default interval between feed updates"
-msgstr ""
-
-#: localized_schema.php:29
-msgid "Amount of articles to display at once"
-msgstr ""
-
-#: localized_schema.php:30
-msgid "Allow duplicate posts"
-msgstr ""
-
-#: localized_schema.php:31
-msgid "Enable feed categories"
-msgstr ""
-
-#: localized_schema.php:32
-msgid "Show content preview in headlines list"
-msgstr ""
-
-#: localized_schema.php:33
-msgid "Short date format"
-msgstr ""
-
-#: localized_schema.php:34
-msgid "Long date format"
-msgstr ""
-
-#: localized_schema.php:35
-msgid "Combined feed display"
-msgstr ""
-
-#: localized_schema.php:36
-msgid "Hide feeds with no unread messages"
-msgstr ""
-
-#: localized_schema.php:37
-msgid "On catchup show next feed"
-msgstr ""
-
-#: localized_schema.php:38
-msgid "Sort feeds by unread articles count"
-msgstr ""
-
-#: localized_schema.php:39
-msgid "Reverse headline order (oldest first)"
-msgstr ""
-
-#: localized_schema.php:40
-msgid "Enable e-mail digest"
-msgstr ""
-
-#: localized_schema.php:41
-msgid "Confirm marking feed as read"
-msgstr ""
-
-#: localized_schema.php:42
-msgid "Automatically mark articles as read"
-msgstr ""
-
-#: localized_schema.php:43
-msgid "Strip unsafe tags from articles"
-msgstr ""
-
-#: localized_schema.php:44
-msgid "Blacklisted tags"
-msgstr ""
-
-#: localized_schema.php:45
-msgid "Maximum age of fresh articles (in hours)"
-msgstr ""
-
-#: localized_schema.php:46
-msgid "Mark articles in e-mail digest as read"
-msgstr ""
-
-#: localized_schema.php:47
-msgid "Automatically expand articles in combined mode"
-msgstr ""
-
-#: localized_schema.php:48
-msgid "Purge unread articles"
-msgstr ""
-
-#: localized_schema.php:49
-msgid "Show special feeds when hiding read feeds"
-msgstr ""
-
-#: localized_schema.php:50
-msgid "Group headlines in virtual feeds"
-msgstr ""
-
-#: localized_schema.php:51
-msgid "Do not show images in articles"
-msgstr ""
-
-#: localized_schema.php:52
-msgid "Enable external API"
-msgstr ""
-
-#: localized_schema.php:53
-msgid "User timezone"
-msgstr ""
-
-#: localized_schema.php:54
-msgid "Sort headlines by feed date"
-msgstr ""
-
-#: localized_schema.php:55 prefs.js:1784
-msgid "Customize stylesheet"
-msgstr ""
-
-#: localized_schema.php:56
-msgid "Login with an SSL certificate"
-msgstr ""
-
-#: login_form.php:131 mobile/login_form.php:38
-msgid "Login:"
-msgstr ""
-
-#: login_form.php:135 mobile/login_form.php:43
-msgid "Password:"
-msgstr ""
-
-#: login_form.php:139
-msgid "Language:"
-msgstr ""
-
-#: login_form.php:148
-msgid "Profile:"
-msgstr ""
-
-#: login_form.php:161 mobile/login_form.php:28
-msgid "Log in"
-msgstr ""
-
-#: login_form.php:164 register.php:181
-msgid "Create new account"
-msgstr ""
-
-#: login_form.php:178
-msgid "Use less traffic"
-msgstr ""
-
-#: opml.php:163 opml.php:168
-msgid "OPML Utility"
-msgstr ""
-
-#: opml.php:186
-msgid "Importing OPML..."
-msgstr ""
-
-#: opml.php:191
-msgid "Return to preferences"
-msgstr ""
-
-#: prefs.php:81
-msgid "Keyboard shortcuts"
-msgstr ""
-
-#: prefs.php:82 help/4.php:14
-msgid "Exit preferences"
-msgstr ""
-
-#: prefs.php:90 tt-rss.php:74 modules/pref-prefs.php:265 help/3.php:74
-#: help/4.php:8
-msgid "Preferences"
-msgstr ""
-
-#: prefs.php:96 modules/pref-filters.php:90 help/4.php:11
-msgid "Filters"
-msgstr ""
-
-#: prefs.php:103 help/4.php:13
-msgid "Users"
-msgstr ""
-
-#: prefs.php:108
-msgid "Linked"
-msgstr ""
-
-#: register.php:185
-msgid "New user registrations are administratively disabled."
-msgstr ""
-
-#: register.php:210
-msgid ""
-"Your temporary password will be sent to the specified email. Accounts, which "
-"were not logged in once, are erased automatically 24 hours after temporary "
-"password is sent."
-msgstr ""
-
-#: register.php:216
-msgid "Desired login:"
-msgstr ""
-
-#: register.php:219
-msgid "Check availability"
-msgstr ""
-
-#: register.php:221
-msgid "Email:"
-msgstr ""
-
-#: register.php:224
-msgid "How much is two plus two:"
-msgstr ""
-
-#: register.php:227
-msgid "Submit registration"
-msgstr ""
-
-#: register.php:245
-msgid "Your registration information is incomplete."
-msgstr ""
-
-#: register.php:260
-msgid "Sorry, this username is already taken."
-msgstr ""
-
-#: register.php:278
-msgid "Registration failed."
-msgstr ""
-
-#: register.php:362
-msgid "Account created successfully."
-msgstr ""
-
-#: register.php:384
-msgid "New user registrations are currently closed."
-msgstr ""
-
-#: tt-rss.php:78
-msgid "Comments?"
-msgstr ""
-
-#: tt-rss.php:88
-msgid "New version of Tiny Tiny RSS is available!"
-msgstr ""
-
-#: tt-rss.php:113
-msgid "News"
-msgstr ""
-
-#: tt-rss.php:122
-msgid "Collapse feedlist"
-msgstr ""
-
-#: tt-rss.php:125
-msgid "Show articles"
-msgstr ""
-
-#: tt-rss.php:128
-msgid "Adaptive"
-msgstr ""
-
-#: tt-rss.php:129
-msgid "All Articles"
-msgstr ""
-
-#: tt-rss.php:133
-msgid "Ignore Scoring"
-msgstr ""
-
-#: tt-rss.php:134
-msgid "Updated"
-msgstr ""
-
-#: tt-rss.php:137
-msgid "Sort articles"
-msgstr ""
-
-#: tt-rss.php:141 modules/pref-filters.php:228
-msgid "Date"
-msgstr ""
-
-#: tt-rss.php:143
-msgid "Score"
-msgstr ""
-
-#: tt-rss.php:148 modules/pref-feeds.php:347 modules/pref-feeds.php:600
-msgid "Update"
-msgstr ""
-
-#: tt-rss.php:160
-msgid "Search..."
-msgstr ""
-
-#: tt-rss.php:161
-msgid "Feed actions:"
-msgstr ""
-
-#: tt-rss.php:162
-msgid "Subscribe to feed..."
-msgstr ""
-
-#: tt-rss.php:163
-msgid "Edit this feed..."
-msgstr ""
-
-#: tt-rss.php:164
-msgid "Rescore feed"
-msgstr ""
-
-#: tt-rss.php:165 modules/pref-feeds.php:530 modules/pref-feeds.php:1374
-msgid "Unsubscribe"
-msgstr ""
-
-#: tt-rss.php:166
-msgid "All feeds:"
-msgstr ""
-
-#: tt-rss.php:168 help/3.php:56
-msgid "(Un)hide read feeds"
-msgstr ""
-
-#: tt-rss.php:169
-msgid "Other actions:"
-msgstr ""
-
-#: tt-rss.php:170
-msgid "Switch to digest..."
-msgstr ""
-
-#: tt-rss.php:171
-msgid "Show tag cloud..."
-msgstr ""
-
-#: tt-rss.php:172
-msgid "Select by tags..."
-msgstr ""
-
-#: tt-rss.php:174
-msgid "Create filter..."
-msgstr ""
-
-#: tt-rss.php:175
-msgid "Keyboard shortcuts help"
-msgstr ""
-
-#: tt-rss.php:176 tt-rss.js:437
-msgid "About..."
-msgstr ""
-
-#: twitter.php:95
-msgid "Register with Twitter"
-msgstr ""
-
-#: twitter.php:99
-msgid "Could not connect to Twitter. Refresh the page or try again later."
-msgstr ""
-
-#: twitter.php:103
-msgid "Congratulations! You have successfully registered with Twitter."
-msgstr ""
-
-#: twitter.php:115 modules/pref-prefs.php:464
-msgid "Register"
-msgstr ""
-
-#: modules/backend-rpc.php:843
-msgid "Your request could not be completed."
-msgstr ""
-
-#: modules/backend-rpc.php:847
-msgid "Feed update has been scheduled."
-msgstr ""
-
-#: modules/backend-rpc.php:855
-msgid "Category update has been scheduled."
-msgstr ""
-
-#: modules/backend-rpc.php:868
-msgid "Can't update this kind of feed."
-msgstr ""
-
-#: modules/help.php:6
-msgid "Help"
-msgstr ""
-
-#: modules/help.php:17
-msgid "Help topic not found."
-msgstr ""
-
-#: modules/opml_domdoc.php:60
-#, php-format
-msgid "<li>Adding category <b>%s</b>.</li>"
-msgstr ""
-
-#: modules/opml_domdoc.php:82
-#, php-format
-msgid "Setting preference key %s to %s"
-msgstr ""
-
-#: modules/opml_domdoc.php:128
-msgid "is already imported."
-msgstr ""
-
-#: modules/opml_domdoc.php:148
-msgid "OK"
-msgstr ""
-
-#: modules/opml_domdoc.php:157
-msgid "Error while parsing document."
-msgstr ""
-
-#: modules/opml_domdoc.php:161
-msgid "Error: please upload OPML file."
-msgstr ""
-
-#: modules/popup-dialog.php:34
-msgid "Importing using DOMXML."
-msgstr ""
-
-#: modules/popup-dialog.php:40
-msgid "Importing using DOMDocument."
-msgstr ""
-
-#: modules/popup-dialog.php:45
-msgid "DOMXML extension is not found. It is required for PHP versions below 5."
-msgstr ""
-
-#: modules/popup-dialog.php:80
-msgid "Create profile"
-msgstr ""
-
-#: modules/popup-dialog.php:103 modules/popup-dialog.php:132
-msgid "(active)"
-msgstr ""
-
-#: modules/popup-dialog.php:166
-msgid "Remove selected profiles"
-msgstr ""
-
-#: modules/popup-dialog.php:168
-msgid "Activate profile"
-msgstr ""
-
-#: modules/popup-dialog.php:179
-msgid "Public OPML URL"
-msgstr ""
-
-#: modules/popup-dialog.php:184
-msgid "Your Public OPML URL is:"
-msgstr ""
-
-#: modules/popup-dialog.php:193 modules/popup-dialog.php:901
-msgid "Generate new URL"
-msgstr ""
-
-#: modules/popup-dialog.php:206
-msgid "Notice"
-msgstr ""
-
-#: modules/popup-dialog.php:212
-msgid ""
-"Update daemon is enabled in configuration, but daemon process is not "
-"running, which prevents all feeds from updating. Please start the daemon "
-"process or contact instance owner."
-msgstr ""
-
-#: modules/popup-dialog.php:216 modules/popup-dialog.php:225
-msgid "Last update:"
-msgstr ""
-
-#: modules/popup-dialog.php:221
-msgid ""
-"Update daemon is taking too long to perform a feed update. This could "
-"indicate a problem like crash or a hang. Please check the daemon process or "
-"contact instance owner."
-msgstr ""
-
-#: modules/popup-dialog.php:247 modules/pref-feeds.php:300
-#: modules/pref-feeds.php:561
-msgid "Feed"
-msgstr ""
-
-#: modules/popup-dialog.php:257 modules/pref-feeds.php:339
-#: modules/pref-feeds.php:589
-msgid "Place in category:"
-msgstr ""
-
-#: modules/popup-dialog.php:265
-msgid "Available feeds"
-msgstr ""
-
-#: modules/popup-dialog.php:277 modules/pref-feeds.php:379
-#: modules/pref-feeds.php:632 modules/pref-prefs.php:205
-#: modules/pref-users.php:147
-msgid "Authentication"
-msgstr ""
-
-#: modules/popup-dialog.php:281 modules/pref-feeds.php:389
-#: modules/pref-feeds.php:636 modules/pref-users.php:436
-msgid "Login"
-msgstr ""
-
-#: modules/popup-dialog.php:284 modules/pref-feeds.php:397
-#: modules/pref-feeds.php:642
-msgid "Password"
-msgstr ""
-
-#: modules/popup-dialog.php:294
-msgid "This feed requires authentication."
-msgstr ""
-
-#: modules/popup-dialog.php:299 modules/popup-dialog.php:352
-msgid "Subscribe"
-msgstr ""
-
-#: modules/popup-dialog.php:300
-msgid "More feeds"
-msgstr ""
-
-#: modules/popup-dialog.php:301 modules/popup-dialog.php:354
-#: modules/popup-dialog.php:433 modules/popup-dialog.php:544
-#: modules/popup-dialog.php:715 modules/popup-dialog.php:873
-#: modules/popup-dialog.php:962 modules/popup-dialog.php:989
-#: modules/popup-dialog.php:1071 modules/pref-feeds.php:547
-#: modules/pref-feeds.php:704 modules/pref-filters.php:340
-#: modules/pref-instances.php:98 modules/pref-labels.php:80
-#: modules/pref-users.php:186
-msgid "Cancel"
-msgstr ""
-
-#: modules/popup-dialog.php:324 modules/popup-dialog.php:432
-#: modules/pref-feeds.php:1335 modules/pref-users.php:367 tt-rss.js:233
-msgid "Search"
-msgstr ""
-
-#: modules/popup-dialog.php:328
-msgid "Popular feeds"
-msgstr ""
-
-#: modules/popup-dialog.php:329
-msgid "Feed archive"
-msgstr ""
-
-#: modules/popup-dialog.php:332
-msgid "limit:"
-msgstr ""
-
-#: modules/popup-dialog.php:353 modules/pref-feeds.php:520
-#: modules/pref-filters.php:330 modules/pref-filters.php:537
-#: modules/pref-instances.php:144 modules/pref-labels.php:281
-#: modules/pref-users.php:393
-msgid "Remove"
-msgstr ""
-
-#: modules/popup-dialog.php:365
-msgid "Look for"
-msgstr ""
-
-#: modules/popup-dialog.php:375
-msgid "match on"
-msgstr ""
-
-#: modules/popup-dialog.php:380
-msgid "Title or content"
-msgstr ""
-
-#: modules/popup-dialog.php:391
-msgid "Limit search to:"
-msgstr ""
-
-#: modules/popup-dialog.php:407
-msgid "This feed"
-msgstr ""
-
-#: modules/popup-dialog.php:455 modules/pref-filters.php:219
-msgid "Match"
-msgstr ""
-
-#: modules/popup-dialog.php:462 modules/pref-filters.php:231
-msgid "before"
-msgstr ""
-
-#: modules/popup-dialog.php:463 modules/pref-filters.php:232
-msgid "after"
-msgstr ""
-
-#: modules/popup-dialog.php:478 modules/pref-filters.php:245
-msgid "Check it"
-msgstr ""
-
-#: modules/popup-dialog.php:481 modules/pref-filters.php:248
-msgid "on field"
-msgstr ""
-
-#: modules/popup-dialog.php:487 modules/pref-filters.php:254 digest.js:239
-msgid "in"
-msgstr ""
-
-#: modules/popup-dialog.php:493 modules/pref-filters.php:260
-msgid "Perform Action"
-msgstr ""
-
-#: modules/popup-dialog.php:510 modules/pref-filters.php:280
-msgid "with parameters:"
-msgstr ""
-
-#: modules/popup-dialog.php:524 modules/pref-feeds.php:407
-#: modules/pref-feeds.php:648 modules/pref-filters.php:300
-#: modules/pref-users.php:169
-msgid "Options"
-msgstr ""
-
-#: modules/popup-dialog.php:528 modules/pref-filters.php:312
-msgid "Enabled"
-msgstr ""
-
-#: modules/popup-dialog.php:531 modules/pref-filters.php:321
-msgid "Inverse match"
-msgstr ""
-
-#: modules/popup-dialog.php:538 modules/pref-filters.php:334
-msgid "Test"
-msgstr ""
-
-#: modules/popup-dialog.php:541
-msgid "Create"
-msgstr ""
-
-#: modules/popup-dialog.php:571
-msgid ""
-"These feeds have not been updated with new content for 3 months (oldest "
-"first):"
-msgstr ""
-
-#: modules/popup-dialog.php:595 modules/popup-dialog.php:655
-msgid "Click to edit feed"
-msgstr ""
-
-#: modules/popup-dialog.php:613 modules/popup-dialog.php:675
-msgid "Unsubscribe from selected feeds"
-msgstr ""
-
-#: modules/popup-dialog.php:628
-msgid "These feeds have not been updated because of errors:"
-msgstr ""
-
-#: modules/popup-dialog.php:688
-msgid "Tags for this article (separated by commas):"
-msgstr ""
-
-#: modules/popup-dialog.php:713 modules/popup-dialog.php:960
-#: modules/popup-dialog.php:987 modules/pref-feeds.php:546
-#: modules/pref-feeds.php:701 modules/pref-filters.php:337
-#: modules/pref-instances.php:95 modules/pref-labels.php:78
-#: modules/pref-users.php:184
-msgid "Save"
-msgstr ""
-
-#: modules/popup-dialog.php:721
-msgid "Tag Cloud"
-msgstr ""
-
-#: modules/popup-dialog.php:743
-msgid "Select item(s) by tags"
-msgstr ""
-
-#: modules/popup-dialog.php:746
-msgid "Match:"
-msgstr ""
-
-#: modules/popup-dialog.php:751
-msgid "Which Tags?"
-msgstr ""
-
-#: modules/popup-dialog.php:764
-msgid "Display entries"
-msgstr ""
-
-#: modules/popup-dialog.php:813 modules/popup-dialog.php:819
-msgid "[Forwarded]"
-msgstr ""
-
-#: modules/popup-dialog.php:813
-msgid "Multiple articles"
-msgstr ""
-
-#: modules/popup-dialog.php:834
-msgid "From:"
-msgstr ""
-
-#: modules/popup-dialog.php:843
-msgid "To:"
-msgstr ""
-
-#: modules/popup-dialog.php:856
-msgid "Subject:"
-msgstr ""
-
-#: modules/popup-dialog.php:872
-msgid "Send e-mail"
-msgstr ""
-
-#: modules/popup-dialog.php:892
-msgid "You can view this feed as RSS using the following URL:"
-msgstr ""
-
-#: modules/popup-dialog.php:919
-#, php-format
-msgid "New version of Tiny Tiny RSS is available (%s)."
-msgstr ""
-
-#: modules/popup-dialog.php:929 modules/pref-users.php:389
-msgid "Details"
-msgstr ""
-
-#: modules/popup-dialog.php:931
-msgid "Download"
-msgstr ""
-
-#: modules/popup-dialog.php:945
-#, php-format
-msgid ""
-"You can override colors, fonts and layout of your currently selected theme "
-"with custom CSS declarations here. <a target=\"_blank\" class=\"visibleLink"
-"\" href=\"%s\">This file</a> can be used as a baseline."
-msgstr ""
-
-#: modules/popup-dialog.php:1030 modules/pref-instances.php:54
-msgid "Instance"
-msgstr ""
-
-#: modules/popup-dialog.php:1036 modules/pref-feeds.php:317
-#: modules/pref-feeds.php:576 modules/pref-instances.php:62
-msgid "URL:"
-msgstr ""
-
-#: modules/popup-dialog.php:1039 modules/pref-instances.php:65
-#: modules/pref-instances.php:162
-msgid "Instance URL"
-msgstr ""
-
-#: modules/popup-dialog.php:1049 modules/pref-instances.php:76
-msgid "Access key:"
-msgstr ""
-
-#: modules/popup-dialog.php:1052 modules/pref-instances.php:79
-#: modules/pref-instances.php:163
-msgid "Access key"
-msgstr ""
-
-#: modules/popup-dialog.php:1056 modules/pref-instances.php:83
-msgid "Use one access key for both linked instances."
-msgstr ""
-
-#: modules/popup-dialog.php:1064 modules/pref-instances.php:91
-msgid "Generate new key"
-msgstr ""
-
-#: modules/popup-dialog.php:1068
-msgid "Create link"
-msgstr ""
-
-#: modules/popup-dialog.php:1094
-msgid "You can share this article by the following unique URL:"
-msgstr ""
-
-#: modules/pref-feeds.php:4
-msgid "Check to enable field"
-msgstr ""
-
-#: modules/pref-feeds.php:83 modules/pref-feeds.php:121
-#: modules/pref-feeds.php:127 modules/pref-feeds.php:150
-#, php-format
-msgid "(%d feeds)"
-msgstr ""
-
-#: modules/pref-feeds.php:306
-msgid "Feed Title"
-msgstr ""
-
-#: modules/pref-feeds.php:362 modules/pref-feeds.php:612
-msgid "using"
-msgstr ""
-
-#: modules/pref-feeds.php:372 modules/pref-feeds.php:623
-msgid "Article purging:"
-msgstr ""
-
-#: modules/pref-feeds.php:401
-msgid ""
-"<b>Hint:</b> you need to fill in your login information if your feed "
-"requires authentication, except for Twitter feeds."
-msgstr ""
-
-#: modules/pref-feeds.php:421 modules/pref-feeds.php:652
-msgid "Hide from Popular feeds"
-msgstr ""
-
-#: modules/pref-feeds.php:432 modules/pref-feeds.php:657
-msgid "Right-to-left content"
-msgstr ""
-
-#: modules/pref-feeds.php:444 modules/pref-feeds.php:663
-msgid "Include in e-mail digest"
-msgstr ""
-
-#: modules/pref-feeds.php:457 modules/pref-feeds.php:669
-msgid "Always display image attachments"
-msgstr ""
-
-#: modules/pref-feeds.php:472
-msgid "Cache images locally (SimplePie only)"
-msgstr ""
-
-#: modules/pref-feeds.php:485 modules/pref-feeds.php:686
-msgid "Mark updated articles as unread"
-msgstr ""
-
-#: modules/pref-feeds.php:497 modules/pref-feeds.php:692
-msgid "Mark posts as updated on content change"
-msgstr ""
-
-#: modules/pref-feeds.php:504
-msgid "Icon"
-msgstr ""
-
-#: modules/pref-feeds.php:518
-msgid "Replace"
-msgstr ""
-
-#: modules/pref-feeds.php:537
-msgid "Resubscribe to push updates"
-msgstr ""
-
-#: modules/pref-feeds.php:544
-msgid "Resets PubSubHubbub subscription status for push-enabled feeds."
-msgstr ""
-
-#: modules/pref-feeds.php:678
-msgid "Cache images locally"
-msgstr ""
-
-#: modules/pref-feeds.php:942 modules/pref-feeds.php:995
-msgid "All done."
-msgstr ""
-
-#: modules/pref-feeds.php:1027
-#, php-format
-msgid "Subscribed to <b>%s</b>."
-msgstr ""
-
-#: modules/pref-feeds.php:1030
-#, php-format
-msgid "Could not subscribe to <b>%s</b>."
-msgstr ""
-
-#: modules/pref-feeds.php:1033
-#, php-format
-msgid "No feeds found in <b>%s</b>."
-msgstr ""
-
-#: modules/pref-feeds.php:1036
-#, php-format
-msgid "Already subscribed to <b>%s</b>."
-msgstr ""
-
-#: modules/pref-feeds.php:1044
-#, php-format
-msgid "Could not subscribe to <b>%s</b>.<br>Can't download the Feed URL."
-msgstr ""
-
-#: modules/pref-feeds.php:1066
-msgid "Subscribe to selected feed"
-msgstr ""
-
-#: modules/pref-feeds.php:1091
-msgid "Edit subscription options"
-msgstr ""
-
-#: modules/pref-feeds.php:1173
-#, php-format
-msgid "Category <b>$%s</b> already exists in the database."
-msgstr ""
-
-#: modules/pref-feeds.php:1189
-msgid "Create category"
-msgstr ""
-
-#: modules/pref-feeds.php:1259
-msgid "No feed categories defined."
-msgstr ""
-
-#: modules/pref-feeds.php:1265
-msgid "Remove selected categories"
-msgstr ""
-
-#: modules/pref-feeds.php:1293
-msgid "Feeds with errors"
-msgstr ""
-
-#: modules/pref-feeds.php:1316
-msgid "Inactive feeds"
-msgstr ""
-
-#: modules/pref-feeds.php:1339 modules/pref-filters.php:522
-#: modules/pref-instances.php:134 modules/pref-labels.php:269
-#: modules/pref-users.php:377
-msgid "Select"
-msgstr ""
-
-#: modules/pref-feeds.php:1351 help/3.php:57 help/4.php:22
-msgid "Subscribe to feed"
-msgstr ""
-
-#: modules/pref-feeds.php:1353
-msgid "Edit selected feeds"
-msgstr ""
-
-#: modules/pref-feeds.php:1355 modules/pref-feeds.php:1365
-msgid "Reset sort order"
-msgstr ""
-
-#: modules/pref-feeds.php:1360
-msgid "Categories"
-msgstr ""
-
-#: modules/pref-feeds.php:1363
-msgid "Edit categories"
-msgstr ""
-
-#: modules/pref-feeds.php:1379
-msgid "More actions..."
-msgstr ""
-
-#: modules/pref-feeds.php:1383
-msgid "Manual purge"
-msgstr ""
-
-#: modules/pref-feeds.php:1387
-msgid "Clear feed data"
-msgstr ""
-
-#: modules/pref-feeds.php:1388 modules/pref-filters.php:541
-msgid "Rescore articles"
-msgstr ""
-
-#: modules/pref-feeds.php:1430
-msgid "<b>Hint:</b> you can drag feeds and categories around."
-msgstr ""
-
-#: modules/pref-feeds.php:1438
-msgid "OPML"
-msgstr ""
-
-#: modules/pref-feeds.php:1440
-msgid ""
-"Using OPML you can export and import your feeds and Tiny Tiny RSS settings."
-msgstr ""
-
-#: modules/pref-feeds.php:1442
-msgid "Note: Only main settings profile can be migrated using OPML."
-msgstr ""
-
-#: modules/pref-feeds.php:1446 modules/pref-feeds.php:1459
-msgid "Import"
-msgstr ""
-
-#: modules/pref-feeds.php:1461 modules/pref-feeds.php:1469
-msgid "Export"
-msgstr ""
-
-#: modules/pref-feeds.php:1463
-msgid "Filename:"
-msgstr ""
-
-#: modules/pref-feeds.php:1465
-msgid "Include settings"
-msgstr ""
-
-#: modules/pref-feeds.php:1471
-msgid "Publish"
-msgstr ""
-
-#: modules/pref-feeds.php:1473
-msgid ""
-"Your OPML can be published publicly and can be subscribed by anyone who "
-"knows the URL below."
-msgstr ""
-
-#: modules/pref-feeds.php:1475
-msgid ""
-"Note: Published OPML does not include your Tiny Tiny RSS settings, feeds "
-"that require authentication or feeds hidden from Popular feeds."
-msgstr ""
-
-#: modules/pref-feeds.php:1478 modules/pref-feeds.php:1526
-msgid "Display URL"
-msgstr ""
-
-#: modules/pref-feeds.php:1485
-msgid "Firefox integration"
-msgstr ""
-
-#: modules/pref-feeds.php:1487
-msgid ""
-"This Tiny Tiny RSS site can be used as a Firefox Feed Reader by clicking the "
-"link below."
-msgstr ""
-
-#: modules/pref-feeds.php:1494
-msgid "Click here to register this site as a feed reader."
-msgstr ""
-
-#: modules/pref-feeds.php:1502
-msgid "Subscribing using bookmarklet"
-msgstr ""
-
-#: modules/pref-feeds.php:1504
-msgid ""
-"Drag the link below to your browser toolbar, open the feed you're interested "
-"in in your browser and click on the link to subscribe to it."
-msgstr ""
-
-#: modules/pref-feeds.php:1508
-#, php-format
-msgid "Subscribe to %s in Tiny Tiny RSS?"
-msgstr ""
-
-#: modules/pref-feeds.php:1512
-msgid "Subscribe in Tiny Tiny RSS"
-msgstr ""
-
-#: modules/pref-feeds.php:1516
-msgid "Published & shared articles and generated feeds"
-msgstr ""
-
-#: modules/pref-feeds.php:1518
-msgid "Published articles and generated feeds"
-msgstr ""
-
-#: modules/pref-feeds.php:1520
-msgid ""
-"Published articles are exported as a public RSS feed and can be subscribed "
-"by anyone who knows the URL specified below."
-msgstr ""
-
-#: modules/pref-feeds.php:1529
-msgid "Clear all generated URLs"
-msgstr ""
-
-#: modules/pref-feeds.php:1531
-msgid "Articles shared by URL"
-msgstr ""
-
-#: modules/pref-feeds.php:1533
-msgid "You can disable all articles shared by unique URLs here."
-msgstr ""
-
-#: modules/pref-feeds.php:1536
-msgid "Unshare all articles"
-msgstr ""
-
-#: modules/pref-feeds.php:1542
-msgid "Twitter"
-msgstr ""
-
-#: modules/pref-feeds.php:1551
-msgid ""
-"Before you can update your Twitter feeds, you must register this instance of "
-"Tiny Tiny RSS with Twitter.com."
-msgstr ""
-
-#: modules/pref-feeds.php:1553
-msgid ""
-"You have been successfully registered with Twitter.com and should be able to "
-"access your Twitter feeds."
-msgstr ""
-
-#: modules/pref-feeds.php:1557
-msgid "Register with Twitter.com"
-msgstr ""
-
-#: modules/pref-feeds.php:1563
-msgid "Clear stored credentials"
-msgstr ""
-
-#: modules/pref-feeds.php:1654
-#, php-format
-msgid "%d archived articles"
-msgstr ""
-
-#: modules/pref-feeds.php:1678
-msgid "No feeds found."
-msgstr ""
-
-#: modules/pref-filters.php:38
-msgid "Articles matching this filter:"
-msgstr ""
-
-#: modules/pref-filters.php:75
-msgid "No articles matching this filter has been found."
-msgstr ""
-
-#: modules/pref-filters.php:470
-#, php-format
-msgid "Created filter <b>%s</b>"
-msgstr ""
-
-#: modules/pref-filters.php:531 help/3.php:34 help/4.php:25
-msgid "Create filter"
-msgstr ""
-
-#: modules/pref-filters.php:534 modules/pref-instances.php:143
-#: modules/pref-users.php:391
-msgid "Edit"
-msgstr ""
-
-#: modules/pref-instances.php:5 modules/pref-users.php:7
-msgid "Your access level is insufficient to open this tab."
-msgstr ""
-
-#: modules/pref-instances.php:142
-msgid "Link instance"
-msgstr ""
-
-#: modules/pref-instances.php:154
-msgid ""
-"You can connect other instances of Tiny Tiny RSS to this one to share "
-"Popular feeds. Link to this instance of Tiny Tiny RSS by using this URL:"
-msgstr ""
-
-#: modules/pref-instances.php:164
-msgid "Last connected"
-msgstr ""
-
-#: modules/pref-instances.php:165
-msgid "Stored feeds"
-msgstr ""
-
-#: modules/pref-instances.php:183 modules/pref-users.php:467
-msgid "Click to edit"
-msgstr ""
-
-#: modules/pref-labels.php:21
-msgid "Caption"
-msgstr ""
-
-#: modules/pref-labels.php:36
-msgid "Colors"
-msgstr ""
-
-#: modules/pref-labels.php:41
-msgid "Foreground:"
-msgstr ""
-
-#: modules/pref-labels.php:41
-msgid "Background:"
-msgstr ""
-
-#: modules/pref-labels.php:231
-#, php-format
-msgid "Created label <b>%s</b>"
-msgstr ""
-
-#: modules/pref-labels.php:278 help/3.php:33 help/4.php:26
-msgid "Create label"
-msgstr ""
-
-#: modules/pref-labels.php:284
-msgid "Clear colors"
-msgstr ""
-
-#: modules/pref-prefs.php:29
-msgid "Old password cannot be blank."
-msgstr ""
-
-#: modules/pref-prefs.php:34
-msgid "New password cannot be blank."
-msgstr ""
-
-#: modules/pref-prefs.php:39
-msgid "Entered passwords do not match."
-msgstr ""
-
-#: modules/pref-prefs.php:63
-msgid "Password has been changed."
-msgstr ""
-
-#: modules/pref-prefs.php:65
-msgid "Old password is incorrect."
-msgstr ""
-
-#: modules/pref-prefs.php:93
-msgid "The configuration was saved."
-msgstr ""
-
-#: modules/pref-prefs.php:109
-#, php-format
-msgid "Unknown option: %s"
-msgstr ""
-
-#: modules/pref-prefs.php:122
-msgid "Your personal data has been saved."
-msgstr ""
-
-#: modules/pref-prefs.php:154
-msgid "Personal data"
-msgstr ""
-
-#: modules/pref-prefs.php:181
-msgid "Full name"
-msgstr ""
-
-#: modules/pref-prefs.php:185
-msgid "E-mail"
-msgstr ""
-
-#: modules/pref-prefs.php:190
-msgid "Access level"
-msgstr ""
-
-#: modules/pref-prefs.php:200
-msgid "Save data"
-msgstr ""
-
-#: modules/pref-prefs.php:212
-msgid "Your password is at default value, please change it."
-msgstr ""
-
-#: modules/pref-prefs.php:240
-msgid "Old password"
-msgstr ""
-
-#: modules/pref-prefs.php:243
-msgid "New password"
-msgstr ""
-
-#: modules/pref-prefs.php:248
-msgid "Confirm password"
-msgstr ""
-
-#: modules/pref-prefs.php:258
-msgid "Change password"
-msgstr ""
-
-#: modules/pref-prefs.php:344
-msgid "Select theme"
-msgstr ""
-
-#: modules/pref-prefs.php:402
-msgid "Customize"
-msgstr ""
-
-#: modules/pref-prefs.php:422 modules/pref-prefs.php:429
-#: modules/pref-prefs.php:434
-msgid "Yes"
-msgstr ""
-
-#: modules/pref-prefs.php:424 modules/pref-prefs.php:434
-msgid "No"
-msgstr ""
-
-#: modules/pref-prefs.php:468
-msgid "Clear"
-msgstr ""
-
-#: modules/pref-prefs.php:494
-msgid "Save configuration"
-msgstr ""
-
-#: modules/pref-prefs.php:497
-msgid "Manage profiles"
-msgstr ""
-
-#: modules/pref-prefs.php:500
-msgid "Reset to defaults"
-msgstr ""
-
-#: modules/pref-users.php:20
-msgid "User details"
-msgstr ""
-
-#: modules/pref-users.php:34
-msgid "User not found"
-msgstr ""
-
-#: modules/pref-users.php:53 modules/pref-users.php:438
-msgid "Registered"
-msgstr ""
-
-#: modules/pref-users.php:54
-msgid "Last logged in"
-msgstr ""
-
-#: modules/pref-users.php:61
-msgid "Subscribed feeds count"
-msgstr ""
-
-#: modules/pref-users.php:65
-msgid "Subscribed feeds"
-msgstr ""
-
-#: modules/pref-users.php:114
-msgid "User Editor"
-msgstr ""
-
-#: modules/pref-users.php:150
-msgid "Access level: "
-msgstr ""
-
-#: modules/pref-users.php:163
-msgid "Change password to"
-msgstr ""
-
-#: modules/pref-users.php:172
-msgid "E-mail: "
-msgstr ""
-
-#: modules/pref-users.php:206
-#, php-format
-msgid "Changed password of user <b>%s</b>."
-msgstr ""
-
-#: modules/pref-users.php:254
-#, php-format
-msgid "Added user <b>%s</b> with password <b>%s</b>"
-msgstr ""
-
-#: modules/pref-users.php:261
-#, php-format
-msgid "Could not create user <b>%s</b>"
-msgstr ""
-
-#: modules/pref-users.php:265
-#, php-format
-msgid "User <b>%s</b> already exists."
-msgstr ""
-
-#: modules/pref-users.php:285
-#, php-format
-msgid ""
-"Changed password of user <b>%s</b>\n"
-"\t\t\t\t\t to <b>%s</b>"
-msgstr ""
-
-#: modules/pref-users.php:289
-#, php-format
-msgid "Notifying <b>%s</b>."
-msgstr ""
-
-#: modules/pref-users.php:326
-msgid "[tt-rss] Password change notification"
-msgstr ""
-
-#: modules/pref-users.php:385 help/4.php:27
-msgid "Create user"
-msgstr ""
-
-#: modules/pref-users.php:395
-msgid "Reset password"
-msgstr ""
-
-#: modules/pref-users.php:437
-msgid "Access Level"
-msgstr ""
-
-#: modules/pref-users.php:439
-msgid "Last login"
-msgstr ""
-
-#: modules/pref-users.php:487
-msgid "No users defined."
-msgstr ""
-
-#: modules/pref-users.php:489
-msgid "No matching users found."
-msgstr ""
-
-#: help/2.php:1
-msgid "Content filtering"
-msgstr ""
-
-#: help/2.php:3
-msgid ""
-"Tiny Tiny RSS has support for filtering (or processing) articles. Filtering "
-"is done once, when new article is imported to the database from the "
-"newsfeed, specified field is matched against regular expression and some "
-"action is taken. Regular expression matching is case-insensitive."
-msgstr ""
-
-#: help/2.php:5
-msgid ""
-"Supported actions are: filter (do not import) article, mark article as read, "
-"set starred, assign tag(s), and set score. Filters can be defined globally "
-"and for some specific feed."
-msgstr ""
-
-#: help/2.php:7
-msgid ""
-"Multiple and inverse matching are supported. All matching filters are "
-"considered when article is being imported and all actions executed in "
-"sequence. Inverse matching reverts matching result, e.g. filter matching "
-"XYZZY in title with inverse flag will match all articles, except those "
-"containing string XYZZY in title."
-msgstr ""
-
-#: help/2.php:9
-msgid "See also:"
-msgstr ""
-
-#: help/3.php:1 help/4.php:1
-msgid "Keyboard Shortcuts"
-msgstr ""
-
-#: help/3.php:5
-msgid "Navigation"
-msgstr ""
-
-#: help/3.php:8
-msgid "Move between feeds"
-msgstr ""
-
-#: help/3.php:9
-msgid "Move between articles"
-msgstr ""
-
-#: help/3.php:10
-msgid "Show search dialog"
-msgstr ""
-
-#: help/3.php:13
-msgid "Active article actions"
-msgstr ""
-
-#: help/3.php:16
-msgid "Toggle starred"
-msgstr ""
-
-#: help/3.php:17
-msgid "Toggle published"
-msgstr ""
-
-#: help/3.php:18
-msgid "Toggle unread"
-msgstr ""
-
-#: help/3.php:19
-msgid "Edit tags"
-msgstr ""
-
-#: help/3.php:20
-msgid "Dismiss selected articles"
-msgstr ""
-
-#: help/3.php:21
-msgid "Dismiss read articles"
-msgstr ""
-
-#: help/3.php:22
-msgid "Open article in new window"
-msgstr ""
-
-#: help/3.php:23
-msgid "Mark articles below/above active one as read"
-msgstr ""
-
-#: help/3.php:24
-msgid "Scroll article content"
-msgstr ""
-
-#: help/3.php:25
-msgid "Email article"
-msgstr ""
-
-#: help/3.php:29 help/4.php:30
-msgid "Other actions"
-msgstr ""
-
-#: help/3.php:32
-msgid "Select article under mouse cursor"
-msgstr ""
-
-#: help/3.php:35
-msgid "Collapse sidebar"
-msgstr ""
-
-#: help/3.php:36
-msgid "Toggle category reordering mode"
-msgstr ""
-
-#: help/3.php:37 help/4.php:34
-msgid "Display this help dialog"
-msgstr ""
-
-#: help/3.php:42
-msgid "Multiple articles actions"
-msgstr ""
-
-#: help/3.php:45
-msgid "Select all articles"
-msgstr ""
-
-#: help/3.php:46
-msgid "Select unread articles"
-msgstr ""
-
-#: help/3.php:47
-msgid "Invert article selection"
-msgstr ""
-
-#: help/3.php:48
-msgid "Deselect all articles"
-msgstr ""
-
-#: help/3.php:51
-msgid "Feed actions"
-msgstr ""
-
-#: help/3.php:54
-msgid "Refresh active feed"
-msgstr ""
-
-#: help/3.php:55
-msgid "Update all feeds"
-msgstr ""
-
-#: help/3.php:58 FeedTree.js:131
-msgid "Edit feed"
-msgstr ""
-
-#: help/3.php:59
-msgid "Sort by name or unread count"
-msgstr ""
-
-#: help/3.php:60
-msgid "Mark feed as read"
-msgstr ""
-
-#: help/3.php:61
-msgid "Reverse headlines order"
-msgstr ""
-
-#: help/3.php:62
-msgid "Mark all feeds as read"
-msgstr ""
-
-#: help/3.php:63
-msgid "If viewing category, (un)collapse it"
-msgstr ""
-
-#: help/3.php:66 help/4.php:5
-msgid "Go to..."
-msgstr ""
-
-#: help/3.php:73
-msgid "Tag cloud"
-msgstr ""
-
-#: help/3.php:80
-msgid "Other interface tips are available in the Tiny Tiny RSS wiki."
-msgstr ""
-
-#: help/3.php:82 help/4.php:41
-msgid "Press any key to close this window."
-msgstr ""
-
-#: help/4.php:9
-msgid "My Feeds"
-msgstr ""
-
-#: help/4.php:10
-msgid "Other Feeds"
-msgstr ""
-
-#: help/4.php:19
-msgid "Panel actions"
-msgstr ""
-
-#: help/4.php:23
-msgid "Top 25 feeds"
-msgstr ""
-
-#: help/4.php:24
-msgid "Edit feed categories"
-msgstr ""
-
-#: help/4.php:33
-msgid "Focus search (if present)"
-msgstr ""
-
-#: help/4.php:39
-msgid ""
-"<b>Note:</b> not all actions may be available, depending on Tiny Tiny RSS "
-"configuration and your access level."
-msgstr ""
-
-#: mobile/functions.php:58 mobile/functions.php:134 mobile/functions.php:170
-#: mobile/functions.php:197 mobile/functions.php:233 mobile/functions.php:372
-#: mobile/prefs.php:25
-msgid "Home"
-msgstr ""
-
-#: mobile/functions.php:408
-msgid "Nothing found (click to reload feed)."
-msgstr ""
-
-#: mobile/prefs.php:30
-msgid "Enable categories"
-msgstr ""
-
-#: mobile/prefs.php:31 mobile/prefs.php:36 mobile/prefs.php:42
-#: mobile/prefs.php:47 mobile/prefs.php:52
-msgid "ON"
-msgstr ""
-
-#: mobile/prefs.php:31 mobile/prefs.php:36 mobile/prefs.php:42
-#: mobile/prefs.php:47 mobile/prefs.php:52
-msgid "OFF"
-msgstr ""
-
-#: mobile/prefs.php:35
-msgid "Browse categories like folders"
-msgstr ""
-
-#: mobile/prefs.php:41
-msgid "Show images in posts"
-msgstr ""
-
-#: mobile/prefs.php:46
-msgid "Hide read articles and feeds"
-msgstr ""
-
-#: mobile/prefs.php:51
-msgid "Sort feeds by unread count"
-msgstr ""
-
-#: digest.js:23 feedlist.js:462 tt-rss.js:521 tt-rss.js:534
-msgid "Mark all articles in %s as read?"
-msgstr ""
-
-#: digest.js:69
-msgid "Mark %d displayed articles as read?"
-msgstr ""
-
-#: digest.js:255 digest.js:688 viewfeed.js:425
-msgid "Unstar article"
-msgstr ""
-
-#: digest.js:257 digest.js:692 viewfeed.js:430
-msgid "Star article"
-msgstr ""
-
-#: digest.js:260 digest.js:723 viewfeed.js:465
-msgid "Unpublish article"
-msgstr ""
-
-#: digest.js:265
-msgid "Original article"
-msgstr ""
-
-#: digest.js:290
-msgid "Error: unable to load article."
-msgstr ""
-
-#: digest.js:442
-msgid "Click to expand article."
-msgstr ""
-
-#: digest.js:517
-msgid "%d more..."
-msgstr ""
-
-#: digest.js:524
-msgid "No unread feeds."
-msgstr ""
-
-#: digest.js:626
-msgid "Load more..."
-msgstr ""
-
-#: feedlist.js:269
-msgid "New articles available in this feed (click to show)"
-msgstr ""
-
-#: FeedTree.js:137
-msgid "Update feed"
-msgstr ""
-
-#: functions.js:72
-msgid ""
-"Are you sure to report this exception to tt-rss.org? The report will include "
-"your browser information. Your IP would be saved in the database."
-msgstr ""
-
-#: functions.js:624
-msgid "Date syntax appears to be correct:"
-msgstr ""
-
-#: functions.js:627
-msgid "Date syntax is incorrect."
-msgstr ""
-
-#: functions.js:763
-msgid "Remove stored feed icon?"
-msgstr ""
-
-#: functions.js:795
-msgid "Please select an image file to upload."
-msgstr ""
-
-#: functions.js:797
-msgid "Upload new icon for this feed?"
-msgstr ""
-
-#: functions.js:814
-msgid "Please enter label caption:"
-msgstr ""
-
-#: functions.js:819
-msgid "Can't create label: missing caption."
-msgstr ""
-
-#: functions.js:861
-msgid "Subscribe to Feed"
-msgstr ""
-
-#: functions.js:869
-msgid "Subscribing to feed..."
-msgstr ""
-
-#: functions.js:887
-msgid "Subscribed to %s"
-msgstr ""
-
-#: functions.js:892
-msgid "Specified URL seems to be invalid."
-msgstr ""
-
-#: functions.js:895
-msgid "Specified URL doesn't seem to contain any feeds."
-msgstr ""
-
-#: functions.js:931
-msgid "Couldn't download the specified URL."
-msgstr ""
-
-#: functions.js:934
-msgid "You are already subscribed to this feed."
-msgstr ""
-
-#: functions.js:963
-msgid "Create Filter"
-msgstr ""
-
-#: functions.js:973 prefs.js:214
-msgid "Filter Test Results"
-msgstr ""
-
-#: functions.js:1031
-msgid ""
-"Reset subscription? Tiny Tiny RSS will try to subscribe to the notification "
-"hub again on next feed update."
-msgstr ""
-
-#: functions.js:1052 tt-rss.js:396
-msgid "Unsubscribe from %s?"
-msgstr ""
-
-#: functions.js:1159
-msgid "Please enter category title:"
-msgstr ""
-
-#: functions.js:1190
-msgid "Generate new syndication address for this feed?"
-msgstr ""
-
-#: functions.js:1374 tt-rss.js:375 tt-rss.js:892
-msgid "You can't edit this kind of feed."
-msgstr ""
-
-#: functions.js:1386
-msgid "Edit Feed"
-msgstr ""
-
-#: functions.js:1424
-msgid "More Feeds"
-msgstr ""
-
-#: functions.js:1485 functions.js:1595 prefs.js:439 prefs.js:469 prefs.js:501
-#: prefs.js:659 prefs.js:679 prefs.js:1268 prefs.js:1413
-msgid "No feeds are selected."
-msgstr ""
-
-#: functions.js:1527
-msgid ""
-"Remove selected feeds from the archive? Feeds with stored articles will not "
-"be removed."
-msgstr ""
-
-#: functions.js:1566
-msgid "Feeds with update errors"
-msgstr ""
-
-#: functions.js:1577 prefs.js:1250
-msgid "Remove selected feeds?"
-msgstr ""
-
-#: PrefFilterTree.js:32
-msgid "Inverse"
-msgstr ""
-
-#: prefs.js:114
-msgid "Please enter login:"
-msgstr ""
-
-#: prefs.js:121
-msgid "Can't create user: no login specified."
-msgstr ""
-
-#: prefs.js:183
-msgid "Edit Filter"
-msgstr ""
-
-#: prefs.js:187
-msgid "Remove filter %s?"
-msgstr ""
-
-#: prefs.js:321
-msgid "Remove selected labels?"
-msgstr ""
-
-#: prefs.js:337 prefs.js:1454
-msgid "No labels are selected."
-msgstr ""
-
-#: prefs.js:351
-msgid ""
-"Remove selected users? Neither default admin nor your account will be "
-"removed."
-msgstr ""
-
-#: prefs.js:368 prefs.js:549 prefs.js:570 prefs.js:609
-msgid "No users are selected."
-msgstr ""
-
-#: prefs.js:386
-msgid "Remove selected filters?"
-msgstr ""
-
-#: prefs.js:401 prefs.js:639
-msgid "No filters are selected."
-msgstr ""
-
-#: prefs.js:420
-msgid "Unsubscribe from selected feeds?"
-msgstr ""
-
-#: prefs.js:454
-msgid "Please select only one feed."
-msgstr ""
-
-#: prefs.js:460
-msgid "Erase all non-starred articles in selected feed?"
-msgstr ""
-
-#: prefs.js:482
-msgid "How many days of articles to keep (0 - use default)?"
-msgstr ""
-
-#: prefs.js:520
-msgid "Login field cannot be blank."
-msgstr ""
-
-#: prefs.js:554 prefs.js:575 prefs.js:614
-msgid "Please select only one user."
-msgstr ""
-
-#: prefs.js:579
-msgid "Reset password of selected user?"
-msgstr ""
-
-#: prefs.js:644
-msgid "Please select only one filter."
-msgstr ""
-
-#: prefs.js:701
-msgid "Edit Multiple Feeds"
-msgstr ""
-
-#: prefs.js:725
-msgid "Save changes to selected feeds?"
-msgstr ""
-
-#: prefs.js:815
-msgid "OPML Import"
-msgstr ""
-
-#: prefs.js:834
-msgid "Please choose an OPML file first."
-msgstr ""
-
-#: prefs.js:954
-msgid "Reset to defaults?"
-msgstr ""
-
-#: prefs.js:1170
-msgid "Feed Categories"
-msgstr ""
-
-#: prefs.js:1179
-msgid "Remove selected categories?"
-msgstr ""
-
-#: prefs.js:1198
-msgid "No categories are selected."
-msgstr ""
-
-#: prefs.js:1239
-msgid "Feeds without recent updates"
-msgstr ""
-
-#: prefs.js:1288
-msgid "Replace current OPML publishing address with a new one?"
-msgstr ""
-
-#: prefs.js:1397
-msgid "Rescore articles in selected feeds?"
-msgstr ""
-
-#: prefs.js:1420
-msgid "Rescore all articles? This operation may take a lot of time."
-msgstr ""
-
-#: prefs.js:1440
-msgid "Reset selected labels to default colors?"
-msgstr ""
-
-#: prefs.js:1477
-msgid "Settings Profiles"
-msgstr ""
-
-#: prefs.js:1486
-msgid ""
-"Remove selected profiles? Active and default profiles will not be removed."
-msgstr ""
-
-#: prefs.js:1504
-msgid "No profiles are selected."
-msgstr ""
-
-#: prefs.js:1512 prefs.js:1565
-msgid "Activate selected profile?"
-msgstr ""
-
-#: prefs.js:1528 prefs.js:1581
-msgid "Please choose a profile to activate."
-msgstr ""
-
-#: prefs.js:1589
-msgid "This will invalidate all previously generated feed URLs. Continue?"
-msgstr ""
-
-#: prefs.js:1608
-msgid "This will invalidate all previously shared article URLs. Continue?"
-msgstr ""
-
-#: prefs.js:1691
-msgid "Label Editor"
-msgstr ""
-
-#: prefs.js:1755
-msgid ""
-"This will clear your stored authentication information for Twitter. Continue?"
-msgstr ""
-
-#: prefs.js:1826
-msgid "Link Instance"
-msgstr ""
-
-#: prefs.js:1877
-msgid "Edit Instance"
-msgstr ""
-
-#: prefs.js:1926
-msgid "Remove selected instances?"
-msgstr ""
-
-#: prefs.js:1943 prefs.js:1955
-msgid "No instances are selected."
-msgstr ""
-
-#: prefs.js:1960
-msgid "Please select only one instance."
-msgstr ""
-
-#: tt-rss.js:147
-msgid "Mark all articles as read?"
-msgstr ""
-
-#: tt-rss.js:385
-msgid "You can't unsubscribe from the category."
-msgstr ""
-
-#: tt-rss.js:390 tt-rss.js:606 tt-rss.js:1055
-msgid "Please select some feed first."
-msgstr ""
-
-#: tt-rss.js:601
-msgid "You can't rescore this kind of feed."
-msgstr ""
-
-#: tt-rss.js:611
-msgid "Rescore articles in %s?"
-msgstr ""
-
-#: tt-rss.js:1095
-msgid "New version available!"
-msgstr ""
-
-#: viewfeed.js:636 viewfeed.js:664 viewfeed.js:691 viewfeed.js:753
-#: viewfeed.js:785 viewfeed.js:901 viewfeed.js:945 viewfeed.js:995
-#: viewfeed.js:1509
-msgid "No articles are selected."
-msgstr ""
-
-#: viewfeed.js:881
-msgid "Mark all visible articles in %s as read?"
-msgstr ""
-
-#: viewfeed.js:910
-msgid "Delete %d selected articles in %s?"
-msgstr ""
-
-#: viewfeed.js:912
-msgid "Delete %d selected articles?"
-msgstr ""
-
-#: viewfeed.js:954
-msgid "Archive %d selected articles in %s?"
-msgstr ""
-
-#: viewfeed.js:957
-msgid "Move %d archived articles back?"
-msgstr ""
-
-#: viewfeed.js:1001
-msgid "Mark %d selected articles in %s as read?"
-msgstr ""
-
-#: viewfeed.js:1025
-msgid "Edit article Tags"
-msgstr ""
-
-#: viewfeed.js:1175
-msgid "No article is selected."
-msgstr ""
-
-#: viewfeed.js:1210
-msgid "No articles found to mark"
-msgstr ""
-
-#: viewfeed.js:1212
-msgid "Mark %d article(s) as read?"
-msgstr ""
-
-#: viewfeed.js:1376
-msgid "Loading..."
-msgstr ""
-
-#: viewfeed.js:1523
-msgid "Forward article by email"
-msgstr ""
-
-#: viewfeed.js:1920
-msgid "Open original article"
-msgstr ""
-
-#: viewfeed.js:1926
-msgid "View in a tt-rss tab"
-msgstr ""
-
-#: viewfeed.js:1973
-msgid "Remove label"
-msgstr ""
-
-#: viewfeed.js:2078
-msgid "Playing..."
-msgstr ""
-
-#: viewfeed.js:2079
-msgid "Click to pause"
-msgstr ""
-
-#: viewfeed.js:2223
-msgid "Share article by URL"
-msgstr ""
define('MOBILE_VERSION', true);
require_once "../config.php";
- require_once "functions.php";
- require_once "../functions.php";
-
- require_once "../sessions.php";
-
- require_once "../version.php";
- require_once "../db-prefs.php";
+ require_once "mobile-functions.php";
$link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
define('MOBILE_VERSION', true);
require_once "../config.php";
- require_once "functions.php";
- require_once "../functions.php";
-
- require_once "../sessions.php";
-
- require_once "../version.php";
- require_once "../db-prefs.php";
+ require_once "mobile-functions.php";
$link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
+++ /dev/null
-<?php
- define('TTRSS_SESSION_NAME', 'ttrss_m_sid');
-
- function render_feeds_list($link) {
-
- $tags = $_GET["tags"];
-
- print "<div id=\"heading\">";
-
- if ($tags) {
- print __("Tags")."<span id=\"headingAddon\">
- (<a href=\"index.php\">".__("View feeds")."</a>, ";
- } else {
- print __("Feeds")." <span id=\"headingAddon\">
- (<a href=\"index.php?tags=1\">".__("View tags")."</a>, ";
- }
-
- print "<a href=\"index.php?go=sform\">".__("Search")."</a>, ";
-
- print "<a href=\"logout.php\">".__("Logout")."</a>)</span>";
- print "</div>";
-
- print "<ul class=\"feedList\">";
-
- $owner_uid = $_SESSION["uid"];
-
- if (!$tags) {
-
- /* virtual feeds */
-
- if (get_pref($link, 'ENABLE_FEED_CATS')) {
-
- $collapsed = get_pref($link, "_COLLAPSED_SPECIAL");
-
- if ($collapsed == "t" || $collapsed == "1") {
- $holder_class = "invisible";
- $ellipsis = "...";
- } else {
- $holder_class = "feedCatHolder";
- $ellipsis = "";
- }
-
- $tmp_category = __("Special");
-
- print "<li class=\"feedCat\">
- <a href=\"?subop=tc&id=-1\">$tmp_category</a>$ellipsis
- </li>";
-
- print "<li class=\"$holder_class\"><ul class=\"feedCatList\">";
- }
-
- foreach (array(-4, -3, -1, -2, 0) as $i) {
- printMobileFeedEntry($i, "virt", false, false,
- false, $link);
- }
-
- if (get_pref($link, 'ENABLE_FEED_CATS')) {
- print "</ul>";
- }
-
-
- $result = db_query($link, "SELECT id,caption FROM
- ttrss_labels2 WHERE owner_uid = '$owner_uid' ORDER by caption");
-
- if (db_num_rows($result) > 0) {
- if (get_pref($link, 'ENABLE_FEED_CATS')) {
-
- $collapsed = get_pref($link, "_COLLAPSED_LABELS");
-
- if ($collapsed == "t" || $collapsed == "1") {
- $holder_class = "invisible";
- $ellipsis = "...";
- } else {
- $holder_class = "feedCatHolder";
- $ellipsis = "";
- }
-
- $tmp_category = __("Labels");
-
- print "<li class=\"feedCat\">
- <a href=\"?subop=tc&id=-2\">$tmp_category</a>$ellipsis
- </li>";
-
- print "<li class=\"$holder_class\"><ul class=\"feedCatList\">";
- } else {
-// print "<li><hr></li>";
- }
- }
-
- while ($line = db_fetch_assoc($result)) {
-
- $count = getFeedUnread($link, -$line["id"]-11);
-
- $class = "label";
-
- printMobileFeedEntry(-$line["id"]-11,
- $class, $line["caption"], $count, false, $link);
-
- }
-
- if (db_num_rows($result) > 0) {
- if (get_pref($link, 'ENABLE_FEED_CATS')) {
- print "</ul>";
- }
- }
-
-
- if (get_pref($link, 'ENABLE_FEED_CATS')) {
- $order_by_qpart = "category,title";
- } else {
- $order_by_qpart = "title";
- }
-
- $result = db_query($link, "SELECT ttrss_feeds.*,
- ".SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated_noms,
- (SELECT COUNT(id) FROM ttrss_entries,ttrss_user_entries
- WHERE feed_id = ttrss_feeds.id AND
- ttrss_user_entries.ref_id = ttrss_entries.id AND
- owner_uid = '$owner_uid') AS total,
- (SELECT COUNT(id) FROM ttrss_entries,ttrss_user_entries
- WHERE feed_id = ttrss_feeds.id AND unread = true
- AND ttrss_user_entries.ref_id = ttrss_entries.id
- AND owner_uid = '$owner_uid') as unread,
- cat_id,last_error,
- ttrss_feed_categories.title AS category,
- ttrss_feed_categories.collapsed
- FROM ttrss_feeds LEFT JOIN ttrss_feed_categories
- ON (ttrss_feed_categories.id = cat_id)
- WHERE
- ttrss_feeds.owner_uid = '$owner_uid'
- ORDER BY $order_by_qpart");
-
- $actid = $_GET["actid"];
-
- /* real feeds */
-
- $lnum = 0;
-
- $category = "";
-
- while ($line = db_fetch_assoc($result)) {
- if (get_pref($link, 'HIDE_READ_FEEDS') && (int)$line['unread']==0) {
- continue;
- }
-
- $feed = db_unescape_string($line["title"]);
- $feed_id = $line["id"];
-
- $subop = $_GET["subop"];
-
- $total = $line["total"];
- $unread = $line["unread"];
-
- $rtl_content = sql_bool_to_bool($line["rtl_content"]);
-
- if ($rtl_content) {
- $rtl_tag = "dir=\"RTL\"";
- } else {
- $rtl_tag = "";
- }
-
- $cat_id = $line["cat_id"];
-
- $tmp_category = $line["category"];
-
- if (!$tmp_category) {
- $tmp_category = "Uncategorized";
- }
-
- // $class = ($lnum % 2) ? "even" : "odd";
-
- if ($line["last_error"]) {
- $class = "error";
- } else {
- $class = "feed";
- }
-
- if ($category != $tmp_category && get_pref($link, 'ENABLE_FEED_CATS')) {
-
- if ($category) {
- print "</ul></li>";
- }
-
- $category = $tmp_category;
-
- $collapsed = $line["collapsed"];
-
- // workaround for NULL category
- if ($category == "Uncategorized") {
- $collapsed = get_pref($link, "_COLLAPSED_UNCAT");
- }
-
- if ($collapsed == "t" || $collapsed == "1") {
- $holder_class = "invisible";
- $ellipsis = "...";
- } else {
- $holder_class = "feedCatHolder";
- $ellipsis = "";
- }
-
- if ($cat_id) {
- $cat_id_qpart = "cat_id = '$cat_id'";
- } else {
- $cat_id_qpart = "cat_id IS NULL";
- }
-
- $cat_id = sprintf("%d", $cat_id);
- $cat_unread = getCategoryUnread($link, $cat_id);
-
- if ($cat_unread > 0) {
- $catctr_class = "";
- } else {
- $catctr_class = "invisible";
- }
-
- print "<li class=\"feedCat\">
- <a href=\"?subop=tc&id=$cat_id\">$tmp_category</a>
- <a href=\"?go=vf&id=$cat_id&cat=true\">
- <span class=\"$catctr_class\">($cat_unread)$ellipsis</span>
- </a></li>";
-
- print "<li id=\"feedCatHolder\" class=\"$holder_class\">
- <ul class=\"feedCatList\">";
- }
-
- printMobileFeedEntry($feed_id, $class, $feed, $unread,
- false, $link, $rtl_content);
-
- ++$lnum;
- }
-
- } else {
- // tags
-
- $result = db_query($link, "SELECT tag_name,SUM((SELECT COUNT(int_id)
- FROM ttrss_user_entries WHERE int_id = post_int_id
- AND unread = true)) AS count FROM ttrss_tags
- WHERE owner_uid = '".$_SESSION['uid']."' GROUP BY tag_name ORDER BY tag_name");
-
- $tags = array();
-
- while ($line = db_fetch_assoc($result)) {
- $tags[$line["tag_name"]] += $line["count"];
- }
-
- foreach (array_keys($tags) as $tag) {
-
- $unread = $tags[$tag];
-
- $class = "tag";
-
- printMobileFeedEntry($tag, $class, $tag, $unread,
- "../images/tag.png", $link);
-
- }
-
-
- }
- }
-
- function printMobileFeedEntry($feed_id, $class, $feed_title, $unread, $icon_file, $link,
- $rtl_content = false) {
-
- if (!$feed_title) $feed_title = getFeedTitle($link, $feed_id, false);
- if (!$unread) $unread = getFeedUnread($link, $feed_id);
-
- if ($unread > 0) $class .= "Unread";
-
- if (!$icon_file) $icon_file = "../../" . getFeedIcon($feed_id);
-
- if (file_exists($icon_file) && filesize($icon_file) > 0) {
- $feed_icon = "<img src=\"$icon_file\">";
- } else {
- $feed_icon = "<img src=\"../../images/blank_icon.gif\">";
- }
-
- if ($rtl_content) {
- $rtl_tag = "dir=\"rtl\"";
- } else {
- $rtl_tag = "dir=\"ltr\"";
- }
-
- $feed = "<a href=\"?go=vf&id=$feed_id\">$feed_title</a>";
-
- print "<li class=\"$class\">";
- print "$feed_icon";
- print "<span $rtl_tag>$feed</span> ";
-
- if ($unread != 0) {
- print "<span $rtl_tag>($unread)</span>";
- }
-
- print "</li>";
-
- }
-
- function render_headlines($link) {
-
- $feed = db_escape_string($_GET["id"]);
- $limit = db_escape_string($_GET["limit"]);
- $view_mode = db_escape_string($_GET["viewmode"]);
- $cat_view = db_escape_string($_GET["cat"]);
- $subop = $_GET["subop"];
- $catchup_op = $_GET["catchup_op"];
-
- if (!$view_mode) {
- if ($_SESSION["mobile:viewmode"]) {
- $view_mode = $_SESSION["mobile:viewmode"];
- } else {
- $view_mode = "adaptive";
- }
- }
-
- $_SESSION["mobile:viewmode"] = $view_mode;
-
- if (!$limit) $limit = 30;
- if (!$feed) $feed = 0;
-
- if (preg_match("/^-?[0-9][0-9]*$/", $feed) != false) {
-
- $result = db_query($link, "SELECT rtl_content FROM ttrss_feeds
- WHERE id = '$feed' AND owner_uid = " . $_SESSION["uid"]);
-
- if (db_num_rows($result) == 1) {
- $rtl_content = sql_bool_to_bool(db_fetch_result($result, 0, "rtl_content"));
- } else {
- $rtl_content = false;
- }
-
- if ($rtl_content) {
- $rtl_tag = "dir=\"RTL\"";
- } else {
- $rtl_tag = "";
- }
- } else {
- $rtl_content = false;
- $rtl_tag = "";
- }
-
- print "<div id=\"headlines\" $rtl_tag>";
-
- if ($subop == "ForceUpdate" && sprintf("%d", $feed) > 0) {
- update_generic_feed($link, $feed, $cat_view, true);
- }
-
- if ($subop == "MarkAllRead" || $catchup_op == "feed") {
- catchup_feed($link, $feed, $cat_view);
- }
-
- if ($catchup_op == "selection") {
- if (is_array($_GET["sel_ids"])) {
- $ids_to_mark = array_keys($_GET["sel_ids"]);
- if ($ids_to_mark) {
- foreach ($ids_to_mark as $id) {
- db_query($link, "UPDATE ttrss_user_entries SET
- unread = false,last_read = NOW()
- WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
- }
- }
- }
- }
-
- if ($subop == "MarkPageRead" || $catchup_op == "page") {
- $ids_to_mark = $_SESSION["last_page_ids.$feed"];
-
- if ($ids_to_mark) {
-
- foreach ($ids_to_mark as $id) {
- db_query($link, "UPDATE ttrss_user_entries SET
- unread = false,last_read = NOW()
- WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
- }
- }
- }
-
-
- /// START /////////////////////////////////////////////////////////////////////////////////
-
- $search = db_escape_string($_GET["query"]);
- $search_mode = db_escape_string($_GET["search_mode"]);
- $match_on = db_escape_string($_GET["match_on"]);
-
- if (!$match_on) {
- $match_on = "both";
- }
-
- $real_offset = $offset * $limit;
-
- if ($_GET["debug"]) $timing_info = print_checkpoint("H0", $timing_info);
-
- $qfh_ret = queryFeedHeadlines($link, $feed, $limit, $view_mode, $cat_view,
- $search, $search_mode, $match_on, false, $real_offset);
-
- if ($_GET["debug"]) $timing_info = print_checkpoint("H1", $timing_info);
-
- $result = $qfh_ret[0];
- $feed_title = $qfh_ret[1];
- $feed_site_url = $qfh_ret[2];
- $last_error = $qfh_ret[3];
-
- /// STOP //////////////////////////////////////////////////////////////////////////////////
-
- if (!$result) {
- print "<div align='center'>".
- __("Could not display feed (query failed). Please check label match syntax or local configuration.").
- "</div>";
- return;
- }
-
- print "<div id=\"heading\">";
- # if (!$cat_view && file_exists("../icons/$feed.ico") && filesize("../icons/$feed.ico") > 0) {
- # print "<img class=\"feedIcon\" src=\"../icons/$feed.ico\">";
- # }
-
- print "$feed_title <span id=\"headingAddon\">(";
- print "<a href=\"index.php\">".__("Back")."</a>, ";
- print "<a href=\"index.php?go=sform&aid=$feed&ic=$cat_view\">".__("Search")."</a>, ";
- print "<a href=\"index.php?go=vf&id=$feed&subop=ForceUpdate\">".__("Update")."</a>";
-
-# print "Mark as read: ";
-# print "<a href=\"index.php?go=vf&id=$feed&subop=MarkAsRead\">Page</a>, ";
-# print "<a href=\"index.php?go=vf&id=$feed&subop=MarkAllRead\">Feed</a>";
-
- print ")</span>";
-
- print " " . __('View:');
-
- print "<form style=\"display : inline\" method=\"GET\" action=\"index.php\">";
-
- /* print "<select name=\"viewmode\">
- <option selected value=\"adaptive\"> " . __('Adaptive') . "</option>
- <option value=\"all_articles\">" . __('All Articles') . "</option>
- <option value=\"marked\">" . __('Starred') . "</option>
- <option value=\"unread\">" . __('Unread') . "</option>
- </select>"; */
-
- $sel_values = array(
- "adaptive" => __("Adaptive"),
- "all_articles" => __("All Articles"),
- "unread" => __("Unread"),
- "marked" => __("Starred"));
-
- print_select_hash("viewmode", $view_mode, $sel_values);
-
- print "<input type=\"hidden\" name=\"id\" value=\"$feed\">
- <input type=\"hidden\" name=\"cat\" value=\"$cat_view\">
- <input type=\"hidden\" name=\"go\" value=\"vf\">
- <input type=\"submit\" value=\"".__('Refresh')."\">";
- print "</form>";
-
- print "</div>";
-
- if (db_num_rows($result) > 0) {
-
- print "<form method=\"GET\" action=\"index.php\">";
- print "<input type=\"hidden\" name=\"go\" value=\"vf\">";
- print "<input type=\"hidden\" name=\"id\" value=\"$feed\">";
- print "<input type=\"hidden\" name=\"cat\" value=\"$cat_view\">";
-
- print "<ul class=\"headlines\" id=\"headlines\">";
-
- $page_art_ids = array();
-
- $lnum = 0;
-
- error_reporting (DEFAULT_ERROR_LEVEL);
-
- $num_unread = 0;
-
- while ($line = db_fetch_assoc($result)) {
-
- $class = ($lnum % 2) ? "even" : "odd";
-
- $id = $line["id"];
- $feed_id = $line["feed_id"];
-
- array_push($page_art_ids, $id);
-
- if ($line["last_read"] == "" &&
- ($line["unread"] != "t" && $line["unread"] != "1")) {
-
- $update_pic = "<img id='FUPDPIC-$id' src=\"images/updated.png\"
- alt=\"".__("Updated")."\">";
- } else {
- $update_pic = "<img id='FUPDPIC-$id' src=\"images/blank_icon.gif\"
- alt=\"".__("Updated")."\">";
- }
-
- if ($line["unread"] == "t" || $line["unread"] == "1") {
- $class .= "Unread";
- ++$num_unread;
- $is_unread = true;
- } else {
- $is_unread = false;
- }
-
- if ($line["marked"] == "t" || $line["marked"] == "1") {
- $marked_pic = "<img alt=\"S\" class='marked' src=\"../../images/mark_set.png\">";
- } else {
- $marked_pic = "<img alt=\"s\" class='marked' src=\"../../images/mark_unset.png\">";
- }
-
- if ($line["published"] == "t" || $line["published"] == "1") {
- $published_pic = "<img alt=\"P\" class='marked' src=\"../../images/pub_set.gif\">";
- } else {
- $published_pic = "<img alt=\"p\" class='marked' src=\"../../images/pub_unset.gif\">";
- }
-
- $content_link = "<a href=\"?go=view&id=$id&cat=$cat_view&ret_feed=$feed&feed=$feed_id\">" .
- $line["title"] . "</a>";
-
- $updated_fmt = make_local_datetime($link, $line['updated'], false);
-
- print "<li class='$class' id=\"HROW-$id\">";
-
- print "<input type=\"checkbox\" name=\"sel_ids[$id]\"
- id=\"HSCB-$id\" onchange=\"toggleSelectRow(this, $id)\">";
-
- print "<a href=\"?go=vf&id=$feed&ts=$id&cat=$cat_view\">$marked_pic</a>";
- print "<a href=\"?go=vf&id=$feed&tp=$id&cat=$cat_view\">$published_pic</a>";
-
- print $content_link;
-
- if ($line["feed_title"]) {
- print " (<a href='?go=vf&id=$feed_id'>".
- $line["feed_title"]."</a>)";
- }
-
- print "<span class='hlUpdated'> ($updated_fmt)</span>";
-
- print "</li>";
-
-
- ++$lnum;
- }
-
- print "</ul>";
-
- print "<div class='footerAddon'>";
-
- $_SESSION["last_page_ids.$feed"] = $page_art_ids;
-
-/* print "<a href=\"index.php?go=vf&id=$feed&subop=MarkPageRead\">Page</a>, ";
- print "<a href=\"index.php?go=vf&id=$feed&subop=MarkAllRead\">Feed</a></div>"; */
-
- print "Select:
- <a href=\"javascript:selectHeadlines(1)\">".__("All")."</a>,
- <a href=\"javascript:selectHeadlines(2)\">".__("Unread")."</a>,
- <a href=\"javascript:selectHeadlines(3)\">".__("None")."</a>,
- <a href=\"javascript:selectHeadlines(4)\">".__("Invert")."</a>";
-
- print " ";
-
- print "<select name=\"catchup_op\">
- <option value=\"selection\">".__("Selection")."</option>
- <option value=\"page\">".__("Page")."</option>
- <option value=\"feed\">".__("Entire feed")."</option>
- </select>
- <input type=\"hidden\" name=\"cat\" value=\"$cat_view\">
- <input type=\"submit\" value=\"".__("Mark as read")."\">";
-
- print "</form>";
-
- } else {
- print "<div align='center'>No articles found.</div>";
- }
-
- }
-
- function render_article($link) {
-
- $id = db_escape_string($_GET["id"]);
- $feed_id = db_escape_string($_GET["feed"]);
- $ret_feed_id = db_escape_string($_GET["ret_feed"]);
- $cat_view = db_escape_string($_GET["cat"]);
-
- $result = db_query($link, "SELECT rtl_content FROM ttrss_feeds
- WHERE id = '$feed_id' AND owner_uid = " . $_SESSION["uid"]);
-
- if (db_num_rows($result) == 1) {
- $rtl_content = sql_bool_to_bool(db_fetch_result($result, 0, "rtl_content"));
- } else {
- $rtl_content = false;
- }
-
- if ($rtl_content) {
- $rtl_tag = "dir=\"RTL\"";
- $rtl_class = "RTL";
- } else {
- $rtl_tag = "";
- $rtl_class = "";
- }
-
- $result = db_query($link, "UPDATE ttrss_user_entries
- SET unread = false,last_read = NOW()
- WHERE ref_id = '$id' AND feed_id = '$feed_id' AND owner_uid = " . $_SESSION["uid"]);
-
- $result = db_query($link, "SELECT title,link,content,feed_id,comments,int_id,
- marked,published,
- ".SUBSTRING_FOR_DATE."(updated,1,16) as updated,
- (SELECT icon_url FROM ttrss_feeds WHERE id = feed_id) as icon_url,
- num_comments,
- author
- FROM ttrss_entries,ttrss_user_entries
- WHERE id = '$id' AND ref_id = id");
-
- if ($result) {
-
- $line = db_fetch_assoc($result);
-
- $num_comments = $line["num_comments"];
- $entry_comments = "";
-
- if ($num_comments > 0) {
- if ($line["comments"]) {
- $comments_url = $line["comments"];
- } else {
- $comments_url = $line["link"];
- }
- $entry_comments = "<a href=\"$comments_url\">$num_comments comments</a>";
- } else {
- if ($line["comments"] && $line["link"] != $line["comments"]) {
- $entry_comments = "<a href=\"".$line["comments"]."\">comments</a>";
- }
- }
-
- $tmp_result = db_query($link, "SELECT DISTINCT tag_name FROM
- ttrss_tags WHERE post_int_id = " . $line["int_id"] . "
- ORDER BY tag_name");
-
- $tags_str = "";
- $f_tags_str = "";
-
- $num_tags = 0;
-
- while ($tmp_line = db_fetch_assoc($tmp_result)) {
- $num_tags++;
- $tag = $tmp_line["tag_name"];
- $tag_str = "<a href=\"?go=vf&id=$tag\">$tag</a>, ";
- $tags_str .= $tag_str;
- }
-
- $tags_str = preg_replace("/, $/", "", $tags_str);
-
- $parsed_updated = date(get_pref($link, 'SHORT_DATE_FORMAT'),
- strtotime($line["updated"]));
-
- print "<div id=\"heading\">";
-
- # if (file_exists("../icons/$feed_id.ico") && filesize("../icons/$feed_id.ico") > 0) {
- # print "<img class=\"feedIcon\" src=\"../icons/$feed_id.ico\">";
- # }
-
- if (!$cat_view) {
- $feed_title = getFeedTitle($link, $ret_feed_id);
- } else {
- $feed_title = getCategoryTitle($link, $ret_feed_id);
- $feed_title_native = getFeedTitle($link, $feed_id);
- }
-
- if ($feed_title_native) {
- $feed_link = "<a href=\"index.php?go=vf&id=$feed_id\">$feed_title_native</a>";
- $feed_link .= " in <a href=\"index.php?go=vf&id=$ret_feed_id&cat=$cat_view\">
- $feed_title</a>";
- } else {
- $feed_link = "<a href=\"index.php?go=vf&id=$ret_feed_id\">$feed_title</a>";
- }
-
- $feedlist = "<a href=\"index.php\">".__('Back to feedlist')."</a>";
-
- print "<a href=\"" . $line["link"] . "\">" .
- truncate_string($line["title"], 30) . "</a>";
- print " <span id=\"headingAddon\">$parsed_updated ($feed_link, $feedlist)</span>";
- print "</div>";
-
- if ($num_tags > 0) {
- print "<div class=\"postTags\">".__("Tags:")." $tags_str</div>";
- }
-
- if ($line["marked"] == "t" || $line["marked"] == "1") {
- $marked_pic = "<img class='marked' src=\"../../images/mark_set.png\">";
- } else {
- $marked_pic = "<img class='marked' src=\"../../images/mark_unset.png\">";
- }
-
- if ($line["published"] == "t" || $line["published"] == "1") {
- $published_pic = "<img class='marked' src=\"../../images/pub_set.gif\">";
- } else {
- $published_pic = "<img class='marked' src=\"../../images/pub_unset.gif\">";
- }
-
-
- print "<div class=\"postStarOps\">";
- print "<a title=\"".__('Toggle starred')."\"href=\"?go=view&id=$id&ret_feed=$ret_feed_id&feed=$feed_id&sop=ts\">$marked_pic</a>";
- print "<a title=\"".__('Toggle published')."\" href=\"?go=view&id=$id&ret_feed=$ret_feed_id&feed=$feed_id&sop=tp\">$published_pic</a>";
- // Mark unread
- print "<a title=\"".__('Mark as unread')."\" href=\"?go=vf&id=$ret_feed_id&feed=$feed_id&sop=mu&aid=$id";
- if ($cat_view) { print "&cat=$cat_view"; }
- print "\"><img class='marked' src=\"../../images/art-set-unread.png\"></a>";
- print "</div>";
-
- print sanitize_rss($link, $line["content"], true);;
-
- }
-
- print "</body></html>";
- }
-
- function render_search_form($link, $active_feed_id = false, $is_cat = false) {
-
- print "<div id=\"heading\">";
-
- print __("Search")." <span id=\"headingAddon\">
- (<a href=\"index.php\">".__("Go back")."</a>)</span></div>";
-
- print "<form method=\"GET\" action=\"index.php\" class=\"searchForm\">";
-
- print "<input type=\"hidden\" name=\"go\" value=\"vf\">";
- print "<input type=\"hidden\" name=\"id\" value=\"$active_feed_id\">";
- print "<input type=\"hidden\" name=\"cat\" value=\"$is_cat\">";
-
- print "<table><tr><td>".__('Search:')."</td><td>";
- print "<input name=\"query\"></td></tr>";
-
- print "<tr><td>".__('Where:')."</td><td>";
-
- print "<select name=\"search_mode\">
- <option value=\"all_feeds\">".__('All feeds')."</option>";
-
- $feed_title = getFeedTitle($link, $active_feed_id);
-
- if (!$is_cat) {
- $feed_cat_title = getFeedCatTitle($link, $active_feed_id);
- } else {
- $feed_cat_title = getCategoryTitle($link, $active_feed_id);
- }
-
- if ($active_feed_id && !$is_cat) {
- print "<option selected value=\"this_feed\">$feed_title</option>";
- } else {
- print "<option disabled>".__('This feed')."</option>";
- }
-
- if ($is_cat) {
- $cat_preselected = "selected";
- }
-
- if (get_pref($link, 'ENABLE_FEED_CATS') && ($active_feed_id > 0 || $is_cat)) {
- print "<option $cat_preselected value=\"this_cat\">$feed_cat_title</option>";
- } else {
- //print "<option disabled>".__('This category')."</option>";
- }
-
- print "</select></td></tr>";
-
- print "<tr><td>".__('Match on:')."</td><td>";
-
- $search_fields = array(
- "title" => __("Title"),
- "content" => __("Content"),
- "both" => __("Title or content"));
-
- print_select_hash("match_on", 3, $search_fields);
-
- print "</td></tr></table>";
-
- print "<input type=\"submit\" value=\"".__('Search')."\">";
-
- print "</form>";
-
- print "</div>";
- }
-
- function toggleMarked($link, $ts_id) {
- $result = db_query($link, "UPDATE ttrss_user_entries SET marked = NOT marked
- WHERE ref_id = '$ts_id' AND owner_uid = " . $_SESSION["uid"]);
- }
-
- function togglePublished($link, $tp_id) {
- $result = db_query($link, "UPDATE ttrss_user_entries SET published = NOT published
- WHERE ref_id = '$tp_id' AND owner_uid = " . $_SESSION["uid"]);
- }
-
- function markUnread($link, $mu_id) {
- $result = db_query($link, "UPDATE ttrss_user_entries SET unread = true
- WHERE ref_id = '$mu_id' AND owner_uid = " . $_SESSION["uid"]);
- }
-
-?>
+++ /dev/null
-<?php
- error_reporting(E_ERROR | E_WARNING | E_PARSE);
-
- define('MOBILE_VERSION', true);
-
- require_once "../../config.php";
- require_once "functions.php";
- require_once "../../functions.php";
-
- require_once "../../sessions.php";
-
- require_once "../../version.php";
- require_once "../../db-prefs.php";
-
- $link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
-
- init_connection($link);
-
- login_sequence($link, 2);
-
- /* perform various redirect-needing subops */
-
- $subop = db_escape_string($_GET["subop"]);
- $go = $_GET["go"];
-
- if ($subop == "tc" && !$go) {
-
- $cat_id = db_escape_string($_GET["id"]);
- toggle_collapse_cat($link, $cat_id);
-
- header("Location: index.php");
- return;
- }
-
- $ts_id = db_escape_string($_GET["ts"]);
-
- if ($go == "vf" && $ts_id) {
-
- toggleMarked($link, $ts_id);
-
- $query_string = preg_replace("/&ts=[0-9]*/", "", $_SERVER["QUERY_STRING"]);
- header("Location: index.php?$query_string");
- return;
- }
-
- $tp_id = db_escape_string($_GET["tp"]);
-
- if ($go == "vf" && $tp_id) {
-
- togglePublished($link, $tp_id);
-
- $query_string = preg_replace("/&tp=[0-9]*/", "", $_SERVER["QUERY_STRING"]);
- header("Location: index.php?$query_string");
- return;
- }
-
- $sop = db_escape_string($_GET["sop"]);
-
- if ($sop) {
- if ($go == "view") {
- $a_id = db_escape_string($_GET["id"]);
- } elseif ($go == "vf") {
- $a_id = db_escape_string($_GET["aid"]);
- }
-
- if ($a_id) {
-
- if ($sop == "tp") {
- togglePublished($link, $a_id);
- }
-
- if ($sop == "ts") {
- toggleMarked($link, $a_id);
- }
-
- if ($sop == "mu") {
- markUnread($link, $a_id);
- }
-
- $query_string = str_replace("&sop=$sop", "", $_SERVER["QUERY_STRING"]);
- header("Location: index.php?$query_string");
- }
- }
-
-?>
-<html>
-<head>
- <title>Tiny Tiny RSS</title>
- <link rel="stylesheet" type="text/css" href="mobile.css">
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <script type="text/javascript" src="mobile.js"></script>
- <?php print_user_stylesheet($link) ?>
-</head>
-<body id="ttrssMobile">
-
-<div id="content">
-<?php
- if (!$go) {
- render_feeds_list($link);
- } else if ($go == "vf") {
- render_headlines($link);
- } else if ($go == "view") {
- render_article($link);
- } else if ($go == "sform") {
- render_search_form($link, $_GET["aid"], $_GET["ic"]);
- } else {
- print __("Internal error: Function not implemented");
- }
-
-?>
-</div>
-
-</body>
-</html>
+++ /dev/null
-<html>
-<head>
- <title>Tiny Tiny RSS : Login</title>
- <link rel="stylesheet" type="text/css" href="mobile.css">
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <script type="text/javascript" charset="utf-8" src="mobile.js"></script>
-</head>
-
-<script type="text/javascript">
-function init() {
-
- if (arguments.callee.done) return;
- arguments.callee.done = true;
-
- var login = document.forms["loginForm"].login;
- var click = document.forms["loginForm"].click;
-
- login.focus();
- click.disabled = false;
-
-}
-function languageChange(elem) {
- try {
- document.forms['loginForm']['click'].disabled = true;
-
- var lang = elem[elem.selectedIndex].value;
- setCookie("ttrss_lang", lang, <?php print SESSION_COOKIE_LIFETIME ?>);
- window.location.reload();
- } catch (e) {
- exception_error("languageChange", e);
- }
-}
-
-</script>
-
-<script type="text/javascript">
-if (document.addEventListener) {
- document.addEventListener("DOMContentLoaded", init, null);
-}
-window.onload = init;
-</script>
-
-
-<body>
-
- <div id="content">
- <div id="heading">Tiny Tiny RSS</div>
-
- <form action="index.php" method="POST" name="loginForm">
- <input type="hidden" name="rt" value="<?php echo $_GET['rt'] ?>">
- <input type="hidden" name="login_action" value="do_login">
-
- <?php if ($_SESSION['login_error_msg']) { ?>
- <div class="loginError"><?php echo $_SESSION['login_error_msg'] ?></div>
- <?php $_SESSION['login_error_msg'] = ""; ?>
- <?php } ?>
-
- <table>
- <tr><td align='right'><?php echo __("Login:") ?></td><td><input type="text" name="login"></td>
- <tr><td align='right'><?php echo __("Password:") ?></td><td><input type="password" name="password"></tr>
-
- <tr><td align="right"><?php echo __("Language:") ?></td>
- <td>
- <?php
- print_select_hash("language", $_COOKIE["ttrss_lang"], get_translations(),
- "style='width : 100%' onchange='languageChange(this)'");
-
- ?>
- </td></tr>
- <tr><td colspan='2'>
- <input type="submit" class="button" value="<?php echo __('Log in') ?>" name="click">
- </td></tr>
- </table>
- </form>
- </div>
-
-</body>
-</html>
-
+++ /dev/null
-<?php
- require_once "functions.php";
- require_once "../../sessions.php";
- require_once "../../functions.php";
-
- logout_user();
-
- header("Location: index.php");
-?>
+++ /dev/null
-body {
- padding : 0px;
- margin : 0px;
- font-family : sans-serif;
-}
-
-h1 {
- font-size : medium;
-}
-
-h2 {
- font-size : medium;
- font-weight : bold;
- border-width : 0px 0px 1px 0px;
- border-style : solid;
- border-color : #88b0ff;
-}
-
-h3 {
- font-size : medium;
- font-weight : bold;
- border-width : 0px 0px 1px 0px;
- border-style : solid;
- border-color : #e0e0e0;
-}
-
-#heading {
- font-size : small;
-
- border-width : 0px 0px 1px 0px;
- border-style : solid;
- border-color : #f0f0f0;
-
- color : #88b0ff;
- font-weight : bold;
-}
-
-#content {
- background : white;
-}
-
-#footer {
- font-size : x-small;
- color : gray;
- margin-top : 5px;
-}
-
-form {
- padding : 0px;
- margin : 0px;
-}
-
-li.feedCatHolder {
- display : inline;
-}
-
-ul.feedList {
- list-style-type : none;
- margin : 0px;
- padding : 0px;
-
-}
-
-ul.feedList li.feedCat {
- margin : 0px;
- padding : 0px;
- color : #707070;
-}
-
-ul.feedList li.feedCat a {
- color : #707070;
-}
-
-ul.feedList li.feedCat a:hover {
- color : #4684ff;
-}
-
-ul.feedCatList {
- list-style-type : none;
- margin : 0px 0px 0px 1em;
- padding : 0px;
-}
-
-ul.feedCatList li {
- margin : 0px;
- padding : 0px;
- color : black;
-}
-
-ul.feedList li {
- margin : 0px;
-}
-
-hr {
- border-width : 0px 0px 1px 0px;
- border-style : dashed;
- border-color : #e0e0e0;
-}
-
-ul.headlines a, ul.feedList a {
- color : black;
-}
-
-a {
- color : #4684ff;
- text-decoration : none;
-}
-
-a:hover {
- color : black;
-}
-
-ul.feedList img, img.tinyFeedIcon {
- margin : 0px 3px 0px 0px;
- width : 16px;
- height : 16px;
- border-width : 0px;
-}
-
-ul.feedlist li.feedUnread,
-ul.feedlist li.errorUnread,
-ul.feedlist li.labelUnread,
-ul.feedlist li.virtUnread,
-ul.feedlist li.tagUnread {
- font-weight : bold;
-}
-
-.even {
-/* background-color : #9bbdff; */
- border-width : 0px 0px 1px 0px;
- border-color : #88b0ff;
- border-style : solid;
- background-color : #cbddff;
-}
-
-.odd {
- border-width : 0px 0px 1px 0px;
- border-color : #88b0ff;
- border-style : solid;
-}
-
-.evenUnread {
- border-width : 0px 0px 1px 0px;
- border-color : #88b0ff;
- border-style : solid;
-/* background-color : #9bbdff; */
- font-weight : bold;
- background-color : #cbddff;
-}
-
-.oddUnread {
- border-width : 0px 0px 1px 0px;
- border-color : #88b0ff;
- border-style : solid;
- font-weight : bold;
-}
-
-.evenSelected, .oddSelected, .evenUnreadSelected, .oddUnreadSelected {
- background-color : #fff7d5;
- border-width : 0px 0px 1px 0px;
- border-color : #88b0ff;
- border-style : solid;
-}
-
-.evenUnreadSelected, .oddUnreadSelected {
- font-weight : bold;
-}
-
-.invisible {
- display : none;
-}
-
-ul.headlines {
- list-style-type : none;
- margin : 0px;
- padding : 0px;
-}
-
-ul.headlines span.hlUpdated {
- color : gray;
-}
-
-ul.headlines img.feedIcon {
- width : 25px;
- text-align : center;
-}
-
-ul.headlines img.marked {
- border-width : 0px;
-}
-
-div.postStarOps img.marked {
- border-width : 0px;
-}
-
-div.postTags {
- color : gray;
- font-size : small;
-}
-
-div.footerAddon {
- font-size : small;
-}
-
-.loginError {
- color : red;
- margin : 0.5em;
-}
-
-form.searchForm {
- margin : 5px;
-}
-
-div.postStarOps {
- float : right;
-}
+++ /dev/null
-function toggleSelectRow(cb, id) {
- try {
-
- var row = document.getElementById("HROW-" + id);
- var checked = cb.checked;
- if (row) {
- var unread = row.className.match("Unread");
- var new_classname = row.className;
-
- new_classname = new_classname.replace("Selected", "");
- new_classname = new_classname.replace("Unread", "");
-
- if (unread) new_classname = new_classname + "Unread";
- if (checked) new_classname = new_classname + "Selected";
-
- row.className = new_classname;
- }
- } catch (e) {
- exception_error("toggleSelectRow", e);
- }
-}
-
-function selectHeadlines(mode) {
- try {
-
- var cboxes = document.getElementsByTagName("INPUT");
-
- for (var i = 0; i < cboxes.length; i++) {
- if (cboxes[i].id && cboxes[i].id.match("HSCB-")) {
- var row_id = cboxes[i].id.replace("HSCB-", "")
- var row = document.getElementById("HROW-" + row_id);
-
- if (row) {
-
- if (mode == 1) {
- cboxes[i].checked = true;
- toggleSelectRow(cboxes[i], row_id);
- }
-
- if (mode == 2) {
-
- var unread = row.className.match("Unread");
-
- if (unread) {
- cboxes[i].checked = true;
- } else {
- cboxes[i].checked = false;
- }
- }
-
- if (mode == 3) {
- cboxes[i].checked = false;
- }
-
- if (mode == 4) {
- cboxes[i].checked = !cboxes[i].checked;
- }
-
- toggleSelectRow(cboxes[i], row_id);
-
- }
-
- }
-
- }
-
- } catch (e) {
- exception_error("selectHeadlines", e);
- }
-}
-
-function exception_error(location, e, silent) {
- var msg;
-
- if (e.fileName) {
- var base_fname = e.fileName.substring(e.fileName.lastIndexOf("/") + 1);
-
- msg = "Exception: " + e.name + ", " + e.message +
- "\nFunction: " + location + "()" +
- "\nLocation: " + base_fname + ":" + e.lineNumber;
-
- } else if (e.description) {
- msg = "Exception: " + e.description + "\nFunction: " + location + "()";
- } else {
- msg = "Exception: " + e + "\nFunction: " + location + "()";
- }
-
- debug("<b>EXCEPTION: " + msg + "</b>");
-
- if (!silent) {
- alert(msg);
- }
-}
-
define('MOBILE_VERSION', true);
require_once "../config.php";
- require_once "functions.php";
- require_once "../functions.php";
-
- require_once "../sessions.php";
-
- require_once "../version.php";
- require_once "../db-prefs.php";
+ require_once "mobile-functions.php";
$link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
+++ /dev/null
-<?php
- define('TTRSS_SESSION_NAME', 'ttrss_m_sid');
-
- /* TODO replace with interface to db-prefs */
-
- function mobile_pref_toggled($link, $id) {
- if (get_pref($link, "_MOBILE_$id"))
- return "true";
- else
- return "";
- }
-
- function mobile_get_pref($link, $id) {
- //return $_SESSION["mobile-prefs"][$id];
- return get_pref($link, "_MOBILE_$id");
- }
-
- function mobile_set_pref($link, $id, $value) {
- //$_SESSION["mobile-prefs"][$id] = $value;
- return set_pref($link, "_MOBILE_$id", $value);
- }
-
- function mobile_feed_has_icon($id) {
- $filename = "../".ICONS_DIR."/$id.ico";
-
- return file_exists($filename) && filesize($filename) > 0;
- }
-
- function render_flat_feed_list($link, $offset) {
- $owner_uid = $_SESSION["uid"];
- $limit = 0;
-
- if (!$offset) $offset = 0;
-
- if (mobile_get_pref($link, "SORT_FEEDS_UNREAD")) {
- $order_by = "unread DESC, title";
- } else {
- $order_by = "title";
- }
-
- if ($limit > 0) {
- $limit_qpart = "LIMIT $limit OFFSET $offset";
- } else {
- $limit_qpart = "";
- }
-
- $result = db_query($link, "SELECT id,
- title,
- (SELECT COUNT(id) FROM ttrss_entries,ttrss_user_entries
- WHERE feed_id = ttrss_feeds.id AND unread = true
- AND ttrss_user_entries.ref_id = ttrss_entries.id
- AND owner_uid = '$owner_uid') AS unread
- FROM ttrss_feeds
- WHERE
- ttrss_feeds.owner_uid = '$owner_uid'
- ORDER BY $order_by $limit_qpart");
-
- if (!$offset) print '<ul id="home" title="'.__('Home').'" selected="true"
- myBackLabel="'.__('Logout').'" myBackHref="logout.php" myBackTarget="_self">';
-
-
- // print "<li><a href='#cat-actions'>".__('Actions...')."</a></li>";
-
- $num_feeds = 0;
-
- while ($line = db_fetch_assoc($result)) {
- $id = $line["id"];
- $unread = $line["unread"];
-
- // $unread = rand(0, 100);
-
- if ($unread > 0) {
- $line["title"] = $line["title"] . " ($unread)";
- $class = '';
- } else {
- $class = 'oldItem';
- }
-
- if (mobile_feed_has_icon($id)) {
- $icon_url = "../".ICONS_URL."/$id.ico";
- } else {
- $icon_url = "../images/blank_icon.gif";
- }
-
- if ($unread > 0 || !mobile_get_pref($link, "HIDE_READ")) {
- print "<li class='$class'><a href='feed.php?id=$id'>" .
- "<img class='tinyIcon' src='$icon_url'/>".
- $line["title"] . "</a></li>";
- }
-
- ++$num_feeds;
- }
-
-/* $next_offset = $offset + $num_feeds;
-
- print "<li><a href=\"home.php?skip=$next_offset\"
- target=\"_replace\">Show more feeds...</a></li>"; */
-
- if (!$offset) print "</ul>";
-
- }
-
- function render_category($link, $cat_id, $offset) {
- $owner_uid = $_SESSION["uid"];
-
- if ($cat_id >= 0) {
-
- if ($cat_id != 0) {
- $cat_query = "cat_id = '$cat_id'";
- } else {
- $cat_query = "cat_id IS NULL";
- }
-
- if (mobile_get_pref($link, "SORT_FEEDS_UNREAD")) {
- $order_by = "unread DESC, title";
- } else {
- $order_by = "title";
- }
-
- $result = db_query($link, "SELECT id,
- title,
- (SELECT COUNT(id) FROM ttrss_entries,ttrss_user_entries
- WHERE feed_id = ttrss_feeds.id AND unread = true
- AND ttrss_user_entries.ref_id = ttrss_entries.id
- AND owner_uid = '$owner_uid') as unread
- FROM ttrss_feeds
- WHERE
- ttrss_feeds.owner_uid = '$owner_uid' AND
- $cat_query
- ORDER BY $order_by");
-
- $title = getCategoryTitle($link, $cat_id);
-
- print "<ul id='cat-$cat_id' title='$title' myBackLabel='".__("Home")."'
- myBackHref='home.php'>";
-
- // print "<li><a href='#cat-actions'>".__('Actions...')."</a></li>";
-
- while ($line = db_fetch_assoc($result)) {
- $id = $line["id"];
- $unread = $line["unread"];
-
- // $unread = rand(0, 100);
-
- if ($unread > 0) {
- $line["title"] = $line["title"] . " ($unread)";
- $class = '';
- } else {
- $class = 'oldItem';
- }
-
- if (mobile_feed_has_icon($id)) {
- $icon_url = "../".ICONS_URL."/$id.ico";
- } else {
- $icon_url = "../images/blank_icon.gif";
- }
-
- if ($unread > 0 || !mobile_get_pref($link, "HIDE_READ")) {
- print "<li class='$class'><a href='feed.php?id=$id&cat=$cat_id'>" .
- "<img class='tinyIcon' src='$icon_url'/>".
- $line["title"] . "</a></li>";
- }
- }
-
- print "</ul>";
- } else if ($cat_id == -1) {
-
- $title = __('Special');
-
- print "<ul id='cat--1' title='$title' myBackLabel='".__("Home")."'
- myBackHref='home.php'>";
-
- foreach (array(-4, -3, -1, -2, 0) as $id) {
- $title = getFeedTitle($link, $id);
- $unread = getFeedUnread($link, $id, false);
- $icon = getFeedIcon($id);
-
- if ($unread > 0) {
- $title = $title . " ($unread)";
- $class = '';
- } else {
- $class = 'oldItem';
- }
-
- if ($unread > 0 || !mobile_get_pref($link, "HIDE_READ")) {
- print "<li class='$class'>
- <a href='feed.php?id=$id&cat=-1'>
- <img class='tinyIcon' src='../$icon'/>$title</a></li>";
- }
- }
-
- print "</ul>";
- } else if ($cat_id == -2) {
-
- $title = __('Labels');
-
- print "<ul id='cat--2' title='$title' myBackLabel='".__("Home")."'
- myBackHref='home.php'>";
-
- $result = db_query($link, "SELECT id, caption FROM ttrss_labels2
- WHERE owner_uid = '$owner_uid'");
-
- $label_data = array();
-
- while ($line = db_fetch_assoc($result)) {
-
- $id = -$line["id"] - 11;
-
- $unread = getFeedUnread($link, $id);
- $title = $line["caption"];
-
- if ($unread > 0) {
- $title = $title . " ($unread)";
- $class = '';
- } else {
- $class = 'oldItem';
- }
-
- if ($unread > 0 || !mobile_get_pref($link, "HIDE_READ")) {
- print "<li class='$class'>
- <a href='feed.php?id=$id&cat=-2'>$title</a></li>";
- }
- }
- print "</ul>";
- }
- }
-
- function render_categories_list($link) {
- $owner_uid = $_SESSION["uid"];
-
- $cat_browse = mobile_get_pref($link, "BROWSE_CATS");
-
- print '<ul id="home" title="'.__('Home').'" selected="true"
- myBackLabel="'.__('Logout').'" myBackHref="logout.php" myBackTarget="_self">';
-
-// print "<li><a href='#searchForm'>Search...</a></li>";
-
- foreach (array(-1, -2) as $id) {
- $title = getCategoryTitle($link, $id);
- $unread = getFeedUnread($link, $id, true);
- if ($unread > 0) {
- $title = $title . " ($unread)";
- $class = '';
- } else {
- $class = 'oldItem';
- }
-
- if ($cat_browse)
- print "<li class='$class'><a href='cat.php?id=$id'>$title</a></li>";
- else
- print "<li class='$class'><a href='feed.php?id=$id&is_cat=true'>$title</a></li>";
- }
-
- $result = db_query($link, "SELECT
- ttrss_feed_categories.id,
- ttrss_feed_categories.title,
- COUNT(ttrss_feeds.id) AS num_feeds
- FROM ttrss_feed_categories, ttrss_feeds
- WHERE ttrss_feed_categories.owner_uid = $owner_uid
- AND ttrss_feed_categories.id = cat_id
- GROUP BY ttrss_feed_categories.id,
- ttrss_feed_categories.title
- ORDER BY ttrss_feed_categories.title");
-
- while ($line = db_fetch_assoc($result)) {
-
- if ($line["num_feeds"] > 0) {
-
- $unread = getFeedUnread($link, $line["id"], true);
- $id = $line["id"];
-
- if ($unread > 0) {
- $line["title"] = $line["title"] . " ($unread)";
- $class = '';
- } else {
- $class = 'oldItem';
- }
-
- if ($unread > 0 || !mobile_get_pref($link, "HIDE_READ")) {
-
- if ($cat_browse)
- print "<li class='$class'><a href='cat.php?id=$id'>" .
- $line["title"] . "</a></li>";
- else
- print "<li class='$class'><a href='feed.php?id=$id&is_cat=true'>".
- $line["title"] . "</a></li>";
- }
- }
- }
-
-
- $result = db_query($link, "SELECT COUNT(*) AS nf FROM ttrss_feeds WHERE
- cat_id IS NULL and owner_uid = '$owner_uid'");
-
- $num_feeds = db_fetch_result($result, 0, "nf");
-
- if ($num_feeds > 0) {
- $unread = getFeedUnread($link, 0, true);
- $title = "Uncategorized";
-
- if ($unread > 0) {
- $title = "$title ($unread)";
- $class = '';
- } else {
- $class = 'oldItem';
- }
-
- if ($unread > 0 || !mobile_get_pref($link, "HIDE_READ")) {
- if ($cat_browse)
- print "<li class='$class'><a href='cat.php?id=0'>$title</a></li>";
- else
- print "<li class='$class'><a href='feed.php?id=0&is_cat=true'>$title</a></li>";
-
- }
- }
-
- print "</ul>";
- }
-
- function render_headlines_list($link, $feed_id, $cat_id, $offset, $search,
- $is_cat = false) {
-
- $feed_id = $feed_id;
- $limit = 15;
- $filter = '';
-
- if (!mobile_get_pref($link, "HIDE_READ"))
- $view_mode = "all_articles";
- else
- $view_mode = 'adaptive';
-
- if ($search) {
- $search_mode = 'this_feed';
- $match_on = 'both';
- } else {
- $search_mode = '';
- $match_on = '';
- }
-
- $qfh_ret = queryFeedHeadlines($link, $feed_id, $limit,
- $view_mode, $is_cat, $search, $search_mode, $match_on,
- "score DESC, date_entered DESC", $offset);
-
- $result = $qfh_ret[0];
- $feed_title = $qfh_ret[1];
-
- if (!$offset) {
-
- print "<form id=\"searchForm-$feed_id-$cat_id\" class=\"dialog\" method=\"POST\"
- action=\"feed.php\">
-
- <input type=\"hidden\" name=\"id\" value=\"$feed_id\">
- <input type=\"hidden\" name=\"cat\" value=\"$cat_id\">
-
- <fieldset>
- <h1>Search</h1>
- <a class=\"button leftButton\" type=\"cancel\">Cancel</a>
- <a class=\"button blueButton\" type=\"submit\">Search</a>
-
- <label>Search:</label>
- <input id=\"search\" type=\"text\" name=\"search\"/>
- </fieldset>
- </form>";
-
- if ($cat_id) {
- $cat_title = getCategoryTitle($link, $cat_id);
-
- print "<ul id=\"feed-$feed_id\" title=\"$feed_title\" selected=\"true\"
- myBackLabel='$cat_title' myBackHref='cat.php?id=$cat_id'>";
- } else {
- print "<ul id=\"feed-$feed_id\" title=\"$feed_title\" selected=\"true\"
- myBackLabel='".__("Home")."' myBackHref='home.php'>";
- }
-
- print "<li><a href='#searchForm-$feed_id-$cat_id'>Search...</a></li>";
- }
-
- $num_headlines = 0;
-
- while ($line = db_fetch_assoc($result)) {
- $id = $line["id"];
- $real_feed_id = $line["feed_id"];
-
- if (sql_bool_to_bool($line["unread"])) {
- $class = '';
- } else {
- $class = 'oldItem';
- }
-
- if (mobile_feed_has_icon($real_feed_id)) {
- $icon_url = "../".ICONS_URL."/$real_feed_id.ico";
- } else {
- $icon_url = "../images/blank_icon.gif";
- }
-
- print "<li class='$class'><a href='article.php?id=$id&feed=$feed_id&cat=$cat_id&is_cat=$is_cat'>
- <img class='tinyIcon' src='$icon_url'>";
- print $line["title"];
- print "</a></li>";
-
- ++$num_headlines;
-
- }
-
- if ($num_headlines == 0 && $search) {
- $articles_url = "feed.php?id=$feed_id&cat=$cat_id&skip=$next_offset";
-
- print "<li><a href=\"$articles_url\">" . __("Nothing found (click to reload feed).") . "</a></li>";
-
- }
-
-// print "<a target='_replace' href='feed.php?id=$feed_id&cat=$cat_id&skip=0'>Next $limit articles...</a>";
-
- $next_offset = $offset + $num_headlines;
- $num_unread = getFeedUnread($link, $feed_id, $is_cat);
-
- /* FIXME needs normal implementation */
-
- if ($num_headlines > 0 && ($num_unread == 0 || $num_unread > $next_offset)) {
-
- if ($is_cat) {
- $articles_url = "feed.php?id=$feed_id&skip=$next_offset".
- "&search=$search&is_cat=true";
- } else {
- $articles_url = "feed.php?id=$feed_id&cat=$cat_id&skip=$next_offset".
- "&search=$search";
- }
-
- print "<li><a href=\"$articles_url\"
- target=\"_replace\">Get more articles...</a></li>";
- }
-
- if (!$offset) print "</ul>";
-
- }
-
- function render_article($link, $id, $feed_id, $cat_id, $is_cat) {
-
- $query = "SELECT title,link,content,feed_id,comments,int_id,
- marked,unread,published,
- ".SUBSTRING_FOR_DATE."(updated,1,16) as updated,
- author
- FROM ttrss_entries,ttrss_user_entries
- WHERE id = '$id' AND ref_id = id AND owner_uid = " .
- $_SESSION["uid"] ;
-
- $result = db_query($link, $query);
-
- if (db_num_rows($result) != 0) {
-
- $line = db_fetch_assoc($result);
-
- $tmp_result = db_query($link, "UPDATE ttrss_user_entries
- SET unread = false,last_read = NOW()
- WHERE ref_id = '$id'
- AND owner_uid = " . $_SESSION["uid"]);
-
- $updated_fmt = make_local_datetime($link, $line['updated'], false);
-
- $title = $line["title"];
- $article_link = $line["link"];
-
- if (!$is_cat)
- $feed_title = getFeedTitle($link, $feed_id);
- else
- $feed_title = getCategoryTitle($link, $feed_id);
-
- print "<div class=\"panel\" id=\"article-$id\" title=\"$title\"
- selected=\"true\"
- myBackLabel='$feed_title' myBackHref='feed.php?id=$feed_id&cat=$cat_id&is_cat=$is_cat'>";
-
- if ($line['feed_id'] != $feed_id) {
- $real_feed_title = getFeedTitle($link, $line['feed_id']);
- $real_feed_id = $line['feed_id'];
- $feed_link = "(<a href=\"feed.php?id=$real_feed_id\">$real_feed_title</a>)";
- }
-// print "<fieldset>";
-
- print "<div style='float : right'>($updated_fmt)</div>";
-
- print "<h2><a target='_blank' href='$article_link'>$title</a> $feed_link</h2>";
-
- print "<hr>";
-
-/* print "<div class=\"row\">";
- print "<label id='title'><a target='_blank' href='$article_link'>$title</a></label>";
- print "</div>"; */
-
- $is_starred = (sql_bool_to_bool($line["marked"])) ? "true" : "false";
- $is_published = (sql_bool_to_bool($line["published"])) ? "true" : "false";
-
- //print "<div class=\"row\">";
- //print "<label id='updated'>Updated:</label>";
- //print "<input type='text' enabled='false' name='updated' disabled value='$updated_fmt'/>";
- //print "</div>";
-
-// print "</fieldset>";
-
- $content = sanitize_rss($link, $line["content"]);
- $content = preg_replace("/href=/i", "target=\"_blank\" href=", $content);
-
- if (!mobile_get_pref($link, "SHOW_IMAGES")) {
- $content = preg_replace('/<img[^>]+>/is', '', $content);
- }
-
- print "<p>$content</p>";
-
- print "<div class='nav'>
- <label>Navigation</label>
- <div class='button left' onclick='goPrev($id, $feed_id, this)'>Prev</div>
- <div class='button right' onclick='goNext($id, $feed_id, this)'>Next</div>
- </div>";
-
- print "<fieldset>";
-
- print "<div class=\"row\">
- <label>Starred</label>
- <div class=\"toggle\" onclick=\"toggleMarked($id, this)\" toggled=\"$is_starred\"><span class=\"thumb\"></span><span class=\"toggleOn\">ON</span><span class=\"toggleOff\">OFF</span></div>
- </div>";
-
- print "<div class=\"row\">
- <label>Published</label>
- <div class=\"toggle\" onclick=\"togglePublished($id, this)\" toggled=\"$is_published\"><span class=\"thumb\"></span><span class=\"toggleOn\">ON</span><span class=\"toggleOff\">OFF</span></div>
- </div>";
-
- print "<div class=\"row\">
- <label>Unread</label>
- <div class=\"toggle\" onclick=\"toggleUnread($id, this)\" toggled=\"$is_unread\"><span class=\"thumb\"></span><span class=\"toggleOn\">ON</span><span class=\"toggleOff\">OFF</span></div>
- </div>";
-
-
- print "</fieldset>";
-
- print "</div>";
-
- }
- }
-?>
define('MOBILE_VERSION', true);
require_once "../config.php";
- require_once "functions.php";
- require_once "../functions.php";
-
- require_once "../sessions.php";
-
- require_once "../version.php";
- require_once "../db-prefs.php";
+ require_once "mobile-functions.php";
$link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
$offset = (int) db_escape_string($_REQUEST["skip"]);
if ($use_cats) {
- render_categories_list($link);
+ render_categories_list($link);
} else {
render_flat_feed_list($link, $offset);
}
define('MOBILE_VERSION', true);
require_once "../config.php";
- require_once "functions.php";
- require_once "../functions.php";
-
- require_once "../sessions.php";
-
- require_once "../version.php";
- require_once "../db-prefs.php";
+ require_once "mobile-functions.php";
$link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
<a class="button" href="prefs.php">Preferences</a>
</div>
- <?php
+ <?php
$use_cats = mobile_get_pref($link, 'ENABLE_CATS');
$offset = (int) db_escape_string($_REQUEST["skip"]);
if ($use_cats) {
- render_categories_list($link);
+ render_categories_list($link);
} else {
render_flat_feed_list($link, $offset);
}
-<?php
- require_once "functions.php";
- require_once "../sessions.php";
- require_once "../functions.php";
+<?php
+ require_once "mobile-functions.php";
logout_user();
--- /dev/null
+<?php
+ set_include_path(get_include_path() . PATH_SEPARATOR .
+ dirname(__FILE__) . PATH_SEPARATOR .
+ dirname(dirname(__FILE__)) . PATH_SEPARATOR .
+ dirname(dirname(__FILE__)) . "/include" );
+
+ require_once "include/functions.php";
+ require_once "include/sessions.php";
+ require_once "include/version.php";
+ require_once "include/db-prefs.php";
+
+ define('TTRSS_SESSION_NAME', 'ttrss_m_sid');
+
+ /* TODO replace with interface to db-prefs */
+
+ function mobile_pref_toggled($link, $id) {
+ if (get_pref($link, "_MOBILE_$id"))
+ return "true";
+ else
+ return "";
+ }
+
+ function mobile_get_pref($link, $id) {
+ //return $_SESSION["mobile-prefs"][$id];
+ return get_pref($link, "_MOBILE_$id");
+ }
+
+ function mobile_set_pref($link, $id, $value) {
+ //$_SESSION["mobile-prefs"][$id] = $value;
+ return set_pref($link, "_MOBILE_$id", $value);
+ }
+
+ function mobile_feed_has_icon($id) {
+ $filename = "../".ICONS_DIR."/$id.ico";
+
+ return file_exists($filename) && filesize($filename) > 0;
+ }
+
+ function render_flat_feed_list($link, $offset) {
+ $owner_uid = $_SESSION["uid"];
+ $limit = 0;
+
+ if (!$offset) $offset = 0;
+
+ if (mobile_get_pref($link, "SORT_FEEDS_UNREAD")) {
+ $order_by = "unread DESC, title";
+ } else {
+ $order_by = "title";
+ }
+
+ if ($limit > 0) {
+ $limit_qpart = "LIMIT $limit OFFSET $offset";
+ } else {
+ $limit_qpart = "";
+ }
+
+ $result = db_query($link, "SELECT id,
+ title,
+ (SELECT COUNT(id) FROM ttrss_entries,ttrss_user_entries
+ WHERE feed_id = ttrss_feeds.id AND unread = true
+ AND ttrss_user_entries.ref_id = ttrss_entries.id
+ AND owner_uid = '$owner_uid') AS unread
+ FROM ttrss_feeds
+ WHERE
+ ttrss_feeds.owner_uid = '$owner_uid'
+ ORDER BY $order_by $limit_qpart");
+
+ if (!$offset) print '<ul id="home" title="'.__('Home').'" selected="true"
+ myBackLabel="'.__('Logout').'" myBackHref="logout.php" myBackTarget="_self">';
+
+
+ // print "<li><a href='#cat-actions'>".__('Actions...')."</a></li>";
+
+ $num_feeds = 0;
+
+ while ($line = db_fetch_assoc($result)) {
+ $id = $line["id"];
+ $unread = $line["unread"];
+
+ // $unread = rand(0, 100);
+
+ if ($unread > 0) {
+ $line["title"] = $line["title"] . " ($unread)";
+ $class = '';
+ } else {
+ $class = 'oldItem';
+ }
+
+ if (mobile_feed_has_icon($id)) {
+ $icon_url = "../".ICONS_URL."/$id.ico";
+ } else {
+ $icon_url = "../images/blank_icon.gif";
+ }
+
+ if ($unread > 0 || !mobile_get_pref($link, "HIDE_READ")) {
+ print "<li class='$class'><a href='feed.php?id=$id'>" .
+ "<img class='tinyIcon' src='$icon_url'/>".
+ $line["title"] . "</a></li>";
+ }
+
+ ++$num_feeds;
+ }
+
+/* $next_offset = $offset + $num_feeds;
+
+ print "<li><a href=\"home.php?skip=$next_offset\"
+ target=\"_replace\">Show more feeds...</a></li>"; */
+
+ if (!$offset) print "</ul>";
+
+ }
+
+ function render_category($link, $cat_id, $offset) {
+ $owner_uid = $_SESSION["uid"];
+
+ if ($cat_id >= 0) {
+
+ if ($cat_id != 0) {
+ $cat_query = "cat_id = '$cat_id'";
+ } else {
+ $cat_query = "cat_id IS NULL";
+ }
+
+ if (mobile_get_pref($link, "SORT_FEEDS_UNREAD")) {
+ $order_by = "unread DESC, title";
+ } else {
+ $order_by = "title";
+ }
+
+ $result = db_query($link, "SELECT id,
+ title,
+ (SELECT COUNT(id) FROM ttrss_entries,ttrss_user_entries
+ WHERE feed_id = ttrss_feeds.id AND unread = true
+ AND ttrss_user_entries.ref_id = ttrss_entries.id
+ AND owner_uid = '$owner_uid') as unread
+ FROM ttrss_feeds
+ WHERE
+ ttrss_feeds.owner_uid = '$owner_uid' AND
+ $cat_query
+ ORDER BY $order_by");
+
+ $title = getCategoryTitle($link, $cat_id);
+
+ print "<ul id='cat-$cat_id' title='$title' myBackLabel='".__("Home")."'
+ myBackHref='home.php'>";
+
+ // print "<li><a href='#cat-actions'>".__('Actions...')."</a></li>";
+
+ while ($line = db_fetch_assoc($result)) {
+ $id = $line["id"];
+ $unread = $line["unread"];
+
+ // $unread = rand(0, 100);
+
+ if ($unread > 0) {
+ $line["title"] = $line["title"] . " ($unread)";
+ $class = '';
+ } else {
+ $class = 'oldItem';
+ }
+
+ if (mobile_feed_has_icon($id)) {
+ $icon_url = "../".ICONS_URL."/$id.ico";
+ } else {
+ $icon_url = "../images/blank_icon.gif";
+ }
+
+ if ($unread > 0 || !mobile_get_pref($link, "HIDE_READ")) {
+ print "<li class='$class'><a href='feed.php?id=$id&cat=$cat_id'>" .
+ "<img class='tinyIcon' src='$icon_url'/>".
+ $line["title"] . "</a></li>";
+ }
+ }
+
+ print "</ul>";
+ } else if ($cat_id == -1) {
+
+ $title = __('Special');
+
+ print "<ul id='cat--1' title='$title' myBackLabel='".__("Home")."'
+ myBackHref='home.php'>";
+
+ foreach (array(-4, -3, -1, -2, 0) as $id) {
+ $title = getFeedTitle($link, $id);
+ $unread = getFeedUnread($link, $id, false);
+ $icon = getFeedIcon($id);
+
+ if ($unread > 0) {
+ $title = $title . " ($unread)";
+ $class = '';
+ } else {
+ $class = 'oldItem';
+ }
+
+ if ($unread > 0 || !mobile_get_pref($link, "HIDE_READ")) {
+ print "<li class='$class'>
+ <a href='feed.php?id=$id&cat=-1'>
+ <img class='tinyIcon' src='../$icon'/>$title</a></li>";
+ }
+ }
+
+ print "</ul>";
+ } else if ($cat_id == -2) {
+
+ $title = __('Labels');
+
+ print "<ul id='cat--2' title='$title' myBackLabel='".__("Home")."'
+ myBackHref='home.php'>";
+
+ $result = db_query($link, "SELECT id, caption FROM ttrss_labels2
+ WHERE owner_uid = '$owner_uid'");
+
+ $label_data = array();
+
+ while ($line = db_fetch_assoc($result)) {
+
+ $id = -$line["id"] - 11;
+
+ $unread = getFeedUnread($link, $id);
+ $title = $line["caption"];
+
+ if ($unread > 0) {
+ $title = $title . " ($unread)";
+ $class = '';
+ } else {
+ $class = 'oldItem';
+ }
+
+ if ($unread > 0 || !mobile_get_pref($link, "HIDE_READ")) {
+ print "<li class='$class'>
+ <a href='feed.php?id=$id&cat=-2'>$title</a></li>";
+ }
+ }
+ print "</ul>";
+ }
+ }
+
+ function render_categories_list($link) {
+ $owner_uid = $_SESSION["uid"];
+
+ $cat_browse = mobile_get_pref($link, "BROWSE_CATS");
+
+ print '<ul id="home" title="'.__('Home').'" selected="true"
+ myBackLabel="'.__('Logout').'" myBackHref="logout.php" myBackTarget="_self">';
+
+// print "<li><a href='#searchForm'>Search...</a></li>";
+
+ foreach (array(-1, -2) as $id) {
+ $title = getCategoryTitle($link, $id);
+ $unread = getFeedUnread($link, $id, true);
+ if ($unread > 0) {
+ $title = $title . " ($unread)";
+ $class = '';
+ } else {
+ $class = 'oldItem';
+ }
+
+ if ($cat_browse)
+ print "<li class='$class'><a href='cat.php?id=$id'>$title</a></li>";
+ else
+ print "<li class='$class'><a href='feed.php?id=$id&is_cat=true'>$title</a></li>";
+ }
+
+ $result = db_query($link, "SELECT
+ ttrss_feed_categories.id,
+ ttrss_feed_categories.title,
+ COUNT(ttrss_feeds.id) AS num_feeds
+ FROM ttrss_feed_categories, ttrss_feeds
+ WHERE ttrss_feed_categories.owner_uid = $owner_uid
+ AND ttrss_feed_categories.id = cat_id
+ GROUP BY ttrss_feed_categories.id,
+ ttrss_feed_categories.title
+ ORDER BY ttrss_feed_categories.title");
+
+ while ($line = db_fetch_assoc($result)) {
+
+ if ($line["num_feeds"] > 0) {
+
+ $unread = getFeedUnread($link, $line["id"], true);
+ $id = $line["id"];
+
+ if ($unread > 0) {
+ $line["title"] = $line["title"] . " ($unread)";
+ $class = '';
+ } else {
+ $class = 'oldItem';
+ }
+
+ if ($unread > 0 || !mobile_get_pref($link, "HIDE_READ")) {
+
+ if ($cat_browse)
+ print "<li class='$class'><a href='cat.php?id=$id'>" .
+ $line["title"] . "</a></li>";
+ else
+ print "<li class='$class'><a href='feed.php?id=$id&is_cat=true'>".
+ $line["title"] . "</a></li>";
+ }
+ }
+ }
+
+
+ $result = db_query($link, "SELECT COUNT(*) AS nf FROM ttrss_feeds WHERE
+ cat_id IS NULL and owner_uid = '$owner_uid'");
+
+ $num_feeds = db_fetch_result($result, 0, "nf");
+
+ if ($num_feeds > 0) {
+ $unread = getFeedUnread($link, 0, true);
+ $title = "Uncategorized";
+
+ if ($unread > 0) {
+ $title = "$title ($unread)";
+ $class = '';
+ } else {
+ $class = 'oldItem';
+ }
+
+ if ($unread > 0 || !mobile_get_pref($link, "HIDE_READ")) {
+ if ($cat_browse)
+ print "<li class='$class'><a href='cat.php?id=0'>$title</a></li>";
+ else
+ print "<li class='$class'><a href='feed.php?id=0&is_cat=true'>$title</a></li>";
+
+ }
+ }
+
+ print "</ul>";
+ }
+
+ function render_headlines_list($link, $feed_id, $cat_id, $offset, $search,
+ $is_cat = false) {
+
+ $feed_id = $feed_id;
+ $limit = 15;
+ $filter = '';
+
+ if (!mobile_get_pref($link, "HIDE_READ"))
+ $view_mode = "all_articles";
+ else
+ $view_mode = 'adaptive';
+
+ if ($search) {
+ $search_mode = 'this_feed';
+ $match_on = 'both';
+ } else {
+ $search_mode = '';
+ $match_on = '';
+ }
+
+ $qfh_ret = queryFeedHeadlines($link, $feed_id, $limit,
+ $view_mode, $is_cat, $search, $search_mode, $match_on,
+ "score DESC, date_entered DESC", $offset);
+
+ $result = $qfh_ret[0];
+ $feed_title = $qfh_ret[1];
+
+ if (!$offset) {
+
+ print "<form id=\"searchForm-$feed_id-$cat_id\" class=\"dialog\" method=\"POST\"
+ action=\"feed.php\">
+
+ <input type=\"hidden\" name=\"id\" value=\"$feed_id\">
+ <input type=\"hidden\" name=\"cat\" value=\"$cat_id\">
+
+ <fieldset>
+ <h1>Search</h1>
+ <a class=\"button leftButton\" type=\"cancel\">Cancel</a>
+ <a class=\"button blueButton\" type=\"submit\">Search</a>
+
+ <label>Search:</label>
+ <input id=\"search\" type=\"text\" name=\"search\"/>
+ </fieldset>
+ </form>";
+
+ if ($cat_id) {
+ $cat_title = getCategoryTitle($link, $cat_id);
+
+ print "<ul id=\"feed-$feed_id\" title=\"$feed_title\" selected=\"true\"
+ myBackLabel='$cat_title' myBackHref='cat.php?id=$cat_id'>";
+ } else {
+ print "<ul id=\"feed-$feed_id\" title=\"$feed_title\" selected=\"true\"
+ myBackLabel='".__("Home")."' myBackHref='home.php'>";
+ }
+
+ print "<li><a href='#searchForm-$feed_id-$cat_id'>Search...</a></li>";
+ }
+
+ $num_headlines = 0;
+
+ while ($line = db_fetch_assoc($result)) {
+ $id = $line["id"];
+ $real_feed_id = $line["feed_id"];
+
+ if (sql_bool_to_bool($line["unread"])) {
+ $class = '';
+ } else {
+ $class = 'oldItem';
+ }
+
+ if (mobile_feed_has_icon($real_feed_id)) {
+ $icon_url = "../".ICONS_URL."/$real_feed_id.ico";
+ } else {
+ $icon_url = "../images/blank_icon.gif";
+ }
+
+ print "<li class='$class'><a href='article.php?id=$id&feed=$feed_id&cat=$cat_id&is_cat=$is_cat'>
+ <img class='tinyIcon' src='$icon_url'>";
+ print $line["title"];
+ print "</a></li>";
+
+ ++$num_headlines;
+
+ }
+
+ if ($num_headlines == 0 && $search) {
+ $articles_url = "feed.php?id=$feed_id&cat=$cat_id&skip=$next_offset";
+
+ print "<li><a href=\"$articles_url\">" . __("Nothing found (click to reload feed).") . "</a></li>";
+
+ }
+
+// print "<a target='_replace' href='feed.php?id=$feed_id&cat=$cat_id&skip=0'>Next $limit articles...</a>";
+
+ $next_offset = $offset + $num_headlines;
+ $num_unread = getFeedUnread($link, $feed_id, $is_cat);
+
+ /* FIXME needs normal implementation */
+
+ if ($num_headlines > 0 && ($num_unread == 0 || $num_unread > $next_offset)) {
+
+ if ($is_cat) {
+ $articles_url = "feed.php?id=$feed_id&skip=$next_offset".
+ "&search=$search&is_cat=true";
+ } else {
+ $articles_url = "feed.php?id=$feed_id&cat=$cat_id&skip=$next_offset".
+ "&search=$search";
+ }
+
+ print "<li><a href=\"$articles_url\"
+ target=\"_replace\">Get more articles...</a></li>";
+ }
+
+ if (!$offset) print "</ul>";
+
+ }
+
+ function render_article($link, $id, $feed_id, $cat_id, $is_cat) {
+
+ $query = "SELECT title,link,content,feed_id,comments,int_id,
+ marked,unread,published,
+ ".SUBSTRING_FOR_DATE."(updated,1,16) as updated,
+ author
+ FROM ttrss_entries,ttrss_user_entries
+ WHERE id = '$id' AND ref_id = id AND owner_uid = " .
+ $_SESSION["uid"] ;
+
+ $result = db_query($link, $query);
+
+ if (db_num_rows($result) != 0) {
+
+ $line = db_fetch_assoc($result);
+
+ $tmp_result = db_query($link, "UPDATE ttrss_user_entries
+ SET unread = false,last_read = NOW()
+ WHERE ref_id = '$id'
+ AND owner_uid = " . $_SESSION["uid"]);
+
+ $updated_fmt = make_local_datetime($link, $line['updated'], false);
+
+ $title = $line["title"];
+ $article_link = $line["link"];
+
+ if (!$is_cat)
+ $feed_title = getFeedTitle($link, $feed_id);
+ else
+ $feed_title = getCategoryTitle($link, $feed_id);
+
+ print "<div class=\"panel\" id=\"article-$id\" title=\"$title\"
+ selected=\"true\"
+ myBackLabel='$feed_title' myBackHref='feed.php?id=$feed_id&cat=$cat_id&is_cat=$is_cat'>";
+
+ if ($line['feed_id'] != $feed_id) {
+ $real_feed_title = getFeedTitle($link, $line['feed_id']);
+ $real_feed_id = $line['feed_id'];
+ $feed_link = "(<a href=\"feed.php?id=$real_feed_id\">$real_feed_title</a>)";
+ }
+// print "<fieldset>";
+
+ print "<div style='float : right'>($updated_fmt)</div>";
+
+ print "<h2><a target='_blank' href='$article_link'>$title</a> $feed_link</h2>";
+
+ print "<hr>";
+
+/* print "<div class=\"row\">";
+ print "<label id='title'><a target='_blank' href='$article_link'>$title</a></label>";
+ print "</div>"; */
+
+ $is_starred = (sql_bool_to_bool($line["marked"])) ? "true" : "false";
+ $is_published = (sql_bool_to_bool($line["published"])) ? "true" : "false";
+
+ //print "<div class=\"row\">";
+ //print "<label id='updated'>Updated:</label>";
+ //print "<input type='text' enabled='false' name='updated' disabled value='$updated_fmt'/>";
+ //print "</div>";
+
+// print "</fieldset>";
+
+ $content = sanitize_rss($link, $line["content"]);
+ $content = preg_replace("/href=/i", "target=\"_blank\" href=", $content);
+
+ if (!mobile_get_pref($link, "SHOW_IMAGES")) {
+ $content = preg_replace('/<img[^>]+>/is', '', $content);
+ }
+
+ print "<p>$content</p>";
+
+ print "<div class='nav'>
+ <label>Navigation</label>
+ <div class='button left' onclick='goPrev($id, $feed_id, this)'>Prev</div>
+ <div class='button right' onclick='goNext($id, $feed_id, this)'>Next</div>
+ </div>";
+
+ print "<fieldset>";
+
+ print "<div class=\"row\">
+ <label>Starred</label>
+ <div class=\"toggle\" onclick=\"toggleMarked($id, this)\" toggled=\"$is_starred\"><span class=\"thumb\"></span><span class=\"toggleOn\">ON</span><span class=\"toggleOff\">OFF</span></div>
+ </div>";
+
+ print "<div class=\"row\">
+ <label>Published</label>
+ <div class=\"toggle\" onclick=\"togglePublished($id, this)\" toggled=\"$is_published\"><span class=\"thumb\"></span><span class=\"toggleOn\">ON</span><span class=\"toggleOff\">OFF</span></div>
+ </div>";
+
+ print "<div class=\"row\">
+ <label>Unread</label>
+ <div class=\"toggle\" onclick=\"toggleUnread($id, this)\" toggled=\"$is_unread\"><span class=\"thumb\"></span><span class=\"toggleOn\">ON</span><span class=\"toggleOff\">OFF</span></div>
+ </div>";
+
+
+ print "</fieldset>";
+
+ print "</div>";
+
+ }
+ }
+?>
define('MOBILE_VERSION', true);
require_once "../config.php";
- require_once "functions.php";
- require_once "../functions.php";
-
- require_once "../sessions.php";
-
- require_once "../version.php";
- require_once "../db-prefs.php";
+ require_once "mobile-functions.php";
$link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
<?php
+ set_include_path(get_include_path() . PATH_SEPARATOR . "include");
+
require_once "functions.php";
require_once "sessions.php";
require_once "sanity_check.php";
+++ /dev/null
-var init_params = new Array();
-
-var hotkey_prefix = false;
-var hotkey_prefix_pressed = false;
-
-var seq = "";
-
-function instancelist_callback2(transport) {
- try {
- dijit.byId('instanceConfigTab').attr('content', transport.responseText);
- selectTab("instanceConfig", true);
- notify("");
- } catch (e) {
- exception_error("instancelist_callback2", e);
- }
-}
-
-function feedlist_callback2(transport) {
- try {
- dijit.byId('feedConfigTab').attr('content', transport.responseText);
- selectTab("feedConfig", true);
- notify("");
- } catch (e) {
- exception_error("feedlist_callback2", e);
- }
-}
-
-function filterlist_callback2(transport) {
- dijit.byId('filterConfigTab').attr('content', transport.responseText);
- notify("");
-}
-
-function labellist_callback2(transport) {
- try {
- dijit.byId('labelConfigTab').attr('content', transport.responseText);
- notify("");
- } catch (e) {
- exception_error("labellist_callback2", e);
- }
-}
-
-function userlist_callback2(transport) {
- try {
- dijit.byId('userConfigTab').attr('content', transport.responseText);
-
- notify("");
- } catch (e) {
- exception_error("userlist_callback2", e);
- }
-}
-
-function prefslist_callback2(transport) {
- try {
- dijit.byId('genConfigTab').attr('content', transport.responseText);
-
- notify("");
- } catch (e) {
- exception_error("prefslist_callback2", e);
- }
-}
-
-function notify_callback2(transport) {
- notify_info(transport.responseText);
-}
-
-function updateFeedList(sort_key) {
-
- var user_search = $("feed_search");
- var search = "";
- if (user_search) { search = user_search.value; }
-
- new Ajax.Request("backend.php", {
- parameters: "?op=pref-feeds&search=" + param_escape(search),
- onComplete: function(transport) {
- feedlist_callback2(transport);
- } });
-}
-
-function updateInstanceList(sort_key) {
- new Ajax.Request("backend.php", {
- parameters: "?op=pref-instances&sort=" + param_escape(sort_key),
- onComplete: function(transport) {
- instancelist_callback2(transport);
- } });
-}
-
-function updateUsersList(sort_key) {
-
- try {
-
- var user_search = $("user_search");
- var search = "";
- if (user_search) { search = user_search.value; }
-
- var query = "?op=pref-users&sort="
- + param_escape(sort_key) +
- "&search=" + param_escape(search);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- userlist_callback2(transport);
- } });
-
- } catch (e) {
- exception_error("updateUsersList", e);
- }
-}
-
-function addUser() {
-
- try {
-
- var login = prompt(__("Please enter login:"), "");
-
- if (login == null) {
- return false;
- }
-
- if (login == "") {
- alert(__("Can't create user: no login specified."));
- return false;
- }
-
- notify_progress("Adding user...");
-
- var query = "?op=pref-users&subop=add&login=" +
- param_escape(login);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- userlist_callback2(transport);
- } });
-
- } catch (e) {
- exception_error("addUser", e);
- }
-}
-
-function editUser(id, event) {
-
- try {
- if (!event || !event.ctrlKey) {
-
- notify_progress("Loading, please wait...");
-
- selectTableRows('prefUserList', 'none');
- selectTableRowById('UMRR-'+id, 'UMCHK-'+id, true);
-
- var query = "?op=pref-users&subop=edit&id=" +
- param_escape(id);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- infobox_callback2(transport);
- document.forms['user_edit_form'].login.focus();
- } });
-
- } else if (event.ctrlKey) {
- var cb = $('UMCHK-' + id);
- cb.checked = !cb.checked;
- toggleSelectRow(cb);
- }
-
- } catch (e) {
- exception_error("editUser", e);
- }
-
-}
-
-function editFilter(id) {
- try {
-
- var query = "backend.php?op=pref-filters&subop=edit&id=" + param_escape(id);
-
- if (dijit.byId("filterEditDlg"))
- dijit.byId("filterEditDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "filterEditDlg",
- title: __("Edit Filter"),
- style: "width: 600px",
- removeFilter: function() {
- var title = this.attr('value').reg_exp;
- var msg = __("Remove filter %s?").replace("%s", title);
-
- if (confirm(msg)) {
- this.hide();
-
- notify_progress("Removing filter...");
-
- var id = this.attr('value').id;
-
- var query = "?op=pref-filters&subop=remove&ids="+
- param_escape(id);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- updateFilterList();
- } });
- }
- },
- test: function() {
- if (this.validate()) {
-
- if (dijit.byId("filterTestDlg"))
- dijit.byId("filterTestDlg").destroyRecursive();
-
- tdialog = new dijit.Dialog({
- id: "filterTestDlg",
- title: __("Filter Test Results"),
- style: "width: 600px",
- href: "backend.php?savemode=test&" +
- dojo.objectToQuery(dialog.attr('value')),
- });
-
- tdialog.show();
-
- }
- },
- execute: function() {
- if (this.validate()) {
-
- var query = "?op=rpc&subop=verifyRegexp®_exp=" +
- param_escape(dialog.attr('value').reg_exp);
-
- notify_progress("Verifying regular expression...");
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- var reply = JSON.parse(transport.responseText);
-
- if (reply) {
- notify('');
-
- if (!reply['status']) {
- alert("Match regular expression seems to be invalid.");
- return;
- } else {
- notify_progress("Saving data...", true);
-
- console.log(dojo.objectToQuery(dialog.attr('value')));
-
- new Ajax.Request("backend.php", {
- parameters: dojo.objectToQuery(dialog.attr('value')),
- onComplete: function(transport) {
- dialog.hide();
- updateFilterList();
- }});
- }
- }
- }});
- }
- },
- href: query});
-
- dialog.show();
-
-
- } catch (e) {
- exception_error("editFilter", e);
- }
-}
-
-function getSelectedLabels() {
- var tree = dijit.byId("labelTree");
- var items = tree.model.getCheckedItems();
- var rv = [];
-
- items.each(function(item) {
- rv.push(tree.model.store.getValue(item, 'bare_id'));
- });
-
- return rv;
-}
-
-function getSelectedUsers() {
- return getSelectedTableRowIds("prefUserList");
-}
-
-function getSelectedFeeds() {
- var tree = dijit.byId("feedTree");
- var items = tree.model.getCheckedItems();
- var rv = [];
-
- items.each(function(item) {
- if (item.id[0].match("FEED:"))
- rv.push(tree.model.store.getValue(item, 'bare_id'));
- });
-
- return rv;
-}
-
-function getSelectedFilters() {
- var tree = dijit.byId("filterTree");
- var items = tree.model.getCheckedItems();
- var rv = [];
-
- items.each(function(item) {
- rv.push(tree.model.store.getValue(item, 'bare_id'));
- });
-
- return rv;
-
-}
-
-/* function getSelectedFeedCats() {
- return getSelectedTableRowIds("prefFeedCatList");
-} */
-
-function removeSelectedLabels() {
-
- var sel_rows = getSelectedLabels();
-
- if (sel_rows.length > 0) {
-
- var ok = confirm(__("Remove selected labels?"));
-
- if (ok) {
- notify_progress("Removing selected labels...");
-
- var query = "?op=pref-labels&subop=remove&ids="+
- param_escape(sel_rows.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- labellist_callback2(transport);
- } });
-
- }
- } else {
- alert(__("No labels are selected."));
- }
-
- return false;
-}
-
-function removeSelectedUsers() {
-
- try {
-
- var sel_rows = getSelectedUsers();
-
- if (sel_rows.length > 0) {
-
- var ok = confirm(__("Remove selected users? Neither default admin nor your account will be removed."));
-
- if (ok) {
- notify_progress("Removing selected users...");
-
- var query = "?op=pref-users&subop=remove&ids="+
- param_escape(sel_rows.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- userlist_callback2(transport);
- } });
-
- }
-
- } else {
- alert(__("No users are selected."));
- }
-
- } catch (e) {
- exception_error("removeSelectedUsers", e);
- }
-
- return false;
-}
-
-function removeSelectedFilters() {
-
- try {
-
- var sel_rows = getSelectedFilters();
-
- if (sel_rows.length > 0) {
-
- var ok = confirm(__("Remove selected filters?"));
-
- if (ok) {
- notify_progress("Removing selected filters...");
-
- var query = "?op=pref-filters&subop=remove&ids="+
- param_escape(sel_rows.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- updateFilterList();
- } });
- }
- } else {
- alert(__("No filters are selected."));
- }
-
- } catch (e) {
- exception_error("removeSelectedFilters", e);
- }
-
- return false;
-}
-
-
-function removeSelectedFeeds() {
-
- try {
-
- var sel_rows = getSelectedFeeds();
-
- if (sel_rows.length > 0) {
-
- var ok = confirm(__("Unsubscribe from selected feeds?"));
-
- if (ok) {
-
- notify_progress("Unsubscribing from selected feeds...", true);
-
- var query = "?op=pref-feeds&subop=remove&ids="+
- param_escape(sel_rows.toString());
-
- console.log(query);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- updateFeedList();
- } });
- }
-
- } else {
- alert(__("No feeds are selected."));
- }
-
- } catch (e) {
- exception_error("removeSelectedFeeds", e);
- }
-
- return false;
-}
-
-function clearSelectedFeeds() {
-
- var sel_rows = getSelectedFeeds();
-
- if (sel_rows.length > 1) {
- alert(__("Please select only one feed."));
- return;
- }
-
- if (sel_rows.length > 0) {
-
- var ok = confirm(__("Erase all non-starred articles in selected feed?"));
-
- if (ok) {
- notify_progress("Clearing selected feed...");
- clearFeedArticles(sel_rows[0]);
- }
-
- } else {
-
- alert(__("No feeds are selected."));
-
- }
-
- return false;
-}
-
-function purgeSelectedFeeds() {
-
- var sel_rows = getSelectedFeeds();
-
- if (sel_rows.length > 0) {
-
- var pr = prompt(__("How many days of articles to keep (0 - use default)?"), "0");
-
- if (pr != undefined) {
- notify_progress("Purging selected feed...");
-
- var query = "?op=rpc&subop=purge&ids="+
- param_escape(sel_rows.toString()) + "&days=" + pr;
-
- console.log(query);
-
- new Ajax.Request("prefs.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
- } });
- }
-
- } else {
-
- alert(__("No feeds are selected."));
-
- }
-
- return false;
-}
-
-function userEditCancel() {
- closeInfoBox();
- return false;
-}
-
-function userEditSave() {
-
- try {
-
- var login = document.forms["user_edit_form"].login.value;
-
- if (login.length == 0) {
- alert(__("Login field cannot be blank."));
- return;
- }
-
- notify_progress("Saving user...");
-
- closeInfoBox();
-
- var query = Form.serialize("user_edit_form");
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- userlist_callback2(transport);
- } });
-
- } catch (e) {
- exception_error("userEditSave", e);
- }
-
- return false;
-
-}
-
-
-function editSelectedUser() {
- var rows = getSelectedUsers();
-
- if (rows.length == 0) {
- alert(__("No users are selected."));
- return;
- }
-
- if (rows.length > 1) {
- alert(__("Please select only one user."));
- return;
- }
-
- notify("");
-
- editUser(rows[0]);
-}
-
-function resetSelectedUserPass() {
-
- try {
-
- var rows = getSelectedUsers();
-
- if (rows.length == 0) {
- alert(__("No users are selected."));
- return;
- }
-
- if (rows.length > 1) {
- alert(__("Please select only one user."));
- return;
- }
-
- var ok = confirm(__("Reset password of selected user?"));
-
- if (ok) {
- notify_progress("Resetting password for selected user...");
-
- var id = rows[0];
-
- var query = "?op=pref-users&subop=resetPass&id=" +
- param_escape(id);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- userlist_callback2(transport);
- } });
-
- }
-
- } catch (e) {
- exception_error("resetSelectedUserPass", e);
- }
-}
-
-function selectedUserDetails() {
-
- try {
-
- var rows = getSelectedUsers();
-
- if (rows.length == 0) {
- alert(__("No users are selected."));
- return;
- }
-
- if (rows.length > 1) {
- alert(__("Please select only one user."));
- return;
- }
-
- notify_progress("Loading, please wait...");
-
- var id = rows[0];
-
- var query = "?op=pref-users&subop=user-details&id=" + id;
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- infobox_callback2(transport);
- } });
- } catch (e) {
- exception_error("selectedUserDetails", e);
- }
-}
-
-
-function editSelectedFilter() {
- var rows = getSelectedFilters();
-
- if (rows.length == 0) {
- alert(__("No filters are selected."));
- return;
- }
-
- if (rows.length > 1) {
- alert(__("Please select only one filter."));
- return;
- }
-
- notify("");
-
- editFilter(rows[0]);
-
-}
-
-
-function editSelectedFeed() {
- var rows = getSelectedFeeds();
-
- if (rows.length == 0) {
- alert(__("No feeds are selected."));
- return;
- }
-
- if (rows.length > 1) {
- return editSelectedFeeds();
- }
-
- notify("");
-
- editFeed(rows[0], {});
-
-}
-
-function editSelectedFeeds() {
-
- try {
- var rows = getSelectedFeeds();
-
- if (rows.length == 0) {
- alert(__("No feeds are selected."));
- return;
- }
-
- notify_progress("Loading, please wait...");
-
- var query = "backend.php?op=pref-feeds&subop=editfeeds&ids=" +
- param_escape(rows.toString());
-
- console.log(query);
-
- if (dijit.byId("feedEditDlg"))
- dijit.byId("feedEditDlg").destroyRecursive();
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
-
- notify("");
-
- var dialog = new dijit.Dialog({
- id: "feedEditDlg",
- title: __("Edit Multiple Feeds"),
- style: "width: 600px",
- getChildByName: function (name) {
- var rv = null;
- this.getChildren().each(
- function(child) {
- if (child.name == name) {
- rv = child;
- return;
- }
- });
- return rv;
- },
- toggleField: function (checkbox, elem, label) {
- this.getChildByName(elem).attr('disabled', !checkbox.checked);
-
- if ($(label))
- if (checkbox.checked)
- $(label).removeClassName('insensitive');
- else
- $(label).addClassName('insensitive');
-
- },
- execute: function() {
- if (this.validate() && confirm(__("Save changes to selected feeds?"))) {
- var query = dojo.objectToQuery(this.attr('value'));
-
- /* Form.serialize ignores unchecked checkboxes */
-
- if (!query.match("&rtl_content=") &&
- this.getChildByName('rtl_content').attr('disabled') == false) {
- query = query + "&rtl_content=false";
- }
-
- if (!query.match("&private=") &&
- this.getChildByName('private').attr('disabled') == false) {
- query = query + "&private=false";
- }
-
- try {
- if (!query.match("&cache_images=") &&
- this.getChildByName('cache_images').attr('disabled') == false) {
- query = query + "&cache_images=false";
- }
- } catch (e) { }
-
- if (!query.match("&include_in_digest=") &&
- this.getChildByName('include_in_digest').attr('disabled') == false) {
- query = query + "&include_in_digest=false";
- }
-
- if (!query.match("&always_display_enclosures=") &&
- this.getChildByName('always_display_enclosures').attr('disabled') == false) {
- query = query + "&always_display_enclosures=false";
- }
-
- if (!query.match("&mark_unread_on_update=") &&
- this.getChildByName('mark_unread_on_update').attr('disabled') == false) {
- query = query + "&mark_unread_on_update=false";
- }
-
- if (!query.match("&update_on_checksum_change=") &&
- this.getChildByName('update_on_checksum_change').attr('disabled') == false) {
- query = query + "&update_on_checksum_change=false";
- }
-
- console.log(query);
-
- notify_progress("Saving data...", true);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- dialog.hide();
- updateFeedList();
- }});
- }
- },
- content: transport.responseText});
-
- dialog.show();
-
- } });
-
- } catch (e) {
- exception_error("editSelectedFeeds", e);
- }
-}
-
-function piggie(enable) {
- if (enable) {
- console.log("I LOVEDED IT!");
- var piggie = $("piggie");
-
- Element.show(piggie);
- Position.Center(piggie);
- Effect.Puff(piggie);
-
- }
-}
-
-function opmlImportComplete(iframe) {
- try {
- if (!iframe.contentDocument.body.innerHTML) return false;
-
- notify('');
-
- if (dijit.byId('opmlImportDlg'))
- dijit.byId('opmlImportDlg').destroyRecursive();
-
- var content = iframe.contentDocument.body.innerHTML;
-
- dialog = new dijit.Dialog({
- id: "opmlImportDlg",
- title: __("OPML Import"),
- style: "width: 600px",
- onCancel: function() {
- updateFeedList();
- },
- content: content});
-
- dialog.show();
-
- } catch (e) {
- exception_error("opmlImportComplete", e);
- }
-}
-
-function opmlImport() {
-
- var opml_file = $("opml_file");
-
- if (opml_file.value.length == 0) {
- alert(__("Please choose an OPML file first."));
- return false;
- } else {
- notify_progress("Importing, please wait...", true);
- return true;
- }
-}
-
-function updateFilterList() {
- new Ajax.Request("backend.php", {
- parameters: "?op=pref-filters",
- onComplete: function(transport) {
- filterlist_callback2(transport);
- } });
-}
-
-function updateLabelList() {
- new Ajax.Request("backend.php", {
- parameters: "?op=pref-labels",
- onComplete: function(transport) {
- labellist_callback2(transport);
- } });
-}
-
-function updatePrefsList() {
- new Ajax.Request("backend.php", {
- parameters: "?op=pref-prefs",
- onComplete: function(transport) {
- prefslist_callback2(transport);
- } });
-}
-
-function selectTab(id, noupdate, subop) {
- try {
- if (!noupdate) {
- notify_progress("Loading, please wait...");
-
- if (id == "feedConfig") {
- updateFeedList();
- } else if (id == "filterConfig") {
- updateFilterList();
- } else if (id == "labelConfig") {
- updateLabelList();
- } else if (id == "genConfig") {
- updatePrefsList();
- } else if (id == "userConfig") {
- updateUsersList();
- }
-
- var tab = dijit.byId(id + "Tab");
- dijit.byId("pref-tabs").selectChild(tab);
-
- }
-
- } catch (e) {
- exception_error("selectTab", e);
- }
-}
-
-function init_second_stage() {
- try {
-
- document.onkeydown = pref_hotkey_handler;
- loading_set_progress(50);
- notify("");
-
- dojo.addOnLoad(function() {
- var tab = getURLParam('tab');
-
- if (tab) {
- tab = dijit.byId(tab + "Tab");
- if (tab) dijit.byId("pref-tabs").selectChild(tab);
- }
-
- var subop = getURLParam('subop');
-
- if (subop == 'editFeed') {
- var param = getURLParam('subopparam');
-
- window.setTimeout('editFeed(' + param + ')', 100);
- }
- });
-
- setTimeout("hotkey_prefix_timeout()", 5*1000);
-
- } catch (e) {
- exception_error("init_second_stage", e);
- }
-}
-
-function init() {
-
- try {
- dojo.registerModulePath("lib", "..");
- dojo.registerModulePath("fox", "../..");
-
- dojo.require("lib.CheckBoxTree");
- dojo.require("fox.PrefFeedTree");
- dojo.require("fox.PrefFilterTree");
- dojo.require("fox.PrefLabelTree");
-
- dojo.parser.parse();
-
- dojo.addOnLoad(function() {
- loading_set_progress(50);
-
- new Ajax.Request("backend.php", {
- parameters: {op: "rpc", subop: "sanityCheck"},
- onComplete: function(transport) {
- backend_sanity_check_callback(transport);
- } });
- });
-
- } catch (e) {
- exception_error("init", e);
- }
-}
-
-function validatePrefsReset() {
- try {
- var ok = confirm(__("Reset to defaults?"));
-
- if (ok) {
-
- query = "?op=pref-prefs&subop=reset-config";
- console.log(query);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- var msg = transport.responseText;
- if (msg.match("PREFS_THEME_CHANGED")) {
- window.location.reload();
- } else {
- notify_info(msg);
- selectTab();
- }
- } });
-
- }
-
- } catch (e) {
- exception_error("validatePrefsReset", e);
- }
-
- return false;
-
-}
-
-
-function pref_hotkey_handler(e) {
- try {
- if (e.target.nodeName == "INPUT") return;
-
- var keycode = false;
- var shift_key = false;
-
- var cmdline = $('cmdline');
-
- try {
- shift_key = e.shiftKey;
- } catch (e) {
-
- }
-
- if (window.event) {
- keycode = window.event.keyCode;
- } else if (e) {
- keycode = e.which;
- }
-
- var keychar = String.fromCharCode(keycode);
-
- if (keycode == 27) { // escape
- if (Element.visible("hotkey_help_overlay")) {
- Element.hide("hotkey_help_overlay");
- }
- hotkey_prefix = false;
- closeInfoBox();
- }
-
- if (keycode == 16) return; // ignore lone shift
- if (keycode == 17) return; // ignore lone ctrl
-
- if ((keycode == 67 || keycode == 71) && !hotkey_prefix) {
- hotkey_prefix = keycode;
-
- var date = new Date();
- var ts = Math.round(date.getTime() / 1000);
-
- hotkey_prefix_pressed = ts;
-
- cmdline.innerHTML = keychar;
- Element.show(cmdline);
-
- console.log("KP: PREFIX=" + keycode + " CHAR=" + keychar);
- return;
- }
-
- if (Element.visible("hotkey_help_overlay")) {
- Element.hide("hotkey_help_overlay");
- }
-
- if (keycode == 13 || keycode == 27) {
- seq = "";
- } else {
- seq = seq + "" + keycode;
- }
-
- /* Global hotkeys */
-
- Element.hide(cmdline);
-
- if (!hotkey_prefix) {
-
- if ((keycode == 191 || keychar == '?') && shift_key) { // ?
- if (!Element.visible("hotkey_help_overlay")) {
- //Element.show("hotkey_help_overlay");
- Effect.Appear("hotkey_help_overlay", {duration : 0.3, to: 0.9});
- } else {
- Element.hide("hotkey_help_overlay");
- }
- return false;
- }
-
- if (keycode == 191 || keychar == '/') { // /
- var search_boxes = new Array("label_search",
- "feed_search", "filter_search", "user_search", "feed_browser_search");
-
- for (var i = 0; i < search_boxes.length; i++) {
- var elem = $(search_boxes[i]);
- if (elem) {
- $(search_boxes[i]).focus();
- return false;
- }
- }
- }
- }
-
- /* Prefix c */
-
- if (hotkey_prefix == 67) { // c
- hotkey_prefix = false;
-
- if (keycode == 70) { // f
- quickAddFilter();
- return false;
- }
-
- if (keycode == 83) { // s
- quickAddFeed();
- return false;
- }
-
- if (keycode == 85) { // u
- // no-op
- }
-
- if (keycode == 67) { // c
- editFeedCats();
- return false;
- }
-
- if (keycode == 84 && shift_key) { // T
- feedBrowser();
- return false;
- }
-
- }
-
- /* Prefix g */
-
- if (hotkey_prefix == 71) { // g
-
- hotkey_prefix = false;
-
- if (keycode == 49 && $("genConfigTab")) { // 1
- selectTab("genConfig");
- return false;
- }
-
- if (keycode == 50 && $("feedConfigTab")) { // 2
- selectTab("feedConfig");
- return false;
- }
-
- if (keycode == 51 && $("filterConfigTab")) { // 4
- selectTab("filterConfig");
- return false;
- }
-
- if (keycode == 52 && $("labelConfigTab")) { // 5
- selectTab("labelConfig");
- return false;
- }
-
- if (keycode == 53 && $("userConfigTab")) { // 6
- selectTab("userConfig");
- return false;
- }
-
- if (keycode == 88) { // x
- return gotoMain();
- }
-
- }
-
- if ($("piggie")) {
- if (seq.match("8073717369")) {
- seq = "";
- piggie(true);
- } else {
- piggie(false);
- }
- }
-
- if (hotkey_prefix) {
- console.log("KP: PREFIX=" + hotkey_prefix + " CODE=" + keycode + " CHAR=" + keychar);
- } else {
- console.log("KP: CODE=" + keycode + " CHAR=" + keychar);
- }
-
- } catch (e) {
- exception_error("pref_hotkey_handler", e);
- }
-}
-
-function editFeedCats() {
- try {
- var query = "backend.php?op=pref-feeds&subop=editCats";
-
- if (dijit.byId("feedCatEditDlg"))
- dijit.byId("feedCatEditDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "feedCatEditDlg",
- title: __("Feed Categories"),
- style: "width: 600px",
- getSelectedCategories: function() {
- return getSelectedTableRowIds("prefFeedCatList");
- },
- removeSelected: function() {
- var sel_rows = this.getSelectedCategories();
-
- if (sel_rows.length > 0) {
- var ok = confirm(__("Remove selected categories?"));
-
- if (ok) {
- notify_progress("Removing selected categories...", true);
-
- var query = "?op=pref-feeds&subop=editCats&action=remove&ids="+
- param_escape(sel_rows.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
- dialog.attr('content', transport.responseText);
- updateFeedList();
- } });
-
- }
-
- } else {
- alert(__("No categories are selected."));
- }
- },
- addCategory: function() {
- if (this.validate()) {
- notify_progress("Creating category...");
-
- var query = "?op=pref-feeds&subop=editCats&action=add&cat=" +
- param_escape(this.attr('value').newcat);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
- dialog.attr('content', transport.responseText);
- updateFeedList();
- } });
- }
- },
- execute: function() {
- if (this.validate()) {
- }
- },
- href: query});
-
- dialog.show();
-
- } catch (e) {
- exception_error("editFeedCats", e);
- }
-}
-
-function showInactiveFeeds() {
- try {
- var query = "backend.php?op=dlg&id=inactiveFeeds";
-
- if (dijit.byId("inactiveFeedsDlg"))
- dijit.byId("inactiveFeedsDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "inactiveFeedsDlg",
- title: __("Feeds without recent updates"),
- style: "width: 600px",
- getSelectedFeeds: function() {
- return getSelectedTableRowIds("prefInactiveFeedList");
- },
- removeSelected: function() {
- var sel_rows = this.getSelectedFeeds();
-
- console.log(sel_rows);
-
- if (sel_rows.length > 0) {
- var ok = confirm(__("Remove selected feeds?"));
-
- if (ok) {
- notify_progress("Removing selected feeds...", true);
-
- var query = "?op=pref-feeds&subop=remove&ids="+
- param_escape(sel_rows.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
- dialog.hide();
- updateFeedList();
- } });
- }
-
- } else {
- alert(__("No feeds are selected."));
- }
- },
- execute: function() {
- if (this.validate()) {
- }
- },
- href: query});
-
- dialog.show();
-
- } catch (e) {
- exception_error("showInactiveFeeds", e);
- }
-
-}
-
-function opmlRegenKey() {
-
- try {
- var ok = confirm(__("Replace current OPML publishing address with a new one?"));
-
- if (ok) {
-
- notify_progress("Trying to change address...", true);
-
- var query = "?op=rpc&subop=regenOPMLKey";
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- var reply = JSON.parse(transport.responseText);
-
- var new_link = reply.link;
-
- var e = $('pub_opml_url');
-
- if (new_link) {
- e.href = new_link;
- e.innerHTML = new_link;
-
- new Effect.Highlight(e);
-
- notify('');
-
- } else {
- notify_error("Could not change feed URL.");
- }
- } });
- }
- } catch (e) {
- exception_error("opmlRegenKey", e);
- }
- return false;
-}
-
-function feedActionChange() {
- try {
- var chooser = $("feedActionChooser");
- var opid = chooser[chooser.selectedIndex].value;
-
- chooser.selectedIndex = 0;
- feedActionGo(opid);
- } catch (e) {
- exception_error("feedActionChange", e);
- }
-}
-
-function feedActionGo(op) {
- try {
- if (op == "facEdit") {
-
- var rows = getSelectedFeeds();
-
- if (rows.length > 1) {
- editSelectedFeeds();
- } else {
- editSelectedFeed();
- }
- }
-
- if (op == "facClear") {
- clearSelectedFeeds();
- }
-
- if (op == "facPurge") {
- purgeSelectedFeeds();
- }
-
- if (op == "facEditCats") {
- editFeedCats();
- }
-
- if (op == "facRescore") {
- rescoreSelectedFeeds();
- }
-
- if (op == "facUnsubscribe") {
- removeSelectedFeeds();
- }
-
- } catch (e) {
- exception_error("feedActionGo", e);
-
- }
-}
-
-function clearFeedArticles(feed_id) {
-
- notify_progress("Clearing feed...");
-
- var query = "?op=pref-feeds&quiet=1&subop=clear&id=" + feed_id;
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
- } });
-
- return false;
-}
-
-function rescoreSelectedFeeds() {
-
- var sel_rows = getSelectedFeeds();
-
- if (sel_rows.length > 0) {
-
- //var ok = confirm(__("Rescore last 100 articles in selected feeds?"));
- var ok = confirm(__("Rescore articles in selected feeds?"));
-
- if (ok) {
- notify_progress("Rescoring selected feeds...", true);
-
- var query = "?op=pref-feeds&subop=rescore&quiet=1&ids="+
- param_escape(sel_rows.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify_callback2(transport);
- } });
-
- }
- } else {
- alert(__("No feeds are selected."));
- }
-
- return false;
-}
-
-function rescore_all_feeds() {
- var ok = confirm(__("Rescore all articles? This operation may take a lot of time."));
-
- if (ok) {
- notify_progress("Rescoring feeds...", true);
-
- var query = "?op=pref-feeds&subop=rescoreAll&quiet=1";
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify_callback2(transport);
- } });
- }
-}
-
-function labelColorReset() {
- try {
- var labels = getSelectedLabels();
-
- if (labels.length > 0) {
- var ok = confirm(__("Reset selected labels to default colors?"));
-
- if (ok) {
- var query = "?op=pref-labels&subop=color-reset&ids="+
- param_escape(labels.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- labellist_callback2(transport);
- } });
- }
-
- } else {
- alert(__("No labels are selected."));
- }
-
- } catch (e) {
- exception_error("labelColorReset", e);
- }
-}
-
-
-function inPreferences() {
- return true;
-}
-
-function editProfiles() {
- try {
-
- if (dijit.byId("profileEditDlg"))
- dijit.byId("profileEditDlg").destroyRecursive();
-
- var query = "backend.php?op=dlg&id=editPrefProfiles";
-
- dialog = new dijit.Dialog({
- id: "profileEditDlg",
- title: __("Settings Profiles"),
- style: "width: 600px",
- getSelectedProfiles: function() {
- return getSelectedTableRowIds("prefFeedProfileList");
- },
- removeSelected: function() {
- var sel_rows = this.getSelectedProfiles();
-
- if (sel_rows.length > 0) {
- var ok = confirm(__("Remove selected profiles? Active and default profiles will not be removed."));
-
- if (ok) {
- notify_progress("Removing selected profiles...", true);
-
- var query = "?op=rpc&subop=remprofiles&ids="+
- param_escape(sel_rows.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
- editProfiles();
- } });
-
- }
-
- } else {
- alert(__("No profiles are selected."));
- }
- },
- activateProfile: function() {
- var sel_rows = this.getSelectedProfiles();
-
- if (sel_rows.length == 1) {
-
- var ok = confirm(__("Activate selected profile?"));
-
- if (ok) {
- notify_progress("Loading, please wait...");
-
- var query = "?op=rpc&subop=setprofile&id="+
- param_escape(sel_rows.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- window.location.reload();
- } });
- }
-
- } else {
- alert(__("Please choose a profile to activate."));
- }
- },
- addProfile: function() {
- if (this.validate()) {
- notify_progress("Creating profile...", true);
-
- var query = "?op=rpc&subop=addprofile&title=" +
- param_escape(dialog.attr('value').newprofile);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
- editProfiles();
- } });
-
- }
- },
- execute: function() {
- if (this.validate()) {
- }
- },
- href: query});
-
- dialog.show();
- } catch (e) {
- exception_error("editProfiles", e);
- }
-}
-
-function activatePrefProfile() {
-
- var sel_rows = getSelectedFeedCats();
-
- if (sel_rows.length == 1) {
-
- var ok = confirm(__("Activate selected profile?"));
-
- if (ok) {
- notify_progress("Loading, please wait...");
-
- var query = "?op=rpc&subop=setprofile&id="+
- param_escape(sel_rows.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- window.location.reload();
- } });
- }
-
- } else {
- alert(__("Please choose a profile to activate."));
- }
-
- return false;
-}
-
-function clearFeedAccessKeys() {
-
- var ok = confirm(__("This will invalidate all previously generated feed URLs. Continue?"));
-
- if (ok) {
- notify_progress("Clearing URLs...");
-
- var query = "?op=rpc&subop=clearKeys";
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify_info("Generated URLs cleared.");
- } });
- }
-
- return false;
-}
-
-function clearArticleAccessKeys() {
-
- var ok = confirm(__("This will invalidate all previously shared article URLs. Continue?"));
-
- if (ok) {
- notify_progress("Clearing URLs...");
-
- var query = "?op=rpc&subop=clearArticleKeys";
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify_info("Shared URLs cleared.");
- } });
- }
-
- return false;
-}
-function resetFeedOrder() {
- try {
- notify_progress("Loading, please wait...");
-
- new Ajax.Request("backend.php", {
- parameters: "?op=pref-feeds&subop=feedsortreset",
- onComplete: function(transport) {
- updateFeedList();
- } });
-
-
- } catch (e) {
- exception_error("resetFeedOrder");
- }
-}
-
-function resetCatOrder() {
- try {
- notify_progress("Loading, please wait...");
-
- new Ajax.Request("backend.php", {
- parameters: "?op=pref-feeds&subop=catsortreset",
- onComplete: function(transport) {
- updateFeedList();
- } });
-
-
- } catch (e) {
- exception_error("resetCatOrder");
- }
-}
-
-function editCat(id, item, event) {
- try {
- var new_name = prompt(__('Rename category to:'), item.name);
-
- if (new_name && new_name != item.name) {
-
- notify_progress("Loading, please wait...");
-
- new Ajax.Request("backend.php", {
- parameters: {
- op: 'pref-feeds',
- subop: 'renamecat',
- id: id,
- title: new_name,
- },
- onComplete: function(transport) {
- updateFeedList();
- } });
- }
-
- } catch (e) {
- exception_error("editCat", e);
- }
-}
-
-function editLabel(id, event) {
- try {
- var query = "backend.php?op=pref-labels&subop=edit&id=" +
- param_escape(id);
-
- if (dijit.byId("labelEditDlg"))
- dijit.byId("labelEditDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "labelEditDlg",
- title: __("Label Editor"),
- style: "width: 600px",
- setLabelColor: function(id, fg, bg) {
-
- var kind = '';
- var color = '';
-
- if (fg && bg) {
- kind = 'both';
- } else if (fg) {
- kind = 'fg';
- color = fg;
- } else if (bg) {
- kind = 'bg';
- color = bg;
- }
-
- var query = "?op=pref-labels&subop=color-set&kind="+kind+
- "&ids=" + param_escape(id) + "&fg=" + param_escape(fg) +
- "&bg=" + param_escape(bg) + "&color=" + param_escape(color);
-
- // console.log(query);
-
- var e = $("LICID-" + id);
-
- if (e) {
- if (fg) e.style.color = fg;
- if (bg) e.style.backgroundColor = bg;
- }
-
- new Ajax.Request("backend.php", { parameters: query });
-
- updateFilterList();
- },
- execute: function() {
- if (this.validate()) {
- var caption = this.attr('value').caption;
- var fg_color = this.attr('value').fg_color;
- var bg_color = this.attr('value').bg_color;
- var query = dojo.objectToQuery(this.attr('value'));
-
- dijit.byId('labelTree').setNameById(id, caption);
- this.setLabelColor(id, fg_color, bg_color);
- this.hide();
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- updateFilterList();
- } });
- }
- },
- href: query});
-
- dialog.show();
-
- } catch (e) {
- exception_error("editLabel", e);
- }
-}
-
-function clearTwitterCredentials() {
- try {
- var ok = confirm(__("This will clear your stored authentication information for Twitter. Continue?"));
-
- if (ok) {
- notify_progress("Clearing credentials...");
-
- var query = "?op=pref-feeds&subop=remtwitterinfo";
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify_info("Twitter credentials have been cleared.");
- updateFeedList();
- } });
- }
-
- } catch (e) {
- exception_error("clearTwitterCredentials", e);
- }
-}
-
-function customizeCSS() {
- try {
- var query = "backend.php?op=dlg&id=customizeCSS";
-
- if (dijit.byId("cssEditDlg"))
- dijit.byId("cssEditDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "cssEditDlg",
- title: __("Customize stylesheet"),
- style: "width: 600px",
- execute: function() {
- notify_progress('Saving data...', true);
- new Ajax.Request("backend.php", {
- parameters: dojo.objectToQuery(this.attr('value')),
- onComplete: function(transport) {
- notify('');
- window.location.reload();
- } });
-
- },
- href: query});
-
- dialog.show();
-
- } catch (e) {
- exception_error("customizeCSS", e);
- }
-}
-
-function insertSSLserial(value) {
- try {
- dijit.byId("SSL_CERT_SERIAL").attr('value', value);
- } catch (e) {
- exception_error("insertSSLcerial", e);
- }
-}
-
-function getSelectedInstances() {
- return getSelectedTableRowIds("prefInstanceList");
-}
-
-function addInstance() {
- try {
- var query = "backend.php?op=dlg&id=addInstance";
-
- if (dijit.byId("instanceAddDlg"))
- dijit.byId("instanceAddDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "instanceAddDlg",
- title: __("Link Instance"),
- style: "width: 600px",
- regenKey: function() {
- new Ajax.Request("backend.php", {
- parameters: "?op=rpc&subop=genHash",
- onComplete: function(transport) {
- var reply = JSON.parse(transport.responseText);
- if (reply)
- dijit.byId('instance_add_key').attr('value', reply.hash);
-
- } });
- },
- execute: function() {
- if (this.validate()) {
- console.warn(dojo.objectToQuery(this.attr('value')));
-
- notify_progress('Saving data...', true);
- new Ajax.Request("backend.php", {
- parameters: dojo.objectToQuery(this.attr('value')),
- onComplete: function(transport) {
- dialog.hide();
- notify('');
- updateInstanceList();
- } });
- }
- },
- href: query,
- });
-
- dialog.show();
-
- } catch (e) {
- exception_error("addInstance", e);
- }
-}
-
-function editInstance(id, event) {
- try {
- if (!event || !event.ctrlKey) {
-
- selectTableRows('prefInstanceList', 'none');
- selectTableRowById('LIRR-'+id, 'LICHK-'+id, true);
-
- var query = "backend.php?op=pref-instances&subop=edit&id=" +
- param_escape(id);
-
- if (dijit.byId("instanceEditDlg"))
- dijit.byId("instanceEditDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "instanceEditDlg",
- title: __("Edit Instance"),
- style: "width: 600px",
- regenKey: function() {
- new Ajax.Request("backend.php", {
- parameters: "?op=rpc&subop=genHash",
- onComplete: function(transport) {
- var reply = JSON.parse(transport.responseText);
- if (reply)
- dijit.byId('instance_edit_key').attr('value', reply.hash);
-
- } });
- },
- execute: function() {
- if (this.validate()) {
-// console.warn(dojo.objectToQuery(this.attr('value')));
-
- notify_progress('Saving data...', true);
- new Ajax.Request("backend.php", {
- parameters: dojo.objectToQuery(this.attr('value')),
- onComplete: function(transport) {
- dialog.hide();
- notify('');
- updateInstanceList();
- } });
- }
- },
- href: query,
- });
-
- dialog.show();
-
- } else if (event.ctrlKey) {
- var cb = $('LICHK-' + id);
- cb.checked = !cb.checked;
- toggleSelectRow(cb);
- }
-
-
- } catch (e) {
- exception_error("editInstance", e);
- }
-}
-
-function removeSelectedInstances() {
- try {
- var sel_rows = getSelectedInstances();
-
- if (sel_rows.length > 0) {
-
- var ok = confirm(__("Remove selected instances?"));
-
- if (ok) {
- notify_progress("Removing selected instances...");
-
- var query = "?op=pref-instances&subop=remove&ids="+
- param_escape(sel_rows.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
- updateInstanceList();
- } });
- }
-
- } else {
- alert(__("No instances are selected."));
- }
-
- } catch (e) {
- exception_error("removeInstance", e);
- }
-}
-
-function editSelectedInstance() {
- var rows = getSelectedInstances();
-
- if (rows.length == 0) {
- alert(__("No instances are selected."));
- return;
- }
-
- if (rows.length > 1) {
- alert(__("Please select only one instance."));
- return;
- }
-
- notify("");
-
- editInstance(rows[0]);
-}
-
<?php
+ set_include_path(get_include_path() . PATH_SEPARATOR . "include");
+
require_once "functions.php";
require_once "sessions.php";
require_once "sanity_check.php";
<script type="text/javascript" charset="utf-8" src="localized_js.php?<?php echo $dt_add ?>"></script>
- <script type="text/javascript" charset="utf-8" src="functions.js?<?php echo $dt_add ?>"></script>
- <script type="text/javascript" charset="utf-8" src="deprecated.js?<?php echo $dt_add ?>"></script>
-
- <script type="text/javascript" charset="utf-8" src="prefs.js?<?php echo $dt_add ?>"></script>
+ <script type="text/javascript" charset="utf-8" src="js/functions.js?<?php echo $dt_add ?>"></script>
+ <script type="text/javascript" charset="utf-8" src="js/deprecated.js?<?php echo $dt_add ?>"></script>
+ <script type="text/javascript" charset="utf-8" src="js/prefs.js?<?php echo $dt_add ?>"></script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
// 1) templates/register_notice.txt - displayed above the registration form
// 2) register_expire_do.php - contains user expiration queries when necessary
+ set_include_path(get_include_path() . PATH_SEPARATOR . "include");
+
require_once 'lib/phpmailer/class.phpmailer.php';
$action = $_REQUEST["action"];
<title>Create new account</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="utility.css">
-<script type="text/javascript" src="functions.js"></script>
+<script type="text/javascript" src="js/functions.js"></script>
<script type="text/javascript" src="lib/prototype.js"></script>
<script type="text/javascript" src="lib/scriptaculous/scriptaculous.js?load=effects,dragdrop,controls"></script>
</head>
</table>
</form>
- <?php print "<p><form method=\"GET\" action=\"tt-rss.php\">
+ <?php print "<p><form method=\"GET\" action=\"index.php\">
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
</form>"; ?>
if (!$login || !$email || !$test) {
print_error(__("Your registration information is incomplete."));
- print "<p><form method=\"GET\" action=\"tt-rss.php\">
+ print "<p><form method=\"GET\" action=\"index.php\">
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
</form>";
return;
if ($is_registered) {
print_error(__('Sorry, this username is already taken.'));
- print "<p><form method=\"GET\" action=\"tt-rss.php\">
+ print "<p><form method=\"GET\" action=\"index.php\">
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
</form>";
} else {
if (db_num_rows($result) != 1) {
print_error(__('Registration failed.'));
- print "<p><form method=\"GET\" action=\"tt-rss.php\">
+ print "<p><form method=\"GET\" action=\"index.php\">
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
</form>";
} else {
print_notice(__("Account created successfully."));
- print "<p><form method=\"GET\" action=\"tt-rss.php\">
+ print "<p><form method=\"GET\" action=\"index.php\">
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
</form>";
} else {
print_error('Plese check the form again, you have failed the robot test.');
- print "<p><form method=\"GET\" action=\"tt-rss.php\">
+ print "<p><form method=\"GET\" action=\"index.php\">
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
</form>";
<?php print_notice(__('New user registrations are currently closed.')) ?>
- <?php print "<p><form method=\"GET\" action=\"tt-rss.php\">
+ <?php print "<p><form method=\"GET\" action=\"index.php\">
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
</form>"; ?>
+++ /dev/null
-<?php
- require_once "functions.php";
-
- define('EXPECTED_CONFIG_VERSION', 23);
- define('SCHEMA_VERSION', 86);
-
- if (!file_exists("config.php")) {
- print "<b>Fatal Error</b>: You forgot to copy
- <b>config.php-dist</b> to <b>config.php</b> and edit it.\n";
- exit;
- }
-
- require_once "config.php";
- require_once "sanity_config.php";
-
- if (CONFIG_VERSION != EXPECTED_CONFIG_VERSION) {
- $err_msg = "config: your config file version is incorrect. See config.php-dist.\n";
- }
-
- $purifier_cache_dir = CACHE_DIR . "/htmlpurifier";
-
- if (!is_writable($purifier_cache_dir)) {
- $err_msg = "config: HTMLPurifier cache directory should be writable by anyone (chmod -R 777 $purifier_cache_dir)";
- }
-
- if (GENERATED_CONFIG_CHECK != EXPECTED_CONFIG_VERSION) {
- $err_msg = "config: your sanity_config.php is outdated, please recreate it using ./utils/regen_config_checks.sh";
- }
-
- foreach ($requred_defines as $d) {
- if (!defined($d)) {
- $err_msg = "config: required constant $d is not defined. Please check config.php";
- }
- }
-
- if (defined('RSS_BACKEND_TYPE')) {
- print "<b>Fatal error</b>: RSS_BACKEND_TYPE is deprecated. Please remove this
- option from config.php\n";
- exit;
- }
-
- if (file_exists("xml-export.php") || file_exists("xml-import.php")) {
- print "<b>Fatal Error</b>: XML Import/Export tools (<b>xml-export.php</b>
- and <b>xml-import.php</b>) could be used maliciously. Please remove them
- from your TT-RSS instance.\n";
- exit;
- }
-
- if (SINGLE_USER_MODE && DAEMON_UPDATE_LOGIN_LIMIT > 0) {
- print "<b>Fatal Error</b>: Please set DAEMON_UPDATE_LOGIN_LIMIT
- to 0 in single user mode.\n";
- exit;
- }
-
- if (!defined('SESSION_EXPIRE_TIME')) {
- $err_msg = "config: SESSION_EXPIRE_TIME is undefined";
- }
-
- if (SESSION_EXPIRE_TIME < 60) {
- $err_msg = "config: SESSION_EXPIRE_TIME is too low (less than 60)";
- }
-
- if (SESSION_EXPIRE_TIME < SESSION_COOKIE_LIFETIME) {
- $err_msg = "config: SESSION_EXPIRE_TIME should be greater or equal to" .
- "SESSION_COOKIE_LIFETIME";
- }
-
-/* if (defined('DISABLE_SESSIONS')) {
- $err_msg = "config: you have enabled DISABLE_SESSIONS. Please disable this option.";
-} */
-
- if (DATABASE_BACKED_SESSIONS && SINGLE_USER_MODE) {
- $err_msg = "config: DATABASE_BACKED_SESSIONS is incompatible with SINGLE_USER_MODE";
- }
-
- if (DATABASE_BACKED_SESSIONS && DB_TYPE == "mysql") {
- $err_msg = "config: DATABASE_BACKED_SESSIONS are currently broken with MySQL";
- }
-
- if (SINGLE_USER_MODE) {
- $link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
-
- if ($link) {
- $result = db_query($link, "SELECT id FROM ttrss_users WHERE id = 1");
-
- if (db_num_rows($result) != 1) {
- $err_msg = "config: SINGLE_USER_MODE is enabled but default admin account (UID=1) is not found.";
- }
- }
- }
-
- if (defined('MAIL_FROM')) {
- $err_msg = "config: MAIL_FROM has been split into DIGEST_FROM_NAME and DIGEST_FROM_ADDRESS";
- }
-
- if (!defined('COUNTERS_MAX_AGE')) {
- $err_msg = "config: option COUNTERS_MAX_AGE expected, but not defined";
- }
-
- if (defined('DAEMON_REFRESH_ONLY')) {
- $err_msg = "config: option DAEMON_REFRESH_ONLY is obsolete. Please remove this option and read about other ways to update feeds on the <a href='http://tt-rss.org/wiki/UpdatingFeeds'>wiki</a>.";
-
- }
-
- if (defined('ENABLE_SIMPLEPIE')) {
- $err_msg = "config: ENABLE_SIMPLEPIE is obsolete and replaced with DEFAULT_UPDATE_METHOD. Please adjust your config.php.";
- }
-
- if (!defined('DEFAULT_UPDATE_METHOD') || (DEFAULT_UPDATE_METHOD != 0 &&
- DEFAULT_UPDATE_METHOD != 1)) {
- $err_msg = "config: DEFAULT_UPDATE_METHOD should be either 0 or 1.";
- }
-
- if (SELF_URL_PATH == "http://yourserver/tt-rss/") {
- $err_msg = "config: please set SELF_URL_PATH to the correct value.";
- }
-
- if (!is_writable(ICONS_DIR)) {
- $err_msg = "config: your ICONS_DIR (" . ICONS_DIR . ") is not writable.\n";
- }
-
- if (ini_get("open_basedir")) {
- $err_msg = "php.ini: open_basedir is not supported.";
- }
-
- if (!function_exists("curl_init") && !ini_get("allow_url_fopen")) {
- $err_msg = "php.ini: either allow_url_fopen or CURL needs to be enabled.";
- }
-
- if (!function_exists("json_encode")) {
- $err_msg = "PHP: json functions not found.";
- }
-
- if (DB_TYPE == "mysql" && !function_exists("mysql_connect")) {
- $err_msg = "PHP: MySQL functions not found.";
- }
-
- if (DB_TYPE == "pgsql" && !function_exists("pg_connect")) {
- $err_msg = "PHP: PostgreSQL functions not found.";
- }
-
- if (!function_exists("mb_strlen")) {
- $err_msg = "PHP: mbstring functions not found.";
- }
-
- if (!function_exists("ctype_lower")) {
- $err_msg = "PHP: ctype functions not found (required for HTMLPurifier).";
- }
-
- if (ini_get("safe_mode")) {
- $err_msg = "php.ini: Safe mode is not supported. If you wish to continue, remove this test from sanity_check.php and proceeed at your own risk. Please note that your bug reports will not be accepted or reviewed.";
- }
-
- if ((PUBSUBHUBBUB_HUB || PUBSUBHUBBUB_ENABLED) && !function_exists("curl_init")) {
- $err_msg = "CURL is required for PubSubHubbub support.";
- }
-
- if (!class_exists("DOMDocument")) {
- $err_msg = "PHP: DOMDocument extension not found.";
- }
-
- if (SELF_URL_PATH == "http://local.host/tt-rss") {
- $err_msg = "config: please set SELF_URL_PATH to the correct value";
- }
-
- if (!ISCONFIGURED) {
- $err_msg = "config: please read config.php completely.";
- }
-
- if ($err_msg) {
- print "<b>Fatal Error</b>: $err_msg\n";
- exit;
- }
-
-?>
+++ /dev/null
-<?php # This file has been generated at: Tue Apr 26 18:40:48 MSD 2011
-define('GENERATED_CONFIG_CHECK', 23);
-$requred_defines = array( 'DB_TYPE', 'DB_HOST', 'DB_USER', 'DB_NAME', 'DB_PASS', 'SELF_URL_PATH', 'SINGLE_USER_MODE', 'CACHE_DIR', 'SIMPLEPIE_CACHE_IMAGES', 'ICONS_DIR', 'ICONS_URL', 'TMP_DIRECTORY', 'DAEMON_SLEEP_INTERVAL', 'DATABASE_BACKED_SESSIONS', 'SESSION_CHECK_ADDRESS', 'SESSION_COOKIE_LIFETIME', 'SESSION_EXPIRE_TIME', 'DAEMON_UPDATE_LOGIN_LIMIT', 'CHECK_FOR_NEW_VERSION', 'DIGEST_ENABLE', 'DIGEST_EMAIL_LIMIT', 'DAEMON_SENDS_DIGESTS', 'MYSQL_CHARSET', 'DEFAULT_UPDATE_METHOD', 'COUNTERS_MAX_AGE', 'DIGEST_FROM_NAME', 'DIGEST_FROM_ADDRESS', 'DIGEST_SUBJECT', 'DIGEST_SMTP_HOST', 'DIGEST_SMTP_LOGIN', 'DIGEST_SMTP_PASSWORD', 'DAEMON_FEED_LIMIT', 'ALLOW_REMOTE_USER_AUTH', 'AUTO_LOGIN', 'AUTO_CREATE_USER', 'LOCK_DIRECTORY', 'ENABLE_GZIP_OUTPUT', 'PHP_EXECUTABLE', 'ENABLE_REGISTRATION', 'REG_NOTIFY_ADDRESS', 'REG_MAX_USERS', 'FEEDBACK_URL', 'FORCE_ARTICLE_PURGE', 'SPHINX_ENABLED', 'SPHINX_INDEX', 'ENABLE_TWEET_BUTTON', 'CONSUMER_KEY', 'CONSUMER_SECRET', 'PUBSUBHUBBUB_HUB', 'PUBSUBHUBBUB_ENABLED', 'ISCONFIGURED', 'CONFIG_VERSION'); ?>
+++ /dev/null
-<?php
- // Original from http://www.daniweb.com/code/snippet43.html
-
- require_once "config.php";
- require_once "db.php";
-
- $session_expire = SESSION_EXPIRE_TIME; //seconds
- $session_name = (!defined('TTRSS_SESSION_NAME')) ? "ttrss_sid" : TTRSS_SESSION_NAME;
-
- if ($_SERVER['HTTPS'] == "on") {
- $session_name .= "_ssl";
- ini_set("session.cookie_secure", true);
- }
-
- ini_set("session.gc_probability", 50);
- ini_set("session.name", $session_name);
- ini_set("session.use_only_cookies", true);
- ini_set("session.gc_maxlifetime", SESSION_EXPIRE_TIME);
-
- function ttrss_open ($s, $n) {
-
- global $session_connection;
-
- $session_connection = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
-
- return true;
- }
-
- function ttrss_read ($id){
-
- global $session_connection,$session_read;
-
- $query = "SELECT data FROM ttrss_sessions WHERE id='$id'";
-
- $res = db_query($session_connection, $query);
-
- if (db_num_rows($res) != 1) {
- return "";
- } else {
- $session_read = db_fetch_assoc($res);
- $session_read["data"] = base64_decode($session_read["data"]);
- return $session_read["data"];
- }
- }
-
- function ttrss_write ($id, $data) {
-
- if (! $data) {
- return false;
- }
-
- global $session_connection, $session_read, $session_expire;
-
- $expire = time() + $session_expire;
-
- $data = db_escape_string(base64_encode($data), $session_connection);
-
- if ($session_read) {
- $query = "UPDATE ttrss_sessions SET data='$data',
- expire='$expire' WHERE id='$id'";
- } else {
- $query = "INSERT INTO ttrss_sessions (id, data, expire)
- VALUES ('$id', '$data', '$expire')";
- }
-
- db_query($session_connection, $query);
- return true;
- }
-
- function ttrss_close () {
-
- global $session_connection;
-
- db_close($session_connection);
-
- return true;
- }
-
- function ttrss_destroy ($id) {
-
- global $session_connection;
-
- $query = "DELETE FROM ttrss_sessions WHERE id = '$id'";
-
- db_query($session_connection, $query);
-
- return true;
- }
-
- function ttrss_gc ($expire) {
-
- global $session_connection;
-
- $query = "DELETE FROM ttrss_sessions WHERE expire < " . time();
-
- db_query($session_connection, $query);
- }
-
- if (DATABASE_BACKED_SESSIONS) {
- session_set_save_handler("ttrss_open",
- "ttrss_close", "ttrss_read", "ttrss_write",
- "ttrss_destroy", "ttrss_gc");
- }
-
- session_set_cookie_params(SESSION_COOKIE_LIFETIME);
-
- session_start();
-?>
+++ /dev/null
-var total_unread = 0;
-var global_unread = -1;
-var firsttime_update = true;
-var _active_feed_id = 0;
-var _active_feed_is_cat = false;
-var hotkey_prefix = false;
-var hotkey_prefix_pressed = false;
-var init_params = {};
-var _force_scheduled_update = false;
-var last_scheduled_update = false;
-
-var _rpc_seq = 0;
-
-function next_seq() {
- _rpc_seq += 1;
- return _rpc_seq;
-}
-
-function get_seq() {
- return _rpc_seq;
-}
-
-function activeFeedIsCat() {
- return _active_feed_is_cat;
-}
-
-function getActiveFeedId() {
- try {
- //console.log("gAFID: " + _active_feed_id);
- return _active_feed_id;
- } catch (e) {
- exception_error("getActiveFeedId", e);
- }
-}
-
-function setActiveFeedId(id, is_cat) {
- try {
- _active_feed_id = id;
-
- if (is_cat != undefined) {
- _active_feed_is_cat = is_cat;
- }
-
- selectFeed(id, is_cat);
-
- } catch (e) {
- exception_error("setActiveFeedId", e);
- }
-}
-
-
-function updateFeedList() {
- try {
-
-// $("feeds-holder").innerHTML = "<div id=\"feedlistLoading\">" +
-// __("Loading, please wait...") + "</div>";
-
- Element.show("feedlistLoading");
-
- if (dijit.byId("feedTree")) {
- dijit.byId("feedTree").destroyRecursive();
- }
-
- var store = new dojo.data.ItemFileWriteStore({
- url: "backend.php?op=feeds"});
-
- var treeModel = new fox.FeedStoreModel({
- store: store,
- query: {
- "type": "feed"
- },
- rootId: "root",
- rootLabel: "Feeds",
- childrenAttrs: ["items"]
- });
-
- var tree = new fox.FeedTree({
- persist: false,
- model: treeModel,
- onOpen: function (item, node) {
- var id = String(item.id);
- var cat_id = id.substr(id.indexOf(":")+1);
-
- new Ajax.Request("backend.php",
- { parameters: "backend.php?op=feeds&subop=collapse&cid=" +
- param_escape(cat_id) + "&mode=0" } );
- },
- onClose: function (item, node) {
- var id = String(item.id);
- var cat_id = id.substr(id.indexOf(":")+1);
-
- new Ajax.Request("backend.php",
- { parameters: "backend.php?op=feeds&subop=collapse&cid=" +
- param_escape(cat_id) + "&mode=1" } );
-
- },
- onClick: function (item, node) {
- var id = String(item.id);
- var is_cat = id.match("^CAT:");
- var feed = id.substr(id.indexOf(":")+1);
- viewfeed(feed, '', is_cat);
- return false;
- },
- openOnClick: false,
- showRoot: false,
- id: "feedTree",
- }, "feedTree");
-
-/* var menu = new dijit.Menu({id: 'feedMenu'});
-
- menu.addChild(new dijit.MenuItem({
- label: "Simple menu item"
- }));
-
-// menu.bindDomNode(tree.domNode); */
-
- var tmph = dojo.connect(dijit.byId('feedMenu'), '_openMyself', function (event) {
- console.log(dijit.getEnclosingWidget(event.target));
- dojo.disconnect(tmph);
- });
-
- $("feeds-holder").appendChild(tree.domNode);
-
- var tmph = dojo.connect(tree, 'onLoad', function() {
- dojo.disconnect(tmph);
- Element.hide("feedlistLoading");
-
- tree.collapseHiddenCats();
-
- feedlist_init();
-
-// var node = dijit.byId("feedTree")._itemNodesMap['FEED:-2'][0].domNode
-// menu.bindDomNode(node);
-
- loading_set_progress(25);
- });
-
- tree.startup();
-
- } catch (e) {
- exception_error("updateFeedList", e);
- }
-}
-
-function catchupAllFeeds() {
-
- var str = __("Mark all articles as read?");
-
- if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
-
- var query_str = "backend.php?op=feeds&subop=catchupAll";
-
- notify_progress("Marking all feeds as read...");
-
- //console.log("catchupAllFeeds Q=" + query_str);
-
- new Ajax.Request("backend.php", {
- parameters: query_str,
- onComplete: function(transport) {
- feedlist_callback2(transport);
- } });
-
- global_unread = 0;
- updateTitle("");
- }
-}
-
-function viewCurrentFeed(subop) {
-
- if (getActiveFeedId() != undefined) {
- viewfeed(getActiveFeedId(), subop, activeFeedIsCat());
- }
- return false; // block unneeded form submits
-}
-
-function timeout() {
- if (getInitParam("bw_limit") == "1") return;
-
- try {
- var date = new Date();
- var ts = Math.round(date.getTime() / 1000);
-
- if (ts - last_scheduled_update > 10 || _force_scheduled_update) {
-
- //console.log("timeout()");
-
- window.clearTimeout(counter_timeout_id);
-
- var query_str = "?op=rpc&subop=getAllCounters&seq=" + next_seq();
-
- var omode;
-
- if (firsttime_update && !navigator.userAgent.match("Opera")) {
- firsttime_update = false;
- omode = "T";
- } else {
- omode = "flc";
- }
-
- query_str = query_str + "&omode=" + omode;
-
- if (!_force_scheduled_update)
- query_str = query_str + "&last_article_id=" + getInitParam("last_article_id");
-
- //console.log("[timeout]" + query_str);
-
- new Ajax.Request("backend.php", {
- parameters: query_str,
- onComplete: function(transport) {
- handle_rpc_json(transport, !_force_scheduled_update);
- _force_scheduled_update = false;
- } });
-
- last_scheduled_update = ts;
- }
-
- } catch (e) {
- exception_error("timeout", e);
- }
-
- setTimeout("timeout()", 3000);
-}
-
-function search() {
- var query = "backend.php?op=dlg&id=search¶m=" +
- param_escape(getActiveFeedId() + ":" + activeFeedIsCat());
-
- if (dijit.byId("searchDlg"))
- dijit.byId("searchDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "searchDlg",
- title: __("Search"),
- style: "width: 600px",
- execute: function() {
- if (this.validate()) {
- _search_query = dojo.objectToQuery(this.attr('value'));
- this.hide();
- viewCurrentFeed();
- }
- },
- href: query});
-
- dialog.show();
-}
-
-function updateTitle() {
- var tmp = "Tiny Tiny RSS";
-
- if (global_unread > 0) {
- tmp = tmp + " (" + global_unread + ")";
- }
-
- if (window.fluid) {
- if (global_unread > 0) {
- window.fluid.dockBadge = global_unread;
- } else {
- window.fluid.dockBadge = "";
- }
- }
-
- document.title = tmp;
-}
-
-function genericSanityCheck() {
- setCookie("ttrss_test", "TEST");
-
- if (getCookie("ttrss_test") != "TEST") {
- return fatalError(2);
- }
-
- return true;
-}
-
-function init() {
- try {
- dojo.registerModulePath("fox", "../..");
-
- dojo.require("fox.FeedTree");
-
- if (typeof themeBeforeLayout == 'function') {
- themeBeforeLayout();
- }
-
- dojo.parser.parse();
-
- dojo.addOnLoad(function() {
- updateFeedList();
- closeArticlePanel();
-
- if (typeof themeAfterLayout == 'function') {
- themeAfterLayout();
- }
-
- });
-
- if (!genericSanityCheck())
- return false;
-
- loading_set_progress(20);
-
- var hasAudio = !!((myAudioTag = document.createElement('audio')).canPlayType);
-
- new Ajax.Request("backend.php", {
- parameters: {op: "rpc", subop: "sanityCheck", hasAudio: hasAudio},
- onComplete: function(transport) {
- backend_sanity_check_callback(transport);
- } });
-
- } catch (e) {
- exception_error("init", e);
- }
-}
-
-function init_second_stage() {
-
- try {
-
- delCookie("ttrss_test");
-
- var toolbar = document.forms["main_toolbar_form"];
-
- dijit.getEnclosingWidget(toolbar.view_mode).attr('value',
- getInitParam("default_view_mode"));
-
- dijit.getEnclosingWidget(toolbar.order_by).attr('value',
- getInitParam("default_view_order_by"));
-
- feeds_sort_by_unread = getInitParam("feeds_sort_by_unread") == 1;
-
- loading_set_progress(30);
-
- // can't use cache_clear() here because viewfeed might not have initialized yet
- if ('sessionStorage' in window && window['sessionStorage'] !== null)
- sessionStorage.clear();
-
- console.log("second stage ok");
-
- } catch (e) {
- exception_error("init_second_stage", e);
- }
-}
-
-function quickMenuGo(opid) {
- try {
- if (opid == "qmcPrefs") {
- gotoPreferences();
- }
-
- if (opid == "qmcTagCloud") {
- displayDlg("printTagCloud");
- }
-
- if (opid == "qmcTagSelect") {
- displayDlg("printTagSelect");
- }
-
- if (opid == "qmcSearch") {
- search();
- return;
- }
-
- if (opid == "qmcAddFeed") {
- quickAddFeed();
- return;
- }
-
- if (opid == "qmcDigest") {
- window.location.href = "digest.php";
- return;
- }
-
- if (opid == "qmcEditFeed") {
- if (activeFeedIsCat())
- alert(__("You can't edit this kind of feed."));
- else
- editFeed(getActiveFeedId());
- return;
- }
-
- if (opid == "qmcRemoveFeed") {
- var actid = getActiveFeedId();
-
- if (activeFeedIsCat()) {
- alert(__("You can't unsubscribe from the category."));
- return;
- }
-
- if (!actid) {
- alert(__("Please select some feed first."));
- return;
- }
-
- var fn = getFeedName(actid);
-
- var pr = __("Unsubscribe from %s?").replace("%s", fn);
-
- if (confirm(pr)) {
- unsubscribeFeed(actid);
- }
-
- return;
- }
-
- if (opid == "qmcCatchupAll") {
- catchupAllFeeds();
- return;
- }
-
- if (opid == "qmcShowOnlyUnread") {
- toggleDispRead();
- return;
- }
-
- if (opid == "qmcAddFilter") {
- quickAddFilter();
- return;
- }
-
- if (opid == "qmcAddLabel") {
- addLabel();
- return;
- }
-
- if (opid == "qmcRescoreFeed") {
- rescoreCurrentFeed();
- return;
- }
-
- if (opid == "qmcHKhelp") {
- //Element.show("hotkey_help_overlay");
- Effect.Appear("hotkey_help_overlay", {duration : 0.3});
- }
-
- if (opid == "qmcAbout") {
- dialog = new dijit.Dialog({
- title: __("About..."),
- style: "width: 400px",
- href: "backend.php?op=dlg&id=about",
- });
-
- dialog.show();
- }
-
- } catch (e) {
- exception_error("quickMenuGo", e);
- }
-}
-
-function toggleDispRead() {
- try {
-
- var hide = !(getInitParam("hide_read_feeds") == "1");
-
- hideOrShowFeeds(hide);
-
- var query = "?op=rpc&subop=setpref&key=HIDE_READ_FEEDS&value=" +
- param_escape(hide);
-
- setInitParam("hide_read_feeds", hide);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- } });
-
- } catch (e) {
- exception_error("toggleDispRead", e);
- }
-}
-
-function parse_runtime_info(data) {
-
- //console.log("parsing runtime info...");
-
- for (k in data) {
- var v = data[k];
-
-// console.log("RI: " + k + " => " + v);
-
- if (k == "new_version_available") {
- var icon = $("newVersionIcon");
- if (icon) {
- if (v == "1") {
- icon.style.display = "inline";
- } else {
- icon.style.display = "none";
- }
- }
- return;
- }
-
- if (k == "daemon_is_running" && v != 1) {
- notify_error("<span onclick=\"javascript:explainError(1)\">Update daemon is not running.</span>", true);
- return;
- }
-
- if (k == "daemon_stamp_ok" && v != 1) {
- notify_error("<span onclick=\"javascript:explainError(3)\">Update daemon is not updating feeds.</span>", true);
- return;
- }
-
- if (k == "max_feed_id" || k == "num_feeds") {
- if (init_params[k] != v) {
- console.log("feed count changed, need to reload feedlist.");
- updateFeedList();
- }
- }
-
- init_params[k] = v;
- notify('');
- }
-}
-
-function catchupCurrentFeed() {
-
- var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
-
- var str = __("Mark all articles in %s as read?").replace("%s", fn);
-
- if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
- return viewCurrentFeed('MarkAllRead');
- }
-}
-
-function catchupFeedInGroup(id) {
-
- try {
-
- var title = getFeedName(id);
-
- var str = __("Mark all articles in %s as read?").replace("%s", title);
-
- if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
- return viewCurrentFeed('MarkAllReadGR:' + id);
- }
-
- } catch (e) {
- exception_error("catchupFeedInGroup", e);
- }
-}
-
-function collapse_feedlist() {
- try {
-
- if (!Element.visible('feeds-holder')) {
- Element.show('feeds-holder');
- Element.show('feeds-holder_splitter');
- $("collapse_feeds_btn").innerHTML = "<<";
- } else {
- Element.hide('feeds-holder');
- Element.hide('feeds-holder_splitter');
- $("collapse_feeds_btn").innerHTML = ">>";
- }
-
- dijit.byId("main").resize();
-
- query = "?op=rpc&subop=setpref&key=_COLLAPSED_FEEDLIST&value=true";
- new Ajax.Request("backend.php", { parameters: query });
-
- } catch (e) {
- exception_error("collapse_feedlist", e);
- }
-}
-
-function viewModeChanged() {
- return viewCurrentFeed('');
-}
-
-function viewLimitChanged() {
- return viewCurrentFeed('');
-}
-
-/* function adjustArticleScore(id, score) {
- try {
-
- var pr = prompt(__("Assign score to article:"), score);
-
- if (pr != undefined) {
- var query = "?op=rpc&subop=setScore&id=" + id + "&score=" + pr;
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- viewCurrentFeed();
- } });
-
- }
- } catch (e) {
- exception_error("adjustArticleScore", e);
- }
-} */
-
-function rescoreCurrentFeed() {
-
- var actid = getActiveFeedId();
-
- if (activeFeedIsCat() || actid < 0) {
- alert(__("You can't rescore this kind of feed."));
- return;
- }
-
- if (!actid) {
- alert(__("Please select some feed first."));
- return;
- }
-
- var fn = getFeedName(actid);
- var pr = __("Rescore articles in %s?").replace("%s", fn);
-
- if (confirm(pr)) {
- notify_progress("Rescoring articles...");
-
- var query = "?op=pref-feeds&subop=rescore&quiet=1&ids=" + actid;
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- viewCurrentFeed();
- } });
- }
-}
-
-function hotkey_handler(e) {
- try {
-
- if (e.target.nodeName == "INPUT" || e.target.nodeName == "TEXTAREA") return;
-
- var keycode = false;
- var shift_key = false;
-
- var cmdline = $('cmdline');
-
- try {
- shift_key = e.shiftKey;
- } catch (e) {
-
- }
-
- if (window.event) {
- keycode = window.event.keyCode;
- } else if (e) {
- keycode = e.which;
- }
-
- var keychar = String.fromCharCode(keycode);
-
- if (keycode == 27) { // escape
- if (Element.visible("hotkey_help_overlay")) {
- Element.hide("hotkey_help_overlay");
- }
- hotkey_prefix = false;
- }
-
- if (keycode == 16) return; // ignore lone shift
- if (keycode == 17) return; // ignore lone ctrl
-
- if ((keycode == 70 || keycode == 67 || keycode == 71 || keycode == 65)
- && !hotkey_prefix) {
-
- var date = new Date();
- var ts = Math.round(date.getTime() / 1000);
-
- hotkey_prefix = keycode;
- hotkey_prefix_pressed = ts;
-
- cmdline.innerHTML = keychar;
- Element.show(cmdline);
-
- console.log("KP: PREFIX=" + keycode + " CHAR=" + keychar + " TS=" + ts);
- return true;
- }
-
- if (Element.visible("hotkey_help_overlay")) {
- Element.hide("hotkey_help_overlay");
- }
-
- /* Global hotkeys */
-
- Element.hide(cmdline);
-
- if (!hotkey_prefix) {
-
- if (keycode == 27) { // escape
- closeArticlePanel();
- return;
- }
-
- if (keycode == 69) { // e
- var id = getActiveArticleId();
- emailArticle(id);
- }
-
- if ((keycode == 191 || keychar == '?') && shift_key) { // ?
- if (!Element.visible("hotkey_help_overlay")) {
- Effect.Appear("hotkey_help_overlay", {duration : 0.3, to : 0.9});
- } else {
- Element.hide("hotkey_help_overlay");
- }
- return false;
- }
-
- if (keycode == 191 || keychar == '/') { // /
- search();
- return false;
- }
-
- if (keycode == 74 && !shift_key) { // j
- var rv = dijit.byId("feedTree").getPreviousFeed(
- getActiveFeedId(), activeFeedIsCat());
-
- if (rv) viewfeed(rv[0], '', rv[1]);
-
- return;
- }
-
- if (keycode == 75) { // k
- var rv = dijit.byId("feedTree").getNextFeed(
- getActiveFeedId(), activeFeedIsCat());
-
- if (rv) viewfeed(rv[0], '', rv[1]);
-
- return;
- }
-
- if (shift_key && keycode == 40) { // shift-down
- catchupRelativeToArticle(1);
- return;
- }
-
- if (shift_key && keycode == 38) { // shift-up
- catchupRelativeToArticle(0);
- return;
- }
-
- if (shift_key && keycode == 78) { // N
- scrollArticle(50);
- return;
- }
-
- if (shift_key && keycode == 80) { // P
- scrollArticle(-50);
- return;
- }
-
- if (keycode == 68 && shift_key) { // shift-D
- dismissSelectedArticles();
- return;
- }
-
- if (keycode == 88 && shift_key) { // shift-X
- dismissReadArticles();
- return;
- }
-
- if (keycode == 78 || keycode == 40) { // n, down
- if (typeof moveToPost != 'undefined') {
- moveToPost('next');
- return false;
- }
- }
-
- if (keycode == 80 || keycode == 38) { // p, up
- if (typeof moveToPost != 'undefined') {
- moveToPost('prev');
- return false;
- }
- }
-
- if (keycode == 83 && shift_key) { // S
- selectionTogglePublished(undefined, false, true);
- return;
- }
-
- if (keycode == 83) { // s
- selectionToggleMarked(undefined, false, true);
- return;
- }
-
- if (keycode == 85) { // u
- selectionToggleUnread(undefined, false, true);
- return;
- }
-
- if (keycode == 84 && shift_key) { // T
- var id = getActiveArticleId();
- if (id) {
- editArticleTags(id, getActiveFeedId(), isCdmMode());
- return;
- }
- }
-
- if (keycode == 9) { // tab
- var id = getArticleUnderPointer();
- if (id) {
- var cb = $("RCHK-" + id);
-
- if (cb) {
- cb.checked = !cb.checked;
- toggleSelectRowById(cb, "RROW-" + id);
- return false;
- }
- }
- }
-
- if (keycode == 79) { // o
- if (getActiveArticleId()) {
- openArticleInNewWindow(getActiveArticleId());
- return;
- }
- }
-
- if (keycode == 81 && shift_key) { // Q
- if (typeof catchupAllFeeds != 'undefined') {
- catchupAllFeeds();
- return;
- }
- }
-
- if (keycode == 88 && !shift_key) { // x
- if (activeFeedIsCat()) {
- dijit.byId("feedTree").collapseCat(getActiveFeedId());
- return;
- }
- }
- }
-
- /* Prefix a */
-
- if (hotkey_prefix == 65) { // a
- hotkey_prefix = false;
-
- if (keycode == 65) { // a
- selectArticles('all');
- return;
- }
-
- if (keycode == 85) { // u
- selectArticles('unread');
- return;
- }
-
- if (keycode == 73) { // i
- selectArticles('invert');
- return;
- }
-
- if (keycode == 78) { // n
- selectArticles('none');
- return;
- }
-
- }
-
- /* Prefix f */
-
- if (hotkey_prefix == 70) { // f
-
- hotkey_prefix = false;
-
- if (keycode == 81) { // q
- if (getActiveFeedId()) {
- catchupCurrentFeed();
- return;
- }
- }
-
- if (keycode == 82) { // r
- if (getActiveFeedId()) {
- viewfeed(getActiveFeedId(), '', activeFeedIsCat());
- return;
- }
- }
-
- if (keycode == 65) { // a
- toggleDispRead();
- return false;
- }
-
- if (keycode == 85) { // u
- if (getActiveFeedId()) {
- viewfeed(getActiveFeedId(), '');
- return false;
- }
- }
-
- if (keycode == 69) { // e
-
- if (activeFeedIsCat())
- alert(__("You can't edit this kind of feed."));
- else
- editFeed(getActiveFeedId());
- return;
-
- return false;
- }
-
- if (keycode == 83) { // s
- quickAddFeed();
- return false;
- }
-
- if (keycode == 67 && shift_key) { // C
- if (typeof catchupAllFeeds != 'undefined') {
- catchupAllFeeds();
- return false;
- }
- }
-
- if (keycode == 67) { // c
- if (getActiveFeedId()) {
- catchupCurrentFeed();
- return false;
- }
- }
-
- if (keycode == 88) { // x
- reverseHeadlineOrder();
- return;
- }
- }
-
- /* Prefix c */
-
- if (hotkey_prefix == 67) { // c
- hotkey_prefix = false;
-
- if (keycode == 70) { // f
- quickAddFilter();
- return false;
- }
-
- if (keycode == 76) { // l
- addLabel();
- return false;
- }
-
- if (keycode == 83) { // s
- if (typeof collapse_feedlist != 'undefined') {
- collapse_feedlist();
- return false;
- }
- }
-
- if (keycode == 77) { // m
- // TODO: sortable feedlist
- return;
- }
-
- if (keycode == 78) { // n
- catchupRelativeToArticle(1);
- return;
- }
-
- if (keycode == 80) { // p
- catchupRelativeToArticle(0);
- return;
- }
-
-
- }
-
- /* Prefix g */
-
- if (hotkey_prefix == 71) { // g
-
- hotkey_prefix = false;
-
-
- if (keycode == 65) { // a
- viewfeed(-4);
- return false;
- }
-
- if (keycode == 83) { // s
- viewfeed(-1);
- return false;
- }
-
- if (keycode == 80 && shift_key) { // P
- gotoPreferences();
- return false;
- }
-
- if (keycode == 80) { // p
- viewfeed(-2);
- return false;
- }
-
- if (keycode == 70) { // f
- viewfeed(-3);
- return false;
- }
-
- if (keycode == 84) { // t
- displayDlg("printTagCloud");
- return false;
- }
- }
-
- /* Cmd */
-
- if (hotkey_prefix == 224 || hotkey_prefix == 91) { // f
- hotkey_prefix = false;
- return;
- }
-
- if (hotkey_prefix) {
- console.log("KP: PREFIX=" + hotkey_prefix + " CODE=" + keycode + " CHAR=" + keychar);
- } else {
- console.log("KP: CODE=" + keycode + " CHAR=" + keychar);
- }
-
-
- } catch (e) {
- exception_error("hotkey_handler", e);
- }
-}
-
-function inPreferences() {
- return false;
-}
-
-function reverseHeadlineOrder() {
- try {
-
- var query_str = "?op=rpc&subop=togglepref&key=REVERSE_HEADLINES";
-
- new Ajax.Request("backend.php", {
- parameters: query_str,
- onComplete: function(transport) {
- viewCurrentFeed();
- } });
-
- } catch (e) {
- exception_error("reverseHeadlineOrder", e);
- }
-}
-
-function scheduleFeedUpdate(id, is_cat) {
- try {
- if (!id) {
- id = getActiveFeedId();
- is_cat = activeFeedIsCat();
- }
-
- if (!id) {
- alert(__("Please select some feed first."));
- return;
- }
-
- var query = "?op=rpc&subop=scheduleFeedUpdate&id=" +
- param_escape(id) +
- "&is_cat=" + param_escape(is_cat);
-
- console.log(query);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
-
- var reply = JSON.parse(transport.responseText);
- var message = reply['message'];
-
- if (message) {
- notify_info(message);
- return;
- }
-
- } });
-
-
- } catch (e) {
- exception_error("scheduleFeedUpdate", e);
- }
-}
-
-function newVersionDlg() {
- try {
- var query = "backend.php?op=dlg&id=newVersion";
-
- if (dijit.byId("newVersionDlg"))
- dijit.byId("newVersionDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "newVersionDlg",
- title: __("New version available!"),
- style: "width: 600px",
- href: query,
- });
-
- dialog.show();
-
- } catch (e) {
- exception_error("newVersionDlg", e);
- }
-}
-
-function handle_rpc_json(transport, scheduled_call) {
- try {
- var reply = JSON.parse(transport.responseText);
-
- if (reply) {
-
- var error = reply['error'];
-
- if (error) {
- var code = error['code'];
- var msg = error['msg'];
-
- console.warn("[handle_rpc_json] received fatal error " + code + "/" + msg);
-
- if (code != 0) {
- fatalError(code, msg);
- return false;
- }
- }
-
- var seq = reply['seq'];
-
- if (seq) {
- if (get_seq() != seq) {
- console.log("[handle_rpc_json] sequence mismatch: " + seq +
- " (want: " + get_seq() + ")");
- return true;
- }
- }
-
- var message = reply['message'];
-
- if (message) {
- if (message == "UPDATE_COUNTERS") {
- console.log("need to refresh counters...");
- setInitParam("last_article_id", -1);
- _force_scheduled_update = true;
- }
- }
-
- var counters = reply['counters'];
-
- if (counters)
- parse_counters(counters, scheduled_call);
-
- var runtime_info = reply['runtime-info'];;
-
- if (runtime_info)
- parse_runtime_info(runtime_info);
-
- hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
-
- } else {
- notify_error("Error communicating with server.");
- }
-
- } catch (e) {
- notify_error("Error communicating with server.");
- console.log(e);
- //exception_error("handle_rpc_json", e, transport);
- }
-
- return true;
-}
-
+++ /dev/null
-<?php
- require_once "functions.php";
- require_once "sessions.php";
- require_once "sanity_check.php";
- require_once "version.php";
- require_once "config.php";
- require_once "db-prefs.php";
-
- $link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
-
- init_connection($link);
-
- login_sequence($link);
-
- $dt_add = time();
-
- no_cache_incantation();
-
- header('Content-Type: text/html; charset=utf-8');
-
-?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html>
-<head>
- <title>Tiny Tiny RSS</title>
- <link rel="stylesheet" type="text/css" href="lib/dijit/themes/claro/claro.css"/>
- <link rel="stylesheet" type="text/css" href="tt-rss.css?<?php echo $dt_add ?>"/>
- <link rel="stylesheet" type="text/css" href="cdm.css?<?php echo $dt_add ?>"/>
-
- <?php print_theme_includes($link) ?>
- <?php print_user_stylesheet($link) ?>
-
- <link rel="shortcut icon" type="image/png" href="images/favicon.png"/>
-
- <script type="text/javascript" src="lib/prototype.js"></script>
- <script type="text/javascript" src="lib/scriptaculous/scriptaculous.js?load=effects,dragdrop,controls"></script>
- <script type="text/javascript" src="lib/dojo/dojo.js"></script>
- <script type="text/javascript" src="lib/dijit/dijit.js"></script>
- <script type="text/javascript" src="lib/dojo/tt-rss-layer.js"></script>
-
- <script type="text/javascript" charset="utf-8" src="localized_js.php?<?php echo $dt_add ?>"></script>
- <script type="text/javascript" charset="utf-8" src="tt-rss.js?<?php echo $dt_add ?>"></script>
- <script type="text/javascript" charset="utf-8" src="functions.js?<?php echo $dt_add ?>"></script>
- <script type="text/javascript" charset="utf-8" src="feedlist.js?<?php echo $dt_add ?>"></script>
- <script type="text/javascript" charset="utf-8" src="viewfeed.js?<?php echo $dt_add ?>"></script>
- <script type="text/javascript" charset="utf-8" src="errors.php?mode=js"></script>
-
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
-
- <script type="text/javascript">
- Event.observe(window, 'load', function() {
- init();
- });
- </script>
-</head>
-
-<body id="ttrssMain" class="claro">
-
-<div id="overlay" style="display : block">
- <div id="overlay_inner">
- <div class="insensitive"><?php echo __("Loading, please wait...") ?></div>
- <div dojoType="dijit.ProgressBar" places="0" style="width : 300px" id="loading_bar"
- progress="0" maximum="100">
- </div>
- <noscript><br/><?php print_error('Javascript is disabled. Please enable it.') ?></noscript>
- </div>
-</div>
-
-<div id="header">
- <?php if (!SINGLE_USER_MODE) { ?>
- <?php echo __('Hello,') ?> <b><?php echo $_SESSION["name"] ?></b> |
- <?php } ?>
- <a href="prefs.php"><?php echo __('Preferences') ?></a>
-
- <?php if (defined('FEEDBACK_URL') && FEEDBACK_URL) { ?>
- | <a target="_blank" class="feedback" href="<?php echo FEEDBACK_URL ?>">
- <?php echo __('Comments?') ?></a>
- <?php } ?>
-
- <?php if (!SINGLE_USER_MODE) { ?>
- | <a href="backend.php?op=logout"><?php echo __('Logout') ?></a>
- <?php } ?>
-
- <img id="newVersionIcon" style="display:none" onclick="newVersionDlg()"
- width="13" height="13"
- src="<?php echo theme_image($link, 'images/new_version.png') ?>"
- title="<?php echo __('New version of Tiny Tiny RSS is available!') ?>"
- alt="new_version_icon"/>
-</div>
-
-<div id="hotkey_help_overlay" style="display : none" onclick="Element.hide(this)">
- <?php include "help/3.php" ?>
-</div>
-
-<div id="notify" class="notify"><span id="notify_body"> </span></div>
-<div id="cmdline" style="display : none"></div>
-<div id="auxDlg" style="display : none"></div>
-<div id="headlines-tmp" style="display : none"></div>
-
-<div id="main" dojoType="dijit.layout.BorderContainer">
-
-<div id="feeds-holder" dojoType="dijit.layout.ContentPane" region="leading" style="width : 20%" splitter="true">
- <div id="feedlistLoading">
- <img src='images/indicator_tiny.gif'/>
- <?php echo __("Loading, please wait..."); ?></div>
- <div id="feedTree"></div>
-</div>
-
-<div dojoType="dijit.layout.BorderContainer" region="center" id="header-wrap" gutters="false">
-<div dojoType="dijit.layout.TabContainer" region="center" id="content-tabs">
-<div dojoType="dijit.layout.BorderContainer" region="center" id="content-wrap"
- title="<?php echo __("News") ?>">
-
-<div id="toolbar" dojoType="dijit.layout.ContentPane" region="top">
- <div id="main-toolbar" dojoType="dijit.Toolbar">
-
- <form id="main_toolbar_form" action="" onsubmit='return false'>
-
- <button dojoType="dijit.form.Button" id="collapse_feeds_btn"
- onclick="collapse_feedlist()"
- title="<?php echo __('Collapse feedlist') ?>" style="display : inline">
- <<</button>
-
- <select name="view_mode" title="<?php echo __('Show articles') ?>"
- onchange="viewModeChanged()"
- dojoType="dijit.form.Select">
- <option selected="selected" value="adaptive"><?php echo __('Adaptive') ?></option>
- <option value="all_articles"><?php echo __('All Articles') ?></option>
- <option value="marked"><?php echo __('Starred') ?></option>
- <option value="published"><?php echo __('Published') ?></option>
- <option value="unread"><?php echo __('Unread') ?></option>
- <!-- <option value="noscores"><?php echo __('Ignore Scoring') ?></option> -->
- <option value="updated"><?php echo __('Updated') ?></option>
- </select>
-
- <select title="<?php echo __('Sort articles') ?>"
- onchange="viewModeChanged()"
- dojoType="dijit.form.Select" name="order_by">
- <option selected="selected" value="default"><?php echo __('Default') ?></option>
- <option value="date"><?php echo __('Date') ?></option>
- <option value="title"><?php echo __('Title') ?></option>
- <option value="score"><?php echo __('Score') ?></option>
- </select>
-
- <button dojoType="dijit.form.Button" name="update"
- onclick="scheduleFeedUpdate()">
- <?php echo __('Update') ?></button>
-
- <button dojoType="dijit.form.Button"
- onclick="catchupCurrentFeed()">
- <?php echo __('Mark as read') ?></button>
-
- </form>
-
- <div class="actionChooser">
- <div dojoType="dijit.form.DropDownButton">
- <span><?php echo __('Actions...') ?></span>
- <div dojoType="dijit.Menu" style="display: none">
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcSearch')"><?php echo __('Search...') ?></div>
- <div dojoType="dijit.MenuItem" disabled="1"><?php echo __('Feed actions:') ?></div>
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcAddFeed')"><?php echo __('Subscribe to feed...') ?></div>
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcEditFeed')"><?php echo __('Edit this feed...') ?></div>
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcRescoreFeed')"><?php echo __('Rescore feed') ?></div>
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcRemoveFeed')"><?php echo __('Unsubscribe') ?></div>
- <div dojoType="dijit.MenuItem" disabled="1"><?php echo __('All feeds:') ?></div>
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcCatchupAll')"><?php echo __('Mark as read') ?></div>
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcShowOnlyUnread')"><?php echo __('(Un)hide read feeds') ?></div>
- <div dojoType="dijit.MenuItem" disabled="1"><?php echo __('Other actions:') ?></div>
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcDigest')"><?php echo __('Switch to digest...') ?></div>
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcTagCloud')"><?php echo __('Show tag cloud...') ?></div>
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcTagSelect')"><?php echo __('Select by tags...') ?></div>
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcAddLabel')"><?php echo __('Create label...') ?></div>
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcAddFilter')"><?php echo __('Create filter...') ?></div>
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcHKhelp')"><?php echo __('Keyboard shortcuts help') ?></div>
- <div dojoType="dijit.MenuItem" onclick="quickMenuGo('qmcAbout')"><?php echo __('About...') ?></div>
- </div>
- </div>
- </div>
- </div> <!-- toolbar -->
-</div> <!-- toolbar pane -->
-
- <div id="headlines-wrap-inner" dojoType="dijit.layout.BorderContainer" region="center">
-
- <div id="headlines-toolbar" dojoType="dijit.layout.ContentPane" region="top">
- </div>
-
- <div id="headlines-frame" dojoType="dijit.layout.ContentPane"
- onscroll="headlines_scroll_handler(this)" region="center">
- <div id="headlinesInnerContainer">
- <div class="whiteBox"><?php echo __('Loading, please wait...') ?></div>
- </div>
- </div>
-
- <?php if (!get_pref($link, 'COMBINED_DISPLAY_MODE')) { ?>
- <div id="content-insert" dojoType="dijit.layout.ContentPane" region="bottom"
- style="height : 50%" splitter="true"></div>
- <?php } ?>
-
- </div>
-</div>
-</div>
-</div>
-</div>
-
-<?php db_close($link); ?>
-
-</body>
-</html>
<?php
+ set_include_path(get_include_path() . PATH_SEPARATOR . "include");
+
require_once "functions.php";
require_once "sessions.php";
require_once "sanity_check.php";
//require_once "lib/twitteroauth/twitteroauth.php";
require_once "lib/tmhoauth/tmhOAuth.php";
- $link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
+ $link = db_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
- init_connection($link);
+ init_connection($link);
login_sequence($link);
-
+
$owner_uid = $_SESSION["uid"];
$op = $_REQUEST['op'];
- if (!SINGLE_USER_MODE && !$_SESSION['uid']) {
+ if (!SINGLE_USER_MODE && !$_SESSION['uid']) {
render_login_form($link);
exit;
}
$tmhOAuth = new tmhOAuth(array(
'consumer_key' => CONSUMER_KEY,
'consumer_secret' => CONSUMER_SECRET,
- ));
+ ));
if ($op == 'clear') {
unset($_SESSION['oauth']);
$code = $tmhOAuth->request('POST', $tmhOAuth->url('oauth/access_token', ''), array(
'oauth_verifier' => $_REQUEST['oauth_verifier']));
-
+
if ($code == 200) {
$access_token = json_encode($tmhOAuth->extract_params($tmhOAuth->response['response']));
if ($op == 'register') {
- $code = $tmhOAuth->request('POST',
+ $code = $tmhOAuth->request('POST',
$tmhOAuth->url('oauth/request_token', ''), array(
'oauth_callback' => $callback));
$force = isset($_REQUEST['force']) ? '&force_login=1' : '';
$forcewrite = isset($_REQUEST['force_write']) ? '&oauth_access_type=write' : '';
$forceread = isset($_REQUEST['force_read']) ? '&oauth_access_type=read' : '';
-
- $location = $tmhOAuth->url("oauth/{$method}", '') .
+
+ $location = $tmhOAuth->url("oauth/{$method}", '') .
"?oauth_token={$_SESSION['oauth']['oauth_token']}{$force}{$forcewrite}{$forceread}";
header("Location: $location");
#!/usr/bin/php
<?php
+ set_include_path(get_include_path() . PATH_SEPARATOR . "include");
+
define('DISABLE_SESSIONS', true);
chdir(dirname(__FILE__));
}
db_close($link);
-
+
if ($lock_handle != false) {
fclose($lock_handle);
}
#!/usr/bin/php
<?php
+ set_include_path(get_include_path() . PATH_SEPARATOR . "include");
+
// This is an experimental multiprocess update daemon.
// Some configurable variable may be found below.
+++ /dev/null
-<?php
- define('VERSION', "1.5.7");
-?>
+++ /dev/null
-var active_post_id = false;
-
-var article_cache = new Array();
-
-var vgroup_last_feed = false;
-var post_under_pointer = false;
-
-var last_requested_article = false;
-
-var catchup_id_batch = [];
-var catchup_timeout_id = false;
-var feed_precache_timeout_id = false;
-var precache_idle_timeout_id = false;
-
-var cids_requested = [];
-
-var has_storage = 'sessionStorage' in window && window['sessionStorage'] !== null;
-
-function headlines_callback2(transport, offset, background, infscroll_req) {
- try {
- handle_rpc_json(transport);
-
- loading_set_progress(25);
-
- console.log("headlines_callback2 [offset=" + offset + "] B:" + background + " I:" + infscroll_req);
-
- var is_cat = false;
- var feed_id = false;
-
- var reply = false;
-
- try {
- reply = JSON.parse(transport.responseText);
- } catch (e) {
- console.error(e);
- }
-
- if (reply) {
-
- is_cat = reply['headlines']['is_cat'];
- feed_id = reply['headlines']['id'];
-
- if (background) {
- var content = reply['headlines']['content'];
-
- if (getInitParam("cdm_auto_catchup") == 1) {
- content = content + "<div id='headlines-spacer'></div>";
- }
-
- cache_headlines(feed_id, is_cat, reply['headlines']['toolbar'], content);
- return;
- }
-
- setActiveFeedId(feed_id, is_cat);
-
- try {
- if (offset == 0 && infscroll_req == false) {
- $("headlines-frame").scrollTop = 0;
- }
- } catch (e) { };
-
- var headlines_count = reply['headlines-info']['count'];
-
- vgroup_last_feed = reply['headlines-info']['vgroup_last_feed'];
-
- if (parseInt(headlines_count) < getInitParam("default_article_limit")) {
- _infscroll_disable = 1;
- } else {
- _infscroll_disable = 0;
- }
-
- var counters = reply['counters'];
- var articles = reply['articles'];
- //var runtime_info = reply['runtime-info'];
-
- if (offset == 0 && infscroll_req == false) {
- dijit.byId("headlines-frame").attr('content',
- reply['headlines']['content']);
-
- dijit.byId("headlines-toolbar").attr('content',
- reply['headlines']['toolbar']);
-
-
- if (getInitParam("cdm_auto_catchup") == 1) {
- var hsp = $("headlines-spacer");
- if (!hsp) hsp = new Element("DIV", {"id": "headlines-spacer"});
- dijit.byId('headlines-frame').domNode.appendChild(hsp);
- }
-
- initHeadlinesMenu();
-
- } else {
-
- if (headlines_count > 0 && feed_id == getActiveFeedId() && is_cat == activeFeedIsCat()) {
- console.log("adding some more headlines...");
-
- var c = dijit.byId("headlines-frame");
- var ids = getSelectedArticleIds2();
-
- $("headlines-tmp").innerHTML = reply['headlines']['content'];
-
- var hsp = $("headlines-spacer");
-
- if (hsp)
- c.domNode.removeChild(hsp);
-
- $$("#headlines-tmp > div").each(function(row) {
- if ($$("#headlines-frame DIV[id="+row.id+"]").length == 0) {
- row.style.display = 'none';
- c.domNode.appendChild(row);
- } else {
- row.parentNode.removeChild(row);
- }
- });
-
- if (!hsp) hsp = new Element("DIV", {"id": "headlines-spacer"});
-
- fixHeadlinesOrder(getLoadedArticleIds());
-
- if (getInitParam("cdm_auto_catchup") == 1) {
- c.domNode.appendChild(hsp);
- }
-
- console.log("restore selected ids: " + ids);
-
- for (var i = 0; i < ids.length; i++) {
- markHeadline(ids[i]);
- }
-
- initHeadlinesMenu();
-
- $$("#headlines-frame > div[id*=RROW]").each(
- function(child) {
- if (!Element.visible(child))
- new Effect.Appear(child, { duration : 0.5 });
- });
-
- } else {
- console.log("no new headlines received");
-
- var hsp = $("headlines-spacer");
-
- if (hsp) hsp.innerHTML = "";
- }
- }
-
- if (headlines_count > 0)
- cache_headlines(feed_id, is_cat, reply['headlines']['toolbar'], $("headlines-frame").innerHTML);
-
- if (articles) {
- for (var i = 0; i < articles.length; i++) {
- var a_id = articles[i]['id'];
- cache_set("article:" + a_id, articles[i]['content']);
- }
- } else {
- console.log("no cached articles received");
- }
-
- // do not precache stuff after fresh feed
- if (feed_id != -3)
- precache_headlines();
-
- if (counters)
- parse_counters(counters);
- else
- request_counters();
-
- } else {
- console.error("Invalid object received: " + transport.responseText);
- dijit.byId("headlines-frame").attr('content', "<div class='whiteBox'>" +
- __('Could not update headlines (invalid object received - see error console for details)') +
- "</div>");
- }
-
- _infscroll_request_sent = 0;
-
- notify("");
-
- } catch (e) {
- exception_error("headlines_callback2", e, transport);
- }
-}
-
-function render_article(article) {
- try {
- dijit.byId("headlines-wrap-inner").addChild(
- dijit.byId("content-insert"));
-
- var c = dijit.byId("content-insert");
-
- try {
- c.domNode.scrollTop = 0;
- } catch (e) { };
-
- c.attr('content', article);
-
- correctHeadlinesOffset(getActiveArticleId());
-
- try {
- c.focus();
- } catch (e) { };
-
- } catch (e) {
- exception_error("render_article", e);
- }
-}
-
-function showArticleInHeadlines(id) {
-
- try {
-
- selectArticles("none");
-
- var crow = $("RROW-" + id);
-
- if (!crow) return;
-
- var article_is_unread = crow.hasClassName("Unread");
-
- crow.removeClassName("Unread");
-
- selectArticles('none');
-
- var upd_img_pic = $("FUPDPIC-" + id);
-
- var view_mode = false;
-
- try {
- view_mode = document.forms['main_toolbar_form'].view_mode;
- view_mode = view_mode[view_mode.selectedIndex].value;
- } catch (e) {
- //
- }
-
- if (upd_img_pic && (upd_img_pic.src.match("updated.png") ||
- upd_img_pic.src.match("fresh_sign.png"))) {
-
- upd_img_pic.src = "images/blank_icon.gif";
-
- cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
-
- } else if (article_is_unread && view_mode == "all_articles") {
- cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
- }
-
- markHeadline(id);
-
- if (article_is_unread)
- _force_scheduled_update = true;
-
- } catch (e) {
- exception_error("showArticleInHeadlines", e);
- }
-}
-
-function article_callback2(transport, id) {
- try {
- console.log("article_callback2 " + id);
-
- handle_rpc_json(transport);
-
- var reply = false;
-
- try {
- reply = JSON.parse(transport.responseText);
- } catch (e) {
- console.error(e);
- }
-
- if (reply) {
-
- var upic = $('FUPDPIC-' + id);
-
- if (upic) upic.src = 'images/blank_icon.gif';
-
- reply.each(function(article) {
- if (active_post_id == article['id']) {
- render_article(article['content']);
- }
- cids_requested.remove(article['id']);
-
- cache_set("article:" + article['id'], article['content']);
- });
-
-// if (id != last_requested_article) {
-// console.log("requested article id is out of sequence, aborting");
-// return;
-// }
-
- } else {
- console.error("Invalid object received: " + transport.responseText);
-
- render_article("<div class='whiteBox'>" +
- __('Could not display article (invalid object received - see error console for details)') + "</div>");
- }
-
- request_counters();
-
- try {
- if (!_infscroll_disable &&
- $$("#headlines-frame > div[id*=RROW]").last().hasClassName("Selected")) {
-
- loadMoreHeadlines();
- }
- } catch (e) {
- console.warn(e);
- }
-
- notify("");
- } catch (e) {
- exception_error("article_callback2", e, transport);
- }
-}
-
-function view(id) {
- try {
- console.log("loading article: " + id);
-
- var cached_article = cache_get("article:" + id);
-
- console.log("cache check result: " + (cached_article != false));
-
- hideAuxDlg();
-
- var query = "?op=view&id=" + param_escape(id);
-
- var neighbor_ids = getRelativePostIds(id);
-
- /* only request uncached articles */
-
- var cids_to_request = [];
-
- for (var i = 0; i < neighbor_ids.length; i++) {
- if (cids_requested.indexOf(neighbor_ids[i]) == -1)
- if (!cache_get("article:" + neighbor_ids[i])) {
- cids_to_request.push(neighbor_ids[i]);
- cids_requested.push(neighbor_ids[i]);
- }
- }
-
- console.log("additional ids: " + cids_to_request.toString());
-
- query = query + "&cids=" + cids_to_request.toString();
-
- var crow = $("RROW-" + id);
- var article_is_unread = crow.hasClassName("Unread");
-
- active_post_id = id;
- showArticleInHeadlines(id);
-
- precache_headlines();
-
- if (!cached_article) {
-
- var upic = $('FUPDPIC-' + id);
-
- if (upic) {
- upic.src = getInitParam("sign_progress");
- }
-
- } else if (cached_article && article_is_unread) {
-
- query = query + "&mode=prefetch";
-
- render_article(cached_article);
-
- } else if (cached_article) {
-
- query = query + "&mode=prefetch_old";
- render_article(cached_article);
-
- // if we don't need to request any relative ids, we might as well skip
- // the server roundtrip altogether
- if (cids_to_request.length == 0) {
-
- try {
- if (!_infscroll_disable &&
- $$("#headlines-frame > div[id*=RROW]").last().hasClassName("Selected")) {
-
- loadMoreHeadlines();
- }
- } catch (e) {
- console.warn(e);
- }
-
- return;
- }
- }
-
- last_requested_article = id;
-
- console.log(query);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- article_callback2(transport, id);
- } });
-
- return false;
-
- } catch (e) {
- exception_error("view", e);
- }
-}
-
-function toggleMark(id, client_only) {
- try {
- var query = "?op=rpc&id=" + id + "&subop=mark";
-
- var img = $("FMPIC-" + id);
-
- if (!img) return;
-
- if (img.src.match("mark_unset")) {
- img.src = img.src.replace("mark_unset", "mark_set");
- img.alt = __("Unstar article");
- query = query + "&mark=1";
-
- } else {
- img.src = img.src.replace("mark_set", "mark_unset");
- img.alt = __("Star article");
- query = query + "&mark=0";
- }
-
- cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
-
- if (!client_only) {
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- } });
- }
-
- } catch (e) {
- exception_error("toggleMark", e);
- }
-}
-
-function togglePub(id, client_only, no_effects, note) {
- try {
- var query = "?op=rpc&id=" + id + "&subop=publ";
-
- if (note != undefined) {
- query = query + "¬e=" + param_escape(note);
- } else {
- query = query + "¬e=undefined";
- }
-
- var img = $("FPPIC-" + id);
-
- if (!img) return;
-
- if (img.src.match("pub_unset") || note != undefined) {
- img.src = img.src.replace("pub_unset", "pub_set");
- img.alt = __("Unpublish article");
- query = query + "&pub=1";
-
- } else {
- img.src = img.src.replace("pub_set", "pub_unset");
- img.alt = __("Publish article");
-
- query = query + "&pub=0";
- }
-
- cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
-
- if (!client_only) {
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- } });
- }
-
- } catch (e) {
- exception_error("togglePub", e);
- }
-}
-
-function moveToPost(mode) {
-
- try {
-
- var rows = getVisibleArticleIds();
-
- var prev_id = false;
- var next_id = false;
-
- if (!$('RROW-' + active_post_id)) {
- active_post_id = false;
- }
-
- if (active_post_id == false) {
- next_id = getFirstVisibleHeadlineId();
- prev_id = getLastVisibleHeadlineId();
- } else {
- for (var i = 0; i < rows.length; i++) {
- if (rows[i] == active_post_id) {
- prev_id = rows[i-1];
- next_id = rows[i+1];
- }
- }
- }
-
- if (mode == "next") {
- if (next_id) {
- if (isCdmMode()) {
-
- cdmExpandArticle(next_id);
- cdmScrollToArticleId(next_id);
-
- } else {
- correctHeadlinesOffset(next_id);
- view(next_id, getActiveFeedId());
- }
- }
- }
-
- if (mode == "prev") {
- if (prev_id) {
- if (isCdmMode()) {
- cdmExpandArticle(prev_id);
- cdmScrollToArticleId(prev_id);
- } else {
- correctHeadlinesOffset(prev_id);
- view(prev_id, getActiveFeedId());
- }
- }
- }
-
- } catch (e) {
- exception_error("moveToPost", e);
- }
-}
-
-function toggleSelected(id, force_on) {
- try {
-
- var cb = $("RCHK-" + id);
- var row = $("RROW-" + id);
-
- if (row) {
- if (row.hasClassName('Selected') && !force_on) {
- row.removeClassName('Selected');
- if (cb) cb.checked = false;
- } else {
- row.addClassName('Selected');
- if (cb) cb.checked = true;
- }
- }
- } catch (e) {
- exception_error("toggleSelected", e);
- }
-}
-
-function toggleUnread_afh(effect) {
- try {
-
- var elem = effect.element;
- elem.style.backgroundColor = "";
-
- } catch (e) {
- exception_error("toggleUnread_afh", e);
- }
-}
-
-function toggleUnread(id, cmode, effect) {
- try {
-
- var row = $("RROW-" + id);
- if (row) {
- if (cmode == undefined || cmode == 2) {
- if (row.hasClassName("Unread")) {
- row.removeClassName("Unread");
-
- if (effect) {
- new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
- afterFinish: toggleUnread_afh,
- queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
- }
-
- } else {
- row.addClassName("Unread");
- }
-
- } else if (cmode == 0) {
-
- row.removeClassName("Unread");
-
- if (effect) {
- new Effect.Highlight(row, {duration: 1, startcolor: "#fff7d5",
- afterFinish: toggleUnread_afh,
- queue: { position:'end', scope: 'TMRQ-' + id, limit: 1 } } );
- }
-
- } else if (cmode == 1) {
- row.addClassName("Unread");
- }
-
- if (cmode == undefined) cmode = 2;
-
- var query = "?op=rpc&subop=catchupSelected" +
- "&cmode=" + param_escape(cmode) + "&ids=" + param_escape(id);
-
-// notify_progress("Loading, please wait...");
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- } });
-
- }
-
- } catch (e) {
- exception_error("toggleUnread", e);
- }
-}
-
-function selectionRemoveLabel(id, ids) {
- try {
-
- if (!ids) ids = getSelectedArticleIds2();
-
- if (ids.length == 0) {
- alert(__("No articles are selected."));
- return;
- }
-
- var query = "?op=rpc&subop=removeFromLabel&ids=" +
- param_escape(ids.toString()) + "&lid=" + param_escape(id);
-
- console.log(query);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- show_labels_in_headlines(transport);
- } });
-
- } catch (e) {
- exception_error("selectionAssignLabel", e);
-
- }
-}
-
-function selectionAssignLabel(id, ids) {
- try {
-
- if (!ids) ids = getSelectedArticleIds2();
-
- if (ids.length == 0) {
- alert(__("No articles are selected."));
- return;
- }
-
- var query = "?op=rpc&subop=assignToLabel&ids=" +
- param_escape(ids.toString()) + "&lid=" + param_escape(id);
-
- console.log(query);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- show_labels_in_headlines(transport);
- } });
-
- } catch (e) {
- exception_error("selectionAssignLabel", e);
-
- }
-}
-
-function selectionToggleUnread(set_state, callback, no_error) {
- try {
- var rows = getSelectedArticleIds2();
-
- if (rows.length == 0 && !no_error) {
- alert(__("No articles are selected."));
- return;
- }
-
- for (var i = 0; i < rows.length; i++) {
- var row = $("RROW-" + rows[i]);
- if (row) {
- if (set_state == undefined) {
- if (row.hasClassName("Unread")) {
- row.removeClassName("Unread");
- } else {
- row.addClassName("Unread");
- }
- }
-
- if (set_state == false) {
- row.removeClassName("Unread");
- }
-
- if (set_state == true) {
- row.addClassName("Unread");
- }
- }
- }
-
- if (rows.length > 0) {
-
- var cmode = "";
-
- if (set_state == undefined) {
- cmode = "2";
- } else if (set_state == true) {
- cmode = "1";
- } else if (set_state == false) {
- cmode = "0";
- }
-
- var query = "?op=rpc&subop=catchupSelected" +
- "&cmode=" + cmode + "&ids=" + param_escape(rows.toString());
-
- notify_progress("Loading, please wait...");
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- if (callback) callback(transport);
- } });
-
- }
-
- } catch (e) {
- exception_error("selectionToggleUnread", e);
- }
-}
-
-function selectionToggleMarked() {
- try {
-
- var rows = getSelectedArticleIds2();
-
- if (rows.length == 0) {
- alert(__("No articles are selected."));
- return;
- }
-
- for (var i = 0; i < rows.length; i++) {
- toggleMark(rows[i], true, true);
- }
-
- if (rows.length > 0) {
-
- var query = "?op=rpc&subop=markSelected&ids=" +
- param_escape(rows.toString()) + "&cmode=2";
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- } });
-
- }
-
- } catch (e) {
- exception_error("selectionToggleMarked", e);
- }
-}
-
-function selectionTogglePublished() {
- try {
-
- var rows = getSelectedArticleIds2();
-
- if (rows.length == 0) {
- alert(__("No articles are selected."));
- return;
- }
-
- for (var i = 0; i < rows.length; i++) {
- togglePub(rows[i], true, true);
- }
-
- if (rows.length > 0) {
-
- var query = "?op=rpc&subop=publishSelected&ids=" +
- param_escape(rows.toString()) + "&cmode=2";
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- } });
-
- }
-
- } catch (e) {
- exception_error("selectionToggleMarked", e);
- }
-}
-
-function getSelectedArticleIds2() {
-
- var rv = [];
-
- $$("#headlines-frame > div[id*=RROW][class*=Selected]").each(
- function(child) {
- rv.push(child.id.replace("RROW-", ""));
- });
-
- return rv;
-}
-
-function getLoadedArticleIds() {
- var rv = [];
-
- var children = $$("#headlines-frame > div[id*=RROW-]");
-
- children.each(function(child) {
- rv.push(child.id.replace("RROW-", ""));
- });
-
- return rv;
-
-}
-
-// mode = all,none,unread,invert
-function selectArticles(mode) {
- try {
-
- var children = $$("#headlines-frame > div[id*=RROW]");
-
- children.each(function(child) {
- var id = child.id.replace("RROW-", "");
- var cb = $("RCHK-" + id);
-
- if (mode == "all") {
- child.addClassName("Selected");
- cb.checked = true;
- } else if (mode == "unread") {
- if (child.hasClassName("Unread")) {
- child.addClassName("Selected");
- cb.checked = true;
- } else {
- child.removeClassName("Selected");
- cb.checked = false;
- }
- } else if (mode == "invert") {
- if (child.hasClassName("Selected")) {
- child.removeClassName("Selected");
- cb.checked = false;
- } else {
- child.addClassName("Selected");
- cb.checked = true;
- }
-
- } else {
- child.removeClassName("Selected");
- cb.checked = false;
- }
- });
-
- } catch (e) {
- exception_error("selectArticles", e);
- }
-}
-
-function catchupPage() {
-
- var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
-
- var str = __("Mark all visible articles in %s as read?");
-
- str = str.replace("%s", fn);
-
- if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
- return;
- }
-
- selectArticles('all');
- selectionToggleUnread(false, 'viewCurrentFeed()', true);
- selectArticles('none');
-}
-
-function deleteSelection() {
-
- try {
-
- var rows = getSelectedArticleIds2();
-
- if (rows.length == 0) {
- alert(__("No articles are selected."));
- return;
- }
-
- var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
- var str;
-
- if (getActiveFeedId() != 0) {
- str = __("Delete %d selected articles in %s?");
- } else {
- str = __("Delete %d selected articles?");
- }
-
- str = str.replace("%d", rows.length);
- str = str.replace("%s", fn);
-
- if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
- return;
- }
-
- query = "?op=rpc&subop=delete&ids=" + param_escape(rows);
-
- console.log(query);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- viewCurrentFeed();
- } });
-
- } catch (e) {
- exception_error("deleteSelection", e);
- }
-}
-
-function archiveSelection() {
-
- try {
-
- var rows = getSelectedArticleIds2();
-
- if (rows.length == 0) {
- alert(__("No articles are selected."));
- return;
- }
-
- var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
- var str;
- var op;
-
- if (getActiveFeedId() != 0) {
- str = __("Archive %d selected articles in %s?");
- op = "archive";
- } else {
- str = __("Move %d archived articles back?");
- op = "unarchive";
- }
-
- str = str.replace("%d", rows.length);
- str = str.replace("%s", fn);
-
- if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
- return;
- }
-
- query = "?op=rpc&subop="+op+"&ids=" + param_escape(rows);
-
- console.log(query);
-
- for (var i = 0; i < rows.length; i++) {
- cache_delete("article:" + rows[i]);
- }
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- viewCurrentFeed();
- } });
-
- } catch (e) {
- exception_error("archiveSelection", e);
- }
-}
-
-function catchupSelection() {
-
- try {
-
- var rows = getSelectedArticleIds2();
-
- if (rows.length == 0) {
- alert(__("No articles are selected."));
- return;
- }
-
- var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
-
- var str = __("Mark %d selected articles in %s as read?");
-
- str = str.replace("%d", rows.length);
- str = str.replace("%s", fn);
-
- if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) {
- return;
- }
-
- selectionToggleUnread(false, 'viewCurrentFeed()', true);
-
- } catch (e) {
- exception_error("catchupSelection", e);
- }
-}
-
-function editArticleTags(id) {
- var query = "backend.php?op=dlg&id=editArticleTags¶m=" + param_escape(id);
-
- if (dijit.byId("editTagsDlg"))
- dijit.byId("editTagsDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "editTagsDlg",
- title: __("Edit article Tags"),
- style: "width: 600px",
- execute: function() {
- if (this.validate()) {
- var query = dojo.objectToQuery(this.attr('value'));
-
- notify_progress("Saving article tags...", true);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
- dialog.hide();
-
- var data = JSON.parse(transport.responseText);
-
- if (data) {
- var tags_str = article.tags;
- var id = tags_str.id;
-
- var tags = $("ATSTR-" + id);
- var tooltip = dijit.byId("ATSTRTIP-" + id);
-
- if (tags) tags.innerHTML = tags_str.content;
- if (tooltip) tooltip.attr('label', tags_str.content_full);
-
- cache_delete("article:" + id);
- }
-
- }});
- }
- },
- href: query,
- });
-
- var tmph = dojo.connect(dialog, 'onLoad', function() {
- dojo.disconnect(tmph);
-
- new Ajax.Autocompleter('tags_str', 'tags_choices',
- "backend.php?op=rpc&subop=completeTags",
- { tokens: ',', paramName: "search" });
- });
-
- dialog.show();
-
-}
-
-function cdmScrollToArticleId(id) {
- try {
- var ctr = $("headlines-frame");
- var e = $("RROW-" + id);
-
- if (!e || !ctr) return;
-
- ctr.scrollTop = e.offsetTop;
-
- } catch (e) {
- exception_error("cdmScrollToArticleId", e);
- }
-}
-
-function getActiveArticleId() {
- return active_post_id;
-}
-
-function postMouseIn(id) {
- post_under_pointer = id;
-}
-
-function postMouseOut(id) {
- post_under_pointer = false;
-}
-
-function headlines_scroll_handler(e) {
- try {
- var hsp = $("headlines-spacer");
-
- if (!_infscroll_disable) {
- if (hsp && (e.scrollTop + e.offsetHeight > hsp.offsetTop) ||
- e.scrollTop + e.offsetHeight > e.scrollHeight - 100) {
-
- if (hsp)
- hsp.innerHTML = "<img src='images/indicator_tiny.gif'> " +
- __("Loading, please wait...");
-
- loadMoreHeadlines();
- return;
-
- }
- } else {
- if (hsp) hsp.innerHTML = "";
- }
-
- if (getInitParam("cdm_auto_catchup") == 1) {
-
- $$("#headlines-frame > div[id*=RROW][class*=Unread]").each(
- function(child) {
- if ($("headlines-frame").scrollTop >
- (child.offsetTop + child.offsetHeight/2)) {
-
- var id = child.id.replace("RROW-", "");
-
- if (catchup_id_batch.indexOf(id) == -1)
- catchup_id_batch.push(id);
-
- //console.log("auto_catchup_batch: " + catchup_id_batch.toString());
- }
- });
-
- if (catchup_id_batch.length > 0) {
- window.clearTimeout(catchup_timeout_id);
-
- if (!_infscroll_request_sent) {
- catchup_timeout_id = window.setTimeout('catchupBatchedArticles()',
- 2000);
- }
- }
- }
-
- } catch (e) {
- console.warn("headlines_scroll_handler: " + e);
- }
-}
-
-function catchupBatchedArticles() {
- try {
- if (catchup_id_batch.length > 0 && !_infscroll_request_sent) {
-
- var query = "?op=rpc&subop=catchupSelected" +
- "&cmode=0&ids=" + param_escape(catchup_id_batch.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
-
- catchup_id_batch.each(function(id) {
- var elem = $("RROW-" + id);
- if (elem) elem.removeClassName("Unread");
- });
-
- catchup_id_batch = [];
- } });
- }
-
- } catch (e) {
- exception_error("catchupBatchedArticles", e);
- }
-}
-
-function catchupRelativeToArticle(below, id) {
-
- try {
-
- if (!id) id = getActiveArticleId();
-
- if (!id) {
- alert(__("No article is selected."));
- return;
- }
-
- var visible_ids = getVisibleArticleIds();
-
- var ids_to_mark = new Array();
-
- if (!below) {
- for (var i = 0; i < visible_ids.length; i++) {
- if (visible_ids[i] != id) {
- var e = $("RROW-" + visible_ids[i]);
-
- if (e && e.hasClassName("Unread")) {
- ids_to_mark.push(visible_ids[i]);
- }
- } else {
- break;
- }
- }
- } else {
- for (var i = visible_ids.length-1; i >= 0; i--) {
- if (visible_ids[i] != id) {
- var e = $("RROW-" + visible_ids[i]);
-
- if (e && e.hasClassName("Unread")) {
- ids_to_mark.push(visible_ids[i]);
- }
- } else {
- break;
- }
- }
- }
-
- if (ids_to_mark.length == 0) {
- alert(__("No articles found to mark"));
- } else {
- var msg = __("Mark %d article(s) as read?").replace("%d", ids_to_mark.length);
-
- if (getInitParam("confirm_feed_catchup") != 1 || confirm(msg)) {
-
- for (var i = 0; i < ids_to_mark.length; i++) {
- var e = $("RROW-" + ids_to_mark[i]);
- e.removeClassName("Unread");
- }
-
- var query = "?op=rpc&subop=catchupSelected" +
- "&cmode=0" + "&ids=" + param_escape(ids_to_mark.toString());
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- } });
-
- }
- }
-
- } catch (e) {
- exception_error("catchupRelativeToArticle", e);
- }
-}
-
-function cdmExpandArticle(id) {
- try {
-
- hideAuxDlg();
-
- var elem = $("CICD-" + active_post_id);
-
- var upd_img_pic = $("FUPDPIC-" + id);
-
- if (upd_img_pic && (upd_img_pic.src.match("updated.png") ||
- upd_img_pic.src.match("fresh_sign.png"))) {
-
- upd_img_pic.src = "images/blank_icon.gif";
- }
-
- if (id == active_post_id && Element.visible(elem))
- return true;
-
- selectArticles("none");
-
- var old_offset = $("RROW-" + id).offsetTop;
-
- if (active_post_id && elem && !getInitParam("cdm_expanded")) {
- Element.hide(elem);
- Element.show("CEXC-" + active_post_id);
- }
-
- active_post_id = id;
-
- elem = $("CICD-" + id);
-
- if (!Element.visible(elem)) {
- Element.show(elem);
- Element.hide("CEXC-" + id);
-
- if ($("CWRAP-" + id).innerHTML == "") {
-
- $("FUPDPIC-" + id).src = "images/indicator_tiny.gif";
-
- $("CWRAP-" + id).innerHTML = "<div class=\"insensitive\">" +
- __("Loading, please wait...") + "</div>";
-
- var query = "?op=rpc&subop=cdmGetArticle&id=" + param_escape(id);
-
- var neighbor_ids = getRelativePostIds(id);
-
- /* only request uncached articles */
- var cids_to_request = [];
-
- for (var i = 0; i < neighbor_ids.length; i++) {
- if (cids_requested.indexOf(neighbor_ids[i]) == -1)
- if ($("CWRAP-" + neighbor_ids[i]).innerHTML == "") {
- cids_to_request.push(neighbor_ids[i]);
- cids_requested.push(neighbor_ids[i]);
- }
- }
-
- console.log("additional ids: " + cids_to_request.toString());
-
- query = query + "&cids=" + cids_to_request.toString();
-
- console.log(query);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
-
- $("FUPDPIC-" + id).src = 'images/blank_icon.gif';
-
- handle_rpc_json(transport);
-
- var reply = JSON.parse(transport.responseText);
-
- reply.each(function(article) {
- $("CWRAP-" + article['id']).innerHTML = article['content'];
- cids_requested.remove(article['id']);
- });
- }});
-
- }
- }
-
- var new_offset = $("RROW-" + id).offsetTop;
-
- $("headlines-frame").scrollTop += (new_offset-old_offset);
-
- if ($("RROW-" + id).offsetTop != old_offset)
- $("headlines-frame").scrollTop = new_offset;
-
- toggleUnread(id, 0, true);
- toggleSelected(id);
-
- } catch (e) {
- exception_error("cdmExpandArticle", e);
- }
-
- return false;
-}
-
-function fixHeadlinesOrder(ids) {
- try {
- for (var i = 0; i < ids.length; i++) {
- var e = $("RROW-" + ids[i]);
-
- if (e) {
- if (i % 2 == 0) {
- e.removeClassName("even");
- e.addClassName("odd");
- } else {
- e.removeClassName("odd");
- e.addClassName("even");
- }
- }
- }
- } catch (e) {
- exception_error("fixHeadlinesOrder", e);
- }
-}
-
-function getArticleUnderPointer() {
- return post_under_pointer;
-}
-
-function zoomToArticle(event, id) {
- try {
- var cached_article = cache_get("article: " + id);
-
- if (dijit.byId("ATAB-" + id))
- if (!event || !event.shiftKey)
- return dijit.byId("content-tabs").selectChild(dijit.byId("ATAB-" + id));
-
- if (dijit.byId("ATSTRTIP-" + id))
- dijit.byId("ATSTRTIP-" + id).destroyRecursive();
-
- if (cached_article) {
- //closeArticlePanel();
-
- var article_pane = new dijit.layout.ContentPane({
- title: __("Loading...") , content: cached_article,
- style: 'padding : 0px;',
- id: 'ATAB-' + id,
- closable: true });
-
- dijit.byId("content-tabs").addChild(article_pane);
-
- if (!event || !event.shiftKey)
- dijit.byId("content-tabs").selectChild(article_pane);
-
- if ($("PTITLE-" + id))
- article_pane.attr('title', $("PTITLE-" + id).innerHTML);
-
- } else {
-
- var query = "?op=rpc&subop=getArticles&ids=" + param_escape(id);
-
- notify_progress("Loading, please wait...", true);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
-
- var reply = JSON.parse(transport.responseText);
-
- if (reply) {
- //closeArticlePanel();
-
- var content = reply[0]['content'];
-
- var article_pane = new dijit.layout.ContentPane({
- title: "article-" + id , content: content,
- style: 'padding : 0px;',
- id: 'ATAB-' + id,
- closable: true });
-
- dijit.byId("content-tabs").addChild(article_pane);
-
- if (!event || !event.shiftKey)
- dijit.byId("content-tabs").selectChild(article_pane);
-
- if ($("PTITLE-" + id))
- article_pane.attr('title', $("PTITLE-" + id).innerHTML);
- }
-
- } });
- }
-
- } catch (e) {
- exception_error("zoomToArticle", e);
- }
-}
-
-function scrollArticle(offset) {
- try {
- if (!isCdmMode()) {
- var ci = $("content-insert");
- if (ci) {
- ci.scrollTop += offset;
- }
- } else {
- var hi = $("headlines-frame");
- if (hi) {
- hi.scrollTop += offset;
- }
-
- }
- } catch (e) {
- exception_error("scrollArticle", e);
- }
-}
-
-function show_labels_in_headlines(transport) {
- try {
- var data = JSON.parse(transport.responseText);
-
- if (data) {
- data['info-for-headlines'].each(function(elem) {
- var ctr = $("HLLCTR-" + elem.id);
-
- if (ctr) ctr.innerHTML = elem.labels;
- });
-
- cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML);
-
- }
- } catch (e) {
- exception_error("show_labels_in_headlines", e);
- }
-}
-
-/* function toggleHeadlineActions() {
- try {
- var e = $("headlineActionsBody");
- var p = $("headlineActionsDrop");
-
- if (!Element.visible(e)) {
- Element.show(e);
- } else {
- Element.hide(e);
- }
-
- e.scrollTop = 0;
- e.style.left = (p.offsetLeft + 1) + "px";
- e.style.top = (p.offsetTop + p.offsetHeight + 2) + "px";
-
- } catch (e) {
- exception_error("toggleHeadlineActions", e);
- }
-} */
-
-/* function publishWithNote(id, def_note) {
- try {
- if (!def_note) def_note = '';
-
- var note = prompt(__("Please enter a note for this article:"), def_note);
-
- if (note != undefined) {
- togglePub(id, false, false, note);
- }
-
- } catch (e) {
- exception_error("publishWithNote", e);
- }
-} */
-
-function emailArticle(id) {
- try {
- if (!id) {
- var ids = getSelectedArticleIds2();
-
- if (ids.length == 0) {
- alert(__("No articles are selected."));
- return;
- }
-
- id = ids.toString();
- }
-
- if (dijit.byId("emailArticleDlg"))
- dijit.byId("emailArticleDlg").destroyRecursive();
-
- var query = "backend.php?op=dlg&id=emailArticle¶m=" + param_escape(id);
-
- dialog = new dijit.Dialog({
- id: "emailArticleDlg",
- title: __("Forward article by email"),
- style: "width: 600px",
- execute: function() {
- if (this.validate()) {
-
- new Ajax.Request("backend.php", {
- parameters: dojo.objectToQuery(this.attr('value')),
- onComplete: function(transport) {
-
- var reply = JSON.parse(transport.responseText);
-
- var error = reply['error'];
-
- if (error) {
- alert(__('Error sending email:') + ' ' + error);
- } else {
- notify_info('Your message has been sent.');
- dialog.hide();
- }
-
- } });
- }
- },
- href: query});
-
- var tmph = dojo.connect(dialog, 'onLoad', function() {
- dojo.disconnect(tmph);
-
- new Ajax.Autocompleter('emailArticleDlg_destination', 'emailArticleDlg_dst_choices',
- "backend.php?op=rpc&subop=completeEmails",
- { tokens: '', paramName: "search" });
- });
-
- dialog.show();
-
- /* displayDlg('emailArticle', id,
- function () {
- document.forms['article_email_form'].destination.focus();
-
- new Ajax.Autocompleter('destination', 'destination_choices',
- "backend.php?op=rpc&subop=completeEmails",
- { tokens: '', paramName: "search" });
-
- }); */
-
- } catch (e) {
- exception_error("emailArticle", e);
- }
-}
-
-function dismissArticle(id) {
- try {
- var elem = $("RROW-" + id);
-
- toggleUnread(id, 0, true);
-
- new Effect.Fade(elem, {duration : 0.5});
-
- active_post_id = false;
-
- } catch (e) {
- exception_error("dismissArticle", e);
- }
-}
-
-function dismissSelectedArticles() {
- try {
-
- var ids = getVisibleArticleIds();
- var tmp = [];
- var sel = [];
-
- for (var i = 0; i < ids.length; i++) {
- var elem = $("RROW-" + ids[i]);
-
- if (elem.className && elem.hasClassName("Selected") &&
- ids[i] != active_post_id) {
- new Effect.Fade(elem, {duration : 0.5});
- sel.push(ids[i]);
- } else {
- tmp.push(ids[i]);
- }
- }
-
- if (sel.length > 0)
- selectionToggleUnread(false);
-
- fixHeadlinesOrder(tmp);
-
- } catch (e) {
- exception_error("dismissSelectedArticles", e);
- }
-}
-
-function dismissReadArticles() {
- try {
-
- var ids = getVisibleArticleIds();
- var tmp = [];
-
- for (var i = 0; i < ids.length; i++) {
- var elem = $("RROW-" + ids[i]);
-
- if (elem.className && !elem.hasClassName("Unread") &&
- !elem.hasClassName("Selected")) {
-
- new Effect.Fade(elem, {duration : 0.5});
- } else {
- tmp.push(ids[i]);
- }
- }
-
- fixHeadlinesOrder(tmp);
-
- } catch (e) {
- exception_error("dismissSelectedArticles", e);
- }
-}
-
-function getVisibleArticleIds() {
- var ids = [];
-
- try {
-
- getLoadedArticleIds().each(function(id) {
- var elem = $("RROW-" + id);
- if (elem && Element.visible(elem))
- ids.push(id);
- });
-
- } catch (e) {
- exception_error("getVisibleArticleIds", e);
- }
-
- return ids;
-}
-
-function cdmClicked(event, id) {
- try {
- //var shift_key = event.shiftKey;
-
- hideAuxDlg();
-
- if (!event.ctrlKey) {
-
- if (!getInitParam("cdm_expanded")) {
- return cdmExpandArticle(id);
- } else {
-
- selectArticles("none");
- toggleSelected(id);
-
- var elem = $("RROW-" + id);
-
- if (elem)
- elem.removeClassName("Unread");
-
- var upd_img_pic = $("FUPDPIC-" + id);
-
- if (upd_img_pic && (upd_img_pic.src.match("updated.png") ||
- upd_img_pic.src.match("fresh_sign.png"))) {
-
- upd_img_pic.src = "images/blank_icon.gif";
- }
-
- active_post_id = id;
-
- var query = "?op=rpc&subop=catchupSelected" +
- "&cmode=0&ids=" + param_escape(id);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- handle_rpc_json(transport);
- } });
-
- return true;
- }
-
- } else {
- toggleSelected(id, true);
- toggleUnread(id, 0, false);
- zoomToArticle(event, id);
- }
-
- } catch (e) {
- exception_error("cdmClicked");
- }
-
- return false;
-}
-
-function postClicked(event, id) {
- try {
-
- if (!event.ctrlKey) {
- return true;
- } else {
- postOpenInNewTab(event, id);
- return false;
- }
-
- } catch (e) {
- exception_error("postClicked");
- }
-}
-
-function hlOpenInNewTab(event, id) {
- toggleUnread(id, 0, false);
- zoomToArticle(event, id);
-}
-
-function postOpenInNewTab(event, id) {
- closeArticlePanel(id);
- zoomToArticle(event, id);
-}
-
-function hlClicked(event, id) {
- try {
- if (event.which == 2) {
- view(id);
- return true;
- } else if (event.altKey) {
- openArticleInNewWindow(id);
- } else if (!event.ctrlKey) {
- view(id);
- return false;
- } else {
- toggleSelected(id);
- toggleUnread(id, 0, false);
- zoomToArticle(event, id);
- return false;
- }
-
- } catch (e) {
- exception_error("hlClicked");
- }
-}
-
-function getFirstVisibleHeadlineId() {
- var rows = getVisibleArticleIds();
- return rows[0];
-
-}
-
-function getLastVisibleHeadlineId() {
- var rows = getVisibleArticleIds();
- return rows[rows.length-1];
-}
-
-function openArticleInNewWindow(id) {
- toggleUnread(id, 0, false);
- window.open("backend.php?op=la&id=" + id);
-}
-
-function isCdmMode() {
- return getInitParam("combined_display_mode");
-}
-
-function markHeadline(id) {
- var row = $("RROW-" + id);
- if (row) {
- var check = $("RCHK-" + id);
-
- if (check) {
- check.checked = true;
- }
-
- row.addClassName("Selected");
- }
-}
-
-function getRelativePostIds(id, limit) {
-
- var tmp = [];
-
- try {
-
- if (!limit) limit = 6; //3
-
- var ids = getVisibleArticleIds();
-
- for (var i = 0; i < ids.length; i++) {
- if (ids[i] == id) {
- for (var k = 1; k <= limit; k++) {
- //if (i > k-1) tmp.push(ids[i-k]);
- if (i < ids.length-k) tmp.push(ids[i+k]);
- }
- break;
- }
- }
-
- } catch (e) {
- exception_error("getRelativePostIds", e);
- }
-
- return tmp;
-}
-
-function correctHeadlinesOffset(id) {
-
- try {
-
- var container = $("headlines-frame");
- var row = $("RROW-" + id);
-
- var viewport = container.offsetHeight;
-
- var rel_offset_top = row.offsetTop - container.scrollTop;
- var rel_offset_bottom = row.offsetTop + row.offsetHeight - container.scrollTop;
-
- //console.log("Rtop: " + rel_offset_top + " Rbtm: " + rel_offset_bottom);
- //console.log("Vport: " + viewport);
-
- if (rel_offset_top <= 0 || rel_offset_top > viewport) {
- container.scrollTop = row.offsetTop;
- } else if (rel_offset_bottom > viewport) {
-
- /* doesn't properly work with Opera in some cases because
- Opera fucks up element scrolling */
-
- container.scrollTop = row.offsetTop + row.offsetHeight - viewport;
- }
-
- } catch (e) {
- exception_error("correctHeadlinesOffset", e);
- }
-
-}
-
-function headlineActionsChange(elem) {
- try {
- eval(elem.value);
- elem.attr('value', 'false');
- } catch (e) {
- exception_error("headlineActionsChange", e);
- }
-}
-
-function closeArticlePanel() {
-
- var tabs = dijit.byId("content-tabs");
- var child = tabs.selectedChildWidget;
-
- if (child && tabs.getIndexOfChild(child) > 0) {
- tabs.removeChild(child);
- child.destroy();
- } else {
- if (dijit.byId("content-insert"))
- dijit.byId("headlines-wrap-inner").removeChild(
- dijit.byId("content-insert"));
- }
-}
-
-function initHeadlinesMenu() {
- try {
- if (dijit.byId("headlinesMenu"))
- dijit.byId("headlinesMenu").destroyRecursive();
-
- var ids = [];
-
- if (!isCdmMode()) {
- nodes = $$("#headlines-frame > div[id*=RROW]");
- } else {
- nodes = $$("#headlines-frame span[id*=RTITLE]");
- }
-
- nodes.each(function(node) {
- ids.push(node.id);
- });
-
- var menu = new dijit.Menu({
- id: "headlinesMenu",
- targetNodeIds: ids,
- });
-
- var tmph = dojo.connect(menu, '_openMyself', function (event) {
- var callerNode = event.target, match = null, tries = 0;
-
- while (match == null && callerNode && tries <= 3) {
- match = callerNode.id.match("^[A-Z]+[-]([0-9]+)$");
- callerNode = callerNode.parentNode;
- ++tries;
- }
-
- if (match) this.callerRowId = parseInt(match[1]);
-
- });
-
-/* if (!isCdmMode())
- menu.addChild(new dijit.MenuItem({
- label: __("View article"),
- onClick: function(event) {
- view(this.getParent().callerRowId);
- }})); */
-
- menu.addChild(new dijit.MenuItem({
- label: __("Open original article"),
- onClick: function(event) {
- openArticleInNewWindow(this.getParent().callerRowId);
- }}));
-
- menu.addChild(new dijit.MenuItem({
- label: __("View in a tt-rss tab"),
- onClick: function(event) {
- hlOpenInNewTab(event, this.getParent().callerRowId);
- }}));
-
- menu.addChild(new dijit.MenuSeparator());
-
- menu.addChild(new dijit.MenuItem({
- label: __("Mark above as read"),
- onClick: function(event) {
- catchupRelativeToArticle(0, this.getParent().callerRowId);
- }}));
-
- menu.addChild(new dijit.MenuItem({
- label: __("Mark below as read"),
- onClick: function(event) {
- catchupRelativeToArticle(1, this.getParent().callerRowId);
- }}));
-
-
- var labels = dijit.byId("feedTree").model.getItemsInCategory(-2);
-
- if (labels) {
-
- menu.addChild(new dijit.MenuSeparator());
-
- var labelAddMenu = new dijit.Menu({ownerMenu: menu});
- var labelDelMenu = new dijit.Menu({ownerMenu: menu});
-
- labels.each(function(label) {
- var id = label.id[0];
- var bare_id = id.substr(id.indexOf(":")+1);
- var name = label.name[0];
-
- bare_id = -11-bare_id;
-
- labelAddMenu.addChild(new dijit.MenuItem({
- label: name,
- labelId: bare_id,
- onClick: function(event) {
- selectionAssignLabel(this.labelId,
- [this.getParent().ownerMenu.callerRowId]);
- }}));
-
- labelDelMenu.addChild(new dijit.MenuItem({
- label: name,
- labelId: bare_id,
- onClick: function(event) {
- selectionRemoveLabel(this.labelId,
- [this.getParent().ownerMenu.callerRowId]);
- }}));
-
- });
-
- menu.addChild(new dijit.PopupMenuItem({
- label: __("Assign label"),
- popup: labelAddMenu,
- }));
-
- menu.addChild(new dijit.PopupMenuItem({
- label: __("Remove label"),
- popup: labelDelMenu,
- }));
-
- }
-
- menu.startup();
-
- } catch (e) {
- exception_error("initHeadlinesMenu", e);
- }
-}
-
-function tweetArticle(id) {
- try {
- var query = "?op=rpc&subop=getTweetInfo&id=" + param_escape(id);
-
- console.log(query);
-
- var d = new Date();
- var ts = d.getTime();
-
- var w = window.open('backend.php?op=loading', 'ttrss_tweet',
- "status=0,toolbar=0,location=0,width=500,height=400,scrollbars=1,menubar=0");
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- var ti = JSON.parse(transport.responseText);
-
- var share_url = "http://twitter.com/share?_=" + ts +
- "&text=" + param_escape(ti.title) +
- "&url=" + param_escape(ti.link);
-
- w.location.href = share_url;
-
- } });
-
-
- } catch (e) {
- exception_error("tweetArticle", e);
- }
-}
-
-function editArticleNote(id) {
- try {
-
- var query = "backend.php?op=dlg&id=editArticleNote¶m=" + param_escape(id);
-
- if (dijit.byId("editNoteDlg"))
- dijit.byId("editNoteDlg").destroyRecursive();
-
- dialog = new dijit.Dialog({
- id: "editNoteDlg",
- title: __("Edit article note"),
- style: "width: 600px",
- execute: function() {
- if (this.validate()) {
- var query = dojo.objectToQuery(this.attr('value'));
-
- notify_progress("Saving article note...", true);
-
- new Ajax.Request("backend.php", {
- parameters: query,
- onComplete: function(transport) {
- notify('');
- dialog.hide();
-
- var reply = JSON.parse(transport.responseText);
-
- cache_delete("article:" + id);
-
- var elem = $("POSTNOTE-" + id);
-
- if (elem) {
- Element.hide(elem);
- elem.innerHTML = reply.note;
-
- if (reply.raw_length != 0)
- new Effect.Appear(elem);
- }
-
- }});
- }
- },
- href: query,
- });
-
- dialog.show();
-
- } catch (e) {
- exception_error("editArticleNote", e);
- }
-}
-
-function player(elem) {
- var aid = elem.getAttribute("audio-id");
- var status = elem.getAttribute("status");
-
- var audio = $(aid);
-
- if (audio) {
- if (status == 0) {
- audio.play();
- status = 1;
- elem.innerHTML = __("Playing...");
- elem.title = __("Click to pause");
- elem.addClassName("playing");
- } else {
- audio.pause();
- status = 0;
- elem.innerHTML = __("Play");
- elem.title = __("Click to play");
- elem.removeClassName("playing");
- }
-
- elem.setAttribute("status", status);
- } else {
- alert("Your browser doesn't seem to support HTML5 audio.");
- }
-}
-
-function cache_set(id, obj) {
- //console.log("cache_set: " + id);
- if (has_storage)
- try {
- sessionStorage[id] = obj;
- } catch (e) {
- sessionStorage.clear();
- }
-}
-
-function cache_get(id) {
- if (has_storage)
- return sessionStorage[id];
-}
-
-function cache_clear() {
- if (has_storage)
- sessionStorage.clear();
-}
-
-function cache_delete(id) {
- if (has_storage)
- sessionStorage.removeItem(id);
-}
-
-function cache_headlines(feed, is_cat, toolbar_obj, content_obj) {
- if (toolbar_obj && content_obj) {
- cache_set("feed:" + feed + ":" + is_cat,
- JSON.stringify({toolbar: toolbar_obj, content: content_obj}));
- } else {
- try {
- obj = cache_get("feed:" + feed + ":" + is_cat);
-
- if (obj) {
- obj = JSON.parse(obj);
-
- if (toolbar_obj) obj.toolbar = toolbar_obj;
- if (content_obj) obj.content = content_obj;
-
- cache_set("feed:" + feed + ":" + is_cat, JSON.stringify(obj));
- }
-
- } catch (e) {
- console.warn("cache_headlines failed: " + e);
- }
- }
-}
-
-function render_local_headlines(feed, is_cat, obj) {
- try {
-
- dijit.byId("headlines-toolbar").attr('content',
- obj.toolbar);
-
- dijit.byId("headlines-frame").attr('content',
- obj.content);
-
- dojo.parser.parse('headlines-toolbar');
-
- $("headlines-frame").scrollTop = 0;
- selectArticles('none');
- setActiveFeedId(feed, is_cat);
- initHeadlinesMenu();
-
- precache_headlines();
-
- } catch (e) {
- exception_error("render_local_headlines", e);
- }
-}
-
-function precache_headlines_idle() {
- try {
- if (!feed_precache_timeout_id) {
- var feeds = dijit.byId("feedTree").getVisibleUnreadFeeds();
- var uncached = [];
-
- feeds.each(function(item) {
- if (parseInt(item[0]) > 0 && !cache_get("feed:" + item[0] + ":" + item[1]))
- uncached.push(item);
- });
-
- if (uncached.length > 0) {
- var rf = uncached[Math.floor(Math.random()*uncached.length)];
- viewfeed(rf[0], '', rf[1], 0, true);
- }
- }
- precache_idle_timeout_id = setTimeout("precache_headlines_idle()", 1000*30);
-
- } catch (e) {
- exception_error("precache_headlines_idle", e);
- }
-}
-
-function precache_headlines() {
- try {
-
- if (!feed_precache_timeout_id) {
- feed_precache_timeout_id = window.setTimeout(function() {
- var nuf = getNextUnreadFeed(getActiveFeedId(), activeFeedIsCat());
- var nf = dijit.byId("feedTree").getNextFeed(getActiveFeedId(), activeFeedIsCat());
-
- if (nuf && !cache_get("feed:" + nuf + ":" + activeFeedIsCat()))
- viewfeed(nuf, '', activeFeedIsCat(), 0, true);
-
- if (nf != nuf && nf && !cache_get("feed:" + nf[0] + ":" + nf[1]))
- viewfeed(nf[0], '', nf[1], 0, true);
-
- window.setTimeout(function() {
- feed_precache_timeout_id = false;
- }, 3000);
- }, 1000);
- }
-
- } catch (e) {
- exception_error("precache_headlines", e);
- }
-}
-
-function shareArticle(id) {
- try {
- if (dijit.byId("shareArticleDlg"))
- dijit.byId("shareArticleDlg").destroyRecursive();
-
- var query = "backend.php?op=dlg&id=shareArticle¶m=" + param_escape(id);
-
- dialog = new dijit.Dialog({
- id: "shareArticleDlg",
- title: __("Share article by URL"),
- style: "width: 600px",
- href: query});
-
- dialog.show();
-
- } catch (e) {
- exception_error("emailArticle", e);
- }
-}
-
-