Commit 30e64c99 authored by Sebastian Reichel's avatar Sebastian Reichel

Imported Upstream version 1.7.0+dfsg

parent f53db3b4
......@@ -8,7 +8,7 @@ http://tt-rss.org
Licensed under GNU GPL version 2
Copyright (c) 2005-2010 Andrew Dolgov (unless explicitly stated otherwise).
Copyright (c) 2005 Andrew Dolgov (unless explicitly stated otherwise).
## Requirements
......
......@@ -37,8 +37,8 @@
@$csrf_token = $_REQUEST['csrf_token'];
require_once "functions.php";
require_once "sessions.php";
require_once "functions.php";
require_once "config.php";
require_once "db.php";
require_once "db-prefs.php";
......@@ -53,7 +53,7 @@
if (!init_connection($link)) return;
header("Content-Type: text/plain; charset=utf-8");
header("Content-Type: text/json; charset=utf-8");
if (ENABLE_GZIP_OUTPUT && function_exists("ob_gzhandler")) {
ob_start("ob_gzhandler");
......@@ -63,6 +63,10 @@
authenticate_user($link, "admin", null);
}
if ($_SESSION["uid"]) {
load_user_plugins($link, $_SESSION["uid"]);
}
$purge_intervals = array(
0 => __("Use default"),
-1 => __("Never purge"),
......@@ -93,17 +97,6 @@
1440 => __("Daily"),
10080 => __("Weekly"));
$update_methods = array(
0 => __("Default"),
1 => __("Magpie"),
2 => __("SimplePie"));
if (DEFAULT_UPDATE_METHOD == "1") {
$update_methods[0] .= ' (SimplePie)';
} else {
$update_methods[0] .= ' (Magpie)';
}
$access_level_names = array(
0 => __("User"),
5 => __("Power User"),
......@@ -118,31 +111,43 @@
$op = str_replace("-", "_", $op);
if (class_exists($op)) {
$handler = new $op($link, $_REQUEST);
global $pluginhost;
$override = $pluginhost->lookup_handler($op, $method);
if (class_exists($op) || $override) {
if ($override) {
$handler = $override;
} else {
$handler = new $op($link, $_REQUEST);
}
if ($handler && is_subclass_of($handler, 'Handler')) {
if ($handler && implements_interface($handler, 'IHandler')) {
if (validate_csrf($csrf_token) || $handler->csrf_ignore($method)) {
if ($handler->before($method)) {
if ($method && method_exists($handler, $method)) {
$handler->$method();
} else {
if (method_exists($handler, "catchall")) {
$handler->catchall($method);
}
}
$handler->after();
return;
} else {
header("Content-Type: text/plain");
header("Content-Type: text/json");
print json_encode(array("error" => array("code" => 6)));
return;
}
} else {
header("Content-Type: text/plain");
header("Content-Type: text/json");
print json_encode(array("error" => array("code" => 6)));
return;
}
}
}
header("Content-Type: text/plain");
header("Content-Type: text/json");
print json_encode(array("error" => array("code" => 7)));
// We close the connection to database.
......
......@@ -11,7 +11,7 @@ class API extends Handler {
function before($method) {
if (parent::before($method)) {
header("Content-Type: text/plain");
header("Content-Type: text/json");
if (!$_SESSION["uid"] && $method != "login" && $method != "isloggedin") {
print $this->wrap(self::STATUS_ERR, array("error" => 'NOT_LOGGED_IN'));
......@@ -104,11 +104,7 @@ class API extends Handler {
/* Method added for ttrss-reader for Android */
function getCounters() {
/* flct (flc is the default) FIXME: document */
$output_mode = db_escape_string($_REQUEST["output_mode"]);
print $this->wrap(self::STATUS_OK, getAllCounters($this->link, $output_mode));
print $this->wrap(self::STATUS_OK, getAllCounters($this->link));
}
function getFeeds() {
......@@ -118,7 +114,7 @@ class API extends Handler {
$offset = (int) db_escape_string($_REQUEST["offset"]);
$include_nested = (bool)db_escape_string($_REQUEST["include_nested"]);
$feeds = api_get_feeds($this->link, $cat_id, $unread_only, $limit, $offset, $include_nested);
$feeds = $this->api_get_feeds($this->link, $cat_id, $unread_only, $limit, $offset, $include_nested);
print $this->wrap(self::STATUS_OK, $feeds);
}
......@@ -135,24 +131,29 @@ class API extends Handler {
$nested_qpart = "true";
$result = db_query($this->link, "SELECT
id, title, order_id FROM ttrss_feed_categories
id, title, order_id, (SELECT COUNT(id) FROM
ttrss_feeds WHERE
ttrss_feed_categories.id IS NOT NULL AND cat_id = ttrss_feed_categories.id) AS num_feeds
FROM ttrss_feed_categories
WHERE $nested_qpart AND owner_uid = " .
$_SESSION["uid"]);
$cats = array();
while ($line = db_fetch_assoc($result)) {
$unread = getFeedUnread($this->link, $line["id"], true);
if ($enable_nested)
$unread += getCategoryChildrenUnread($this->link, $line["id"]);
if ($unread || !$unread_only) {
array_push($cats, array("id" => $line["id"],
"title" => $line["title"],
"unread" => $unread,
"order_id" => (int) $line["order_id"],
));
if ($line["num_feeds"] > 0) {
$unread = getFeedUnread($this->link, $line["id"], true);
if ($enable_nested)
$unread += getCategoryChildrenUnread($this->link, $line["id"]);
if ($unread || !$unread_only) {
array_push($cats, array("id" => $line["id"],
"title" => $line["title"],
"unread" => $unread,
"order_id" => (int) $line["order_id"],
));
}
}
}
......@@ -195,7 +196,7 @@ class API extends Handler {
$search_mode = db_escape_string($_REQUEST["search_mode"]);
$match_on = db_escape_string($_REQUEST["match_on"]);
$headlines = api_get_headlines($this->link, $feed_id, $limit, $offset,
$headlines = $this->api_get_headlines($this->link, $feed_id, $limit, $offset,
$filter, $is_cat, $show_excerpt, $show_content, $view_mode, false,
$include_attachments, $since_id, $search, $search_mode, $match_on,
$include_nested, $sanitize_content);
......@@ -439,12 +440,219 @@ class API extends Handler {
$url = db_escape_string(strip_tags($_REQUEST["url"]));
$content = db_escape_string(strip_tags($_REQUEST["content"]));
if (create_published_article($this->link, $title, $url, $content, "", $_SESSION["uid"])) {
if (Article::create_published_article($this->link, $title, $url, $content, "", $_SESSION["uid"])) {
print $this->wrap(self::STATUS_OK, array("status" => 'OK'));
} else {
print $this->wrap(self::STATUS_ERR, array("error" => 'Publishing failed'));
}
}
static function api_get_feeds($link, $cat_id, $unread_only, $limit, $offset, $include_nested = false) {
$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, -6, 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);
}
}
}
/* Child cats */
if ($include_nested && $cat_id) {
$result = db_query($link, "SELECT
id, title FROM ttrss_feed_categories
WHERE parent_cat = '$cat_id' AND owner_uid = " . $_SESSION["uid"] .
" ORDER BY id, title");
while ($line = db_fetch_assoc($result)) {
$unread = getFeedUnread($link, $line["id"], true) +
getCategoryChildrenUnread($link, $line["id"]);
if ($unread || !$unread_only) {
$row = array(
"id" => $line["id"],
"title" => $line["title"],
"unread" => $unread,
"is_cat" => true,
);
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, order_id, ".
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, order_id, ".
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"]),
"order_id" => (int) $line["order_id"],
);
array_push($feeds, $row);
}
}
return $feeds;
}
static function api_get_headlines($link, $feed_id, $limit, $offset,
$filter, $is_cat, $show_excerpt, $show_content, $view_mode, $order,
$include_attachments, $since_id,
$search = "", $search_mode = "", $match_on = "",
$include_nested = false, $sanitize_content = true) {
$qfh_ret = queryFeedHeadlines($link, $feed_id, $limit,
$view_mode, $is_cat, $search, $search_mode, $match_on,
$order, $offset, 0, false, $since_id, $include_nested);
$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) {
if ($line["cached_content"] != "") {
$line["content_preview"] =& $line["cached_content"];
}
if ($sanitize_content) {
$headline_row["content"] = sanitize($link,
$line["content_preview"], false, false, $line["site_url"]);
} else {
$headline_row["content"] = $line["content_preview"];
}
}
// unify label output to ease parsing
if ($labels["no-labels"] == 1) $labels = array();
$headline_row["labels"] = $labels;
$headline_row["feed_title"] = $line["feed_title"];
$headline_row["comments_count"] = (int)$line["num_comments"];
$headline_row["comments_link"] = $line["comments"];
$headline_row["always_display_attachments"] = sql_bool_to_bool($line["always_display_enclosures"]);
array_push($headlines, $headline_row);
}
return $headlines;
}
}
?>
......@@ -52,7 +52,7 @@ class Article extends Handler_Protected {
return;
}
catchupArticleById($this->link, $id, 0);
$this->catchupArticleById($this->link, $id, 0);
if (!$_SESSION["bw_limit"]) {
foreach ($cids as $cid) {
......@@ -63,7 +63,114 @@ class Article extends Handler_Protected {
}
print json_encode($articles);
}
private 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"]);
}
static function create_published_article($link, $title, $url, $content, $labels_str,
$owner_uid) {
$guid = sha1($url . $owner_uid); // include owner_uid to prevent global GUID clash
$content_hash = sha1($content);
if ($labels_str != "") {
$labels = explode(",", $labels_str);
} else {
$labels = array();
}
$rc = false;
if (!$title) $title = $url;
if (!$title && !$url) return false;
if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) return false;
db_query($link, "BEGIN");
// only check for our user data here, others might have shared this with different content etc
$result = db_query($link, "SELECT id FROM ttrss_entries, ttrss_user_entries WHERE
link = '$url' 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");
$result = db_query($link, "SELECT int_id FROM ttrss_user_entries WHERE
ref_id = '$ref_id' AND owner_uid = '$owner_uid' LIMIT 1");
if (db_num_rows($result) != 0) {
$int_id = db_fetch_result($result, 0, "int_id");
db_query($link, "UPDATE ttrss_entries SET
content = '$content', content_hash = '$content_hash' WHERE id = '$ref_id'");
db_query($link, "UPDATE ttrss_user_entries SET published = true WHERE
int_id = '$int_id' AND owner_uid = '$owner_uid'");
} else {
db_query($link, "INSERT INTO ttrss_user_entries
(ref_id, uuid, feed_id, orig_feed_id, owner_uid, published, tag_cache, label_cache, last_read, note, unread)
VALUES
('$ref_id', '', NULL, NULL, $owner_uid, true, '', '', NOW(), '', false)");
}
if (count($labels) != 0) {
foreach ($labels as $label) {
label_add_article($link, $ref_id, trim($label), $owner_uid);
}
}
$rc = true;
} else {
$result = db_query($link, "INSERT INTO ttrss_entries
(title, guid, link, updated, content, content_hash, date_entered, date_updated)
VALUES
('$title', '$guid', '$url', NOW(), '$content', '$content_hash', NOW(), NOW())");
$result = db_query($link, "SELECT id FROM ttrss_entries WHERE guid = '$guid'");
if (db_num_rows($result) != 0) {
$ref_id = db_fetch_result($result, 0, "id");
db_query($link, "INSERT INTO ttrss_user_entries
(ref_id, uuid, feed_id, orig_feed_id, owner_uid, published, tag_cache, label_cache, last_read, note, unread)
VALUES
('$ref_id', '', NULL, NULL, $owner_uid, true, '', '', NOW(), '', false)");
if (count($labels) != 0) {
foreach ($labels as $label) {
label_add_article($link, $ref_id, trim($label), $owner_uid);
}
}
$rc = true;
}
}
db_query($link, "COMMIT");
return $rc;
}
}
<?php
class Backend extends Handler {
function loading() {
header("Content-type: text/html");
print __("Loading, please wait...") . " " .
......@@ -10,6 +9,8 @@ class Backend extends Handler {
function digestTest() {
header("Content-type: text/html");
require_once "digest.php";
$rv = prepare_headlines_digest($this->link, $_SESSION['uid'], 1, 1000);
$rv[3] = "<pre>" . $rv[3] . "</pre>";
......@@ -17,14 +18,78 @@ class Backend extends Handler {
print_r($rv);
}
private function display_main_help() {
$info = get_hotkeys_info($this->link);
$imap = get_hotkeys_map($this->link);
$omap = array();
// :(
$tinycharmap = array(
"(9)" => "{TAB}",
"(191)" => "?");
foreach ($imap[1] as $sequence => $action) {
if (!isset($omap[$action])) {
$omap[$action] = isset($tinycharmap[$sequence]) ? $tinycharmap[$sequence] :
$sequence;
}
}
print "<ul class='helpKbList' id='helpKbList'>";
print "<h2>" . __("Keyboard Shortcuts") . "</h2>";
foreach ($info as $section => $hotkeys) {
print "<li><h3>" . $section . "</h3></li>";
foreach ($hotkeys as $action => $description) {
if (strpos($omap[$action], "|") !== FALSE) {
$omap[$action] = substr($omap[$action],
strpos($omap[$action], "|")+1,
strlen($omap[$action]));
}
print "<li>";
print "<span class='hksequence'>" . $omap[$action] . "</span>";
print $description;
print "</li>";
}
}
print "</ul>";
print "<p><a target=\"_blank\" href=\"http://tt-rss.org/wiki/InterfaceTips\">".
__("Other interface tips are available in the Tiny Tiny RSS wiki.") .
"</a></p>";
}
function help() {
$topic = basename($_REQUEST["topic"]);
if (file_exists("help/$topic.php")) {
switch ($topic) {
case "main":
$this->display_main_help();
break;
case "prefs":
//$this->display_prefs_help();
break;
default:
print "<p>".__("Help topic not found.")."</p>";
}
print "<div align='center'>";
print "<button dojoType=\"dijit.form.Button\"
onclick=\"return dijit.byId('helpDlg').hide()\">".
__('Close this window')."</button>";
print "</div>";
/* if (file_exists("help/$topic.php")) {
include("help/$topic.php");
} else {
print "<p>".__("Help topic not found.")."</p>";
}
} */
/* print "<div align='center'>
<button onclick=\"javascript:window.close()\">".
__('Close this window')."</button></div>"; */
......
<?php
class Button {
protected $link;
function __construct($link) {
$this->link = $link;
}
}
?>
......@@ -16,24 +16,6 @@ class Dlg extends Handler_Protected {
print "</dlg>";
}
function exportData() {
print "<p style='text-align : center' id='export_status_message'>You need to prepare exported data first by clicking the button below.</p>";
print "<div align='center'>";
print "<button dojoType=\"dijit.form.Button\"
onclick=\"dijit.byId('dataExportDlg').prepare()\">".
__('Prepare data')."</button>";
print "<button dojoType=\"dijit.form.Button\"
onclick=\"dijit.byId('dataExportDlg').hide()\">".
__('Close this window')."</button>";
print "</div>";
}
function importOpml() {
header("Content-Type: text/html"); # required for iframe
......@@ -186,7 +168,7 @@ class Dlg extends Handler_Protected {
print "<title>".__('Public OPML URL')."</title>";
print "<content><![CDATA[";
$url_path = opml_publish_url($this->link);