]> git.wh0rd.org - tt-rss.git/blame - include/functions.php
Added string for Dutch
[tt-rss.git] / include / functions.php
CommitLineData
1d3a17c7 1<?php
6e658547 2 define('EXPECTED_CONFIG_VERSION', 26);
bfd61d3f 3 define('SCHEMA_VERSION', 106);
545ca067 4
23d2471c 5 $fetch_last_error = false;
19b3992b 6 $pluginhost = false;
23d2471c 7
a48d8533 8 function __autoload($class) {
8c0496f7 9 $class_file = str_replace("_", "/", strtolower(basename($class)));
a48d8533 10
8c0496f7 11 $file = dirname(__FILE__)."/../classes/$class_file.php";
a48d8533 12
8c0496f7
AD
13 if (file_exists($file)) {
14 require $file;
a48d8533 15 }
8c0496f7 16
a48d8533 17 }
0d421af8 18
d68629dc 19 mb_internal_encoding("UTF-8");
324944f3 20 date_default_timezone_set('UTC');
8a7f5767
CW
21 if (defined('E_DEPRECATED')) {
22 error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
23 } else {
24 error_reporting(E_ALL & ~E_NOTICE);
25 }
cce28758 26
40d13c28 27 require_once 'config.php';
cc17c205 28
fc2b26a6
AD
29 if (DB_TYPE == "pgsql") {
30 define('SUBSTRING_FOR_DATE', 'SUBSTRING_FOR_DATE');
31 } else {
32 define('SUBSTRING_FOR_DATE', 'SUBSTRING');
33 }
34
0c425dc7
AD
35 define('THEME_VERSION_REQUIRED', 1.1);
36
9632f884
AD
37 /**
38 * Return available translations names.
8d505d78 39 *
9632f884
AD
40 * @access public
41 * @return array A array of available translations.
42 */
f8c612d4 43 function get_translations() {
6a214f92 44 $tr = array(
8d505d78 45 "auto" => "Detect automatically",
a3162add 46 "ca_CA" => "Català",
a06b79c4 47 "cs_CZ" => "Česky",
6a214f92 48 "en_US" => "English",
36d0510c 49 "es_ES" => "Español",
a927fe7b 50 "de_DE" => "Deutsch",
6a214f92 51 "fr_FR" => "Français",
e78fd196 52 "hu_HU" => "Magyar (Hungarian)",
bb5d3960 53 "it_IT" => "Italiano",
1d004f12 54 "ja_JP" => "日本語 (Japanese)",
7b6c1ca7 55 "lv_LV" => "Latviešu",
592535d7 56 "nb_NO" => "Norwegian bokmål",
1171fc44 57 "nl_NL" -> "Dutch",
ea45791a 58 "pl_PL" => "Polski",
6a214f92 59 "ru_RU" => "Русский",
9a063469 60 "pt_BR" => "Portuguese/Brazil",
6a214f92 61 "zh_CN" => "Simplified Chinese");
f8c612d4
AD
62
63 return $tr;
64 }
65
7b26a148
AD
66 require_once "lib/accept-to-gettext.php";
67 require_once "lib/gettext/gettext.inc";
aba609e0 68
87d7e850 69
7b26a148 70 function startup_gettext() {
8d505d78 71
7b26a148
AD
72 # Get locale from Accept-Language header
73 $lang = al2gt(array_keys(get_translations()), "text/html");
89cb787e 74
7b26a148
AD
75 if (defined('_TRANSLATION_OVERRIDE_DEFAULT')) {
76 $lang = _TRANSLATION_OVERRIDE_DEFAULT;
77 }
89cb787e 78
7b26a148
AD
79 /* In login action of mobile version */
80 if ($_POST["language"] && defined('MOBILE_VERSION')) {
81 $lang = $_POST["language"];
1389501e 82 } else if ($_SESSION["language"] && $_SESSION["language"] != "auto") {
afc3cf55 83 $lang = $_SESSION["language"];
7b26a148 84 }
7c33dbd4 85
7b26a148
AD
86 if ($lang) {
87 if (defined('LC_MESSAGES')) {
88 _setlocale(LC_MESSAGES, $lang);
89 } else if (defined('LC_ALL')) {
90 _setlocale(LC_ALL, $lang);
8d039718 91 }
aba609e0 92
7b26a148
AD
93 if (defined('MOBILE_VERSION')) {
94 _bindtextdomain("messages", "../locale");
95 } else {
96 _bindtextdomain("messages", "locale");
97 }
865220a4 98
7b26a148
AD
99 _textdomain("messages");
100 _bind_textdomain_codeset("messages", "UTF-8");
865220a4 101 }
7b26a148
AD
102 }
103
104 startup_gettext();
cc17c205 105
b619ff15 106 require_once 'db-prefs.php';
8911ac8b 107 require_once 'version.php';
87d7e850
AD
108 require_once 'ccache.php';
109 require_once 'labels.php';
40d13c28 110
fb850eec 111 define('SELF_USER_AGENT', 'Tiny Tiny RSS/' . VERSION . ' (http://tt-rss.org/)');
500943a4
AD
112 ini_set('user_agent', SELF_USER_AGENT);
113
b0f379df 114 require_once 'lib/pubsubhubbub/publisher.php';
010efc9b 115
7d96bfcd
AD
116 $tz_offset = -1;
117 $utc_tz = new DateTimeZone('UTC');
118 $schema_version = false;
119
45004d43
AD
120 /**
121 * Print a timestamped debug message.
8d505d78 122 *
45004d43
AD
123 * @param string $msg The debug message.
124 * @return void
125 */
6f9e33e4
AD
126 function _debug($msg) {
127 $ts = strftime("%H:%M:%S", time());
2a6a9395
AD
128 if (function_exists('posix_getpid')) {
129 $ts = "$ts/" . posix_getpid();
130 }
2191eb7a
AD
131
132 if (!(defined('QUIET') && QUIET)) {
133 print "[$ts] $msg\n";
134 }
135
136 if (defined('LOGFILE')) {
137 $fp = fopen(LOGFILE, 'a+');
138
139 if ($fp) {
140 fputs($fp, "[$ts] $msg\n");
141 fclose($fp);
142 }
143 }
144
45004d43 145 } // function _debug
6f9e33e4 146
9632f884
AD
147 /**
148 * Purge a feed old posts.
8d505d78 149 *
9632f884
AD
150 * @param mixed $link A database connection.
151 * @param mixed $feed_id The id of the purged feed.
152 * @param mixed $purge_interval Olderness of purged posts.
153 * @param boolean $debug Set to True to enable the debug. False by default.
154 * @access public
155 * @return void
156 */
ad507f85
AD
157 function purge_feed($link, $feed_id, $purge_interval, $debug = false) {
158
07d0efe9 159 if (!$purge_interval) $purge_interval = feed_purge_interval($link, $feed_id);
8d505d78 160
ad507f85 161 $rows = -1;
4c193675 162
8d505d78 163 $result = db_query($link,
07d0efe9
AD
164 "SELECT owner_uid FROM ttrss_feeds WHERE id = '$feed_id'");
165
166 $owner_uid = false;
167
168 if (db_num_rows($result) == 1) {
169 $owner_uid = db_fetch_result($result, 0, "owner_uid");
170 }
171
ab954dff
AD
172 if ($purge_interval == -1 || !$purge_interval) {
173 if ($owner_uid) {
174 ccache_update($link, $feed_id, $owner_uid);
175 }
176 return;
177 }
178
07d0efe9
AD
179 if (!$owner_uid) return;
180
3907ef71
AD
181 if (FORCE_ARTICLE_PURGE == 0) {
182 $purge_unread = get_pref($link, "PURGE_UNREAD_ARTICLES",
183 $owner_uid, false);
184 } else {
185 $purge_unread = true;
186 $purge_interval = FORCE_ARTICLE_PURGE;
187 }
07d0efe9
AD
188
189 if (!$purge_unread) $query_limit = " unread = false AND ";
190
fefa6ca3 191 if (DB_TYPE == "pgsql") {
6e7f8d26
AD
192 $pg_version = get_pgsql_version($link);
193
194 if (preg_match("/^7\./", $pg_version) || preg_match("/^8\.0/", $pg_version)) {
1e59ae35 195
8d505d78
AD
196 $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE
197 ttrss_entries.id = ref_id AND
198 marked = false AND
199 feed_id = '$feed_id' AND
07d0efe9 200 $query_limit
25ea2805 201 ttrss_entries.date_updated < NOW() - INTERVAL '$purge_interval days'");
1e59ae35
AD
202
203 } else {
204
8d505d78
AD
205 $result = db_query($link, "DELETE FROM ttrss_user_entries
206 USING ttrss_entries
207 WHERE ttrss_entries.id = ref_id AND
208 marked = false AND
209 feed_id = '$feed_id' AND
07d0efe9 210 $query_limit
25ea2805 211 ttrss_entries.date_updated < NOW() - INTERVAL '$purge_interval days'");
1e59ae35 212 }
ad507f85 213
8c0496f7
AD
214 $rows = pg_affected_rows($result);
215
fefa6ca3 216 } else {
8d505d78 217
30f1746f 218/* $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE
fefa6ca3 219 marked = false AND feed_id = '$feed_id' AND
8d505d78 220 (SELECT date_updated FROM ttrss_entries WHERE
30f1746f
AD
221 id = ref_id) < DATE_SUB(NOW(), INTERVAL $purge_interval DAY)"); */
222
8d505d78
AD
223 $result = db_query($link, "DELETE FROM ttrss_user_entries
224 USING ttrss_user_entries, ttrss_entries
225 WHERE ttrss_entries.id = ref_id AND
226 marked = false AND
227 feed_id = '$feed_id' AND
07d0efe9 228 $query_limit
25ea2805 229 ttrss_entries.date_updated < DATE_SUB(NOW(), INTERVAL $purge_interval DAY)");
8d505d78 230
8c0496f7
AD
231 $rows = mysql_affected_rows($link);
232
ad507f85
AD
233 }
234
ced46404
AD
235 ccache_update($link, $feed_id, $owner_uid);
236
ad507f85 237 if ($debug) {
6f9e33e4 238 _debug("Purged feed $feed_id ($purge_interval): deleted $rows articles");
fefa6ca3 239 }
2ea09bde
AD
240
241 return $rows;
9632f884 242 } // function purge_feed
fefa6ca3 243
07d0efe9
AD
244 function feed_purge_interval($link, $feed_id) {
245
8d505d78 246 $result = db_query($link, "SELECT purge_interval, owner_uid FROM ttrss_feeds
07d0efe9
AD
247 WHERE id = '$feed_id'");
248
249 if (db_num_rows($result) == 1) {
250 $purge_interval = db_fetch_result($result, 0, "purge_interval");
251 $owner_uid = db_fetch_result($result, 0, "owner_uid");
252
8d505d78 253 if ($purge_interval == 0) $purge_interval = get_pref($link,
863be6ca 254 'PURGE_OLD_DAYS', $owner_uid);
07d0efe9
AD
255
256 return $purge_interval;
257
258 } else {
259 return -1;
260 }
261 }
262
a2d79981
AD
263 function purge_orphans($link, $do_output = false) {
264
71604ca4 265 // purge orphaned posts in main content table
8d505d78 266 $result = db_query($link, "DELETE FROM ttrss_entries WHERE
71604ca4 267 (SELECT COUNT(int_id) FROM ttrss_user_entries WHERE ref_id = id) = 0");
a2d79981
AD
268
269 if ($do_output) {
270 $rows = db_affected_rows($link, $result);
271 _debug("Purged $rows orphaned posts.");
272 }
c3a8d71a
AD
273 }
274
c7d57b66
AD
275 function get_feed_update_interval($link, $feed_id) {
276 $result = db_query($link, "SELECT owner_uid, update_interval FROM
277 ttrss_feeds WHERE id = '$feed_id'");
278
279 if (db_num_rows($result) == 1) {
280 $update_interval = db_fetch_result($result, 0, "update_interval");
281 $owner_uid = db_fetch_result($result, 0, "owner_uid");
282
283 if ($update_interval != 0) {
284 return $update_interval;
285 } else {
286 return get_pref($link, 'DEFAULT_UPDATE_INTERVAL', $owner_uid, false);
287 }
288
289 } else {
290 return -1;
291 }
292 }
293
fb850eec 294 function fetch_file_contents($url, $type = false, $login = false, $pass = false, $post_query = false, $timeout = false) {
8d505d78
AD
295 $login = urlencode($login);
296 $pass = urlencode($pass);
297
23d2471c
AD
298 global $fetch_last_error;
299
3610b48b 300 if (function_exists('curl_init') && !ini_get("open_basedir")) {
b799dc8b
AD
301
302 if (ini_get("safe_mode")) {
303 $ch = curl_init(geturl($url));
304 } else {
305 $ch = curl_init($url);
306 }
a1af1574 307
fb850eec
AD
308 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout ? $timeout : 15);
309 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout ? $timeout : 45);
81153e6b 310 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, !ini_get("safe_mode"));
a1af1574
AD
311 curl_setopt($ch, CURLOPT_MAXREDIRS, 20);
312 curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
313 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
8d505d78 314 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
5f6804bc 315 curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
19929bbe 316 curl_setopt($ch, CURLOPT_USERAGENT, SELF_USER_AGENT);
268a06dc 317 curl_setopt($ch, CURLOPT_ENCODING , "gzip");
48b657fc 318 curl_setopt($ch, CURLOPT_REFERER, $url);
8d505d78 319
ae5f7bb1
AD
320 if ($post_query) {
321 curl_setopt($ch, CURLOPT_POST, true);
322 curl_setopt($ch, CURLOPT_POSTFIELDS, $post_query);
323 }
324
8d505d78
AD
325 if ($login && $pass)
326 curl_setopt($ch, CURLOPT_USERPWD, "$login:$pass");
a1af1574 327
fb074239 328 $contents = @curl_exec($ch);
268a06dc 329
48b657fc
AD
330 if (curl_errno($ch) === 23 || curl_errno($ch) === 61) {
331 curl_setopt($ch, CURLOPT_ENCODING, 'none');
332 $contents = @curl_exec($ch);
fb850eec
AD
333 }
334
a1af1574 335 if ($contents === false) {
fb850eec 336 $fetch_last_error = curl_errno($ch) . " " . curl_error($ch);
a1af1574
AD
337 curl_close($ch);
338 return false;
4065b60b
AD
339 }
340
8d505d78 341 $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
a1af1574 342 $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
4065b60b 343
8d505d78 344 if ($http_code != 200 || $type && strpos($content_type, "$type") === false) {
fb850eec
AD
345 if (curl_errno($ch) != 0) {
346 $fetch_last_error = curl_errno($ch) . " " . curl_error($ch);
347 } else {
348 $fetch_last_error = "HTTP Code: $http_code";
349 }
350 curl_close($ch);
a1af1574
AD
351 return false;
352 }
4065b60b 353
fb850eec
AD
354 curl_close($ch);
355
a1af1574 356 return $contents;
4065b60b 357 } else {
9949bd15 358 if ($login && $pass ){
8d505d78
AD
359 $url_parts = array();
360
361 preg_match("/(^[^:]*):\/\/(.*)/", $url, $url_parts);
362
363 if ($url_parts[1] && $url_parts[2]) {
364 $url = $url_parts[1] . "://$login:$pass@" . $url_parts[2];
365 }
366 }
367
23d2471c
AD
368 $data = @file_get_contents($url);
369
a0f2a3e1
AD
370 $gzdecoded = gzdecode($data);
371 if ($gzdecoded) $data = $gzdecoded;
372
23d2471c
AD
373 if (!$data && function_exists('error_get_last')) {
374 $error = error_get_last();
375 $fetch_last_error = $error["message"];
376 }
377 return $data;
4065b60b
AD
378 }
379
380 }
78800912 381
9632f884
AD
382 /**
383 * Try to determine the favicon URL for a feed.
384 * adapted from wordpress favicon plugin by Jeff Minard (http://thecodepro.com/)
385 * http://dev.wp-plugins.org/file/favatars/trunk/favatars.php
8d505d78 386 *
9632f884
AD
387 * @param string $url A feed or page URL
388 * @access public
389 * @return mixed The favicon URL, or false if none was found.
390 */
1bd11fdf 391 function get_favicon_url($url) {
99331724 392
1bd11fdf 393 $favicon_url = false;
ed214298 394
4065b60b 395 if ($html = @fetch_file_contents($url)) {
78800912 396
ed214298 397 libxml_use_internal_errors(true);
c798704b 398
ed214298
AD
399 $doc = new DOMDocument();
400 $doc->loadHTML($html);
401 $xpath = new DOMXPath($doc);
717f5e64 402
a712429e
AD
403 $base = $xpath->query('/html/head/base');
404 foreach ($base as $b) {
405 $url = $b->getAttribute("href");
406 break;
407 }
408
1bd11fdf 409 $entries = $xpath->query('/html/head/link[@rel="shortcut icon" or @rel="icon"]');
ed214298
AD
410 if (count($entries) > 0) {
411 foreach ($entries as $entry) {
1bd11fdf
AD
412 $favicon_url = rewrite_relative_url($url, $entry->getAttribute("href"));
413 break;
ed214298 414 }
8d505d78 415 }
4065b60b 416 }
c798704b 417
1bd11fdf
AD
418 if (!$favicon_url)
419 $favicon_url = rewrite_relative_url($url, "/favicon.ico");
420
421 return $favicon_url;
422 } // function get_favicon_url
423
424 function check_feed_favicon($site_url, $feed, $link) {
882311d9 425# print "FAVICON [$site_url]: $favicon_url\n";
4065b60b 426
1bd11fdf
AD
427 $icon_file = ICONS_DIR . "/$feed.ico";
428
429 if (!file_exists($icon_file)) {
430 $favicon_url = get_favicon_url($site_url);
431
432 if ($favicon_url) {
433 // Limiting to "image" type misses those served with text/plain
434 $contents = fetch_file_contents($favicon_url); // , "image");
435
436 if ($contents) {
437 // Crude image type matching.
438 // Patterns gleaned from the file(1) source code.
439 if (preg_match('/^\x00\x00\x01\x00/', $contents)) {
440 // 0 string \000\000\001\000 MS Windows icon resource
441 //error_log("check_feed_favicon: favicon_url=$favicon_url isa MS Windows icon resource");
442 }
443 elseif (preg_match('/^GIF8/', $contents)) {
444 // 0 string GIF8 GIF image data
445 //error_log("check_feed_favicon: favicon_url=$favicon_url isa GIF image");
446 }
447 elseif (preg_match('/^\x89PNG\x0d\x0a\x1a\x0a/', $contents)) {
448 // 0 string \x89PNG\x0d\x0a\x1a\x0a PNG image data
449 //error_log("check_feed_favicon: favicon_url=$favicon_url isa PNG image");
450 }
451 elseif (preg_match('/^\xff\xd8/', $contents)) {
452 // 0 beshort 0xffd8 JPEG image data
453 //error_log("check_feed_favicon: favicon_url=$favicon_url isa JPG image");
454 }
455 else {
456 //error_log("check_feed_favicon: favicon_url=$favicon_url isa UNKNOWN type");
457 $contents = "";
458 }
459 }
460
461 if ($contents) {
462 $fp = @fopen($icon_file, "w");
463
464 if ($fp) {
465 fwrite($fp, $contents);
466 fclose($fp);
467 chmod($icon_file, 0644);
468 }
469 }
470 }
78800912
AD
471 }
472 }
473
f175937c 474 function print_select($id, $default, $values, $attributes = "") {
79f3553b 475 print "<select name=\"$id\" id=\"$id\" $attributes>";
a0d53889
AD
476 foreach ($values as $v) {
477 if ($v == $default)
60807300 478 $sel = "selected=\"1\"";
a0d53889
AD
479 else
480 $sel = "";
8d505d78 481
e88c1943
AD
482 $v = trim($v);
483
60807300 484 print "<option value=\"$v\" $sel>$v</option>";
a0d53889
AD
485 }
486 print "</select>";
487 }
40d13c28 488
79f3553b
AD
489 function print_select_hash($id, $default, $values, $attributes = "") {
490 print "<select name=\"$id\" id='$id' $attributes>";
673d54ca
AD
491 foreach (array_keys($values) as $v) {
492 if ($v == $default)
74d5c8fa 493 $sel = 'selected="selected"';
673d54ca
AD
494 else
495 $sel = "";
8d505d78 496
e88c1943
AD
497 $v = trim($v);
498
673d54ca
AD
499 print "<option $sel value=\"$v\">".$values[$v]."</option>";
500 }
501
502 print "</select>";
503 }
504
f541eb78 505 function print_radio($id, $default, $true_is, $values, $attributes = "") {
77e96719 506 foreach ($values as $v) {
8d505d78 507
77e96719 508 if ($v == $default)
5da169d9 509 $sel = "checked";
77e96719 510 else
5da169d9
AD
511 $sel = "";
512
f541eb78 513 if ($v == $true_is) {
5da169d9
AD
514 $sel .= " value=\"1\"";
515 } else {
516 $sel .= " value=\"0\"";
517 }
8d505d78
AD
518
519 print "<input class=\"noborder\" dojoType=\"dijit.form.RadioButton\"
69654950 520 type=\"radio\" $sel $attributes name=\"$id\">&nbsp;$v&nbsp;";
77e96719
AD
521
522 }
523 }
524
d9084cf2 525 function initialize_user_prefs($link, $uid, $profile = false) {
ff485f1d
AD
526
527 $uid = db_escape_string($uid);
528
d9084cf2
AD
529 if (!$profile) {
530 $profile = "NULL";
f9aa6a89 531 $profile_qpart = "AND profile IS NULL";
d9084cf2 532 } else {
f9aa6a89 533 $profile_qpart = "AND profile = '$profile'";
d9084cf2
AD
534 }
535
f9aa6a89
AD
536 if (get_schema_version($link) < 63) $profile_qpart = "";
537
ff485f1d
AD
538 db_query($link, "BEGIN");
539
540 $result = db_query($link, "SELECT pref_name,def_value FROM ttrss_prefs");
8d505d78
AD
541
542 $u_result = db_query($link, "SELECT pref_name
f9aa6a89 543 FROM ttrss_user_prefs WHERE owner_uid = '$uid' $profile_qpart");
ff485f1d
AD
544
545 $active_prefs = array();
546
547 while ($line = db_fetch_assoc($u_result)) {
8d505d78 548 array_push($active_prefs, $line["pref_name"]);
ff485f1d
AD
549 }
550
551 while ($line = db_fetch_assoc($result)) {
552 if (array_search($line["pref_name"], $active_prefs) === FALSE) {
553// print "adding " . $line["pref_name"] . "<br>";
554
f9aa6a89
AD
555 if (get_schema_version($link) < 63) {
556 db_query($link, "INSERT INTO ttrss_user_prefs
8d505d78 557 (owner_uid,pref_name,value) VALUES
f9aa6a89
AD
558 ('$uid', '".$line["pref_name"]."','".$line["def_value"]."')");
559
560 } else {
561 db_query($link, "INSERT INTO ttrss_user_prefs
8d505d78 562 (owner_uid,pref_name,value, profile) VALUES
f9aa6a89
AD
563 ('$uid', '".$line["pref_name"]."','".$line["def_value"]."', $profile)");
564 }
ff485f1d
AD
565
566 }
567 }
568
569 db_query($link, "COMMIT");
570
571 }
956c7629 572
8de8bfb8
AD
573 function get_ssl_certificate_id() {
574 if ($_SERVER["REDIRECT_SSL_CLIENT_M_SERIAL"]) {
575 return sha1($_SERVER["REDIRECT_SSL_CLIENT_M_SERIAL"] .
576 $_SERVER["REDIRECT_SSL_CLIENT_V_START"] .
577 $_SERVER["REDIRECT_SSL_CLIENT_V_END"] .
578 $_SERVER["REDIRECT_SSL_CLIENT_S_DN"]);
579 }
580 return "";
581 }
582
0d421af8 583 function authenticate_user($link, $login, $password, $check_only = false) {
c8437f35 584
131b01b3 585 if (!SINGLE_USER_MODE) {
c8437f35 586
0d421af8 587 $user_id = false;
0f28f81f
AD
588
589 global $pluginhost;
590 foreach ($pluginhost->get_hooks($pluginhost::HOOK_AUTH_USER) as $plugin) {
591
592 $user_id = (int) $plugin->authenticate($login, $password);
593
594 if ($user_id) {
595 $_SESSION["auth_module"] = strtolower(get_class($plugin));
596 break;
597 }
461766f3
AD
598 }
599
0d421af8
AD
600 if ($user_id && !$check_only) {
601 $_SESSION["uid"] = $user_id;
602
603 $result = db_query($link, "SELECT login,access_level,pwd_hash FROM ttrss_users
604 WHERE id = '$user_id'");
8d505d78 605
131b01b3
AD
606 $_SESSION["name"] = db_fetch_result($result, 0, "login");
607 $_SESSION["access_level"] = db_fetch_result($result, 0, "access_level");
8484ce22 608 $_SESSION["csrf_token"] = sha1(uniqid(rand(), true));
8d505d78
AD
609
610 db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " .
131b01b3 611 $_SESSION["uid"]);
8d505d78 612
131b01b3 613 $_SESSION["ip_address"] = $_SERVER["REMOTE_ADDR"];
1a9f4d3c 614 $_SESSION["pwd_hash"] = db_fetch_result($result, 0, "pwd_hash");
91c5f229
AD
615
616 $_SESSION["last_version_check"] = time();
8d505d78 617
131b01b3 618 initialize_user_prefs($link, $_SESSION["uid"]);
8d505d78 619
131b01b3
AD
620 return true;
621 }
8d505d78 622
131b01b3 623 return false;
503eb349 624
131b01b3 625 } else {
503eb349 626
131b01b3
AD
627 $_SESSION["uid"] = 1;
628 $_SESSION["name"] = "admin";
787e5ebc 629 $_SESSION["access_level"] = 10;
21e42e5f 630
0d421af8
AD
631 $_SESSION["hide_hello"] = true;
632 $_SESSION["hide_logout"] = true;
633
d5fd183d
AD
634 $_SESSION["auth_module"] = false;
635
21e42e5f
AD
636 if (!$_SESSION["csrf_token"]) {
637 $_SESSION["csrf_token"] = sha1(uniqid(rand(), true));
638 }
f557cd78 639
0bbba72d 640 $_SESSION["ip_address"] = $_SERVER["REMOTE_ADDR"];
8d505d78 641
0bbba72d 642 initialize_user_prefs($link, $_SESSION["uid"]);
8d505d78 643
c8437f35
AD
644 return true;
645 }
c8437f35
AD
646 }
647
e6cb77a0
AD
648 function make_password($length = 8) {
649
85db6213
AD
650 $password = "";
651 $possible = "0123456789abcdfghjkmnpqrstvwxyzABCDFGHJKMNPQRSTVWXYZ";
652
653 $i = 0;
654
655 while ($i < $length) {
656 $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
657
658 if (!strstr($password, $char)) {
659 $password .= $char;
660 $i++;
661 }
662 }
663 return $password;
e6cb77a0
AD
664 }
665
666 // this is called after user is created to initialize default feeds, labels
667 // or whatever else
8d505d78 668
e6cb77a0
AD
669 // user preferences are checked on every login, not here
670
671 function initialize_user($link, $uid) {
672
e6cb77a0 673 db_query($link, "insert into ttrss_feeds (owner_uid,title,feed_url)
74bff337 674 values ('$uid', 'Tiny Tiny RSS: New Releases',
b6d486a3 675 'http://tt-rss.org/releases.rss')");
3b0feb9b 676
cd2cd415
AD
677 db_query($link, "insert into ttrss_feeds (owner_uid,title,feed_url)
678 values ('$uid', 'Tiny Tiny RSS: Forum',
f0855b88 679 'http://tt-rss.org/forum/rss.php')");
3b0feb9b 680 }
e6cb77a0 681
b8aa49bc 682 function logout_user() {
5ccc1cf5
AD
683 session_destroy();
684 if (isset($_COOKIE[session_name()])) {
685 setcookie(session_name(), '', time()-42000, '/');
686 }
b8aa49bc
AD
687 }
688
8484ce22
AD
689 function validate_csrf($csrf_token) {
690 return $csrf_token == $_SESSION['csrf_token'];
691 }
692
916f788a 693 function validate_session($link) {
0f41fce8
AD
694 if (SINGLE_USER_MODE) return true;
695
696 $check_ip = $_SESSION['ip_address'];
697
698 switch (SESSION_CHECK_ADDRESS) {
699 case 0:
700 $check_ip = '';
701 break;
702 case 1:
703 $check_ip = substr($check_ip, 0, strrpos($check_ip, '.')+1);
704 break;
705 case 2:
706 $check_ip = substr($check_ip, 0, strrpos($check_ip, '.'));
707 $check_ip = substr($check_ip, 0, strrpos($check_ip, '.')+1);
708 break;
709 };
710
d769a0f7 711 if ($check_ip && strpos($_SERVER['REMOTE_ADDR'], $check_ip) !== 0) {
8d505d78 712 $_SESSION["login_error_msg"] =
d769a0f7
AD
713 __("Session failed to validate (incorrect IP)");
714 return false;
715 }
0f41fce8
AD
716
717 if ($_SESSION["ref_schema_version"] != get_schema_version($link, true))
05044a59 718 return false;
05044a59 719
e6684130
AD
720 if ($_SESSION["uid"]) {
721
8d505d78 722 $result = db_query($link,
e6684130
AD
723 "SELECT pwd_hash FROM ttrss_users WHERE id = '".$_SESSION["uid"]."'");
724
725 $pwd_hash = db_fetch_result($result, 0, "pwd_hash");
726
727 if ($pwd_hash != $_SESSION["pwd_hash"]) {
728 return false;
729 }
730 }
731
a885f0ec 732/* if ($_SESSION["cookie_lifetime"] && $_SESSION["uid"]) {
d620cfe7 733
8e849206 734 //print_r($_SESSION);
d620cfe7
AD
735
736 if (time() > $_SESSION["cookie_lifetime"]) {
737 return false;
738 }
a885f0ec
AD
739 } */
740
916f788a
AD
741 return true;
742 }
743
de612e7a
AD
744 function load_user_plugins($link, $owner_uid) {
745 if ($owner_uid) {
746 $plugins = get_pref($link, "_ENABLED_PLUGINS", $owner_uid);
747
748 global $pluginhost;
d8a1d2a2 749 $pluginhost->load($plugins, $pluginhost::KIND_USER, $owner_uid);
e9c04fd4
AD
750
751 if (get_schema_version($link) > 100) {
752 $pluginhost->load_data();
753 }
de612e7a
AD
754 }
755 }
756
97acbaf1 757 function login_sequence($link, $login_form = 0) {
75a316ab
AD
758 $_SESSION["prefs_cache"] = false;
759
97acbaf1 760 if (SINGLE_USER_MODE) {
de612e7a 761 authenticate_user($link, "admin", null);
0a117b86 762 cache_prefs($link);
de612e7a 763 load_user_plugins($link, $_SESSION["uid"]);
97acbaf1
AD
764 } else {
765 if (!$_SESSION["uid"] || !validate_session($link)) {
766
767 if (AUTH_AUTO_LOGIN && authenticate_user($link, null, null)) {
768 $_SESSION["ref_schema_version"] = get_schema_version($link, true);
769 } else {
770 authenticate_user($link, null, null, true);
771 }
772
773 if (!$_SESSION["uid"]) render_login_form($link, $login_form);
774
775 } else {
776 /* bump login timestamp */
777 db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " .
778 $_SESSION["uid"]);
01a87dff
AD
779 }
780
afc3cf55
AD
781 if ($_SESSION["uid"] && $_SESSION["language"] && SESSION_COOKIE_LIFETIME > 0) {
782 setcookie("ttrss_lang", $_SESSION["language"],
783 time() + SESSION_COOKIE_LIFETIME);
b8aa49bc 784 }
de612e7a
AD
785
786 if ($_SESSION["uid"]) {
0a117b86 787 cache_prefs($link);
de612e7a
AD
788 load_user_plugins($link, $_SESSION["uid"]);
789 }
b8aa49bc 790 }
afc3cf55 791 }
3547842a 792
411fe209 793 function truncate_string($str, $max_len, $suffix = '&hellip;') {
12db369c 794 if (mb_strlen($str, "utf-8") > $max_len - 3) {
411fe209 795 return mb_substr($str, 0, $max_len, "utf-8") . $suffix;
3547842a
AD
796 } else {
797 return $str;
798 }
799 }
54a60e1a 800
ab4b768f
AD
801 function convert_timestamp($timestamp, $source_tz, $dest_tz) {
802
803 try {
804 $source_tz = new DateTimeZone($source_tz);
805 } catch (Exception $e) {
806 $source_tz = new DateTimeZone('UTC');
807 }
808
809 try {
810 $dest_tz = new DateTimeZone($dest_tz);
811 } catch (Exception $e) {
812 $dest_tz = new DateTimeZone('UTC');
813 }
814
815 $dt = new DateTime(date('Y-m-d H:i:s', $timestamp), $source_tz);
816 return $dt->format('U') + $dest_tz->getOffset($dt);
817 }
818
324944f3
AD
819 function make_local_datetime($link, $timestamp, $long, $owner_uid = false,
820 $no_smart_dt = false) {
821
822 if (!$owner_uid) $owner_uid = $_SESSION['uid'];
823 if (!$timestamp) $timestamp = '1970-01-01 0:00';
824
7d96bfcd
AD
825 global $utc_tz;
826 global $tz_offset;
324944f3 827
7d96bfcd
AD
828 # We store date in UTC internally
829 $dt = new DateTime($timestamp, $utc_tz);
830
831 if ($tz_offset == -1) {
832
833 $user_tz_string = get_pref($link, 'USER_TIMEZONE', $owner_uid);
834
835 try {
836 $user_tz = new DateTimeZone($user_tz_string);
837 } catch (Exception $e) {
838 $user_tz = $utc_tz;
839 }
840
841 $tz_offset = $user_tz->getOffset($dt);
324944f3
AD
842 }
843
7d96bfcd 844 $user_timestamp = $dt->format('U') + $tz_offset;
324944f3 845
1dc52ae7 846 if (!$no_smart_dt) {
8d505d78 847 return smart_date_time($link, $user_timestamp,
7d96bfcd 848 $tz_offset, $owner_uid);
324944f3
AD
849 } else {
850 if ($long)
851 $format = get_pref($link, 'LONG_DATE_FORMAT', $owner_uid);
852 else
853 $format = get_pref($link, 'SHORT_DATE_FORMAT', $owner_uid);
854
855 return date($format, $user_timestamp);
856 }
857 }
858
2a5c136e
AD
859 function smart_date_time($link, $timestamp, $tz_offset = 0, $owner_uid = false) {
860 if (!$owner_uid) $owner_uid = $_SESSION['uid'];
861
862 if (date("Y.m.d", $timestamp) == date("Y.m.d", time() + $tz_offset)) {
be773442 863 return date("G:i", $timestamp);
2a5c136e
AD
864 } else if (date("Y", $timestamp) == date("Y", time() + $tz_offset)) {
865 $format = get_pref($link, 'SHORT_DATE_FORMAT', $owner_uid);
866 return date($format, $timestamp);
be773442 867 } else {
2a5c136e
AD
868 $format = get_pref($link, 'LONG_DATE_FORMAT', $owner_uid);
869 return date($format, $timestamp);
be773442
AD
870 }
871 }
872
e3c99f3b 873 function sql_bool_to_bool($s) {
9955a134 874 if ($s == "t" || $s == "1" || strtolower($s) == "true") {
e3c99f3b
AD
875 return true;
876 } else {
877 return false;
878 }
879 }
8d505d78 880
badac687
AD
881 function bool_to_sql_bool($s) {
882 if ($s) {
883 return "true";
884 } else {
885 return "false";
886 }
887 }
e3c99f3b 888
fcfa9ef1
AD
889 // Session caching removed due to causing wrong redirects to upgrade
890 // script when get_schema_version() is called on an obsolete session
891 // created on a previous schema version.
199db684 892 function get_schema_version($link, $nocache = false) {
7d96bfcd
AD
893 global $schema_version;
894
895 if (!$schema_version) {
199db684
AD
896 $result = db_query($link, "SELECT schema_version FROM ttrss_version");
897 $version = db_fetch_result($result, 0, "schema_version");
7d96bfcd 898 $schema_version = $version;
199db684 899 return $version;
7d96bfcd
AD
900 } else {
901 return $schema_version;
902 }
e4c51a6c
AD
903 }
904
6043fb7e 905 function sanity_check($link) {
31303c6b 906 require_once 'errors.php';
ebb948c2 907
6043fb7e 908 $error_code = 0;
7d96bfcd 909 $schema_version = get_schema_version($link, true);
6043fb7e
AD
910
911 if ($schema_version != SCHEMA_VERSION) {
912 $error_code = 5;
913 }
914
aec3ce39
AD
915 if (DB_TYPE == "mysql") {
916 $result = db_query($link, "SELECT true", false);
917 if (db_num_rows($result) != 1) {
918 $error_code = 10;
919 }
920 }
921
f29ba148
AD
922 if (db_escape_string("testTEST") != "testTEST") {
923 $error_code = 12;
924 }
925
ebb948c2 926 return array("code" => $error_code, "message" => $ERRORS[$error_code]);
6043fb7e
AD
927 }
928
27981ca3 929 function file_is_locked($filename) {
31a6d42d 930 if (function_exists('flock')) {
fb074239 931 $fp = @fopen(LOCK_DIRECTORY . "/$filename", "r");
31a6d42d
AD
932 if ($fp) {
933 if (flock($fp, LOCK_EX | LOCK_NB)) {
934 flock($fp, LOCK_UN);
935 fclose($fp);
936 return false;
937 }
27981ca3 938 fclose($fp);
31a6d42d 939 return true;
e89aed7b
AD
940 } else {
941 return false;
27981ca3 942 }
27981ca3 943 }
c1fb4a5e 944 return true; // consider the file always locked and skip the test
27981ca3
AD
945 }
946
fcb4c0c9 947 function make_lockfile($filename) {
cfa43e02 948 $fp = fopen(LOCK_DIRECTORY . "/$filename", "w");
fcb4c0c9 949
a44bfcfd 950 if ($fp && flock($fp, LOCK_EX | LOCK_NB)) {
4c59adb1
AD
951 if (function_exists('posix_getpid')) {
952 fwrite($fp, posix_getpid() . "\n");
953 }
fcb4c0c9
AD
954 return $fp;
955 } else {
956 return false;
957 }
958 }
959
bf7fcde8 960 function make_stampfile($filename) {
cfa43e02 961 $fp = fopen(LOCK_DIRECTORY . "/$filename", "w");
bf7fcde8 962
8e00ae9b 963 if (flock($fp, LOCK_EX | LOCK_NB)) {
bf7fcde8 964 fwrite($fp, time() . "\n");
8e00ae9b 965 flock($fp, LOCK_UN);
bf7fcde8
AD
966 fclose($fp);
967 return true;
968 } else {
969 return false;
970 }
971 }
972
894ebcf5 973 function sql_random_function() {
8c0496f7 974 if (DB_TYPE == "mysql") {
894ebcf5
AD
975 return "RAND()";
976 } else {
977 return "RANDOM()";
978 }
979 }
980
184f5195 981 function catchup_feed($link, $feed, $cat_view, $owner_uid = false, $max_id = false) {
c7e51de1
AD
982
983 if (!$owner_uid) $owner_uid = $_SESSION['uid'];
88040f57 984
37c03d3a 985 //if (preg_match("/^-?[0-9][0-9]*$/", $feed) != false) {
22fdebff 986
705b97b7
AD
987 $ref_check_qpart = ($max_id &&
988 !get_pref($link, 'REVERSE_HEADLINES')) ? "ref_id <= '$max_id'" : "true";
184f5195 989
37c03d3a 990 if (is_numeric($feed)) {
23aa0d16
AD
991 if ($cat_view) {
992
72a2f4f5 993 if ($feed >= 0) {
f9fca8cb
AD
994
995 if ($feed > 0) {
bda6afa2
AD
996 $children = getChildCategories($link, $feed, $owner_uid);
997 array_push($children, $feed);
998
999 $children = join(",", $children);
1000
1001 $cat_qpart = "cat_id IN ($children)";
f9fca8cb
AD
1002 } else {
1003 $cat_qpart = "cat_id IS NULL";
1004 }
8d505d78 1005
bda6afa2
AD
1006 db_query($link, "UPDATE ttrss_user_entries
1007 SET unread = false,last_read = NOW()
1008 WHERE feed_id IN (SELECT id FROM ttrss_feeds WHERE $cat_qpart)
1bad74ea 1009 AND $ref_check_qpart AND unread = true
bda6afa2 1010 AND owner_uid = $owner_uid");
23aa0d16 1011
f9fca8cb 1012 } else if ($feed == -2) {
23aa0d16 1013
8d505d78
AD
1014 db_query($link, "UPDATE ttrss_user_entries
1015 SET unread = false,last_read = NOW() WHERE (SELECT COUNT(*)
1016 FROM ttrss_user_labels2 WHERE article_id = ref_id) > 0
184f5195
AD
1017 AND $ref_check_qpart
1018 AND unread = true AND owner_uid = $owner_uid");
23aa0d16
AD
1019 }
1020
1021 } else if ($feed > 0) {
1022
8d505d78
AD
1023 db_query($link, "UPDATE ttrss_user_entries
1024 SET unread = false,last_read = NOW()
184f5195 1025 WHERE feed_id = '$feed'
1bad74ea 1026 AND $ref_check_qpart AND unread = true
184f5195 1027 AND owner_uid = $owner_uid");
8d505d78 1028
23aa0d16
AD
1029 } else if ($feed < 0 && $feed > -10) { // special, like starred
1030
1031 if ($feed == -1) {
8d505d78 1032 db_query($link, "UPDATE ttrss_user_entries
23aa0d16 1033 SET unread = false,last_read = NOW()
184f5195 1034 WHERE marked = true
1bad74ea 1035 AND $ref_check_qpart AND unread = true
184f5195 1036 AND owner_uid = $owner_uid");
23aa0d16 1037 }
e4f4b46f
AD
1038
1039 if ($feed == -2) {
8d505d78 1040 db_query($link, "UPDATE ttrss_user_entries
e4f4b46f 1041 SET unread = false,last_read = NOW()
184f5195 1042 WHERE published = true
1bad74ea 1043 AND $ref_check_qpart AND unread = true
184f5195 1044 AND owner_uid = $owner_uid");
e4f4b46f
AD
1045 }
1046
2d24f032
AD
1047 if ($feed == -3) {
1048
c1d7e6c3
AD
1049 $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE");
1050
2d24f032 1051 if (DB_TYPE == "pgsql") {
8d505d78 1052 $match_part = "updated > NOW() - INTERVAL '$intl hour' ";
2d24f032 1053 } else {
8d505d78 1054 $match_part = "updated > DATE_SUB(NOW(),
c1d7e6c3 1055 INTERVAL $intl HOUR) ";
2d24f032
AD
1056 }
1057
8d505d78 1058 $result = db_query($link, "SELECT id FROM ttrss_entries,
1f3335dc
AD
1059 ttrss_user_entries WHERE $match_part AND
1060 unread = true AND
8d505d78 1061 ttrss_user_entries.ref_id = ttrss_entries.id AND
c7e51de1 1062 owner_uid = $owner_uid");
1f3335dc
AD
1063
1064 $affected_ids = array();
1065
1066 while ($line = db_fetch_assoc($result)) {
1067 array_push($affected_ids, $line["id"]);
1068 }
1069
1070 catchupArticlesById($link, $affected_ids, 0);
2d24f032
AD
1071 }
1072
3584cb11 1073 if ($feed == -4) {
8d505d78 1074 db_query($link, "UPDATE ttrss_user_entries
3584cb11 1075 SET unread = false,last_read = NOW()
1bad74ea
AD
1076 WHERE $ref_check_qpart AND unread = true AND
1077 owner_uid = $owner_uid");
3584cb11
AD
1078 }
1079
23aa0d16
AD
1080 } else if ($feed < -10) { // label
1081
23aa0d16
AD
1082 $label_id = -$feed - 11;
1083
8d505d78
AD
1084 db_query($link, "UPDATE ttrss_user_entries, ttrss_user_labels2
1085 SET unread = false, last_read = NOW()
338c238d 1086 WHERE label_id = '$label_id' AND unread = true
184f5195 1087 AND $ref_check_qpart
c7e51de1 1088 AND owner_uid = '$owner_uid' AND ref_id = article_id");
23aa0d16 1089
23aa0d16 1090 }
ad0056a8 1091
c7e51de1 1092 ccache_update($link, $feed, $owner_uid, $cat_view);
ad0056a8 1093
23aa0d16
AD
1094 } else { // tag
1095 db_query($link, "BEGIN");
1096
1097 $tag_name = db_escape_string($feed);
1098
1099 $result = db_query($link, "SELECT post_int_id FROM ttrss_tags
c7e51de1 1100 WHERE tag_name = '$tag_name' AND owner_uid = $owner_uid");
23aa0d16
AD
1101
1102 while ($line = db_fetch_assoc($result)) {
1103 db_query($link, "UPDATE ttrss_user_entries SET
8d505d78 1104 unread = false, last_read = NOW()
1bad74ea
AD
1105 WHERE $ref_check_qpart AND unread = true
1106 AND int_id = " . $line["post_int_id"]);
23aa0d16
AD
1107 }
1108 db_query($link, "COMMIT");
1109 }
1110 }
1111
5b55e9e2 1112 function getAllCounters($link) {
6a7817c1 1113 $data = getGlobalCounters($link);
8d505d78 1114
6a7817c1 1115 $data = array_merge($data, getVirtCounters($link));
5b55e9e2
AD
1116 $data = array_merge($data, getLabelCounters($link));
1117 $data = array_merge($data, getFeedCounters($link, $active_feed));
1118 $data = array_merge($data, getCategoryCounters($link));
6a7817c1
AD
1119
1120 return $data;
8d505d78 1121 }
a9cb1f83 1122
79178062
AD
1123 function getCategoryTitle($link, $cat_id) {
1124
1125 if ($cat_id == -1) {
1126 return __("Special");
1127 } else if ($cat_id == -2) {
1128 return __("Labels");
1129 } else {
1130
1131 $result = db_query($link, "SELECT title FROM ttrss_feed_categories WHERE
1132 id = '$cat_id'");
1133
1134 if (db_num_rows($result) == 1) {
1135 return db_fetch_result($result, 0, "title");
1136 } else {
f99759da 1137 return __("Uncategorized");
79178062
AD
1138 }
1139 }
1140 }
1141
1142
a9cb1f83 1143 function getCategoryCounters($link) {
6a7817c1 1144 $ret_arr = array();
bba7c4bf 1145
6a7817c1 1146 /* Labels category */
bba7c4bf 1147
8acc449c 1148 $cv = array("id" => -2, "kind" => "cat",
6a7817c1 1149 "counter" => getCategoryUnread($link, -2));
bba7c4bf 1150
6a7817c1 1151 array_push($ret_arr, $cv);
bba7c4bf 1152
2c5f231e
AD
1153 $result = db_query($link, "SELECT id AS cat_id, value AS unread,
1154 (SELECT COUNT(id) FROM ttrss_feed_categories AS c2
1155 WHERE c2.parent_cat = ttrss_feed_categories.id) AS num_children
8d505d78
AD
1156 FROM ttrss_feed_categories, ttrss_cat_counters_cache
1157 WHERE ttrss_cat_counters_cache.feed_id = id AND
fc9de939 1158 ttrss_cat_counters_cache.owner_uid = ttrss_feed_categories.owner_uid AND
31375163 1159 ttrss_feed_categories.owner_uid = " . $_SESSION["uid"]);
a9cb1f83
AD
1160
1161 while ($line = db_fetch_assoc($result)) {
22fdebff 1162 $line["cat_id"] = (int) $line["cat_id"];
8a4c759e 1163
2c5f231e 1164 if ($line["num_children"] > 0) {
99c9e91a 1165 $child_counter = getCategoryChildrenUnread($link, $line["cat_id"], $_SESSION["uid"]);
2c5f231e
AD
1166 } else {
1167 $child_counter = 0;
1168 }
1169
8acc449c 1170 $cv = array("id" => $line["cat_id"], "kind" => "cat",
0ef32f48 1171 "counter" => $line["unread"] + $child_counter);
6a7817c1
AD
1172
1173 array_push($ret_arr, $cv);
a9cb1f83 1174 }
d232a40f
AD
1175
1176 /* Special case: NULL category doesn't actually exist in the DB */
1177
9798b2b4 1178 $cv = array("id" => 0, "kind" => "cat",
12e6de72 1179 "counter" => (int) ccache_find($link, 0, $_SESSION["uid"], true));
d232a40f 1180
6a7817c1
AD
1181 array_push($ret_arr, $cv);
1182
1183 return $ret_arr;
a9cb1f83
AD
1184 }
1185
2c5f231e 1186 // only accepts real cats (>= 0)
99c9e91a 1187 function getCategoryChildrenUnread($link, $cat, $owner_uid = false) {
2c5f231e
AD
1188 if (!$owner_uid) $owner_uid = $_SESSION["uid"];
1189
1190 $result = db_query($link, "SELECT id FROM ttrss_feed_categories WHERE parent_cat = '$cat'
1191 AND owner_uid = $owner_uid");
1192
1193 $unread = 0;
1194
1195 while ($line = db_fetch_assoc($result)) {
1196 $unread += getCategoryUnread($link, $line["id"], $owner_uid);
99c9e91a 1197 $unread += getCategoryChildrenUnread($link, $line["id"], $owner_uid);
2c5f231e
AD
1198 }
1199
1200 return $unread;
1201 }
1202
b6d486a3
AD
1203 function getCategoryUnread($link, $cat, $owner_uid = false) {
1204
1205 if (!$owner_uid) $owner_uid = $_SESSION["uid"];
f295c368 1206
bba7c4bf 1207 if ($cat >= 0) {
18664970 1208
bba7c4bf
AD
1209 if ($cat != 0) {
1210 $cat_query = "cat_id = '$cat'";
1211 } else {
1212 $cat_query = "cat_id IS NULL";
1213 }
14073c0a 1214
8d505d78 1215 $result = db_query($link, "SELECT id FROM ttrss_feeds WHERE $cat_query
b6d486a3 1216 AND owner_uid = " . $owner_uid);
8d505d78 1217
bba7c4bf
AD
1218 $cat_feeds = array();
1219 while ($line = db_fetch_assoc($result)) {
1220 array_push($cat_feeds, "feed_id = " . $line["id"]);
1221 }
8d505d78 1222
bba7c4bf 1223 if (count($cat_feeds) == 0) return 0;
8d505d78 1224
bba7c4bf 1225 $match_part = implode(" OR ", $cat_feeds);
8d505d78
AD
1226
1227 $result = db_query($link, "SELECT COUNT(int_id) AS unread
687bb90d
AD
1228 FROM ttrss_user_entries
1229 WHERE unread = true AND ($match_part)
1230 AND owner_uid = " . $owner_uid);
8d505d78 1231
bba7c4bf 1232 $unread = 0;
8d505d78 1233
bba7c4bf
AD
1234 # this needs to be rewritten
1235 while ($line = db_fetch_assoc($result)) {
1236 $unread += $line["unread"];
1237 }
8d505d78 1238
bba7c4bf
AD
1239 return $unread;
1240 } else if ($cat == -1) {
59e15af4 1241 return getFeedUnread($link, -1) + getFeedUnread($link, -2) + getFeedUnread($link, -3) + getFeedUnread($link, 0);
bba7c4bf 1242 } else if ($cat == -2) {
f295c368 1243
b2531a28 1244 $result = db_query($link, "
8d505d78 1245 SELECT COUNT(unread) AS unread FROM
687bb90d
AD
1246 ttrss_user_entries, ttrss_user_labels2
1247 WHERE article_id = ref_id AND unread = true
b2531a28 1248 AND ttrss_user_entries.owner_uid = '$owner_uid'");
ceb30ba4 1249
b2531a28 1250 $unread = db_fetch_result($result, 0, "unread");
f295c368 1251
b2531a28 1252 return $unread;
f295c368 1253
8d505d78 1254 }
f295c368
AD
1255 }
1256
1257 function getFeedUnread($link, $feed, $is_cat = false) {
2627f2d0 1258 return getFeedArticles($link, $feed, $is_cat, true, $_SESSION["uid"]);
bdb7369b
AD
1259 }
1260
ceb30ba4
AD
1261 function getLabelUnread($link, $label_id, $owner_uid = false) {
1262 if (!$owner_uid) $owner_uid = $_SESSION["uid"];
1263
f360b028
AD
1264 $result = db_query($link, "SELECT COUNT(ref_id) AS unread FROM ttrss_user_entries, ttrss_user_labels2
1265 WHERE owner_uid = '$owner_uid' AND unread = true AND label_id = '$label_id' AND article_id = ref_id");
ceb30ba4
AD
1266
1267 if (db_num_rows($result) != 0) {
1268 return db_fetch_result($result, 0, "unread");
1269 } else {
1270 return 0;
1271 }
1272 }
1273
2627f2d0
AD
1274 function getFeedArticles($link, $feed, $is_cat = false, $unread_only = false,
1275 $owner_uid = false) {
1276
22fdebff 1277 $n_feed = (int) $feed;
687bb90d 1278 $need_entries = false;
f295c368 1279
2627f2d0
AD
1280 if (!$owner_uid) $owner_uid = $_SESSION["uid"];
1281
bdb7369b
AD
1282 if ($unread_only) {
1283 $unread_qpart = "unread = true";
1284 } else {
1285 $unread_qpart = "true";
1286 }
1287
f295c368 1288 if ($is_cat) {
8d505d78 1289 return getCategoryUnread($link, $n_feed, $owner_uid);
5417fbd7
AD
1290 } else if ($n_feed == -6) {
1291 return 0;
1292 } else if ($feed != "0" && $n_feed == 0) {
326469fc 1293
c5701e70
AD
1294 $feed = db_escape_string($feed);
1295
326469fc 1296 $result = db_query($link, "SELECT SUM((SELECT COUNT(int_id)
8d505d78 1297 FROM ttrss_user_entries,ttrss_entries WHERE int_id = post_int_id
687bb90d 1298 AND ref_id = id AND $unread_qpart)) AS count FROM ttrss_tags
326469fc
AD
1299 WHERE owner_uid = $owner_uid AND tag_name = '$feed'");
1300 return db_fetch_result($result, 0, "count");
1301
f295c368 1302 } else if ($n_feed == -1) {
a9cb1f83 1303 $match_part = "marked = true";
e4f4b46f
AD
1304 } else if ($n_feed == -2) {
1305 $match_part = "published = true";
2d24f032 1306 } else if ($n_feed == -3) {
cd2cc43d 1307 $match_part = "unread = true AND score >= 0";
2d24f032 1308
b71e188e 1309 $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE", $owner_uid);
c1d7e6c3 1310
2d24f032 1311 if (DB_TYPE == "pgsql") {
8d505d78 1312 $match_part .= " AND updated > NOW() - INTERVAL '$intl hour' ";
2d24f032 1313 } else {
7608b38a 1314 $match_part .= " AND updated > DATE_SUB(NOW(), INTERVAL $intl HOUR) ";
2d24f032 1315 }
687bb90d
AD
1316
1317 $need_entries = true;
1318
b2531a28
AD
1319 } else if ($n_feed == -4) {
1320 $match_part = "true";
e04c18a2 1321 } else if ($n_feed >= 0) {
831ff047 1322
6e63a7c3
AD
1323 if ($n_feed != 0) {
1324 $match_part = "feed_id = '$n_feed'";
831ff047 1325 } else {
6e63a7c3 1326 $match_part = "feed_id IS NULL";
831ff047 1327 }
6e63a7c3 1328
a9cb1f83 1329 } else if ($feed < -10) {
318260cc 1330
a9cb1f83
AD
1331 $label_id = -$feed - 11;
1332
ceb30ba4 1333 return getLabelUnread($link, $label_id, $owner_uid);
a9cb1f83 1334
a9cb1f83
AD
1335 }
1336
1337 if ($match_part) {
e04c18a2 1338
687bb90d 1339 if ($need_entries) {
e04c18a2 1340 $from_qpart = "ttrss_user_entries,ttrss_entries";
687bb90d
AD
1341 $from_where = "ttrss_entries.id = ttrss_user_entries.ref_id AND";
1342 } else {
1343 $from_qpart = "ttrss_user_entries";
e04c18a2
AD
1344 }
1345
8d505d78 1346 $query = "SELECT count(int_id) AS unread
e04c18a2 1347 FROM $from_qpart WHERE
687bb90d
AD
1348 $unread_qpart AND $from_where ($match_part) AND ttrss_user_entries.owner_uid = $owner_uid";
1349
1350 //echo "[$feed/$query]\n";
dbfc4365
AD
1351
1352 $result = db_query($link, $query);
8d505d78 1353
a9cb1f83 1354 } else {
8d505d78 1355
a9cb1f83 1356 $result = db_query($link, "SELECT COUNT(post_int_id) AS unread
8d505d78
AD
1357 FROM ttrss_tags,ttrss_user_entries,ttrss_entries
1358 WHERE tag_name = '$feed' AND post_int_id = int_id AND ref_id = ttrss_entries.id
687bb90d 1359 AND $unread_qpart AND ttrss_tags.owner_uid = " . $owner_uid);
a9cb1f83 1360 }
8d505d78 1361
a9cb1f83 1362 $unread = db_fetch_result($result, 0, "unread");
cfb02131 1363
a9cb1f83
AD
1364 return $unread;
1365 }
1366
f3acc32e
AD
1367 function getGlobalUnread($link, $user_id = false) {
1368
1369 if (!$user_id) {
1370 $user_id = $_SESSION["uid"];
1371 }
1372
8a4c759e
AD
1373 $result = db_query($link, "SELECT SUM(value) AS c_id FROM ttrss_counters_cache
1374 WHERE owner_uid = '$user_id' AND feed_id > 0");
1375
8d505d78 1376 $c_id = db_fetch_result($result, 0, "c_id");
8a4c759e 1377
a9cb1f83
AD
1378 return $c_id;
1379 }
1380
1381 function getGlobalCounters($link, $global_unread = -1) {
6a7817c1
AD
1382 $ret_arr = array();
1383
8d505d78 1384 if ($global_unread == -1) {
a9cb1f83
AD
1385 $global_unread = getGlobalUnread($link);
1386 }
6a7817c1 1387
8d505d78 1388 $cv = array("id" => "global-unread",
12e6de72 1389 "counter" => (int) $global_unread);
6a7817c1
AD
1390
1391 array_push($ret_arr, $cv);
7bf7e4d3 1392
8d505d78 1393 $result = db_query($link, "SELECT COUNT(id) AS fn FROM
7bf7e4d3
AD
1394 ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]);
1395
1396 $subscribed_feeds = db_fetch_result($result, 0, "fn");
1397
8d505d78 1398 $cv = array("id" => "subscribed-feeds",
12e6de72 1399 "counter" => (int) $subscribed_feeds);
7bf7e4d3 1400
6a7817c1
AD
1401 array_push($ret_arr, $cv);
1402
1403 return $ret_arr;
a9cb1f83
AD
1404 }
1405
6a7817c1 1406 function getVirtCounters($link) {
a9cb1f83 1407
ef393de7 1408 $ret_arr = array();
bdb7369b 1409
e04c18a2 1410 for ($i = 0; $i >= -4; $i--) {
bdb7369b 1411
ceb30ba4 1412 $count = getFeedUnread($link, $i);
6a7817c1
AD
1413
1414 $cv = array("id" => $i,
12e6de72 1415 "counter" => (int) $count);
8d505d78 1416
296c8134
AD
1417// if (get_pref($link, 'EXTENDED_FEEDLIST'))
1418// $cv["xmsg"] = getFeedArticles($link, $i)." ".__("total");
bdb7369b 1419
6a7817c1 1420 array_push($ret_arr, $cv);
8d505d78 1421 }
0a6e5382
AD
1422
1423 return $ret_arr;
1424 }
1425
11232703 1426 function getLabelCounters($link, $descriptions = false) {
6a7817c1
AD
1427
1428 $ret_arr = array();
0a6e5382 1429
3809b278 1430 $owner_uid = $_SESSION["uid"];
bdb7369b 1431
45942238
AD
1432 $result = db_query($link, "SELECT id,caption,COUNT(unread) AS unread
1433 FROM ttrss_labels2 LEFT JOIN ttrss_user_labels2 ON
1434 (ttrss_labels2.id = label_id)
1435 LEFT JOIN ttrss_user_entries ON (ref_id = article_id AND unread = true)
123a7643
AD
1436 WHERE ttrss_labels2.owner_uid = $owner_uid GROUP BY ttrss_labels2.id,
1437 ttrss_labels2.caption");
8d505d78 1438
3809b278 1439 while ($line = db_fetch_assoc($result)) {
2d24f032 1440
3809b278 1441 $id = -$line["id"] - 11;
e4f4b46f 1442
3809b278 1443 $label_name = $line["caption"];
45942238 1444 $count = $line["unread"];
3809b278 1445
6a7817c1 1446 $cv = array("id" => $id,
12e6de72 1447 "counter" => (int) $count);
11232703
AD
1448
1449 if ($descriptions)
1450 $cv["description"] = $label_name;
a9cb1f83 1451
296c8134
AD
1452// if (get_pref($link, 'EXTENDED_FEEDLIST'))
1453// $cv["xmsg"] = getFeedArticles($link, $id)." ".__("total");
ef393de7 1454
6a7817c1 1455 array_push($ret_arr, $cv);
3809b278 1456 }
8d505d78 1457
ef393de7 1458 return $ret_arr;
a9cb1f83
AD
1459 }
1460
3809b278 1461 function getFeedCounters($link, $active_feed = false) {
a9cb1f83 1462
6a7817c1
AD
1463 $ret_arr = array();
1464
8a4c759e
AD
1465 $query = "SELECT ttrss_feeds.id,
1466 ttrss_feeds.title,
8d505d78 1467 ".SUBSTRING_FOR_DATE."(ttrss_feeds.last_updated,1,19) AS last_updated,
de0a2122
AD
1468 last_error, value AS count
1469 FROM ttrss_feeds, ttrss_counters_cache
8d505d78 1470 WHERE ttrss_feeds.owner_uid = ".$_SESSION["uid"]."
fc9de939 1471 AND ttrss_counters_cache.owner_uid = ttrss_feeds.owner_uid
55e01d7e 1472 AND ttrss_counters_cache.feed_id = id";
a9cb1f83 1473
14073c0a 1474 $result = db_query($link, $query);
a9cb1f83
AD
1475 $fctrs_modified = false;
1476
1477 while ($line = db_fetch_assoc($result)) {
8d505d78 1478
a9cb1f83 1479 $id = $line["id"];
de0a2122 1480 $count = $line["count"];
a9cb1f83 1481 $last_error = htmlspecialchars($line["last_error"]);
fb1fb4ab 1482
324944f3 1483 $last_updated = make_local_datetime($link, $line['last_updated'], false);
fb1fb4ab 1484
7defa089 1485 $has_img = feed_has_icon($id);
a9cb1f83 1486
428b704d
AD
1487 if (date('Y') - date('Y', strtotime($line['last_updated'])) > 2)
1488 $last_updated = '';
1489
6a7817c1 1490 $cv = array("id" => $id,
21884958 1491 "updated" => $last_updated,
12e6de72 1492 "counter" => (int) $count,
6a7817c1 1493 "has_img" => (int) $has_img);
a9cb1f83 1494
6a7817c1
AD
1495 if ($last_error)
1496 $cv["error"] = $last_error;
4ffa126e 1497
296c8134
AD
1498// if (get_pref($link, 'EXTENDED_FEEDLIST'))
1499// $cv["xmsg"] = getFeedArticles($link, $id)." ".__("total");
bdb7369b 1500
6a7817c1 1501 if ($active_feed && $id == $active_feed)
fbc95c5b 1502 $cv["title"] = truncate_string($line["title"], 30);
6a7817c1
AD
1503
1504 array_push($ret_arr, $cv);
a9cb1f83 1505
a9cb1f83 1506 }
6a7817c1
AD
1507
1508 return $ret_arr;
a9cb1f83
AD
1509 }
1510
6e7f8d26
AD
1511 function get_pgsql_version($link) {
1512 $result = db_query($link, "SELECT version() AS version");
9949bd15 1513 $version = explode(" ", db_fetch_result($result, 0, "version"));
6e7f8d26
AD
1514 return $version[1];
1515 }
1516
2b8290cd 1517 /**
23d2471c
AD
1518 * @return array (code => Status code, message => error message if available)
1519 *
2b8290cd
CW
1520 * 0 - OK, Feed already exists
1521 * 1 - OK, Feed added
1522 * 2 - Invalid URL
9a8ce956
CW
1523 * 3 - URL content is HTML, no feeds available
1524 * 4 - URL content is HTML which contains multiple feeds.
1525 * Here you should call extractfeedurls in rpc-backend
1526 * to get all possible feeds.
5414ad4c 1527 * 5 - Couldn't download the URL content.
2b8290cd 1528 */
8d505d78 1529 function subscribe_to_feed($link, $url, $cat_id = 0,
aa60999b 1530 $auth_login = '', $auth_pass = '', $need_auth = false) {
bb0f29a4 1531
23d2471c
AD
1532 global $fetch_last_error;
1533
2c08214a
AD
1534 require_once "include/rssfuncs.php";
1535
f0266f51 1536 $url = fix_url($url);
ec39a02c 1537
23d2471c 1538 if (!$url || !validate_feed_url($url)) return array("code" => 2);
a5819bb3 1539
759e5132
AD
1540 $contents = @fetch_file_contents($url, false, $auth_login, $auth_pass);
1541
1542 if (!$contents) {
304aadb9 1543 return array("code" => 5, "message" => $fetch_last_error);
759e5132
AD
1544 }
1545
1546 if (is_html($contents)) {
1547 $feedUrls = get_feeds_from_html($url, $contents);
304aadb9 1548
304aadb9
AD
1549 if (count($feedUrls) == 0) {
1550 return array("code" => 3);
1551 } else if (count($feedUrls) > 1) {
759e5132 1552 return array("code" => 4, "feeds" => $feedUrls);
f6d8345b 1553 }
304aadb9
AD
1554 //use feed url as new URL
1555 $url = key($feedUrls);
1556 }
f6d8345b 1557
956c7629
AD
1558 if ($cat_id == "0" || !$cat_id) {
1559 $cat_qpart = "NULL";
1560 } else {
1561 $cat_qpart = "'$cat_id'";
1562 }
8d505d78 1563
956c7629 1564 $result = db_query($link,
8d505d78 1565 "SELECT id FROM ttrss_feeds
a5819bb3 1566 WHERE feed_url = '$url' AND owner_uid = ".$_SESSION["uid"]);
8d505d78 1567
956c7629 1568 if (db_num_rows($result) == 0) {
956c7629 1569 $result = db_query($link,
8d505d78
AD
1570 "INSERT INTO ttrss_feeds
1571 (owner_uid,feed_url,title,cat_id, auth_login,auth_pass,update_method)
1572 VALUES ('".$_SESSION["uid"]."', '$url',
19b3992b 1573 '[Unknown]', $cat_qpart, '$auth_login', '$auth_pass', 0)");
8d505d78 1574
956c7629 1575 $result = db_query($link,
8d505d78 1576 "SELECT id FROM ttrss_feeds WHERE feed_url = '$url'
f27de515 1577 AND owner_uid = " . $_SESSION["uid"]);
8d505d78 1578
956c7629 1579 $feed_id = db_fetch_result($result, 0, "id");
8d505d78 1580
956c7629 1581 if ($feed_id) {
c633e370 1582 update_rss_feed($link, $feed_id, true);
956c7629
AD
1583 }
1584
23d2471c 1585 return array("code" => 1);
956c7629 1586 } else {
23d2471c 1587 return array("code" => 0);
956c7629
AD
1588 }
1589 }
1590
8d505d78 1591 function print_feed_select($link, $id, $default_id = "",
4c9d0490
AD
1592 $attributes = "", $include_all_feeds = true,
1593 $root_id = false, $nest_level = 0) {
1594
1595 if (!$root_id) {
1596 print "<select id=\"$id\" name=\"$id\" $attributes>";
1597 if ($include_all_feeds) {
1598 $is_selected = ("0" == $default_id) ? "selected=\"1\"" : "";
1599 print "<option $is_selected value=\"0\">".__('All feeds')."</option>";
1600 }
673d54ca 1601 }
8d505d78 1602
4c9d0490 1603 if (get_pref($link, 'ENABLE_FEED_CATS')) {
673d54ca 1604
4c9d0490
AD
1605 if ($root_id)
1606 $parent_qpart = "parent_cat = '$root_id'";
1607 else
1608 $parent_qpart = "parent_cat IS NULL";
673d54ca 1609
4c9d0490
AD
1610 $result = db_query($link, "SELECT id,title,
1611 (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE
1612 c2.parent_cat = ttrss_feed_categories.id) AS num_children
1613 FROM ttrss_feed_categories
1614 WHERE owner_uid = ".$_SESSION["uid"]." AND $parent_qpart ORDER BY title");
1615
1616 while ($line = db_fetch_assoc($result)) {
1617
1618 for ($i = 0; $i < $nest_level; $i++)
1619 $line["title"] = " - " . $line["title"];
1620
1621 $is_selected = ("CAT:".$line["id"] == $default_id) ? "selected=\"1\"" : "";
1622
1623 printf("<option $is_selected value='CAT:%d'>%s</option>",
1624 $line["id"], htmlspecialchars($line["title"]));
1625
1626 if ($line["num_children"] > 0)
1627 print_feed_select($link, $id, $default_id, $attributes,
1628 $include_all_feeds, $line["id"], $nest_level+1);
1629
1630 $feed_result = db_query($link, "SELECT id,title FROM ttrss_feeds
1631 WHERE cat_id = '".$line["id"]."' AND owner_uid = ".$_SESSION["uid"] . " ORDER BY title");
1632
1633 while ($fline = db_fetch_assoc($feed_result)) {
1634 $is_selected = ($fline["id"] == $default_id) ? "selected=\"1\"" : "";
1635
1636 $fline["title"] = " + " . $fline["title"];
1637
1638 for ($i = 0; $i < $nest_level; $i++)
1639 $fline["title"] = " - " . $fline["title"];
1640
1641 printf("<option $is_selected value='%d'>%s</option>",
1642 $fline["id"], htmlspecialchars($fline["title"]));
1643 }
673d54ca 1644 }
b1710666 1645
4c9d0490
AD
1646 if (!$root_id) {
1647 $is_selected = ($default_id == "CAT:0") ? "selected=\"1\"" : "";
1648
1649 printf("<option $is_selected value='CAT:0'>%s</option>",
1650 __("Uncategorized"));
1651
1652 $feed_result = db_query($link, "SELECT id,title FROM ttrss_feeds
1653 WHERE cat_id IS NULL AND owner_uid = ".$_SESSION["uid"] . " ORDER BY title");
1654
1655 while ($fline = db_fetch_assoc($feed_result)) {
1656 $is_selected = ($fline["id"] == $default_id && !$default_is_cat) ? "selected=\"1\"" : "";
1657
1658 $fline["title"] = " + " . $fline["title"];
1659
1660 for ($i = 0; $i < $nest_level; $i++)
1661 $fline["title"] = " - " . $fline["title"];
1662
1663 printf("<option $is_selected value='%d'>%s</option>",
1664 $fline["id"], htmlspecialchars($fline["title"]));
1665 }
1666 }
b1710666 1667
4c9d0490
AD
1668 } else {
1669 $result = db_query($link, "SELECT id,title FROM ttrss_feeds
1670 WHERE owner_uid = ".$_SESSION["uid"]." ORDER BY title");
1671
1672 while ($line = db_fetch_assoc($result)) {
1673
1674 $is_selected = ($line["id"] == $default_id) ? "selected=\"1\"" : "";
1675
1676 printf("<option $is_selected value='%d'>%s</option>",
1677 $line["id"], htmlspecialchars($line["title"]));
1678 }
673d54ca 1679 }
8d505d78 1680
4c9d0490
AD
1681 if (!$root_id) {
1682 print "</select>";
1683 }
673d54ca
AD
1684 }
1685
fbf85cf6
AD
1686 function print_feed_cat_select($link, $id, $default_id,
1687 $attributes, $include_all_cats = true, $root_id = false, $nest_level = 0) {
8d505d78 1688
fbf85cf6
AD
1689 if (!$root_id) {
1690 print "<select id=\"$id\" name=\"$id\" default=\"$default_id\" onchange=\"catSelectOnChange(this)\" $attributes>";
1691 }
673d54ca 1692
fbf85cf6
AD
1693 if ($root_id)
1694 $parent_qpart = "parent_cat = '$root_id'";
1695 else
1696 $parent_qpart = "parent_cat IS NULL";
673d54ca 1697
fbf85cf6
AD
1698 $result = db_query($link, "SELECT id,title,
1699 (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE
1700 c2.parent_cat = ttrss_feed_categories.id) AS num_children
1701 FROM ttrss_feed_categories
1702 WHERE owner_uid = ".$_SESSION["uid"]." AND $parent_qpart ORDER BY title");
673d54ca 1703
fbf85cf6
AD
1704 while ($line = db_fetch_assoc($result)) {
1705 if ($line["id"] == $default_id) {
1706 $is_selected = "selected=\"1\"";
1707 } else {
1708 $is_selected = "";
1709 }
673d54ca 1710
fbf85cf6
AD
1711 for ($i = 0; $i < $nest_level; $i++)
1712 $line["title"] = " - " . $line["title"];
c00907f2 1713
fbf85cf6
AD
1714 if ($line["title"])
1715 printf("<option $is_selected value='%d'>%s</option>",
1716 $line["id"], htmlspecialchars($line["title"]));
673d54ca 1717
fbf85cf6
AD
1718 if ($line["num_children"] > 0)
1719 print_feed_cat_select($link, $id, $default_id, $attributes,
1720 $include_all_cats, $line["id"], $nest_level+1);
1721 }
5c7c7da9 1722
fbf85cf6
AD
1723 if (!$root_id) {
1724 if ($include_all_cats) {
1725 if (db_num_rows($result) > 0) {
1726 print "<option disabled=\"1\">--------</option>";
1727 }
7e18f8e7
AD
1728
1729 if ($default_id == 0) {
1730 $is_selected = "selected=\"1\"";
1731 } else {
1732 $is_selected = "";
1733 }
1734
1735 print "<option $is_selected value=\"0\">".__('Uncategorized')."</option>";
fbf85cf6
AD
1736 }
1737 print "</select>";
1738 }
1739 }
8d505d78 1740
14f69488
AD
1741 function checkbox_to_sql_bool($val) {
1742 return ($val == "on") ? "true" : "false";
1743 }
86b682ce
AD
1744
1745 function getFeedCatTitle($link, $id) {
1746 if ($id == -1) {
d1db26aa 1747 return __("Special");
86b682ce 1748 } else if ($id < -10) {
d1db26aa 1749 return __("Labels");
86b682ce 1750 } else if ($id > 0) {
8d505d78 1751 $result = db_query($link, "SELECT ttrss_feed_categories.title
86b682ce
AD
1752 FROM ttrss_feeds, ttrss_feed_categories WHERE ttrss_feeds.id = '$id' AND
1753 cat_id = ttrss_feed_categories.id");
1754 if (db_num_rows($result) == 1) {
1755 return db_fetch_result($result, 0, "title");
1756 } else {
d1db26aa 1757 return __("Uncategorized");
86b682ce
AD
1758 }
1759 } else {
1760 return "getFeedCatTitle($id) failed";
1761 }
1762
1763 }
1764
9299102f 1765 function getFeedIcon($id) {
af88c48a 1766 switch ($id) {
4bee8b5f
AD
1767 case 0:
1768 return "images/archive.png";
1769 break;
af88c48a 1770 case -1:
c2167866 1771 return "images/mark_set.svg";
af88c48a
AD
1772 break;
1773 case -2:
c2167866 1774 return "images/pub_set.svg";
af88c48a
AD
1775 break;
1776 case -3:
1777 return "images/fresh.png";
1778 break;
1779 case -4:
1780 return "images/tag.png";
1781 break;
5417fbd7
AD
1782 case -6:
1783 return "images/recently_read.png";
1784 break;
af88c48a 1785 default:
4bee8b5f
AD
1786 if ($id < -10) {
1787 return "images/label.png";
1788 } else {
8d505d78 1789 if (file_exists(ICONS_DIR . "/$id.ico"))
e2eda979 1790 return ICONS_URL . "/$id.ico";
4bee8b5f 1791 }
af88c48a
AD
1792 break;
1793 }
1794 }
1795
fd994f1a
AD
1796 function getFeedTitle($link, $id, $cat = false) {
1797 if ($cat) {
8add44ec 1798 return getCategoryTitle($link, $id);
fd994f1a 1799 } else if ($id == -1) {
d1db26aa 1800 return __("Starred articles");
945c243e
AD
1801 } else if ($id == -2) {
1802 return __("Published articles");
2d24f032
AD
1803 } else if ($id == -3) {
1804 return __("Fresh articles");
b2531a28
AD
1805 } else if ($id == -4) {
1806 return __("All articles");
80db1113 1807 } else if ($id === 0 || $id === "0") {
e04c18a2 1808 return __("Archived articles");
5417fbd7
AD
1809 } else if ($id == -6) {
1810 return __("Recently read");
86b682ce 1811 } else if ($id < -10) {
76626c72 1812 $label_id = -$id - 11;
ceb30ba4 1813 $result = db_query($link, "SELECT caption FROM ttrss_labels2 WHERE id = '$label_id'");
86b682ce 1814 if (db_num_rows($result) == 1) {
ceb30ba4 1815 return db_fetch_result($result, 0, "caption");
86b682ce
AD
1816 } else {
1817 return "Unknown label ($label_id)";
1818 }
1819
147f5632 1820 } else if (is_numeric($id) && $id > 0) {
86b682ce
AD
1821 $result = db_query($link, "SELECT title FROM ttrss_feeds WHERE id = '$id'");
1822 if (db_num_rows($result) == 1) {
1823 return db_fetch_result($result, 0, "title");
1824 } else {
1825 return "Unknown feed ($id)";
1826 }
1827 } else {
22fdebff 1828 return $id;
86b682ce 1829 }
86b682ce 1830 }
3dd46f19 1831
d8221301 1832 function make_init_params($link) {
f1f3a642 1833 $params = array();
c9268ed5 1834
2a3b6de0
J
1835 $params["sign_progress"] = "images/indicator_white.gif";
1836 $params["sign_progress_tiny"] = "images/indicator_tiny.gif";
1837 $params["sign_excl"] = "images/sign_excl.svg";
1838 $params["sign_info"] = "images/sign_info.svg";
be0801a1 1839
f1f3a642
AD
1840 foreach (array("ON_CATCHUP_SHOW_NEXT_FEED", "HIDE_READ_FEEDS",
1841 "ENABLE_FEED_CATS", "FEEDS_SORT_BY_UNREAD", "CONFIRM_FEED_CATCHUP",
7d12b6c8 1842 "CDM_AUTO_CATCHUP", "FRESH_ARTICLE_MAX_AGE", "DEFAULT_ARTICLE_LIMIT",
30b6ee8c 1843 "HIDE_READ_SHOWS_SPECIAL", "COMBINED_DISPLAY_MODE") as $param) {
40496720 1844
c4f7ba80 1845 $params[strtolower($param)] = (int) get_pref($link, $param);
f1f3a642 1846 }
40496720 1847
c4f7ba80
AD
1848 $params["icons_url"] = ICONS_URL;
1849 $params["cookie_lifetime"] = SESSION_COOKIE_LIFETIME;
1850 $params["default_view_mode"] = get_pref($link, "_DEFAULT_VIEW_MODE");
1851 $params["default_view_limit"] = (int) get_pref($link, "_DEFAULT_VIEW_LIMIT");
1852 $params["default_view_order_by"] = get_pref($link, "_DEFAULT_VIEW_ORDER_BY");
c4f7ba80 1853 $params["bw_limit"] = (int) $_SESSION["bw_limit"];
59b223d7 1854
8cd576a1 1855 $result = db_query($link, "SELECT MAX(id) AS mid, COUNT(*) AS nf FROM
9b7ecc0a
AD
1856 ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]);
1857
8cd576a1
AD
1858 $max_feed_id = db_fetch_result($result, 0, "mid");
1859 $num_feeds = db_fetch_result($result, 0, "nf");
9b7ecc0a 1860
8cd576a1 1861 $params["max_feed_id"] = (int) $max_feed_id;
c4f7ba80 1862 $params["num_feeds"] = (int) $num_feeds;
8cd576a1 1863
c4f7ba80 1864 $params["collapsed_feedlist"] = (int) get_pref($link, "_COLLAPSED_FEEDLIST");
b8cb4d08 1865 $params["hotkeys"] = get_hotkeys_map($link);
9b7ecc0a 1866
8484ce22 1867 $params["csrf_token"] = $_SESSION["csrf_token"];
f03701fe 1868 $params["widescreen"] = (int) $_COOKIE["ttrss_widescreen"];
8484ce22 1869
6b1a4ecd 1870 $params['simple_update'] = defined('SIMPLE_UPDATE_MODE') && SIMPLE_UPDATE_MODE;
8b83bf5f 1871
d8221301 1872 return $params;
3ac2b520 1873 }
f54f515f 1874
b8cb4d08
AD
1875 function get_hotkeys_info($link) {
1876 $hotkeys = array(
1877 __("Navigation") => array(
1878 "next_feed" => __("Open next feed"),
1879 "prev_feed" => __("Open previous feed"),
1880 "next_article" => __("Open next article"),
1881 "prev_article" => __("Open previous article"),
c22580b5
AD
1882 "next_article_noscroll" => __("Open next article (don't scroll long articles)"),
1883 "prev_article_noscroll" => __("Open previous article (don't scroll long articles)"),
b8cb4d08
AD
1884 "search_dialog" => __("Show search dialog")),
1885 __("Article") => array(
1886 "toggle_mark" => __("Toggle starred"),
1887 "toggle_publ" => __("Toggle published"),
1888 "toggle_unread" => __("Toggle unread"),
1889 "edit_tags" => __("Edit tags"),
1890 "dismiss_selected" => __("Dismiss selected"),
1891 "dismiss_read" => __("Dismiss read"),
1892 "open_in_new_window" => __("Open in new window"),
1893 "catchup_below" => __("Mark below as read"),
1894 "catchup_above" => __("Mark above as read"),
1895 "article_scroll_down" => __("Scroll down"),
1896 "article_scroll_up" => __("Scroll up"),
1897 "select_article_cursor" => __("Select article under cursor"),
1bcf8f45 1898 "email_article" => __("Email article"),
414191d4 1899 "close_article" => __("Close/collapse article"),
1bcf8f45 1900 "toggle_widescreen" => __("Toggle widescreen mode")),
b8cb4d08
AD
1901 __("Article selection") => array(
1902 "select_all" => __("Select all articles"),
1903 "select_unread" => __("Select unread"),
1904 "select_marked" => __("Select starred"),
1905 "select_published" => __("Select published"),
1906 "select_invert" => __("Invert selection"),
1907 "select_none" => __("Deselect everything")),
1908 __("Feed") => array(
1909 "feed_refresh" => __("Refresh current feed"),
1910 "feed_unhide_read" => __("Un/hide read feeds"),
1911 "feed_subscribe" => __("Subscribe to feed"),
1912 "feed_edit" => __("Edit feed"),
1913 "feed_catchup" => __("Mark as read"),
1914 "feed_reverse" => __("Reverse headlines"),
43f775de 1915 "feed_debug_update" => __("Debug feed update"),
b8cb4d08 1916 "catchup_all" => __("Mark all feeds as read"),
4b27f0c0
AD
1917 "cat_toggle_collapse" => __("Un/collapse current category"),
1918 "toggle_combined_mode" => __("Toggle combined mode")),
b8cb4d08
AD
1919 __("Go to") => array(
1920 "goto_all" => __("All articles"),
1921 "goto_fresh" => __("Fresh"),
1922 "goto_marked" => __("Starred"),
1923 "goto_published" => __("Published"),
1924 "goto_tagcloud" => __("Tag cloud"),
1925 "goto_prefs" => __("Preferences")),
1926 __("Other") => array(
1927 "create_label" => __("Create label"),
1928 "create_filter" => __("Create filter"),
1929 "collapse_sidebar" => __("Un/collapse sidebar"),
1930 "help_dialog" => __("Show help dialog"))
1931 );
1932
1933 return $hotkeys;
1934 }
1935
1936 function get_hotkeys_map($link) {
a83b58f1 1937 $hotkeys = array(
e218c5f5
AD
1938// "navigation" => array(
1939 "k" => "next_feed",
1940 "j" => "prev_feed",
1941 "n" => "next_article",
1942 "p" => "prev_article",
e5e2cf3b
AD
1943 "(38)|up" => "prev_article",
1944 "(40)|down" => "next_article",
da15c140
AD
1945// "^(38)|Ctrl-up" => "prev_article_noscroll",
1946// "^(40)|Ctrl-down" => "next_article_noscroll",
e5e2cf3b 1947 "(191)|/" => "search_dialog",
e218c5f5
AD
1948// "article" => array(
1949 "s" => "toggle_mark",
5b18c936 1950 "*s" => "toggle_publ",
e218c5f5 1951 "u" => "toggle_unread",
5b18c936
AD
1952 "*t" => "edit_tags",
1953 "*d" => "dismiss_selected",
1954 "*x" => "dismiss_read",
e218c5f5
AD
1955 "o" => "open_in_new_window",
1956 "c p" => "catchup_below",
1957 "c n" => "catchup_above",
5b18c936
AD
1958 "*n" => "article_scroll_down",
1959 "*p" => "article_scroll_up",
d2db81a5
AD
1960 "*(38)|Shift+up" => "article_scroll_up",
1961 "*(40)|Shift+down" => "article_scroll_down",
5b18c936 1962 "a *w" => "toggle_widescreen",
e218c5f5 1963 "e" => "email_article",
2cda4314 1964 "a q" => "close_article",
e218c5f5
AD
1965// "article_selection" => array(
1966 "a a" => "select_all",
1967 "a u" => "select_unread",
5b18c936 1968 "a *u" => "select_marked",
e218c5f5
AD
1969 "a p" => "select_published",
1970 "a i" => "select_invert",
1971 "a n" => "select_none",
1972// "feed" => array(
1973 "f r" => "feed_refresh",
1974 "f a" => "feed_unhide_read",
1975 "f s" => "feed_subscribe",
1976 "f e" => "feed_edit",
1977 "f q" => "feed_catchup",
1978 "f x" => "feed_reverse",
5b18c936
AD
1979 "f *d" => "feed_debug_update",
1980 "f *c" => "toggle_combined_mode",
1981 "*q" => "catchup_all",
e218c5f5
AD
1982 "x" => "cat_toggle_collapse",
1983// "goto" => array(
1984 "g a" => "goto_all",
1985 "g f" => "goto_fresh",
1986 "g s" => "goto_marked",
1987 "g p" => "goto_published",
1988 "g t" => "goto_tagcloud",
5b18c936 1989 "g *p" => "goto_prefs",
e218c5f5 1990// "other" => array(
3fb40112 1991 "(9)|Tab" => "select_article_cursor", // tab
e218c5f5
AD
1992 "c l" => "create_label",
1993 "c f" => "create_filter",
1994 "c s" => "collapse_sidebar",
3fb40112 1995 "^(191)|Ctrl+/" => "help_dialog",
a83b58f1
AD
1996 );
1997
da15c140
AD
1998 if (get_pref($link, 'COMBINED_DISPLAY_MODE')) {
1999 $hotkeys["^(38)|Ctrl-up"] = "prev_article_noscroll";
2000 $hotkeys["^(40)|Ctrl-down"] = "next_article_noscroll";
2001 }
2002
e218c5f5
AD
2003 global $pluginhost;
2004 foreach ($pluginhost->get_hooks($pluginhost::HOOK_HOTKEY_MAP) as $plugin) {
2005 $hotkeys = $plugin->hook_hotkey_map($hotkeys);
2006 }
2007
2008 $prefixes = array();
2009
2010 foreach (array_keys($hotkeys) as $hotkey) {
2011 $pair = explode(" ", $hotkey, 2);
2012
2013 if (count($pair) > 1 && !in_array($pair[0], $prefixes)) {
2014 array_push($prefixes, $pair[0]);
2015 }
2016 }
2017
2018 return array($prefixes, $hotkeys);
a83b58f1
AD
2019 }
2020
c4f7ba80 2021 function make_runtime_info($link) {
8cd576a1
AD
2022 $data = array();
2023
2024 $result = db_query($link, "SELECT MAX(id) AS mid, COUNT(*) AS nf FROM
9b7ecc0a
AD
2025 ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"]);
2026
8cd576a1
AD
2027 $max_feed_id = db_fetch_result($result, 0, "mid");
2028 $num_feeds = db_fetch_result($result, 0, "nf");
9b7ecc0a 2029
8cd576a1
AD
2030 $data["max_feed_id"] = (int) $max_feed_id;
2031 $data["num_feeds"] = (int) $num_feeds;
c4f7ba80 2032
f8fb4498 2033 $data['last_article_id'] = getLastArticleId($link);
5ae8f858 2034 $data['cdm_expanded'] = get_pref($link, 'CDM_EXPANDED');
f8fb4498 2035
dbaa4e4a 2036 if (file_exists(LOCK_DIRECTORY . "/update_daemon.lock")) {
c4f7ba80
AD
2037
2038 $data['daemon_is_running'] = (int) file_is_locked("update_daemon.lock");
8e00ae9b 2039
9041f58b 2040 if (time() - $_SESSION["daemon_stamp_check"] > 30) {
8e00ae9b 2041
fb074239 2042 $stamp = (int) @file_get_contents(LOCK_DIRECTORY . "/update_daemon.stamp");
fbae93d8 2043
8e00ae9b 2044 if ($stamp) {
9041f58b
AD
2045 $stamp_delta = time() - $stamp;
2046
2047 if ($stamp_delta > 1800) {
f6854e44 2048 $stamp_check = 0;
8e00ae9b 2049 } else {
f6854e44
AD
2050 $stamp_check = 1;
2051 $_SESSION["daemon_stamp_check"] = time();
8e00ae9b
AD
2052 }
2053
c4f7ba80 2054 $data['daemon_stamp_ok'] = $stamp_check;
f6854e44 2055
8e00ae9b
AD
2056 $stamp_fmt = date("Y.m.d, G:i", $stamp);
2057
c4f7ba80 2058 $data['daemon_stamp'] = $stamp_fmt;
8e00ae9b 2059 }
8e00ae9b 2060 }
71ad883b 2061 }
8e00ae9b 2062
63855db1 2063 if ($_SESSION["last_version_check"] + 86400 + rand(-1000, 1000) < time()) {
fb074239 2064 $new_version_details = @check_for_update($link);
d9fa39f1 2065
63855db1 2066 $data['new_version_available'] = (int) ($new_version_details != false);
d9fa39f1
AD
2067
2068 $_SESSION["last_version_check"] = time();
27211afe 2069 $_SESSION["version_data"] = $new_version_details;
d9fa39f1
AD
2070 }
2071
c4f7ba80 2072 return $data;
f54f515f 2073 }
ef393de7 2074
ca5d9be4 2075 function search_to_sql($link, $search) {
ef393de7 2076
88040f57 2077 $search_query_part = "";
e20c9d88 2078
9949bd15 2079 $keywords = explode(" ", $search);
88040f57 2080 $query_keywords = array();
e20c9d88 2081
ab4b768f
AD
2082 foreach ($keywords as $k) {
2083 if (strpos($k, "-") === 0) {
2084 $k = substr($k, 1);
2085 $not = "NOT";
2086 } else {
2087 $not = "";
88040f57 2088 }
e20c9d88 2089
9949bd15 2090 $commandpair = explode(":", mb_strtolower($k), 2);
53003548
AD
2091
2092 if ($commandpair[0] == "note" && $commandpair[1]) {
2093
2094 if ($commandpair[1] == "true")
2095 array_push($query_keywords, "($not (note IS NOT NULL AND note != ''))");
2096 else
2097 array_push($query_keywords, "($not (note IS NULL OR note = ''))");
2098
2099 } else if ($commandpair[0] == "star" && $commandpair[1]) {
2100
2101 if ($commandpair[1] == "true")
2102 array_push($query_keywords, "($not (marked = true))");
2103 else
2104 array_push($query_keywords, "($not (marked = false))");
2105
2106 } else if ($commandpair[0] == "pub" && $commandpair[1]) {
2107
2108 if ($commandpair[1] == "true")
2109 array_push($query_keywords, "($not (published = true))");
2110 else
2111 array_push($query_keywords, "($not (published = false))");
2112
2113 } else if (strpos($k, "@") === 0) {
e20c9d88 2114
ab4b768f
AD
2115 $user_tz_string = get_pref($link, 'USER_TIMEZONE', $_SESSION['uid']);
2116 $orig_ts = strtotime(substr($k, 1));
ab4b768f 2117 $k = date("Y-m-d", convert_timestamp($orig_ts, $user_tz_string, 'UTC'));
8d505d78 2118
53003548
AD
2119 //$k = date("Y-m-d", strtotime(substr($k, 1)));
2120
ab4b768f 2121 array_push($query_keywords, "(".SUBSTRING_FOR_DATE."(updated,1,LENGTH('$k')) $not = '$k')");
ca5d9be4 2122 } else {
ab4b768f
AD
2123 array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%')
2124 OR UPPER(ttrss_entries.content) $not LIKE UPPER('%$k%'))");
88040f57
AD
2125 }
2126 }
2127
2128 $search_query_part = implode("AND", $query_keywords);
2129
2130 return $search_query_part;
2131 }
2132
67bd0b1f
AD
2133 function getParentCategories($link, $cat, $owner_uid) {
2134 $rv = array();
2135
2136 $result = db_query($link, "SELECT parent_cat FROM ttrss_feed_categories
2137 WHERE id = '$cat' AND parent_cat IS NOT NULL AND owner_uid = $owner_uid");
2138
2139 while ($line = db_fetch_assoc($result)) {
2140 array_push($rv, $line["parent_cat"]);
2141 $rv = array_merge($rv, getParentCategories($link, $line["parent_cat"], $owner_uid));
2142 }
2143
2144 return $rv;
2145 }
2146
6d8d00e8
AD
2147 function getChildCategories($link, $cat, $owner_uid) {
2148 $rv = array();
2149
2150 $result = db_query($link, "SELECT id FROM ttrss_feed_categories
2151 WHERE parent_cat = '$cat' AND owner_uid = $owner_uid");
2152
2153 while ($line = db_fetch_assoc($result)) {
2154 array_push($rv, $line["id"]);
2155 $rv = array_merge($rv, getChildCategories($link, $line["id"], $owner_uid));
2156 }
2157
2158 return $rv;
2159 }
147f5632 2160
ca5d9be4 2161 function queryFeedHeadlines($link, $feed, $limit, $view_mode, $cat_view, $search, $search_mode, $override_order = false, $offset = 0, $owner_uid = 0, $filter = false, $since_id = 0, $include_children = false, $ignore_vfeed_group = false) {
c36bf4d5
AD
2162
2163 if (!$owner_uid) $owner_uid = $_SESSION["uid"];
c1a0b534 2164
c3fddd05
AD
2165 $ext_tables_part = "";
2166
88040f57 2167 if ($search) {
e4f7f8df
AD
2168
2169 if (SPHINX_ENABLED) {
2170 $ids = join(",", @sphinx_search($search, 0, 500));
2171
8d505d78 2172 if ($ids)
e4f7f8df
AD
2173 $search_query_part = "ref_id IN ($ids) AND ";
2174 else
2175 $search_query_part = "ref_id = -1 AND ";
2176
2177 } else {
ca5d9be4 2178 $search_query_part = search_to_sql($link, $search);
e4f7f8df 2179 $search_query_part .= " AND ";
8d505d78 2180 }
e20c9d88 2181
ef393de7
AD
2182 } else {
2183 $search_query_part = "";
2184 }
2185
36184020 2186 if ($filter) {
4e02f582
AD
2187
2188 if (DB_TYPE == "pgsql") {
2189 $query_strategy_part .= " AND updated > NOW() - INTERVAL '14 days' ";
2190 } else {
2191 $query_strategy_part .= " AND updated > DATE_SUB(NOW(), INTERVAL 14 DAY) ";
2192 }
2193
2194 $override_order = "updated DESC";
2195
2680295b 2196 $filter_query_part = filter_to_sql($link, $filter, $owner_uid);
dd8c36af
AD
2197
2198 // Try to check if SQL regexp implementation chokes on a valid regexp
809c8e62 2199 $result = db_query($link, "SELECT true AS true_val FROM ttrss_entries,
2680295b 2200 ttrss_user_entries, ttrss_feeds, ttrss_feed_categories
dd8c36af
AD
2201 WHERE $filter_query_part LIMIT 1", false);
2202
7726063c
AD
2203 if ($result) {
2204 $test = db_fetch_result($result, 0, "true_val");
dd8c36af 2205
7726063c
AD
2206 if (!$test) {
2207 $filter_query_part = "false AND";
2208 } else {
2209 $filter_query_part .= " AND";
2210 }
dd8c36af 2211 } else {
7726063c 2212 $filter_query_part = "false AND";
dd8c36af
AD
2213 }
2214
36184020
AD
2215 } else {
2216 $filter_query_part = "";
2217 }
2218
97e5dbb2
AD
2219 if ($since_id) {
2220 $since_id_part = "ttrss_entries.id > $since_id AND ";
2221 } else {
2222 $since_id_part = "";
2223 }
2224
ef393de7 2225 $view_query_part = "";
8d505d78 2226
7b4d02a8 2227 if ($view_mode == "adaptive" || $view_query_part == "noscores") {
ef393de7
AD
2228 if ($search) {
2229 $view_query_part = " ";
2230 } else if ($feed != -1) {
f295c368 2231 $unread = getFeedUnread($link, $feed, $cat_view);
6d8d00e8 2232
09101297 2233 if ($cat_view && $feed > 0 && $include_children)
99c9e91a 2234 $unread += getCategoryChildrenUnread($link, $feed);
6d8d00e8 2235
ef393de7 2236 if ($unread > 0) {
ff863e00 2237 $view_query_part = " unread = true AND ";
ef393de7
AD
2238 }
2239 }
2240 }
8d505d78 2241
ef393de7
AD
2242 if ($view_mode == "marked") {
2243 $view_query_part = " marked = true AND ";
2244 }
23d72f39
AD
2245
2246 if ($view_mode == "published") {
2247 $view_query_part = " published = true AND ";
2248 }
2249
ef393de7
AD
2250 if ($view_mode == "unread") {
2251 $view_query_part = " unread = true AND ";
2252 }
8b09eac8
AD
2253
2254 if ($view_mode == "updated") {
2255 $view_query_part = " (last_read is null and unread = false) AND ";
2256 }
2257
ef393de7
AD
2258 if ($limit > 0) {
2259 $limit_query_part = "LIMIT " . $limit;
8d505d78 2260 }
ef393de7 2261
8361e724
AD
2262 $allow_archived = false;
2263
ef393de7 2264 $vfeed_query_part = "";
8d505d78 2265
ef393de7
AD
2266 // override query strategy and enable feed display when searching globally
2267 if ($search && $search_mode == "all_feeds") {
7032f2a5 2268 $query_strategy_part = "true";
8d505d78 2269 $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
22fdebff 2270 /* tags */
75c648cf 2271 } else if (!is_numeric($feed)) {
7032f2a5 2272 $query_strategy_part = "true";
ef393de7
AD
2273 $vfeed_query_part = "(SELECT title FROM ttrss_feeds WHERE
2274 id = feed_id) as feed_title,";
7032f2a5 2275 } else if ($search && $search_mode == "this_cat") {
8d505d78 2276 $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
0a6c4846 2277
7032f2a5
AD
2278 if ($feed > 0) {
2279 if ($include_children) {
2280 $subcats = getChildCategories($link, $feed, $owner_uid);
2281 array_push($subcats, $feed);
2282 $cats_qpart = join(",", $subcats);
2283 } else {
2284 $cats_qpart = $feed;
ef393de7 2285 }
8d505d78 2286
7032f2a5 2287 $query_strategy_part = "ttrss_feeds.cat_id IN ($cats_qpart)";
8d505d78 2288
ef393de7 2289 } else {
7032f2a5 2290 $query_strategy_part = "ttrss_feeds.cat_id IS NULL";
ef393de7 2291 }
8d505d78 2292
e04c18a2 2293 } else if ($feed > 0) {
8d505d78 2294
ef393de7 2295 if ($cat_view) {
5c365f60 2296
ef393de7 2297 if ($feed > 0) {
09101297
AD
2298 if ($include_children) {
2299 # sub-cats
2300 $subcats = getChildCategories($link, $feed, $owner_uid);
2301
7032f2a5
AD
2302 array_push($subcats, $feed);
2303 $query_strategy_part = "cat_id IN (".
09101297 2304 implode(",", $subcats).")";
7032f2a5 2305
6d8d00e8 2306 } else {
09101297 2307 $query_strategy_part = "cat_id = '$feed'";
6d8d00e8
AD
2308 }
2309
ef393de7
AD
2310 } else {
2311 $query_strategy_part = "cat_id IS NULL";
2312 }
8d505d78 2313
ef393de7 2314 $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
5c365f60 2315
8d505d78 2316 } else {
6e63a7c3 2317 $query_strategy_part = "feed_id = '$feed'";
ef393de7 2318 }
bfe5ddfc 2319 } else if ($feed == 0 && !$cat_view) { // archive virtual feed
e04c18a2 2320 $query_strategy_part = "feed_id IS NULL";
8361e724 2321 $allow_archived = true;
bfe5ddfc 2322 } else if ($feed == 0 && $cat_view) { // uncategorized
65dd90f2 2323 $query_strategy_part = "cat_id IS NULL AND feed_id IS NOT NULL";
bfe5ddfc 2324 $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
ef393de7
AD
2325 } else if ($feed == -1) { // starred virtual feed
2326 $query_strategy_part = "marked = true";
2327 $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
835fb294
AD
2328 $allow_archived = true;
2329
7873d588
AD
2330 if (!$override_order) $override_order = "last_marked DESC, updated DESC";
2331
e6a38cde
AD
2332 } else if ($feed == -2) { // published virtual feed OR labels category
2333
2334 if (!$cat_view) {
2335 $query_strategy_part = "published = true";
2336 $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
8361e724 2337 $allow_archived = true;
46b78149 2338
7873d588 2339 if (!$override_order) $override_order = "last_published DESC, updated DESC";
e6a38cde
AD
2340 } else {
2341 $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
2342
2343 $ext_tables_part = ",ttrss_labels2,ttrss_user_labels2";
8d505d78 2344
e6a38cde
AD
2345 $query_strategy_part = "ttrss_labels2.id = ttrss_user_labels2.label_id AND
2346 ttrss_user_labels2.article_id = ref_id";
2347
2348 }
5417fbd7 2349 } else if ($feed == -6) { // recently read
5089b30b 2350 $query_strategy_part = "unread = false AND last_read IS NOT NULL";
5417fbd7 2351 $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
835fb294 2352 $allow_archived = true;
46b78149
AD
2353
2354 if (!$override_order) $override_order = "last_read DESC";
2d24f032 2355 } else if ($feed == -3) { // fresh virtual feed
cd2cc43d 2356 $query_strategy_part = "unread = true AND score >= 0";
2d24f032 2357
7a22dc2a 2358 $intl = get_pref($link, "FRESH_ARTICLE_MAX_AGE", $owner_uid);
c1d7e6c3 2359
2d24f032 2360 if (DB_TYPE == "pgsql") {
8d505d78 2361 $query_strategy_part .= " AND updated > NOW() - INTERVAL '$intl hour' ";
2d24f032 2362 } else {
7608b38a 2363 $query_strategy_part .= " AND updated > DATE_SUB(NOW(), INTERVAL $intl HOUR) ";
2d24f032
AD
2364 }
2365
b2531a28
AD
2366 $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
2367 } else if ($feed == -4) { // all articles virtual feed
2368 $query_strategy_part = "true";
e4f4b46f 2369 $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
ef393de7
AD
2370 } else if ($feed <= -10) { // labels
2371 $label_id = -$feed - 11;
3de0261a 2372
ceb30ba4
AD
2373 $query_strategy_part = "label_id = '$label_id' AND
2374 ttrss_labels2.id = ttrss_user_labels2.label_id AND
2375 ttrss_user_labels2.article_id = ref_id";
3de0261a 2376
ef393de7 2377 $vfeed_query_part = "ttrss_feeds.title AS feed_title,";
ceb30ba4 2378 $ext_tables_part = ",ttrss_labels2,ttrss_user_labels2";
835fb294 2379 $allow_archived = true;
8d505d78 2380
ef393de7 2381 } else {
835fb294 2382 $query_strategy_part = "true";
ef393de7 2383 }
d6e5706d 2384
b3990c92
AD
2385 if (get_pref($link, "SORT_HEADLINES_BY_FEED_DATE", $owner_uid)) {
2386 $date_sort_field = "updated";
2387 } else {
2388 $date_sort_field = "date_entered";
2389 }
2390
7a22dc2a 2391 if (get_pref($link, 'REVERSE_HEADLINES', $owner_uid)) {
b3990c92 2392 $order_by = "$date_sort_field";
8d505d78 2393 } else {
b3990c92 2394 $order_by = "$date_sort_field DESC";
d6e5706d 2395 }
e939722a 2396
7b4d02a8
AD
2397 if ($view_mode != "noscores") {
2398 $order_by = "score DESC, $order_by";
2399 }
48b0c4ec 2400
e939722a
AD
2401 if ($override_order) {
2402 $order_by = $override_order;
2403 }
8d505d78 2404
ef393de7
AD
2405 $feed_title = "";
2406
22fdebff 2407 if ($search) {
7032f2a5 2408 $feed_title = T_sprintf("Search results: %s", $search);
22fdebff 2409 } else {
ef393de7 2410 if ($cat_view) {
22fdebff 2411 $feed_title = getCategoryTitle($link, $feed);
ef393de7 2412 } else {
147f5632 2413 if (is_numeric($feed) && $feed > 0) {
8d505d78 2414 $result = db_query($link, "SELECT title,site_url,last_error
22fdebff 2415 FROM ttrss_feeds WHERE id = '$feed' AND owner_uid = $owner_uid");
8d505d78 2416
22fdebff
AD
2417 $feed_title = db_fetch_result($result, 0, "title");
2418 $feed_site_url = db_fetch_result($result, 0, "site_url");
2419 $last_error = db_fetch_result($result, 0, "last_error");
2420 } else {
2421 $feed_title = getFeedTitle($link, $feed);
8d505d78 2422 }
88040f57 2423 }
ef393de7
AD
2424 }
2425
87764a50 2426 $content_query_part = "content as content_preview, cached_content, ";
62129e67 2427
75c648cf 2428 if (is_numeric($feed)) {
8d505d78 2429
ef393de7
AD
2430 if ($feed >= 0) {
2431 $feed_kind = "Feeds";
2432 } else {
2433 $feed_kind = "Labels";
2434 }
8d505d78 2435
95a82c08
AD
2436 if ($limit_query_part) {
2437 $offset_query_part = "OFFSET $offset";
2438 }
2439
7fdf8eca 2440 // proper override_order applied above
6b3f228f 2441 if ($vfeed_query_part && !$ignore_vfeed_group && get_pref($link, 'VFEED_GROUP_BY_FEED', $owner_uid)) {
6cfea5c7 2442 if (!$override_order) {
8d505d78 2443 $order_by = "ttrss_feeds.title, $order_by";
7fdf8eca
AD
2444 } else {
2445 $order_by = "ttrss_feeds.title, $override_order";
43fc671f 2446 }
6cfea5c7
AD
2447 }
2448
8361e724 2449 if (!$allow_archived) {
e04c18a2 2450 $from_qpart = "ttrss_entries,ttrss_user_entries,ttrss_feeds$ext_tables_part";
117335bf 2451 $feed_check_qpart = "ttrss_user_entries.feed_id = ttrss_feeds.id AND";
e04c18a2
AD
2452
2453 } else {
835fb294 2454 $from_qpart = "ttrss_entries$ext_tables_part,ttrss_user_entries
e04c18a2
AD
2455 LEFT JOIN ttrss_feeds ON (feed_id = ttrss_feeds.id)";
2456 }
2457
8d505d78 2458 $query = "SELECT DISTINCT
f9b2d27c 2459 date_entered,
1f64b1be 2460 guid,
ef393de7 2461 ttrss_entries.id,ttrss_entries.title,
46921916 2462 updated,
9c506873
AD
2463 label_cache,
2464 tag_cache,
c0644ee4 2465 always_display_enclosures,
d1fc2f92 2466 site_url,
c7e51de1 2467 note,
13992673
AD
2468 num_comments,
2469 comments,
db16ae50 2470 int_id,
bfd61d3f 2471 hide_images,
494a64ea 2472 unread,feed_id,marked,published,link,last_read,orig_feed_id,
7873d588 2473 last_marked, last_published,
fc2b26a6 2474 ".SUBSTRING_FOR_DATE."(last_read,1,19) as last_read_noms,
ef393de7
AD
2475 $vfeed_query_part
2476 $content_query_part
fc2b26a6 2477 ".SUBSTRING_FOR_DATE."(updated,1,19) as updated_noms,
ff6e357a 2478 author,score
ef393de7 2479 FROM
e04c18a2 2480 $from_qpart
ef393de7 2481 WHERE
e04c18a2 2482 $feed_check_qpart
ef393de7 2483 ttrss_user_entries.ref_id = ttrss_entries.id AND
c36bf4d5 2484 ttrss_user_entries.owner_uid = '$owner_uid' AND
ef393de7 2485 $search_query_part
36184020 2486 $filter_query_part
ef393de7 2487 $view_query_part
97e5dbb2 2488 $since_id_part
ef393de7 2489 $query_strategy_part ORDER BY $order_by
95a82c08 2490 $limit_query_part $offset_query_part";
4bc311fc 2491
b4e75b2a 2492 if ($_REQUEST["debug"]) print $query;
4bc311fc
AD
2493
2494 $result = db_query($link, $query);
8d505d78 2495
ef393de7
AD
2496 } else {
2497 // browsing by tag
8d505d78 2498
147f5632
CM
2499 $select_qpart = "SELECT DISTINCT " .
2500 "date_entered," .
2501 "guid," .
2502 "note," .
2503 "ttrss_entries.id as id," .
2504 "title," .
2505 "updated," .
2506 "unread," .
2507 "feed_id," .
2508 "orig_feed_id," .
2509 "marked," .
d1fc2f92
AD
2510 "num_comments, " .
2511 "comments, " .
c0644ee4
AD
2512 "tag_cache," .
2513 "label_cache," .
147f5632
CM
2514 "link," .
2515 "last_read," .
94a567df 2516 "(SELECT hide_images FROM ttrss_feeds WHERE id = feed_id) AS hide_images," .
7873d588 2517 "last_marked, last_published, " .
147f5632 2518 SUBSTRING_FOR_DATE . "(last_read,1,19) as last_read_noms," .
97e5dbb2 2519 $since_id_part .
147f5632
CM
2520 $vfeed_query_part .
2521 $content_query_part .
2522 SUBSTRING_FOR_DATE . "(updated,1,19) as updated_noms," .
2523 "score ";
2524
ef393de7 2525 $feed_kind = "Tags";
147f5632
CM
2526 $all_tags = explode(",", $feed);
2527 if ($search_mode == 'any') {
2528 $tag_sql = "tag_name in (" . implode(", ", array_map("db_quote", $all_tags)) . ")";
2529 $from_qpart = " FROM ttrss_entries,ttrss_user_entries,ttrss_tags ";
2530 $where_qpart = " WHERE " .
2531 "ref_id = ttrss_entries.id AND " .
2532 "ttrss_user_entries.owner_uid = $owner_uid AND " .
2533 "post_int_id = int_id AND $tag_sql AND " .
2534 $view_query_part .
2535 $search_query_part .
2536 $query_strategy_part . " ORDER BY $order_by " .
2537 $limit_query_part;
8d505d78 2538
147f5632
CM
2539 } else {
2540 $i = 1;
2541 $sub_selects = array();
2542 $sub_ands = array();
2543 foreach ($all_tags as $term) {
2544 array_push($sub_selects, "(SELECT post_int_id from ttrss_tags WHERE tag_name = " . db_quote($term) . " AND owner_uid = $owner_uid) as A$i");
2545 $i++;
2546 }
2547 if ($i > 2) {
2548 $x = 1;
2549 $y = 2;
2550 do {
2551 array_push($sub_ands, "A$x.post_int_id = A$y.post_int_id");
2552 $x++;
2553 $y++;
2554 } while ($y < $i);
2555 }
2556 array_push($sub_ands, "A1.post_int_id = ttrss_user_entries.int_id and ttrss_user_entries.owner_uid = $owner_uid");
2557 array_push($sub_ands, "ttrss_user_entries.ref_id = ttrss_entries.id");
2558 $from_qpart = " FROM " . implode(", ", $sub_selects) . ", ttrss_user_entries, ttrss_entries";
2559 $where_qpart = " WHERE " . implode(" AND ", $sub_ands);
2560 }
2561 // error_log("TAG SQL: " . $tag_sql);
2562 // $tag_sql = "tag_name = '$feed'"; DEFAULT way
2563
2564 // error_log("[". $select_qpart . "][" . $from_qpart . "][" .$where_qpart . "]");
2565 $result = db_query($link, $select_qpart . $from_qpart . $where_qpart);
ef393de7
AD
2566 }
2567
c7188969 2568 return array($result, $feed_title, $feed_site_url, $last_error);
8d505d78 2569
ef393de7
AD
2570 }
2571
bfd61d3f 2572 function sanitize($link, $str, $force_remove_images = false, $owner = false, $site_url = false) {
ceb0cab5
AD
2573 if (!$owner) $owner = $_SESSION["uid"];
2574
96811a55
AD
2575 $res = trim($str); if (!$res) return '';
2576
46137483
AD
2577 if (strpos($res, "href=") === false)
2578 $res = rewrite_urls($res);
533c0ea6 2579
8cc3c778
AD
2580 $charset_hack = '<head>
2581 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
2582 </head>';
2583
96811a55
AD
2584 $res = trim($res); if (!$res) return '';
2585
8cc3c778
AD
2586 libxml_use_internal_errors(true);
2587
2588 $doc = new DOMDocument();
2589 $doc->loadHTML($charset_hack . $res);
2590 $xpath = new DOMXPath($doc);
8d505d78 2591
8cc3c778
AD
2592 $entries = $xpath->query('(//a[@href]|//img[@src])');
2593
2594 foreach ($entries as $entry) {
2595
2596 if ($site_url) {
2597
2598 if ($entry->hasAttribute('href'))
2599 $entry->setAttribute('href',
2600 rewrite_relative_url($site_url, $entry->getAttribute('href')));
8d505d78 2601
f0bd8e65
AD
2602 if ($entry->hasAttribute('src')) {
2603 $src = rewrite_relative_url($site_url, $entry->getAttribute('src'));
2604
2605 $cached_filename = CACHE_DIR . '/images/' . sha1($src) . '.png';
2606
2607 if (file_exists($cached_filename)) {
2608 $src = SELF_URL_PATH . '/image.php?hash=' . sha1($src);
2609 }
2610
2611 $entry->setAttribute('src', $src);
2612 }
bfd61d3f
AD
2613
2614 if ($entry->nodeName == 'img') {
f0540b59
AD
2615 if (($owner && get_pref($link, "STRIP_IMAGES", $owner)) ||
2616 $force_remove_images) {
bfd61d3f
AD
2617
2618 $p = $doc->createElement('p');
2619
2620 $a = $doc->createElement('a');
2621 $a->setAttribute('href', $entry->getAttribute('src'));
2622
2623 $a->appendChild(new DOMText($entry->getAttribute('src')));
2624 $a->setAttribute('target', '_blank');
2625
2626 $p->appendChild($a);
2627
2628 $entry->parentNode->replaceChild($p, $entry);
2629 }
2630 }
8cc3c778
AD
2631 }
2632
fa403733 2633 if (strtolower($entry->nodeName) == "a") {
c401d5c9 2634 $entry->setAttribute("target", "_blank");
fa403733 2635 }
8dccabed 2636 }
8d505d78 2637
254a3f56
AD
2638 $entries = $xpath->query('//iframe');
2639 foreach ($entries as $entry) {
4e404802
AD
2640 $entry->setAttribute('sandbox', 'allow-scripts');
2641
254a3f56 2642 }
8dccabed 2643
e9b86f0a
AD
2644 global $pluginhost;
2645
2646 if (isset($pluginhost)) {
2647 foreach ($pluginhost->get_hooks($pluginhost::HOOK_SANITIZE) as $plugin) {
2648 $doc = $plugin->hook_sanitize($doc, $site_url);
2649 }
2650 }
2651
be124dc2 2652 $doc->removeChild($doc->firstChild); //remove doctype
254a3f56 2653 $doc = strip_harmful_tags($doc);
be124dc2 2654 $res = $doc->saveHTML();
254a3f56
AD
2655 return $res;
2656 }
16ad9085 2657
254a3f56
AD
2658 function strip_harmful_tags($doc) {
2659 $entries = $doc->getElementsByTagName("*");
16ad9085 2660
2229e6ed 2661 $allowed_elements = array('a', 'address', 'audio', 'article',
10b55a12 2662 'b', 'big', 'blockquote', 'body', 'br', 'cite',
46ec3348 2663 'code', 'dd', 'del', 'details', 'div', 'dl', 'font',
10b55a12 2664 'dt', 'em', 'footer', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
6e61104d 2665 'header', 'html', 'i', 'img', 'ins', 'kbd',
10b55a12
AD
2666 'li', 'nav', 'ol', 'p', 'pre', 'q', 's','small',
2667 'source', 'span', 'strike', 'strong', 'sub', 'summary',
2668 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead',
2669 'tr', 'track', 'tt', 'u', 'ul', 'var', 'wbr', 'video' );
4f7d69e1
AD
2670
2671 if ($_SESSION['hasSandbox']) array_push($allowed_elements, 'iframe');
254a3f56
AD
2672
2673 $disallowed_attributes = array('id', 'style', 'class');
2674
2675 foreach ($entries as $entry) {
2676 if (!in_array($entry->nodeName, $allowed_elements)) {
2677 $entry->parentNode->removeChild($entry);
2678 }
2679
2680 if ($entry->hasAttributes()) {
2681 foreach (iterator_to_array($entry->attributes) as $attr) {
2682
2683 if (strpos($attr->nodeName, 'on') === 0) {
2684 $entry->removeAttributeNode($attr);
2685 }
2686
2687 if (in_array($attr->nodeName, $disallowed_attributes)) {
2688 $entry->removeAttributeNode($attr);
2689 }
2690 }
2691 }
2692 }
2693
2694 return $doc;
183ad07b 2695 }
b72c3ef8 2696
73495fd1 2697 function check_for_update($link) {
63855db1 2698 if (CHECK_FOR_NEW_VERSION && $_SESSION['access_level'] >= 10) {
f6064662
AD
2699 $version_url = "http://tt-rss.org/version.php?ver=" . VERSION .
2700 "&iid=" . sha1(SELF_URL_PATH);
b72c3ef8 2701
63855db1 2702 $version_data = @fetch_file_contents($version_url);
b72c3ef8 2703
63855db1
AD
2704 if ($version_data) {
2705 $version_data = json_decode($version_data, true);
8d505d78 2706 if ($version_data && $version_data['version']) {
f67d9754 2707
63855db1 2708 if (version_compare(VERSION, $version_data['version']) == -1) {
e91ad1e9 2709 return $version_data;
63855db1
AD
2710 }
2711 }
f67d9754 2712 }
b72c3ef8 2713 }
63855db1 2714 return false;
b72c3ef8 2715 }
472782e8 2716
9968d46f
AD
2717 function catchupArticlesById($link, $ids, $cmode, $owner_uid = false) {
2718
2719 if (!$owner_uid) $owner_uid = $_SESSION["uid"];
ed41f171 2720 if (count($ids) == 0) return;
472782e8
AD
2721
2722 $tmp_ids = array();
2723
2724 foreach ($ids as $id) {
2725 array_push($tmp_ids, "ref_id = '$id'");
2726 }
2727
2728 $ids_qpart = join(" OR ", $tmp_ids);
2729
2730 if ($cmode == 0) {
8d505d78 2731 db_query($link, "UPDATE ttrss_user_entries SET
472782e8 2732 unread = false,last_read = NOW()
9968d46f 2733 WHERE ($ids_qpart) AND owner_uid = $owner_uid");
472782e8 2734 } else if ($cmode == 1) {
8d505d78 2735 db_query($link, "UPDATE ttrss_user_entries SET
472782e8 2736 unread = true
9968d46f 2737 WHERE ($ids_qpart) AND owner_uid = $owner_uid");
472782e8 2738 } else {
8d505d78 2739 db_query($link, "UPDATE ttrss_user_entries SET
472782e8 2740 unread = NOT unread,last_read = NOW()
9968d46f 2741 WHERE ($ids_qpart) AND owner_uid = $owner_uid");
472782e8 2742 }
0737b95a
AD
2743
2744 /* update ccache */
2745
2746 $result = db_query($link, "SELECT DISTINCT feed_id FROM ttrss_user_entries
2747 WHERE ($ids_qpart) AND owner_uid = $owner_uid");
2748
2749 while ($line = db_fetch_assoc($result)) {
2750 ccache_update($link, $line["feed_id"], $owner_uid);
2751 }
472782e8
AD
2752 }
2753
ca5133cb 2754 function get_article_tags($link, $id, $owner_uid = 0, $tag_cache = false) {
0b126ac2
AD
2755
2756 $a_id = db_escape_string($id);
2757
bc976a8c
AD
2758 if (!$owner_uid) $owner_uid = $_SESSION["uid"];
2759
8d505d78 2760 $query = "SELECT DISTINCT tag_name,
0c3d1c68 2761 owner_uid as owner FROM
0b126ac2 2762 ttrss_tags WHERE post_int_id = (SELECT int_id FROM ttrss_user_entries WHERE
bd3f2ade 2763 ref_id = '$a_id' AND owner_uid = '$owner_uid' LIMIT 1) ORDER BY tag_name";
0b126ac2 2764
bd3f2ade 2765 $obj_id = md5("TAGS:$owner_uid:$id");
8d505d78 2766 $tags = array();
bd3f2ade 2767
0e4a7d7a 2768 /* check cache first */
490c366d 2769
0e4a7d7a
AD
2770 if ($tag_cache === false) {
2771 $result = db_query($link, "SELECT tag_cache FROM ttrss_user_entries
2772 WHERE ref_id = '$id' AND owner_uid = $owner_uid");
490c366d 2773
0e4a7d7a
AD
2774 $tag_cache = db_fetch_result($result, 0, "tag_cache");
2775 }
bd3f2ade 2776
0e4a7d7a
AD
2777 if ($tag_cache) {
2778 $tags = explode(",", $tag_cache);
2779 } else {
490c366d 2780
0e4a7d7a 2781 /* do it the hard way */
490c366d 2782
0e4a7d7a 2783 $tmp_result = db_query($link, $query);
490c366d 2784
0e4a7d7a
AD
2785 while ($tmp_line = db_fetch_assoc($tmp_result)) {
2786 array_push($tags, $tmp_line["tag_name"]);
2787 }
490c366d 2788
0e4a7d7a 2789 /* update the cache */
490c366d 2790
0e4a7d7a 2791 $tags_str = db_escape_string(join(",", $tags));
bd3f2ade 2792
0e4a7d7a
AD
2793 db_query($link, "UPDATE ttrss_user_entries
2794 SET tag_cache = '$tags_str' WHERE ref_id = '$id'
2795 AND owner_uid = $owner_uid");
0b126ac2
AD
2796 }
2797
2798 return $tags;
2799 }
2800
d62a3b63
AD
2801 function trim_array($array) {
2802 $tmp = $array;
3415b075 2803 array_walk($tmp, 'trim');
d62a3b63
AD
2804 return $tmp;
2805 }
2806
be832a1a 2807 function tag_is_valid($tag) {
ef063748
AD
2808 if ($tag == '') return false;
2809 if (preg_match("/^[0-9]*$/", $tag)) return false;
41f7498a 2810 if (mb_strlen($tag) > 250) return false;
ef063748 2811
31365729
AD
2812 if (function_exists('iconv')) {
2813 $tag = iconv("utf-8", "utf-8", $tag);
2814 }
2815
ef063748
AD
2816 if (!$tag) return false;
2817
2818 return true;
be832a1a
AD
2819 }
2820
97acbaf1
AD
2821 function render_login_form($link, $form_id = 0) {
2822 switch ($form_id) {
afb12ed0 2823 case 0:
793185a9 2824 require_once "login_form.php";
afb12ed0
AD
2825 break;
2826 case 1:
793185a9 2827 require_once "mobile/login_form.php";
afb12ed0 2828 break;
793185a9 2829 }
97acbaf1 2830 exit;
01a87dff
AD
2831 }
2832
dc56b3b7
AD
2833 // from http://developer.apple.com/internet/safari/faq.html
2834 function no_cache_incantation() {
2835 header("Expires: Mon, 22 Dec 1980 00:00:00 GMT"); // Happy birthday to me :)
2836 header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified
2837 header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); // HTTP/1.1
2838 header("Cache-Control: post-check=0, pre-check=0", false);
2839 header("Pragma: no-cache"); // HTTP/1.0
2840 }
2841
42395d28 2842 function format_warning($msg, $id = "") {
883fee8d 2843 global $link;
8d505d78 2844 return "<div class=\"warning\" id=\"$id\">
2a3b6de0 2845 <img src=\"images/sign_excl.svg\">$msg</div>";
0d32b41e
AD
2846 }
2847
08ac193a 2848 function format_notice($msg, $id = "") {
883fee8d 2849 global $link;
8d505d78 2850 return "<div class=\"notice\" id=\"$id\">
2a3b6de0 2851 <img src=\"images/sign_info.svg\">$msg</div>";
0d32b41e
AD
2852 }
2853
08ac193a 2854 function format_error($msg, $id = "") {
883fee8d 2855 global $link;
8d505d78 2856 return "<div class=\"error\" id=\"$id\">
2a3b6de0 2857 <img src=\"images/sign_excl.svg\">$msg</div>";
68d2f95e
AD
2858 }
2859
4dccf1ed
AD
2860 function print_notice($msg) {
2861 return print format_notice($msg);
2862 }
2863
2864 function print_warning($msg) {
2865 return print format_warning($msg);
2866 }
2867
68d2f95e
AD
2868 function print_error($msg) {
2869 return print format_error($msg);
2870 }
2871
2872
4dccf1ed
AD
2873 function T_sprintf() {
2874 $args = func_get_args();
2875 return vsprintf(__(array_shift($args)), $args);
2876 }
2877
51682b23
AD
2878 function format_inline_player($link, $url, $ctype) {
2879
2880 $entry = "";
2881
44cd77b6
AD
2882 $url = htmlspecialchars($url);
2883
8d505d78 2884 if (strpos($ctype, "audio/") === 0) {
c3edc667
AD
2885
2886 if ($_SESSION["hasAudio"] && (strpos($ctype, "ogg") !== false ||
8d505d78 2887 strpos($_SERVER['HTTP_USER_AGENT'], "Chrome") !== false ||
c3edc667
AD
2888 strpos($_SERVER['HTTP_USER_AGENT'], "Safari") !== false )) {
2889
2890 $id = 'AUDIO-' . uniqid();
2891
cb081096 2892 $entry .= "<audio id=\"$id\"\" controls style='display : none'>
ca3bca99 2893 <source type=\"$ctype\" src=\"$url\"></source>
8d505d78 2894 </audio>";
c3edc667 2895
8d505d78 2896 $entry .= "<span onclick=\"player(this)\"
c3edc667
AD
2897 title=\"".__("Click to play")."\" status=\"0\"
2898 class=\"player\" audio-id=\"$id\">".__("Play")."</span>";
2899
2900 } else {
8d505d78
AD
2901
2902 $entry .= "<object type=\"application/x-shockwave-flash\"
ad95edc2 2903 data=\"lib/button/musicplayer.swf?song_url=$url\"
8d505d78
AD
2904 width=\"17\" height=\"17\" style='float : left; margin-right : 5px;'>
2905 <param name=\"movie\"
ad95edc2 2906 value=\"lib/button/musicplayer.swf?song_url=$url\" />
8d505d78 2907 </object>";
c3edc667 2908 }
ca3bca99 2909
44cd77b6
AD
2910 if ($entry) $entry .= "&nbsp; <a target=\"_blank\"
2911 href=\"$url\">" . basename($url) . "</a>";
ca3bca99
AD
2912
2913 return $entry;
2914
51682b23
AD
2915 }
2916
ca3bca99
AD
2917 return "";
2918
2919/* $filename = substr($url, strrpos($url, "/")+1);
c3edc667
AD
2920
2921 $entry .= " <a target=\"_blank\" href=\"" . htmlspecialchars($url) . "\">" .
ca3bca99 2922 $filename . " (" . $ctype . ")" . "</a>"; */
c3edc667 2923
51682b23
AD
2924 }
2925
64436e10 2926 function format_article($link, $id, $mark_as_read = true, $zoom_mode = false, $owner_uid = false) {
64436e10 2927 if (!$owner_uid) $owner_uid = $_SESSION["uid"];
3de0261a 2928
009646d2
AD
2929 $rv = array();
2930
2931 $rv['id'] = $id;
2932
10eb9da8 2933 /* we can figure out feed_id from article id anyway, why do we
e04c18a2 2934 * pass feed_id here? let's ignore the argument :( */
10eb9da8
AD
2935
2936 $result = db_query($link, "SELECT feed_id FROM ttrss_user_entries
2937 WHERE ref_id = '$id'");
2938
e04c18a2 2939 $feed_id = (int) db_fetch_result($result, 0, "feed_id");
10eb9da8 2940
009646d2
AD
2941 $rv['feed_id'] = $feed_id;
2942
2943 //if (!$zoom_mode) { print "<article id='$id'><![CDATA["; };
3de0261a 2944
3de0261a 2945 if ($mark_as_read) {
8d505d78
AD
2946 $result = db_query($link, "UPDATE ttrss_user_entries
2947 SET unread = false,last_read = NOW()
64436e10 2948 WHERE ref_id = '$id' AND owner_uid = $owner_uid");
8a4c759e 2949
64436e10 2950 ccache_update($link, $feed_id, $owner_uid);
3de0261a
AD
2951 }
2952
7252abe3 2953 $result = db_query($link, "SELECT id,title,link,content,feed_id,comments,int_id,
fc2b26a6 2954 ".SUBSTRING_FOR_DATE."(updated,1,16) as updated,
8cc3c778 2955 (SELECT site_url FROM ttrss_feeds WHERE id = feed_id) as site_url,
3de0261a 2956 num_comments,
9c506873 2957 tag_cache,
c7e51de1 2958 author,
ef83538d 2959 orig_feed_id,
87764a50
AD
2960 note,
2961 cached_content
3de0261a 2962 FROM ttrss_entries,ttrss_user_entries
64436e10 2963 WHERE id = '$id' AND ref_id = id AND owner_uid = $owner_uid");
3de0261a
AD
2964
2965 if ($result) {
2966
3de0261a
AD
2967 $line = db_fetch_assoc($result);
2968
84d952f1
AD
2969 $tag_cache = $line["tag_cache"];
2970
2971 $line["tags"] = get_article_tags($link, $id, $owner_uid, $line["tag_cache"]);
2972 unset($line["tag_cache"]);
2973
2974 $line["content"] = sanitize($link, $line["content"], false, $owner_uid, $line["site_url"]);
2975
2976 global $pluginhost;
2977
2978 foreach ($pluginhost->get_hooks($pluginhost::HOOK_RENDER_ARTICLE) as $p) {
2979 $line = $p->hook_render_article($line);
2980 }
8cc3c778 2981
3de0261a
AD
2982 $num_comments = $line["num_comments"];
2983 $entry_comments = "";
2984
2985 if ($num_comments > 0) {
2986 if ($line["comments"]) {
6e577ba1 2987 $comments_url = htmlspecialchars($line["comments"]);
3de0261a 2988 } else {
6e577ba1 2989 $comments_url = htmlspecialchars($line["link"]);
3de0261a 2990 }
7514749d 2991 $entry_comments = "<a target='_blank' href=\"$comments_url\">$num_comments comments</a>";
3de0261a
AD
2992 } else {
2993 if ($line["comments"] && $line["link"] != $line["comments"]) {
6e577ba1 2994 $entry_comments = "<a target='_blank' href=\"".htmlspecialchars($line["comments"])."\">comments</a>";
8d505d78 2995 }
3de0261a
AD
2996 }
2997
eedfb635
AD
2998 if ($zoom_mode) {
2999 header("Content-Type: text/html");
009646d2 3000 $rv['content'] .= "<html><head>
5bb0cc8e 3001 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>
eedfb635
AD
3002 <title>Tiny Tiny RSS - ".$line["title"]."</title>
3003 <link rel=\"stylesheet\" type=\"text/css\" href=\"tt-rss.css\">
3004 </head><body>";
3005 }
3006
5c568973 3007 $title_escaped = htmlspecialchars($line['title']);
2ea9bbfd 3008
e54dbacb
AD
3009 $rv['content'] .= "<div id=\"PTITLE-FULL-$id\" style=\"display : none\">" .
3010 strip_tags($line['title']) . "</div>";
3011
009646d2 3012 $rv['content'] .= "<div class=\"postReply\" id=\"POST-$id\">";
bc372fe3 3013
126e639a 3014 $rv['content'] .= "<div class=\"postHeader\" id=\"POSTHDR-$id\">";
3de0261a
AD
3015
3016 $entry_author = $line["author"];
3017
3018 if ($entry_author) {
60164936 3019 $entry_author = __(" - ") . $entry_author;
3de0261a
AD
3020 }
3021
8d505d78 3022 $parsed_updated = make_local_datetime($link, $line["updated"], true,
64436e10 3023 $owner_uid, true);
324944f3 3024
5321e775 3025 $rv['content'] .= "<div class=\"postDate\">$parsed_updated</div>";
3de0261a
AD
3026
3027 if ($line["link"]) {
c6c010d9 3028 $rv['content'] .= "<div class='postTitle'><a target='_blank'
a64029e5 3029 title=\"".htmlspecialchars($line['title'])."\"
8d505d78 3030 href=\"" .
5c568973 3031 htmlspecialchars($line["link"]) . "\">" .
c6c010d9 3032 $line["title"] .
a64029e5 3033 "<span class='author'>$entry_author</span></a></div>";
3de0261a 3034 } else {
c6c010d9 3035 $rv['content'] .= "<div class='postTitle'>" . $line["title"] . "$entry_author</div>";
3de0261a
AD
3036 }
3037
84d952f1
AD
3038 $tags_str = format_tags_string($line["tags"], $id);
3039 $tags_str_full = join(", ", $line["tags"]);
0780f4f4
AD
3040
3041 if (!$tags_str_full) $tags_str_full = __("no tags");
e7544143 3042
3de0261a
AD
3043 if (!$entry_comments) $entry_comments = "&nbsp;"; # placeholder
3044
f0755b7c 3045 $rv['content'] .= "<div class='postTags' style='float : right'>
2a3b6de0 3046 <img src='images/tag.png'
e9823609 3047 class='tagsPic' alt='Tags' title='Tags'>&nbsp;";
eedfb635
AD
3048
3049 if (!$zoom_mode) {
009646d2 3050 $rv['content'] .= "<span id=\"ATSTR-$id\">$tags_str</span>
8d505d78 3051 <a title=\"".__('Edit tags for this article')."\"
31a53903 3052 href=\"#\" onclick=\"editArticleTags($id, $feed_id)\">(+)</a>";
4710e3dc 3053
0780f4f4
AD
3054 $rv['content'] .= "<div dojoType=\"dijit.Tooltip\"
3055 id=\"ATSTRTIP-$id\" connectId=\"ATSTR-$id\"
3056 position=\"below\">$tags_str_full</div>";
3057
19c73507 3058 global $pluginhost;
f9ac31d6 3059
19c73507
AD
3060 foreach ($pluginhost->get_hooks($pluginhost::HOOK_ARTICLE_BUTTON) as $p) {
3061 $rv['content'] .= $p->hook_article_button($line);
411fe209
AD
3062 }
3063
6f3976c9 3064
24ecbcae
AD
3065 } else {
3066 $tags_str = strip_tags($tags_str);
009646d2 3067 $rv['content'] .= "<span id=\"ATSTR-$id\">$tags_str</span>";
eedfb635 3068 }
009646d2
AD
3069 $rv['content'] .= "</div>";
3070 $rv['content'] .= "<div clear='both'>$entry_comments</div>";
3de0261a 3071
ef83538d
AD
3072 if ($line["orig_feed_id"]) {
3073
3074 $tmp_result = db_query($link, "SELECT * FROM ttrss_archived_feeds
3075 WHERE id = ".$line["orig_feed_id"]);
3076
3077 if (db_num_rows($tmp_result) != 0) {
3078
009646d2
AD
3079 $rv['content'] .= "<div clear='both'>";
3080 $rv['content'] .= __("Originally from:");
ef83538d 3081
009646d2 3082 $rv['content'] .= "&nbsp;";
ef83538d
AD
3083
3084 $tmp_line = db_fetch_assoc($tmp_result);
3085
009646d2 3086 $rv['content'] .= "<a target='_blank'
ef83538d
AD
3087 href=' " . htmlspecialchars($tmp_line['site_url']) . "'>" .
3088 $tmp_line['title'] . "</a>";
3089
009646d2 3090 $rv['content'] .= "&nbsp;";
ef83538d 3091
009646d2 3092 $rv['content'] .= "<a target='_blank' href='" . htmlspecialchars($tmp_line['feed_url']) . "'>";
c2167866 3093 $rv['content'] .= "<img title='".__('Feed URL')."'class='tinyFeedIcon' src='images/pub_set.svg'></a>";
ef83538d 3094
009646d2 3095 $rv['content'] .= "</div>";
ef83538d
AD
3096 }
3097 }
3098
009646d2 3099 $rv['content'] .= "</div>";
3de0261a 3100
009646d2 3101 $rv['content'] .= "<div id=\"POSTNOTE-$id\">";
c7e51de1 3102 if ($line['note']) {
16cbc19a 3103 $rv['content'] .= format_article_note($id, $line['note'], !$zoom_mode);
c7e51de1 3104 }
009646d2 3105 $rv['content'] .= "</div>";
c7e51de1 3106
009646d2 3107 $rv['content'] .= "<div class=\"postContent\">";
741b6090 3108
d3d69daa
AD
3109 // N-grams
3110
6f4bd262 3111 if (DB_TYPE == "pgsql" and defined('_NGRAM_TITLE_RELATED_THRESHOLD')) {
d3d69daa
AD
3112
3113 $ngram_result = db_query($link, "SELECT id,title FROM
3114 ttrss_entries,ttrss_user_entries
3115 WHERE ref_id = id AND updated >= NOW() - INTERVAL '7 day'
6f4bd262 3116 AND similarity(title, '$title_escaped') >= "._NGRAM_TITLE_RELATED_THRESHOLD."
d3d69daa
AD
3117 AND title != '$title_escaped'
3118 AND owner_uid = $owner_uid");
3119
3120 if (db_num_rows($ngram_result) > 0) {
3121 $rv['content'] .= "<div dojoType=\"dijit.form.DropDownButton\">".
3122 "<span>" . __('Related')."</span>";
3123 $rv['content'] .= "<div dojoType=\"dijit.Menu\" style=\"display: none;\">";
3124
3125 while ($nline = db_fetch_assoc($ngram_result)) {
3126 $rv['content'] .= "<div onclick=\"hlOpenInNewTab(null,".$nline['id'].")\"
3127 dojoType=\"dijit.MenuItem\">".$nline['title']."</div>";
3128
3129 }
3130 $rv['content'] .= "</div></div><br/";
3131 }
3132 }
3133
84d952f1 3134 $rv['content'] .= $line["content"];
db54143e 3135
009646d2 3136 $rv['content'] .= format_article_enclosures($link, $id,
84d952f1 3137 $always_display_enclosures, $line["content"]);
ce53e200 3138
009646d2 3139 $rv['content'] .= "</div>";
dad14b51 3140
009646d2 3141 $rv['content'] .= "</div>";
3de0261a
AD
3142
3143 }
3144
009646d2
AD
3145 if ($zoom_mode) {
3146 $rv['content'] .= "
eedfb635 3147 <div style=\"text-align : center\">
2ae69126
AD
3148 <button onclick=\"return window.close()\">".
3149 __("Close this window")."</button></div>";
009646d2 3150 $rv['content'] .= "</body></html>";
eedfb635 3151 }
3de0261a 3152
009646d2
AD
3153 return $rv;
3154
3de0261a
AD
3155 }
3156
79178062 3157 function print_checkpoint($n, $s) {
fa9e88c3 3158 $ts = microtime(true);
79178062
AD
3159 echo sprintf("<!-- CP[$n] %.4f seconds -->", $ts - $s);
3160 return $ts;
3161 }
3de0261a 3162
79178062
AD
3163 function sanitize_tag($tag) {
3164 $tag = trim($tag);
52d7e7da 3165
79178062 3166 $tag = mb_strtolower($tag, 'utf-8');
bd202c3f 3167
79178062 3168 $tag = preg_replace('/[\'\"\+\>\<]/', "", $tag);
46921916 3169
79178062
AD
3170// $tag = str_replace('"', "", $tag);
3171// $tag = str_replace("+", " ", $tag);
3172 $tag = str_replace("technorati tag: ", "", $tag);
961f4c73 3173
79178062
AD
3174 return $tag;
3175 }
3de0261a 3176
79178062 3177 function get_self_url_prefix() {
51cc3873
AD
3178 if (strrpos(SELF_URL_PATH, "/") === strlen(SELF_URL_PATH)-1) {
3179 return substr(SELF_URL_PATH, 0, strlen(SELF_URL_PATH)-1);
3180 } else {
3181 return SELF_URL_PATH;
3182 }
79178062 3183 }
a9bcfb8f 3184
45004d43
AD
3185 /**
3186 * Compute the Mozilla Firefox feed adding URL from server HOST and REQUEST_URI.
3187 *
3188 * @return string The Mozilla Firefox feed adding URL.
3189 */
3190 function add_feed_url() {
ed102aa0
AD
3191 //$url_path = ($_SERVER['HTTPS'] != "on" ? 'http://' : 'https://') . $_SERVER["HTTP_HOST"] . parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
3192
3193 $url_path = get_self_url_prefix() .
97acbaf1 3194 "/public.php?op=subscribe&feed_url=%s";
755a43ee 3195 return $url_path;
45004d43
AD
3196 } // function add_feed_url
3197
e90053fe
AD
3198 function encrypt_password($pass, $salt = '', $mode2 = false) {
3199 if ($salt && $mode2) {
3200 return "MODE2:" . hash('sha256', $salt . $pass);
3201 } else if ($salt) {
3202 return "SHA1X:" . sha1("$salt:$pass");
1a9f4d3c
AD
3203 } else {
3204 return "SHA1:" . sha1($pass);
3205 }
45004d43
AD
3206 } // function encrypt_password
3207
6aff7845 3208 function load_filters($link, $feed_id, $owner_uid, $action_id = false) {
fee840fb
AD
3209 $filters = array();
3210
5574b09e 3211 $cat_id = (int)getFeedCategory($link, $feed_id);
fee840fb 3212
6aff7845
AD
3213 $result = db_query($link, "SELECT * FROM ttrss_filters2 WHERE
3214 owner_uid = $owner_uid AND enabled = true");
8d505d78 3215
67bd0b1f
AD
3216 $check_cats = join(",", array_merge(
3217 getParentCategories($link, $cat_id, $owner_uid),
3218 array($cat_id)));
3219
0e4a7d7a 3220 while ($line = db_fetch_assoc($result)) {
6aff7845
AD
3221 $filter_id = $line["id"];
3222
3223 $result2 = db_query($link, "SELECT
3224 r.reg_exp, r.feed_id, r.cat_id, r.cat_filter, t.name AS type_name
3225 FROM ttrss_filters2_rules AS r,
3226 ttrss_filter_types AS t
3227 WHERE
67bd0b1f 3228 (cat_id IS NULL OR cat_id IN ($check_cats)) AND
6aff7845
AD
3229 (feed_id IS NULL OR feed_id = '$feed_id') AND
3230 filter_type = t.id AND filter_id = '$filter_id'");
3231
3232 $rules = array();
3233 $actions = array();
ba975b2e 3234
6aff7845
AD
3235 while ($rule_line = db_fetch_assoc($result2)) {
3236# print_r($rule_line);
8d505d78 3237
6aff7845
AD
3238 $rule = array();
3239 $rule["reg_exp"] = $rule_line["reg_exp"];
3240 $rule["type"] = $rule_line["type_name"];
3241
3242 array_push($rules, $rule);
3243 }
3244
3245 $result2 = db_query($link, "SELECT a.action_param,t.name AS type_name
3246 FROM ttrss_filters2_actions AS a,
3247 ttrss_filter_actions AS t
3248 WHERE
3249 action_id = t.id AND filter_id = '$filter_id'");
3250
3251 while ($action_line = db_fetch_assoc($result2)) {
3252# print_r($action_line);
3253
3254 $action = array();
3255 $action["type"] = $action_line["type_name"];
3256 $action["param"] = $action_line["action_param"];
3257
3258 array_push($actions, $action);
0e4a7d7a 3259 }
b8ffa322 3260
b8ffa322 3261
6aff7845
AD
3262 $filter = array();
3263 $filter["match_any_rule"] = sql_bool_to_bool($line["match_any_rule"]);
3264 $filter["rules"] = $rules;
3265 $filter["actions"] = $actions;
3266
3267 if (count($rules) > 0 && count($actions) > 0) {
3268 array_push($filters, $filter);
3269 }
3270 }
3271
0e4a7d7a 3272 return $filters;
fee840fb 3273 }
1e36af0c
AD
3274
3275 function get_score_pic($score) {
8d505d78
AD
3276 if ($score > 100) {
3277 return "score_high.png";
3278 } else if ($score > 0) {
883fee8d 3279 return "score_half_high.png";
1cce3aca 3280 } else if ($score < -100) {
883fee8d 3281 return "score_low.png";
1cce3aca 3282 } else if ($score < 0) {
883fee8d 3283 return "score_half_low.png";
8d505d78 3284 } else {
883fee8d 3285 return "score_neutral.png";
1e36af0c
AD
3286 }
3287 }
ec92c9d1 3288
7defa089
AD
3289 function feed_has_icon($id) {
3290 return is_file(ICONS_DIR . "/$id.ico") && filesize(ICONS_DIR . "/$id.ico") > 0;
3291 }
f29ba148
AD
3292
3293 function init_connection($link) {
8c0496f7
AD
3294 if ($link) {
3295
3296 if (DB_TYPE == "pgsql") {
3297 pg_query($link, "set client_encoding = 'UTF-8'");
3298 pg_set_client_encoding("UNICODE");
3299 pg_query($link, "set datestyle = 'ISO, european'");
3300 pg_query($link, "set TIME ZONE 0");
3301 } else {
3302 db_query($link, "SET time_zone = '+0:0'");
3303
3304 if (defined('MYSQL_CHARSET') && MYSQL_CHARSET) {
3305 db_query($link, "SET NAMES " . MYSQL_CHARSET);
3306 }
3307 }
19c73507
AD
3308
3309 global $pluginhost;
3310
8c0496f7 3311 $pluginhost = new PluginHost($link);
d2a421e3 3312 $pluginhost->load(PLUGINS, $pluginhost::KIND_ALL);
19c73507 3313
5f0a3741
AD
3314 return true;
3315 } else {
3316 print "Unable to connect to database:" . db_last_error();
3317 return false;
f29ba148
AD
3318 }
3319 }
5e96ca9d 3320
307d187c
AD
3321 function format_tags_string($tags, $id) {
3322
3323 $tags_str = "";
3324 $tags_nolinks_str = "";
3325
3326 $num_tags = 0;
3327
d9084cf2 3328 $tag_limit = 6;
307d187c
AD
3329
3330 $formatted_tags = array();
3331
3332 foreach ($tags as $tag) {
3333 $num_tags++;
3334 $tag_escaped = str_replace("'", "\\'", $tag);
3335
275a0af2
AD
3336 if (mb_strlen($tag) > 30) {
3337 $tag = truncate_string($tag, 30);
3338 }
3339
307d187c
AD
3340 $tag_str = "<a href=\"javascript:viewfeed('$tag_escaped')\">$tag</a>";
3341
3342 array_push($formatted_tags, $tag_str);
275a0af2
AD
3343
3344 $tmp_tags_str = implode(", ", $formatted_tags);
8d505d78 3345
275a0af2 3346 if ($num_tags == $tag_limit || mb_strlen($tmp_tags_str) > 150) {
307d187c
AD
3347 break;
3348 }
3349 }
3350
3351 $tags_str = implode(", ", $formatted_tags);
3352
3353 if ($num_tags < count($tags)) {
3354 $tags_str .= ", &hellip;";
3355 }
3356
3357 if ($num_tags == 0) {
3358 $tags_str = __("no tags");
3359 }
3360
3361 return $tags_str;
3362
3363 }
2eb9c95c
AD
3364
3365 function format_article_labels($labels, $id) {
3366
3367 $labels_str = "";
3368
3369 foreach ($labels as $l) {
8d505d78 3370 $labels_str .= sprintf("<span class='hlLabelRef'
2eb9c95c
AD
3371 style='color : %s; background-color : %s'>%s</span>",
3372 $l[2], $l[3], $l[1]);
3373 }
3374
3375 return $labels_str;
3376
3377 }
c7e51de1 3378
16cbc19a 3379 function format_article_note($id, $note, $allow_edit = true) {
c7e51de1 3380
fcfa9ef1
AD
3381 $str = "<div class='articleNote' onclick=\"editArticleNote($id)\">
3382 <div class='noteEdit' onclick=\"editArticleNote($id)\">".
16cbc19a 3383 ($allow_edit ? __('(edit note)') : "")."</div>$note</div>";
c7e51de1
AD
3384
3385 return $str;
3386 }
7f969260 3387
7e329f13 3388
d2a317e3
AD
3389 function get_feed_category($link, $feed_cat, $parent_cat_id = false) {
3390 if ($parent_cat_id) {
3391 $parent_qpart = "parent_cat = '$parent_cat_id'";
3392 $parent_insert = "'$parent_cat_id'";
3393 } else {
3394 $parent_qpart = "parent_cat IS NULL";
3395 $parent_insert = "NULL";
3396 }
3397
3398 $result = db_query($link,
3399 "SELECT id FROM ttrss_feed_categories
3400 WHERE $parent_qpart AND title = '$feed_cat' AND owner_uid = ".$_SESSION["uid"]);
3401
3402 if (db_num_rows($result) == 0) {
3403 return false;
3404 } else {
3405 return db_fetch_result($result, 0, "id");
3406 }
3407 }
3408
3409 function add_feed_category($link, $feed_cat, $parent_cat_id = false) {
c00907f2
AD
3410
3411 if (!$feed_cat) return false;
3412
5c7c7da9
AD
3413 db_query($link, "BEGIN");
3414
d2a317e3
AD
3415 if ($parent_cat_id) {
3416 $parent_qpart = "parent_cat = '$parent_cat_id'";
3417 $parent_insert = "'$parent_cat_id'";
3418 } else {
3419 $parent_qpart = "parent_cat IS NULL";
3420 $parent_insert = "NULL";
3421 }
3422
5c7c7da9
AD
3423 $result = db_query($link,
3424 "SELECT id FROM ttrss_feed_categories
d2a317e3 3425 WHERE $parent_qpart AND title = '$feed_cat' AND owner_uid = ".$_SESSION["uid"]);
5c7c7da9
AD
3426
3427 if (db_num_rows($result) == 0) {
8d505d78 3428
5c7c7da9 3429 $result = db_query($link,
d2a317e3
AD
3430 "INSERT INTO ttrss_feed_categories (owner_uid,title,parent_cat)
3431 VALUES ('".$_SESSION["uid"]."', '$feed_cat', $parent_insert)");
5c7c7da9
AD
3432
3433 db_query($link, "COMMIT");
3434
3435 return true;
3436 }
3437
3438 return false;
8d505d78 3439 }
5c7c7da9 3440
ab197ae1 3441 function getArticleFeed($link, $id) {
8d505d78 3442 $result = db_query($link, "SELECT feed_id FROM ttrss_user_entries
a545dc31 3443 WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"]);
ab197ae1
AD
3444
3445 if (db_num_rows($result) != 0) {
3446 return db_fetch_result($result, 0, "feed_id");
3447 } else {
3448 return 0;
3449 }
3450 }
a5819bb3 3451
f2c6c008
CW
3452 /**
3453 * Fixes incomplete URLs by prepending "http://".
f0266f51
CW
3454 * Also replaces feed:// with http://, and
3455 * prepends a trailing slash if the url is a domain name only.
f2c6c008
CW
3456 *
3457 * @param string $url Possibly incomplete URL
3458 *
3459 * @return string Fixed URL.
3460 */
3461 function fix_url($url) {
3462 if (strpos($url, '://') === false) {
3463 $url = 'http://' . $url;
f0266f51
CW
3464 } else if (substr($url, 0, 5) == 'feed:') {
3465 $url = 'http:' . substr($url, 5);
3466 }
3467
3468 //prepend slash if the URL has no slash in it
3469 // "http://www.example" -> "http://www.example/"
44453773 3470 if (strpos($url, '/', strpos($url, ':') + 3) === false) {
f0266f51 3471 $url .= '/';
f2c6c008 3472 }
ec39a02c
AD
3473
3474 if ($url != "http:///")
3475 return $url;
3476 else
3477 return '';
f2c6c008
CW
3478 }
3479
a5819bb3
AD
3480 function validate_feed_url($url) {
3481 $parts = parse_url($url);
3482
3483 return ($parts['scheme'] == 'http' || $parts['scheme'] == 'feed' || $parts['scheme'] == 'https');
3484
3485 }
d9084cf2 3486
be35798b
AD
3487 function get_article_enclosures($link, $id) {
3488
8d505d78 3489 $query = "SELECT * FROM ttrss_enclosures
be35798b
AD
3490 WHERE post_id = '$id' AND content_url != ''";
3491
be35798b
AD
3492 $rv = array();
3493
0e4a7d7a 3494 $result = db_query($link, $query);
be35798b 3495
0e4a7d7a
AD
3496 if (db_num_rows($result) > 0) {
3497 while ($line = db_fetch_assoc($result)) {
3498 array_push($rv, $line);
be35798b
AD
3499 }
3500 }
3501
3502 return $rv;
3503 }
3504
31a53903
AD
3505 function save_email_address($link, $email) {
3506 // FIXME: implement persistent storage of emails
3507
8d505d78 3508 if (!$_SESSION['stored_emails'])
31a53903
AD
3509 $_SESSION['stored_emails'] = array();
3510
3511 if (!in_array($email, $_SESSION['stored_emails']))
3512 array_push($_SESSION['stored_emails'], $email);
3513 }
8801fb01 3514
8801fb01
AD
3515
3516 function get_feed_access_key($link, $feed_id, $is_cat, $owner_uid = false) {
3517
3518 if (!$owner_uid) $owner_uid = $_SESSION["uid"];
3519
3520 $sql_is_cat = bool_to_sql_bool($is_cat);
3521
8d505d78
AD
3522 $result = db_query($link, "SELECT access_key FROM ttrss_access_keys
3523 WHERE feed_id = '$feed_id' AND is_cat = $sql_is_cat
8801fb01
AD
3524 AND owner_uid = " . $owner_uid);
3525
3526 if (db_num_rows($result) == 1) {
3527 return db_fetch_result($result, 0, "access_key");
3528 } else {
3529 $key = db_escape_string(sha1(uniqid(rand(), true)));
3530
8d505d78 3531 $result = db_query($link, "INSERT INTO ttrss_access_keys
8801fb01
AD
3532 (access_key, feed_id, is_cat, owner_uid)
3533 VALUES ('$key', '$feed_id', $sql_is_cat, '$owner_uid')");
3534
3535 return $key;
3536 }
3537 return false;
3538 }
f0266f51 3539
759e5132 3540 function get_feeds_from_html($url, $content)
f0266f51
CW
3541 {
3542 $url = fix_url($url);
3543 $baseUrl = substr($url, 0, strrpos($url, '/') + 1);
3544
fb074239
AD
3545 libxml_use_internal_errors(true);
3546
f0266f51 3547 $doc = new DOMDocument();
8d505d78 3548 $doc->loadHTML($content);
f0266f51
CW
3549 $xpath = new DOMXPath($doc);
3550 $entries = $xpath->query('/html/head/link[@rel="alternate"]');
3551 $feedUrls = array();
3552 foreach ($entries as $entry) {
3553 if ($entry->hasAttribute('href')) {
3554 $title = $entry->getAttribute('title');
3555 if ($title == '') {
3556 $title = $entry->getAttribute('type');
3557 }
923818fc
CW
3558 $feedUrl = rewrite_relative_url(
3559 $baseUrl, $entry->getAttribute('href')
3560 );
f0266f51
CW
3561 $feedUrls[$feedUrl] = $title;
3562 }
3563 }
3564 return $feedUrls;
3565 }
3566
759e5132 3567 function is_html($content) {
32b86711 3568 return preg_match("/<html|DOCTYPE html/i", substr($content, 0, 20)) !== 0;
759e5132 3569 }
f33479da 3570
759e5132
AD
3571 function url_is_html($url, $login = false, $pass = false) {
3572 return is_html(fetch_file_contents($url, false, $login, $pass));
f33479da 3573 }
24e2bb3a 3574
d90868d7 3575 function print_label_select($link, $name, $value, $attributes = "") {
24e2bb3a
AD
3576
3577 $result = db_query($link, "SELECT caption FROM ttrss_labels2
3578 WHERE owner_uid = '".$_SESSION["uid"]."' ORDER BY caption");
3579
8d505d78 3580 print "<select default=\"$value\" name=\"" . htmlspecialchars($name) .
d90868d7 3581 "\" $attributes onchange=\"labelSelectOnChange(this)\" >";
24e2bb3a
AD
3582
3583 while ($line = db_fetch_assoc($result)) {
3584
3585 $issel = ($line["caption"] == $value) ? "selected=\"1\"" : "";
3586
d90868d7
AD
3587 print "<option value=\"".htmlspecialchars($line["caption"])."\"
3588 $issel>" . htmlspecialchars($line["caption"]) . "</option>";
24e2bb3a
AD
3589
3590 }
3591
d90868d7 3592# print "<option value=\"ADD_LABEL\">" .__("Add label...") . "</option>";
24e2bb3a
AD
3593
3594 print "</select>";
3595
3596
3597 }
3598
009646d2 3599 function format_article_enclosures($link, $id, $always_display_enclosures,
dad14b51
AD
3600 $article_content) {
3601
3602 $result = get_article_enclosures($link, $id);
009646d2 3603 $rv = '';
8d505d78 3604
dad14b51 3605 if (count($result) > 0) {
8d505d78 3606
dad14b51
AD
3607 $entries_html = array();
3608 $entries = array();
ca3bca99 3609 $entries_inline = array();
8d505d78 3610
dad14b51 3611 foreach ($result as $line) {
8d505d78 3612
dad14b51
AD
3613 $url = $line["content_url"];
3614 $ctype = $line["content_type"];
8d505d78 3615
dad14b51 3616 if (!$ctype) $ctype = __("unknown type");
8d505d78 3617
749b56bd 3618 $filename = substr($url, strrpos($url, "/")+1);
8d505d78 3619
ca3bca99
AD
3620 $player = format_inline_player($link, $url, $ctype);
3621
3622 if ($player) array_push($entries_inline, $player);
8d505d78 3623
c3edc667
AD
3624# $entry .= " <a target=\"_blank\" href=\"" . htmlspecialchars($url) . "\">" .
3625# $filename . " (" . $ctype . ")" . "</a>";
8d505d78 3626
749b56bd
AD
3627 $entry = "<div onclick=\"window.open('".htmlspecialchars($url)."')\"
3628 dojoType=\"dijit.MenuItem\">$filename ($ctype)</div>";
3629
dad14b51 3630 array_push($entries_html, $entry);
8d505d78 3631
dad14b51 3632 $entry = array();
8d505d78 3633
dad14b51
AD
3634 $entry["type"] = $ctype;
3635 $entry["filename"] = $filename;
3636 $entry["url"] = $url;
8d505d78 3637
dad14b51
AD
3638 array_push($entries, $entry);
3639 }
8d505d78 3640
f0540b59 3641 if ($_SESSION['uid'] && !get_pref($link, "STRIP_IMAGES")) {
dad14b51
AD
3642 if ($always_display_enclosures ||
3643 !preg_match("/<img/i", $article_content)) {
8d505d78 3644
dad14b51 3645 foreach ($entries as $entry) {
8d505d78 3646
dad14b51
AD
3647 if (preg_match("/image/", $entry["type"]) ||
3648 preg_match("/\.(jpg|png|gif|bmp)/i", $entry["filename"])) {
8d505d78 3649
009646d2 3650 $rv .= "<p><img
dad14b51
AD
3651 alt=\"".htmlspecialchars($entry["filename"])."\"
3652 src=\"" .htmlspecialchars($entry["url"]) . "\"/></p>";
749b56bd 3653
dad14b51
AD
3654 }
3655 }
3656 }
3657 }
8d505d78 3658
ca3bca99
AD
3659 if (count($entries_inline) > 0) {
3660 $rv .= "<hr clear='both'/>";
3661 foreach ($entries_inline as $entry) { $rv .= $entry; };
3662 $rv .= "<hr clear='both'/>";
3663 }
3664
2a3d00bb 3665 $rv .= "<br/><div dojoType=\"dijit.form.DropDownButton\">".
749b56bd
AD
3666 "<span>" . __('Attachments')."</span>";
3667 $rv .= "<div dojoType=\"dijit.Menu\" style=\"display: none;\">";
8d505d78 3668
749b56bd 3669 foreach ($entries_html as $entry) { $rv .= $entry; };
8d505d78 3670
749b56bd 3671 $rv .= "</div></div>";
dad14b51 3672 }
009646d2
AD
3673
3674 return $rv;
dad14b51
AD
3675 }
3676
f8fb4498
AD
3677 function getLastArticleId($link) {
3678 $result = db_query($link, "SELECT MAX(ref_id) AS id FROM ttrss_user_entries
3679 WHERE owner_uid = " . $_SESSION["uid"]);
3680
3681 if (db_num_rows($result) == 1) {
3682 return db_fetch_result($result, 0, "id");
3683 } else {
3684 return -1;
3685 }
3686 }
8cc3c778
AD
3687
3688 function build_url($parts) {
3689 return $parts['scheme'] . "://" . $parts['host'] . $parts['path'];
3690 }
3691
f679105c
CW
3692 /**
3693 * Converts a (possibly) relative URL to a absolute one.
3694 *
3695 * @param string $url Base URL (i.e. from where the document is)
3696 * @param string $rel_url Possibly relative URL in the document
3697 *
3698 * @return string Absolute URL
3699 */
8cc3c778 3700 function rewrite_relative_url($url, $rel_url) {
b4520bb8
AD
3701 if (strpos($rel_url, "magnet:") === 0) {
3702 return $rel_url;
3703 } else if (strpos($rel_url, "://") !== false) {
8cc3c778 3704 return $rel_url;
f9052d35 3705 } else if (strpos($rel_url, "//") === 0) {
3706 # protocol-relative URL (rare but they exist)
3707 return $rel_url;
8d505d78 3708 } else if (strpos($rel_url, "/") === 0)
8cc3c778
AD
3709 {
3710 $parts = parse_url($url);
3711 $parts['path'] = $rel_url;
3712
3713 return build_url($parts);
3714
3715 } else {
3716 $parts = parse_url($url);
f679105c
CW
3717 if (!isset($parts['path'])) {
3718 $parts['path'] = '/';
3719 }
3720 $dir = $parts['path'];
3721 if (substr($dir, -1) !== '/') {
3722 $dir = dirname($parts['path']);
3723 $dir !== '/' && $dir .= '/';
3724 }
3725 $parts['path'] = $dir . $rel_url;
8cc3c778
AD
3726
3727 return build_url($parts);
3728 }
3729 }
3730
e4f7f8df 3731 function sphinx_search($query, $offset = 0, $limit = 30) {
31303c6b
AD
3732 require_once 'lib/sphinxapi.php';
3733
e4f7f8df
AD
3734 $sphinxClient = new SphinxClient();
3735
3736 $sphinxClient->SetServer('localhost', 9312);
3737 $sphinxClient->SetConnectTimeout(1);
3738
8d505d78 3739 $sphinxClient->SetFieldWeights(array('title' => 70, 'content' => 30,
e4f7f8df
AD
3740 'feed_title' => 20));
3741
3742 $sphinxClient->SetMatchMode(SPH_MATCH_EXTENDED2);
3743 $sphinxClient->SetRankingMode(SPH_RANK_PROXIMITY_BM25);
3744 $sphinxClient->SetLimits($offset, $limit, 1000);
3745 $sphinxClient->SetArrayResult(false);
3746 $sphinxClient->SetFilter('owner_uid', array($_SESSION['uid']));
8d505d78 3747
e4f7f8df
AD
3748 $result = $sphinxClient->Query($query, SPHINX_INDEX);
3749
3750 $ids = array();
3751
3752 if (is_array($result['matches'])) {
3753 foreach (array_keys($result['matches']) as $int_id) {
3754 $ref_id = $result['matches'][$int_id]['attrs']['ref_id'];
3755 array_push($ids, $ref_id);
3756 }
3757 }
3758
3759 return $ids;
3760 }
3761
868650e4
AD
3762 function cleanup_tags($link, $days = 14, $limit = 1000) {
3763
3764 if (DB_TYPE == "pgsql") {
3765 $interval_query = "date_updated < NOW() - INTERVAL '$days days'";
3766 } else if (DB_TYPE == "mysql") {
3767 $interval_query = "date_updated < DATE_SUB(NOW(), INTERVAL $days DAY)";
3768 }
3769
b5ec13fa 3770 $tags_deleted = 0;
868650e4 3771
b5ec13fa
AD
3772 while ($limit > 0) {
3773 $limit_part = 500;
3774
8d505d78
AD
3775 $query = "SELECT ttrss_tags.id AS id
3776 FROM ttrss_tags, ttrss_user_entries, ttrss_entries
b5ec13fa
AD
3777 WHERE post_int_id = int_id AND $interval_query AND
3778 ref_id = ttrss_entries.id AND tag_cache != '' LIMIT $limit_part";
8d505d78 3779
b5ec13fa
AD
3780 $result = db_query($link, $query);
3781
3782 $ids = array();
3783
3784 while ($line = db_fetch_assoc($result)) {
3785 array_push($ids, $line['id']);
3786 }
3787
3788 if (count($ids) > 0) {
3789 $ids = join(",", $ids);
3790 print ".";
3791
3792 $tmp_result = db_query($link, "DELETE FROM ttrss_tags WHERE id IN ($ids)");
3793 $tags_deleted += db_affected_rows($link, $tmp_result);
3794 } else {
3795 break;
3796 }
3797
3798 $limit -= $limit_part;
3799 }
3800
3801 print "\n";
868650e4 3802
b5ec13fa 3803 return $tags_deleted;
868650e4
AD
3804 }
3805
88e4e597
AD
3806 function print_user_stylesheet($link) {
3807 $value = get_pref($link, 'USER_STYLESHEET');
3808
3809 if ($value) {
3810 print "<style type=\"text/css\">";
5823f9fb 3811 print str_replace("<br/>", "\n", $value);
88e4e597
AD
3812 print "</style>";
3813 }
3814
3815 }
3816
73c32678
AD
3817 function rewrite_urls($html) {
3818 libxml_use_internal_errors(true);
3819
3820 $charset_hack = '<head>
3821 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
3822 </head>';
3823
3824 $doc = new DOMDocument();
3825 $doc->loadHTML($charset_hack . $html);
3826 $xpath = new DOMXPath($doc);
3827
3828 $entries = $xpath->query('//*/text()');
3829
3830 foreach ($entries as $entry) {
3831 if (strstr($entry->wholeText, "://") !== false) {
3832 $text = preg_replace("/((?<!=.)((http|https|ftp)+):\/\/[^ ,!]+)/i",
3833 "<a target=\"_blank\" href=\"\\1\">\\1</a>", $entry->wholeText);
3834
3835 if ($text != $entry->wholeText) {
3836 $cdoc = new DOMDocument();
3837 $cdoc->loadHTML($charset_hack . $text);
3838
3839
3840 foreach ($cdoc->childNodes as $cnode) {
3841 $cnode = $doc->importNode($cnode, true);
3842
3843 if ($cnode) {
3844 $entry->parentNode->insertBefore($cnode);
3845 }
3846 }
3847
3848 $entry->parentNode->removeChild($entry);
3849
3850 }
3851 }
3852 }
3853
3854 $node = $doc->getElementsByTagName('body')->item(0);
3855
376897af
AD
3856 // http://tt-rss.org/forum/viewtopic.php?f=1&t=970
3857 if ($node)
cc38c8e5 3858 return $doc->saveXML($node);
376897af
AD
3859 else
3860 return $html;
533c0ea6
AD
3861 }
3862
2680295b 3863 function filter_to_sql($link, $filter, $owner_uid) {
4e02f582 3864 $query = array();
36184020 3865
4e02f582
AD
3866 if (DB_TYPE == "pgsql")
3867 $reg_qpart = "~";
3868 else
3869 $reg_qpart = "REGEXP";
36184020 3870
4e02f582
AD
3871 foreach ($filter["rules"] AS $rule) {
3872 $regexp_valid = preg_match('/' . $rule['reg_exp'] . '/',
3873 $rule['reg_exp']) !== FALSE;
36184020 3874
4e02f582 3875 if ($regexp_valid) {
36184020 3876
4e02f582 3877 $rule['reg_exp'] = db_escape_string($rule['reg_exp']);
36184020 3878
4e02f582
AD
3879 switch ($rule["type"]) {
3880 case "title":
3881 $qpart = "LOWER(ttrss_entries.title) $reg_qpart LOWER('".
3882 $rule['reg_exp'] . "')";
3883 break;
3884 case "content":
3885 $qpart = "LOWER(ttrss_entries.content) $reg_qpart LOWER('".
3886 $rule['reg_exp'] . "')";
3887 break;
3888 case "both":
3889 $qpart = "LOWER(ttrss_entries.title) $reg_qpart LOWER('".
3890 $rule['reg_exp'] . "') OR LOWER(" .
3891 "ttrss_entries.content) $reg_qpart LOWER('" . $rule['reg_exp'] . "')";
3892 break;
3893 case "tag":
3894 $qpart = "LOWER(ttrss_user_entries.tag_cache) $reg_qpart LOWER('".
3895 $rule['reg_exp'] . "')";
3896 break;
3897 case "link":
3898 $qpart = "LOWER(ttrss_entries.link) $reg_qpart LOWER('".
3899 $rule['reg_exp'] . "')";
3900 break;
3901 case "author":
3902 $qpart = "LOWER(ttrss_entries.author) $reg_qpart LOWER('".
3903 $rule['reg_exp'] . "')";
3904 break;
3905 }
36184020 3906
6b218731
AD
3907 if (isset($rule["feed_id"]) && $rule["feed_id"] > 0) {
3908 $qpart .= " AND feed_id = " . db_escape_string($rule["feed_id"]);
4e02f582 3909 }
6b8b3af8 3910
4e02f582 3911 if (isset($rule["cat_id"])) {
2680295b
AD
3912
3913 if ($rule["cat_id"] > 0) {
3914 $children = getChildCategories($link, $rule["cat_id"], $owner_uid);
3915 array_push($children, $rule["cat_id"]);
3916
3917 $children = join(",", $children);
3918
3919 $cat_qpart = "cat_id IN ($children)";
3920 } else {
3921 $cat_qpart = "cat_id IS NULL";
3922 }
3923
3924 $qpart .= " AND $cat_qpart";
56fbb82c 3925 }
4e02f582
AD
3926
3927 array_push($query, "($qpart)");
3928
56fbb82c 3929 }
4e02f582 3930 }
56fbb82c 3931
4e02f582
AD
3932 if (count($query) > 0) {
3933 return "(" . join($filter["match_any_rule"] ? "OR" : "AND", $query) . ")";
56fbb82c 3934 } else {
4e02f582 3935 return "(false)";
56fbb82c 3936 }
36184020 3937 }
ae5f7bb1 3938
3382bce1
AD
3939 if (!function_exists('gzdecode')) {
3940 function gzdecode($string) { // no support for 2nd argument
3941 return file_get_contents('compress.zlib://data:who/cares;base64,'.
3942 base64_encode($string));
3943 }
3944 }
3945
8db5d8ea
AD
3946 function get_random_bytes($length) {
3947 if (function_exists('openssl_random_pseudo_bytes')) {
3948 return openssl_random_pseudo_bytes($length);
3949 } else {
3950 $output = "";
3951
3952 for ($i = 0; $i < $length; $i++)
3953 $output .= chr(mt_rand(0, 255));
3954
3955 return $output;
3956 }
3957 }
871f0a7a
AD
3958
3959 function read_stdin() {
3960 $fp = fopen("php://stdin", "r");
3961
3962 if ($fp) {
3963 $line = trim(fgets($fp));
3964 fclose($fp);
3965 return $line;
3966 }
3967
3968 return null;
3969 }
e3449aa1
AD
3970
3971 function tmpdirname($path, $prefix) {
3972 // Use PHP's tmpfile function to create a temporary
3973 // directory name. Delete the file and keep the name.
3974 $tempname = tempnam($path,$prefix);
3975 if (!$tempname)
3976 return false;
3977
3978 if (!unlink($tempname))
3979 return false;
3980
3981 return $tempname;
3982 }
3983
6aff7845
AD
3984 function getFeedCategory($link, $feed) {
3985 $result = db_query($link, "SELECT cat_id FROM ttrss_feeds
3986 WHERE id = '$feed'");
3987
3988 if (db_num_rows($result) > 0) {
3989 return db_fetch_result($result, 0, "cat_id");
3990 } else {
3991 return false;
3992 }
3993
3994 }
3995
8dcb2b47
AD
3996 function implements_interface($class, $interface) {
3997 return in_array($interface, class_implements($class));
3998 }
e88c1943 3999
e2b0054b
AD
4000 function geturl($url){
4001
4002 (function_exists('curl_init')) ? '' : die('cURL Must be installed for geturl function to work. Ask your host to enable it or uncomment extension=php_curl.dll in php.ini');
4003
4004 $curl = curl_init();
4005 $header[0] = "Accept: text/xml,application/xml,application/xhtml+xml,";
4006 $header[0] .= "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
4007 $header[] = "Cache-Control: max-age=0";
4008 $header[] = "Connection: keep-alive";
4009 $header[] = "Keep-Alive: 300";
4010 $header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7";
4011 $header[] = "Accept-Language: en-us,en;q=0.5";
4012 $header[] = "Pragma: ";
4013
4014 curl_setopt($curl, CURLOPT_URL, $url);
4015 curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0 Firefox/5.0');
4016 curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
4017 curl_setopt($curl, CURLOPT_HEADER, true);
4018 curl_setopt($curl, CURLOPT_REFERER, $url);
4019 curl_setopt($curl, CURLOPT_ENCODING, 'gzip,deflate');
4020 curl_setopt($curl, CURLOPT_AUTOREFERER, true);
4021 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
4022 //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); //CURLOPT_FOLLOWLOCATION Disabled...
4023 curl_setopt($curl, CURLOPT_TIMEOUT, 60);
4024
4025 $html = curl_exec($curl);
4026
4027 $status = curl_getinfo($curl);
4028 curl_close($curl);
4029
4030 if($status['http_code']!=200){
4031 if($status['http_code'] == 301 || $status['http_code'] == 302) {
4032 list($header) = explode("\r\n\r\n", $html, 2);
4033 $matches = array();
4034 preg_match("/(Location:|URI:)[^(\n)]*/", $header, $matches);
4035 $url = trim(str_replace($matches[1],"",$matches[0]));
4036 $url_parsed = parse_url($url);
4037 return (isset($url_parsed))? geturl($url, $referer):'';
4038 }
4039 $oline='';
4040 foreach($status as $key=>$eline){$oline.='['.$key.']'.$eline.' ';}
4041 $line =$oline." \r\n ".$url."\r\n-----------------\r\n";
911845b5
AD
4042# $handle = @fopen('./curl.error.log', 'a');
4043# fwrite($handle, $line);
e2b0054b
AD
4044 return FALSE;
4045 }
4046 return $url;
4047 }
8dcb2b47 4048
c670a80d
AD
4049 function get_minified_js($files) {
4050 require_once 'lib/jshrink/Minifier.php';
4051
4052 $rv = '';
4053
4054 foreach ($files as $js) {
4055 if (!isset($_GET['debug'])) {
4056 $cached_file = CACHE_DIR . "/js/$js.js";
4057
4058 if (file_exists($cached_file) &&
4059 is_readable($cached_file) &&
4060 filemtime($cached_file) >= filemtime("js/$js.js")) {
4061
4062 $rv .= file_get_contents($cached_file);
4063
4064 } else {
4065 $minified = JShrink\Minifier::minify(file_get_contents("js/$js.js"));
4066 file_put_contents($cached_file, $minified);
4067 $rv .= $minified;
4068 }
4069 } else {
4070 $rv .= file_get_contents("js/$js.js");
4071 }
4072 }
4073
4074 return $rv;
4075 }
4076
b5d4716a
AD
4077 function stylesheet_tag($filename) {
4078 $timestamp = filemtime($filename);
4079
4080 echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"$filename?$timestamp\"/>\n";
4081 }
4082
4083 function javascript_tag($filename) {
4084 $query = "";
4085
4086 if (!(strpos($filename, "?") === FALSE)) {
4087 $query = substr($filename, strpos($filename, "?")+1);
4088 $filename = substr($filename, 0, strpos($filename, "?"));
4089 }
4090
4091 $timestamp = filemtime($filename);
4092
4093 if ($query) $timestamp .= "&$query";
4094
4095 echo "<script type=\"text/javascript\" charset=\"utf-8\" src=\"$filename?$timestamp\"></script>\n";
4096 }
4097
8c0496f7 4098?>