X-Git-Url: https://git.wh0rd.org/?a=blobdiff_plain;f=functions.php;h=f9771879080d61ef883e9c54db8e0ce25d1d86ae;hb=45004d43408bb006f89dd2c46fb3b934966896b0;hp=c82f45cc928efe73b66fcfb0192e77296cba614e;hpb=dd40e08cc39bca52b236e538b8e44085aaacd2fd;p=tt-rss.git diff --git a/functions.php b/functions.php index c82f45cc..f9771879 100644 --- a/functions.php +++ b/functions.php @@ -13,8 +13,9 @@ "auto" => "Detect automatically", "en_US" => "English", "fr_FR" => "Français", + "nb_NO" => "Norsk Bokmål", "ru_RU" => "Русский", - "pt_BR" => "Portuguese/Brazil" + "pt_BR" => "Portuguese/Brazil", "zh_CN" => "Simplified Chinese"); return $tr; @@ -67,22 +68,44 @@ define('MAGPIE_USER_AGENT_EXT', ' (Tiny Tiny RSS/' . VERSION . ')'); define('MAGPIE_OUTPUT_ENCODING', 'UTF-8'); - if (ENABLE_SIMPLEPIE) { - require_once "simplepie/simplepie.inc"; - } else { - require_once "magpierss/rss_fetch.inc"; - require_once 'magpierss/rss_utils.inc'; - } + require_once "simplepie/simplepie.inc"; + require_once "magpierss/rss_fetch.inc"; + require_once 'magpierss/rss_utils.inc'; + /** + * Print a timestamped debug message. + * + * @param string $msg The debug message. + * @return void + */ function _debug($msg) { $ts = strftime("%H:%M:%S", time()); + $ts = "$ts/" . posix_getpid(); print "[$ts] $msg\n"; - } + } // function _debug function purge_feed($link, $feed_id, $purge_interval, $debug = false) { + if (!$purge_interval) $purge_interval = feed_purge_interval($link, $feed_id); + $rows = -1; + $result = db_query($link, + "SELECT owner_uid FROM ttrss_feeds WHERE id = '$feed_id'"); + + $owner_uid = false; + + if (db_num_rows($result) == 1) { + $owner_uid = db_fetch_result($result, 0, "owner_uid"); + } + + if (!$owner_uid) return; + + $purge_unread = get_pref($link, "PURGE_UNREAD_ARTICLES", + $owner_uid, false); + + if (!$purge_unread) $query_limit = " unread = false AND "; + if (DB_TYPE == "pgsql") { /* $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE marked = false AND feed_id = '$feed_id' AND @@ -97,6 +120,7 @@ ttrss_entries.id = ref_id AND marked = false AND feed_id = '$feed_id' AND + $query_limit ttrss_entries.date_entered < NOW() - INTERVAL '$purge_interval days'"); } else { @@ -106,6 +130,7 @@ WHERE ttrss_entries.id = ref_id AND marked = false AND feed_id = '$feed_id' AND + $query_limit ttrss_entries.date_entered < NOW() - INTERVAL '$purge_interval days'"); } @@ -123,6 +148,7 @@ WHERE ttrss_entries.id = ref_id AND marked = false AND feed_id = '$feed_id' AND + $query_limit ttrss_entries.date_entered < DATE_SUB(NOW(), INTERVAL $purge_interval DAY)"); $rows = mysql_affected_rows($link); @@ -185,6 +211,25 @@ } + function feed_purge_interval($link, $feed_id) { + + $result = db_query($link, "SELECT purge_interval, owner_uid FROM ttrss_feeds + WHERE id = '$feed_id'"); + + if (db_num_rows($result) == 1) { + $purge_interval = db_fetch_result($result, 0, "purge_interval"); + $owner_uid = db_fetch_result($result, 0, "owner_uid"); + + if ($purge_interval == 0) $purge_interval = get_pref($link, + 'PURGE_OLD_DAYS', $user_id); + + return $purge_interval; + + } else { + return -1; + } + } + function purge_old_posts($link) { $user_id = $_SESSION["uid"]; @@ -420,27 +465,63 @@ function update_rss_feed($link, $feed_url, $feed, $ignore_daemon = false) { if (!$_GET["daemon"] && !$ignore_daemon) { - return; + return false; } if (defined('DAEMON_EXTENDED_DEBUG') || $_GET['xdebug']) { _debug("update_rss_feed: start"); } - $result = db_query($link, "SELECT id,update_interval,auth_login,auth_pass,cache_images - FROM ttrss_feeds WHERE id = '$feed'"); + if (!$ignore_daemon) { + + if (DB_TYPE == "pgsql") { + $updstart_thresh_qpart = "(ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < NOW() - INTERVAL '120 seconds')"; + } else { + $updstart_thresh_qpart = "(ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < DATE_SUB(NOW(), INTERVAL 120 SECOND))"; + } + + $result = db_query($link, "SELECT id,update_interval,auth_login, + auth_pass,cache_images,update_method + FROM ttrss_feeds WHERE id = '$feed' AND $updstart_thresh_qpart"); + + } else { + + $result = db_query($link, "SELECT id,update_interval,auth_login, + auth_pass,cache_images,update_method + FROM ttrss_feeds WHERE id = '$feed'"); + + } if (db_num_rows($result) == 0) { if (defined('DAEMON_EXTENDED_DEBUG') || $_GET['xdebug']) { - _debug("update_rss_feed: feed $feed [$feed_url] NOT FOUND"); + _debug("update_rss_feed: feed $feed [$feed_url] NOT FOUND/SKIPPED"); } - return; + return false; } + $update_method = db_fetch_result($result, 0, "update_method"); + + db_query($link, "UPDATE ttrss_feeds SET last_update_started = NOW() + WHERE id = '$feed'"); + $auth_login = db_fetch_result($result, 0, "auth_login"); $auth_pass = db_fetch_result($result, 0, "auth_pass"); - if (!ENABLE_SIMPLEPIE) { + if (ALLOW_SELECT_UPDATE_METHOD) { + if (ENABLE_SIMPLEPIE) { + $use_simplepie = $update_method != 1; + } else { + $use_simplepie = $update_method == 2; + } + } else { + $use_simplepie = ENABLE_SIMPLEPIE; + } + + if (defined('DAEMON_EXTENDED_DEBUG') || $_GET['xdebug']) { + _debug("use simplepie: $use_simplepie (feed setting: $update_method)\n"); + } + + if (!$use_simplepie) { $auth_login = urlencode($auth_login); $auth_pass = urlencode($auth_pass); } @@ -472,7 +553,7 @@ error_reporting(0); } - if (!ENABLE_SIMPLEPIE) { + if (!$use_simplepie) { $rss = fetch_rss($fetch_url); } else { if (!is_dir(SIMPLEPIE_CACHE_DIR)) { @@ -481,7 +562,7 @@ $rss = new SimplePie(); $rss->set_useragent(SIMPLEPIE_USERAGENT . MAGPIE_USER_AGENT_EXT); -// $rss->set_timeout(MAGPIE_FETCH_TIME_OUT); +# $rss->set_timeout(10); $rss->set_feed_url($fetch_url); $rss->set_output_encoding('UTF-8'); @@ -516,7 +597,7 @@ $feed = db_escape_string($feed); - if (ENABLE_SIMPLEPIE) { + if ($use_simplepie) { $fetch_ok = !$rss->error(); } else { $fetch_ok = !!$rss; @@ -539,7 +620,7 @@ $owner_uid = db_fetch_result($result, 0, "owner_uid"); - if (ENABLE_SIMPLEPIE) { + if ($use_simplepie) { $site_url = $rss->get_link(); } else { $site_url = $rss->channel["link"]; @@ -555,7 +636,7 @@ if (!$registered_title || $registered_title == "[Unknown]") { - if (ENABLE_SIMPLEPIE) { + if ($use_simplepie) { $feed_title = db_escape_string($rss->get_title()); } else { $feed_title = db_escape_string($rss->channel["title"]); @@ -570,7 +651,7 @@ } // weird, weird Magpie - if (!ENABLE_SIMPLEPIE) { + if (!$use_simplepie) { if (!$site_url) $site_url = db_escape_string($rss->channel["link_"]); } @@ -581,7 +662,7 @@ // print "I: " . $rss->channel["image"]["url"]; - if (!ENABLE_SIMPLEPIE) { + if (!$use_simplepie) { $icon_url = $rss->image["url"]; } else { $icon_url = $rss->get_image_url(); @@ -621,7 +702,7 @@ array_push($filters[$line["name"]], $filter); } - if (ENABLE_SIMPLEPIE) { + if ($use_simplepie) { $iterator = $rss->get_items(); } else { $iterator = $rss->items; @@ -653,7 +734,12 @@ foreach ($iterator as $item) { - if (ENABLE_SIMPLEPIE) { + if ($_GET['xdebug']) { + print_r($item); + + } + + if ($use_simplepie) { $entry_guid = $item->get_id(); if (!$entry_guid) $entry_guid = $item->get_link(); if (!$entry_guid) $entry_guid = make_guid_from_title($item->get_title()); @@ -675,7 +761,7 @@ $entry_timestamp = ""; - if (ENABLE_SIMPLEPIE) { + if ($use_simplepie) { $entry_timestamp = strtotime($item->get_date()); } else { $rss_2_date = $item['pubdate']; @@ -701,13 +787,13 @@ $entry_timestamp_fmt = strftime("%Y/%m/%d %H:%M:%S", $entry_timestamp); - if (ENABLE_SIMPLEPIE) { + if ($use_simplepie) { $entry_title = $item->get_title(); } else { $entry_title = trim(strip_tags($item["title"])); } - if (ENABLE_SIMPLEPIE) { + if ($use_simplepie) { $entry_link = $item->get_link(); } else { // strange Magpie workaround @@ -723,13 +809,17 @@ $entry_link = strip_tags($entry_link); - if (ENABLE_SIMPLEPIE) { + if ($use_simplepie) { $entry_content = $item->get_description(); } else { $entry_content = $item["content:escaped"]; if (!$entry_content) $entry_content = $item["content:encoded"]; if (!$entry_content) $entry_content = $item["content"]; + + // Magpie bugs are getting ridiculous + if (trim($entry_content) == "Array") $entry_content = false; + if (!$entry_content) $entry_content = $item["atom_content"]; if (!$entry_content) $entry_content = $item["summary"]; if (!$entry_content) $entry_content = $item["description"]; @@ -738,16 +828,17 @@ if (is_array($entry_content)) { $entry_content = $entry_content["encoded"]; if (!$entry_content) $entry_content = $entry_content["escaped"]; - } + } } -// print_r($item); -// print_r(htmlspecialchars($entry_content)); -// print "
"; + if ($_GET["xdebug"]) { + print "update_rss_feed: content: "; + print_r(htmlspecialchars($entry_content)); + } $entry_content_unescaped = $entry_content; - if (ENABLE_SIMPLEPIE) { + if ($use_simplepie) { $entry_comments = strip_tags($item->data["comments"]); if ($item->get_author()) { $entry_author_item = $item->get_author(); @@ -780,6 +871,7 @@ if (preg_match('/^[\t\n\r ]*$/', $entry_author)) $entry_author = ''; $entry_guid = db_escape_string(strip_tags($entry_guid)); + $entry_guid = mb_substr($entry_guid, 0, 250); $result = db_query($link, "SELECT id FROM ttrss_entries WHERE guid = '$entry_guid'"); @@ -793,7 +885,7 @@ $entry_comments = mb_substr(db_escape_string($entry_comments), 0, 250); $entry_author = mb_substr($entry_author, 0, 250); - if (ENABLE_SIMPLEPIE) { + if ($use_simplepie) { $num_comments = 0; #FIXME# } else { $num_comments = db_escape_string($item["slash"]["comments"]); @@ -803,11 +895,11 @@ // parse entries into tags - if (ENABLE_SIMPLEPIE) { + if ($use_simplepie) { $additional_tags = array(); $additional_tags_src = $item->get_categories(); - + if (is_array($additional_tags_src)) { foreach ($additional_tags_src as $tobj) { array_push($additional_tags, $tobj->get_term()); @@ -827,14 +919,21 @@ if ($t_ctr == 0) { $additional_tags = false; - } else if ($t_ctr == 1) { + } else if ($t_ctr > 0) { $additional_tags = array($item['category']); - } else { - $additional_tags = array(); + + if ($item['category@term']) { + array_push($additional_tags, $item['category@term']); + } + for ($i = 0; $i <= $t_ctr; $i++ ) { if ($item["category#$i"]) { array_push($additional_tags, $item["category#$i"]); } + + if ($item["category#$i@term"]) { + array_push($additional_tags, $item["category#$i@term"]); + } } } @@ -842,10 +941,9 @@ $t_ctr = $item['dc']['subject#']; - if ($t_ctr == 1) { + if ($t_ctr > 0) { $additional_tags = array($item['dc']['subject']); - } else if ($t_ctr > 1) { - $additional_tags = array(); + for ($i = 0; $i <= $t_ctr; $i++ ) { if ($item['dc']["subject#$i"]) { array_push($additional_tags, $item['dc']["subject#$i"]); @@ -854,6 +952,45 @@ } } + // enclosures + + $enclosures = array(); + + if ($use_simplepie) { + $encs = $item->get_enclosures(); + + if (is_array($encs)) { + foreach ($encs as $e) { + $e_item = array( + $e->link, $e->type, $e->length); + + array_push($enclosures, $e_item); + } + } + + } else { + $e_ctr = $item['enclosure#']; + + if ($e_ctr > 0) { + $e_item = array($item['enclosure@url'], + $item['enclosure@type'], + $item['enclosure@length']); + + array_push($enclosures, $e_item); + + for ($i = 0; $i <= $e_ctr; $i++ ) { + + if ($item["enclosure#$i@url"]) { + $e_item = array($item["enclosure#$i@url"], + $item["enclosure#$i@type"], + $item["enclosure#$i@length"]); + array_push($enclosures, $e_item); + } + } + } + + } + # sanitize content // $entry_content = sanitize_rss($entry_content); @@ -920,6 +1057,9 @@ ttrss_entries WHERE guid = '$entry_guid'"); + $entry_ref_id = 0; + $entry_int_id = 0; + if (db_num_rows($result) == 1) { if (defined('DAEMON_EXTENDED_DEBUG') || $_GET['xdebug']) { @@ -934,6 +1074,7 @@ 0, "date_entered")); $ref_id = db_fetch_result($result, 0, "id"); + $entry_ref_id = $ref_id; // check for user post link to main table @@ -963,7 +1104,7 @@ // error_reporting (DEFAULT_ERROR_LEVEL); $result = db_query($link, - "SELECT ref_id FROM ttrss_user_entries WHERE + "SELECT ref_id, int_id FROM ttrss_user_entries WHERE ref_id = '$ref_id' AND owner_uid = '$owner_uid' $dupcheck_qpart"); @@ -999,8 +1140,24 @@ (ref_id, owner_uid, feed_id, unread, last_read, marked, published) VALUES ('$ref_id', '$owner_uid', '$feed', $unread, $last_read_qpart, $marked, $published)"); + + $result = db_query($link, + "SELECT int_id FROM ttrss_user_entries WHERE + ref_id = '$ref_id' AND owner_uid = '$owner_uid' AND + feed_id = '$feed' LIMIT 1"); + + if (db_num_rows($result) == 1) { + $entry_int_id = db_fetch_result($result, 0, "int_id"); + } + } else { + $entry_ref_id = db_fetch_result($result, 0, "ref_id"); + $entry_int_id = db_fetch_result($result, 0, "int_id"); } - + + if (defined('DAEMON_EXTENDED_DEBUG') || $_GET['xdebug']) { + _debug("update_rss_feed: RID: $entry_ref_id, IID: $entry_int_id"); + } + $post_needs_update = false; if (get_pref($link, "UPDATE_POST_ON_CHECKSUM_CHANGE", $owner_uid, false) && @@ -1052,6 +1209,33 @@ db_query($link, "COMMIT"); + if (defined('DAEMON_EXTENDED_DEBUG') || $_GET['xdebug']) { + _debug("update_rss_feed: looking for enclosures..."); + } + + if (defined('DAEMON_EXTENDED_DEBUG') || $_GET['xdebug']) { + print_r($enclosures); + } + + db_query($link, "BEGIN"); + + foreach ($enclosures as $enc) { + $enc_url = db_escape_string($enc[0]); + $enc_type = db_escape_string($enc[1]); + $enc_dur = db_escape_string($enc[2]); + + $result = db_query($link, "SELECT id FROM ttrss_enclosures + WHERE content_url = '$enc_url' AND post_id = '$entry_ref_id'"); + + if (db_num_rows($result) == 0) { + db_query($link, "INSERT INTO ttrss_enclosures + (content_url, content_type, title, duration, post_id) VALUES + ('$enc_url', '$enc_type', '', '$enc_dur', '$entry_ref_id')"); + } + } + + db_query($link, "COMMIT"); + if (defined('DAEMON_EXTENDED_DEBUG') || $_GET['xdebug']) { _debug("update_rss_feed: looking for tags..."); } @@ -1107,17 +1291,6 @@ db_query($link, "BEGIN"); - $result = db_query($link, "SELECT id,int_id - FROM ttrss_entries,ttrss_user_entries - WHERE guid = '$entry_guid' - AND feed_id = '$feed' AND ref_id = id - AND owner_uid = '$owner_uid'"); - - if (db_num_rows($result) == 1) { - - $entry_id = db_fetch_result($result, 0, "id"); - $entry_int_id = db_fetch_result($result, 0, "int_id"); - foreach ($entry_tags as $tag) { $tag = sanitize_tag($tag); @@ -1138,7 +1311,7 @@ VALUES ('$owner_uid','$tag', '$entry_int_id')"); } } - } + db_query($link, "COMMIT"); } @@ -1154,7 +1327,7 @@ } else { - if (ENABLE_SIMPLEPIE) { + if ($use_simplepie) { $error_msg = mb_substr($rss->error(), 0, 250); } else { $error_msg = mb_substr(magpie_error(), 0, 250); @@ -1171,7 +1344,7 @@ last_updated = NOW() WHERE id = '$feed'"); } - if (ENABLE_SIMPLEPIE) { + if ($use_simplepie) { unset($rss); } @@ -1431,10 +1604,15 @@ $pwd_hash1 = encrypt_password($password); $pwd_hash2 = encrypt_password($password, $login); - if ($force_auth && defined('_DEBUG_USER_SWITCH')) { + if (defined('ALLOW_REMOTE_USER_AUTH') && ALLOW_REMOTE_USER_AUTH + && $_SERVER["REMOTE_USER"]) { + + $login = db_escape_string($_SERVER["REMOTE_USER"]); + $query = "SELECT id,login,access_level FROM ttrss_users WHERE - login = '$login'"; + login = '$login'"; + } else { $query = "SELECT id,login,access_level,pwd_hash FROM ttrss_users WHERE @@ -1511,7 +1689,7 @@ db_query($link, "insert into ttrss_labels (owner_uid,sql_exp,description) values ('$uid','last_read is null and unread = false', 'Updated articles')"); - + db_query($link, "insert into ttrss_feeds (owner_uid,title,feed_url) values ('$uid', 'Tiny Tiny RSS: New Releases', 'http://tt-rss.spb.ru/releases.rss')"); @@ -1627,7 +1805,7 @@ function truncate_string($str, $max_len) { if (mb_strlen($str, "utf-8") > $max_len - 3) { - return mb_substr($str, 0, $max_len, "utf-8") . "..."; + return mb_substr($str, 0, $max_len, "utf-8") . "…"; } else { return $str; } @@ -1721,7 +1899,7 @@ function file_is_locked($filename) { if (function_exists('flock')) { error_reporting(0); - $fp = fopen($filename, "r"); + $fp = fopen(LOCK_DIRECTORY . "/$filename", "r"); error_reporting(DEFAULT_ERROR_LEVEL); if ($fp) { if (flock($fp, LOCK_EX | LOCK_NB)) { @@ -1737,7 +1915,7 @@ } function make_lockfile($filename) { - $fp = fopen($filename, "w"); + $fp = fopen(LOCK_DIRECTORY . "/$filename", "w"); if (flock($fp, LOCK_EX | LOCK_NB)) { return $fp; @@ -1747,7 +1925,7 @@ } function make_stampfile($filename) { - $fp = fopen($filename, "w"); + $fp = fopen(LOCK_DIRECTORY . "/$filename", "w"); if (flock($fp, LOCK_EX | LOCK_NB)) { fwrite($fp, time() . "\n"); @@ -1762,7 +1940,7 @@ function read_stampfile($filename) { error_reporting(0); - $fp = fopen($filename, "r"); + $fp = fopen(LOCK_DIRECTORY . "/$filename", "r"); error_reporting (DEFAULT_ERROR_LEVEL); if (flock($fp, LOCK_EX)) { @@ -1934,7 +2112,7 @@ } } - function update_generic_feed($link, $feed, $cat_view) { + function update_generic_feed($link, $feed, $cat_view, $force_update = false) { if ($cat_view) { if ($feed > 0) { @@ -1949,14 +2127,14 @@ while ($tmp_line = db_fetch_assoc($tmp_result)) { $feed_url = $tmp_line["feed_url"]; $feed_id = $tmp_line["id"]; - update_rss_feed($link, $feed_url, $feed_id, ENABLE_UPDATE_DAEMON); + update_rss_feed($link, $feed_url, $feed_id, $force_update); } } else { $tmp_result = db_query($link, "SELECT feed_url FROM ttrss_feeds WHERE id = '$feed'"); $feed_url = db_fetch_result($tmp_result, 0, "feed_url"); - update_rss_feed($link, $feed_url, $feed, ENABLE_UPDATE_DAEMON); + update_rss_feed($link, $feed_url, $feed, $force_update); } } @@ -2664,6 +2842,7 @@ } } + print ""; print ""; print ""; print ""; @@ -2702,11 +2881,15 @@ print ""; + print ""; + print ""; } function print_runtime_info($link) { print ""; + if (ENABLE_UPDATE_DAEMON) { print ""; @@ -3002,6 +3185,8 @@ if ($feed < -10) error_reporting (0); + $content_query_part = "content as content_preview,"; + if (preg_match("/^-?[0-9][0-9]*$/", $feed) != false) { if ($feed >= 0) { @@ -3010,8 +3195,6 @@ $feed_kind = "Labels"; } - $content_query_part = "content as content_preview,"; - if ($limit_query_part) { $offset_query_part = "OFFSET $offset"; } @@ -3179,6 +3362,13 @@ 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; @@ -3208,49 +3398,42 @@ $digest = $tuple[0]; $headlines_count = $tuple[1]; $affected_ids = $tuple[2]; + $digest_text = $tuple[3]; if ($headlines_count > 0) { - if (!DIGEST_SMTP_HOST) { + $mail = new PHPMailer(); - $rc = mail($line["login"] . " <" . $line["email"] . ">", - "[tt-rss] New headlines for last 24 hours", $digest, - "From: " . DIGEST_FROM_NAME . " <" . DIGEST_FROM_ADDRESS . ">\n". - "Content-Type: text/plain; charset=\"utf-8\"\n". - "Content-Transfer-Encoding: 8bit\n"); + $mail->PluginDir = "phpmailer/"; + $mail->SetLanguage("en", "phpmailer/language/"); - } else { - - $mail = new PHPMailer(); + $mail->CharSet = "UTF-8"; - $mail->PluginDir = "phpmailer/"; - $mail->SetLanguage("en", "phpmailer/language/"); + $mail->From = DIGEST_FROM_ADDRESS; + $mail->FromName = DIGEST_FROM_NAME; + $mail->AddAddress($line["email"], $line["login"]); - $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->Username = DIGEST_SMTP_LOGIN; $mail->Password = DIGEST_SMTP_PASSWORD; + } - $mail->Subject = "[tt-rss] New headlines for last 24 hours"; - $mail->Body = $digest; - - $rc = $mail->Send(); + $mail->IsHTML(true); + $mail->Subject = DIGEST_SUBJECT; + $mail->Body = $digest; + $mail->AltBody = $digest_text; - if (!$rc) print "ERROR: " . $mail->ErrorInfo; + $rc = $mail->Send(); - } + if (!$rc) print "ERROR: " . $mail->ErrorInfo; print "RC=$rc\n"; - if ($rc) { + if ($rc && $do_catchup) { print "Marking affected articles as read...\n"; - catchupArticlesById($link, $affected_ids, 0); + catchupArticlesById($link, $affected_ids, 0, $line["id"]); } db_query($link, "UPDATE ttrss_users SET last_digest_sent = NOW() @@ -3261,13 +3444,25 @@ } } -// $digest = prepare_headlines_digest($link, $user_id, $days, $limit); + print "All done.\n"; } function prepare_headlines_digest($link, $user_id, $days = 1, $limit = 100) { - $tmp = __("New headlines for last 24 hours, as of ") . date("Y/m/d H:m") . "\n"; - $tmp .= "=======================================================\n\n"; + + require_once "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(); @@ -3282,6 +3477,7 @@ date_entered, ttrss_user_entries.ref_id, link, + SUBSTRING(content, 1, 120) AS excerpt, SUBSTRING(last_updated,1,19) AS last_updated FROM ttrss_user_entries,ttrss_entries,ttrss_feeds @@ -3291,38 +3487,60 @@ AND $interval_query AND hidden = false AND ttrss_user_entries.owner_uid = $user_id - AND unread = true ORDER BY ttrss_feeds.title, date_entered DESC + AND unread = true + ORDER BY ttrss_feeds.title, date_entered 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"])); - $feed_title = $line["feed_title"]; - if ($cur_feed_title != $feed_title) { - $cur_feed_title = $feed_title; + $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)); - $tmp .= "$feed_title\n\n"; + $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'); } - $tmp .= " * " . trim($line["title"]) . " - $updated\n"; - $tmp .= " " . trim($line["link"]) . "\n"; - $tmp .= "\n"; } - $tmp .= "--- \n"; - $tmp .= __("You have been sent this email because you have enabled daily digests in Tiny Tiny RSS at ") . - DIGEST_HOSTNAME . "\n". - __("To unsubscribe, visit your configuration options or contact instance owner.\n"); - + $tpl->addBlock('digest'); + $tpl->generateOutputToString($tmp); - return array($tmp, $headlines_count, $affected_ids); + $tpl_t->addBlock('digest'); + $tpl_t->generateOutputToString($tmp_t); + + return array($tmp, $headlines_count, $affected_ids, $tmp_t); } function check_for_update($link, $brief_fmt = true) { @@ -3444,7 +3662,9 @@ } } - function catchupArticlesById($link, $ids, $cmode) { + function catchupArticlesById($link, $ids, $cmode, $owner_uid = false) { + + if (!$owner_uid) $owner_uid = $_SESSION["uid"]; $tmp_ids = array(); @@ -3457,15 +3677,15 @@ if ($cmode == 0) { db_query($link, "UPDATE ttrss_user_entries SET unread = false,last_read = NOW() - WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]); + WHERE ($ids_qpart) AND owner_uid = $owner_uid"); } else if ($cmode == 1) { db_query($link, "UPDATE ttrss_user_entries SET unread = true - WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]); + WHERE ($ids_qpart) AND owner_uid = $owner_uid"); } else { db_query($link, "UPDATE ttrss_user_entries SET unread = NOT unread,last_read = NOW() - WHERE ($ids_qpart) AND owner_uid = " . $_SESSION["uid"]); + WHERE ($ids_qpart) AND owner_uid = $owner_uid"); } } @@ -3561,13 +3781,20 @@
  • ".__('Published')."
  •  
  • -
  • ".__('Mark as read')."
      +
    • ".__('Mark as read')."
      • ".__('Selection')."
      • - + "; + + if (!get_pref($link, 'COMBINED_DISPLAY_MODE')) { + + print "
      • --------
      • ".__("Above active article")."
      • ".__("Below active article")."
      • -
      • --------
      • +
      • --------
      • "; + } + + print "
      • ".__('Entire feed')."
    • "; @@ -3629,7 +3856,9 @@ } */ print ""; - + + print ""; + if ($feed_site_url) { if (!$bottom) { $target = "target=\"_new\""; @@ -3648,6 +3877,8 @@ print " [$user_page_offset] "; } + print ""; + if (!$bottom) { print " "; } - print " ($cat_unread) $ellipsis"; if ($can_browse) { @@ -3958,7 +4189,7 @@ if ($collapsed == "t" || $collapsed == "1") { $holder_class = "feedCatHolder"; $holder_style = "display:none;"; - $ellipsis = "..."; + $ellipsis = "…"; } else { $holder_class = "feedCatHolder"; $holder_style = ""; @@ -3974,7 +4205,7 @@ print "
    • $tmp_category - ($cat_unread) $ellipsis
    • "; @@ -3982,7 +4213,7 @@ } printFeedEntry($feed_id, $class, $feed, $unread, - ICONS_DIR."/$feed_id.ico", $link, $rtl_content, + ICONS_URL."/$feed_id.ico", $link, $rtl_content, $last_updated, $line["last_error"]); ++$lnum; @@ -4257,16 +4488,22 @@ $num_tags = 0; + if ($_SESSION["theme"] == "3pane") { + $tag_limit = 3; + } else { + $tag_limit = 6; + } + foreach ($tags as $tag) { $num_tags++; $tag_escaped = str_replace("'", "\\'", $tag); $tag_str = "$tag, "; - if ($num_tags == 6) { - $tags_str .= "..."; + if ($num_tags == $tag_limit) { + $tags_str .= "…"; - } else if ($num_tags < 6) { + } else if ($num_tags < $tag_limit) { $tags_str .= $tag_str; } $f_tags_str .= $tag_str; @@ -4275,7 +4512,7 @@ $tags_str = preg_replace("/, $/", "", $tags_str); $f_tags_str = preg_replace("/, $/", "", $f_tags_str); - $all_tags_div = "...
      All Tags: $f_tags_str
      "; + $all_tags_div = "
      All Tags: $f_tags_str
      "; $tags_str = preg_replace("/\.\.\.$/", "$all_tags_div", $tags_str); if (!$entry_comments) $entry_comments = " "; # placeholder @@ -4302,7 +4539,40 @@ $line["content"] = preg_replace("/href=/i", "target=\"_new\" href=", $line["content"]); } - print $line["content"] . ""; + print $line["content"]; + + $result = db_query($link, "SELECT * FROM ttrss_enclosures WHERE + post_id = '$id'"); + + if (db_num_rows($result) > 0) { + print "
      "; + + if (db_num_rows($result) == 1) { + print __("Attachment:") . " "; + } else { + print __("Attachments:") . " "; + } + + $entries = array(); + + while ($line = db_fetch_assoc($result)) { + + $url = $line["content_url"]; + + $filename = substr($url, strrpos($url, "/")+1); + + $entry = "" . + $filename . " (" . $line["content_type"] . ")" . ""; + + array_push($entries, $entry); + } + + print join(", ", $entries); + + print "
      "; + } + + print ""; print ""; @@ -4315,6 +4585,8 @@ function outputHeadlinesList($link, $feed, $subop, $view_mode, $limit, $cat_view, $next_unread_feed, $offset) { + $disable_cache = false; + $timing_info = getmicrotime(); $topmost_article_ids = array(); @@ -4333,7 +4605,7 @@ } if ($subop == "ForceUpdate" && sprintf("%d", $feed) > 0) { - update_generic_feed($link, $feed, $cat_view); + update_generic_feed($link, $feed, $cat_view, true); } if ($subop == "MarkAllRead") { @@ -4382,6 +4654,11 @@ /// START ///////////////////////////////////////////////////////////////////////////////// $search = db_escape_string($_GET["query"]); + + if ($search) { + $disable_cache = true; + } + $search_mode = db_escape_string($_GET["search_mode"]); $match_on = db_escape_string($_GET["match_on"]); @@ -4585,7 +4862,15 @@ } else { $add_class = ""; } - + + $expand_cdm = get_pref($link, 'CDM_EXPANDED'); + + if ($expand_cdm) { + $cdm_cstyle = ""; + } else { + $cdm_cstyle = "style=\"display : none\""; + } + print "
      "; @@ -4600,6 +4885,13 @@ print $entry_author; + if (!$expand_cdm) { + print "  + (".__('Show article').")"; + } + + if ($line["feed_title"]) { print " (".$line["feed_title"].")"; } @@ -4611,27 +4903,52 @@ "target=\"_new\" href=", $line["content_preview"]); } - $expand_cdm = get_pref($link, 'CDM_EXPANDED'); + print "
      "; - if ($expand_cdm) { - $cdm_cstyle = ""; - } else { - $cdm_cstyle = "style=\"display : none\""; - } +// print "
      "; + print $line["content_preview"]; - print "
      "; + $e_result = db_query($link, "SELECT * FROM ttrss_enclosures WHERE + post_id = '$id'"); - print "
      "; - print $line["content_preview"]; - print "
      "; + if (db_num_rows($e_result) > 0) { + print "
      "; - if (!$expand_cdm) { + if (db_num_rows($e_result) == 1) { + print __("Attachment:") . " "; + } else { + print __("Attachments:") . " "; + } + + $entries = array(); + + while ($e_line = db_fetch_assoc($e_result)) { + + $url = $e_line["content_url"]; + + $filename = substr($url, strrpos($url, "/")+1); + + $entry = "" . + $filename . " (" . $e_line["content_type"] . ")" . ""; + + array_push($entries, $entry); + } + + print join(", ", $entries); + + print "
      "; + } + + print "
      "; +// print "
      "; + +/* if (!$expand_cdm) { print " Show article"; - } + } */ - print "

      "; + print "
      "; print "
      "; @@ -4656,14 +4973,14 @@ if ($num_tags < 5) { $tags_str .= "$tag, "; } else if ($num_tags == 5) { - $tags_str .= "..."; + $tags_str .= "…"; } } $tags_str = preg_replace("/, $/", "", $tags_str); $full_tags_str = preg_replace("/, $/", "", $full_tags_str); - $all_tags_div = "...
      All Tags: $full_tags_str
      "; + $all_tags_div = "
      All Tags: $full_tags_str
      "; $tags_str = preg_replace("/\.\.\.$/", "$all_tags_div", $tags_str); @@ -4708,7 +5025,7 @@ print "
      "; } - return array($topmost_article_ids, $headlines_count); + return array($topmost_article_ids, $headlines_count, $feed, $disable_cache); } // from here: http://www.roscripts.com/Create_tag_cloud-71.html @@ -4814,26 +5131,154 @@ 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 add_feed_url() { + } // 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 = 'http://' . $_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) + ))"; + } 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) + ))"; + } + + // 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); + + // We search for feed needing update. + $result = db_query($link, "SELECT ttrss_feeds.feed_url,ttrss_feeds.id, ttrss_feeds.owner_uid, + SUBSTRING(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 ttrss_feeds.last_updated ASC $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) pcntl_alarm(300); + update_rss_feed($link, $line["feed_url"], $line["id"], true); + // Cancel the alarm (the update went well) + if(!$from_http) 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 ?>