";
					print "
$entry_title : $entry_content_unescaped
";
				print_r($entry_tags);
				print "
TAGS: "; print_r($entry_tags); print "
"; if (defined('DAEMON_EXTENDED_DEBUG') || $_REQUEST['xdebug']) { print_r($entry_tags); } if (count($entry_tags) > 0) { db_query($link, "BEGIN"); foreach ($entry_tags as $tag) { $tag = sanitize_tag($tag); $tag = db_escape_string($tag); if (!tag_is_valid($tag)) continue; $result = db_query($link, "SELECT id FROM ttrss_tags WHERE tag_name = '$tag' AND post_int_id = '$entry_int_id' AND owner_uid = '$owner_uid' LIMIT 1"); // print db_fetch_result($result, 0, "id"); if ($result && db_num_rows($result) == 0) { db_query($link, "INSERT INTO ttrss_tags (owner_uid,tag_name,post_int_id) VALUES ('$owner_uid','$tag', '$entry_int_id')"); } } db_query($link, "COMMIT"); } if (defined('DAEMON_EXTENDED_DEBUG') || $_REQUEST['xdebug']) { _debug("update_rss_feed: article processed"); } } if (!$last_updated) { if (defined('DAEMON_EXTENDED_DEBUG') || $_REQUEST['xdebug']) { _debug("update_rss_feed: new feed, catching it up..."); } catchup_feed($link, $feed, false, $owner_uid); } purge_feed($link, $feed, 0); db_query($link, "UPDATE ttrss_feeds SET last_updated = NOW(), last_error = '' WHERE id = '$feed'"); // db_query($link, "COMMIT"); } else { if ($use_simplepie) { $error_msg = mb_substr($rss->error(), 0, 250); } else { $error_msg = mb_substr(magpie_error(), 0, 250); } if (defined('DAEMON_EXTENDED_DEBUG') || $_REQUEST['xdebug']) { _debug("update_rss_feed: error fetching feed: $error_msg"); } $error_msg = db_escape_string($error_msg); db_query($link, "UPDATE ttrss_feeds SET last_error = '$error_msg', last_updated = NOW() WHERE id = '$feed'"); } if ($use_simplepie) { unset($rss); } if (defined('DAEMON_EXTENDED_DEBUG') || $_REQUEST['xdebug']) { _debug("update_rss_feed: done"); } } function print_select($id, $default, $values, $attributes = "") { print ""; } function print_select_hash($id, $default, $values, $attributes = "") { print ""; } function get_article_filters($filters, $title, $content, $link, $timestamp, $author) { $matches = array(); if ($filters["title"]) { foreach ($filters["title"] as $filter) { $reg_exp = $filter["reg_exp"]; $inverse = $filter["inverse"]; if ((!$inverse && preg_match("/$reg_exp/i", $title)) || ($inverse && !preg_match("/$reg_exp/i", $title))) { array_push($matches, array($filter["action"], $filter["action_param"])); } } } if ($filters["content"]) { foreach ($filters["content"] as $filter) { $reg_exp = $filter["reg_exp"]; $inverse = $filter["inverse"]; if ((!$inverse && preg_match("/$reg_exp/i", $content)) || ($inverse && !preg_match("/$reg_exp/i", $content))) { array_push($matches, array($filter["action"], $filter["action_param"])); } } } if ($filters["both"]) { foreach ($filters["both"] as $filter) { $reg_exp = $filter["reg_exp"]; $inverse = $filter["inverse"]; if ($inverse) { if (!preg_match("/$reg_exp/i", $title) && !preg_match("/$reg_exp/i", $content)) { array_push($matches, array($filter["action"], $filter["action_param"])); } } else { if (preg_match("/$reg_exp/i", $title) || preg_match("/$reg_exp/i", $content)) { array_push($matches, array($filter["action"], $filter["action_param"])); } } } } if ($filters["link"]) { $reg_exp = $filter["reg_exp"]; foreach ($filters["link"] as $filter) { $reg_exp = $filter["reg_exp"]; $inverse = $filter["inverse"]; if ((!$inverse && preg_match("/$reg_exp/i", $link)) || ($inverse && !preg_match("/$reg_exp/i", $link))) { array_push($matches, array($filter["action"], $filter["action_param"])); } } } if ($filters["date"]) { $reg_exp = $filter["reg_exp"]; foreach ($filters["date"] as $filter) { $date_modifier = $filter["filter_param"]; $inverse = $filter["inverse"]; $check_timestamp = strtotime($filter["reg_exp"]); # no-op when timestamp doesn't parse to prevent misfires if ($check_timestamp) { $match_ok = false; if ($date_modifier == "before" && $timestamp < $check_timestamp || $date_modifier == "after" && $timestamp > $check_timestamp) { $match_ok = true; } if ($inverse) $match_ok = !$match_ok; if ($match_ok) { array_push($matches, array($filter["action"], $filter["action_param"])); } } } } if ($filters["author"]) { foreach ($filters["author"] as $filter) { $reg_exp = $filter["reg_exp"]; $inverse = $filter["inverse"]; if ((!$inverse && preg_match("/$reg_exp/i", $author)) || ($inverse && !preg_match("/$reg_exp/i", $author))) { array_push($matches, array($filter["action"], $filter["action_param"])); } } } return $matches; } function find_article_filter($filters, $filter_name) { foreach ($filters as $f) { if ($f[0] == $filter_name) { return $f; }; } return false; } function calculate_article_score($filters) { $score = 0; foreach ($filters as $f) { if ($f[0] == "score") { $score += $f[1]; }; } return $score; } function assign_article_to_labels($link, $id, $filters, $owner_uid) { foreach ($filters as $f) { if ($f[0] == "label") { label_add_article($link, $id, $f[1], $owner_uid); }; } } function printFeedEntry($feed_id, $class, $feed_title, $unread, $icon_file, $link, $rtl_content = false, $last_updated = false, $last_error = false, $fg_content = false, $bg_content = false) { if (!$feed_title) $feed_title = getFeedTitle($link, $feed_id, false); if (!$unread) $unread = getFeedUnread($link, $feed_id); if ($unread > 0) $class .= "Unread"; if (!$icon_file) $icon_file = getFeedIcon($feed_id); if (strpos($icon_file, "images") !== false) { $icon_file = theme_image($link, $icon_file); } if (file_exists($icon_file) && filesize($icon_file) > 0) { $feed_icon = "";
		$result = db_query($link, "SELECT ".SUBSTRING_FOR_DATE."(MAX(last_updated), 1, 19) AS last_updated FROM ttrss_feeds
			WHERE owner_uid = " . $_SESSION['uid']);
		$last_updated = db_fetch_result($result, 0, "last_updated");
		if (get_pref($link, 'HEADLINES_SMART_DATE')) {
			$last_updated = smart_date_time(strtotime($last_updated));
		} else {
			$last_updated = date($short_date, strtotime($last_updated));
		}				
		printf(__("Feeds last updated at %s"), $last_updated);
		$result = db_query($link, "SELECT COUNT(id) AS num_errors
			FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ".$_SESSION["uid"]);
		$num_errors = db_fetch_result($result, 0, "num_errors");
		if ($num_errors > 0) {
			print "
";
					}
				
					$category = $tmp_category;
					$collapsed = sql_bool_to_bool($line["collapsed"]);
					// workaround for NULL category
					if ($category == __("Uncategorized")) {
						$collapsed = get_pref($link, "_COLLAPSED_UNCAT");
					}
					$cat_id = (int) $cat_id;
					printCategoryHeader($link, $cat_id, $collapsed, true);
				}
	
				printFeedEntry($feed_id, $class, $feed, $unread, 
					false, $link, $rtl_content, 
					$last_updated, $line["last_error"]);
	
				++$lnum;
			}
			if (db_num_rows($result) == 0) {
				if (!get_pref($link, 'ENABLE_FEED_CATS')) {
					print "]+>/is', '', $res);
		}
		if (get_pref($link, 'OPEN_LINKS_IN_NEW_WINDOW', $owner)) {
			$res = preg_replace("/href=/i", "target=\"_blank\" href=", $res);
		}
		return $res;
	}
	/**
	 * Send by mail a digest of last articles.
	 * 
	 * @param mixed $link The database connection.
	 * @param integer $limit The maximum number of articles by digest.
	 * @return boolean Return false if digests are not enabled.
	 */
	function send_headlines_digests($link, $limit = 100) {
		if (!DIGEST_ENABLE) return false;
		$user_limit = DIGEST_EMAIL_LIMIT;
		$days = 1;
		print "Sending digests, batch of max $user_limit users, days = $days, headline limit = $limit\n\n";
		if (DB_TYPE == "pgsql") {
			$interval_query = "last_digest_sent < NOW() - INTERVAL '$days days'";
		} else if (DB_TYPE == "mysql") {
			$interval_query = "last_digest_sent < DATE_SUB(NOW(), INTERVAL $days DAY)";
		}
		$result = db_query($link, "SELECT id,email FROM ttrss_users 
				WHERE email != '' AND (last_digest_sent IS NULL OR $interval_query)");
		while ($line = db_fetch_assoc($result)) {
			if (get_pref($link, 'DIGEST_ENABLE', $line['id'], false)) {
				print "Sending digest for UID:" . $line['id'] . " - " . $line["email"] . " ... ";
				$do_catchup = get_pref($link, 'DIGEST_CATCHUP', $line['id'], false);
				$tuple = prepare_headlines_digest($link, $line["id"], $days, $limit);
				$digest = $tuple[0];
				$headlines_count = $tuple[1];
				$affected_ids = $tuple[2];
				$digest_text = $tuple[3];
				if ($headlines_count > 0) {
					$mail = new PHPMailer();
					$mail->PluginDir = "lib/phpmailer/";
					$mail->SetLanguage("en", "lib/phpmailer/language/");
					$mail->CharSet = "UTF-8";
					$mail->From = DIGEST_FROM_ADDRESS;
					$mail->FromName = DIGEST_FROM_NAME;
					$mail->AddAddress($line["email"], $line["login"]);
					if (DIGEST_SMTP_HOST) {
						$mail->Host = DIGEST_SMTP_HOST;
						$mail->Mailer = "smtp";
						$mail->SMTPAuth = DIGEST_SMTP_LOGIN != '';
						$mail->Username = DIGEST_SMTP_LOGIN;
						$mail->Password = DIGEST_SMTP_PASSWORD;
					}
					$mail->IsHTML(true);
					$mail->Subject = DIGEST_SUBJECT;
					$mail->Body = $digest;
					$mail->AltBody = $digest_text;
					$rc = $mail->Send();
					if (!$rc) print "ERROR: " . $mail->ErrorInfo;
					print "RC=$rc\n";
					if ($rc && $do_catchup) {
						print "Marking affected articles as read...\n";
						catchupArticlesById($link, $affected_ids, 0, $line["id"]);
					}
					db_query($link, "UPDATE ttrss_users SET last_digest_sent = NOW() 
							WHERE id = " . $line["id"]);
				} else {
					print "No headlines\n";
				}
			}
		}
		print "All done.\n";
	}
	function prepare_headlines_digest($link, $user_id, $days = 1, $limit = 100) {
		require_once "lib/MiniTemplator.class.php";
		$tpl = new MiniTemplator;
		$tpl_t = new MiniTemplator;
		$tpl->readTemplateFromFile("templates/digest_template_html.txt");
		$tpl_t->readTemplateFromFile("templates/digest_template.txt");
		$tpl->setVariable('CUR_DATE', date('Y/m/d'));
		$tpl->setVariable('CUR_TIME', date('G:i'));
		$tpl_t->setVariable('CUR_DATE', date('Y/m/d'));
		$tpl_t->setVariable('CUR_TIME', date('G:i'));
		$affected_ids = array();
		if (DB_TYPE == "pgsql") {
			$interval_query = "ttrss_entries.date_updated > NOW() - INTERVAL '$days days'";
		} else if (DB_TYPE == "mysql") {
			$interval_query = "ttrss_entries.date_updated > DATE_SUB(NOW(), INTERVAL $days DAY)";
		}
		$result = db_query($link, "SELECT ttrss_entries.title,
				ttrss_feeds.title AS feed_title,
				date_updated,
				ttrss_user_entries.ref_id,
				link,
				SUBSTRING(content, 1, 120) AS excerpt,
				".SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated
			FROM 
				ttrss_user_entries,ttrss_entries,ttrss_feeds 
			WHERE 
				ref_id = ttrss_entries.id AND feed_id = ttrss_feeds.id 
				AND include_in_digest = true
				AND $interval_query
				AND ttrss_user_entries.owner_uid = $user_id
				AND unread = true 
			ORDER BY ttrss_feeds.title, date_updated DESC
			LIMIT $limit");
		$cur_feed_title = "";
		$headlines_count = db_num_rows($result);
		$headlines = array();
		while ($line = db_fetch_assoc($result)) {
			array_push($headlines, $line);
		}
		for ($i = 0; $i < sizeof($headlines); $i++) {	
			$line = $headlines[$i];
			array_push($affected_ids, $line["ref_id"]);
			$updated = smart_date_time(strtotime($line["last_updated"]));
			$tpl->setVariable('FEED_TITLE', $line["feed_title"]);
			$tpl->setVariable('ARTICLE_TITLE', $line["title"]);
			$tpl->setVariable('ARTICLE_LINK', $line["link"]);
			$tpl->setVariable('ARTICLE_UPDATED', $updated);
			$tpl->setVariable('ARTICLE_EXCERPT', 
				truncate_string(strip_tags($line["excerpt"]), 100));
			$tpl->addBlock('article');
			$tpl_t->setVariable('FEED_TITLE', $line["feed_title"]);
			$tpl_t->setVariable('ARTICLE_TITLE', $line["title"]);
			$tpl_t->setVariable('ARTICLE_LINK', $line["link"]);
			$tpl_t->setVariable('ARTICLE_UPDATED', $updated);
//			$tpl_t->setVariable('ARTICLE_EXCERPT', 
//				truncate_string(strip_tags($line["excerpt"]), 100));
			$tpl_t->addBlock('article');
			if ($headlines[$i]['feed_title'] != $headlines[$i+1]['feed_title']) {
				$tpl->addBlock('feed');
				$tpl_t->addBlock('feed');
			}
		}
		$tpl->addBlock('digest');
		$tpl->generateOutputToString($tmp);
		$tpl_t->addBlock('digest');
		$tpl_t->generateOutputToString($tmp_t);
		return array($tmp, $headlines_count, $affected_ids, $tmp_t);
	}
	function check_for_update($link) {
		$releases_feed = "http://tt-rss.org/releases.rss";
		if (!CHECK_FOR_NEW_VERSION || $_SESSION["access_level"] < 10) {
			return;
		}
		error_reporting(0);
		if (DEFAULT_UPDATE_METHOD == "1") {
			$rss = new SimplePie();
			$rss->set_useragent(SIMPLEPIE_USERAGENT . MAGPIE_USER_AGENT_EXT);
//			$rss->set_timeout(MAGPIE_FETCH_TIME_OUT);
			$rss->set_feed_url($fetch_url);
			$rss->set_output_encoding('UTF-8');
			$rss->init();
		} else {
			$rss = fetch_rss($releases_feed);
		}
		error_reporting (DEFAULT_ERROR_LEVEL);
		if ($rss) {
			if (DEFAULT_UPDATE_METHOD == "1") {
				$items = $rss->get_items();
			} else {
				$items = $rss->items;
				if (!$items || !is_array($items)) $items = $rss->entries;
				if (!$items || !is_array($items)) $items = $rss;
			}
			if (!is_array($items) || count($items) == 0) {
				return;
			}			
			$latest_item = $items[0];
			if (DEFAULT_UPDATE_METHOD == "1") {
				$last_title = $latest_item->get_title();
			} else {
				$last_title = $latest_item["title"];
			}
			$latest_version = trim(preg_replace("/(Milestone)|(completed)/", "", $last_title));
			if (DEFAULT_UPDATE_METHOD == "1") {
				$release_url = sanitize_rss($link, $latest_item->get_link());
				$content = sanitize_rss($link, $latest_item->get_description());
			} else {
				$release_url = sanitize_rss($link, $latest_item["link"]);
				$content = sanitize_rss($link, $latest_item["description"]);
			}
			if (version_compare(VERSION, $latest_version) == -1) {
				return sprintf("New version of Tiny-Tiny RSS (%s) is available:", 
					$latest_version)."
$tmp_category";
			print "";
			print " ($cat_unread) $ellipsis";
			print "";
			//print "";
	}
	
	function outputFeedList($link, $tags = false) {
		print "
";
					}
				} 
			if (!get_pref($link, 'ENABLE_FEED_CATS')) {
				print "";
		$owner_uid = $_SESSION["uid"];
		/* virtual feeds */
		if (get_pref($link, 'ENABLE_FEED_CATS')) {
			$cat_hidden = get_pref($link, "_COLLAPSED_SPECIAL");
			printCategoryHeader($link, -1, $cat_hidden, false);
		}
		foreach (array(-4, -3, -1, -2, 0) as $i) {
			printFeedEntry($i, "virt", false, false, 
				false, $link);
		}
		if (get_pref($link, 'ENABLE_FEED_CATS')) {
			print "
";
		}
		if (!$tags) {
				$result = db_query($link, "SELECT * FROM
					ttrss_labels2 WHERE owner_uid = '$owner_uid' ORDER by caption");
		
				if (db_num_rows($result) > 0) {
					if (get_pref($link, 'ENABLE_FEED_CATS')) {
						$cat_hidden = get_pref($link, "_COLLAPSED_LABELS");
						printCategoryHeader($link, -2, $cat_hidden, true);
					} else {
						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";
				printFeedEntry($tag, $class, $tag, $unread, "images/tag.png", $link);
	
			} 
			if (db_num_rows($result) == 0) {
				print "
";
			}
		}
		print "";
	}
	function get_article_tags($link, $id, $owner_uid = 0) {
		global $memcache;
		$a_id = db_escape_string($id);
		if (!$owner_uid) $owner_uid = $_SESSION["uid"];
		$query = "SELECT DISTINCT tag_name, 
			owner_uid as owner FROM
			ttrss_tags WHERE post_int_id = (SELECT int_id FROM ttrss_user_entries WHERE
			ref_id = '$a_id' AND owner_uid = '$owner_uid' LIMIT 1) ORDER BY tag_name";
		$obj_id = md5("TAGS:$owner_uid:$id");
		$tags = array();	
		if ($memcache && $obj = $memcache->get($obj_id)) {
			$tags = $obj;
		} else {
			$tmp_result = db_query($link, $query);
			while ($tmp_line = db_fetch_assoc($tmp_result)) {
				array_push($tags, $tmp_line["tag_name"]);				
			}
			if ($memcache) $memcache->add($obj_id, $tags, 0, 3600);
		}
		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 (mb_strlen($tag) > 250) return false;
		if (function_exists('iconv')) {
			$tag = iconv("utf-8", "utf-8", $tag);
		}
		if (!$tag) return false;
		return true;
	}
	function render_login_form($link, $mobile = 0) {
		switch ($mobile) {
		case 0:
			require_once "login_form.php";
			break;
		case 1:
			require_once "mobile/login_form.php";
			break;
		case 2:
			require_once "mobile/classic/login_form.php";
		}
	}
	// from http://developer.apple.com/internet/safari/faq.html
	function no_cache_incantation() {
		header("Expires: Mon, 22 Dec 1980 00:00:00 GMT"); // Happy birthday to me :)
		header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified
		header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); // HTTP/1.1
		header("Cache-Control: post-check=0, pre-check=0", false);
		header("Pragma: no-cache"); // HTTP/1.0
	}
	function format_warning($msg, $id = "") {
		global $link;
		return "$msg
$msg
$msg
 ";
			if (!$zoom_mode) {
				print "$tags_str
					(+)";
				print "
";
				$note_escaped = htmlspecialchars($line['note'], ENT_QUOTES);
				print "
";
				if (DIGEST_ENABLE) {
					print "
";
				}
			} else {
				$tags_str = strip_tags($tags_str);
				print "$tags_str";
			}
			print "
";
					print "";
							}
						}
					}
				}
				if (db_num_rows($result) == 1) {
					print __("Attachment:") . " ";
				} else {
					print __("Attachments:") . " ";
				}
				print join(", ", $entries_html);
				print "
";
			}
			$lnum = $limit*$offset;
			error_reporting (DEFAULT_ERROR_LEVEL);
	
			$num_unread = 0;
			$cur_feed_title = '';
			$fresh_intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE") * 60 * 60;
			while ($line = db_fetch_assoc($result)) {
				$class = ($lnum % 2) ? "even" : "odd";
	
				$id = $line["id"];
				$feed_id = $line["feed_id"];
				$labels = get_article_labels($link, $id);
				$labels_str = "";
				$labels_str .= format_article_labels($labels, $id);
				$labels_str .= "";
	
				if (count($topmost_article_ids) < 5) {
					array_push($topmost_article_ids, $id);
				}
				if ($line["last_read"] == "" && !sql_bool_to_bool($line["unread"])) {
	
					$update_pic = "
";
			}
		} else {
			$message = "";
			switch ($view_mode) {
				case "unread":
					$message = __("No unread articles found to display.");
					break;
				case "updated":
					$message = __("No updated articles found to display.");
					break;
				case "marked":
					$message = __("No starred articles found to display.");
					break;
				default:
					if ($feed < -10) {
						$message = __("No articles found to display. You can assign articles to labels manually (see the Actions menu above) or use a filter.");
					} else {
						$message = __("No articles found to display.");
					}
			}
			if (!$offset) print "";
				} else {
					$update_pic = "
";
				}
				if (sql_bool_to_bool($line["unread"]) && 
					time() - strtotime($line["updated_noms"]) < $fresh_intl) {
					$update_pic = "";
				}
	
				if ($line["unread"] == "t" || $line["unread"] == "1") {
					$class .= "Unread";
					++$num_unread;
					$is_unread = true;
				} else {
					$is_unread = false;
				}
				if ($line["marked"] == "t" || $line["marked"] == "1") {
					$marked_pic = "
";
				} else {
					$marked_pic = "
";
				}
				if ($line["published"] == "t" || $line["published"] == "1") {
					$published_pic = "
";
				} else {
					$published_pic = "
";
				}
#				$content_link = "" .
#					$line["title"] . "";
#				$content_link = "" .
#					$line["title"] . "";
#				$content_link = "" .
#					$line["title"] . "";
				if (get_pref($link, 'HEADLINES_SMART_DATE')) {
					$updated_fmt = smart_date_time(strtotime($line["updated_noms"]));
				} else {
					$short_date = get_pref($link, 'SHORT_DATE_FORMAT');
					$updated_fmt = date($short_date, strtotime($line["updated_noms"]));
				}				
				if (get_pref($link, 'SHOW_CONTENT_PREVIEW')) {
					$content_preview = truncate_string(strip_tags($line["content_preview"]), 
						100);
				}
				$score = $line["score"];
				$score_pic = theme_image($link, 
					"images/" . get_score_pic($score));
/*				$score_title = __("(Click to change)");
				$score_pic = "
"; */
				$score_pic = "
";
				if ($score > 500) {
					$hlc_suffix = "H";
				} else if ($score < -100) {
					$hlc_suffix = "L";
				} else {
					$hlc_suffix = "";
				}
				$entry_author = $line["author"];
				if ($entry_author) {
					$entry_author = " - $entry_author";
				}
				$has_feed_icon = feed_has_icon($feed_id);
				if ($has_feed_icon) {
					$feed_icon_img = "
";
				} else {
					//$feed_icon_img = "
";
					$feed_icon_img = "";
				}
				if (!get_pref($link, 'COMBINED_DISPLAY_MODE')) {
					if (get_pref($link, 'VFEED_GROUP_BY_FEED')) {
						if ($feed_id != $vgroup_last_feed && $line["feed_title"]) {
							$cur_feed_title = $line["feed_title"];
							$vgroup_last_feed = $feed_id;
							$cur_feed_title = htmlspecialchars($cur_feed_title);
							$vf_catchup_link = "(".__('mark as read').")";
							print " ";
						}
					}
					$mouseover_attrs = "onmouseover='postMouseIn($id)' 
						onmouseout='postMouseOut($id)'";
					print "".
								" ";
		
					print " ";
				} else {
					if (get_pref($link, 'VFEED_GROUP_BY_FEED') && $line["feed_title"]) {
						if ($feed_id != $vgroup_last_feed) {
							$cur_feed_title = $line["feed_title"];
							$vgroup_last_feed = $feed_id;
							$cur_feed_title = htmlspecialchars($cur_feed_title);
							$vf_catchup_link = "(".__('mark as read').")";
							$has_feed_icon = feed_has_icon($feed_id);
							if ($has_feed_icon) {
								$feed_icon_img = "$update_pic ";
		
					print "
						
						 ";
		
					print "$marked_pic ";
					print "$published_pic ";
#					if ($line["feed_title"]) {			
#						print "$content_link ";
#						print "
#							".
#								truncate_string($line["feed_title"],30)."  ";
#					} else {			
					print "";
					print "" .
						$line["title"];
					if (get_pref($link, 'SHOW_CONTENT_PREVIEW')) {
						if ($content_preview) {
							print " - $content_preview";
						}
					}
					print "";
					print $labels_str;
#							".
#							$line["feed_title"]."	
					if (!get_pref($link, 'VFEED_GROUP_BY_FEED')) {
						if (@$line["feed_title"]) {			
							print "
								(".
								$line["feed_title"].")
							";
						}
					}
//					print " ";
#					}
					
					print "
";
					print " ";
					print "$score_pic ";
					if (@$line["feed_title"] && !get_pref($link, 'VFEED_GROUP_BY_FEED')) {
						print "$feed_icon_img ";
					}
					print "";
							} else {
								//$feed_icon_img = "
";
							}
							print "
";
						print "
";
//					print "";
		print "
";
	}
	function feed_has_icon($id) {
		return is_file(ICONS_DIR . "/$id.ico") && filesize(ICONS_DIR . "/$id.ico") > 0;
	}
	function init_connection($link) {
		if (DB_TYPE == "pgsql") {
			pg_query($link, "set client_encoding = 'UTF-8'");
			pg_set_client_encoding("UNICODE");
			pg_query($link, "set datestyle = 'ISO, european'");
		} else {
			if (defined('MYSQL_CHARSET') && MYSQL_CHARSET) {
				db_query($link, "SET NAMES " . MYSQL_CHARSET);
	//			db_query($link, "SET CHARACTER SET " . MYSQL_CHARSET);
			}
		}
	}
	function update_feedbrowser_cache($link) {
		$result = db_query($link, "SELECT feed_url,title, COUNT(id) AS subscribers
	  		FROM ttrss_feeds WHERE (SELECT COUNT(id) = 0 FROM ttrss_feeds AS tf 
				WHERE tf.feed_url = ttrss_feeds.feed_url 
				AND (private IS true OR feed_url LIKE '%:%@%/%')) 
				GROUP BY feed_url, title ORDER BY subscribers DESC LIMIT 1000");
	
		db_query($link, "BEGIN");
	
		db_query($link, "DELETE FROM ttrss_feedbrowser_cache");
	
		$count = 0;
	
		while ($line = db_fetch_assoc($result)) {
			$subscribers = db_escape_string($line["subscribers"]);
			$feed_url = db_escape_string($line["feed_url"]);
			$title = db_escape_string($line["title"]);
			$tmp_result = db_query($link, "SELECT subscribers FROM
				ttrss_feedbrowser_cache WHERE feed_url = '$feed_url'");
			if (db_num_rows($tmp_result) == 0) {
				db_query($link, "INSERT INTO ttrss_feedbrowser_cache 
					(feed_url, title, subscribers) VALUES ('$feed_url', 
						'$title', '$subscribers')");
				++$count;
			}
	
		}
	
		db_query($link, "COMMIT");
		return $count;
	}
	function ccache_zero($link, $feed_id, $owner_uid) {
		db_query($link, "UPDATE ttrss_counters_cache SET
			value = 0, updated = NOW() WHERE
			feed_id = '$feed_id' AND owner_uid = '$owner_uid'");
	}
	function ccache_zero_all($link, $owner_uid) {
		db_query($link, "UPDATE ttrss_counters_cache SET
			value = 0 WHERE owner_uid = '$owner_uid'");
		db_query($link, "UPDATE ttrss_cat_counters_cache SET
			value = 0 WHERE owner_uid = '$owner_uid'");
	}
	function ccache_remove($link, $feed_id, $owner_uid, $is_cat = false) {
		if (!$is_cat) {
			$table = "ttrss_counters_cache";
		} else {
			$table = "ttrss_cat_counters_cache";
		}
		db_query($link, "DELETE FROM $table WHERE
			feed_id = '$feed_id' AND owner_uid = '$owner_uid'");
	}
	function ccache_update_all($link, $owner_uid) {
		if (get_pref($link, 'ENABLE_FEED_CATS', $owner_uid)) {
			$result = db_query($link, "SELECT feed_id FROM ttrss_cat_counters_cache
				WHERE feed_id > 0 AND owner_uid = '$owner_uid'");
			while ($line = db_fetch_assoc($result)) {
				ccache_update($link, $line["feed_id"], $owner_uid, true);
			}
			/* We have to manually include category 0 */
			ccache_update($link, 0, $owner_uid, true);
		} else {
			$result = db_query($link, "SELECT feed_id FROM ttrss_counters_cache
				WHERE feed_id > 0 AND owner_uid = '$owner_uid'");
			while ($line = db_fetch_assoc($result)) {
				print ccache_update($link, $line["feed_id"], $owner_uid);
			}
		}
	}
	function ccache_find($link, $feed_id, $owner_uid, $is_cat = false, 
		$no_update = false) {
		if (!is_numeric($feed_id)) return;
		if (!$is_cat) {
			$table = "ttrss_counters_cache";
			if ($feed_id > 0) {
				$tmp_result = db_query($link, "SELECT owner_uid FROM ttrss_feeds 
					WHERE id = '$feed_id'");
				$owner_uid = db_fetch_result($tmp_result, 0, "owner_uid");
			}
		} else {
			$table = "ttrss_cat_counters_cache";
		}
		if (DB_TYPE == "pgsql") {
			$date_qpart = "updated > NOW() - INTERVAL '15 minutes'";
		} else if (DB_TYPE == "mysql") {
			$date_qpart = "updated > DATE_SUB(NOW(), INTERVAL 15 MINUTE)";
		}
		$result = db_query($link, "SELECT value FROM $table
			WHERE owner_uid = '$owner_uid' AND feed_id = '$feed_id' 
			LIMIT 1");
		if (db_num_rows($result) == 1) {
			return db_fetch_result($result, 0, "value");
		} else {
			if ($no_update) {
				return -1;
			} else {
				return ccache_update($link, $feed_id, $owner_uid, $is_cat);
			}
		}
	}
	function ccache_update($link, $feed_id, $owner_uid, $is_cat = false, 
		$update_pcat = true) {
		if (!is_numeric($feed_id)) return;
		if (!$is_cat && $feed_id > 0) {
			$tmp_result = db_query($link, "SELECT owner_uid FROM ttrss_feeds 
				WHERE id = '$feed_id'");
			$owner_uid = db_fetch_result($tmp_result, 0, "owner_uid");
		}
		$prev_unread = ccache_find($link, $feed_id, $owner_uid, $is_cat, true);
		/* When updating a label, all we need to do is recalculate feed counters
		 * because labels are not cached */
		if ($feed_id < 0) {
			ccache_update_all($link, $owner_uid);
			return;
		}
		if (!$is_cat) {
			$table = "ttrss_counters_cache";
		} else {
			$table = "ttrss_cat_counters_cache";
		}
		if ($is_cat && $feed_id >= 0) {
			if ($feed_id != 0) {
				$cat_qpart = "cat_id = '$feed_id'";
			} else {
				$cat_qpart = "cat_id IS NULL";
			}
			/* Recalculate counters for child feeds */
			$result = db_query($link, "SELECT id FROM ttrss_feeds
						WHERE owner_uid = '$owner_uid' AND $cat_qpart");
			while ($line = db_fetch_assoc($result)) {
				ccache_update($link, $line["id"], $owner_uid, false, false);
			}
			$result = db_query($link, "SELECT SUM(value) AS sv 
				FROM ttrss_counters_cache, ttrss_feeds 
				WHERE id = feed_id AND $cat_qpart AND 
				ttrss_feeds.owner_uid = '$owner_uid'");
			$unread = (int) db_fetch_result($result, 0, "sv");
		} else {
			$unread = (int) getFeedArticles($link, $feed_id, $is_cat, true, $owner_uid);
		}
		db_query($link, "BEGIN");
		$result = db_query($link, "SELECT feed_id FROM $table
			WHERE owner_uid = '$owner_uid' AND feed_id = '$feed_id' LIMIT 1");
		if (db_num_rows($result) == 1) {
			db_query($link, "UPDATE $table SET
				value = '$unread', updated = NOW() WHERE
				feed_id = '$feed_id' AND owner_uid = '$owner_uid'");
		} else {
			db_query($link, "INSERT INTO $table
				(feed_id, value, owner_uid, updated) 
				VALUES 
				($feed_id, $unread, $owner_uid, NOW())");
		}
		db_query($link, "COMMIT");
		if ($feed_id > 0 && $prev_unread != $unread) {
			if (!$is_cat) {
				/* Update parent category */
				if ($update_pcat) {
					$result = db_query($link, "SELECT cat_id FROM ttrss_feeds
						WHERE owner_uid = '$owner_uid' AND id = '$feed_id'");
					$cat_id = (int) db_fetch_result($result, 0, "cat_id");
					ccache_update($link, $cat_id, $owner_uid, true);
				}
			}
		} else if ($feed_id < 0) {
			ccache_update_all($link, $owner_uid);
		}
		return $unread;
	}
	function label_find_id($link, $label, $owner_uid) {
		$result = db_query($link, 
			"SELECT id FROM ttrss_labels2 WHERE caption = '$label' 
				AND owner_uid = '$owner_uid' LIMIT 1");
		if (db_num_rows($result) == 1) {
			return db_fetch_result($result, 0, "id");
		} else {
			return 0;
		}
	}
	function get_article_labels($link, $id) {
		global $memcache;
		$result = db_query($link, 
			"SELECT DISTINCT label_id,caption,fg_color,bg_color 
				FROM ttrss_labels2, ttrss_user_labels2 
			WHERE id = label_id 
				AND article_id = '$id' 
				AND owner_uid = ".$_SESSION["uid"] . "
			ORDER BY caption");
		$obj_id = md5("LABELS:$id:" . $_SESSION["uid"]);
		$rv = array();
		if ($memcache && $obj = $memcache->get($obj_id)) {
			return $obj;
		} else {
			while ($line = db_fetch_assoc($result)) {
				$rk = array($line["label_id"], $line["caption"], $line["fg_color"],
					$line["bg_color"]);
				array_push($rv, $rk);
			}
			if ($memcache) $memcache->add($obj_id, $rv, 0, 3600);
		}
		return $rv;
	}
	function label_find_caption($link, $label, $owner_uid) {
		$result = db_query($link, 
			"SELECT caption FROM ttrss_labels2 WHERE id = '$label' 
				AND owner_uid = '$owner_uid' LIMIT 1");
		if (db_num_rows($result) == 1) {
			return db_fetch_result($result, 0, "caption");
		} else {
			return "";
		}
	}
	function label_remove_article($link, $id, $label, $owner_uid) {
		$label_id = label_find_id($link, $label, $owner_uid);
		if (!$label_id) return;
		$result = db_query($link, 
			"DELETE FROM ttrss_user_labels2
			WHERE 
				label_id = '$label_id' AND
				article_id = '$id'");
	}
	function label_add_article($link, $id, $label, $owner_uid) {
		global $memcache;
		if ($memcache) {
			$obj_id = md5("LABELS:$id:$owner_uid");
			$memcache->delete($obj_id);
		}
		$label_id = label_find_id($link, $label, $owner_uid);
		if (!$label_id) return;
		$result = db_query($link, 
			"SELECT 
				article_id FROM ttrss_labels2, ttrss_user_labels2
			WHERE 
				label_id = id AND 
				label_id = '$label_id' AND
				article_id = '$id' AND owner_uid = '$owner_uid'
			LIMIT 1");
		if (db_num_rows($result) == 0) {
			db_query($link, "INSERT INTO ttrss_user_labels2 
				(label_id, article_id) VALUES ('$label_id', '$id')");
		}
	}
	function label_remove($link, $id, $owner_uid) {
		global $memcache;
		if ($memcache) {
			$obj_id = md5("LABELS:$id:$owner_uid");
			$memcache->delete($obj_id);
		}
		db_query($link, "BEGIN");
		$result = db_query($link, "SELECT caption FROM ttrss_labels2
			WHERE id = '$id'");
		$caption = db_fetch_result($result, 0, "caption");
		$result = db_query($link, "DELETE FROM ttrss_labels2 WHERE id = '$id'
			AND owner_uid = " . $_SESSION["uid"]);
		if (db_affected_rows($link, $result) != 0 && $caption) {
			/* Disable filters that reference label being removed */
	
			db_query($link, "UPDATE ttrss_filters SET
				enabled = false WHERE action_param = '$caption'
					AND action_id = 7
					AND owner_uid = " . $_SESSION["uid"]);
			}
		db_query($link, "COMMIT");
	}
	function label_create($link, $caption) {
		db_query($link, "BEGIN");
		$result = false;
		$result = db_query($link, "SELECT id FROM ttrss_labels2
			WHERE caption = '$caption' AND owner_uid =  ". $_SESSION["uid"]);
		if (db_num_rows($result) == 0) {
			$result = db_query($link,
				"INSERT INTO ttrss_labels2 (caption,owner_uid) 
					VALUES ('$caption', '".$_SESSION["uid"]."')");
			$result = db_affected_rows($link, $result) != 0;
		}
		db_query($link, "COMMIT");
		return $result;
	}
	function print_labels_headlines_dropdown($link, $feed_id) {
		print " ";
		print "  $header    ";
		print "  ";
	}
	function rounded_table_end($footer = " ") {
		print "    ";
		print "  $footer   
";
			print "".
				__('Some feeds have update errors (click for details)')."";
		}
		print "