";
}
}
}
if (!get_pref($link, 'ENABLE_FEED_CATS')) {
print "
";
}
if (get_pref($link, 'ENABLE_FEED_CATS')) {
if (get_pref($link, "FEEDS_SORT_BY_UNREAD")) {
$order_by_qpart = "order_id,category,unread DESC,title";
} else {
$order_by_qpart = "order_id,category,title";
}
} else {
if (get_pref($link, "FEEDS_SORT_BY_UNREAD")) {
$order_by_qpart = "unread DESC,title";
} else {
$order_by_qpart = "title";
}
}
$age_qpart = getMaxAgeSubquery();
$query = "SELECT ttrss_feeds.*,
".SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated_noms,
cat_id,last_error,
ttrss_feed_categories.title AS category,
ttrss_feed_categories.collapsed
FROM ttrss_feeds LEFT JOIN ttrss_feed_categories
ON (ttrss_feed_categories.id = cat_id)
WHERE
ttrss_feeds.hidden = false AND
ttrss_feeds.owner_uid = '$owner_uid' AND parent_feed IS NULL
ORDER BY $order_by_qpart";
$result = db_query($link, $query);
$actid = $_GET["actid"];
/* real feeds */
$lnum = 0;
$total_unread = 0;
$category = "";
$short_date = get_pref($link, 'SHORT_DATE_FORMAT');
while ($line = db_fetch_assoc($result)) {
$feed = trim($line["title"]);
if (!$feed) $feed = "[Untitled]";
$feed_id = $line["id"];
$subop = $_GET["subop"];
$unread = ccache_find($link, $feed_id, $_SESSION["uid"]);
if (get_pref($link, 'HEADLINES_SMART_DATE')) {
$last_updated = smart_date_time(strtotime($line["last_updated_noms"]));
} else {
$last_updated = date($short_date, strtotime($line["last_updated_noms"]));
}
$rtl_content = sql_bool_to_bool($line["rtl_content"]);
if ($rtl_content) {
$rtl_tag = "dir=\"RTL\"";
} else {
$rtl_tag = "";
}
$tmp_result = db_query($link,
"SELECT id,COUNT(unread) AS unread
FROM ttrss_feeds LEFT JOIN ttrss_user_entries
ON (ttrss_feeds.id = ttrss_user_entries.feed_id)
WHERE parent_feed = '$feed_id' AND unread = true
GROUP BY ttrss_feeds.id");
if (db_num_rows($tmp_result) > 0) {
while ($l = db_fetch_assoc($tmp_result)) {
$unread += $l["unread"];
}
}
$cat_id = $line["cat_id"];
$tmp_category = $line["category"];
if (!$tmp_category) {
$tmp_category = __("Uncategorized");
}
// $class = ($lnum % 2) ? "even" : "odd";
if ($line["last_error"]) {
$class = "error";
} else {
$class = "feed";
}
if ($unread > 0) $class .= "Unread";
if ($actid == $feed_id) {
$class .= "Selected";
}
$total_unread += $unread;
if ($category != $tmp_category && get_pref($link, 'ENABLE_FEED_CATS')) {
if ($category) {
print "";
}
$category = $tmp_category;
$collapsed = sql_bool_to_bool($line["collapsed"]);
// workaround for NULL category
if ($category == __("Uncategorized")) {
if ($_COOKIE["ttrss_vf_uclps"] == 1) {
$collapsed = "t";
}
}
$cat_id = sprintf("%d", $cat_id);
printCategoryHeader($link, $cat_id, $collapsed, true);
}
printFeedEntry($feed_id, $class, $feed, $unread,
ICONS_URL."/$feed_id.ico", $link, $rtl_content,
$last_updated, $line["last_error"]);
++$lnum;
}
if (db_num_rows($result) == 0) {
print "
".__('No feeds to display.')."
";
}
} else {
// tags
/* $result = db_query($link, "SELECT tag_name,count(ttrss_entries.id) AS count
FROM ttrss_tags,ttrss_entries,ttrss_user_entries WHERE
post_int_id = ttrss_user_entries.int_id AND
unread = true AND ref_id = ttrss_entries.id
AND ttrss_tags.owner_uid = '$owner_uid' GROUP BY tag_name
UNION
select tag_name,0 as count FROM ttrss_tags WHERE owner_uid = '$owner_uid'
ORDER BY tag_name"); */
if (get_pref($link, 'ENABLE_FEED_CATS')) {
print "
".__('Tags')."
";
print "
";
}
$age_qpart = getMaxAgeSubquery();
$result = db_query($link, "SELECT tag_name,SUM((SELECT COUNT(int_id)
FROM ttrss_user_entries,ttrss_entries WHERE int_id = post_int_id
AND ref_id = id AND $age_qpart
AND unread = true)) AS count FROM ttrss_tags
WHERE owner_uid = ".$_SESSION['uid']." GROUP BY tag_name
ORDER BY count DESC LIMIT 50");
$tags = array();
while ($line = db_fetch_assoc($result)) {
$tags[$line["tag_name"]] += $line["count"];
}
foreach (array_keys($tags) as $tag) {
$unread = $tags[$tag];
$class = "tag";
if ($unread > 0) {
$class .= "Unread";
}
printFeedEntry($tag, $class, $tag, $unread, "images/tag.png", $link);
}
if (db_num_rows($result) == 0) {
print "
No tags to display.
";
}
if (get_pref($link, 'ENABLE_FEED_CATS')) {
print "
";
}
}
print "";
}
function get_article_tags($link, $id, $owner_uid = 0) {
$a_id = db_escape_string($id);
if (!$owner_uid) $owner_uid = $_SESSION["uid"];
$tmp_result = db_query($link, "SELECT DISTINCT tag_name,
owner_uid as owner FROM
ttrss_tags WHERE post_int_id = (SELECT int_id FROM ttrss_user_entries WHERE
ref_id = '$a_id' AND owner_uid = '$owner_uid' LIMIT 1) ORDER BY tag_name");
$tags = array();
while ($tmp_line = db_fetch_assoc($tmp_result)) {
array_push($tags, $tmp_line["tag_name"]);
}
return $tags;
}
function trim_value(&$value) {
$value = trim($value);
}
function trim_array($array) {
$tmp = $array;
array_walk($tmp, 'trim_value');
return $tmp;
}
function tag_is_valid($tag) {
if ($tag == '') return false;
if (preg_match("/^[0-9]*$/", $tag)) return false;
if (function_exists('iconv')) {
$tag = iconv("utf-8", "utf-8", $tag);
}
if (!$tag) return false;
return true;
}
function render_login_form($link, $mobile = false) {
if (!$mobile) {
require_once "login_form.php";
} else {
require_once "mobile/login_form.php";
}
}
// from http://developer.apple.com/internet/safari/faq.html
function no_cache_incantation() {
header("Expires: Mon, 22 Dec 1980 00:00:00 GMT"); // Happy birthday to me :)
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); // HTTP/1.1
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache"); // HTTP/1.0
}
function format_warning($msg, $id = "") {
return "
$msg
";
}
function format_notice($msg) {
return "
$msg
";
}
function format_error($msg) {
return "
$msg
";
}
function print_notice($msg) {
return print format_notice($msg);
}
function print_warning($msg) {
return print format_warning($msg);
}
function print_error($msg) {
return print format_error($msg);
}
function T_sprintf() {
$args = func_get_args();
return vsprintf(__(array_shift($args)), $args);
}
function outputArticleXML($link, $id, $feed_id, $mark_as_read = true,
$zoom_mode = false) {
/* we can figure out feed_id from article id anyway, why do we
* pass feed_id here? */
$result = db_query($link, "SELECT feed_id FROM ttrss_user_entries
WHERE ref_id = '$id'");
$feed_id = db_fetch_result($result, 0, "feed_id");
if (!$zoom_mode) { print "";
} else {
$feed_icon = " ";
}
/* if ($line["comments"] && $line["link"] != $line["comments"]) {
$entry_comments = "(Comments)";
} else {
$entry_comments = "";
} */
$num_comments = $line["num_comments"];
$entry_comments = "";
if ($num_comments > 0) {
if ($line["comments"]) {
$comments_url = $line["comments"];
} else {
$comments_url = $line["link"];
}
$entry_comments = "$num_comments comments";
} else {
if ($line["comments"] && $line["link"] != $line["comments"]) {
$entry_comments = "comments";
}
}
if ($zoom_mode) {
header("Content-Type: text/html");
print "
Tiny Tiny RSS - ".$line["title"]."
";
}
print "
";
}
// print_headline_subtoolbar($link,
// "javascript:catchupPage()", "Mark page as read", true, $rtl_content);
} else {
$message = "";
switch ($view_mode) {
case "unread":
$message = __("No unread articles found to display.");
break;
case "marked":
$message = __("No starred articles found to display.");
break;
default:
$message = __("No articles found to display.");
}
if (!$offset) print "
$message
";
}
if (!$offset) {
print "
";
print "
";
}
return array($topmost_article_ids, $headlines_count, $feed, $disable_cache, $vgroup_last_feed);
}
// from here: http://www.roscripts.com/Create_tag_cloud-71.html
function printTagCloud($link) {
/* get first ref_id to count from */
/*
$query = "";
if (DB_TYPE == "pgsql") {
$query = "SELECT MIN(id) AS id FROM ttrss_user_entries, ttrss_entries
WHERE int_id = id AND owner_uid = ".$_SESSION["uid"]."
AND date_entered > NOW() - INTERVAL '30 days'";
} else {
$query = "SELECT MIN(id) AS id FROM ttrss_user_entries, ttrss_entries
WHERE int_id = id AND owner_uid = ".$_SESSION["uid"]."
AND date_entered > DATE_SUB(NOW(), INTERVAL 30 DAY)";
}
$result = db_query($link, $query);
$first_id = db_fetch_result($result, 0, "id"); */
//AND post_int_id >= '$first_id'
$query = "SELECT tag_name, COUNT(post_int_id) AS count
FROM ttrss_tags WHERE owner_uid = ".$_SESSION["uid"]."
GROUP BY tag_name ORDER BY count DESC LIMIT 50";
$result = db_query($link, $query);
$tags = array();
while ($line = db_fetch_assoc($result)) {
$tags[$line["tag_name"]] = $line["count"];
}
ksort($tags);
$max_size = 32; // max font size in pixels
$min_size = 11; // min font size in pixels
// largest and smallest array values
$max_qty = max(array_values($tags));
$min_qty = min(array_values($tags));
// find the range of values
$spread = $max_qty - $min_qty;
if ($spread == 0) { // we don't want to divide by zero
$spread = 1;
}
// set the font-size increment
$step = ($max_size - $min_size) / ($spread);
// loop through the tag array
foreach ($tags as $key => $value) {
// calculate font-size
// find the $value in excess of $min_qty
// multiply by the font-size increment ($size)
// and add the $min_size set above
$size = round($min_size + (($value - $min_qty) * $step));
$key_escaped = str_replace("'", "\\'", $key);
echo "' . $key . ' ';
}
}
function print_checkpoint($n, $s) {
$ts = getmicrotime();
echo sprintf("", $ts - $s);
return $ts;
}
function sanitize_tag($tag) {
$tag = trim($tag);
$tag = mb_strtolower($tag, 'utf-8');
$tag = preg_replace('/[\"\+\>\<]/', "", $tag);
// $tag = str_replace('"', "", $tag);
// $tag = str_replace("+", " ", $tag);
$tag = str_replace("technorati tag: ", "", $tag);
return $tag;
}
function generate_publish_key() {
return sha1(uniqid(rand(), true));
}
function article_publish_url($link) {
$url_path = "";
if ($_SERVER['HTTPS'] != "on") {
$url_path = "http://";
} else {
$url_path = "https://";
}
$url_path .= $_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']);
$url_path .= "/backend.php?op=publish&key=" . get_pref($link, "_PREFS_PUBLISH_KEY");
return $url_path;
}
/**
* Purge a feed contents, marked articles excepted.
*
* @param mixed $link The database connection.
* @param integer $id The id of the feed to purge.
* @return void
*/
function clear_feed_articles($link, $id) {
$result = db_query($link, "DELETE FROM ttrss_user_entries
WHERE feed_id = '$id' AND marked = false AND owner_uid = " . $_SESSION["uid"]);
$result = db_query($link, "DELETE FROM ttrss_entries WHERE
(SELECT COUNT(int_id) FROM ttrss_user_entries WHERE ref_id = id) = 0");
} // function clear_feed_articles
/**
* Compute the Mozilla Firefox feed adding URL from server HOST and REQUEST_URI.
*
* @return string The Mozilla Firefox feed adding URL.
*/
function add_feed_url() {
$url_path = ($_SERVER['HTTPS'] != "on" ? 'http://' : 'https://') . $_SERVER["HTTP_HOST"] . parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
$url_path .= "?op=pref-feeds&quiet=1&subop=add&feed_url=%s";
return $url_path;
} // function add_feed_url
/**
* Encrypt a password in SHA1.
*
* @param string $pass The password to encrypt.
* @param string $login A optionnal login.
* @return string The encrypted password.
*/
function encrypt_password($pass, $login = '') {
if ($login) {
return "SHA1X:" . sha1("$login:$pass");
} else {
return "SHA1:" . sha1($pass);
}
} // function encrypt_password
/**
* Update a feed batch.
* Used by daemons to update n feeds by run.
* Only update feed needing a update, and not being processed
* by another process.
*
* @param mixed $link Database link
* @param integer $limit Maximum number of feeds in update batch. Default to DAEMON_FEED_LIMIT.
* @param boolean $from_http Set to true if you call this function from http to disable cli specific code.
* @param boolean $debug Set to false to disable debug output. Default to true.
* @return void
*/
function update_daemon_common($link, $limit = DAEMON_FEED_LIMIT, $from_http = false, $debug = true) {
// Process all other feeds using last_updated and interval parameters
// Test if the user has loggued in recently. If not, it does not update its feeds.
if (DAEMON_UPDATE_LOGIN_LIMIT > 0) {
if (DB_TYPE == "pgsql") {
$login_thresh_qpart = "AND ttrss_users.last_login >= NOW() - INTERVAL '".DAEMON_UPDATE_LOGIN_LIMIT." days'";
} else {
$login_thresh_qpart = "AND ttrss_users.last_login >= DATE_SUB(NOW(), INTERVAL ".DAEMON_UPDATE_LOGIN_LIMIT." DAY)";
}
} else {
$login_thresh_qpart = "";
}
// Test if the feed need a update (update interval exceded).
if (DB_TYPE == "pgsql") {
$update_limit_qpart = "AND ((
ttrss_feeds.update_interval = 0
AND ttrss_feeds.last_updated < NOW() - CAST((ttrss_user_prefs.value || ' minutes') AS INTERVAL)
) OR (
ttrss_feeds.update_interval > 0
AND ttrss_feeds.last_updated < NOW() - CAST((ttrss_feeds.update_interval || ' minutes') AS INTERVAL)
) OR ttrss_feeds.last_updated IS NULL)";
} else {
$update_limit_qpart = "AND ((
ttrss_feeds.update_interval = 0
AND ttrss_feeds.last_updated < DATE_SUB(NOW(), INTERVAL CONVERT(ttrss_user_prefs.value, SIGNED INTEGER) MINUTE)
) OR (
ttrss_feeds.update_interval > 0
AND ttrss_feeds.last_updated < DATE_SUB(NOW(), INTERVAL ttrss_feeds.update_interval MINUTE)
) OR ttrss_feeds.last_updated IS NULL)";
}
// Test if feed is currently being updated by another process.
if (DB_TYPE == "pgsql") {
$updstart_thresh_qpart = "AND (ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < NOW() - INTERVAL '120 seconds')";
} else {
$updstart_thresh_qpart = "AND (ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < DATE_SUB(NOW(), INTERVAL 120 SECOND))";
}
// Test if there is a limit to number of updated feeds
$query_limit = "";
if($limit) $query_limit = sprintf("LIMIT %d", $limit);
$random_qpart = sql_random_function();
// We search for feed needing update.
$result = db_query($link, "SELECT ttrss_feeds.feed_url,ttrss_feeds.id, ttrss_feeds.owner_uid,
".SUBSTRING_FOR_DATE."(ttrss_feeds.last_updated,1,19) AS last_updated,
ttrss_feeds.update_interval
FROM
ttrss_feeds, ttrss_users, ttrss_user_prefs
WHERE
ttrss_feeds.owner_uid = ttrss_users.id
AND ttrss_users.id = ttrss_user_prefs.owner_uid
AND ttrss_user_prefs.pref_name = 'DEFAULT_UPDATE_INTERVAL'
$login_thresh_qpart $update_limit_qpart
$updstart_thresh_qpart
ORDER BY $random_qpart $query_limit");
$user_prefs_cache = array();
if($debug) _debug(sprintf("Scheduled %d feeds to update...\n", db_num_rows($result)));
// Here is a little cache magic in order to minimize risk of double feed updates.
$feeds_to_update = array();
while ($line = db_fetch_assoc($result)) {
$feeds_to_update[$line['id']] = $line;
}
// We update the feed last update started date before anything else.
// There is no lag due to feed contents downloads
// It prevent an other process to update the same feed.
$feed_ids = array_keys($feeds_to_update);
if($feed_ids) {
db_query($link, sprintf("UPDATE ttrss_feeds SET last_update_started = NOW()
WHERE id IN (%s)", implode(',', $feed_ids)));
}
// For each feed, we call the feed update function.
while ($line = array_pop($feeds_to_update)) {
if($debug) _debug("Feed: " . $line["feed_url"] . ", " . $line["last_updated"]);
// We setup a alarm to alert if the feed take more than 300s to update.
// => HANG alarm.
if(!$from_http && function_exists('pcntl_alarm')) pcntl_alarm(300);
update_rss_feed($link, $line["feed_url"], $line["id"], true);
// Cancel the alarm (the update went well)
if(!$from_http && function_exists('pcntl_alarm')) pcntl_alarm(0);
sleep(1); // prevent flood (FIXME make this an option?)
}
// Send feed digests by email if needed.
if (DAEMON_SENDS_DIGESTS) send_headlines_digests($link);
} // function update_daemon_common
function generate_dashboard_feed($link) {
print "