summaryrefslogtreecommitdiff
path: root/classes
diff options
context:
space:
mode:
Diffstat (limited to 'classes')
-rw-r--r--classes/api.php101
-rw-r--r--classes/article.php3
-rw-r--r--classes/db/mysql.php7
-rw-r--r--classes/db/mysqli.php7
-rw-r--r--classes/db/pgsql.php7
-rw-r--r--classes/dlg.php3
-rw-r--r--classes/feedenclosure.php3
-rw-r--r--classes/feeditem/atom.php76
-rw-r--r--classes/feeditem/common.php28
-rw-r--r--classes/feeditem/rss.php76
-rw-r--r--classes/feedparser.php116
-rw-r--r--classes/feeds.php197
-rw-r--r--classes/handler/public.php305
-rw-r--r--classes/opml.php12
-rw-r--r--classes/pluginhost.php18
-rw-r--r--classes/pref/feeds.php63
-rw-r--r--classes/pref/filters.php77
-rw-r--r--classes/pref/prefs.php16
-rw-r--r--classes/pref/users.php4
-rw-r--r--classes/rpc.php44
20 files changed, 764 insertions, 399 deletions
diff --git a/classes/api.php b/classes/api.php
index 23866072f..730e20ab9 100644
--- a/classes/api.php
+++ b/classes/api.php
@@ -2,7 +2,7 @@
class API extends Handler {
- const API_LEVEL = 7;
+ const API_LEVEL = 9;
const STATUS_OK = 0;
const STATUS_ERR = 1;
@@ -77,6 +77,7 @@ class API extends Handler {
$this->wrap(self::STATUS_OK, array("session_id" => session_id(),
"api_level" => self::API_LEVEL));
} else { // else we are not logged in
+ user_error("Failed login attempt for $login from {$_SERVER['REMOTE_ADDR']}", E_USER_WARNING);
$this->wrap(self::STATUS_ERR, array("error" => "LOGIN_ERROR"));
}
} else {
@@ -199,11 +200,15 @@ class API extends Handler {
$include_nested = sql_bool_to_bool($_REQUEST["include_nested"]);
$sanitize_content = !isset($_REQUEST["sanitize"]) ||
sql_bool_to_bool($_REQUEST["sanitize"]);
+ $force_update = sql_bool_to_bool($_REQUEST["force_update"]);
$override_order = false;
switch ($_REQUEST["order_by"]) {
+ case "title":
+ $override_order = "ttrss_entries.title";
+ break;
case "date_reverse":
- $override_order = "date_entered, updated";
+ $override_order = "score DESC, date_entered, updated";
break;
case "feed_dates":
$override_order = "updated DESC";
@@ -218,7 +223,7 @@ class API extends Handler {
$headlines = $this->api_get_headlines($feed_id, $limit, $offset,
$filter, $is_cat, $show_excerpt, $show_content, $view_mode, $override_order,
$include_attachments, $since_id, $search, $search_mode,
- $include_nested, $sanitize_content);
+ $include_nested, $sanitize_content, $force_update);
$this->wrap(self::STATUS_OK, $headlines);
} else {
@@ -309,8 +314,8 @@ class API extends Handler {
if ($article_id) {
- $query = "SELECT id,title,link,content,cached_content,feed_id,comments,int_id,
- marked,unread,published,score,
+ $query = "SELECT id,title,link,content,feed_id,comments,int_id,
+ marked,unread,published,score,note,lang,
".SUBSTRING_FOR_DATE."(updated,1,16) as updated,
author,(SELECT title FROM ttrss_feeds WHERE id = feed_id) AS feed_title
FROM ttrss_entries,ttrss_user_entries
@@ -338,11 +343,13 @@ class API extends Handler {
"comments" => $line["comments"],
"author" => $line["author"],
"updated" => (int) strtotime($line["updated"]),
- "content" => $line["cached_content"] != "" ? $line["cached_content"] : $line["content"],
+ "content" => $line["content"],
"feed_id" => $line["feed_id"],
"attachments" => $attachments,
"score" => (int)$line["score"],
- "feed_title" => $line["feed_title"]
+ "feed_title" => $line["feed_title"],
+ "note" => $line["note"],
+ "lang" => $line["lang"]
);
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE_API) as $p) {
@@ -423,14 +430,14 @@ class API extends Handler {
$checked = false;
foreach ($article_labels as $al) {
- if ($al[0] == $line['id']) {
+ if (feed_to_label_id($al[0]) == $line['id']) {
$checked = true;
break;
}
}
array_push($rv, array(
- "id" => (int)$line['id'],
+ "id" => (int)label_to_feed_id($line['id']),
"caption" => $line['caption'],
"fg_color" => $line['fg_color'],
"bg_color" => $line['bg_color'],
@@ -447,7 +454,7 @@ class API extends Handler {
$assign = (bool) $this->dbh->escape_string($_REQUEST['assign']) == "true";
$label = $this->dbh->escape_string(label_find_caption(
- $label_id, $_SESSION["uid"]));
+ feed_to_label_id($label_id), $_SESSION["uid"]));
$num_updated = 0;
@@ -511,7 +518,7 @@ class API extends Handler {
if ($unread || !$unread_only) {
$row = array(
- "id" => $cv["id"],
+ "id" => (int) $cv["id"],
"title" => $cv["description"],
"unread" => $cv["counter"],
"cat_id" => -2,
@@ -557,7 +564,7 @@ class API extends Handler {
if ($unread || !$unread_only) {
$row = array(
- "id" => $line["id"],
+ "id" => (int) $line["id"],
"title" => $line["title"],
"unread" => $unread,
"is_cat" => true,
@@ -626,7 +633,28 @@ class API extends Handler {
$filter, $is_cat, $show_excerpt, $show_content, $view_mode, $order,
$include_attachments, $since_id,
$search = "", $search_mode = "",
- $include_nested = false, $sanitize_content = true) {
+ $include_nested = false, $sanitize_content = true, $force_update = false) {
+
+ if ($force_update && $feed_id > 0 && is_numeric($feed_id)) {
+ // Update the feed if required with some basic flood control
+
+ $result = db_query(
+ "SELECT cache_images,".SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated
+ FROM ttrss_feeds WHERE id = '$feed_id'");
+
+ if (db_num_rows($result) != 0) {
+ $last_updated = strtotime(db_fetch_result($result, 0, "last_updated"));
+ $cache_images = sql_bool_to_bool(db_fetch_result($result, 0, "cache_images"));
+
+ if (!$cache_images && time() - $last_updated > 120) {
+ include "rssfuncs.php";
+ update_rss_feed($feed_id, true, true);
+ } else {
+ db_query("UPDATE ttrss_feeds SET last_updated = '1970-01-01', last_update_started = '1970-01-01'
+ WHERE id = '$feed_id'");
+ }
+ }
+ }
$qfh_ret = queryFeedHeadlines($feed_id, $limit,
$view_mode, $is_cat, $search, $search_mode,
@@ -638,11 +666,31 @@ class API extends Handler {
$headlines = array();
while ($line = db_fetch_assoc($result)) {
+ $line["content_preview"] = truncate_string(strip_tags($line["content"]), 100);
+ foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
+ $line = $p->hook_query_headlines($line, 100, true);
+ }
+
$is_updated = ($line["last_read"] == "" &&
($line["unread"] != "t" && $line["unread"] != "1"));
$tags = explode(",", $line["tag_cache"]);
- $labels = json_decode($line["label_cache"], true);
+
+ $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($line["id"]);
//if (!$tags) $tags = get_article_tags($line["id"]);
//if (!$labels) $labels = get_article_labels($line["id"]);
@@ -660,28 +708,22 @@ class API extends Handler {
"tags" => $tags,
);
- if ($include_attachments)
- $headline_row['attachments'] = get_article_enclosures(
- $line['id']);
+ if ($include_attachments)
+ $headline_row['attachments'] = get_article_enclosures(
+ $line['id']);
- if ($show_excerpt) {
- $excerpt = truncate_string(strip_tags($line["content_preview"]), 100);
- $headline_row["excerpt"] = $excerpt;
- }
+ if ($show_excerpt)
+ $headline_row["excerpt"] = $line["content_preview"];
if ($show_content) {
- if ($line["cached_content"] != "") {
- $line["content_preview"] =& $line["cached_content"];
- }
-
if ($sanitize_content) {
$headline_row["content"] = sanitize(
- $line["content_preview"],
+ $line["content"],
sql_bool_to_bool($line['hide_images']),
- false, $line["site_url"]);
+ false, $line["site_url"], false, $line["id"]);
} else {
- $headline_row["content"] = $line["content_preview"];
+ $headline_row["content"] = $line["content"];
}
}
@@ -699,7 +741,10 @@ class API extends Handler {
$headline_row["always_display_attachments"] = sql_bool_to_bool($line["always_display_enclosures"]);
$headline_row["author"] = $line["author"];
+
$headline_row["score"] = (int)$line["score"];
+ $headline_row["note"] = $line["note"];
+ $headline_row["lang"] = $line["lang"];
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE_API) as $p) {
$headline_row = $p->hook_render_article_api(array("headline" => $headline_row));
diff --git a/classes/article.php b/classes/article.php
index 398132d12..9aef107ec 100644
--- a/classes/article.php
+++ b/classes/article.php
@@ -30,7 +30,6 @@ class Article extends Handler_Protected {
$id = $this->dbh->escape_string($_REQUEST["id"]);
$cids = explode(",", $this->dbh->escape_string($_REQUEST["cids"]));
$mode = $this->dbh->escape_string($_REQUEST["mode"]);
- $omode = $this->dbh->escape_string($_REQUEST["omode"]);
// in prefetch mode we only output requested cids, main article
// just gets marked as read (it already exists in client cache)
@@ -108,7 +107,7 @@ class Article extends Handler_Protected {
// only check for our user data here, others might have shared this with different content etc
$result = db_query("SELECT id FROM ttrss_entries, ttrss_user_entries WHERE
- link = '$url' AND ref_id = id AND owner_uid = '$owner_uid' LIMIT 1");
+ guid = '$guid' AND ref_id = id AND owner_uid = '$owner_uid' LIMIT 1");
if (db_num_rows($result) != 0) {
$ref_id = db_fetch_result($result, 0, "id");
diff --git a/classes/db/mysql.php b/classes/db/mysql.php
index aab05aca2..d4b45b98c 100644
--- a/classes/db/mysql.php
+++ b/classes/db/mysql.php
@@ -26,9 +26,12 @@ class Db_Mysql implements IDb {
}
function query($query, $die_on_error = true) {
- $result = mysql_query($query, $this->link);
+ $result = @mysql_query($query, $this->link);
if (!$result) {
- user_error("Query $query failed: " . ($this->link ? mysql_error($this->link) : "No connection"),
+ $error = @mysql_error($this->link);
+
+ @mysql_query("ROLLBACK", $this->link);
+ user_error("Query $query failed: " . ($this->link ? $error : "No connection"),
$die_on_error ? E_USER_ERROR : E_USER_WARNING);
}
return $result;
diff --git a/classes/db/mysqli.php b/classes/db/mysqli.php
index a41ebf8ec..c685b75a0 100644
--- a/classes/db/mysqli.php
+++ b/classes/db/mysqli.php
@@ -24,9 +24,12 @@ class Db_Mysqli implements IDb {
}
function query($query, $die_on_error = true) {
- $result = mysqli_query($this->link, $query);
+ $result = @mysqli_query($this->link, $query);
if (!$result) {
- user_error("Query $query failed: " . ($this->link ? mysqli_error($this->link) : "No connection"),
+ $error = @mysqli_error($this->link);
+
+ @mysqli_query($this->link, "ROLLBACK");
+ user_error("Query $query failed: " . ($this->link ? $error : "No connection"),
$die_on_error ? E_USER_ERROR : E_USER_WARNING);
}
diff --git a/classes/db/pgsql.php b/classes/db/pgsql.php
index 4d860790b..ba37f83a6 100644
--- a/classes/db/pgsql.php
+++ b/classes/db/pgsql.php
@@ -35,11 +35,14 @@ class Db_Pgsql implements IDb {
}
function query($query, $die_on_error = true) {
- $result = pg_query($query);
+ $result = @pg_query($this->link, $query);
if (!$result) {
+ $error = @pg_last_error($this->link);
+
+ @pg_query($this->link, "ROLLBACK");
$query = htmlspecialchars($query); // just in case
- user_error("Query $query failed: " . ($this->link ? pg_last_error($this->link) : "No connection"),
+ user_error("Query $query failed: " . ($this->link ? $error : "No connection"),
$die_on_error ? E_USER_ERROR : E_USER_WARNING);
}
return $result;
diff --git a/classes/dlg.php b/classes/dlg.php
index cfa960d9a..25a194bed 100644
--- a/classes/dlg.php
+++ b/classes/dlg.php
@@ -16,7 +16,6 @@ class Dlg extends Handler_Protected {
print __("If you have imported labels and/or filters, you might need to reload preferences to see your new data.") . "</p>";
print "<div class=\"prefFeedOPMLHolder\">";
- $owner_uid = $_SESSION["uid"];
$this->dbh->query("BEGIN");
@@ -176,7 +175,7 @@ class Dlg extends Handler_Protected {
while ($row = $this->dbh->fetch_assoc($result)) {
$tmp = htmlspecialchars($row["tag_name"]);
- print "<option value=\"" . str_replace(" ", "%20", $tmp) . "\">$tmp</option>";
+ print "<option value=\"$tmp\">$tmp</option>";
}
print "</select>";
diff --git a/classes/feedenclosure.php b/classes/feedenclosure.php
index d610dd7c8..64f1a0616 100644
--- a/classes/feedenclosure.php
+++ b/classes/feedenclosure.php
@@ -3,5 +3,8 @@ class FeedEnclosure {
public $link;
public $type;
public $length;
+ public $title;
+ public $height;
+ public $width;
}
?>
diff --git a/classes/feeditem/atom.php b/classes/feeditem/atom.php
index 9680748f9..dfac7149f 100644
--- a/classes/feeditem/atom.php
+++ b/classes/feeditem/atom.php
@@ -1,5 +1,6 @@
<?php
class FeedItem_Atom extends FeedItem_Common {
+
function get_id() {
$id = $this->elem->getElementsByTagName("id")->item(0);
@@ -30,6 +31,7 @@ class FeedItem_Atom extends FeedItem_Common {
}
}
+
function get_link() {
$links = $this->elem->getElementsByTagName("link");
@@ -38,8 +40,13 @@ class FeedItem_Atom extends FeedItem_Common {
(!$link->hasAttribute("rel")
|| $link->getAttribute("rel") == "alternate"
|| $link->getAttribute("rel") == "standout")) {
+ $base = $this->xpath->evaluate("string(ancestor-or-self::*[@xml:base][1]/@xml:base)", $link);
+
+ if ($base)
+ return rewrite_relative_url($base, trim($link->getAttribute("href")));
+ else
+ return trim($link->getAttribute("href"));
- return $link->getAttribute("href");
}
}
}
@@ -48,7 +55,7 @@ class FeedItem_Atom extends FeedItem_Common {
$title = $this->elem->getElementsByTagName("title")->item(0);
if ($title) {
- return $title->nodeValue;
+ return trim($title->nodeValue);
}
}
@@ -58,7 +65,13 @@ class FeedItem_Atom extends FeedItem_Common {
if ($content) {
if ($content->hasAttribute('type')) {
if ($content->getAttribute('type') == 'xhtml') {
- return $this->doc->saveXML($content->firstChild->nextSibling);
+ for ($i = 0; $i < $content->childNodes->length; $i++) {
+ $child = $content->childNodes->item($i);
+
+ if ($child->hasChildNodes()) {
+ return $this->doc->saveXML($child);
+ }
+ }
}
}
@@ -72,7 +85,13 @@ class FeedItem_Atom extends FeedItem_Common {
if ($content) {
if ($content->hasAttribute('type')) {
if ($content->getAttribute('type') == 'xhtml') {
- return $this->doc->saveXML($content->firstChild->nextSibling);
+ for ($i = 0; $i < $content->childNodes->length; $i++) {
+ $child = $content->childNodes->item($i);
+
+ if ($child->hasChildNodes()) {
+ return $this->doc->saveXML($child);
+ }
+ }
}
}
@@ -87,13 +106,13 @@ class FeedItem_Atom extends FeedItem_Common {
foreach ($categories as $cat) {
if ($cat->hasAttribute("term"))
- array_push($cats, $cat->getAttribute("term"));
+ array_push($cats, trim($cat->getAttribute("term")));
}
$categories = $this->xpath->query("dc:subject", $this->elem);
foreach ($categories as $cat) {
- array_push($cats, $cat->nodeValue);
+ array_push($cats, trim($cat->nodeValue));
}
return $cats;
@@ -126,6 +145,51 @@ class FeedItem_Atom extends FeedItem_Common {
$enc->type = $enclosure->getAttribute("type");
$enc->link = $enclosure->getAttribute("url");
$enc->length = $enclosure->getAttribute("length");
+ $enc->height = $enclosure->getAttribute("height");
+ $enc->width = $enclosure->getAttribute("width");
+
+ $desc = $this->xpath->query("media:description", $enclosure)->item(0);
+ if ($desc) $enc->title = strip_tags($desc->nodeValue);
+
+ array_push($encs, $enc);
+ }
+
+
+ $enclosures = $this->xpath->query("media:group", $this->elem);
+
+ foreach ($enclosures as $enclosure) {
+ $enc = new FeedEnclosure();
+
+ $content = $this->xpath->query("media:content", $enclosure)->item(0);
+
+ if ($content) {
+ $enc->type = $content->getAttribute("type");
+ $enc->link = $content->getAttribute("url");
+ $enc->length = $content->getAttribute("length");
+ $enc->height = $content->getAttribute("height");
+ $enc->width = $content->getAttribute("width");
+
+ $desc = $this->xpath->query("media:description", $content)->item(0);
+ if ($desc) {
+ $enc->title = strip_tags($desc->nodeValue);
+ } else {
+ $desc = $this->xpath->query("media:description", $enclosure)->item(0);
+ if ($desc) $enc->title = strip_tags($desc->nodeValue);
+ }
+
+ array_push($encs, $enc);
+ }
+ }
+
+ $enclosures = $this->xpath->query("media:thumbnail", $this->elem);
+
+ foreach ($enclosures as $enclosure) {
+ $enc = new FeedEnclosure();
+
+ $enc->type = "image/generic";
+ $enc->link = $enclosure->getAttribute("url");
+ $enc->height = $enclosure->getAttribute("height");
+ $enc->width = $enclosure->getAttribute("width");
array_push($encs, $enc);
}
diff --git a/classes/feeditem/common.php b/classes/feeditem/common.php
index 0787a42cb..80bebf8fb 100644
--- a/classes/feeditem/common.php
+++ b/classes/feeditem/common.php
@@ -8,6 +8,17 @@ abstract class FeedItem_Common extends FeedItem {
$this->elem = $elem;
$this->xpath = $xpath;
$this->doc = $doc;
+
+ try {
+
+ $source = $elem->getElementsByTagName("source")->item(0);
+
+ // we don't need <source> element
+ if ($source)
+ $elem->removeChild($source);
+ } catch (DOMException $e) {
+ //
+ }
}
function get_author() {
@@ -33,13 +44,26 @@ abstract class FeedItem_Common extends FeedItem {
}
}
- // todo
function get_comments_url() {
+ //RSS only. Use a query here to avoid namespace clashes (e.g. with slash).
+ //might give a wrong result if a default namespace was declared (possible with XPath 2.0)
+ $com_url = $this->xpath->query("comments", $this->elem)->item(0);
+
+ if($com_url)
+ return $com_url->nodeValue;
+
+ //Atom Threading Extension (RFC 4685) stuff. Could be used in RSS feeds, so it's in common.
+ //'text/html' for type is too restrictive?
+ $com_url = $this->xpath->query("atom:link[@rel='replies' and contains(@type,'text/html')]/@href", $this->elem)->item(0);
+ if($com_url)
+ return $com_url->nodeValue;
}
function get_comments_count() {
- $comments = $this->xpath->query("slash:comments", $this->elem)->item(0);
+ //also query for ATE stuff here
+ $query = "slash:comments|thread:total|atom:link[@rel='replies']/@thread:count";
+ $comments = $this->xpath->query($query, $this->elem)->item(0);
if ($comments) {
return $comments->nodeValue;
diff --git a/classes/feeditem/rss.php b/classes/feeditem/rss.php
index e5960243c..c9a7467cd 100644
--- a/classes/feeditem/rss.php
+++ b/classes/feeditem/rss.php
@@ -33,20 +33,20 @@ class FeedItem_RSS extends FeedItem_Common {
|| $link->getAttribute("rel") == "alternate"
|| $link->getAttribute("rel") == "standout")) {
- return $link->getAttribute("href");
+ return trim($link->getAttribute("href"));
}
}
$link = $this->elem->getElementsByTagName("guid")->item(0);
if ($link && $link->hasAttributes() && $link->getAttribute("isPermaLink") == "true") {
- return $link->nodeValue;
+ return trim($link->nodeValue);
}
$link = $this->elem->getElementsByTagName("link")->item(0);
if ($link) {
- return $link->nodeValue;
+ return trim($link->nodeValue);
}
}
@@ -54,21 +54,26 @@ class FeedItem_RSS extends FeedItem_Common {
$title = $this->elem->getElementsByTagName("title")->item(0);
if ($title) {
- return $title->nodeValue;
+ return trim($title->nodeValue);
}
}
function get_content() {
- $content = $this->xpath->query("content:encoded", $this->elem)->item(0);
+ $contentA = $this->xpath->query("content:encoded", $this->elem)->item(0);
+ $contentB = $this->elem->getElementsByTagName("description")->item(0);
- if ($content) {
- return $content->nodeValue;
+ if ($contentA && !$contentB) {
+ return $contentA->nodeValue;
}
- $content = $this->elem->getElementsByTagName("description")->item(0);
- if ($content) {
- return $content->nodeValue;
+ if ($contentB && !$contentA) {
+ return $contentB->nodeValue;
+ }
+
+ if ($contentA && $contentB) {
+ return mb_strlen($contentA->nodeValue) > mb_strlen($contentB->nodeValue) ?
+ $contentA->nodeValue : $contentB->nodeValue;
}
}
@@ -85,13 +90,13 @@ class FeedItem_RSS extends FeedItem_Common {
$cats = array();
foreach ($categories as $cat) {
- array_push($cats, $cat->nodeValue);
+ array_push($cats, trim($cat->nodeValue));
}
$categories = $this->xpath->query("dc:subject", $this->elem);
foreach ($categories as $cat) {
- array_push($cats, $cat->nodeValue);
+ array_push($cats, trim($cat->nodeValue));
}
return $cats;
@@ -108,6 +113,8 @@ class FeedItem_RSS extends FeedItem_Common {
$enc->type = $enclosure->getAttribute("type");
$enc->link = $enclosure->getAttribute("url");
$enc->length = $enclosure->getAttribute("length");
+ $enc->height = $enclosure->getAttribute("height");
+ $enc->width = $enclosure->getAttribute("width");
array_push($encs, $enc);
}
@@ -120,6 +127,51 @@ class FeedItem_RSS extends FeedItem_Common {
$enc->type = $enclosure->getAttribute("type");
$enc->link = $enclosure->getAttribute("url");
$enc->length = $enclosure->getAttribute("length");
+ $enc->height = $enclosure->getAttribute("height");
+ $enc->width = $enclosure->getAttribute("width");
+
+ $desc = $this->xpath->query("media:description", $enclosure)->item(0);
+ if ($desc) $enc->title = strip_tags($desc->nodeValue);
+
+ array_push($encs, $enc);
+ }
+
+
+ $enclosures = $this->xpath->query("media:group", $this->elem);
+
+ foreach ($enclosures as $enclosure) {
+ $enc = new FeedEnclosure();
+
+ $content = $this->xpath->query("media:content", $enclosure)->item(0);
+
+ if ($content) {
+ $enc->type = $content->getAttribute("type");
+ $enc->link = $content->getAttribute("url");
+ $enc->length = $content->getAttribute("length");
+ $enc->height = $content->getAttribute("height");
+ $enc->width = $content->getAttribute("width");
+
+ $desc = $this->xpath->query("media:description", $content)->item(0);
+ if ($desc) {
+ $enc->title = strip_tags($desc->nodeValue);
+ } else {
+ $desc = $this->xpath->query("media:description", $enclosure)->item(0);
+ if ($desc) $enc->title = strip_tags($desc->nodeValue);
+ }
+
+ array_push($encs, $enc);
+ }
+ }
+
+ $enclosures = $this->xpath->query("media:thumbnail", $this->elem);
+
+ foreach ($enclosures as $enclosure) {
+ $enc = new FeedEnclosure();
+
+ $enc->type = "image/generic";
+ $enc->link = $enclosure->getAttribute("url");
+ $enc->height = $enclosure->getAttribute("height");
+ $enc->width = $enclosure->getAttribute("width");
array_push($encs, $enc);
}
diff --git a/classes/feedparser.php b/classes/feedparser.php
index d93c575b2..239fdb7a6 100644
--- a/classes/feedparser.php
+++ b/classes/feedparser.php
@@ -2,6 +2,7 @@
class FeedParser {
private $doc;
private $error;
+ private $libxml_errors = array();
private $items;
private $link;
private $title;
@@ -12,27 +13,75 @@ class FeedParser {
const FEED_RSS = 1;
const FEED_ATOM = 2;
+ function normalize_encoding($data) {
+ if (preg_match('/^(<\?xml[\t\n\r ].*?encoding[\t\n\r ]*=[\t\n\r ]*["\'])(.+?)(["\'].*?\?>)/s', $data, $matches) === 1) {
+ $data = mb_convert_encoding($data, 'UTF-8', $matches[2]);
+
+ $data = preg_replace('/^<\?xml[\t\n\r ].*?\?>/s', $matches[1] . "UTF-8" . $matches[3] , $data);
+ }
+
+ return $data;
+ }
+
function __construct($data) {
libxml_use_internal_errors(true);
libxml_clear_errors();
$this->doc = new DOMDocument();
$this->doc->loadXML($data);
+ mb_substitute_character("none");
+
$error = libxml_get_last_error();
- if ($error && $error->code == 9) {
- libxml_clear_errors();
+ // libxml compiled without iconv?
+ if ($error && $error->code == 32) {
+ $data = $this->normalize_encoding($data);
- // we might want to try guessing input encoding here too
- $data = iconv("UTF-8", "UTF-8//IGNORE", $data);
+ if ($data) {
+ libxml_clear_errors();
- $this->doc = new DOMDocument();
- $this->doc->loadXML($data);
+ $this->doc = new DOMDocument();
+ $this->doc->loadXML($data);
- $error = libxml_get_last_error();
+ $error = libxml_get_last_error();
+ }
}
- $this->error = $this->format_error($error);
+ // some terrible invalid unicode entity?
+ if ($error) {
+ foreach (libxml_get_errors() as $err) {
+ if ($err->code == 9) {
+ // if the source feed is not in utf8, next conversion will fail
+ $data = $this->normalize_encoding($data);
+
+ // remove dangling bytes
+ $data = mb_convert_encoding($data, 'UTF-8', 'UTF-8');
+
+ // apparently not all UTF-8 characters are valid for XML
+ $data = preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $data);
+
+ if ($data) {
+ libxml_clear_errors();
+
+ $this->doc = new DOMDocument();
+ $this->doc->loadXML($data);
+
+ $error = libxml_get_last_error();
+ }
+ break;
+ }
+ }
+ }
+
+ if ($error) {
+ foreach (libxml_get_errors() as $error) {
+ if ($error->level == LIBXML_ERR_FATAL) {
+ if(!isset($this->error)) //currently only the first error is reported
+ $this->error = $this->format_error($error);
+ $this->libxml_errors [] = $this->format_error($error);
+ }
+ }
+ }
libxml_clear_errors();
$this->items = array();
@@ -48,27 +97,32 @@ class FeedParser {
$xpath->registerNamespace('slash', 'http://purl.org/rss/1.0/modules/slash/');
$xpath->registerNamespace('dc', 'http://purl.org/dc/elements/1.1/');
$xpath->registerNamespace('content', 'http://purl.org/rss/1.0/modules/content/');
+ $xpath->registerNamespace('thread', 'http://purl.org/syndication/thread/1.0');
$this->xpath = $xpath;
- $root = $xpath->query("(//atom03:feed|//atom:feed|//channel|//rdf:rdf|//rdf:RDF)")->item(0);
-
- if ($root) {
- switch (mb_strtolower($root->tagName)) {
- case "rdf:rdf":
- $this->type = $this::FEED_RDF;
- break;
- case "channel":
- $this->type = $this::FEED_RSS;
- break;
- case "feed":
- $this->type = $this::FEED_ATOM;
- break;
- default:
- if( !isset($this->error) ){
- $this->error = "Unknown/unsupported feed type";
+ $root = $xpath->query("(//atom03:feed|//atom:feed|//channel|//rdf:rdf|//rdf:RDF)");
+
+ if ($root && $root->length > 0) {
+ $root = $root->item(0);
+
+ if ($root) {
+ switch (mb_strtolower($root->tagName)) {
+ case "rdf:rdf":
+ $this->type = $this::FEED_RDF;
+ break;
+ case "channel":
+ $this->type = $this::FEED_RSS;
+ break;
+ case "feed":
+ $this->type = $this::FEED_ATOM;
+ break;
+ default:
+ if( !isset($this->error) ){
+ $this->error = "Unknown/unsupported feed type";
+ }
+ return;
}
- return;
}
switch ($this->type) {
@@ -151,6 +205,10 @@ class FeedParser {
break;
}
+
+ if ($this->title) $this->title = trim($this->title);
+ if ($this->link) $this->link = trim($this->link);
+
} else {
if( !isset($this->error) ){
$this->error = "Unknown/unsupported feed type";
@@ -173,6 +231,10 @@ class FeedParser {
return $this->error;
}
+ function errors() {
+ return $this->libxml_errors;
+ }
+
function get_link() {
return $this->link;
}
@@ -194,7 +256,7 @@ class FeedParser {
foreach ($links as $link) {
if (!$rel || $link->hasAttribute('rel') && $link->getAttribute('rel') == $rel) {
- array_push($rv, $link->getAttribute('href'));
+ array_push($rv, trim($link->getAttribute('href')));
}
}
break;
@@ -203,7 +265,7 @@ class FeedParser {
foreach ($links as $link) {
if (!$rel || $link->hasAttribute('rel') && $link->getAttribute('rel') == $rel) {
- array_push($rv, $link->getAttribute('href'));
+ array_push($rv, trim($link->getAttribute('href')));
}
}
break;
diff --git a/classes/feeds.php b/classes/feeds.php
index 83736925c..5ec109614 100644
--- a/classes/feeds.php
+++ b/classes/feeds.php
@@ -13,12 +13,6 @@ class Feeds extends Handler_Protected {
$feed_id, $is_cat, $search,
$search_mode, $view_mode, $error, $feed_last_updated) {
- $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()";
@@ -43,14 +37,24 @@ class Feeds extends Handler_Protected {
$search_q = "";
}
+ $reply .= "<span class=\"holder\">";
+
$rss_link = htmlspecialchars(get_self_url_prefix() .
"/public.php?op=rss&id=$feed_id$cat_q$search_q");
// right part
- $reply .= "<span class='r'>";
- $reply .= "<span id='selected_prompt'></span>";
- $reply .= "<span id='feed_title'>";
+ $error_class = $error ? "error" : "";
+
+ $reply .= "<span class='r'>
+ <a href=\"#\"
+ title=\"".__("View as RSS feed")."\"
+ onclick=\"displayDlg('".__("View as RSS")."','generatedFeed', '$feed_id:$is_cat:$rss_link')\">
+ <img class=\"noborder\" src=\"images/pub_set.png\"></a>";
+
+
+# $reply .= "<span>";
+ $reply .= "<span id='feed_title' class='$error_class'>";
if ($feed_site_url) {
$last_updated = T_sprintf("Last updated: %s",
@@ -58,10 +62,11 @@ class Feeds extends Handler_Protected {
$target = "target=\"_blank\"";
$reply .= "<a title=\"$last_updated\" $target href=\"$feed_site_url\">".
- truncate_string($feed_title,30)."</a>";
+ truncate_string($feed_title, 30)."</a>";
if ($error) {
- $reply .= " (<span class=\"error\" title=\"$error\">Error</span>)";
+ $error = htmlspecialchars($error);
+ $reply .= "&nbsp;<img title=\"$error\" src='images/error.png' alt='error' class=\"noborder\">";
}
} else {
@@ -70,17 +75,16 @@ class Feeds extends Handler_Protected {
$reply .= "</span>";
- $reply .= "
- <a href=\"#\"
- title=\"".__("View as RSS feed")."\"
- onclick=\"displayDlg('".__("View as RSS")."','generatedFeed', '$feed_id:$is_cat:$rss_link')\">
- <img class=\"noborder\" style=\"vertical-align : middle\" src=\"images/pub_set.svg\"></a>";
-
$reply .= "</span>";
+# $reply .= "</span>";
+
// left part
- $reply .= __('Select:')."
+ $reply .= "<span class=\"main\">";
+ $reply .= "<span id='selected_prompt'></span>";
+
+ $reply .= "
<a href=\"#\" onclick=\"$sel_all_link\">".__('All')."</a>,
<a href=\"#\" onclick=\"$sel_unread_link\">".__('Unread')."</a>,
<a href=\"#\" onclick=\"$sel_inv_link\">".__('Invert')."</a>,
@@ -129,14 +133,14 @@ class Feeds extends Handler_Protected {
$reply .= "</select>";
- //$reply .= "</div>";
-
//$reply .= "</h2";
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HEADLINE_TOOLBAR_BUTTON) as $p) {
- echo $p->hook_headline_toolbar_button($feed_id, $is_cat);
+ $reply .= $p->hook_headline_toolbar_button($feed_id, $is_cat);
}
+ $reply .= "</span></span>";
+
return $reply;
}
@@ -145,7 +149,7 @@ class Feeds extends Handler_Protected {
$override_order = false, $include_children = false) {
if (isset($_REQUEST["DevForceUpdate"]))
- header("Content-Type: text/plain");
+ header("Content-Type: text/plain; charset=utf-8");
$disable_cache = false;
@@ -244,6 +248,8 @@ class Feeds extends Handler_Protected {
false, 0, $include_children);
}
+ $vfeed_group_enabled = get_pref("VFEED_GROUP_BY_FEED") && $feed != -6;
+
if ($_REQUEST["debug"]) $timing_info = print_checkpoint("H1", $timing_info);
$result = $qfh_ret[0];
@@ -252,6 +258,7 @@ class Feeds extends Handler_Protected {
$last_error = $qfh_ret[3];
$last_updated = strpos($qfh_ret[4], '1970-') === FALSE ?
make_local_datetime($qfh_ret[4], false) : __("Never");
+ $highlight_words = $qfh_ret[5];
$vgroup_last_feed = $vgr_last_feed;
@@ -274,6 +281,12 @@ class Feeds extends Handler_Protected {
}
} */
+ if ($offset == 0) {
+ foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HEADLINES_BEFORE) as $p) {
+ $reply['content'] .= $p->hook_headlines_before($feed, $cat_view, $qfh_ret);
+ }
+ }
+
if ($this->dbh->num_rows($result) > 0) {
$lnum = $offset;
@@ -281,13 +294,21 @@ class Feeds extends Handler_Protected {
$num_unread = 0;
$cur_feed_title = '';
- $fresh_intl = get_pref("FRESH_ARTICLE_MAX_AGE") * 60 * 60;
-
if ($_REQUEST["debug"]) $timing_info = print_checkpoint("PS", $timing_info);
$expand_cdm = get_pref('CDM_EXPANDED');
while ($line = $this->dbh->fetch_assoc($result)) {
+ $line["content_preview"] = "&mdash; " . truncate_string(strip_tags($line["content"]), 250);
+
+ foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
+ $line = $p->hook_query_headlines($line, 250, false);
+ }
+
+ if (get_pref('SHOW_CONTENT_PREVIEW')) {
+ $content_preview = $line["content_preview"];
+ }
+
$id = $line["id"];
$feed_id = $line["feed_id"];
$label_cache = $line["label_cache"];
@@ -306,7 +327,7 @@ class Feeds extends Handler_Protected {
if (!is_array($labels)) $labels = get_article_labels($id);
- $labels_str = "<span id=\"HLLCTR-$id\">";
+ $labels_str = "<span class=\"HLLCTR-$id\">";
$labels_str .= format_article_labels($labels, $id);
$labels_str .= "</span>";
@@ -323,24 +344,24 @@ class Feeds extends Handler_Protected {
if (sql_bool_to_bool($line["marked"])) {
$marked_pic = "<img
- src=\"images/mark_set.svg\"
+ src=\"images/mark_set.png\"
class=\"markedPic\" alt=\"Unstar article\"
onclick='toggleMark($id)'>";
$class .= " marked";
} else {
$marked_pic = "<img
- src=\"images/mark_unset.svg\"
+ src=\"images/mark_unset.png\"
class=\"markedPic\" alt=\"Star article\"
onclick='toggleMark($id)'>";
}
if (sql_bool_to_bool($line["published"])) {
- $published_pic = "<img src=\"images/pub_set.svg\"
+ $published_pic = "<img src=\"images/pub_set.png\"
class=\"pubPic\"
alt=\"Unpublish article\" onclick='togglePub($id)'>";
$class .= " published";
} else {
- $published_pic = "<img src=\"images/pub_unset.svg\"
+ $published_pic = "<img src=\"images/pub_unset.png\"
class=\"pubPic\"
alt=\"Publish article\" onclick='togglePub($id)'>";
}
@@ -360,11 +381,6 @@ class Feeds extends Handler_Protected {
$date_entered_fmt = T_sprintf("Imported at %s",
make_local_datetime($line["date_entered"], false));
- if (get_pref('SHOW_CONTENT_PREVIEW')) {
- $content_preview = truncate_string(strip_tags($line["content_preview"]),
- 250);
- }
-
$score = $line["score"];
$score_pic = "images/" . get_score_pic($score);
@@ -377,9 +393,9 @@ class Feeds extends Handler_Protected {
title=\"$score\">";
if ($score > 500) {
- $hlc_suffix = "H";
+ $hlc_suffix = "high";
} else if ($score < -100) {
- $hlc_suffix = "L";
+ $hlc_suffix = "low";
} else {
$hlc_suffix = "";
}
@@ -395,7 +411,7 @@ class Feeds extends Handler_Protected {
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/pub_set.svg\" alt=\"\">";
+ $feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"images/pub_set.png\" alt=\"\">";
}
$entry_site_url = $line["site_url"];
@@ -413,7 +429,7 @@ class Feeds extends Handler_Protected {
if (!get_pref('COMBINED_DISPLAY_MODE')) {
- if (get_pref('VFEED_GROUP_BY_FEED')) {
+ if ($vfeed_group_enabled) {
if ($feed_id != $vgroup_last_feed && $line["feed_title"]) {
$cur_feed_title = $line["feed_title"];
@@ -421,12 +437,12 @@ class Feeds extends Handler_Protected {
$cur_feed_title = htmlspecialchars($cur_feed_title);
- $vf_catchup_link = "(<a class='catchup' onclick='catchupFeedInGroup($feed_id);' href='#'>".__('Mark as read')."</a>)";
+ $vf_catchup_link = "<a class='catchup' onclick='catchupFeedInGroup($feed_id);' href='#'>".__('mark feed as read')."</a>";
- $reply['content'] .= "<div class='cdmFeedTitle'>".
- "<div style=\"float : right\">$feed_icon_img</div>".
- "<a class='title' href=\"#\" onclick=\"viewfeed($feed_id)\">".
- $line["feed_title"]."</a> $vf_catchup_link</div>";
+ $reply['content'] .= "<div id='FTITLE-$feed_id' class='cdmFeedTitle'>".
+ "<div style='float : right'>$feed_icon_img</div>".
+ "<a class='title' href=\"#\" onclick=\"viewfeed($feed_id)\">". $line["feed_title"]."</a>
+ $vf_catchup_link</div>";
}
}
@@ -434,7 +450,7 @@ class Feeds extends Handler_Protected {
$mouseover_attrs = "onmouseover='postMouseIn(event, $id)'
onmouseout='postMouseOut($id)'";
- $reply['content'] .= "<div class='hl $class' id='RROW-$id' $mouseover_attrs>";
+ $reply['content'] .= "<div class='hl $class' orig-feed-id='$feed_id' id='RROW-$id' $mouseover_attrs>";
$reply['content'] .= "<div class='hlLeft'>";
@@ -448,16 +464,14 @@ class Feeds extends Handler_Protected {
$reply['content'] .= "</div>";
$reply['content'] .= "<div onclick='return hlClicked(event, $id)'
- class=\"hlTitle\"><span class='hlContent$hlc_suffix'>";
- $reply['content'] .= "<a id=\"RTITLE-$id\" class=\"title\"
+ class=\"hlTitle\"><span class='hlContent $hlc_suffix'>";
+ $reply['content'] .= "<a id=\"RTITLE-$id\" class=\"title $hlc_suffix\"
href=\"" . htmlspecialchars($line["link"]) . "\"
onclick=\"\">" .
truncate_string($line["title"], 200);
if (get_pref('SHOW_CONTENT_PREVIEW')) {
- if ($content_preview) {
- $reply['content'] .= "<span class=\"contentPreview\"> - $content_preview</span>";
- }
+ $reply['content'] .= "<span class=\"contentPreview\">" . $line["content_preview"] . "</span>";
}
$reply['content'] .= "</a></span>";
@@ -466,17 +480,18 @@ class Feeds extends Handler_Protected {
$reply['content'] .= "</div>";
- $reply['content'] .= "<span class=\"hlUpdated\">";
-
- if (!get_pref('VFEED_GROUP_BY_FEED')) {
+ if (!$vfeed_group_enabled) {
if (@$line["feed_title"]) {
$rgba = @$rgba_cache[$feed_id];
- $reply['content'] .= "<a class=\"hlFeed\" style=\"background : rgba($rgba, 0.3)\" href=\"#\" onclick=\"viewfeed($feed_id)\">".
- truncate_string($line["feed_title"],30)."</a>";
+ $reply['content'] .= "<span class=\"hlFeed\"><a style=\"background : rgba($rgba, 0.3)\" href=\"#\" onclick=\"viewfeed($feed_id)\">".
+ truncate_string($line["feed_title"],30)."</a></span>";
}
}
+
+ $reply['content'] .= "<span class=\"hlUpdated\">";
+
$reply['content'] .= "<div title='$date_entered_fmt'>$updated_fmt</div>
</span>";
@@ -484,12 +499,12 @@ class Feeds extends Handler_Protected {
$reply['content'] .= $score_pic;
- if ($line["feed_title"] && !get_pref('VFEED_GROUP_BY_FEED')) {
+ if ($line["feed_title"] && !$vfeed_group_enabled) {
$reply['content'] .= "<span onclick=\"viewfeed($feed_id)\"
style=\"cursor : pointer\"
title=\"".htmlspecialchars($line['feed_title'])."\">
- $feed_icon_img<span>";
+ $feed_icon_img</span>";
}
$reply['content'] .= "</div>";
@@ -502,14 +517,14 @@ class Feeds extends Handler_Protected {
else
$tags = false;
- $line["content"] = sanitize($line["content_preview"],
- sql_bool_to_bool($line['hide_images']), false, $entry_site_url);
+ $line["content"] = sanitize($line["content"],
+ sql_bool_to_bool($line['hide_images']), false, $entry_site_url, $highlight_words, $line["id"]);
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE_CDM) as $p) {
$line = $p->hook_render_article_cdm($line);
}
- if (get_pref('VFEED_GROUP_BY_FEED') && $line["feed_title"]) {
+ if ($vfeed_group_enabled && $line["feed_title"]) {
if ($feed_id != $vgroup_last_feed) {
$cur_feed_title = $line["feed_title"];
@@ -517,7 +532,7 @@ class Feeds extends Handler_Protected {
$cur_feed_title = htmlspecialchars($cur_feed_title);
- $vf_catchup_link = "(<a class='catchup' onclick='javascript:catchupFeedInGroup($feed_id);' href='#'>".__('mark as read')."</a>)";
+ $vf_catchup_link = "<a class='catchup' onclick='catchupFeedInGroup($feed_id);' href='#'>".__('mark feed as read')."</a>";
$has_feed_icon = feed_has_icon($feed_id);
@@ -527,7 +542,7 @@ class Feeds extends Handler_Protected {
//$feed_icon_img = "<img class=\"tinyFeedIcon\" src=\"images/blank_icon.gif\" alt=\"\">";
}
- $reply['content'] .= "<div class='cdmFeedTitle'>".
+ $reply['content'] .= "<div id='FTITLE-$feed_id' class='cdmFeedTitle'>".
"<div style=\"float : right\">$feed_icon_img</div>".
"<a href=\"#\" class='title' onclick=\"viewfeed($feed_id)\">".
$line["feed_title"]."</a> $vf_catchup_link</div>";
@@ -539,10 +554,10 @@ class Feeds extends Handler_Protected {
$expanded_class = $expand_cdm ? "expanded" : "expandable";
- $reply['content'] .= "<div class=\"cdm $expanded_class $class\"
- id=\"RROW-$id\" $mouseover_attrs>";
+ $reply['content'] .= "<div class=\"cdm $hlc_suffix $expanded_class $class\"
+ id=\"RROW-$id\" orig-feed-id='$feed_id' $mouseover_attrs>";
- $reply['content'] .= "<div class=\"cdmHeader\" style=\"$row_background\">";
+ $reply['content'] .= "<div class=\"cdmHeader\">";
$reply['content'] .= "<div style=\"vertical-align : middle\">";
$reply['content'] .= "<input dojoType=\"dijit.form.CheckBox\"
@@ -554,10 +569,17 @@ class Feeds extends Handler_Protected {
$reply['content'] .= "</div>";
+ if ($highlight_words && count($highlight_words > 0)) {
+ foreach ($highlight_words as $word) {
+ $line["title"] = preg_replace("/(\Q$word\E)/i",
+ "<span class=\"highlight\">$1</span>", $line["title"]);
+ }
+ }
+
$reply['content'] .= "<span id=\"RTITLE-$id\"
onclick=\"return cdmClicked(event, $id);\"
- class=\"titleWrap$hlc_suffix\">
- <a class=\"title\"
+ class=\"titleWrap $hlc_suffix\">
+ <a class=\"title $hlc_suffix\"
target=\"_blank\" href=\"".
htmlspecialchars($line["link"])."\">".
$line["title"] .
@@ -574,11 +596,11 @@ class Feeds extends Handler_Protected {
else
$excerpt_hidden = "style=\"display : none\"";
- $reply['content'] .= "<span $excerpt_hidden
- id=\"CEXC-$id\" class=\"cdmExcerpt\"> - $content_preview</span>";
+ $reply['content'] .= "<span $excerpt_hidden id=\"CEXC-$id\" class=\"cdmExcerpt\">" . $content_preview . "</span>";
+
$reply['content'] .= "</span>";
- if (!get_pref('VFEED_GROUP_BY_FEED')) {
+ if (!$vfeed_group_enabled) {
if (@$line["feed_title"]) {
$rgba = @$rgba_cache[$feed_id];
@@ -615,7 +637,9 @@ class Feeds extends Handler_Protected {
}
$reply['content'] .= "</div>";
- $reply['content'] .= "<div class=\"cdmContentInner\">";
+ if (!$line['lang']) $line['lang'] = 'en';
+
+ $reply['content'] .= "<div class=\"cdmContentInner\" lang=\"".$line['lang']."\">";
if ($line["orig_feed_id"]) {
@@ -638,7 +662,7 @@ class Feeds extends Handler_Protected {
$reply['content'] .= "&nbsp;";
$reply['content'] .= "<a target='_blank' href='" . htmlspecialchars($tmp_line['feed_url']) . "'>";
- $reply['content'] .= "<img title='".__('Feed URL')."'class='tinyFeedIcon' src='images/pub_unset.svg'></a>";
+ $reply['content'] .= "<img title='".__('Feed URL')."'class='tinyFeedIcon' src='images/pub_unset.png'></a>";
$reply['content'] .= "</div>";
}
@@ -685,10 +709,13 @@ class Feeds extends Handler_Protected {
} else {
$comments_url = htmlspecialchars($line["link"]);
}
- $entry_comments = "<a target='_blank' href=\"$comments_url\">$num_comments comments</a>";
+ $entry_comments = "<a class=\"postComments\"
+ target='_blank' href=\"$comments_url\">$num_comments ".
+ _ngettext("comment", "comments", $num_comments)."</a>";
+
} else {
if ($line["comments"] && $line["link"] != $line["comments"]) {
- $entry_comments = "<a target='_blank' href=\"".htmlspecialchars($line["comments"])."\">comments</a>";
+ $entry_comments = "<a class=\"postComments\" target='_blank' href=\"".htmlspecialchars($line["comments"])."\">".__("comments")."</a>";
}
}
@@ -706,7 +733,7 @@ class Feeds extends Handler_Protected {
$reply['content'] .= "</div>";
$reply['content'] .= "</div>";
- $reply['content'] .= "</div><hr/>";
+ $reply['content'] .= "</div>";
$reply['content'] .= "</div>";
@@ -784,8 +811,6 @@ class Feeds extends Handler_Protected {
if ($_REQUEST["debug"]) $timing_info = print_checkpoint("0", $timing_info);
- $omode = $this->dbh->escape_string($_REQUEST["omode"]);
-
$feed = $this->dbh->escape_string($_REQUEST["feed"]);
$method = $this->dbh->escape_string($_REQUEST["m"]);
$view_mode = $this->dbh->escape_string($_REQUEST["view_mode"]);
@@ -863,7 +888,7 @@ class Feeds extends Handler_Protected {
$override_order = "ttrss_entries.title";
break;
case "date_reverse":
- $override_order = "date_entered, updated";
+ $override_order = "score DESC, date_entered, updated";
break;
case "feed_dates":
$override_order = "updated DESC";
@@ -878,7 +903,7 @@ class Feeds extends Handler_Protected {
//$topmost_article_ids = $ret[0];
$headlines_count = $ret[1];
- $returned_feed = $ret[2];
+ /* $returned_feed = $ret[2]; */
$disable_cache = $ret[3];
$vgroup_last_feed = $ret[4];
@@ -959,6 +984,10 @@ class Feeds extends Handler_Protected {
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"op\" value=\"rpc\">";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"method\" value=\"addfeed\">";
+ print "<div id='fadd_multiple_notify' style='display : none'>";
+ print_notice("Provided URL is a HTML page referencing multiple feeds, please select required feed from the dropdown menu below.");
+ print "<p></div>";
+
print "<div class=\"dlgSec\">".__("Feed or site URL")."</div>";
print "<div class=\"dlgSecCont\">";
@@ -1054,20 +1083,18 @@ class Feeds extends Handler_Protected {
print " <select dojoType=\"dijit.form.Select\" name=\"limit\" onchange=\"dijit.byId('feedBrowserDlg').update()\">";
foreach (array(25, 50, 100, 200) as $l) {
- $issel = ($l == $limit) ? "selected=\"1\"" : "";
- print "<option $issel value=\"$l\">$l</option>";
+ //$issel = ($l == $limit) ? "selected=\"1\"" : "";
+ print "<option value=\"$l\">$l</option>";
}
print "</select> ";
print "</div>";
- $owner_uid = $_SESSION["uid"];
-
require_once "feedbrowser.php";
print "<ul class='browseFeedList' id='browseFeedList'>";
- print make_feed_browser($search, 25);
+ print make_feed_browser("", 25);
print "</ul>";
print "<div align='center'>
@@ -1126,9 +1153,9 @@ class Feeds extends Handler_Protected {
print "<div class=\"dlgButtons\">";
- if (!SPHINX_ENABLED) {
+ if (count(PluginHost::getInstance()->get_hooks(PluginHost::HOOK_SEARCH)) == 0) {
print "<div style=\"float : left\">
- <a class=\"visibleLink\" target=\"_blank\" href=\"http://tt-rss.org/wiki/SearchSyntax\">Search syntax</a>
+ <a class=\"visibleLink\" target=\"_blank\" href=\"http://tt-rss.org/wiki/SearchSyntax\">".__("Search syntax")."</a>
</div>";
}
diff --git a/classes/handler/public.php b/classes/handler/public.php
index f05beafd2..34d577441 100644
--- a/classes/handler/public.php
+++ b/classes/handler/public.php
@@ -3,7 +3,7 @@ class Handler_Public extends Handler {
private function generate_syndicated_feed($owner_uid, $feed, $is_cat,
$limit, $offset, $search, $search_mode,
- $view_mode = false, $format = 'atom', $order = false) {
+ $view_mode = false, $format = 'atom', $order = false, $orig_guid = false, $start_ts = false) {
require_once "lib/MiniTemplator.class.php";
@@ -15,11 +15,15 @@ class Handler_Public extends Handler {
if (!$limit) $limit = 60;
$date_sort_field = "date_entered DESC, updated DESC";
+ $date_check_field = "date_entered";
- if ($feed == -2)
+ if ($feed == -2 && !$is_cat) {
$date_sort_field = "last_published DESC";
- else if ($feed == -1)
+ $date_check_field = "last_published";
+ } else if ($feed == -1 && !$is_cat) {
$date_sort_field = "last_marked DESC";
+ $date_check_field = "last_marked";
+ }
switch ($order) {
case "title":
@@ -33,15 +37,18 @@ class Handler_Public extends Handler {
break;
}
+ //function queryFeedHeadlines($feed, $limit, $view_mode, $cat_view, $search, $search_mode, $override_order = false, $offset = 0, $owner_uid = 0, $filter = false, $since_id = 0, $include_children = false, $ignore_vfeed_group = false, $override_strategy = false, $override_vfeed = false, $start_ts = false) {
+
$qfh_ret = queryFeedHeadlines($feed,
1, $view_mode, $is_cat, $search, $search_mode,
$date_sort_field, $offset, $owner_uid,
- false, 0, false, true);
+ false, 0, true, true, false, false, $start_ts);
$result = $qfh_ret[0];
if ($this->dbh->num_rows($result) != 0) {
- $ts = strtotime($this->dbh->fetch_result($result, 0, "date_entered"));
+
+ $ts = strtotime($this->dbh->fetch_result($result, 0, $date_check_field));
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $ts) {
@@ -56,17 +63,17 @@ class Handler_Public extends Handler {
$qfh_ret = queryFeedHeadlines($feed,
$limit, $view_mode, $is_cat, $search, $search_mode,
$date_sort_field, $offset, $owner_uid,
- false, 0, false, true);
+ false, 0, true, true, false, false, $start_ts);
$result = $qfh_ret[0];
$feed_title = htmlspecialchars($qfh_ret[1]);
$feed_site_url = $qfh_ret[2];
- $last_error = $qfh_ret[3];
+ /* $last_error = $qfh_ret[3]; */
$feed_self_url = get_self_url_prefix() .
- "/public.php?op=rss&id=-2&key=" .
- get_feed_access_key(-2, false, $owner_uid);
+ "/public.php?op=rss&id=$feed&key=" .
+ get_feed_access_key($feed, false, $owner_uid);
if (!$feed_site_url) $feed_site_url = get_self_url_prefix();
@@ -85,16 +92,23 @@ class Handler_Public extends Handler {
}
$tpl->setVariable('SELF_URL', htmlspecialchars(get_self_url_prefix()), true);
-
while ($line = $this->dbh->fetch_assoc($result)) {
+ $line["content_preview"] = truncate_string(strip_tags($line["content"]), 100, '...');
+
+ foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
+ $line = $p->hook_query_headlines($line);
+ }
- $tpl->setVariable('ARTICLE_ID', htmlspecialchars($line['link']), true);
+ $tpl->setVariable('ARTICLE_ID',
+ htmlspecialchars($orig_guid ? $line['link'] :
+ get_self_url_prefix() .
+ "/public.php?url=" . urlencode($line['link'])), true);
$tpl->setVariable('ARTICLE_LINK', htmlspecialchars($line['link']), true);
$tpl->setVariable('ARTICLE_TITLE', htmlspecialchars($line['title']), true);
- $tpl->setVariable('ARTICLE_EXCERPT',
- truncate_string(strip_tags($line["content_preview"]), 100, '...'), true);
+ $tpl->setVariable('ARTICLE_EXCERPT', $line["content_preview"], true);
- $content = sanitize($line["content_preview"], false, $owner_uid);
+ $content = sanitize($line["content"], false, $owner_uid,
+ $feed_site_url);
if ($line['note']) {
$content = "<div style=\"$note_style\">Article note: " . $line['note'] . "</div>" .
@@ -111,6 +125,9 @@ class Handler_Public extends Handler {
$tpl->setVariable('ARTICLE_AUTHOR', htmlspecialchars($line['author']), true);
+ $tpl->setVariable('ARTICLE_SOURCE_LINK', htmlspecialchars($line['site_url']), true);
+ $tpl->setVariable('ARTICLE_SOURCE_TITLE', htmlspecialchars($line['feed_title'] ? $line['feed_title'] : $feed_title), true);
+
$tags = get_article_tags($line["id"], $owner_uid);
foreach ($tags as $tag) {
@@ -164,13 +181,17 @@ class Handler_Public extends Handler {
$feed['articles'] = array();
while ($line = $this->dbh->fetch_assoc($result)) {
+ $line["content_preview"] = truncate_string(strip_tags($line["content_preview"]), 100, '...');
+ foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
+ $line = $p->hook_query_headlines($line, 100);
+ }
$article = array();
$article['id'] = $line['link'];
$article['link'] = $line['link'];
$article['title'] = $line['title'];
- $article['excerpt'] = truncate_string(strip_tags($line["content_preview"]), 100, '...');
- $article['content'] = sanitize($line["content_preview"], false, $owner_uid);
+ $article['excerpt'] = $line["content_preview"];
+ $article['content'] = sanitize($line["content"], false, $owner_uid);
$article['updated'] = date('c', strtotime($line["updated"]));
if ($line['note']) $article['note'] = $line['note'];
@@ -256,16 +277,22 @@ class Handler_Public extends Handler {
function pubsub() {
$mode = $this->dbh->escape_string($_REQUEST['hub_mode']);
+ if (!$mode) $mode = $this->dbh->escape_string($_REQUEST['hub.mode']);
+
$feed_id = (int) $this->dbh->escape_string($_REQUEST['id']);
$feed_url = $this->dbh->escape_string($_REQUEST['hub_topic']);
+ if (!$feed_url) $feed_url = $this->dbh->escape_string($_REQUEST['hub.topic']);
+
if (!PUBSUBHUBBUB_ENABLED) {
header('HTTP/1.0 404 Not Found');
- echo "404 Not found";
+ echo "404 Not found (Disabled by server)";
return;
}
// TODO: implement hub_verifytoken checking
+ // TODO: store requested rel=self or whatever for verification
+ // (may be different from stored feed url) e.g. http://url/ or http://url
$result = $this->dbh->query("SELECT feed_url FROM ttrss_feeds
WHERE id = '$feed_id'");
@@ -274,7 +301,8 @@ class Handler_Public extends Handler {
$check_feed_url = $this->dbh->fetch_result($result, 0, "feed_url");
- if ($check_feed_url && ($check_feed_url == $feed_url || !$feed_url)) {
+ // ignore url checking for the time being
+ if ($check_feed_url && (true || $check_feed_url == $feed_url || !$feed_url)) {
if ($mode == "subscribe") {
$this->dbh->query("UPDATE ttrss_feeds SET pubsub_state = 2
@@ -303,11 +331,11 @@ class Handler_Public extends Handler {
}
} else {
header('HTTP/1.0 404 Not Found');
- echo "404 Not found";
+ echo "404 Not found (URL check failed)";
}
} else {
header('HTTP/1.0 404 Not Found');
- echo "404 Not found";
+ echo "404 Not found (Feed not found)";
}
}
@@ -342,7 +370,7 @@ class Handler_Public extends Handler {
function rss() {
$feed = $this->dbh->escape_string($_REQUEST["id"]);
$key = $this->dbh->escape_string($_REQUEST["key"]);
- $is_cat = $_REQUEST["is_cat"] != false;
+ $is_cat = sql_bool_to_bool($_REQUEST["is_cat"]);
$limit = (int)$this->dbh->escape_string($_REQUEST["limit"]);
$offset = (int)$this->dbh->escape_string($_REQUEST["offset"]);
@@ -350,8 +378,10 @@ class Handler_Public extends Handler {
$search_mode = $this->dbh->escape_string($_REQUEST["smode"]);
$view_mode = $this->dbh->escape_string($_REQUEST["view-mode"]);
$order = $this->dbh->escape_string($_REQUEST["order"]);
+ $start_ts = $this->dbh->escape_string($_REQUEST["ts"]);
$format = $this->dbh->escape_string($_REQUEST['format']);
+ $orig_guid = sql_bool_to_bool($_REQUEST["orig_guid"]);
if (!$format) $format = 'atom';
@@ -371,20 +401,24 @@ class Handler_Public extends Handler {
if ($owner_id) {
$this->generate_syndicated_feed($owner_id, $feed, $is_cat, $limit,
- $offset, $search, $search_mode, $view_mode, $format, $order);
+ $offset, $search, $search_mode, $view_mode, $format, $order, $orig_guid, $start_ts);
} else {
header('HTTP/1.1 403 Forbidden');
}
}
- function globalUpdateFeeds() {
- include "rssfuncs.php";
- // Update all feeds needing a update.
- update_daemon_common(0, true, false);
- housekeeping_common(false);
+ function updateTask() {
+ PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", false);
+ }
- PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", $op);
+ function housekeepingTask() {
+ PluginHost::getInstance()->run_hooks(PluginHost::HOOK_HOUSE_KEEPING, "hook_house_keeping", false);
+ }
+
+ function globalUpdateFeeds() {
+ RPC::updaterandomfeed_real($this->dbh);
+ PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", false);
}
function sharepopup() {
@@ -393,11 +427,14 @@ class Handler_Public extends Handler {
}
header('Content-Type: text/html; charset=utf-8');
- print "<html><head><title>Tiny Tiny RSS</title>";
-
- stylesheet_tag("css/utility.css");
- javascript_tag("lib/prototype.js");
- javascript_tag("lib/scriptaculous/scriptaculous.js?load=effects,dragdrop,controls");
+ print "<html><head><title>Tiny Tiny RSS</title>
+ <link rel=\"shortcut icon\" type=\"image/png\" href=\"images/favicon.png\">
+ <link rel=\"icon\" type=\"image/png\" sizes=\"72x72\" href=\"images/favicon-72px.png\">";
+
+ echo stylesheet_tag("css/utility.css");
+ echo stylesheet_tag("css/dijit.css");
+ echo javascript_tag("lib/prototype.js");
+ echo javascript_tag("lib/scriptaculous/scriptaculous.js?load=effects,controls");
print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>
</head><body id='sharepopup'>";
@@ -543,6 +580,7 @@ class Handler_Public extends Handler {
}
} else {
$_SESSION["login_error_msg"] = __("Incorrect username or password");
+ user_error("Failed login attempt for $login from {$_SERVER['REMOTE_ADDR']}", E_USER_WARNING);
}
if ($_REQUEST['return']) {
@@ -553,6 +591,18 @@ class Handler_Public extends Handler {
}
}
+ /* function subtest() {
+ header("Content-type: text/plain; charset=utf-8");
+
+ $url = $_REQUEST["url"];
+
+ print "$url\n\n";
+
+
+ print_r(get_feeds_from_html($url, fetch_file_contents($url)));
+
+ } */
+
function subscribe() {
if (SINGLE_USER_MODE) {
login_sequence();
@@ -568,6 +618,9 @@ class Handler_Public extends Handler {
<title>Tiny Tiny RSS</title>
<link rel=\"stylesheet\" type=\"text/css\" href=\"css/utility.css\">
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>
+ <link rel=\"shortcut icon\" type=\"image/png\" href=\"images/favicon.png\">
+ <link rel=\"icon\" type=\"image/png\" sizes=\"72x72\" href=\"images/favicon-72px.png\">
+
</head>
<body>
<img class=\"floatingLogo\" src=\"images/logo_small.png\"
@@ -652,93 +705,6 @@ class Handler_Public extends Handler {
}
}
- function subscribe2() {
- $feed_url = $this->dbh->escape_string(trim($_REQUEST["feed_url"]));
- $cat_id = $this->dbh->escape_string($_REQUEST["cat_id"]);
- $from = $this->dbh->escape_string($_REQUEST["from"]);
- $feed_urls = array();
-
- /* only read authentication information from POST */
-
- $auth_login = $this->dbh->escape_string(trim($_POST["auth_login"]));
- $auth_pass = $this->dbh->escape_string(trim($_POST["auth_pass"]));
-
- $rc = subscribe_to_feed($feed_url, $cat_id, $auth_login, $auth_pass);
-
- switch ($rc) {
- case 1:
- print_notice(T_sprintf("Subscribed to <b>%s</b>.", $feed_url));
- break;
- case 2:
- print_error(T_sprintf("Could not subscribe to <b>%s</b>.", $feed_url));
- break;
- case 3:
- print_error(T_sprintf("No feeds found in <b>%s</b>.", $feed_url));
- break;
- case 0:
- print_warning(T_sprintf("Already subscribed to <b>%s</b>.", $feed_url));
- break;
- case 4:
- print_notice(__("Multiple feed URLs found."));
- $contents = @fetch_file_contents($url, false, $auth_login, $auth_pass);
- if (is_html($contents)) {
- $feed_urls = get_feeds_from_html($url, $contents);
- }
- break;
- case 5:
- print_error(T_sprintf("Could not subscribe to <b>%s</b>.<br>Can't download the Feed URL.", $feed_url));
- break;
- }
-
- if ($feed_urls) {
- print "<form action=\"backend.php\">";
- print "<input type=\"hidden\" name=\"op\" value=\"pref-feeds\">";
- print "<input type=\"hidden\" name=\"quiet\" value=\"1\">";
- print "<input type=\"hidden\" name=\"method\" value=\"add\">";
-
- print "<select name=\"feed_url\">";
-
- foreach ($feed_urls as $url => $name) {
- $url = htmlspecialchars($url);
- $name = htmlspecialchars($name);
- print "<option value=\"$url\">$name</option>";
- }
-
- print "<input type=\"submit\" value=\"".__("Subscribe to selected feed")."\">";
- print "</form>";
- }
-
- $tp_uri = get_self_url_prefix() . "/prefs.php";
- $tt_uri = get_self_url_prefix();
-
- if ($rc <= 2){
- $result = $this->dbh->query("SELECT id FROM ttrss_feeds WHERE
- feed_url = '$feed_url' AND owner_uid = " . $_SESSION["uid"]);
-
- $feed_id = $this->dbh->fetch_result($result, 0, "id");
- } else {
- $feed_id = 0;
- }
-
- print "<p>";
-
- if ($feed_id) {
- print "<form method=\"GET\" style='display: inline'
- action=\"$tp_uri\">
- <input type=\"hidden\" name=\"tab\" value=\"feedConfig\">
- <input type=\"hidden\" name=\"method\" value=\"editFeed\">
- <input type=\"hidden\" name=\"methodparam\" value=\"$feed_id\">
- <input type=\"submit\" value=\"".__("Edit subscription options")."\">
- </form>";
- }
-
- print "<form style='display: inline' method=\"GET\" action=\"$tt_uri\">
- <input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
- </form></p>";
-
- print "</body></html>";
- }
-
function index() {
header("Content-Type: text/plain");
print json_encode(array("error" => array("code" => 7)));
@@ -747,11 +713,15 @@ class Handler_Public extends Handler {
function forgotpass() {
startup_gettext();
+ @$hash = $_REQUEST["hash"];
+
header('Content-Type: text/html; charset=utf-8');
- print "<html><head><title>Tiny Tiny RSS</title>";
+ print "<html><head><title>Tiny Tiny RSS</title>
+ <link rel=\"shortcut icon\" type=\"image/png\" href=\"images/favicon.png\">
+ <link rel=\"icon\" type=\"image/png\" sizes=\"72x72\" href=\"images/favicon-72px.png\">";
- stylesheet_tag("css/utility.css");
- javascript_tag("lib/prototype.js");
+ echo stylesheet_tag("css/utility.css");
+ echo javascript_tag("lib/prototype.js");
print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>
</head><body id='forgotpass'>";
@@ -762,8 +732,45 @@ class Handler_Public extends Handler {
@$method = $_POST['method'];
- if (!$method) {
- print_notice(__("You will need to provide valid account name and email. New password will be sent on your email address."));
+ if ($hash) {
+ $login = $_REQUEST["login"];
+
+ if ($login) {
+ $result = $this->dbh->query("SELECT id, resetpass_token FROM ttrss_users
+ WHERE login = '$login'");
+
+ if ($this->dbh->num_rows($result) != 0) {
+ $id = $this->dbh->fetch_result($result, 0, "id");
+ $resetpass_token_full = $this->dbh->fetch_result($result, 0, "resetpass_token");
+ list($timestamp, $resetpass_token) = explode(":", $resetpass_token_full);
+
+ if ($timestamp && $resetpass_token &&
+ $timestamp >= time() - 15*60*60 &&
+ $resetpass_token == $hash) {
+
+ $result = $this->dbh->query("UPDATE ttrss_users SET resetpass_token = NULL
+ WHERE id = $id");
+
+ Pref_Users::resetUserPassword($id, true);
+
+ print "<p>"."Completed."."</p>";
+
+ } else {
+ print_error("Some of the information provided is missing or incorrect.");
+ }
+ } else {
+ print_error("Some of the information provided is missing or incorrect.");
+ }
+ } else {
+ print_error("Some of the information provided is missing or incorrect.");
+ }
+
+ print "<form method=\"GET\" action=\"index.php\">
+ <input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
+ </form>";
+
+ } else if (!$method) {
+ print_notice(__("You will need to provide valid account name and email. A password reset link will be sent to your email address."));
print "<form method='POST' action='public.php'>";
print "<input type='hidden' name='method' value='do'>";
@@ -804,17 +811,57 @@ class Handler_Public extends Handler {
} else {
+ print_notice("Password reset instructions are being sent to your email address.");
+
$result = $this->dbh->query("SELECT id FROM ttrss_users
WHERE login = '$login' AND email = '$email'");
if ($this->dbh->num_rows($result) != 0) {
$id = $this->dbh->fetch_result($result, 0, "id");
- Pref_Users::resetUserPassword($id, false);
+ if ($id) {
+ $resetpass_token = sha1(get_random_bytes(128));
+ $resetpass_link = get_self_url_prefix() . "/public.php?op=forgotpass&hash=" . $resetpass_token .
+ "&login=" . urlencode($login);
+
+ require_once 'classes/ttrssmailer.php';
+ require_once "lib/MiniTemplator.class.php";
+
+ $tpl = new MiniTemplator;
+
+ $tpl->readTemplateFromFile("templates/resetpass_link_template.txt");
+
+ $tpl->setVariable('LOGIN', $login);
+ $tpl->setVariable('RESETPASS_LINK', $resetpass_link);
- print "<p>";
+ $tpl->addBlock('message');
- print "<p>"."Completed."."</p>";
+ $message = "";
+
+ $tpl->generateOutputToString($message);
+
+ $mail = new ttrssMailer();
+
+ $rc = $mail->quickMail($email, $login,
+ __("[tt-rss] Password reset request"),
+ $message, false);
+
+ if (!$rc) print_error($mail->ErrorInfo);
+
+ $resetpass_token_full = $this->dbh->escape_string(time() . ":" . $resetpass_token);
+
+ $result = $this->dbh->query("UPDATE ttrss_users
+ SET resetpass_token = '$resetpass_token_full'
+ WHERE login = '$login' AND email = '$email'");
+
+ //Pref_Users::resetUserPassword($id, false);
+
+ print "<p>";
+
+ print "<p>"."Completed."."</p>";
+ } else {
+ print_error("User ID not found.");
+ }
print "<form method=\"GET\" action=\"index.php\">
<input type=\"submit\" value=\"".__("Return to Tiny Tiny RSS")."\">
@@ -853,6 +900,8 @@ class Handler_Public extends Handler {
<title>Database Updater</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<link rel="stylesheet" type="text/css" href="css/utility.css"/>
+ <link rel=\"shortcut icon\" type=\"image/png\" href=\"images/favicon.png\">
+ <link rel=\"icon\" type=\"image/png\" sizes=\"72x72\" href=\"images/favicon-72px.png\">
</head>
<style type="text/css">
span.ok { color : #009000; font-weight : bold; }
diff --git a/classes/opml.php b/classes/opml.php
index c5d14cdde..c8c59e8a2 100644
--- a/classes/opml.php
+++ b/classes/opml.php
@@ -97,7 +97,7 @@ class Opml extends Handler_Protected {
$html_url_qpart = "";
}
- $out .= "<outline text=\"$title\" xmlUrl=\"$url\" $html_url_qpart/>\n";
+ $out .= "<outline type=\"rss\" text=\"$title\" xmlUrl=\"$url\" $html_url_qpart/>\n";
}
if ($cat_title) $out .= "</outline>\n";
@@ -190,6 +190,7 @@ class Opml extends Handler_Protected {
}
$tmp_line["cat_filter"] = sql_bool_to_bool($tmp_line["cat_filter"]);
+ $tmp_line["inverse"] = sql_bool_to_bool($tmp_line["inverse"]);
unset($tmp_line["feed_id"]);
unset($tmp_line["cat_id"]);
@@ -256,8 +257,8 @@ class Opml extends Handler_Protected {
$feed_title = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('text')->nodeValue, 0, 250));
if (!$feed_title) $feed_title = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('title')->nodeValue, 0, 250));
- $feed_url = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('xmlUrl')->nodeValue, 0, 250));
- if (!$feed_url) $feed_url = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('xmlURL')->nodeValue, 0, 250));
+ $feed_url = $this->dbh->escape_string($attrs->getNamedItem('xmlUrl')->nodeValue);
+ if (!$feed_url) $feed_url = $this->dbh->escape_string($attrs->getNamedItem('xmlURL')->nodeValue);
$site_url = $this->dbh->escape_string(mb_substr($attrs->getNamedItem('htmlUrl')->nodeValue, 0, 250));
@@ -363,9 +364,10 @@ class Opml extends Handler_Protected {
$cat_filter = bool_to_sql_bool($rule["cat_filter"]);
$reg_exp = $this->dbh->escape_string($rule["reg_exp"]);
$filter_type = (int)$rule["filter_type"];
+ $inverse = bool_to_sql_bool($rule["inverse"]);
- $this->dbh->query("INSERT INTO ttrss_filters2_rules (feed_id,cat_id,filter_id,filter_type,reg_exp,cat_filter)
- VALUES ($feed_id, $cat_id, $filter_id, $filter_type, '$reg_exp', $cat_filter)");
+ $this->dbh->query("INSERT INTO ttrss_filters2_rules (feed_id,cat_id,filter_id,filter_type,reg_exp,cat_filter,inverse)
+ VALUES ($feed_id, $cat_id, $filter_id, $filter_type, '$reg_exp', $cat_filter,$inverse)");
}
foreach ($filter["actions"] as $action) {
diff --git a/classes/pluginhost.php b/classes/pluginhost.php
index 53adf01f9..1ad7afd60 100644
--- a/classes/pluginhost.php
+++ b/classes/pluginhost.php
@@ -37,6 +37,12 @@ class PluginHost {
const HOOK_PREFS_EDIT_FEED = 20;
const HOOK_PREFS_SAVE_FEED = 21;
const HOOK_FETCH_FEED = 22;
+ const HOOK_QUERY_HEADLINES = 23;
+ const HOOK_HOUSE_KEEPING = 24;
+ const HOOK_SEARCH = 25;
+ const HOOK_FORMAT_ENCLOSURES = 26;
+ const HOOK_SUBSCRIBE_FEED = 27;
+ const HOOK_HEADLINES_BEFORE = 28;
const KIND_ALL = 1;
const KIND_SYSTEM = 2;
@@ -73,6 +79,16 @@ class PluginHost {
return $this->dbh;
}
+ function get_plugin_names() {
+ $names = array();
+
+ foreach ($this->plugins as $p) {
+ array_push($names, get_class($p));
+ }
+
+ return $names;
+ }
+
function get_plugins() {
return $this->plugins;
}
@@ -97,7 +113,7 @@ class PluginHost {
function del_hook($type, $sender) {
if (is_array($this->hooks[$type])) {
- $key = array_Search($this->hooks[$type], $sender);
+ $key = array_Search($sender, $this->hooks[$type]);
if ($key !== FALSE) {
unset($this->hooks[$type][$key]);
}
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php
index d2dc6f7c3..d70c1a26a 100644
--- a/classes/pref/feeds.php
+++ b/classes/pref/feeds.php
@@ -55,6 +55,7 @@ class Pref_Feeds extends Handler_Protected {
$cat['unread'] = 0;
$cat['child_unread'] = 0;
$cat['auxcounter'] = 0;
+ $cat['parent_id'] = $cat_id;
$cat['items'] = $this->get_category_items($line['id']);
@@ -395,7 +396,7 @@ class Pref_Feeds extends Handler_Protected {
# print_r($data['items']);
if (is_array($data) && is_array($data['items'])) {
- $cat_order_id = 0;
+# $cat_order_id = 0;
$data_map = array();
$root_item = false;
@@ -494,7 +495,7 @@ class Pref_Feeds extends Handler_Protected {
$feed_id = $this->dbh->escape_string($_REQUEST["feed_id"]);
if (is_file($icon_file) && $feed_id) {
- if (filesize($icon_file) < 20000) {
+ if (filesize($icon_file) < 65535) {
$result = $this->dbh->query("SELECT id FROM ttrss_feeds
WHERE id = '$feed_id' AND owner_uid = ". $_SESSION["uid"]);
@@ -572,8 +573,9 @@ class Pref_Feeds extends Handler_Protected {
$last_error = $this->dbh->fetch_result($result, 0, "last_error");
if ($last_error) {
- print "&nbsp;<span title=\"".htmlspecialchars($last_error)."\"
- class=\"feed_error\">(error)</span>";
+ print "&nbsp;<img src=\"images/error.png\" alt=\"(error)\"
+ style=\"vertical-align : middle\"
+ title=\"".htmlspecialchars($last_error)."\">";
}
@@ -736,9 +738,9 @@ class Pref_Feeds extends Handler_Protected {
<input type=\"hidden\" name=\"op\" value=\"pref-feeds\">
<input type=\"hidden\" name=\"feed_id\" value=\"$feed_id\">
<input type=\"hidden\" name=\"method\" value=\"uploadicon\">
- <button dojoType=\"dijit.form.Button\" onclick=\"return uploadFeedIcon();\"
+ <button class=\"small\" dojoType=\"dijit.form.Button\" onclick=\"return uploadFeedIcon();\"
type=\"submit\">".__('Replace')."</button>
- <button dojoType=\"dijit.form.Button\" onclick=\"return removeFeedIcon($feed_id);\"
+ <button class=\"small\" dojoType=\"dijit.form.Button\" onclick=\"return removeFeedIcon($feed_id);\"
type=\"submit\">".__('Remove')."</button>
</form>";
@@ -792,31 +794,10 @@ class Pref_Feeds extends Handler_Protected {
print "<div class=\"dlgSec\">".__("Feed")."</div>";
print "<div class=\"dlgSecCont\">";
- /* Title */
-
- print "<input dojoType=\"dijit.form.ValidationTextBox\"
- disabled=\"1\" style=\"font-size : 16px; width : 20em;\" required=\"1\"
- name=\"title\" value=\"\">";
-
- $this->batch_edit_cbox("title");
-
- /* Feed URL */
-
- print "<br/>";
-
- print __('URL:') . " ";
- print "<input dojoType=\"dijit.form.ValidationTextBox\" disabled=\"1\"
- required=\"1\" regExp='^(http|https)://.*' style=\"width : 20em\"
- name=\"feed_url\" value=\"\">";
-
- $this->batch_edit_cbox("feed_url");
-
/* Category */
if (get_pref('ENABLE_FEED_CATS')) {
- print "<br/>";
-
print __('Place in category:') . " ";
print_feed_cat_select("cat_id", false,
@@ -862,7 +843,7 @@ class Pref_Feeds extends Handler_Protected {
$this->batch_edit_cbox("auth_login");
- print "<br/><input dojoType=\"dijit.form.TextBox\" type=\"password\" name=\"auth_pass\"
+ print "<hr/> <input dojoType=\"dijit.form.TextBox\" type=\"password\" name=\"auth_pass\"
placeHolder=\"".__("Password")."\" disabled=\"1\"
value=\"\">";
@@ -982,7 +963,7 @@ class Pref_Feeds extends Handler_Protected {
if (!$batch) {
- $result = $this->dbh->query("UPDATE ttrss_feeds SET
+ $this->dbh->query("UPDATE ttrss_feeds SET
$category_qpart
title = '$feed_title', feed_url = '$feed_link',
update_interval = '$upd_intl',
@@ -1279,13 +1260,18 @@ class Pref_Feeds extends Handler_Protected {
$interval_qpart = "DATE_SUB(NOW(), INTERVAL 3 MONTH)";
}
- $result = $this->dbh->query("SELECT COUNT(*) AS num_inactive FROM ttrss_feeds WHERE
+ // could be performance-intensive and prevent feeds pref-panel from showing
+ if (!defined('_DISABLE_INACTIVE_FEEDS') || !_DISABLE_INACTIVE_FEEDS) {
+ $result = $this->dbh->query("SELECT COUNT(*) AS num_inactive FROM ttrss_feeds WHERE
(SELECT MAX(updated) FROM ttrss_entries, ttrss_user_entries WHERE
ttrss_entries.id = ref_id AND
ttrss_user_entries.feed_id = ttrss_feeds.id) < $interval_qpart AND
ttrss_feeds.owner_uid = ".$_SESSION["uid"]);
- $num_inactive = $this->dbh->fetch_result($result, 0, "num_inactive");
+ $num_inactive = $this->dbh->fetch_result($result, 0, "num_inactive");
+ } else {
+ $num_inactive = 0;
+ }
if ($num_inactive > 0) {
$inactive_button = "<button dojoType=\"dijit.form.Button\"
@@ -1492,15 +1478,6 @@ class Pref_Feeds extends Handler_Protected {
print "</p>";
- print_warning(__("You can disable all articles shared by unique URLs here."));
-
- print "<p>";
-
- print "<button dojoType=\"dijit.form.Button\" onclick=\"return clearArticleAccessKeys()\">".
- __('Unshare all articles')."</button> ";
-
- print "</p>";
-
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION,
"hook_prefs_tab_section", "prefFeedsPublishedGenerated");
@@ -1602,8 +1579,6 @@ class Pref_Feeds extends Handler_Protected {
# class needed for selectTableRows()
print "<tr class=\"placeholder\" $this_row_id>";
- $edit_title = htmlspecialchars($line["title"]);
-
# id needed for selectTableRows()
print "<td width='5%' align='center'><input
onclick='toggleSelectRow2(this);' dojoType=\"dijit.form.CheckBox\"
@@ -1668,8 +1643,6 @@ class Pref_Feeds extends Handler_Protected {
# class needed for selectTableRows()
print "<tr class=\"placeholder\" $this_row_id>";
- $edit_title = htmlspecialchars($line["title"]);
-
# id needed for selectTableRows()
print "<td width='5%' align='center'><input
onclick='toggleSelectRow2(this);' dojoType=\"dijit.form.CheckBox\"
@@ -1920,7 +1893,7 @@ class Pref_Feeds extends Handler_Protected {
AND owner_uid = " . $owner_uid);
if ($this->dbh->num_rows($result) == 1) {
- $key = $this->dbh->escape_string(sha1(uniqid(rand(), true)));
+ $key = $this->dbh->escape_string(uniqid(base_convert(rand(), 10, 36)));
$this->dbh->query("UPDATE ttrss_access_keys SET access_key = '$key'
WHERE feed_id = '$feed_id' AND is_cat = $sql_is_cat
diff --git a/classes/pref/filters.php b/classes/pref/filters.php
index bcc7b5aec..170c1a527 100644
--- a/classes/pref/filters.php
+++ b/classes/pref/filters.php
@@ -88,7 +88,6 @@ class Pref_Filters extends Handler_Protected {
$result = $qfh_ret[0];
- $articles = array();
$found = 0;
print __("Articles matching this filter:");
@@ -97,12 +96,13 @@ class Pref_Filters extends Handler_Protected {
print "<table width=\"100%\" cellspacing=\"0\" id=\"prefErrorFeedList\">";
while ($line = $this->dbh->fetch_assoc($result)) {
+ $line["content_preview"] = truncate_string(strip_tags($line["content"]), 100, '...');
- $entry_timestamp = strtotime($line["updated"]);
- $entry_tags = get_article_tags($line["id"], $_SESSION["uid"]);
+ foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
+ $line = $p->hook_query_headlines($line, 100);
+ }
- $content_preview = truncate_string(
- strip_tags($line["content_preview"]), 100, '...');
+ $content_preview = $line["content_preview"];
if ($line["feed_title"])
$feed_title = $line["feed_title"];
@@ -147,6 +147,40 @@ class Pref_Filters extends Handler_Protected {
}
+ private function getfilterrules_concise($filter_id) {
+ $result = $this->dbh->query("SELECT reg_exp,
+ inverse,
+ feed_id,
+ cat_id,
+ cat_filter,
+ ttrss_filter_types.description AS field
+ FROM
+ ttrss_filters2_rules, ttrss_filter_types
+ WHERE
+ filter_id = '$filter_id' AND filter_type = ttrss_filter_types.id");
+
+ $rv = "";
+
+ while ($line = $this->dbh->fetch_assoc($result)) {
+
+ $where = sql_bool_to_bool($line["cat_filter"]) ?
+ getCategoryTitle($line["cat_id"]) :
+ ($line["feed_id"] ?
+ getFeedTitle($line["feed_id"]) : __("All feeds"));
+
+# $where = $line["cat_id"] . "/" . $line["feed_id"];
+
+ $inverse = sql_bool_to_bool($line["inverse"]) ? "inverse" : "";
+
+ $rv .= "<span class='$inverse'>" . T_sprintf("%s on %s in %s %s",
+ strip_tags($line["reg_exp"]),
+ $line["field"],
+ $where,
+ sql_bool_to_bool($line["inverse"]) ? __("(inverse)") : "") . "</span>";
+ }
+
+ return $rv;
+ }
function getfiltertree() {
$root = array();
@@ -170,24 +204,11 @@ class Pref_Filters extends Handler_Protected {
owner_uid = ".$_SESSION["uid"]." ORDER BY order_id, title");
- $action_id = -1;
$folder = array();
$folder['items'] = array();
while ($line = $this->dbh->fetch_assoc($result)) {
- /* if ($action_id != $line["action_id"]) {
- if (count($folder['items']) > 0) {
- array_push($root['items'], $folder);
- }
-
- $folder = array();
- $folder['id'] = $line["action_id"];
- $folder['name'] = __($line["action_name"]);
- $folder['items'] = array();
- $action_id = $line["action_id"];
- } */
-
$name = $this->getFilterName($line["id"]);
$match_ok = false;
@@ -223,6 +244,7 @@ class Pref_Filters extends Handler_Protected {
$filter['param'] = $name[1];
$filter['checkbox'] = false;
$filter['enabled'] = sql_bool_to_bool($line["enabled"]);
+ $filter['rules'] = $this->getfilterrules_concise($line['id']);
if (!$filter_search || $match_ok) {
array_push($folder['items'], $filter);
@@ -429,8 +451,11 @@ class Pref_Filters extends Handler_Protected {
WHERE id = ".(int)$rule["filter_type"]);
$filter_type = $this->dbh->fetch_result($result, 0, "description");
- return T_sprintf("%s on %s in %s %s", strip_tags($rule["reg_exp"]),
- $filter_type, $feed, isset($rule["inverse"]) ? __("(inverse)") : "");
+ $inverse = isset($rule["inverse"]) ? "inverse" : "";
+
+ return "<span class='filterRule $inverse'>" .
+ T_sprintf("%s on %s in %s %s", strip_tags($rule["reg_exp"]),
+ $filter_type, $feed, isset($rule["inverse"]) ? __("(inverse)") : "") . "</span>";
}
function printRuleName() {
@@ -467,7 +492,7 @@ class Pref_Filters extends Handler_Protected {
$inverse = checkbox_to_sql_bool($this->dbh->escape_string($_REQUEST["inverse"]));
$title = $this->dbh->escape_string($_REQUEST["title"]);
- $result = $this->dbh->query("UPDATE ttrss_filters2 SET enabled = $enabled,
+ $this->dbh->query("UPDATE ttrss_filters2 SET enabled = $enabled,
match_any_rule = $match_any_rule,
inverse = $inverse,
title = '$title'
@@ -585,14 +610,15 @@ class Pref_Filters extends Handler_Protected {
$enabled = checkbox_to_sql_bool($_REQUEST["enabled"]);
$match_any_rule = checkbox_to_sql_bool($_REQUEST["match_any_rule"]);
$title = $this->dbh->escape_string($_REQUEST["title"]);
+ $inverse = checkbox_to_sql_bool($_REQUEST["inverse"]);
$this->dbh->query("BEGIN");
/* create base filter */
$result = $this->dbh->query("INSERT INTO ttrss_filters2
- (owner_uid, match_any_rule, enabled, title) VALUES
- (".$_SESSION["uid"].",$match_any_rule,$enabled, '$title')");
+ (owner_uid, match_any_rule, enabled, title, inverse) VALUES
+ (".$_SESSION["uid"].",$match_any_rule,$enabled, '$title', $inverse)");
$result = $this->dbh->query("SELECT MAX(id) AS id FROM ttrss_filters2
WHERE owner_uid = ".$_SESSION["uid"]);
@@ -870,6 +896,11 @@ class Pref_Filters extends Handler_Protected {
print "<div class=\"dlgButtons\">";
+ print "<div style=\"float : left\">
+ <a class=\"visibleLink\" target=\"_blank\" href=\"http://tt-rss.org/wiki/ContentFilters\">".__("Wiki: Filters")."</a>
+ </div>";
+
+
print "<button dojoType=\"dijit.form.Button\" onclick=\"return dijit.byId('filterNewRuleDlg').execute()\">".
($rule ? __("Save rule") : __('Add rule'))."</button> ";
diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php
index 32071e3b3..571237239 100644
--- a/classes/pref/prefs.php
+++ b/classes/pref/prefs.php
@@ -181,7 +181,8 @@ class Pref_Prefs extends Handler_Protected {
global $access_level_names;
$prefs_blacklist = array("STRIP_UNSAFE_TAGS", "REVERSE_HEADLINES",
- "SORT_HEADLINES_BY_FEED_DATE", "DEFAULT_ARTICLE_LIMIT");
+ "SORT_HEADLINES_BY_FEED_DATE", "DEFAULT_ARTICLE_LIMIT",
+ "FEEDS_SORT_BY_UNREAD");
/* "FEEDS_SORT_BY_UNREAD", "HIDE_READ_FEEDS", "REVERSE_HEADLINES" */
@@ -765,7 +766,9 @@ class Pref_Prefs extends Handler_Protected {
dojoType=\"dijit.form.CheckBox\" $checked
type=\"checkbox\"></td>";
- print "<td>$name</td>";
+ $plugin_icon = $checked ? "plugin.png" : "plugin_disabled.png";
+
+ print "<td><label><img src='images/$plugin_icon' alt=''> $name</label></td>";
print "<td>" . htmlspecialchars($about[1]);
if (@$about[4]) {
print " &mdash; <a target=\"_blank\" class=\"visibleLink\"
@@ -818,11 +821,13 @@ class Pref_Prefs extends Handler_Protected {
print "<tr class='$rowclass'>";
+ $plugin_icon = $checked ? "plugin.png" : "plugin_disabled.png";
+
print "<td align='center'><input id='FPCHK-$name' name='plugins[]' value='$name' onclick='toggleSelectRow2(this);'
dojoType=\"dijit.form.CheckBox\" $checked $disabled
type=\"checkbox\"></td>";
- print "<td><label for='FPCHK-$name'>$name</label></td>";
+ print "<td><label for='FPCHK-$name'><img src='images/$plugin_icon' alt=''> $name</label></td>";
print "<td><label for='FPCHK-$name'>" . htmlspecialchars($about[1]) . "</label>";
if (@$about[4]) {
print " &mdash; <a target=\"_blank\" class=\"visibleLink\"
@@ -883,8 +888,9 @@ class Pref_Prefs extends Handler_Protected {
if (!$otp_enabled) {
$secret = $base32->encode(sha1($this->dbh->fetch_result($result, 0, "salt")));
- $topt = new \OTPHP\TOTP($secret);
- print QRcode::png($topt->provisioning_uri($login));
+ print QRcode::png("otpauth://totp/".urlencode($login).
+ "?secret=$secret&issuer=".urlencode("Tiny Tiny RSS"));
+
}
}
diff --git a/classes/pref/users.php b/classes/pref/users.php
index 8a0202483..a5d48ac96 100644
--- a/classes/pref/users.php
+++ b/classes/pref/users.php
@@ -258,7 +258,7 @@ class Pref_Users extends Handler_Protected {
$pwd_hash = encrypt_password($tmp_user_pwd, $new_salt, true);
- db_query("UPDATE ttrss_users SET pwd_hash = '$pwd_hash', salt = '$new_salt'
+ db_query("UPDATE ttrss_users SET pwd_hash = '$pwd_hash', salt = '$new_salt', otp_enabled = false
WHERE id = '$uid'");
if ($show_password) {
@@ -418,7 +418,7 @@ class Pref_Users extends Handler_Protected {
$onclick = "onclick='editUser($uid, event)' title='".__('Click to edit')."'";
- print "<td $onclick>" . $line["login"] . "</td>";
+ print "<td $onclick><img src='images/user.png' class='markedPic' alt=''> " . $line["login"] . "</td>";
if (!$line["email"]) $line["email"] = "&nbsp;";
diff --git a/classes/rpc.php b/classes/rpc.php
index 46583feb5..b4de44a74 100644
--- a/classes/rpc.php
+++ b/classes/rpc.php
@@ -95,7 +95,7 @@ class RPC extends Handler_Protected {
WHERE orig_feed_id = '$id') = 0 AND
id = '$id' AND owner_uid = ".$_SESSION["uid"]);
- $rc = $this->dbh->affected_rows($result);
+ $this->dbh->affected_rows($result);
}
}
@@ -138,7 +138,7 @@ class RPC extends Handler_Protected {
$mark = "false";
}
- $result = $this->dbh->query("UPDATE ttrss_user_entries SET marked = $mark,
+ $this->dbh->query("UPDATE ttrss_user_entries SET marked = $mark,
last_marked = NOW()
WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
@@ -148,8 +148,8 @@ class RPC extends Handler_Protected {
function delete() {
$ids = $this->dbh->escape_string($_REQUEST["ids"]);
- $result = $this->dbh->query("DELETE FROM ttrss_user_entries
- WHERE ref_id IN ($ids) AND owner_uid = " . $_SESSION["uid"]);
+ $this->dbh->query("DELETE FROM ttrss_user_entries
+ WHERE ref_id IN ($ids) AND owner_uid = " . $_SESSION["uid"]);
purge_orphans();
@@ -258,7 +258,6 @@ class RPC extends Handler_Protected {
function publ() {
$pub = $_REQUEST["pub"];
$id = $this->dbh->escape_string($_REQUEST["id"]);
- $note = trim(strip_tags($this->dbh->escape_string($_REQUEST["note"])));
if ($pub == "1") {
$pub = "true";
@@ -266,7 +265,7 @@ class RPC extends Handler_Protected {
$pub = "false";
}
- $result = $this->dbh->query("UPDATE ttrss_user_entries SET
+ $this->dbh->query("UPDATE ttrss_user_entries SET
published = $pub, last_published = NOW()
WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
@@ -467,14 +466,6 @@ class RPC extends Handler_Protected {
print_feed_cat_select("cat_id", $id, '');
}
- // Silent
- function clearArticleKeys() {
- $this->dbh->query("UPDATE ttrss_user_entries SET uuid = '' WHERE
- owner_uid = " . $_SESSION["uid"]);
-
- return;
- }
-
function setpanelmode() {
$wide = (int) $_REQUEST["wide"];
@@ -484,7 +475,8 @@ class RPC extends Handler_Protected {
print json_encode(array("wide" => $wide));
}
- function updaterandomfeed() {
+ static function updaterandomfeed_real($dbh) {
+
// Test if the feed need a update (update interval exceded).
if (DB_TYPE == "pgsql") {
$update_limit_qpart = "AND ((
@@ -515,16 +507,24 @@ class RPC extends Handler_Protected {
$random_qpart = sql_random_function();
+ // we could be invoked from public.php with no active session
+ if ($_SESSION["uid"]) {
+ $owner_check_qpart = "AND ttrss_feeds.owner_uid = '".$_SESSION["uid"]."'";
+ } else {
+ $owner_check_qpart = "";
+ }
+
// We search for feed needing update.
- $result = $this->dbh->query("SELECT ttrss_feeds.feed_url,ttrss_feeds.id
+ $result = $dbh->query("SELECT ttrss_feeds.feed_url,ttrss_feeds.id
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'
- AND ttrss_feeds.owner_uid = ".$_SESSION["uid"]."
- $update_limit_qpart $updstart_thresh_qpart
+ $owner_check_qpart
+ $update_limit_qpart
+ $updstart_thresh_qpart
ORDER BY $random_qpart LIMIT 30");
$feed_id = -1;
@@ -535,7 +535,7 @@ class RPC extends Handler_Protected {
$tstart = time();
- while ($line = $this->dbh->fetch_assoc($result)) {
+ while ($line = $dbh->fetch_assoc($result)) {
$feed_id = $line["id"];
if (time() - $tstart < ini_get("max_execution_time") * 0.7) {
@@ -559,6 +559,10 @@ class RPC extends Handler_Protected {
}
+ function updaterandomfeed() {
+ RPC::updaterandomfeed_real($this->dbh);
+ }
+
private function markArticlesById($ids, $cmode) {
$tmp_ids = array();
@@ -615,7 +619,7 @@ class RPC extends Handler_Protected {
$p = new Publisher(PUBSUBHUBBUB_HUB);
- $pubsub_result = $p->publish_update($rss_link);
+ /* $pubsub_result = */ $p->publish_update($rss_link);
}
}