Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1171 lines
32 KiB

11 years ago
10 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
10 years ago
11 years ago
11 years ago
10 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
  1. <?php
  2. require_once('include/config.php');
  3. require_once('include/network.php');
  4. require_once('include/plugin.php');
  5. require_once('include/text.php');
  6. require_once("include/pgettext.php");
  7. define ( 'FRIENDIKA_VERSION', '2.2.1080' );
  8. define ( 'DFRN_PROTOCOL_VERSION', '2.21' );
  9. define ( 'DB_UPDATE_VERSION', 1081 );
  10. define ( 'EOL', "<br />\r\n" );
  11. define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' );
  12. /**
  13. *
  14. * Image storage quality. Lower numbers save space at cost of image detail.
  15. * For ease of upgrade, please do not change here. Change jpeg quality with
  16. * set_config('system','jpeg_quality',n) in .htconfig.php
  17. * where n is netween 1 and 100, and with very poor results below about 50
  18. *
  19. */
  20. define ( 'JPEG_QUALITY', 100 );
  21. /**
  22. * SSL redirection policies
  23. */
  24. define ( 'SSL_POLICY_NONE', 0 );
  25. define ( 'SSL_POLICY_FULL', 1 );
  26. define ( 'SSL_POLICY_SELFSIGN', 2 );
  27. /**
  28. * log levels
  29. */
  30. define ( 'LOGGER_NORMAL', 0 );
  31. define ( 'LOGGER_TRACE', 1 );
  32. define ( 'LOGGER_DEBUG', 2 );
  33. define ( 'LOGGER_DATA', 3 );
  34. define ( 'LOGGER_ALL', 4 );
  35. /**
  36. * registration policies
  37. */
  38. define ( 'REGISTER_CLOSED', 0 );
  39. define ( 'REGISTER_APPROVE', 1 );
  40. define ( 'REGISTER_OPEN', 2 );
  41. /**
  42. * relationship types
  43. */
  44. define ( 'CONTACT_IS_FOLLOWER', 1);
  45. define ( 'CONTACT_IS_SHARING', 2);
  46. define ( 'CONTACT_IS_FRIEND', 3);
  47. /**
  48. * Hook array order
  49. */
  50. define ( 'HOOK_HOOK', 0);
  51. define ( 'HOOK_FILE', 1);
  52. define ( 'HOOK_FUNCTION', 2);
  53. /**
  54. *
  55. * page/profile types
  56. *
  57. * PAGE_NORMAL is a typical personal profile account
  58. * PAGE_SOAPBOX automatically approves all friend requests as CONTACT_IS_SHARING, (readonly)
  59. * PAGE_COMMUNITY automatically approves all friend requests as CONTACT_IS_SHARING, but with
  60. * write access to wall and comments (no email and not included in page owner's ACL lists)
  61. * PAGE_FREELOVE automatically approves all friend requests as full friends (CONTACT_IS_FRIEND).
  62. *
  63. */
  64. define ( 'PAGE_NORMAL', 0 );
  65. define ( 'PAGE_SOAPBOX', 1 );
  66. define ( 'PAGE_COMMUNITY', 2 );
  67. define ( 'PAGE_FREELOVE', 3 );
  68. /**
  69. * Network and protocol family types
  70. */
  71. define ( 'NETWORK_ZOT', 'zot!'); // Zot!
  72. define ( 'NETWORK_DFRN', 'dfrn'); // Friendika, Mistpark, other DFRN implementations
  73. define ( 'NETWORK_OSTATUS', 'stat'); // status.net, identi.ca, GNU-social, other OStatus implementations
  74. define ( 'NETWORK_FEED', 'feed'); // RSS/Atom feeds with no known "post/notify" protocol
  75. define ( 'NETWORK_DIASPORA', 'dspr'); // Diaspora
  76. define ( 'NETWORK_MAIL', 'mail'); // IMAP/POP
  77. define ( 'NETWORK_FACEBOOK', 'face'); // Facebook API
  78. /**
  79. * Maximum number of "people who like (or don't like) this" that we will list by name
  80. */
  81. define ( 'MAX_LIKERS', 75);
  82. /**
  83. * Communication timeout
  84. */
  85. define ( 'ZCURL_TIMEOUT' , (-1));
  86. /**
  87. * email notification options
  88. */
  89. define ( 'NOTIFY_INTRO', 0x0001 );
  90. define ( 'NOTIFY_CONFIRM', 0x0002 );
  91. define ( 'NOTIFY_WALL', 0x0004 );
  92. define ( 'NOTIFY_COMMENT', 0x0008 );
  93. define ( 'NOTIFY_MAIL', 0x0010 );
  94. /**
  95. * various namespaces we may need to parse
  96. */
  97. define ( 'NAMESPACE_ZOT', 'http://purl.org/macgirvin/zot' );
  98. define ( 'NAMESPACE_DFRN' , 'http://purl.org/macgirvin/dfrn/1.0' );
  99. define ( 'NAMESPACE_THREAD' , 'http://purl.org/syndication/thread/1.0' );
  100. define ( 'NAMESPACE_TOMB' , 'http://purl.org/atompub/tombstones/1.0' );
  101. define ( 'NAMESPACE_ACTIVITY', 'http://activitystrea.ms/spec/1.0/' );
  102. define ( 'NAMESPACE_ACTIVITY_SCHEMA', 'http://activitystrea.ms/schema/1.0/' );
  103. define ( 'NAMESPACE_MEDIA', 'http://purl.org/syndication/atommedia' );
  104. define ( 'NAMESPACE_SALMON_ME', 'http://salmon-protocol.org/ns/magic-env' );
  105. define ( 'NAMESPACE_OSTATUSSUB', 'http://ostatus.org/schema/1.0/subscribe' );
  106. define ( 'NAMESPACE_GEORSS', 'http://www.georss.org/georss' );
  107. define ( 'NAMESPACE_POCO', 'http://portablecontacts.net/spec/1.0' );
  108. define ( 'NAMESPACE_FEED', 'http://schemas.google.com/g/2010#updates-from' );
  109. define ( 'NAMESPACE_OSTATUS', 'http://ostatus.org/schema/1.0' );
  110. define ( 'NAMESPACE_STATUSNET', 'http://status.net/schema/api/1/' );
  111. define ( 'NAMESPACE_ATOM1', 'http://www.w3.org/2005/Atom' );
  112. /**
  113. * activity stream defines
  114. */
  115. define ( 'ACTIVITY_LIKE', NAMESPACE_ACTIVITY_SCHEMA . 'like' );
  116. define ( 'ACTIVITY_DISLIKE', NAMESPACE_DFRN . '/dislike' );
  117. define ( 'ACTIVITY_OBJ_HEART', NAMESPACE_DFRN . '/heart' );
  118. define ( 'ACTIVITY_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'make-friend' );
  119. define ( 'ACTIVITY_FOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'follow' );
  120. define ( 'ACTIVITY_UNFOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'stop-following' );
  121. define ( 'ACTIVITY_POST', NAMESPACE_ACTIVITY_SCHEMA . 'post' );
  122. define ( 'ACTIVITY_UPDATE', NAMESPACE_ACTIVITY_SCHEMA . 'update' );
  123. define ( 'ACTIVITY_TAG', NAMESPACE_ACTIVITY_SCHEMA . 'tag' );
  124. define ( 'ACTIVITY_OBJ_COMMENT', NAMESPACE_ACTIVITY_SCHEMA . 'comment' );
  125. define ( 'ACTIVITY_OBJ_NOTE', NAMESPACE_ACTIVITY_SCHEMA . 'note' );
  126. define ( 'ACTIVITY_OBJ_PERSON', NAMESPACE_ACTIVITY_SCHEMA . 'person' );
  127. define ( 'ACTIVITY_OBJ_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'photo' );
  128. define ( 'ACTIVITY_OBJ_P_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'profile-photo' );
  129. define ( 'ACTIVITY_OBJ_ALBUM', NAMESPACE_ACTIVITY_SCHEMA . 'photo-album' );
  130. define ( 'ACTIVITY_OBJ_EVENT', NAMESPACE_ACTIVITY_SCHEMA . 'event' );
  131. /**
  132. * item weight for query ordering
  133. */
  134. define ( 'GRAVITY_PARENT', 0);
  135. define ( 'GRAVITY_LIKE', 3);
  136. define ( 'GRAVITY_COMMENT', 6);
  137. /**
  138. *
  139. * Reverse the effect of magic_quotes_gpc if it is enabled.
  140. * Please disable magic_quotes_gpc so we don't have to do this.
  141. * See http://php.net/manual/en/security.magicquotes.disabling.php
  142. *
  143. */
  144. function startup() {
  145. error_reporting(E_ERROR | E_WARNING | E_PARSE);
  146. set_time_limit(0);
  147. ini_set('pcre.backtrack_limit', 250000);
  148. if (get_magic_quotes_gpc()) {
  149. $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
  150. while (list($key, $val) = each($process)) {
  151. foreach ($val as $k => $v) {
  152. unset($process[$key][$k]);
  153. if (is_array($v)) {
  154. $process[$key][stripslashes($k)] = $v;
  155. $process[] = &$process[$key][stripslashes($k)];
  156. } else {
  157. $process[$key][stripslashes($k)] = stripslashes($v);
  158. }
  159. }
  160. }
  161. unset($process);
  162. }
  163. }
  164. /**
  165. *
  166. * class: App
  167. *
  168. * Our main application structure for the life of this page
  169. * Primarily deals with the URL that got us here
  170. * and tries to make some sense of it, and
  171. * stores our page contents and config storage
  172. * and anything else that might need to be passed around
  173. * before we spit the page out.
  174. *
  175. */
  176. if(! class_exists('App')) {
  177. class App {
  178. public $module_loaded = false;
  179. public $query_string;
  180. public $config;
  181. public $page;
  182. public $profile;
  183. public $user;
  184. public $cid;
  185. public $contact;
  186. public $contacts;
  187. public $page_contact;
  188. public $content;
  189. public $data;
  190. public $error = false;
  191. public $cmd;
  192. public $argv;
  193. public $argc;
  194. public $module;
  195. public $pager;
  196. public $strings;
  197. public $path;
  198. public $hooks;
  199. public $timezone;
  200. public $interactive = true;
  201. public $plugins;
  202. public $apps;
  203. public $identities;
  204. private $scheme;
  205. private $hostname;
  206. private $baseurl;
  207. private $db;
  208. private $curl_code;
  209. private $curl_headers;
  210. function __construct() {
  211. $this->config = array();
  212. $this->page = array();
  213. $this->pager= array();
  214. $this->query_string = '';
  215. startup();
  216. $this->scheme = ((isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'])) ? 'https' : 'http' );
  217. if(x($_SERVER,'SERVER_NAME')) {
  218. $this->hostname = $_SERVER['SERVER_NAME'];
  219. if(x($_SERVER,'SERVER_PORT') && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443)
  220. $this->hostname .= ':' . $_SERVER['SERVER_PORT'];
  221. /**
  222. * Figure out if we are running at the top of a domain
  223. * or in a sub-directory and adjust accordingly
  224. */
  225. $path = trim(dirname($_SERVER['SCRIPT_NAME']),'/\\');
  226. if(isset($path) && strlen($path) && ($path != $this->path))
  227. $this->path = $path;
  228. }
  229. set_include_path(
  230. "include/$this->hostname" . PATH_SEPARATOR
  231. . 'include' . PATH_SEPARATOR
  232. . 'library' . PATH_SEPARATOR
  233. . 'library/phpsec' . PATH_SEPARATOR
  234. . '.' );
  235. if((x($_SERVER,'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'],0,2) === "q=")
  236. $this->query_string = substr($_SERVER['QUERY_STRING'],2);
  237. if(x($_GET,'q'))
  238. $this->cmd = trim($_GET['q'],'/\\');
  239. /**
  240. *
  241. * Break the URL path into C style argc/argv style arguments for our
  242. * modules. Given "http://example.com/module/arg1/arg2", $this->argc
  243. * will be 3 (integer) and $this->argv will contain:
  244. * [0] => 'module'
  245. * [1] => 'arg1'
  246. * [2] => 'arg2'
  247. *
  248. *
  249. * There will always be one argument. If provided a naked domain
  250. * URL, $this->argv[0] is set to "home".
  251. *
  252. */
  253. $this->argv = explode('/',$this->cmd);
  254. $this->argc = count($this->argv);
  255. if((array_key_exists('0',$this->argv)) && strlen($this->argv[0])) {
  256. $this->module = str_replace(".", "_", $this->argv[0]);
  257. }
  258. else {
  259. $this->argc = 1;
  260. $this->argv = array('home');
  261. $this->module = 'home';
  262. }
  263. /**
  264. * Special handling for the webfinger/lrdd host XRD file
  265. */
  266. if($this->cmd === '.well-known/host-meta') {
  267. $this->argc = 1;
  268. $this->argv = array('hostxrd');
  269. $this->module = 'hostxrd';
  270. }
  271. /**
  272. * See if there is any page number information, and initialise
  273. * pagination
  274. */
  275. $this->pager['page'] = ((x($_GET,'page')) ? $_GET['page'] : 1);
  276. $this->pager['itemspage'] = 50;
  277. $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage'];
  278. $this->pager['total'] = 0;
  279. }
  280. function get_baseurl($ssl = false) {
  281. $scheme = $this->scheme;
  282. if(x($this->config,'ssl_policy')) {
  283. if(($ssl) || ($this->config['ssl_policy'] == SSL_POLICY_FULL))
  284. $scheme = 'https';
  285. if(($this->config['ssl_policy'] == SSL_POLICY_SELFSIGN) && (local_user() || x($_POST,'auth-params')))
  286. $scheme = 'https';
  287. }
  288. $this->baseurl = $scheme . "://" . $this->hostname . ((isset($this->path) && strlen($this->path)) ? '/' . $this->path : '' );
  289. return $this->baseurl;
  290. }
  291. function set_baseurl($url) {
  292. $parsed = @parse_url($url);
  293. $this->baseurl = $url;
  294. if($parsed) {
  295. $this->scheme = $parsed['scheme'];
  296. $this->hostname = $parsed['host'];
  297. if(x($parsed,'port'))
  298. $this->hostname .= ':' . $parsed['port'];
  299. if(x($parsed,'path'))
  300. $this->path = trim($parsed['path'],'\\/');
  301. }
  302. }
  303. function get_hostname() {
  304. return $this->hostname;
  305. }
  306. function set_hostname($h) {
  307. $this->hostname = $h;
  308. }
  309. function set_path($p) {
  310. $this->path = trim(trim($p),'/');
  311. }
  312. function get_path() {
  313. return $this->path;
  314. }
  315. function set_pager_total($n) {
  316. $this->pager['total'] = intval($n);
  317. }
  318. function set_pager_itemspage($n) {
  319. $this->pager['itemspage'] = intval($n);
  320. $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage'];
  321. }
  322. function init_pagehead() {
  323. $this->page['title'] = $this->config['sitename'];
  324. $tpl = file_get_contents('view/head.tpl');
  325. $this->page['htmlhead'] = replace_macros($tpl,array(
  326. '$baseurl' => $this->get_baseurl(), // FIXME for z_path!!!!
  327. '$generator' => 'Friendika' . ' ' . FRIENDIKA_VERSION,
  328. '$delitem' => t('Delete this item?'),
  329. '$comment' => t('Comment')
  330. ));
  331. }
  332. function set_curl_code($code) {
  333. $this->curl_code = $code;
  334. }
  335. function get_curl_code() {
  336. return $this->curl_code;
  337. }
  338. function set_curl_headers($headers) {
  339. $this->curl_headers = $headers;
  340. }
  341. function get_curl_headers() {
  342. return $this->curl_headers;
  343. }
  344. }}
  345. // retrieve the App structure
  346. // useful in functions which require it but don't get it passed to them
  347. if(! function_exists('get_app')) {
  348. function get_app() {
  349. global $a;
  350. return $a;
  351. }};
  352. // Multi-purpose function to check variable state.
  353. // Usage: x($var) or $x($array,'key')
  354. // returns false if variable/key is not set
  355. // if variable is set, returns 1 if has 'non-zero' value, otherwise returns 0.
  356. // e.g. x('') or x(0) returns 0;
  357. if(! function_exists('x')) {
  358. function x($s,$k = NULL) {
  359. if($k != NULL) {
  360. if((is_array($s)) && (array_key_exists($k,$s))) {
  361. if($s[$k])
  362. return (int) 1;
  363. return (int) 0;
  364. }
  365. return false;
  366. }
  367. else {
  368. if(isset($s)) {
  369. if($s) {
  370. return (int) 1;
  371. }
  372. return (int) 0;
  373. }
  374. return false;
  375. }
  376. }}
  377. // called from db initialisation if db is dead.
  378. if(! function_exists('system_unavailable')) {
  379. function system_unavailable() {
  380. include('system_unavailable.php');
  381. system_down();
  382. killme();
  383. }}
  384. function clean_urls() {
  385. global $a;
  386. // if($a->config['system']['clean_urls'])
  387. return true;
  388. // return false;
  389. }
  390. function z_path() {
  391. global $a;
  392. $base = $a->get_baseurl();
  393. if(! clean_urls())
  394. $base .= '/?q=';
  395. return $base;
  396. }
  397. function z_root() {
  398. global $a;
  399. return $a->get_baseurl();
  400. }
  401. function absurl($path) {
  402. if(strpos($path,'/') === 0)
  403. return z_path() . $path;
  404. return $path;
  405. }
  406. // Primarily involved with database upgrade, but also sets the
  407. // base url for use in cmdline programs which don't have
  408. // $_SERVER variables, and synchronising the state of installed plugins.
  409. if(! function_exists('check_config')) {
  410. function check_config(&$a) {
  411. $build = get_config('system','build');
  412. if(! x($build))
  413. $build = set_config('system','build',DB_UPDATE_VERSION);
  414. $url = get_config('system','url');
  415. // if the url isn't set or the stored url is radically different
  416. // than the currently visited url, store the current value accordingly.
  417. // "Radically different" ignores common variations such as http vs https
  418. // and www.example.com vs example.com.
  419. if((! x($url)) || (! link_compare($url,$a->get_baseurl())))
  420. $url = set_config('system','url',$a->get_baseurl());
  421. if($build != DB_UPDATE_VERSION) {
  422. $stored = intval($build);
  423. $current = intval(DB_UPDATE_VERSION);
  424. if(($stored < $current) && file_exists('update.php')) {
  425. // We're reporting a different version than what is currently installed.
  426. // Run any existing update scripts to bring the database up to current.
  427. require_once('update.php');
  428. // make sure that boot.php and update.php are the same release, we might be
  429. // updating right this very second and the correct version of the update.php
  430. // file may not be here yet. This can happen on a very busy site.
  431. if(DB_UPDATE_VERSION == UPDATE_VERSION) {
  432. for($x = $stored; $x < $current; $x ++) {
  433. if(function_exists('update_' . $x)) {
  434. $func = 'update_' . $x;
  435. $func($a);
  436. }
  437. }
  438. set_config('system','build', DB_UPDATE_VERSION);
  439. }
  440. }
  441. }
  442. /**
  443. *
  444. * Synchronise plugins:
  445. *
  446. * $a->config['system']['addon'] contains a comma-separated list of names
  447. * of plugins/addons which are used on this system.
  448. * Go through the database list of already installed addons, and if we have
  449. * an entry, but it isn't in the config list, call the uninstall procedure
  450. * and mark it uninstalled in the database (for now we'll remove it).
  451. * Then go through the config list and if we have a plugin that isn't installed,
  452. * call the install procedure and add it to the database.
  453. *
  454. */
  455. $r = q("SELECT * FROM `addon` WHERE `installed` = 1");
  456. if(count($r))
  457. $installed = $r;
  458. else
  459. $installed = array();
  460. $plugins = get_config('system','addon');
  461. $plugins_arr = array();
  462. if($plugins)
  463. $plugins_arr = explode(',',str_replace(' ', '',$plugins));
  464. $a->plugins = $plugins_arr;
  465. $installed_arr = array();
  466. if(count($installed)) {
  467. foreach($installed as $i) {
  468. if(! in_array($i['name'],$plugins_arr)) {
  469. uninstall_plugin($i['name']);
  470. }
  471. else
  472. $installed_arr[] = $i['name'];
  473. }
  474. }
  475. if(count($plugins_arr)) {
  476. foreach($plugins_arr as $p) {
  477. if(! in_array($p,$installed_arr)) {
  478. install_plugin($p);
  479. }
  480. }
  481. }
  482. load_hooks();
  483. return;
  484. }}
  485. function get_guid($size=16) {
  486. $exists = true; // assume by default that we don't have a unique guid
  487. do {
  488. $s = random_string($size);
  489. $r = q("select id from guid where guid = '%s' limit 1", dbesc($s));
  490. if(! count($r))
  491. $exists = false;
  492. } while($exists);
  493. q("insert into guid ( guid ) values ( '%s' ) ", dbesc($s));
  494. return $s;
  495. }
  496. // wrapper for adding a login box. If $register == true provide a registration
  497. // link. This will most always depend on the value of $a->config['register_policy'].
  498. // returns the complete html for inserting into the page
  499. if(! function_exists('login')) {
  500. function login($register = false) {
  501. $o = "";
  502. $register_tpl = (($register) ? get_markup_template("register-link.tpl") : "");
  503. $register_html = replace_macros($register_tpl,array(
  504. '$title' => t('Create a New Account'),
  505. '$desc' => t('Register')
  506. ));
  507. $noid = get_config('system','no_openid');
  508. if($noid) {
  509. $classname = 'no-openid';
  510. $namelabel = t('Nickname or Email address: ');
  511. $passlabel = t('Password: ');
  512. $login = t('Login');
  513. }
  514. else {
  515. $classname = 'openid';
  516. $namelabel = t('Nickname/Email/OpenID: ');
  517. $passlabel = t("Password \x28if not OpenID\x29: ");
  518. $login = t('Login');
  519. }
  520. $lostpass = t('Forgot your password?');
  521. $lostlink = t('Password Reset');
  522. if(local_user()) {
  523. $tpl = get_markup_template("logout.tpl");
  524. }
  525. else {
  526. $tpl = get_markup_template("login.tpl");
  527. }
  528. $o = '<script type="text/javascript"> $(document).ready(function() { $("#login-name").focus();} );</script>';
  529. $o .= replace_macros($tpl,array(
  530. '$logout' => t('Logout'),
  531. '$register_html' => $register_html,
  532. '$classname' => $classname,
  533. '$namelabel' => $namelabel,
  534. '$passlabel' => $passlabel,
  535. '$login' => $login,
  536. '$lostpass' => $lostpass,
  537. '$lostlink' => $lostlink
  538. ));
  539. return $o;
  540. }}
  541. // Used to end the current process, after saving session state.
  542. if(! function_exists('killme')) {
  543. function killme() {
  544. session_write_close();
  545. exit;
  546. }}
  547. // redirect to another URL and terminate this process.
  548. if(! function_exists('goaway')) {
  549. function goaway($s) {
  550. header("Location: $s");
  551. killme();
  552. }}
  553. // Returns the uid of locally logged in user or false.
  554. if(! function_exists('local_user')) {
  555. function local_user() {
  556. if((x($_SESSION,'authenticated')) && (x($_SESSION,'uid')))
  557. return intval($_SESSION['uid']);
  558. return false;
  559. }}
  560. // Returns contact id of authenticated site visitor or false
  561. if(! function_exists('remote_user')) {
  562. function remote_user() {
  563. if((x($_SESSION,'authenticated')) && (x($_SESSION,'visitor_id')))
  564. return intval($_SESSION['visitor_id']);
  565. return false;
  566. }}
  567. // contents of $s are displayed prominently on the page the next time
  568. // a page is loaded. Usually used for errors or alerts.
  569. if(! function_exists('notice')) {
  570. function notice($s) {
  571. $a = get_app();
  572. if($a->interactive)
  573. $_SESSION['sysmsg'] .= $s;
  574. }}
  575. if(! function_exists('info')) {
  576. function info($s) {
  577. $a = get_app();
  578. if($a->interactive)
  579. $_SESSION['sysmsg_info'] .= $s;
  580. }}
  581. // wrapper around config to limit the text length of an incoming message
  582. if(! function_exists('get_max_import_size')) {
  583. function get_max_import_size() {
  584. global $a;
  585. return ((x($a->config,'max_import_size')) ? $a->config['max_import_size'] : 0 );
  586. }}
  587. /**
  588. *
  589. * Function : profile_load
  590. * @parameter App $a
  591. * @parameter string $nickname
  592. * @parameter int $profile
  593. *
  594. * Summary: Loads a profile into the page sidebar.
  595. * The function requires a writeable copy of the main App structure, and the nickname
  596. * of a registered local account.
  597. *
  598. * If the viewer is an authenticated remote viewer, the profile displayed is the
  599. * one that has been configured for his/her viewing in the Contact manager.
  600. * Passing a non-zero profile ID can also allow a preview of a selected profile
  601. * by the owner.
  602. *
  603. * Profile information is placed in the App structure for later retrieval.
  604. * Honours the owner's chosen theme for display.
  605. *
  606. */
  607. if(! function_exists('profile_load')) {
  608. function profile_load(&$a, $nickname, $profile = 0) {
  609. if(remote_user()) {
  610. $r = q("SELECT `profile-id` FROM `contact` WHERE `id` = %d LIMIT 1",
  611. intval($_SESSION['visitor_id']));
  612. if(count($r))
  613. $profile = $r[0]['profile-id'];
  614. }
  615. $r = null;
  616. if($profile) {
  617. $profile_int = intval($profile);
  618. $r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `user`.* FROM `profile`
  619. LEFT JOIN `user` ON `profile`.`uid` = `user`.`uid`
  620. WHERE `user`.`nickname` = '%s' AND `profile`.`id` = %d LIMIT 1",
  621. dbesc($nickname),
  622. intval($profile_int)
  623. );
  624. }
  625. if(! count($r)) {
  626. $r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `user`.* FROM `profile`
  627. LEFT JOIN `user` ON `profile`.`uid` = `user`.`uid`
  628. WHERE `user`.`nickname` = '%s' AND `profile`.`is-default` = 1 LIMIT 1",
  629. dbesc($nickname)
  630. );
  631. }
  632. if(($r === false) || (! count($r))) {
  633. notice( t('No profile') . EOL );
  634. $a->error = 404;
  635. return;
  636. }
  637. $a->profile = $r[0];
  638. $a->page['title'] = $a->profile['name'] . " @ " . $a->config['sitename'];
  639. $_SESSION['theme'] = $a->profile['theme'];
  640. if(! (x($a->page,'aside')))
  641. $a->page['aside'] = '';
  642. $block = (((get_config('system','block_public')) && (! local_user()) && (! remote_user())) ? true : false);
  643. $a->page['aside'] .= profile_sidebar($a->profile, $block);
  644. if(! $block)
  645. $a->page['aside'] .= contact_block();
  646. return;
  647. }}
  648. /**
  649. *
  650. * Function: profile_sidebar
  651. *
  652. * Formats a profile for display in the sidebar.
  653. * It is very difficult to templatise the HTML completely
  654. * because of all the conditional logic.
  655. *
  656. * @parameter: array $profile
  657. *
  658. * Returns HTML string stuitable for sidebar inclusion
  659. * Exceptions: Returns empty string if passed $profile is wrong type or not populated
  660. *
  661. */
  662. if(! function_exists('profile_sidebar')) {
  663. function profile_sidebar($profile, $block = 0) {
  664. $a = get_app();
  665. $o = '';
  666. $location = '';
  667. $address = false;
  668. if((! is_array($profile)) && (! count($profile)))
  669. return $o;
  670. call_hooks('profile_sidebar_enter', $profile);
  671. $fullname = '<div class="fn">' . $profile['name'] . '</div>';
  672. $pdesc = '<div class="title">' . $profile['pdesc'] . '</div>';
  673. $tabs = '';
  674. $photo = '<div id="profile-photo-wrapper"><img class="photo" width="175" height="175" src="' . $profile['photo'] . '" alt="' . $profile['name'] . '" /></div>';
  675. // don't show connect link to yourself
  676. $connect = (($profile['uid'] != local_user()) ? '<li><a id="dfrn-request-link" href="dfrn_request/' . $profile['nickname'] . '">' . t('Connect') . '</a></li>' : '');
  677. // don't show connect link to authenticated visitors either
  678. if((remote_user()) && ($_SESSION['visitor_visiting'] == $profile['uid']))
  679. $connect = '';
  680. if((x($profile,'address') == 1)
  681. || (x($profile,'locality') == 1)
  682. || (x($profile,'region') == 1)
  683. || (x($profile,'postal-code') == 1)
  684. || (x($profile,'country-name') == 1))
  685. $address = true;
  686. if($address) {
  687. $location .= '<div class="location"><span class="location-label">' . t('Location:') . '</span> <div class="adr">';
  688. $location .= ((x($profile,'address') == 1) ? '<div class="street-address">' . $profile['address'] . '</div>' : '');
  689. $location .= (((x($profile,'locality') == 1) || (x($profile,'region') == 1) || (x($profile,'postal-code') == 1))
  690. ? '<span class="city-state-zip"><span class="locality">' . $profile['locality'] . '</span>'
  691. . ((x($profile['locality']) == 1) ? t(', ') : '')
  692. . '<span class="region">' . $profile['region'] . '</span>'
  693. . ' <span class="postal-code">' . $profile['postal-code'] . '</span></span>' : '');
  694. $location .= ((x($profile,'country-name') == 1) ? ' <span class="country-name">' . $profile['country-name'] . '</span>' : '');
  695. $location .= '</div></div><div class="profile-clear"></div>';
  696. }
  697. $gender = ((x($profile,'gender') == 1) ? '<div class="mf"><span class="gender-label">' . t('Gender:') . '</span> <span class="x-gender">' . $profile['gender'] . '</span></div><div class="profile-clear"></div>' : '');
  698. $pubkey = ((x($profile,'pubkey') == 1) ? '<div class="key" style="display:none;">' . $profile['pubkey'] . '</div>' : '');
  699. $marital = ((x($profile,'marital') == 1) ? '<div class="marital"><span class="marital-label"><span class="heart">&hearts;</span> ' . t('Status:') . ' </span><span class="marital-text">' . $profile['marital'] . '</span></div><div class="profile-clear"></div>' : '');
  700. $homepage = ((x($profile,'homepage') == 1) ? '<div class="homepage"><span class="homepage-label">' . t('Homepage:') . ' </span><span class="homepage-url">' . linkify($profile['homepage']) . '</span></div><div class="profile-clear"></div>' : '');
  701. if(($profile['hidewall'] || $block) && (! local_user()) && (! remote_user())) {
  702. $location = $pdesc = $connect = $gender = $marital = $homepage = '';
  703. }
  704. $podloc = $a->get_baseurl();
  705. $searchable = (($profile['publish'] && $profile['net-publish']) ? 'true' : 'false' );
  706. $nickname = $profile['nickname'];
  707. $photo300 = $a->get_baseurl() . '/photo/custom/300/' . $profile['uid'] . '.jpg';
  708. $photo100 = $a->get_baseurl() . '/photo/custom/100/' . $profile['uid'] . '.jpg';
  709. $photo50 = $a->get_baseurl() . '/photo/custom/50/' . $profile['uid'] . '.jpg';
  710. $diaspora_vcard = <<< EOT
  711. <div style="display:none;">
  712. <dl class='entity_nickname'>
  713. <dt>Nickname</dt>
  714. <dd>
  715. <a class="nickname url uid" href="$podloc/" rel="me">$nickname</a>
  716. </dd>
  717. </dl>
  718. <dl class='entity_fn'>
  719. <dt>Full name</dt>
  720. <dd>
  721. <span class='fn'>$fullname</span>
  722. </dd>
  723. </dl>
  724. <dl class="entity_url">
  725. <dt>URL</dt>
  726. <dd>
  727. <a class="url" href="$podloc/" id="pod_location" rel="me">$podloc/</a>
  728. </dd>
  729. </dl>
  730. <dl class="entity_photo">
  731. <dt>Photo</dt>
  732. <dd>
  733. <img class="photo avatar" height="300px" width="300px" src="$photo300">
  734. </dd>
  735. </dl>
  736. <dl class="entity_photo_medium">
  737. <dt>Photo</dt>
  738. <dd>
  739. <img class="photo avatar" height="100px" width="100px" src="$photo100">
  740. </dd>
  741. </dl>
  742. <dl class="entity_photo_small">
  743. <dt>Photo</dt>
  744. <dd>
  745. <img class="photo avatar" height="50px" width="50px" src="$photo50">
  746. </dd>
  747. </dl>
  748. <dl class="entity_searchable">
  749. <dt>Searchable</dt>
  750. <dd>
  751. <span class="searchable">$searchable</span>
  752. </dd>
  753. </dl>
  754. </div>
  755. EOT;
  756. $tpl = get_markup_template('profile_vcard.tpl');
  757. $o .= replace_macros($tpl, array(
  758. '$fullname' => $fullname,
  759. '$pdesc' => $pdesc,
  760. '$tabs' => $tabs,
  761. '$photo' => $photo,
  762. '$connect' => $connect,
  763. '$location' => $location,
  764. '$gender' => $gender,
  765. '$pubkey' => $pubkey,
  766. '$marital' => $marital,
  767. '$homepage' => $homepage,
  768. '$diaspora' => $diaspora_vcard
  769. ));
  770. $arr = array('profile' => &$profile, 'entry' => &$o);
  771. call_hooks('profile_sidebar', $arr);
  772. return $o;
  773. }}
  774. if(! function_exists('get_birthdays')) {
  775. function get_birthdays() {
  776. $a = get_app();
  777. $o = '';
  778. if(! local_user())
  779. return $o;
  780. $bd_format = t('g A l F d') ; // 8 AM Friday January 18
  781. $r = q("SELECT `event`.*, `event`.`id` AS `eid`, `contact`.* FROM `event`
  782. LEFT JOIN `contact` ON `contact`.`id` = `event`.`cid`
  783. WHERE `event`.`uid` = %d AND `type` = 'birthday' AND `start` < '%s' AND `finish` > '%s'
  784. ORDER BY `start` DESC ",
  785. intval(local_user()),
  786. dbesc(datetime_convert('UTC','UTC','now + 6 days')),
  787. dbesc(datetime_convert('UTC','UTC','now'))
  788. );
  789. if($r && count($r)) {
  790. $total = 0;
  791. foreach($r as $rr)
  792. if(strlen($rr['name']))
  793. $total ++;
  794. if($total) {
  795. $o .= '<div id="birthday-notice" class="birthday-notice fakelink" onclick=openClose(\'birthday-wrapper\'); >' . t('Birthday Reminders') . ' ' . '(' . $total . ')' . '</div>';
  796. $o .= '<div id="birthday-wrapper" style="display: none;" ><div id="birthday-title">' . t('Birthdays this week:') . '</div>';
  797. $o .= '<div id="birthday-adjust">' . t("\x28Adjusted for local time\x29") . '</div>';
  798. $o .= '<div id="birthday-title-end"></div>';
  799. foreach($r as $rr) {
  800. if(! strlen($rr['name']))
  801. continue;
  802. $now = strtotime('now');
  803. $today = (((strtotime($rr['start'] . ' +00:00') < $now) && (strtotime($rr['finish'] . ' +00:00') > $now)) ? true : false);
  804. $o .= '<div class="birthday-list" id="birthday-' . $rr['eid'] . '"><a class="sparkle" href="'
  805. . $a->get_baseurl() . '/redir/' . $rr['cid'] . '">' . $rr['name'] . '</a> '
  806. . day_translate(datetime_convert('UTC', $a->timezone, $rr['start'], $bd_format)) . (($today) ? ' ' . t('[today]') : '')
  807. . '</div>' ;
  808. }
  809. $o .= '</div></div>';
  810. }
  811. }
  812. return $o;
  813. }}
  814. /**
  815. *
  816. * Wrap calls to proc_close(proc_open()) and call hook
  817. * so plugins can take part in process :)
  818. *
  819. * args:
  820. * $cmd program to run
  821. * next args are passed as $cmd command line
  822. *
  823. * e.g.: proc_run("ls","-la","/tmp");
  824. *
  825. * $cmd and string args are surrounded with ""
  826. */
  827. if(! function_exists('proc_run')) {
  828. function proc_run($cmd){
  829. $a = get_app();
  830. $args = func_get_args();
  831. $arr = array('args' => $args, 'run_cmd' => true);
  832. call_hooks("proc_run", $arr);
  833. if(! $arr['run_cmd'])
  834. return;
  835. if(count($args) && $args[0] === 'php')
  836. $args[0] = ((x($a->config,'php_path')) && (strlen($a->config['php_path'])) ? $a->config['php_path'] : 'php');
  837. foreach ($args as $arg){
  838. $arg = escapeshellarg($arg);
  839. }
  840. $cmdline = implode($args," ");
  841. proc_close(proc_open($cmdline." &",array(),$foo));
  842. }}
  843. if(! function_exists('current_theme')) {
  844. function current_theme(){
  845. $app_base_themes = array('duepuntozero', 'loozah');
  846. $a = get_app();
  847. $system_theme = ((isset($a->config['system']['theme'])) ? $a->config['system']['theme'] : '');
  848. $theme_name = ((is_array($_SESSION) && x($_SESSION,'theme')) ? $_SESSION['theme'] : $system_theme);
  849. if($theme_name && file_exists('view/theme/' . $theme_name . '/style.css'))
  850. return($theme_name);
  851. foreach($app_base_themes as $t) {
  852. if(file_exists('view/theme/' . $t . '/style.css'))
  853. return($t);
  854. }
  855. $fallback = glob('view/theme/*/style.css');
  856. if(count($fallback))
  857. return (str_replace('view/theme/','', str_replace("/style.css","",$fallback[0])));
  858. }}
  859. /*
  860. * Return full URL to theme which is currently in effect.
  861. * Provide a sane default if nothing is chosen or the specified theme does not exist.
  862. */
  863. if(! function_exists('current_theme_url')) {
  864. function current_theme_url() {
  865. global $a;
  866. $t = current_theme();
  867. return($a->get_baseurl() . '/view/theme/' . $t . '/style.css');
  868. }}
  869. if(! function_exists('feed_birthday')) {
  870. function feed_birthday($uid,$tz) {
  871. /**
  872. *
  873. * Determine the next birthday, but only if the birthday is published
  874. * in the default profile. We _could_ also look for a private profile that the
  875. * recipient can see, but somebody could get mad at us if they start getting
  876. * public birthday greetings when they haven't made this info public.
  877. *
  878. * Assuming we are able to publish this info, we are then going to convert
  879. * the start time from the owner's timezone to UTC.
  880. *
  881. * This will potentially solve the problem found with some social networks
  882. * where birthdays are converted to the viewer's timezone and salutations from
  883. * elsewhere in the world show up on the wrong day. We will convert it to the
  884. * viewer's timezone also, but first we are going to convert it from the birthday
  885. * person's timezone to GMT - so the viewer may find the birthday starting at
  886. * 6:00PM the day before, but that will correspond to midnight to the birthday person.
  887. *
  888. */
  889. $birthday = '';
  890. $p = q("SELECT `dob` FROM `profile` WHERE `is-default` = 1 AND `uid` = %d LIMIT 1",
  891. intval($uid)
  892. );
  893. if($p && count($p)) {
  894. $tmp_dob = substr($p[0]['dob'],5);
  895. if(intval($tmp_dob)) {
  896. $y = datetime_convert($tz,$tz,'now','Y');
  897. $bd = $y . '-' . $tmp_dob . ' 00:00';
  898. $t_dob = strtotime($bd);
  899. $now = strtotime(datetime_convert($tz,$tz,'now'));
  900. if($t_dob < $now)
  901. $bd = $y + 1 . '-' . $tmp_dob . ' 00:00';
  902. $birthday = datetime_convert($tz,'UTC',$bd,ATOM_TIME);
  903. }
  904. }
  905. return $birthday;
  906. }}
  907. if(! function_exists('is_site_admin')) {
  908. function is_site_admin() {
  909. $a = get_app();
  910. if(local_user() && x($a->user,'email') && x($a->config,'admin_email') && ($a->user['email'] === $a->config['admin_email']))
  911. return true;
  912. return false;
  913. }}
  914. if(! function_exists('load_contact_links')) {
  915. function load_contact_links($uid) {
  916. $a = get_app();
  917. $ret = array();
  918. if(! $uid || x($a->contacts,'empty'))
  919. return;
  920. $r = q("SELECT `id`,`network`,`url`,`thumb` FROM `contact` WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 ",
  921. intval($uid)
  922. );
  923. if(count($r)) {
  924. foreach($r as $rr){
  925. $url = normalise_link($rr['url']);
  926. $ret[$url] = $rr;
  927. }
  928. }
  929. else
  930. $ret['empty'] = true;
  931. $a->contacts = $ret;
  932. return;
  933. }}