diff options
96 files changed, 2695 insertions, 397 deletions
@@ -1,4 +1,4 @@ -Copyright (c) 2010, 2011 the Friendika Project +Copyright (c) 2010, 2011 the Friendica Project All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy @@ -6,11 +6,12 @@ require_once('include/plugin.php'); require_once('include/text.php'); require_once("include/pgettext.php"); require_once('include/nav.php'); +require_once('include/cache.php'); -define ( 'FRIENDIKA_PLATFORM', 'Free Friendika'); -define ( 'FRIENDIKA_VERSION', '2.3.1139' ); -define ( 'DFRN_PROTOCOL_VERSION', '2.21' ); -define ( 'DB_UPDATE_VERSION', 1097 ); +define ( 'FRIENDIKA_PLATFORM', 'Friendica'); +define ( 'FRIENDIKA_VERSION', '2.3.1157' ); +define ( 'DFRN_PROTOCOL_VERSION', '2.22' ); +define ( 'DB_UPDATE_VERSION', 1102 ); define ( 'EOL', "<br />\r\n" ); define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' ); @@ -93,7 +94,7 @@ define ( 'PAGE_FREELOVE', 3 ); */ define ( 'NETWORK_ZOT', 'zot!'); // Zot! -define ( 'NETWORK_DFRN', 'dfrn'); // Friendika, Mistpark, other DFRN implementations +define ( 'NETWORK_DFRN', 'dfrn'); // Friendica, Mistpark, other DFRN implementations define ( 'NETWORK_OSTATUS', 'stat'); // status.net, identi.ca, GNU-social, other OStatus implementations define ( 'NETWORK_FEED', 'feed'); // RSS/Atom feeds with no known "post/notify" protocol define ( 'NETWORK_DIASPORA', 'dspr'); // Diaspora @@ -190,7 +191,7 @@ function startup() { set_time_limit(0); // This has to be quite large to deal with embedded private photos - ini_set('pcre.backtrack_limit', 350000); + ini_set('pcre.backtrack_limit', 500000); if (get_magic_quotes_gpc()) { @@ -238,7 +239,7 @@ class App { public $contacts; public $page_contact; public $content; - public $data; + public $data = array(); public $error = false; public $cmd; public $argv; @@ -251,8 +252,10 @@ class App { public $timezone; public $interactive = true; public $plugins; - public $apps = Array(); + public $apps = array(); public $identities; + + public $nav_sel; private $scheme; private $hostname; @@ -823,6 +826,13 @@ function profile_load(&$a, $nickname, $profile = 0) { if(! (x($a->page,'aside'))) $a->page['aside'] = ''; + if(local_user() && local_user() == $a->profile['uid']) { + $a->page['aside'] .= replace_macros(get_markup_template('profile_edlink.tpl'),array( + '$editprofile' => t('Edit profile'), + '$profid' => $a->profile['id'] + )); + } + $block = (((get_config('system','block_public')) && (! local_user()) && (! remote_user())) ? true : false); $a->page['aside'] .= profile_sidebar($a->profile, $block); @@ -989,7 +999,7 @@ function get_birthdays() { $r = q("SELECT `event`.*, `event`.`id` AS `eid`, `contact`.* FROM `event` LEFT JOIN `contact` ON `contact`.`id` = `event`.`cid` WHERE `event`.`uid` = %d AND `type` = 'birthday' AND `start` < '%s' AND `finish` > '%s' - ORDER BY `start` DESC ", + ORDER BY `start` ASC ", intval(local_user()), dbesc(datetime_convert('UTC','UTC','now + 6 days')), dbesc(datetime_convert('UTC','UTC','now')) @@ -997,20 +1007,23 @@ function get_birthdays() { if($r && count($r)) { $total = 0; - foreach($r as $rr) + $now = strtotime('now'); + $istoday = false; + foreach($r as $rr) { if(strlen($rr['name'])) $total ++; - + if((strtotime($rr['start'] . ' +00:00') < $now) && (strtotime($rr['finish'] . ' +00:00') > $now)) + $istoday = true; + } + $classtoday = $istoday ? ' birthday-today ' : ''; if($total) { - $o .= '<div id="birthday-notice" class="birthday-notice fakelink" onclick=openClose(\'birthday-wrapper\'); >' . t('Birthday Reminders') . ' ' . '(' . $total . ')' . '</div>'; + $o .= '<div id="birthday-notice" class="birthday-notice fakelink' . $classtoday . '" onclick=openClose(\'birthday-wrapper\'); >' . t('Birthday Reminders') . ' ' . '(' . $total . ')' . '</div>'; $o .= '<div id="birthday-wrapper" style="display: none;" ><div id="birthday-title">' . t('Birthdays this week:') . '</div>'; -// $o .= '<div id="birthday-adjust">' . t("\x28Adjusted for local time\x29") . '</div>'; $o .= '<div id="birthday-title-end"></div>'; foreach($r as $rr) { if(! strlen($rr['name'])) continue; - $now = strtotime('now'); $today = (((strtotime($rr['start'] . ' +00:00') < $now) && (strtotime($rr['finish'] . ' +00:00') > $now)) ? true : false); $sparkle = ''; $url = $rr['url']; @@ -1031,6 +1044,70 @@ function get_birthdays() { }} +if(! function_exists('get_events')) { +function get_events() { + + require_once('include/bbcode.php'); + + $a = get_app(); + $o = ''; + + if(! local_user()) + return $o; + + $bd_format = t('g A l F d') ; // 8 AM Friday January 18 + $bd_short = t('F d'); + + $r = q("SELECT `event`.* FROM `event` + WHERE `event`.`uid` = %d AND `type` != 'birthday' AND `start` < '%s' AND `start` > '%s' + ORDER BY `start` ASC ", + intval(local_user()), + dbesc(datetime_convert('UTC','UTC','now + 6 days')), + dbesc(datetime_convert('UTC','UTC','now - 1 days')) + ); + + if($r && count($r)) { + $now = strtotime('now'); + $istoday = false; + foreach($r as $rr) { + if(strlen($rr['name'])) + $total ++; + + $strt = datetime_convert('UTC',$rr['convert'] ? $a->timezone : 'UTC',$rr['start'],'Y-m-d'); + if($strt === datetime_convert('UTC',$a->timezone,'now','Y-m-d')) + $istoday = true; + } + $classtoday = (($istoday) ? ' event-today ' : ''); + + $o .= '<div id="event-notice" class="birthday-notice fakelink' . $classtoday . '" onclick=openClose(\'event-wrapper\'); >' . t('Event Reminders') . ' ' . '(' . count($r) . ')' . '</div>'; + $o .= '<div id="event-wrapper" style="display: none;" ><div id="event-title">' . t('Events this week:') . '</div>'; + $o .= '<div id="event-title-end"></div>'; + + foreach($r as $rr) { + + if($rr['adjust']) + $md = datetime_convert('UTC',$a->timezone,$rr['start'],'Y/m\#\l\i\n\k\-j'); + else + $md = datetime_convert('UTC','UTC',$rr['start'],'Y/m\#\l\i\n\k\-j'); + + $title = substr(strip_tags(bbcode($rr['desc'])),0,32) . '... '; + if(! $title) + $title = t('[No description]'); + + $strt = datetime_convert('UTC',$rr['convert'] ? $a->timezone : 'UTC',$rr['start']); + $today = ((substr($strt,0,10) === datetime_convert('UTC',$a->timezone,'now','Y-m-d')) ? true : false); + + $o .= '<div class="event-list" id="event-' . $rr['eid'] . '"></a> <a href="events/' . $md . '">' . $title . '</a>' + . day_translate(datetime_convert('UTC', $rr['adjust'] ? $a->timezone : 'UTC', $rr['start'], $bd_format)) . (($today) ? ' ' . t('[today]') : '') + . '</div>' ; + } + $o .= '</div></div>'; + } + + return $o; +}} + + /** * * Wrap calls to proc_close(proc_open()) and call hook diff --git a/database.sql b/database.sql index c9e239075..3d11ff4b7 100644 --- a/database.sql +++ b/database.sql @@ -66,6 +66,7 @@ CREATE TABLE IF NOT EXISTS `contact` ( `issued-id` char(255) NOT NULL, `dfrn-id` char(255) NOT NULL, `url` char(255) NOT NULL, + `nurl` char(255) NOT NULL, `addr` char(255) NOT NULL, `alias` char(255) NOT NULL, `pubkey` text NOT NULL, @@ -75,6 +76,7 @@ CREATE TABLE IF NOT EXISTS `contact` ( `notify` text NOT NULL, `poll` text NOT NULL, `confirm` text NOT NULL, + `poco` text NOT NULL, `aes_allow` tinyint(1) NOT NULL DEFAULT '0', `ret-aes` tinyint(1) NOT NULL DEFAULT '0', `usehub` tinyint(1) NOT NULL DEFAULT '0', @@ -100,6 +102,14 @@ CREATE TABLE IF NOT EXISTS `contact` ( PRIMARY KEY (`id`), KEY `uid` (`uid`), KEY `self` (`self`), + KEY `network` (`network`), + KEY `name` (`name`), + KEY `nick` (`nick`), + KEY `attag` (`attag`), + KEY `url` (`url`), + KEY `nurl` (`nurl`), + KEY `addr` (`addr`), + KEY `batch` (`batch`), KEY `issued-id` (`issued-id`), KEY `dfrn-id` (`dfrn-id`), KEY `blocked` (`blocked`), @@ -477,7 +487,12 @@ CREATE TABLE IF NOT EXISTS `queue` ( `created` DATETIME NOT NULL , `last` DATETIME NOT NULL , `content` MEDIUMTEXT NOT NULL, -`batch` TINYINT( 1 ) NOT NULL DEFAULT '0' +`batch` TINYINT( 1 ) NOT NULL DEFAULT '0', +INDEX ( `cid` ), +INDEX ( `created` ), +INDEX ( `last` ), +INDEX ( `network` ), +INDEX ( `batch` ) ) ENGINE = MyISAM DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `pconfig` ( @@ -646,3 +661,32 @@ CREATE TABLE IF NOT EXISTS `fserver` ( INDEX ( `server` ) ) ENGINE = MyISAM DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `gcontact` ( +`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , +`name` CHAR( 255 ) NOT NULL , +`url` CHAR( 255 ) NOT NULL , +`nurl` CHAR( 255 ) NOT NULL , +`photo` CHAR( 255 ) NOT NULL, +INDEX ( `nurl` ) +) ENGINE = MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `glink` ( +`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , +`cid` INT NOT NULL , +`uid` INT NOT NULL , +`gcid` INT NOT NULL, +`updated` DATETIME NOT NULL, +INDEX ( `cid` ), +INDEX ( `uid` ), +INDEX ( `gcid` ), +INDEX ( `updated` ) +) ENGINE = MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `gcign` ( +`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , +`uid` INT NOT NULL , +`gcid` INT NOT NULL, +INDEX ( `uid` ), +INDEX ( `gcid` ) +) ENGINE = MyISAM DEFAULT CHARSET=utf8; + diff --git a/doc/Install.md b/doc/Install.md index b5ab1ef6f..d851624a7 100644 --- a/doc/Install.md +++ b/doc/Install.md @@ -2,7 +2,7 @@ Friendika Installation We've tried very hard to ensure that Friendika will run on commodity hosting platforms - such as those used to host Wordpress blogs and Drupal websites. But be aware that Friendika is more than a simple web application. It is a complex communications system which more closely resembles an email server than a web server. For reliability and performance, messages are delivered in the background and are queued for later delivery when sites are down. This kind of functionality requires a bit more of the host system than the typical blog. Not every PHP/MySQL hosting provider will be able to support Friendika. Many will. But **please** review the requirements and confirm these with your hosting provider prior to installation. -Also if you encounter installation issues, please let us know via the forums at http://groups.google.com/group/friendika or file an issue at http://bugs.friendika.com . Please be as clear as you can about your operating environment and provide as much detail as possible about any error messages you may see, so that we can prevent it from happening in the future. Due to the large variety of operating systems and PHP platforms in existence we may have only limited ability to debug your PHP installation or acquire any missing modules - but we will do our best to solve any general code issues. +Also if you encounter installation issues, please let us know via the forums at http://groups.google.com/group/friendika or file an issue at http://bugs.friendica.com . Please be as clear as you can about your operating environment and provide as much detail as possible about any error messages you may see, so that we can prevent it from happening in the future. Due to the large variety of operating systems and PHP platforms in existence we may have only limited ability to debug your PHP installation or acquire any missing modules - but we will do our best to solve any general code issues. Before you begin: Choose a domain name or subdomain name for your server. Put some thought into this - because changing it after installation is currently not-supported. Things will break, and some of your friends may have difficulty communicating with you. We plan to address this limitation in a future release. @@ -36,7 +36,7 @@ you might have trouble getting everything to work.] - If you are able to do so, we recommend using git to clone the source repository rather than to use a packaged tar or zip file. This makes the software much easier to update. The Linux command to clone the repository into a directory "mywebsite" would be - `git clone https://github.com/friendika/Free-Friendika.git mywebsite` + `git clone https://github.com/friendica/friendica.git mywebsite` - and then you can pick up the latest changes at any time with @@ -50,7 +50,7 @@ you might have trouble getting everything to work.] - Then you should clone the addon repository (separtely) - `git clone https://github.com/friendika/friendika-addons.git addon` + `git clone https://github.com/friendica/friendica-addons.git addon` - For keeping the addon tree updated, you should be on you addon tree and issue a git pull diff --git a/images/content-types.png b/images/content-types.png Binary files differindex be2ccbf01..e46eba610 100644 --- a/images/content-types.png +++ b/images/content-types.png diff --git a/images/icons/10/play.png b/images/icons/10/play.png Binary files differnew file mode 100644 index 000000000..a9f99e4d1 --- /dev/null +++ b/images/icons/10/play.png diff --git a/images/icons/16/play.png b/images/icons/16/play.png Binary files differnew file mode 100644 index 000000000..19ad05bf2 --- /dev/null +++ b/images/icons/16/play.png diff --git a/images/icons/22/play.png b/images/icons/22/play.png Binary files differnew file mode 100644 index 000000000..a7a8b6124 --- /dev/null +++ b/images/icons/22/play.png diff --git a/images/icons/48/play.png b/images/icons/48/play.png Binary files differnew file mode 100644 index 000000000..fce589370 --- /dev/null +++ b/images/icons/48/play.png diff --git a/images/icons/Makefile b/images/icons/Makefile index a39db119a..ec57b943e 100644 --- a/images/icons/Makefile +++ b/images/icons/Makefile @@ -2,7 +2,7 @@ IMAGES=add.png edit.png gear.png info.png menu.png \ notify_off.png star.png delete.png feed.png group.png \ lock.png notice.png notify_on.png user.png link.png \ - plugin.png + play.png plugin.png DESTS=10/ 16/ 22/ 48/ \ $(addprefix 10/, $(IMAGES)) \ diff --git a/images/icons/play.png b/images/icons/play.png Binary files differnew file mode 100644 index 000000000..7c942072e --- /dev/null +++ b/images/icons/play.png diff --git a/images/plugin.png b/images/plugin.png Binary files differnew file mode 100644 index 000000000..08b09e060 --- /dev/null +++ b/images/plugin.png diff --git a/include/Scrape.php b/include/Scrape.php index 642b8e624..e42d22afc 100644 --- a/include/Scrape.php +++ b/include/Scrape.php @@ -30,8 +30,11 @@ function scrape_dfrn($url) { } } - - $dom = HTML5_Parser::parse($s); + try { + $dom = HTML5_Parser::parse($s); + } catch (DOMException $e) { + logger('scrape_dfrn: parse error: ' . $e); + } if(! $dom) return $ret; @@ -132,9 +135,11 @@ function scrape_meta($url) { } } - - - $dom = HTML5_Parser::parse($s); + try { + $dom = HTML5_Parser::parse($s); + } catch (DOMException $e) { + logger('scrape_meta: parse error: ' . $e); + } if(! $dom) return $ret; @@ -177,7 +182,11 @@ function scrape_vcard($url) { } } - $dom = HTML5_Parser::parse($s); + try { + $dom = HTML5_Parser::parse($s); + } catch (DOMException $e) { + logger('scrape_vcard: parse error: ' . $e); + } if(! $dom) return $ret; @@ -243,7 +252,11 @@ function scrape_feed($url) { } } - $dom = HTML5_Parser::parse($s); + try { + $dom = HTML5_Parser::parse($s); + } catch (DOMException $e) { + logger('scrape_feed: parse error: ' . $e); + } if(! $dom) return $ret; @@ -356,6 +369,8 @@ function probe_url($url, $mode = PROBE_NORMAL) { $hcard = unamp($link['@attributes']['href']); if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') $profile = unamp($link['@attributes']['href']); + if($link['@attributes']['rel'] === 'http://portablecontacts.net/spec/1.0') + $poco = unamp($link['@attributes']['href']); if($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location') { $diaspora_base = unamp($link['@attributes']['href']); $diaspora = true; @@ -671,6 +686,7 @@ function probe_url($url, $mode = PROBE_NORMAL) { $result['poll'] = $poll; $result['request'] = $request; $result['confirm'] = $confirm; + $result['poco'] = $poco; $result['photo'] = $vcard['photo']; $result['priority'] = $priority; $result['network'] = $network; diff --git a/include/api.php b/include/api.php index d8942bfff..1196e0aac 100644 --- a/include/api.php +++ b/include/api.php @@ -421,14 +421,6 @@ return $ret; } - /** - * apply xmlify() to all values of array $val, recursively - */ - function api_xmlify($val){ - if (is_bool($val)) return $val?"true":"false"; - if (is_array($val)) return array_map('api_xmlify', $val); - return xmlify((string) $val); - } /** * load api $templatename for $type and replace $data array @@ -441,7 +433,7 @@ case "atom": case "rss": case "xml": - $data = api_xmlify($data); + $data = array_xmlify($data); $tpl = get_markup_template("api_".$templatename."_".$type.".tpl"); $ret = replace_macros($tpl, $data); break; diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index ef5477f1b..0721d27f6 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -11,15 +11,49 @@ function diaspora2bb($s) { $s = preg_replace('/\@\{(.+?)\; (.+?)\@(.+?)\}/','@[url=https://$3/u/$2]$1[/url]',$s); $s = Markdown($s); $s = html2bbcode($s); + $s = str_replace('*','*',$s); $s = preg_replace("/\[url\=?(.*?)\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/url\]/ism",'[youtube]$2[/youtube]',$s); + $s = preg_replace("/\[url\=https?:\/\/www.youtube.com\/watch\?v\=(.*?)\].*?\[\/url\]/ism",'[youtube]$1[/youtube]',$s); $s = preg_replace("/\[url\=?(.*?)\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/url\]/ism",'[vimeo]$2[/vimeo]',$s); - + $s = preg_replace("/\[url\=https?:\/\/vimeo.com\/([0-9]+)\](.*?)\[\/url\]/ism",'[vimeo]$1[/vimeo]',$s); + $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)(vimeo|youtu|www\.youtube|soundcloud)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url]$2$3$4[/url]',$s); + $s = scale_diaspora_images($s); return $s; } +function scale_diaspora_images($s,$include_link = true) { + + $matches = null; + $c = preg_match_all('/\[img\](.*?)\[\/img\]/ism',$s,$matches,PREG_SET_ORDER); + if($c) { + require_once('include/Photo.php'); + foreach($matches as $mtch) { + logger('scale_diaspora_image: ' . $mtch[1]); + $i = fetch_url($mtch[1]); + if($i) { + $ph = new Photo($i); + if($ph->is_valid()) { + if($ph->getWidth() > 600 || $ph->getHeight() > 600) { + $ph->scaleImage(600); + $new_width = $ph->getWidth(); + $new_height = $ph->getHeight(); + logger('scale_diaspora_image: ' . $new_width . 'w ' . $new_height . 'h' . 'match: ' . $mtch[0], LOGGER_DEBUG); + $s = str_replace($mtch[0],'[img=' . $new_width . 'x' . $new_height. ']' . $mtch[1] . '[/img]' + . "\n" . ((! $include_link) + ? '[url=' . $mtch[1] . ']' . t('view full size') . '[/url]' . "\n" + : ''),$s); + logger('scale_diaspora_image: new string: ' . $s, LOGGER_DEBUG); + } + } + } + } + } + return $s; +} + function stripdcode_br_cb($s) { - return '[code]' . str_replace('<br />', '', $s[1]) . '[/code]'; + return '[code]' . str_replace('<br />', "\n\t", $s[1]) . '[/code]'; } @@ -53,12 +87,14 @@ function bb2diaspora($Text,$preserve_nl = false) { // [img]pathtoimage[/img] + $Text = preg_replace("/\[bookmark\]([$URLSearchString]*)\[\/bookmark\]/ism", '[$1]($1)', $Text); + $Text = preg_replace("/\[bookmark\=([$URLSearchString]*)\](.*?)\[\/bookmark\]/ism", '[$2]($1)', $Text); $Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '[$1]($1)', $Text); $Text = preg_replace("/\#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '[#$2]($1)', $Text); $Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '[$2]($1)', $Text); -// $Text = preg_replace("/\[img\](.*?)\[\/img\]/", t('Image/photo: ') . '$1', $Text); + $Text = preg_replace("/\[img\](.*?)\[\/img\]/", '![' . t('image/photo') . '](' . '$1' . ')', $Text); // $Text = preg_replace("/\[img\](.*?)\[\/img\]/", t('image/photo'), $Text); // Perform MAIL Search @@ -117,17 +153,17 @@ function bb2diaspora($Text,$preserve_nl = false) { $Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/is",'stripdcode_br_cb',$Text); -// $CodeLayout = '<code>$1</code>'; + // $CodeLayout = '<code>$1</code>'; // Check for [code] text - $Text = preg_replace("/\[code\](.*?)\[\/code\]/is","```$1```", $Text); + $Text = preg_replace("/\[code\](.*?)\[\/code\]/is","\t$1\n", $Text); // Declare the format for [quote] layout -// $QuoteLayout = '<blockquote>$1</blockquote>'; + // $QuoteLayout = '<blockquote>$1</blockquote>'; // Check for [quote] text -// $Text = preg_replace("/\[quote\](.*?)\[\/quote\]/is","$QuoteLayout", $Text); + $Text = preg_replace("/\[quote\](.*?)\[\/quote\]/is",">$1\n\n", $Text); // Images diff --git a/include/bbcode.php b/include/bbcode.php index b33be686e..8c565add6 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -9,6 +9,21 @@ function stripcode_br_cb($s) { return '[code]' . str_replace('<br />', '', $s[1]) . '[/code]'; } +function tryoembed($match){ + $url = ((count($match)==2)?$match[1]:$match[2]); + + $o = oembed_fetch_url($url); + + //echo "<pre>"; var_dump($match, $url, $o); killme(); + + if ($o->type=="error") return $match[0]; + + $html = oembed_format_object($o); + return $html; //oembed_iframe($html,$o->width,$o->height); + +} + + // BBcode 2 HTML was written by WAY2WEB.net // extended to work with Mistpark/Friendika - Mike Macgirvin @@ -40,11 +55,15 @@ function bbcode($Text,$preserve_nl = false) { // Set up the parameters for a MAIL search string $MAILSearchString = $URLSearchString; - // Perform URL Search + // Perform URL Search $Text = preg_replace("/([^\]\=]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1<a href="$2" target="external-link">$2</a>', $Text); + + $Text = preg_replace_callback("/\[bookmark\=([^\]]*)\].*?\[\/bookmark\]/ism",'tryoembed',$Text); + $Text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",'[url=$1]$2[/url]',$Text); + $Text = preg_replace_callback("/\[url\]([$URLSearchString]*)\[\/url\]/ism",'tryoembed',$Text); $Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '<a href="$1" target="external-link">$1</a>', $Text); $Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<a href="$1" target="external-link">$2</a>', $Text); //$Text = preg_replace("/\[url\=([$URLSearchString]*)\]([$URLSearchString]*)\[\/url\]/ism", '<a href="$1" target="_blank">$2</a>', $Text); @@ -76,6 +95,10 @@ function bbcode($Text,$preserve_nl = false) { $Text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])ism","<span style=\"font-size: $1;\">$2</span>",$Text); // Check for list text + + if(stristr($Text,'[/list]')) + $Text = str_replace("[*]", "<li>", $Text); + $Text = preg_replace("/\[list\](.*?)\[\/list\]/ism", '<ul class="listbullet">$1</ul>' ,$Text); $Text = preg_replace("/\[list=1\](.*?)\[\/list\]/ism", '<ul class="listdecimal">$1</ul>' ,$Text); $Text = preg_replace("/\[list=i\](.*?)\[\/list\]/sm",'<ul class="listlowerroman">$1</ul>' ,$Text); @@ -92,7 +115,6 @@ function bbcode($Text,$preserve_nl = false) { $Text = preg_replace("/\[table border=0\](.*?)\[\/table\]/sm", '<table border="0" >$1</table>' ,$Text); -// $Text = str_replace("[*]", "<li>", $Text); // Check for font change text $Text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm","<span style=\"font-family: $1;\">$2</span>",$Text); @@ -120,6 +142,13 @@ function bbcode($Text,$preserve_nl = false) { // [img]pathtoimage[/img] $Text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '<img src="$1" alt="' . t('Image/photo') . '" />', $Text); + + + // Try to Oembed + $Text = preg_replace_callback("/\[video\](.*?)\[\/video\]/ism", 'tryoembed', $Text); + $Text = preg_replace_callback("/\[audio\](.*?)\[\/audio\]/ism", 'tryoembed', $Text); + + // html5 video and audio $Text = preg_replace("/\[video\](.*?)\[\/video\]/ism", '<video src="$1" controls="controls" width="425" height="350"><a href="$1">$1</a></video>', $Text); @@ -129,17 +158,25 @@ function bbcode($Text,$preserve_nl = false) { $Text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '<iframe src="$1" width="425" height="350"><a href="$1">$1</a></iframe>', $Text); - if (get_pconfig(local_user(), 'oembed', 'use_for_youtube' )==1){ + /*if (get_pconfig(local_user(), 'oembed', 'use_for_youtube' )==1){ // use oembed for youtube links $Text = preg_replace("/\[youtube\]/",'[embed]',$Text); $Text = preg_replace("/\[\/youtube\]/",'[/embed]',$Text); - } else { + } else {*/ // Youtube extensions + $Text = preg_replace_callback("/\[youtube\](https?:\/\/www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", 'tryoembed', $Text); + $Text = preg_replace_callback("/\[youtube\](https?:\/\/youtu.be\/.*?)\[\/youtube\]/ism",'tryoembed',$Text); + $Text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/youtube\]/ism",'[youtube]$1[/youtube]',$Text); $Text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/embed\/(.*?)\[\/youtube\]/ism",'[youtube]$1[/youtube]',$Text); $Text = preg_replace("/\[youtube\]https?:\/\/youtu.be\/(.*?)\[\/youtube\]/ism",'[youtube]$1[/youtube]',$Text); + + $Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '<iframe width="425" height="350" src="http://www.youtube.com/embed/$1" frameborder="0" ></iframe>', $Text); - } + //} + + $Text = preg_replace_callback("/\[vimeo\](https?:\/\/player.vimeo.com\/video\/[0-9]+).*?\[\/vimeo\]/ism",'tryoembed',$Text); + $Text = preg_replace_callback("/\[vimeo\](https?:\/\/vimeo.com\/[0-9]+).*?\[\/vimeo\]/ism",'tryoembed',$Text); $Text = preg_replace("/\[vimeo\]https?:\/\/player.vimeo.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism",'[vimeo]$1[/vimeo]',$Text); $Text = preg_replace("/\[vimeo\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/vimeo\]/ism",'[vimeo]$1[/vimeo]',$Text); diff --git a/include/cache.php b/include/cache.php new file mode 100644 index 000000000..082974c61 --- /dev/null +++ b/include/cache.php @@ -0,0 +1,29 @@ +<?php + /** + * cache api + */ + + class Cache { + public static function get($key){ + $r = q("SELECT `v` FROM `cache` WHERE `k`='%s'", + dbesc($key) + ); + + if (count($r)) return $r[0]['v']; + return null; + } + + public static function set($key,$value) { + q("INSERT INTO `cache` VALUES ('%s','%s','%s')", + dbesc($key), + dbesc($value), + dbesc(datetime_convert())); + } + + public static function clear(){ + q("DELETE FROM `cache` WHERE `updated` < '%s'", + dbesc(datetime_convert('UTC','UTC',"now - 30 days"))); + } + + } + diff --git a/include/contact_widgets.php b/include/contact_widgets.php index efb833aaf..3a21ff2c6 100644 --- a/include/contact_widgets.php +++ b/include/contact_widgets.php @@ -32,9 +32,11 @@ function findpeople_widget() { '$label' => t('Connect/Follow'), '$hint' => t('Examples: Robert Morgenstein, Fishing'), '$findthem' => t('Find'), + '$suggest' => t('Friend Suggestions'), '$similar' => t('Similar Interests'), '$inv' => $inv )); } + diff --git a/include/conversation.php b/include/conversation.php index 29fa77902..dec70c1a9 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -466,6 +466,8 @@ function conversation(&$a, $items, $mode, $update) { 'classdo' => (($item['starred']) ? "hidden" : ""), 'classundo' => (($item['starred']) ? "" : "hidden"), 'starred' => t('starred'), + 'tagger' => t("add tag"), + 'classtagger' => "", ); } @@ -747,6 +749,7 @@ function status_editor($a,$x, $notes_cid = 0) { '$linkurl' => t('Please enter a link URL:'), '$vidurl' => t("Please enter a video link/URL:"), '$audurl' => t("Please enter an audio link/URL:"), + '$term' => t('Tag term:'), '$whereareu' => t('Where are you right now?'), '$title' => t('Enter a title for this item') )); diff --git a/include/delivery.php b/include/delivery.php index 8318be4dd..a9e629fcf 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -1,5 +1,6 @@ <?php require_once("boot.php"); +require_once('include/queue_fn.php'); function delivery_run($argv, $argc){ global $a, $db; @@ -323,14 +324,7 @@ function delivery_run($argv, $argc){ if($deliver_status == (-1)) { logger('notifier: delivery failed: queuing message'); - // queue message for redelivery - q("INSERT INTO `queue` ( `cid`, `created`, `last`, `content`) - VALUES ( %d, '%s', '%s', '%s') ", - intval($contact['id']), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($atom) - ); + add_to_queue($contact['id'],NETWORK_DFRN,$atom); } break; @@ -370,13 +364,7 @@ function delivery_run($argv, $argc){ $deliver_status = slapper($owner,$contact['notify'],$slappy); if($deliver_status == (-1)) { // queue message for redelivery - q("INSERT INTO `queue` ( `cid`, `created`, `last`, `content`) - VALUES ( %d, '%s', '%s', '%s') ", - intval($contact['id']), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($slappy) - ); + add_to_queue($contact['id'],NETWORK_OSTATUS,$slappy); } } } diff --git a/include/diaspora.php b/include/diaspora.php index 99ef5025d..7e1e034d6 100644 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -4,6 +4,7 @@ require_once('include/crypto.php'); require_once('include/items.php'); require_once('include/bb2diaspora.php'); require_once('include/contact_selectors.php'); +require_once('include/queue_fn.php'); function diaspora_dispatch_public($msg) { @@ -64,6 +65,9 @@ function diaspora_dispatch($importer,$msg) { elseif($xmlbase->retraction) { $ret = diaspora_retraction($importer,$xmlbase->retraction,$msg); } + elseif($xmlbase->signed_retraction) { + $ret = diaspora_signed_retraction($importer,$xmlbase->retraction,$msg); + } elseif($xmlbase->photo) { $ret = diaspora_photo($importer,$xmlbase->photo,$msg); } @@ -91,12 +95,14 @@ function find_diaspora_person_by_handle($handle) { dbesc($handle) ); if(count($r)) { + logger('find_diaspora_person_by handle: in cache ' . print_r($r,true), LOGGER_DEBUG); // update record occasionally so it doesn't get stale $d = strtotime($r[0]['updated'] . ' +00:00'); if($d > strtotime('now - 14 days')) return $r[0]; $update = true; } + logger('find_diaspora_person_by_handle: refresh',LOGGER_DEBUG); require_once('include/Scrape.php'); $r = probe_url($handle, PROBE_DIASPORA); if((count($r)) && ($r['network'] === NETWORK_DIASPORA)) { @@ -448,13 +454,14 @@ function diaspora_request($importer,$xml) { $batch = (($ret['batch']) ? $ret['batch'] : implode('/', array_slice(explode('/',$ret['url']),0,3)) . '/receive/public'); - $r = q("INSERT INTO `contact` (`uid`, `network`,`addr`,`created`,`url`,`batch`,`name`,`nick`,`photo`,`pubkey`,`notify`,`poll`,`blocked`,`priority`) - VALUES ( %d, '%s', '%s', '%s','%s','%s','%s','%s','%s','%s','%s','%s',%d,%d) ", + $r = q("INSERT INTO `contact` (`uid`, `network`,`addr`,`created`,`url`,`nurl`,`batch`,`name`,`nick`,`photo`,`pubkey`,`notify`,`poll`,`blocked`,`priority`) + VALUES ( %d, '%s', '%s', '%s', '%s','%s','%s','%s','%s','%s','%s','%s','%s',%d,%d) ", intval($importer['uid']), dbesc($ret['network']), dbesc($ret['addr']), datetime_convert(), dbesc($ret['url']), + dbesc(normalise_link($ret['url'])), dbesc($batch), dbesc($ret['name']), dbesc($ret['nick']), @@ -589,10 +596,13 @@ function diaspora_post($importer,$xml) { function diaspora_reshare($importer,$xml) { + logger('diaspora_reshare: init: ' . print_r($xml,true)); + $a = get_app(); $guid = notags(unxmlify($xml->guid)); $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle); if(! $contact) return; @@ -624,15 +634,23 @@ function diaspora_reshare($importer,$xml) { logger('diaspora_reshare: unable to fetch source url ' . $source_url); return; } + logger('diaspora_reshare: source: ' . $x); + $x = str_replace(array('<activity_streams-photo>','</activity_streams-photo>'),array('<asphoto>','</asphoto>'),$x); $source_xml = parse_xml_string($x,false); - if(strlen($source_xml->asphoto->objectId) && ($source_xml->asphoto->objectId != 0) && ($source_xml->asphoto->image_url)) - $body = '[url=' . notags(unxmlify($source_xml->asphoto->image_url)) . '][img]' . notags(unxmlify($source_xml->asphoto->objectId)) . '[/img][/url]' . "\n"; - elseif($source_xml->asphoto->image_url) - $body = '[img]' . notags(unxmlify($source_xml->asphoto->image_url)) . '[/img]' . "\n"; - elseif($source_xml->status_message) { - $body = diaspora2bb($source_xml->status_message->raw_message); + if(strlen($source_xml->post->asphoto->objectId) && ($source_xml->post->asphoto->objectId != 0) && ($source_xml->post->asphoto->image_url)) { + $body = '[url=' . notags(unxmlify($source_xml->post->asphoto->image_url)) . '][img]' . notags(unxmlify($source_xml->post->asphoto->objectId)) . '[/img][/url]' . "\n"; + $body = scale_diaspora_images($body,false); + } + elseif($source_xml->post->asphoto->image_url) { + $body = '[img]' . notags(unxmlify($source_xml->post->asphoto->image_url)) . '[/img]' . "\n"; + $body = scale_diaspora_images($body); + } + elseif($source_xml->post->status_message) { + $body = diaspora2bb($source_xml->post->status_message->raw_message); + $body = scale_diaspora_images($body); + } else { logger('diaspora_reshare: no reshare content found: ' . print_r($source_xml,true)); @@ -668,8 +686,6 @@ function diaspora_reshare($importer,$xml) { $created = unxmlify($xml->created_at); $private = ((unxmlify($xml->public) == 'false') ? 1 : 0); - $body = diaspora2bb($xml->raw_message); - $datarray = array(); $str_tags = ''; @@ -765,16 +781,19 @@ function diaspora_asphoto($importer,$xml) { $created = unxmlify($xml->created_at); $private = ((unxmlify($xml->public) == 'false') ? 1 : 0); - if(strlen($xml->objectId) && ($xml->objectId != 0) && ($xml->image_url)) + if(strlen($xml->objectId) && ($xml->objectId != 0) && ($xml->image_url)) { $body = '[url=' . notags(unxmlify($xml->image_url)) . '][img]' . notags(unxmlify($xml->objectId)) . '[/img][/url]' . "\n"; - elseif($xml->image_url) + $body = scale_diaspora_images($body,false); + } + elseif($xml->image_url) { $body = '[img]' . notags(unxmlify($xml->image_url)) . '[/img]' . "\n"; + $body = scale_diaspora_images($body); + } else { logger('diaspora_asphoto: no photo url found.'); return; } - $datarray = array(); @@ -943,7 +962,10 @@ function diaspora_comment($importer,$xml,$msg) { $datarray['author-avatar'] = ((x($person,'thumb')) ? $person['thumb'] : $person['photo']); $datarray['body'] = $body; $datarray['tag'] = $str_tags; - $datarray['app'] = 'Diaspora'; + + // We can't be certain what the original app is if the message is relayed. + if(($parent_item['origin']) && (! $parent_author_signature)) + $datarray['app'] = 'Diaspora'; $message_id = item_store($datarray); @@ -954,7 +976,7 @@ function diaspora_comment($importer,$xml,$msg) { ); } - if(! $parent_author_signature) { + if(($parent_item['origin']) && (! $parent_author_signature)) { q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($message_id), dbesc($author_signed_data), @@ -1010,6 +1032,8 @@ function diaspora_photo($importer,$xml,$msg) { $link_text = '[img]' . $remote_photo_path . $remote_photo_name . '[/img]' . "\n"; + $link_text = scale_diaspora_images($link_text); + if(strpos($parent_item['body'],$link_text) === false) { $r = q("update item set `body` = '%s', `visible` = 1 where `id` = %d and `uid` = %d limit 1", dbesc($link_text . $parent_item['body']), @@ -1159,9 +1183,9 @@ EOT; $arr['parent'] = $parent_item['id']; $arr['parent-uri'] = $parent_item['uri']; - $arr['owner-name'] = $contact['name']; - $arr['owner-link'] = $contact['url']; - $arr['owner-avatar'] = $contact['thumb']; + $arr['owner-name'] = $parent_item['name']; + $arr['owner-link'] = $parent_item['url']; + $arr['owner-avatar'] = $parent_item['thumb']; $arr['author-name'] = $person['name']; $arr['author-link'] = $person['url']; @@ -1203,9 +1227,9 @@ EOT; // if the message isn't already being relayed, notify others // the existence of parent_author_signature means the parent_author or owner - // is already relaying. + // is already relaying. The parent_item['origin'] indicates the message was created on our system - if(! $parent_author_signature) + if(($parent_item['origin']) && (! $parent_author_signature)) proc_run('php','include/notifier.php','comment',$message_id); return; @@ -1243,6 +1267,51 @@ function diaspora_retraction($importer,$xml) { // NOTREACHED } +function diaspora_signed_retraction($importer,$xml) { + + $guid = notags(unxmlify($xml->target_guid)); + $diaspora_handle = notags(unxmlify($xml->sender_handle)); + $type = notags(unxmlify($xml->target_type)); + $sig = notags(unxmlify($xml->target_author_signature)); + + $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle); + if(! $contact) + return; + + // this may not yet work for comments. Need to see how the relaying works + // and figure out who signs it. + + + $signed_data = $guid . ';' . $type ; + + $sig = base64_decode($sig); + + $key = $msg['key']; + + if(! rsa_verify($signed_data,$sig,$key,'sha256')) { + logger('diaspora_signed_retraction: owner verification failed.' . print_r($msg,true)); + return; + } + + if($type === 'StatusMessage') { + $r = q("select * from item where guid = '%s' and uid = %d limit 1", + dbesc('guid'), + intval($importer['uid']) + ); + if(count($r)) { + if(link_compare($r[0]['author-link'],$contact['url'])) { + q("update item set `deleted` = 1, `changed` = '%s' where `id` = %d limit 1", + dbesc(datetime_convert()), + intval($r[0]['id']) + ); + } + } + } + + return 202; + // NOTREACHED +} + function diaspora_profile($importer,$xml) { $a = get_app(); @@ -1372,6 +1441,14 @@ function diaspora_send_status($item,$owner,$contact,$public_batch = false) { $body = $item['body']; +/* + // We're trying to match Diaspora's split message/photo protocol but + // all the photos are displayed on D* as links and not img's - even + // though we're sending pretty much precisely what they send us when + // doing the same operation. + // Commented out for now, we'll use bb2diaspora to convert photos to markdown + // which seems to get through intact. + $cnt = preg_match_all('|\[img\](.*?)\[\/img\]|',$body,$matches,PREG_SET_ORDER); if($cnt) { foreach($matches as $mtch) { @@ -1382,12 +1459,24 @@ function diaspora_send_status($item,$owner,$contact,$public_batch = false) { $detail['guid'] = $item['guid']; $detail['handle'] = $myaddr; $images[] = $detail; - $body = str_replace($detail['str'],t('link'),$body); + $body = str_replace($detail['str'],$mtch[1],$body); } } +*/ $body = xmlify(html_entity_decode(bb2diaspora($body))); + if($item['attach']) { + $cnt = preg_match_all('/href=\"(.*?)\"(.*?)title=\"(.*?)\"/ism',$item['attach'],$matches,PREG_SET_ORDER); + if(cnt) { + $body .= "\n" . t('Attachments:') . "\n"; + foreach($matches as $mtch) { + $body .= '[' . $mtch[3] . '](' . $mtch[1] . ')' . "\n"; + } + } + } + + $public = (($item['private']) ? 'false' : 'true'); require_once('include/datetime.php'); @@ -1618,11 +1707,14 @@ function diaspora_send_retraction($item,$owner,$contact,$public_batch = false) { $a = get_app(); $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); - $tpl = get_markup_template('diaspora_retract.tpl'); + $signed_text = $item['guid'] . ';' . 'StatusMessage'; + + $tpl = get_markup_template('diaspora_signed_retract.tpl'); $msg = replace_macros($tpl, array( '$guid' => $item['guid'], - '$type' => 'Post', - '$handle' => $myaddr + '$type' => 'StatusMessage', + '$handle' => $myaddr, + '$signature' => base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')) )); $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch))); @@ -1636,22 +1728,35 @@ function diaspora_transmit($owner,$contact,$slap,$public_batch) { $a = get_app(); $logid = random_string(4); - logger('diaspora_transmit: ' . $logid . ' ' . (($public_batch) ? $contact['batch'] : $contact['notify'])); - post_url((($public_batch) ? $contact['batch'] : $contact['notify']) . '/',$slap); + $dest_url = (($public_batch) ? $contact['batch'] : $contact['notify']); + if(! $dest_url) { + logger('diaspora_transmit: no url for contact: ' . $contact['id'] . ' batch mode =' . $public_batch); + return 0; + } + + logger('diaspora_transmit: ' . $logid . ' ' . $dest_url); + + post_url($dest_url . '/', $slap); + $return_code = $a->get_curl_code(); logger('diaspora_transmit: ' . $logid . ' returns: ' . $return_code); - if((! $return_code) || (($curl_stat == 503) && (stristr($a->get_curl_headers(),'retry-after')))) { + if((! $return_code) || (($return_code == 503) && (stristr($a->get_curl_headers(),'retry-after')))) { logger('diaspora_transmit: queue message'); - // queue message for redelivery - q("INSERT INTO `queue` ( `cid`, `created`, `last`, `content`,`batch`) - VALUES ( %d, '%s', '%s', '%s', %d) ", + + $r = q("SELECT id from queue where cid = %d and network = '%s' and content = '%s' and batch = %d limit 1", intval($contact['id']), - dbesc(datetime_convert()), - dbesc(datetime_convert()), + dbesc(NETWORK_DIASPORA), dbesc($slap), intval($public_batch) ); + if(count($r)) { + logger('diaspora_transmit: add_to_queue ignored - identical item already in queue'); + } + else { + // queue message for redelivery + add_to_queue($contact['id'],NETWORK_DIASPORA,$slap,$public_batch); + } } diff --git a/include/event.php b/include/event.php index 746422a13..c7669b381 100644 --- a/include/event.php +++ b/include/event.php @@ -53,7 +53,12 @@ function parse_event($h) { $ret = array(); - $dom = HTML5_Parser::parse($h); + + try { + $dom = HTML5_Parser::parse($h); + } catch (DOMException $e) { + logger('parse_event: parse error: ' . $e); + } if(! $dom) return $ret; diff --git a/include/items.php b/include/items.php index 8dc997b16..2af2b5f55 100644 --- a/include/items.php +++ b/include/items.php @@ -617,7 +617,7 @@ function get_atom_elements($feed,$item) { if(! $body) $body = $rawobj[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data']; // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events - $res['object'] .= '<orig>' . xmlify($body) . '</orig>' . "\n"; + $res['target'] .= '<orig>' . xmlify($body) . '</orig>' . "\n"; if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) { $body = html2bb_video($body); @@ -1263,7 +1263,8 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s'); } if($deleted && is_array($contact)) { - $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d AND `contact-id` = %d LIMIT 1", + $r = q("SELECT `item`.*, `contact`.`self` FROM `item` left join `contact` on `item`.`contact-id` = `contact`.`id` + WHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d LIMIT 1", dbesc($uri), intval($importer['uid']), intval($contact['id']) @@ -1274,6 +1275,41 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) if(! $item['deleted']) logger('consume_feed: deleting item ' . $item['id'] . ' uri=' . $item['uri'], LOGGER_DEBUG); + if(($item['verb'] === ACTIVITY_TAG) && ($item['object-type'] === ACTVITY_OBJ_TAGTERM)) { + $xo = parse_xml_string($item['object'],false); + $xt = parse_xml_string($item['target'],false); + if($xt->type === ACTIVITY_OBJ_NOTE) { + $i = q("select * from `item` where uri = '%s' and uid = %d limit 1", + dbesc($xt->id), + intval($importer['importer_uid']) + ); + if(count($i)) { + + // For tags, the owner cannot remove the tag on the author's copy of the post. + + $owner_remove = (($item['contact-id'] == $i[0]['contact-id']) ? true: false); + $author_remove = (($item['origin'] && $item['self']) ? true : false); + $author_copy = (($item['origin']) ? true : false); + + if($owner_remove && $author_copy) + continue; + if($author_remove || $owner_remove) { + $tags = explode(',',$i[0]['tag']); + $newtags = array(); + if(count($tags)) { + foreach($tags as $tag) + if(trim($tag) !== trim($xo->body)) + $newtags[] = trim($tag); + } + q("update item set tag = '%s' where id = %d limit 1", + dbesc(implode(',',$newtags)), + intval($i[0]['id']) + ); + } + } + } + } + if($item['uri'] == $item['parent-uri']) { $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', `body` = '', `title` = '' @@ -1420,6 +1456,30 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) $datarray['gravity'] = GRAVITY_LIKE; } + if(($datarray['verb'] === ACTIVITY_TAG) && ($datarray['object-type'] === ACTIVITY_OBJ_TAGTERM)) { + $xo = parse_xml_string($datarray['object'],false); + $xt = parse_xml_string($datarray['target'],false); + + if($xt->type == ACTIVITY_OBJ_NOTE) { + $r = q("select * from item where `uri` = '%s' AND `uid` = %d limit 1", + dbesc($xt->id), + intval($importer['importer_uid']) + ); + if(! count($r)) + continue; + + // extract tag, if not duplicate, add to parent item + if($xo->content) { + if(! (stristr($r[0]['tag'],trim($xo->content)))) { + q("UPDATE item SET tag = '%s' WHERE id = %d LIMIT 1", + dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'), + intval($r[0]['id']) + ); + } + } + } + } + $r = item_store($datarray,$force_parent); continue; } @@ -1797,7 +1857,8 @@ function local_delivery($importer,$data) { } if($deleted) { - $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d AND `contact-id` = %d LIMIT 1", + $r = q("SELECT `item`.*, `contact`.`self` FROM `item` left join contact on `item`.`contact-id` = `contact`.`id` + WHERE `uri` = '%s' AND `uid` = %d AND `contact-id` = %d LIMIT 1", dbesc($uri), intval($importer['importer_uid']), intval($importer['id']) @@ -1806,8 +1867,45 @@ function local_delivery($importer,$data) { if(count($r)) { $item = $r[0]; - if(! $item['deleted']) - logger('local_delivery: deleting item ' . $item['id'] . ' uri=' . $item['uri'], LOGGER_DEBUG); + if($item['deleted']) + continue; + + logger('local_delivery: deleting item ' . $item['id'] . ' uri=' . $item['uri'], LOGGER_DEBUG); + + if(($item['verb'] === ACTIVITY_TAG) && ($item['object-type'] === ACTVITY_OBJ_TAGTERM)) { + $xo = parse_xml_string($item['object'],false); + $xt = parse_xml_string($item['target'],false); + if($xt->type === ACTIVITY_OBJ_NOTE) { + $i = q("select * from `item` where uri = '%s' and uid = %d limit 1", + dbesc($xt->id), + intval($importer['importer_uid']) + ); + if(count($i)) { + + // For tags, the owner cannot remove the tag on the author's copy of the post. + + $owner_remove = (($item['contact-id'] == $i[0]['contact-id']) ? true: false); + $author_remove = (($item['origin'] && $item['self']) ? true : false); + $author_copy = (($item['origin']) ? true : false); + + if($owner_remove && $author_copy) + continue; + if($author_remove || $owner_remove) { + $tags = explode(',',$i[0]['tag']); + $newtags = array(); + if(count($tags)) { + foreach($tags as $tag) + if(trim($tag) !== trim($xo->body)) + $newtags[] = trim($tag); + } + q("update item set tag = '%s' where id = %d limit 1", + dbesc(implode(',',$newtags)), + intval($i[0]['id']) + ); + } + } + } + } if($item['uri'] == $item['parent-uri']) { $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' @@ -1867,7 +1965,8 @@ function local_delivery($importer,$data) { // was the top-level post for this reply written by somebody on this site? // Specifically, the recipient? - $r = q("select `item`.`id`, `contact`.`name`, `contact`.`url`, `contact`.`thumb` from `item` + $r = q("select `item`.`id`, `item`.`uri`, `item`.`tag`, + `contact`.`name`, `contact`.`url`, `contact`.`thumb` from `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` WHERE `contact`.`self` = 1 AND `item`.`wall` = 1 AND `item`.`uri` = '%s' AND `item`.`parent-uri` = '%s' AND `item`.`uid` = %d LIMIT 1", @@ -1896,12 +1995,39 @@ function local_delivery($importer,$data) { $datarray['owner-link'] = $r[0]['url']; $datarray['owner-avatar'] = $r[0]['thumb']; $datarray['contact-id'] = $importer['id']; - if(($datarray['verb'] == ACTIVITY_LIKE) || ($datarray['verb'] == ACTIVITY_DISLIKE)) { + if(($datarray['verb'] === ACTIVITY_LIKE) || ($datarray['verb'] === ACTIVITY_DISLIKE)) { $is_like = true; $datarray['type'] = 'activity'; $datarray['gravity'] = GRAVITY_LIKE; $datarray['last-child'] = 0; } + + if(($datarray['verb'] === ACTIVITY_TAG) && ($datarray['object-type'] === ACTIVITY_OBJ_TAGTERM)) { + + + $xo = parse_xml_string($datarray['object'],false); + $xt = parse_xml_string($datarray['target'],false); + + if(($xt->type == ACTIVITY_OBJ_NOTE) && ($xt->id == $r[0]['uri'])) { + + // extract tag, if not duplicate, and this user allows tags, add to parent item + if($xo->content) { + + if(! (stristr($r[0]['tag'],trim($xo->content)))) { + $i = q("SELECT `blocktags` FROM `user` where `uid` = %d LIMIT 1", + intval($importer['importer_uid']) + ); + if(count($i) && ! ($i[0]['blocktags'])) { + q("UPDATE item SET tag = '%s' WHERE id = %d LIMIT 1", + dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'), + intval($r[0]['id']) + ); + } + } + } + } + } + $posted_id = item_store($datarray); $parent = 0; @@ -2049,6 +2175,32 @@ function local_delivery($importer,$data) { $datarray['type'] = 'activity'; $datarray['gravity'] = GRAVITY_LIKE; } + + if(($datarray['verb'] === ACTIVITY_TAG) && ($datarray['object-type'] === ACTIVITY_OBJ_TAGTERM)) { + + $xo = parse_xml_string($datarray['object'],false); + $xt = parse_xml_string($datarray['target'],false); + + if($xt->type == ACTIVITY_OBJ_NOTE) { + $r = q("select * from item where `uri` = '%s' AND `uid` = %d limit 1", + dbesc($xt->id), + intval($importer['importer_uid']) + ); + if(! count($r)) + continue; + + // extract tag, if not duplicate, add to parent item + if($xo->content) { + if(! (stristr($r[0]['tag'],trim($xo->content)))) { + q("UPDATE item SET tag = '%s' WHERE id = %d LIMIT 1", + dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . '#[url=' . $xo->id . ']'. $xo->content . '[/url]'), + intval($r[0]['id']) + ); + } + } + } + } + $posted_id = item_store($datarray); // find out if our user is involved in this conversation and wants to be notified. @@ -2236,12 +2388,13 @@ function new_follower($importer,$contact,$datarray,$item,$sharing = false) { // create contact record - $r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `name`, `nick`, `photo`, `network`, `rel`, + $r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `name`, `nick`, `photo`, `network`, `rel`, `blocked`, `readonly`, `pending`, `writable` ) - VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, 0, 0, 1, 1 ) ", + VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, 0, 0, 1, 1 ) ", intval($importer['uid']), dbesc(datetime_convert()), dbesc($url), + dbesc(normalise_link($url)), dbesc($name), dbesc($nick), dbesc($photo), @@ -2523,7 +2676,7 @@ function item_getfeedtags($item) { if($cnt) { for($x = 0; $x < count($matches); $x ++) { if($matches[1][$x]) - $ret[] = array('#',$matches[1][$x], $matches[2][$x]); + $ret[] = array('@',$matches[1][$x], $matches[2][$x]); } } return $ret; @@ -2723,4 +2876,4 @@ function drop_item($id,$interactive = true) { //NOTREACHED } -}
\ No newline at end of file +} diff --git a/include/nav.php b/include/nav.php index 5c24df51e..62a8a6d11 100644 --- a/include/nav.php +++ b/include/nav.php @@ -147,7 +147,7 @@ function nav(&$a) { $banner = get_config('system','banner'); if($banner === false) - $banner .= '<a href="http://project.friendika.com"><img id="logo-img" src="images/friendika-32.png" alt="logo" /></a><span id="logo-text"><a href="http://project.friendika.com">Friendika</a></span>'; + $banner .= '<a href="http://project.friendika.com"><img id="logo-img" src="images/friendika-32.png" alt="logo" /></a><span id="logo-text"><a href="http://project.friendika.com">Friendica</a></span>'; $tpl = get_markup_template('nav.tpl'); diff --git a/include/network.php b/include/network.php index ec99d1e0d..a9ee3f0a5 100644 --- a/include/network.php +++ b/include/network.php @@ -429,7 +429,12 @@ function lrdd($uri) { // don't try and parse raw xml as html if(! strstr($html,'<?xml')) { require_once('library/HTML5/Parser.php'); - $dom = @HTML5_Parser::parse($html); + + try { + $dom = HTML5_Parser::parse($html); + } catch (DOMException $e) { + logger('lrdd: parse error: ' . $e); + } if($dom) { $items = $dom->getElementsByTagName('link'); @@ -727,7 +732,6 @@ function add_fcontact($arr,$update = false) { dbesc($arr['notify']), dbesc($arr['poll']), dbesc($arr['confirm']), - dbesc($arr['network']), dbesc($arr['alias']), dbesc($arr['pubkey']), dbesc(datetime_convert()), @@ -755,5 +759,6 @@ function add_fcontact($arr,$update = false) { dbesc(datetime_convert()) ); } + return $r; } diff --git a/include/notifier.php b/include/notifier.php index 18ad07012..a4fe9b71e 100644 --- a/include/notifier.php +++ b/include/notifier.php @@ -1,6 +1,7 @@ <?php require_once("boot.php"); +require_once('include/queue_fn.php'); /* * This file was at one time responsible for doing all deliveries, but this caused @@ -205,7 +206,7 @@ function notifier_run($argv, $argc){ /** * - * Be VERY CAREFUL if you make any changes to the following lines. Seemingly innocuous changes + * Be VERY CAREFUL if you make any changes to the following several lines. Seemingly innocuous changes * have been known to cause runaway conditions which affected several servers, along with * permissions issues. * @@ -217,6 +218,17 @@ function notifier_run($argv, $argc){ $relay_to_owner = true; } + // until the 'origin' flag has been in use for several months + // we will just use it as a fallback test + // later we will be able to use it as the primary test of whether or not to relay. + + if(! $target_item['origin']) + $relay_to_owner = false; + + if($parent['origin']) + $relay_to_owner = false; + + if($relay_to_owner) { logger('notifier: followup', LOGGER_DEBUG); @@ -519,13 +531,7 @@ function notifier_run($argv, $argc){ if($deliver_status == (-1)) { logger('notifier: delivery failed: queuing message'); // queue message for redelivery - q("INSERT INTO `queue` ( `cid`, `created`, `last`, `content`) - VALUES ( %d, '%s', '%s', '%s') ", - intval($contact['id']), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($atom) - ); + add_to_queue($contact['id'],NETWORK_DFRN,$atom); } break; case NETWORK_OSTATUS: @@ -542,14 +548,7 @@ function notifier_run($argv, $argc){ if($deliver_status == (-1)) { // queue message for redelivery - q("INSERT INTO `queue` ( `cid`, `created`, `last`, `content`) - VALUES ( %d, '%s', '%s', '%s') ", - intval($contact['id']), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($slap) - ); - + add_to_queue($contact['id'],NETWORK_OSTATUS,$slap); } } else { @@ -564,13 +563,7 @@ function notifier_run($argv, $argc){ $deliver_status = slapper($owner,$contact['notify'],$slappy); if($deliver_status == (-1)) { // queue message for redelivery - q("INSERT INTO `queue` ( `cid`, `created`, `last`, `content`) - VALUES ( %d, '%s', '%s', '%s') ", - intval($contact['id']), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($slappy) - ); + add_to_queue($contact['id'],NETWORK_OSTATUS,$slappy); } } } @@ -728,7 +721,7 @@ function notifier_run($argv, $argc){ if($public_message) { $r1 = q("SELECT DISTINCT(`batch`), `id`, `name`,`network` FROM `contact` WHERE `network` = '%s' - AND `uid` = %d AND `rel` != %d ORDER BY rand() ", + AND `uid` = %d AND `rel` != %d group by `batch` ORDER BY rand() ", dbesc(NETWORK_DIASPORA), intval($owner['uid']), intval(CONTACT_IS_SHARING) @@ -802,7 +795,6 @@ function notifier_run($argv, $argc){ call_hooks('notifier_end',$target_item); - return; } diff --git a/include/oembed.php b/include/oembed.php index 06f71a3b3..3e86627e4 100644 --- a/include/oembed.php +++ b/include/oembed.php @@ -1,36 +1,37 @@ <?php function oembed_replacecb($matches){ + logger('oembedcb'); $embedurl=$matches[1]; $j = oembed_fetch_url($embedurl); - return oembed_format_object($j); + $s = oembed_format_object($j); + return $s;//oembed_iframe($s,$j->width,$j->height); + + } function oembed_fetch_url($embedurl){ - - $r = q("SELECT v FROM `cache` WHERE k='%s'", - dbesc($embedurl)); + + $txt = Cache::get($embedurl); - if(count($r)){ - $txt = $r[0]['v']; - } else { + if(is_null($txt)){ $txt = ""; // try oembed autodiscovery $redirects = 0; $html_text = fetch_url($embedurl, false, $redirects, 15); - if(! $html_text) - return; - $dom = @DOMDocument::loadHTML($html_text); - if ($dom){ - $xpath = new DOMXPath($dom); - $attr = "oembed"; - - $xattr = oe_build_xpath("class","oembed"); - $entries = $xpath->query("//link[@type='application/json+oembed']"); - foreach($entries as $e){ - $href = $e->getAttributeNode("href")->nodeValue; - $txt = fetch_url($href); + if($html_text){ + $dom = @DOMDocument::loadHTML($html_text); + if ($dom){ + $xpath = new DOMXPath($dom); + $attr = "oembed"; + + $xattr = oe_build_xpath("class","oembed"); + $entries = $xpath->query("//link[@type='application/json+oembed']"); + foreach($entries as $e){ + $href = $e->getAttributeNode("href")->nodeValue; + $txt = fetch_url($href); + } } } @@ -44,10 +45,8 @@ function oembed_fetch_url($embedurl){ if ($txt[0]!="{") $txt='{"type":"error"}'; //save in cache - /*q("INSERT INTO `cache` VALUES ('%s','%s','%s')", - dbesc($embedurl), - dbesc($txt), - dbesc(datetime_convert()));*/ + Cache::set($embedurl,$txt); + } $j = json_decode($txt); @@ -57,18 +56,27 @@ function oembed_fetch_url($embedurl){ function oembed_format_object($j){ $embedurl = $j->embedurl; + $jhtml = oembed_iframe($j->html,$j->width,$j->height ); $ret="<span class='oembed ".$j->type."'>"; switch ($j->type) { case "video": { if (isset($j->thumbnail_url)) { - /*$tw = (isset($j->thumbnail_width)) ? $j->thumbnail_width:200; - $th = (isset($j->thumbnail_height)) ? $j->thumbnail_height:180;*/ - $tw=150; $th=120; - $ret.= "<a href='".$embedurl."' onclick='this.innerHTML=unescape(\"".urlencode($j->html)."\").replace(/\+/g,\" \"); return false;' style='float:left; margin: 1em; '>"; - $ret.= "<img width='$tw' height='$th' src='".$j->thumbnail_url."'>"; - $ret.= "</a>"; + $tw = (isset($j->thumbnail_width)) ? $j->thumbnail_width:200; + $th = (isset($j->thumbnail_height)) ? $j->thumbnail_height:180; + $tr = $tw/$th; + + $th=120; $tw = $th*$tr; + $tpl=get_markup_template('oembed_video.tpl'); + $ret.=replace_macros($tpl, array( + '$embedurl'=>$embedurl, + '$escapedhtml'=>base64_encode($jhtml), + '$tw'=>$tw, + '$th'=>$th, + '$turl'=>$j->thumbnail_url, + )); + } else { - $ret=$j->html; + $ret=$jhtml; } $ret.="<br>"; }; break; @@ -81,18 +89,40 @@ function oembed_format_object($j){ }; break; case "rich": { // not so safe.. - $ret.= "<blockquote>".$j->html."</blockquote>"; + $ret.= $jhtml; }; break; } - $embedlink = (isset($j->title))?$j->title:$embedurl; - $ret .= "<a href='$embedurl' rel='oembed'>$embedlink</a>"; - if (isset($j->author_name)) $ret.=" by ".$j->author_name; - if (isset($j->provider_name)) $ret.=" on ".$j->provider_name; + // add link to source if not present in "rich" type + if ( $j->type!='rich' || !strpos($j->html,$embedurl) ){ + $embedlink = (isset($j->title))?$j->title:$embedurl; + $ret .= "<a href='$embedurl' rel='oembed'>$embedlink</a>"; + if (isset($j->author_name)) $ret.=" by ".$j->author_name; + if (isset($j->provider_name)) $ret.=" on ".$j->provider_name; + } else { + // add <a> for html2bbcode conversion + $ret .= "<a href='$embedurl' rel='oembed'/>"; + } $ret.="<br style='clear:left'></span>"; - return $ret; + return mb_convert_encoding($ret, 'HTML-ENTITIES', mb_detect_encoding($ret)); +} + +function oembed_iframe($src,$width,$height) { + if(! $width || strstr($width,'%')) + $width = '640'; + if(! $height || strstr($height,'%')) + $height = '300'; + // try and leave some room for the description line. + $height = intval($height) + 80; + $width = intval($width) + 40; + + $s = 'data:text/html;base64,' . base64_encode('<html><body>' . $src . '</body></html>'); + return '<iframe height="' . $height . '" width="' . $width . '" src="' . $s . '" frameborder="no" >' . t('Embedded content') . '</iframe>'; + } + + function oembed_bbcode2html($text){ $stopoembed = get_config("system","no_oembed"); if ($stopoembed == true){ @@ -136,8 +166,8 @@ function oembed_html2bbcode($text) { $xattr = oe_build_xpath("class","oembed"); $entries = $xpath->query("//span[$xattr]"); - - $xattr = oe_build_xpath("rel","oembed"); + + $xattr = "@rel='oembed'";//oe_build_xpath("rel","oembed"); foreach($entries as $e) { $href = $xpath->evaluate("a[$xattr]/@href", $e)->item(0)->nodeValue; if(!is_null($href)) $e->parentNode->replaceChild(new DOMText("[embed]".$href."[/embed]"), $e); @@ -148,4 +178,5 @@ function oembed_html2bbcode($text) { } } -?>
\ No newline at end of file + + diff --git a/include/poller.php b/include/poller.php index cef0647b5..d9e5282f2 100644 --- a/include/poller.php +++ b/include/poller.php @@ -24,6 +24,7 @@ function poller_run($argv, $argc){ require_once('include/items.php'); require_once('include/Contact.php'); require_once('include/email.php'); + require_once('include/socgraph.php'); load_config('config'); load_config('system'); @@ -64,8 +65,7 @@ function poller_run($argv, $argc){ } // clear old cache - q("DELETE FROM `cache` WHERE `updated` < '%s'", - dbesc(datetime_convert('UTC','UTC',"now - 30 days"))); + Cache::clear(); $manual_id = 0; $generation = 0; @@ -108,13 +108,14 @@ function poller_run($argv, $argc){ $contacts = q("SELECT `contact`.`id` FROM `contact` LEFT JOIN `user` ON `user`.`uid` = `contact`.`uid` WHERE ( `rel` = %d OR `rel` = %d ) AND `poll` != '' - AND `network` != '%s' + AND NOT `network` IN ( '%s', '%s' ) $sql_extra AND `self` = 0 AND `contact`.`blocked` = 0 AND `contact`.`readonly` = 0 AND `user`.`account_expired` = 0 $abandon_sql ORDER BY RAND()", intval(CONTACT_IS_SHARING), intval(CONTACT_IS_FRIEND), - dbesc(NETWORK_DIASPORA) + dbesc(NETWORK_DIASPORA), + dbesc(NETWORK_FACEBOOK) ); if(! count($contacts)) { @@ -137,6 +138,9 @@ function poller_run($argv, $argc){ if($manual_id) $contact['last-update'] = '0000-00-00 00:00:00'; + if($contact['network'] === NETWORK_DFRN) + $contact['priority'] = 2; + if($contact['priority'] || $contact['subhub']) { $hub_update = true; @@ -218,7 +222,7 @@ function poller_run($argv, $argc){ $importer = $r[0]; - logger("poller: poll: IMPORTER: {$importer['name']}, CONTACT: {$contact['name']}"); + logger("poller: poll: ({$contact['id']}) IMPORTER: {$importer['name']}, CONTACT: {$contact['name']}"); $last_update = (($contact['last-update'] === '0000-00-00 00:00:00') ? datetime_convert('UTC','UTC','now - 30 days', ATOM_TIME) @@ -299,6 +303,13 @@ function poller_run($argv, $argc){ if((intval($res->status) != 0) || (! strlen($res->challenge)) || (! strlen($res->dfrn_id))) continue; + if(((float) $res->dfrn_version > 2.21) && ($contact['poco'] == '')) { + q("update contact set poco = '%s' where id = %d limit 1", + dbesc(str_replace('/profile/','/poco/', $contact['url'])), + intval($contact['id']) + ); + } + $postvars = array(); $sent_dfrn_id = hex2bin((string) $res->dfrn_id); @@ -522,6 +533,21 @@ function poller_run($argv, $argc){ intval($contact['id']) ); + + // load current friends if possible. + + if($contact['poco']) { + $r = q("SELECT count(*) as total from glink + where `cid` = %d and updated > UTC_TIMESTAMP() - INTERVAL 1 DAY", + intval($contact['id']) + ); + } + if(count($r)) { + if(! $r[0]['total']) { + poco_load($contact['id'],$importer_uid,$contact['poco']); + } + } + // loop - next contact } } diff --git a/include/profile_update.php b/include/profile_update.php new file mode 100644 index 000000000..61eaee75d --- /dev/null +++ b/include/profile_update.php @@ -0,0 +1,107 @@ +<?php + +require_once('include/datetime.php'); +require_once('include/diaspora.php'); +require_once('include/queue_fn.php'); + +function profile_change() { + + $a = get_app(); + + if(! local_user()) + return; + +// $url = $a->get_baseurl() . '/profile/' . $a->user['nickname']; +// if($url && strlen(get_config('system','directory_submit_url'))) +// proc_run('php',"include/directory.php","$url"); + + $recips = q("SELECT `id`,`name`,`network`,`pubkey`,`notify` FROM `contact` WHERE `network` = '%s' + AND `uid` = %d AND `rel` != %d ", + dbesc(NETWORK_DIASPORA), + intval(local_user()), + intval(CONTACT_IS_SHARING) + ); + if(! count($recips)) + return; + + $r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `user`.* FROM `profile` + LEFT JOIN `user` ON `profile`.`uid` = `user`.`uid` + WHERE `user`.`uid` = %d AND `profile`.`is-default` = 1 LIMIT 1", + intval(local_user()) + ); + + if(! count($r)) + return; + $profile = $r[0]; + + $handle = xmlify($a->user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3)); + $first = xmlify(((strpos($profile['name'],' ')) + ? trim(substr($profile['name'],0,strpos($profile['name'],' '))) : $profile['name'])); + $last = xmlify((($first === $profile['name']) ? '' : trim(substr($profile['name'],strlen($first))))); + $large = xmlify($a->get_baseurl() . '/photo/custom/300/' . $profile['uid'] . '.jpg'); + $medium = xmlify($a->get_baseurl() . '/photo/custom/100/' . $profile['uid'] . '.jpg'); + $small = xmlify($a->get_baseurl() . '/photo/custom/50/' . $profile['uid'] . '.jpg'); + $searchable = xmlify((($profile['publish'] && $profile['net-publish']) ? 'true' : 'false' )); +// $searchable = 'true'; + + if($searchable === 'true') { + $dob = '1000-00-00'; + + if(($profile['dob']) && ($profile['dob'] != '0000-00-00')) + $dob = ((intval($profile['dob'])) ? intval($profile['dob']) : '1000') . '-' . datetime_convert('UTC','UTC',$profile['dob'],'m-d'); + $gender = xmlify($profile['gender']); + $about = xmlify($profile['about']); + require_once('include/bbcode.php'); + $about = xmlify(strip_tags(bbcode($about))); + $location = ''; + if($profile['locality']) + $location .= $profile['locality']; + if($profile['region']) { + if($location) + $location .= ', '; + $location .= $profile['region']; + } + if($profile['country-name']) { + if($location) + $location .= ', '; + $location .= $profile['country-name']; + } + $location = xmlify($location); + $tags = ''; + if($profile['pub_keywords']) { + $kw = str_replace(',',' ',$profile['pub_keywords']); + $kw = str_replace(' ',' ',$kw); + $arr = explode(' ',$profile['pub_keywords']); + if(count($arr)) { + for($x = 0; $x < 5; $x ++) { + if(trim($arr[$x])) + $tags .= '#' . trim($arr[$x]) . ' '; + } + } + } + $tags = xmlify(trim($tags)); + } + + $tpl = get_markup_template('diaspora_profile.tpl'); + + $msg = replace_macros($tpl,array( + '$handle' => $handle, + '$first' => $first, + '$last' => $last, + '$large' => $large, + '$medium' => $medium, + '$small' => $small, + '$dob' => $dob, + '$gender' => $gender, + '$about' => $about, + '$location' => $location, + '$searchable' => $searchable, + '$tags' => $tags + )); + logger('profile_change: ' . $msg, LOGGER_ALL); + + foreach($recips as $recip) { + $msgtosend = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$a->user,$recip,$a->user['prvkey'],$recip['pubkey'],false))); + add_to_queue($recip['id'],NETWORK_DIASPORA,$msgtosend,false); + } +} diff --git a/include/queue_fn.php b/include/queue_fn.php index bc47ceffd..3c1087f4e 100644 --- a/include/queue_fn.php +++ b/include/queue_fn.php @@ -14,3 +14,41 @@ function remove_queue_item($id) { intval($id) ); } + + +function add_to_queue($cid,$network,$msg,$batch = false) { + + $max_queue = get_config('system','max_contact_queue'); + if($max_queue < 1) + $max_queue = 500; + + $batch_queue = get_config('system','max_batch_queue'); + if($batch_queue < 1) + $batch_queue = 1000; + + $r = q("SELECT COUNT(*) AS `total` FROM `queue` left join `contact` ON `queue`.`cid` = `contact`.`id` + WHERE `queue`.`cid` = %d AND `contact`.`self` = 0 ", + intval($cid) + ); + if($r && count($r)) { + if($batch && ($r[0]['total'] > $batch_queue)) { + logger('add_to_queue: too many queued items for batch server ' . $cid . ' - discarding message'); + return; + } + elseif((! $batch) && ($r[0]['total'] > $max_queue)) { + logger('add_to_queue: too many queued items for contact ' . $cid . ' - discarding message'); + return; + } + } + + q("INSERT INTO `queue` ( `cid`, `network`, `created`, `last`, `content`, `batch`) + VALUES ( %d, '%s', '%s', '%s', '%s', %d) ", + intval($cid), + dbesc($network), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc($msg), + intval(($batch) ? 1: 0) + ); + +} diff --git a/include/socgraph.php b/include/socgraph.php new file mode 100644 index 000000000..84cfe4468 --- /dev/null +++ b/include/socgraph.php @@ -0,0 +1,185 @@ +<?php + +require_once('include/datetime.php'); + + +/* + * poco_load + * + * Given a contact-id (minimum), load the PortableContacts friend list for that contact, + * and add the entries to the gcontact (Global Contact) table, or update existing entries + * if anything (name or photo) has changed. + * We use normalised urls for comparison which ignore http vs https and www.domain vs domain + * + * Once the global contact is stored add (if necessary) the contact linkage which associates + * the given uid, cid to the global contact entry. There can be many uid/cid combinations + * pointing to the same global contact id. + * + */ + + + + +function poco_load($cid,$uid = 0,$url = null) { + $a = get_app(); + if((! $url) || (! $uid)) { + $r = q("select `poco`, `uid` from `contact` where `id` = %d limit 1", + intval($cid) + ); + if(count($r)) { + $url = $r[0]['poco']; + $uid = $r[0]['uid']; + } + } + if((! $url) || (! $uid)) + return; + $s = fetch_url($url . '/@me/@all?fields=displayName,urls,photos'); + + if(($a->get_curl_code() > 299) || (! $s)) + return; + $j = json_decode($s); + foreach($j->entry as $entry) { + + $profile_url = ''; + $profile_photo = ''; + $name = ''; + + $name = $entry->displayName; + + foreach($entry->urls as $url) { + if($url->type == 'profile') { + $profile_url = $url->value; + break; + } + } + foreach($entry->photos as $photo) { + if($photo->type == 'profile') { + $profile_photo = $photo->value; + break; + } + } + + if((! $name) || (! $profile_url) || (! $profile_photo)) + continue; + + $x = q("select * from `gcontact` where `nurl` = '%s' limit 1", + dbesc(normalise_link($profile_url)) + ); + if(count($x)) { + $gcid = $x[0]['id']; + + if($x[0]['name'] != $name || $x[0]['photo'] != $profile_photo) { + q("update gcontact set `name` = '%s', `photo` = '%s' where + `nurl` = '%s' limit 1", + dbesc($name), + dbesc($profile_photo), + dbesc(normalise_link($profile_url)) + ); + } + } + else { + q("insert into `gcontact` (`name`,`url`,`nurl`,`photo`) + values ( '%s', '%s', '%s', '%s') ", + dbesc($name), + dbesc($profile_url), + dbesc(normalise_link($profile_url)), + dbesc($profile_photo) + ); + $x = q("select * from `gcontact` where `nurl` = '%s' limit 1", + dbesc(normalise_link($profile_url)) + ); + if(count($x)) + $gcid = $x[0]['id']; + } + if(! $gcid) + return; + + $r = q("select * from glink where `cid` = %d and `uid` = %d and `gcid` = %d limit 1", + intval($cid), + intval($uid), + intval($gcid) + ); + if(! count($r)) { + q("insert into glink ( `cid`,`uid`,`gcid`,`updated`) values (%d,%d,%d,'%s') ", + intval($cid), + intval($uid), + intval($gcid), + dbesc(datetime_convert()) + ); + } + else { + q("update glink set updated = '%s' where `cid` = %d and `uid` = %d and `gcid` = %d limit 1", + dbesc(datetime_convert()), + intval($cid), + intval($uid), + intval($gcid) + ); + } + + } + + q("delete from glink where `cid` = %d and `uid` = %d and `updated` < UTC_TIMESTAMP - INTERVAL 2 DAY", + intval($cid), + intval($uid) + ); + +} + + +function count_common_friends($uid,$cid) { + + $r = q("SELECT count(*) as `total` + FROM `glink` left join `gcontact` on `glink`.`gcid` = `gcontact`.`id` + where `glink`.`cid` = %d and `glink`.`uid` = %d + and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and id != %d ) ", + intval($cid), + intval($uid), + intval($uid), + intval($cid) + ); + + if(count($r)) + return $r[0]['total']; + return 0; + +} + + +function common_friends($uid,$cid) { + + $r = q("SELECT `gcontact`.* + FROM `glink` left join `gcontact` on `glink`.`gcid` = `gcontact`.`id` + where `glink`.`cid` = %d and `glink`.`uid` = %d + and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and id != %d ) ", + intval($cid), + intval($uid), + intval($uid), + intval($cid) + ); + + return $r; + +} + + + +function suggestion_query($uid, $start = 0, $limit = 40) { + + if(! $uid) + return array(); + + $r = q("SELECT count(glink.gcid) as `total`, gcontact.* from gcontact + left join glink on glink.gcid = gcontact.id + where uid = %d and not gcontact.nurl in ( select nurl from contact where uid = %d) + and not gcontact.id in ( select gcid from gcign where uid = %d ) + group by glink.gcid order by total desc limit %d, %d ", + intval($uid), + intval($uid), + intval($uid), + intval($start), + intval($limit) + ); + + return $r; + +} diff --git a/include/template_processor.php b/include/template_processor.php index 63d75eaa4..25f7703a2 100644 --- a/include/template_processor.php +++ b/include/template_processor.php @@ -165,17 +165,17 @@ $this->r = $r; $this->search = array(); $this->replace = array(); - + $this->_build_replace($r, ""); #$s = str_replace(array("\n","\r"),array("§n§","§r§"),$s); $s = $this->_build_nodes($s); + $s = preg_replace_callback('/\|\|([0-9]+)\|\|/', array($this, "_replcb_node"), $s); if ($s==Null) $this->_preg_error(); // remove comments block $s = preg_replace('/{#[^#]*#}/', "" , $s); - // replace strings recursively (limit to 10 loops) $os = ""; $count=0; while($os!=$s && $count<10){ diff --git a/include/text.php b/include/text.php index 299410a63..59fc15007 100644 --- a/include/text.php +++ b/include/text.php @@ -195,6 +195,9 @@ function unxmlify($s) { if(! function_exists('hex2bin')) { function hex2bin($s) { + if(! (is_string($s) && strlen($s))) + return ''; + if(! ctype_xdigit($s)) { logger('hex2bin: illegal input: ' . print_r(debug_backtrace(), true)); return($s); @@ -462,7 +465,7 @@ function get_tags($s) { // Match full names against @tags including the space between first and last // We will look these up afterward to see if they are full names or not recognisable. - if(preg_match_all('/(@[^ \x0D\x0A,:?]+ [^ \x0D\x0A,:?]+)([ \x0D\x0A,:?]|$)/',$s,$match)) { + if(preg_match_all('/(@[^ \x0D\x0A,:?]+ [^ \x0D\x0A@,:?]+)([ \x0D\x0A@,:?]|$)/',$s,$match)) { foreach($match[1] as $mtch) { if(strstr($mtch,"]")) { // we might be inside a bbcode color tag - leave it alone @@ -478,7 +481,7 @@ function get_tags($s) { // Otherwise pull out single word tags. These can be @nickname, @first_last // and #hash tags. - if(preg_match_all('/([@#][^ \x0D\x0A,:?]+)([ \x0D\x0A,:?]|$)/',$s,$match)) { + if(preg_match_all('/([@#][^ \x0D\x0A,;:?]+)([ \x0D\x0A,;:?]|$)/',$s,$match)) { foreach($match[1] as $mtch) { if(strstr($mtch,"]")) { // we might be inside a bbcode color tag - leave it alone @@ -669,7 +672,7 @@ function smilies($s) { $s = str_replace( array( '<3', '</3', '<\\3', ':-)', ':)', ';-)', ':-(', ':(', ':-P', ':P', ':-"', ':-x', ':-X', ':-D', '8-|', '8-O', - '~friendika', 'Diaspora*' ), + '~friendika', '~friendica', 'Diaspora*' ), array( '<img src="' . $a->get_baseurl() . '/images/smiley-heart.gif" alt="<3" />', '<img src="' . $a->get_baseurl() . '/images/smiley-brokenheart.gif" alt="</3" />', @@ -688,6 +691,7 @@ function smilies($s) { '<img src="' . $a->get_baseurl() . '/images/smiley-surprised.gif" alt="8-|" />', '<img src="' . $a->get_baseurl() . '/images/smiley-surprised.gif" alt="8-O" />', '<a href="http://project.friendika.com">~friendika <img src="' . $a->get_baseurl() . '/images/friendika-16.png" alt="~friendika" /></a>', + '<a href="http://friendica.com">~friendica <img src="' . $a->get_baseurl() . '/images/friendika-16.png" alt="~friendica" /></a>', '<a href="http://diasporafoundation.org">Diaspora<img src="' . $a->get_baseurl() . '/images/diaspora.png" alt="Diaspora*" /></a>', ), $s); @@ -748,7 +752,9 @@ function prepare_body($item,$attach = false) { $s = prepare_text($item['body']); - call_hooks('prepare_body', $s); + $prep_arr = array('item' => $item, 'html' => $s); + call_hooks('prepare_body', $prep_arr); + $s = $prep_arr['html']; if(! $attach) return $s; @@ -781,8 +787,19 @@ function prepare_body($item,$attach = false) { } $s .= '<div class="clear"></div></div>'; } - call_hooks('prepare_body_final', $s); - return $s; + + $arr = explode(',',$item['tag']); + if(count($arr)) { + $s .= '<div class="body-tag">'; + foreach($arr as $r) { + $s .= bbcode($r) . ' '; + } + $s .= '</div>'; + } + + $prep_arr = array('item' => $item, 'html' => $s); + call_hooks('prepare_body_final', $prep_arr); + return $prep_arr['html']; }} @@ -1036,4 +1053,13 @@ function html2bb_video($s) { '[vimeo]$2[/vimeo]', $s); return $s; -}
\ No newline at end of file +} + +/** + * apply xmlify() to all values of array $val, recursively + */ +function array_xmlify($val){ + if (is_bool($val)) return $val?"true":"false"; + if (is_array($val)) return array_map('array_xmlify', $val); + return xmlify((string) $val); +} diff --git a/js/country.js b/js/country.js index 07ab29ba6..b18a529d1 100644 --- a/js/country.js +++ b/js/country.js @@ -233,7 +233,7 @@ aStates[207]="|Bellona|Central|Choiseul (Lauru)|Guadalcanal|Honiara|Isabel|Makir aStates[208]="|Awdal|Bakool|Banaadir|Bari|Bay|Galguduud|Gedo|Hiiraan|Jubbada Dhexe|Jubbada Hoose|Mudug|Nugaal|Sanaag|Shabeellaha Dhexe|Shabeellaha Hoose|Sool|Togdheer|Woqooyi Galbeed";
aStates[209]="|Eastern Cape|Free State|Gauteng|KwaZulu-Natal|Mpumalanga|North-West|Northern Cape|Northern Province|Western Cape";
aStates[210]="|Bird Island|Bristol Island|Clerke Rocks|Montagu Island|Saunders Island|South Georgia|Southern Thule|Traversay Islands";
-aStates[211]="|Andalucia|Aragon|Asturias|Baleares (Balearic Islands)|Canarias (Canary Islands)|Cantabria|Castilla y Leon|Castilla-La Mancha|Cataluna|Ceuta|Communidad Valencian|Extremadura|Galicia|Islas Chafarinas|La Rioja|Madrid|Melilla|Murcia|Navarra|Pais Vasco (Basque Country)|Penon de Alhucemas|Penon de Velez de la Gomera";
+aStates[211]="|Andalucia|Aragon|Asturias|Baleares (Balearic Islands)|Canarias (Canary Islands)|Cantabria|Castilla y Leon|Castilla-La Mancha|Catalunya|Ceuta|Communidad Valencian|Extremadura|Galicia|Islas Chafarinas|La Rioja|Madrid|Melilla|Murcia|Navarra|Pais Vasco (Basque Country)|Penon de Alhucemas|Penon de Velez de la Gomera";
aStates[212]="|Spratly Islands";
aStates[213]="|Central|Eastern|North Central|North Eastern|North Western|Northern|Sabaragamuwa|Southern|Uva|Western";
aStates[214]="|A'ali an Nil|Al Bahr al Ahmar|Al Buhayrat|Al Jazirah|Al Khartum|Al Qadarif|Al Wahdah|An Nil al Abyad|An Nil al Azraq|Ash Shamaliyah|Bahr al Jabal|Gharb al Istiwa'iyah|Gharb Bahr al Ghazal|Gharb Darfur|Gharb Kurdufan|Janub Darfur|Janub Kurdufan|Junqali|Kassala|Nahr an Nil|Shamal Bahr al Ghazal|Shamal Darfur|Shamal Kurdufan|Sharq al Istiwa'iyah|Sinnar|Warab";
diff --git a/js/fk.autocomplete.js b/js/fk.autocomplete.js new file mode 100644 index 000000000..3f73c6fbb --- /dev/null +++ b/js/fk.autocomplete.js @@ -0,0 +1,182 @@ +/** + * Friendika people autocomplete + * + * require jQuery, jquery.textareas + */ + + + +function ACPopup(elm,backend_url){ + this.idsel=-1; + this.element = elm; + this.searchText=""; + this.ready=true; + this.kp_timer = false; + this.url = backend_url; + + if(typeof elm.editorId == "undefined") { + style = $(elm).offset(); + w = $(elm).width(); + h = $(elm).height(); + } + else { + style = $(elm.container).offset(); + w = elm.container.offsetWidth; + h = elm.container.offsetHeight; + } + + style.top=style.top+h; + style.width = w; + style.position = 'absolute'; + /* style['max-height'] = '150px'; + style.border = '1px solid red'; + style.background = '#cccccc'; + + style.overflow = 'auto'; + style['z-index'] = '100000'; + */ + style.display = 'none'; + + this.cont = $("<div class='acpopup'></div>"); + this.cont.css(style); + + $("body").append(this.cont); +} +ACPopup.prototype.close = function(){ + $(this.cont).remove(); + this.ready=false; +} +ACPopup.prototype.search = function(text){ + var that = this; + this.searchText=text; + if (this.kp_timer) clearTimeout(this.kp_timer); + this.kp_timer = setTimeout( function(){that._search();}, 500); +} +ACPopup.prototype._search = function(){ + console.log("_search"); + var that = this; + var postdata = { + start:0, + count:100, + search:this.searchText, + type:'c', + } + + $.ajax({ + type:'POST', + url: this.url, + data: postdata, + dataType: 'json', + success:function(data){ + that.cont.html(""); + if (data.tot>0){ + that.cont.show(); + $(data.items).each(function(){ + html = "<img src='{0}' height='16px' width='16px'>{1} ({2})".format(this.photo, this.name, this.nick) + that.add(html, this.nick + '+' + this.id + ' - ' + this.link); + }); + } else { + that.cont.hide(); + } + } + }); + +} + ACPopup.prototype.add = function(label, value){ + var that=this; + var elm = $("<div class='acpopupitem' title='"+value+"'>"+label+"</div>"); + elm.click(function(e){ + t = $(this).attr('title').replace(new RegExp(' \- .*'),''); + if(typeof(that.element.container) === "undefined") { + el=$(that.element); + sel = el.getSelection(); + sel.start = sel.start- that.searchText.length; + el.setSelection(sel.start,sel.end).replaceSelectedText(t+' ').collapseSelection(false); + that.close(); + } + else { + txt = tinyMCE.activeEditor.getContent(); + newtxt = txt.replace(that.searchText,t+' '); + tinyMCE.activeEditor.setContent(newtxt); + tinyMCE.activeEditor.focus(); + that.close(); + } + }); + $(this.cont).append(elm); +} +ACPopup.prototype.onkey = function(event){ + if (event.keyCode == '13' && this.idsel>-1) { + this.cont.children()[this.idsel].click(); + event.preventDefault(); + } + if (event.keyCode == '38') { //cursor up + cmax = this.cont.children().size()-1; + this.idsel--; + if (this.idsel<0) this.idsel=cmax; + event.preventDefault(); + } + if (event.keyCode == '40') { //cursor down + cmax = this.cont.children().size()-1; + this.idsel++; + if (this.idsel>cmax) this.idsel=0; + event.preventDefault(); + } + + if (event.keyCode == '38' || event.keyCode == '40' ) { + this.cont.children().removeClass('selected'); + $(this.cont.children()[this.idsel]).addClass('selected'); + } + + if (event.keyCode == '27') { //ESC + this.close(); + } +} + +function ContactAutocomplete(element,backend_url){ + this.pattern=/@([^ \n]+)$/; + this.popup=null; + var that = this; + + $(element).unbind('keydown'); + $(element).unbind('keyup'); + + $(element).keydown(function(event){ + if (that.popup!==null) that.popup.onkey(event); + }); + + $(element).keyup(function(event){ + cpos = $(this).getSelection(); + if (cpos.start==cpos.end){ + match = $(this).val().substring(0,cpos.start).match(that.pattern); + if (match!==null){ + if (that.popup===null){ + that.popup = new ACPopup(this, backend_url); + } + if (that.popup.ready && match[1]!==that.popup.searchText) that.popup.search(match[1]); + if (!that.popup.ready) that.popup=null; + + } else { + if (that.popup!==null) {that.popup.close(); that.popup=null;} + } + + + } + }); + +} + + +/** + * jQuery plugin 'contact_autocomplete' + */ +(function( $ ){ + $.fn.contact_autocomplete = function(backend_url) { + this.each(function(){ + new ContactAutocomplete(this, backend_url); + }); + }; +})( jQuery ); + + + + diff --git a/js/jquery.textinputs.js b/js/jquery.textinputs.js new file mode 100644 index 000000000..fd6d14569 --- /dev/null +++ b/js/jquery.textinputs.js @@ -0,0 +1,20 @@ +/* + Rangy Text Inputs, a cross-browser textarea and text input library plug-in for jQuery. + + Part of Rangy, a cross-browser JavaScript range and selection library + http://code.google.com/p/rangy/ + + Depends on jQuery 1.0 or later. + + Copyright 2010, Tim Down + Licensed under the MIT license. + Version: 0.1.205 + Build date: 5 November 2010 +*/ +(function(n){function o(e,g){var a=typeof e[g];return a==="function"||!!(a=="object"&&e[g])||a=="unknown"}function p(e,g,a){if(g<0)g+=e.value.length;if(typeof a=="undefined")a=g;if(a<0)a+=e.value.length;return{start:g,end:a}}function k(){return typeof document.body=="object"&&document.body?document.body:document.getElementsByTagName("body")[0]}var i,h,q,l,r,s,t,u,m;n(document).ready(function(){function e(a,b){return function(){var c=this.jquery?this[0]:this,d=c.nodeName.toLowerCase();if(c.nodeType== +1&&(d=="textarea"||d=="input"&&c.type=="text")){c=[c].concat(Array.prototype.slice.call(arguments));c=a.apply(this,c);if(!b)return c}if(b)return this}}var g=document.createElement("textarea");k().appendChild(g);if(typeof g.selectionStart!="undefined"&&typeof g.selectionEnd!="undefined"){i=function(a){return{start:a.selectionStart,end:a.selectionEnd,length:a.selectionEnd-a.selectionStart,text:a.value.slice(a.selectionStart,a.selectionEnd)}};h=function(a,b,c){b=p(a,b,c);a.selectionStart=b.start;a.selectionEnd= +b.end};m=function(a,b){if(b)a.selectionEnd=a.selectionStart;else a.selectionStart=a.selectionEnd}}else if(o(g,"createTextRange")&&typeof document.selection=="object"&&document.selection&&o(document.selection,"createRange")){i=function(a){var b=0,c=0,d,f,j;if((j=document.selection.createRange())&&j.parentElement()==a){f=a.value.length;d=a.value.replace(/\r\n/g,"\n");c=a.createTextRange();c.moveToBookmark(j.getBookmark());j=a.createTextRange();j.collapse(false);if(c.compareEndPoints("StartToEnd",j)> +-1)b=c=f;else{b=-c.moveStart("character",-f);b+=d.slice(0,b).split("\n").length-1;if(c.compareEndPoints("EndToEnd",j)>-1)c=f;else{c=-c.moveEnd("character",-f);c+=d.slice(0,c).split("\n").length-1}}}return{start:b,end:c,length:c-b,text:a.value.slice(b,c)}};h=function(a,b,c){b=p(a,b,c);c=a.createTextRange();var d=b.start-(a.value.slice(0,b.start).split("\r\n").length-1);c.collapse(true);if(b.start==b.end)c.move("character",d);else{c.moveEnd("character",b.end-(a.value.slice(0,b.end).split("\r\n").length- +1));c.moveStart("character",d)}c.select()};m=function(a,b){var c=document.selection.createRange();c.collapse(b);c.select()}}else{k().removeChild(g);window.console&&window.console.log&&window.console.log("TextInputs module for Rangy not supported in your browser. Reason: No means of finding text input caret position");return}k().removeChild(g);l=function(a,b,c,d){var f;if(b!=c){f=a.value;a.value=f.slice(0,b)+f.slice(c)}d&&h(a,b,b)};q=function(a){var b=i(a);l(a,b.start,b.end,true)};u=function(a){var b= +i(a),c;if(b.start!=b.end){c=a.value;a.value=c.slice(0,b.start)+c.slice(b.end)}h(a,b.start,b.start);return b.text};r=function(a,b,c,d){var f=a.value;a.value=f.slice(0,c)+b+f.slice(c);if(d){b=c+b.length;h(a,b,b)}};s=function(a,b){var c=i(a),d=a.value;a.value=d.slice(0,c.start)+b+d.slice(c.end);c=c.start+b.length;h(a,c,c)};t=function(a,b,c){var d=i(a),f=a.value;a.value=f.slice(0,d.start)+b+d.text+c+f.slice(d.end);b=d.start+b.length;h(a,b,b+d.length)};n.fn.extend({getSelection:e(i,false),setSelection:e(h, +true),collapseSelection:e(m,true),deleteSelectedText:e(q,true),deleteText:e(l,true),extractSelectedText:e(u,false),insertText:e(r,true),replaceSelectedText:e(s,true),surroundSelectedText:e(t,true)})})})(jQuery);
\ No newline at end of file diff --git a/js/main.js b/js/main.js index 03ba11ed8..15c5b5d1f 100644 --- a/js/main.js +++ b/js/main.js @@ -78,8 +78,6 @@ menu.toggle(); return false; }); - - /* notifications template */ var notifications_tpl= unescape($("#nav-notifications-template[rel=template]").html()); @@ -163,7 +161,9 @@ } } - }); + }); + + }); function NavUpdate() { @@ -245,6 +245,8 @@ commentBusy = false; $('body').css('cursor', 'auto'); } + /* autocomplete @nicknames */ + $(".comment-edit-wrapper textarea").contact_autocomplete(baseurl+"/acl"); }); } @@ -445,6 +447,7 @@ function setupFieldRichtext(){ }); } + /** * sprintf in javascript * "{0} and {1}".format('zero','uno'); diff --git a/js/webtoolkit.base64.js b/js/webtoolkit.base64.js new file mode 100644 index 000000000..5fa3c1ed7 --- /dev/null +++ b/js/webtoolkit.base64.js @@ -0,0 +1,142 @@ +/** +* +* Base64 encode / decode +* http://www.webtoolkit.info/ +* +**/ + +var Base64 = { + + // private property + _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", + + // public method for encoding + encode : function (input) { + var output = ""; + var chr1, chr2, chr3, enc1, enc2, enc3, enc4; + var i = 0; + + input = Base64._utf8_encode(input); + + while (i < input.length) { + + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + + output = output + + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4); + + } + + return output; + }, + + // public method for decoding + decode : function (input) { + var output = ""; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + + while (i < input.length) { + + enc1 = this._keyStr.indexOf(input.charAt(i++)); + enc2 = this._keyStr.indexOf(input.charAt(i++)); + enc3 = this._keyStr.indexOf(input.charAt(i++)); + enc4 = this._keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + output = output + String.fromCharCode(chr1); + + if (enc3 != 64) { + output = output + String.fromCharCode(chr2); + } + if (enc4 != 64) { + output = output + String.fromCharCode(chr3); + } + + } + + output = Base64._utf8_decode(output); + + return output; + + }, + + // private method for UTF-8 encoding + _utf8_encode : function (string) { + string = string.replace(/\r\n/g,"\n"); + var utftext = ""; + + for (var n = 0; n < string.length; n++) { + + var c = string.charCodeAt(n); + + if (c < 128) { + utftext += String.fromCharCode(c); + } + else if((c > 127) && (c < 2048)) { + utftext += String.fromCharCode((c >> 6) | 192); + utftext += String.fromCharCode((c & 63) | 128); + } + else { + utftext += String.fromCharCode((c >> 12) | 224); + utftext += String.fromCharCode(((c >> 6) & 63) | 128); + utftext += String.fromCharCode((c & 63) | 128); + } + + } + + return utftext; + }, + + // private method for UTF-8 decoding + _utf8_decode : function (utftext) { + var string = ""; + var i = 0; + var c = c1 = c2 = 0; + + while ( i < utftext.length ) { + + c = utftext.charCodeAt(i); + + if (c < 128) { + string += String.fromCharCode(c); + i++; + } + else if((c > 191) && (c < 224)) { + c2 = utftext.charCodeAt(i+1); + string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); + i += 2; + } + else { + c2 = utftext.charCodeAt(i+1); + c3 = utftext.charCodeAt(i+2); + string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + + } + + return string; + } + +} diff --git a/library/HTML5/TreeBuilder.php b/library/HTML5/TreeBuilder.php index 03e2ee77f..a64816f56 100644 --- a/library/HTML5/TreeBuilder.php +++ b/library/HTML5/TreeBuilder.php @@ -3041,6 +3041,8 @@ class HTML5_TreeBuilder { if (!empty($token['attr'])) { foreach($token['attr'] as $attr) { + // mike@macgirvin.com 2011-10-21, stray double quotes cause everything to abort + $attr['name'] = str_replace('"','',$attr['name']); if(!$el->hasAttribute($attr['name'])) { $el->setAttribute($attr['name'], $attr['value']); } diff --git a/library/tinymce/jscripts/tiny_mce/plugins/bbcode/editor_plugin_src.js b/library/tinymce/jscripts/tiny_mce/plugins/bbcode/editor_plugin_src.js index 789e75c39..9e680e104 100644 --- a/library/tinymce/jscripts/tiny_mce/plugins/bbcode/editor_plugin_src.js +++ b/library/tinymce/jscripts/tiny_mce/plugins/bbcode/editor_plugin_src.js @@ -53,19 +53,24 @@ /* oembed */ function _h2b_cb(match) { - text = bin2hex(match); function s_h2b(data) { match = data; - } - $.ajax({ - url: 'oembed/h2b?text=' + text, + }
+ $.ajax({
+ type:"POST", + url: 'oembed/h2b',
+ data: {text: match}, async: false, success: s_h2b, dataType: 'html' }); return match; } - s = s.replace(/<span class=\"oembed(.*?)<\/span>/gi, _h2b_cb); + if (s.indexOf('class="oembed')>=0){
+ //alert("request oembed html2bbcode");
+ s = _h2b_cb(s);
+ }
+ /* /oembed */ @@ -154,4 +159,4 @@ // Register plugin
tinymce.PluginManager.add('bbcode', tinymce.plugins.BBCodePlugin);
-})();
\ No newline at end of file +})();
diff --git a/mod/acl.php b/mod/acl.php index f2d2456a6..735c2c0b0 100644 --- a/mod/acl.php +++ b/mod/acl.php @@ -10,73 +10,90 @@ function acl_init(&$a){ $start = (x($_POST,'start')?$_POST['start']:0); $count = (x($_POST,'count')?$_POST['count']:100); $search = (x($_POST,'search')?$_POST['search']:""); + $type = (x($_POST,'type')?$_POST['type']:""); + if ($search!=""){ $sql_extra = "AND `name` LIKE '%%".dbesc($search)."%%'"; + $sql_extra2 = "AND (`attag` LIKE '%%".dbesc($search)."%%' OR `name` LIKE '%%".dbesc($search)."%%' OR `nick` LIKE '%%".dbesc($search)."%%')"; } // count groups and contacts - $r = q("SELECT COUNT(`id`) AS g FROM `group` WHERE `deleted` = 0 AND `uid` = %d $sql_extra", - intval(local_user()) - ); - $group_count = (int)$r[0]['g']; - $r = q("SELECT COUNT(`id`) AS c FROM `contact` - WHERE `uid` = %d AND `self` = 0 - AND `blocked` = 0 AND `pending` = 0 - AND `notify` != '' $sql_extra" , - intval(local_user()) - ); - $contact_count = (int)$r[0]['c']; + if ($type=='' || $type=='g'){ + $r = q("SELECT COUNT(`id`) AS g FROM `group` WHERE `deleted` = 0 AND `uid` = %d $sql_extra", + intval(local_user()) + ); + $group_count = (int)$r[0]['g']; + } else { + $group_count = 0; + } + + if ($type=='' || $type=='c'){ + $r = q("SELECT COUNT(`id`) AS c FROM `contact` + WHERE `uid` = %d AND `self` = 0 + AND `blocked` = 0 AND `pending` = 0 + AND `notify` != '' $sql_extra" , + intval(local_user()) + ); + $contact_count = (int)$r[0]['c']; + } else { + $contact_count = 0; + } $tot = $group_count+$contact_count; $groups = array(); $contacts = array(); - $r = q("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') as uids - FROM `group`,`group_member` - WHERE `group`.`deleted` = 0 AND `group`.`uid` = %d - AND `group_member`.`gid`=`group`.`id` - $sql_extra - GROUP BY `group`.`id` - ORDER BY `group`.`name` - LIMIT %d,%d", - intval(local_user()), - intval($start), - intval($count) - ); - - - foreach($r as $g){ - $groups[] = array( - "type" => "g", - "photo" => "images/default-group-mm.png", - "name" => $g['name'], - "id" => intval($g['id']), - "uids" => array_map("intval", explode(",",$g['uids'])), - "link" => '' + if ($type=='' || $type=='g'){ + + $r = q("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') as uids + FROM `group`,`group_member` + WHERE `group`.`deleted` = 0 AND `group`.`uid` = %d + AND `group_member`.`gid`=`group`.`id` + $sql_extra + GROUP BY `group`.`id` + ORDER BY `group`.`name` + LIMIT %d,%d", + intval(local_user()), + intval($start), + intval($count) ); + + + foreach($r as $g){ + $groups[] = array( + "type" => "g", + "photo" => "images/default-group-mm.png", + "name" => $g['name'], + "id" => intval($g['id']), + "uids" => array_map("intval", explode(",",$g['uids'])), + "link" => '' + ); + } } + if ($type=='' || $type=='c'){ - $r = q("SELECT `id`, `name`, `micro`, `network`, `url` FROM `contact` - WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `pending` = 0 AND `notify` != '' - $sql_extra - ORDER BY `name` ASC ", - intval(local_user()) - ); - foreach($r as $g){ - $contacts[] = array( - "type" => "c", - "photo" => $g['micro'], - "name" => $g['name'], - "id" => intval($g['id']), - "network" => $g['network'], - "link" => $g['url'], + $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url` FROM `contact` + WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `pending` = 0 AND `notify` != '' + $sql_extra2 + ORDER BY `name` ASC ", + intval(local_user()) ); + foreach($r as $g){ + $contacts[] = array( + "type" => "c", + "photo" => $g['micro'], + "name" => $g['name'], + "id" => intval($g['id']), + "network" => $g['network'], + "link" => $g['url'], + "nick" => ($g['attag']) ? $g['attag'] : $g['nick'], + ); + } + } - - $items = array_merge($groups, $contacts); diff --git a/mod/admin.php b/mod/admin.php index f178e67f6..c4bb70056 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -506,7 +506,7 @@ function admin_page_plugins(&$a){ if (x($_GET,"a") && $_GET['a']=="t"){ // Toggle plugin status $idx = array_search($plugin, $a->plugins); - if ($idx){ + if ($idx !== false){ unset($a->plugins[$idx]); uninstall_plugin($plugin); info( sprintf( t("Plugin %s disabled."), $plugin ) ); diff --git a/mod/common.php b/mod/common.php new file mode 100644 index 000000000..852388c14 --- /dev/null +++ b/mod/common.php @@ -0,0 +1,61 @@ +<?php + +require_once('include/socgraph.php'); + +function common_content(&$a) { + + $o = ''; + if(! local_user()) { + notice( t('Permission denied.') . EOL); + return; + } + + if($a->argc > 1) + $cid = intval($a->argv[1]); + if(! $cid) + return; + + $c = q("select name, url, photo from contact where id = %d and uid = %d limit 1", + intval($cid), + intval(local_user()) + ); + + $a->page['aside'] .= '<div class="vcard">' + . '<div class="fn label">' . $c[0]['name'] . '</div>' + . '<div id="profile-photo-wrapper">' + . '<a href="/contacts/' . $cid . '"><img class="photo" width="175" height="175" + src="' . $c[0]['photo'] . '" alt="' . $c[0]['name'] . '" /></div>' + . '</div>'; + + + if(! count($c)) + return; + + $o .= '<h2>' . t('Common Friends') . '</h2>'; + +// $o .= '<h3>' . sprintf( t('You and %s'),$c[0]['name']) . '</h3>'; + + + $r = common_friends(local_user(),$cid); + + if(! count($r)) { + $o .= t('No friends in common.'); + return $o; + } + + $tpl = get_markup_template('common_friends.tpl'); + + foreach($r as $rr) { + + $o .= replace_macros($tpl,array( + '$url' => $rr['url'], + '$name' => $rr['name'], + '$photo' => $rr['photo'], + '$tags' => '' + )); + } + + $o .= cleardiv(); +// $o .= paginate($a); + return $o; +} diff --git a/mod/contacts.php b/mod/contacts.php index 9bbcea07d..ecfbe6c2c 100644 --- a/mod/contacts.php +++ b/mod/contacts.php @@ -1,6 +1,7 @@ <?php require_once('include/Contact.php'); +require_once('include/socgraph.php'); function contacts_init(&$a) { if(! local_user()) @@ -265,6 +266,8 @@ function contacts_content(&$a) { $nettype = '<div id="contact-edit-nettype">' . sprintf( t('Network type: %s'),network_to_name($r[0]['network'])) . '</div>'; + $common = count_common_friends(local_user(),$r[0]['id']); + $common_text = (($common) ? sprintf( tt('%d friends in common','%d friends in common', $common),$common) : ''); $o .= replace_macros($tpl,array( '$header' => t('Contact Editor'), '$submit' => t('Submit'), @@ -275,6 +278,8 @@ function contacts_content(&$a) { '$lbl_rep2' => t('Occasionally your friends may wish to inquire about this person\'s online legitimacy.'), '$lbl_rep3' => t('You may help them choose whether or not to interact with this person by providing a <em>reputation</em> to guide them.'), '$lbl_rep4' => t('Please take a moment to elaborate on this selection if you feel it could be helpful to others.'), + '$common_text' => $common_text, + '$common_link' => $a->get_baseurl() . '/common/' . $r[0]['id'], '$visit' => sprintf( t('Visit %s\'s profile [%s]'),$r[0]['name'],$r[0]['url']), '$blockunblock' => t('Block/Unblock contact'), '$ignorecont' => t('Ignore contact'), diff --git a/mod/dfrn_request.php b/mod/dfrn_request.php index 5d789f480..9755895ce 100644 --- a/mod/dfrn_request.php +++ b/mod/dfrn_request.php @@ -142,12 +142,13 @@ function dfrn_request_post(&$a) { * Create a contact record on our site for the other person */ - $r = q("INSERT INTO `contact` ( `uid`, `created`,`url`, `name`, `nick`, `photo`, `site-pubkey`, - `request`, `confirm`, `notify`, `poll`, `network`, `aes_allow`) - VALUES ( %d, '%s', '%s', '%s' , '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)", + $r = q("INSERT INTO `contact` ( `uid`, `created`,`url`, `nurl`, `name`, `nick`, `photo`, `site-pubkey`, + `request`, `confirm`, `notify`, `poll`, `poco`, `network`, `aes_allow`) + VALUES ( %d, '%s', '%s', '%s', '%s' , '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)", intval(local_user()), datetime_convert(), dbesc($dfrn_url), + dbesc(normalise_link($dfrn_url)), $parms['fn'], $parms['nick'], $parms['photo'], @@ -156,6 +157,7 @@ function dfrn_request_post(&$a) { $parms['dfrn-confirm'], $parms['dfrn-notify'], $parms['dfrn-poll'], + $parms['dfrn-poco'], dbesc(NETWORK_DFRN), intval($aes_allow) ); @@ -370,12 +372,13 @@ function dfrn_request_post(&$a) { dbesc_array($parms); - $r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `name`, `nick`, `issued-id`, `photo`, `site-pubkey`, - `request`, `confirm`, `notify`, `poll`, `network` ) - VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", + $r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`,`name`, `nick`, `issued-id`, `photo`, `site-pubkey`, + `request`, `confirm`, `notify`, `poll`, `poco`, `network` ) + VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", intval($uid), - datetime_convert(), + dbesc(datetime_convert()), $parms['url'], + dbesc(normalise_link($parms['url'])), $parms['fn'], $parms['nick'], $parms['issued-id'], @@ -385,6 +388,7 @@ function dfrn_request_post(&$a) { $parms['dfrn-confirm'], $parms['dfrn-notify'], $parms['dfrn-poll'], + $parms['dfrn-poco'], dbesc(NETWORK_DFRN) ); @@ -635,14 +639,14 @@ function dfrn_request_content(&$a) { $o .= replace_macros($tpl,array( '$header' => t('Friend/Connection Request'), - '$desc' => t('Examples: jojo@demo.friendika.com, http://demo.friendika.com/profile/jojo, testuser@identi.ca'), + '$desc' => t('Examples: jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, testuser@identi.ca'), '$pls_answer' => t('Please answer the following:'), '$does_know' => sprintf( t('Does %s know you?'),$a->profile['name']), '$yes' => t('Yes'), '$no' => t('No'), '$add_note' => t('Add a personal note:'), '$page_desc' => $page_desc, - '$friendika' => t('Friendika'), + '$friendika' => t('Friendica'), '$statusnet' => t('StatusNet/Federated Social Web'), '$diaspora' => t('Diaspora'), '$diasnote' => t('- please share from your own site as noted above'), diff --git a/mod/display.php b/mod/display.php index 281ce1dd4..761eb4997 100644 --- a/mod/display.php +++ b/mod/display.php @@ -15,6 +15,9 @@ function display_content(&$a) { $o = '<div id="live-display"></div>' . "\r\n"; + $a->page['htmlhead'] .= '<script>$(document).ready(function() { $(".comment-edit-wrapper textarea").contact_autocomplete(baseurl+"/acl"); });</script>'; + + $nick = (($a->argc > 1) ? $a->argv[1] : ''); profile_load($a,$nick); diff --git a/mod/follow.php b/mod/follow.php index 77c8ae18f..0329d1eee 100644 --- a/mod/follow.php +++ b/mod/follow.php @@ -100,17 +100,19 @@ function follow_post(&$a) { $new_relation = CONTACT_IS_FOLLOWER; // create contact record - $r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `addr`, `alias`, `batch`, `notify`, `poll`, `name`, `nick`, `photo`, `network`, `pubkey`, `rel`, `priority`, + $r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `batch`, `notify`, `poll`, `poco`, `name`, `nick`, `photo`, `network`, `pubkey`, `rel`, `priority`, `writable`, `blocked`, `readonly`, `pending` ) - VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ", + VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ", intval(local_user()), dbesc(datetime_convert()), dbesc($ret['url']), + dbesc(normalise_link($ret['url'])), dbesc($ret['addr']), dbesc($ret['alias']), dbesc($ret['batch']), dbesc($ret['notify']), dbesc($ret['poll']), + dbesc($ret['poco']), dbesc($ret['name']), dbesc($ret['nick']), dbesc($ret['photo']), diff --git a/mod/friendica.php b/mod/friendica.php new file mode 100644 index 000000000..363f1409f --- /dev/null +++ b/mod/friendica.php @@ -0,0 +1,68 @@ +<?php + +function friendica_init(&$a) { + if ($a->argv[1]=="json"){ + $register_policy = Array('REGISTER_CLOSED', 'REGISTER_APPROVE', 'REGISTER_OPEN'); + + if (isset($a->config['admin_email']) && $a->config['admin_email']!=''){ + $r = q("SELECT username, nickname FROM user WHERE email='%s'", $a->config['admin_email']); + $admin = array( + 'name' => $r[0]['username'], + 'profile'=> $a->get_baseurl().'/profile/'.$r[0]['nickname'], + ); + } else { + $admin = false; + } + + $data = Array( + 'version' => FRIENDIKA_VERSION, + 'url' => z_root(), + 'plugins' => $a->plugins, + 'register_policy' => $register_policy[$a->config['register_policy']], + 'admin' => $admin, + 'site_name' => $a->config['sitename'], + 'platform' => FRIENDIKA_PLATFORM, + 'info' => ((x($a->config,'info')) ? $a->config['info'] : '') + ); + + echo json_encode($data); + killme(); + } +} + + + +function friendica_content(&$a) { + + $o = ''; + $o .= '<h3>Friendica</h3>'; + + + $o .= '<p></p><p>'; + + $o .= t('This is Friendica, version') . ' ' . FRIENDIKA_VERSION . ' '; + $o .= t('running at web location') . ' ' . z_root() . '</p><p>'; + + $o .= t('Please visit <a href="http://project.friendika.com">Project.Friendika.com</a> to learn more about the Friendica project.') . '</p><p>'; + + $o .= t('Bug reports and issues: please visit') . ' ' . '<a href="http://bugs.friendika.com">Bugs.Friendika.com</a></p><p>'; + $o .= t('Suggestions, praise, donations, etc. - please email "Info" at Friendica - dot com') . '</p>'; + + $o .= '<p></p>'; + + if(count($a->plugins)) { + $o .= '<p>' . t('Installed plugins/addons/apps') . '</p>'; + $o .= '<ul>'; + foreach($a->plugins as $p) + if(strlen($p)) + $o .= '<li>' . $p . '</li>'; + $o .= '</ul>'; + } + else + $o .= '<p>' . t('No installed plugins/addons/apps'); + + call_hooks('about_hook', $o); + + return $o; + +} diff --git a/mod/friendika.php b/mod/friendika.php index b12110bd5..1f3df565d 100644 --- a/mod/friendika.php +++ b/mod/friendika.php @@ -1,68 +1,11 @@ <?php -function friendika_init(&$a) { - if ($a->argv[1]=="json"){ - $register_policy = Array('REGISTER_CLOSED', 'REGISTER_APPROVE', 'REGISTER_OPEN'); - - if (isset($a->config['admin_email']) && $a->config['admin_email']!=''){ - $r = q("SELECT username, nickname FROM user WHERE email='%s'", $a->config['admin_email']); - $admin = array( - 'name' => $r[0]['username'], - 'profile'=> $a->get_baseurl().'/profile/'.$r[0]['nickname'], - ); - } else { - $admin = false; - } - - $data = Array( - 'version' => FRIENDIKA_VERSION, - 'url' => z_root(), - 'plugins' => $a->plugins, - 'register_policy' => $register_policy[$a->config['register_policy']], - 'admin' => $admin, - 'site_name' => $a->config['sitename'], - 'platform' => FRIENDIKA_PLATFORM, - 'info' => ((x($a->config,'info')) ? $a->config['info'] : '') - ); +require_once('mod/friendica.php'); - echo json_encode($data); - killme(); - } +function friendika_init(&$a) { + friendica_init($a); } - - function friendika_content(&$a) { - - $o = ''; - $o .= '<h3>Friendika</h3>'; - - - $o .= '<p></p><p>'; - - $o .= t('This is Friendika version') . ' ' . FRIENDIKA_VERSION . ' '; - $o .= t('running at web location') . ' ' . z_root() . '</p><p>'; - - $o .= t('Please visit <a href="http://project.friendika.com">Project.Friendika.com</a> to learn more about the Friendika project.') . '</p><p>'; - - $o .= t('Bug reports and issues: please visit') . ' ' . '<a href="http://bugs.friendika.com">Bugs.Friendika.com</a></p><p>'; - $o .= t('Suggestions, praise, donations, etc. - please email "Info" at Friendika - dot com') . '</p>'; - - $o .= '<p></p>'; - - if(count($a->plugins)) { - $o .= '<p>' . t('Installed plugins/addons/apps') . '</p>'; - $o .= '<ul>'; - foreach($a->plugins as $p) - if(strlen($p)) - $o .= '<li>' . $p . '</li>'; - $o .= '</ul>'; - } - else - $o .= '<p>' . t('No installed plugins/addons/apps'); - - call_hooks('about_hook', $o); - - return $o; - + return friendica_content($a); } diff --git a/mod/install.php b/mod/install.php index 27cc6af84..78e537cfe 100644 --- a/mod/install.php +++ b/mod/install.php @@ -52,7 +52,7 @@ function install_post(&$a) { $result = file_put_contents('.htconfig.php', $txt); if(! $result) { - $a->data = $txt; + $a->data['txt'] = $txt; } $errors = load_database($db); @@ -107,7 +107,7 @@ function install_content(&$a) { if(strlen($o)) return $o; - if(strlen($a->data)) { + if(strlen($a->data['txt'])) { $o .= manual_config($a); return; } @@ -203,7 +203,7 @@ function check_funcs() { if(! function_exists('mb_strlen')) notice( t('Error: mb_string PHP module required but not installed.') . EOL); - if((x($_SESSION,'sysmsg')) && strlen($_SESSION['sysmsg'])) + if((x($_SESSION,'sysmsg')) && is_array($_SESSION['sysmsg']) && count($_SESSION['sysmsg'])) notice( t('Please see the file "INSTALL.txt".') . EOL); } @@ -224,7 +224,7 @@ function check_htconfig() { function manual_config(&$a) { - $data = htmlentities($a->data); + $data = htmlentities($a->data['txt']); $o = t('The database configuration file ".htconfig.php" could not be written. Please use the enclosed text to create a configuration file in your web server root.'); $o .= "<textarea rows=\"24\" cols=\"80\" >$data</textarea>"; return $o; diff --git a/mod/item.php b/mod/item.php index ab104735b..ee3bdca99 100644 --- a/mod/item.php +++ b/mod/item.php @@ -333,15 +333,20 @@ function item_post(&$a) { } } - // embedded bookmark in post? convert to regular url and set bookmark flag + // embedded bookmark in post? set bookmark flag $bookmark = 0; - if(preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",$body,$match)) { + if(preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",$body,$match,PREG_SET_ORDER)) { $bookmark = 1; - $body = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",'[url=$1]$2[/url]',$body); +// foreach($match as $mtch) { +// $body = str_replace( +// '[bookmark=' . $mtch[1] . ']' . $mtch[2] . '[/bookmark]', +// '[url=' . $mtch[1] . ']' . $mtch[2] . '[/url]', +// $body +// ); +// } } - $body = bb_translate_video($body); /** @@ -373,6 +378,7 @@ function item_post(&$a) { if(count($tags)) { foreach($tags as $tag) { + if(isset($profile)) unset($profile); if(strpos($tag,'#') === 0) { @@ -408,7 +414,19 @@ function item_post(&$a) { else { $newname = $name; $alias = ''; - if(strstr($name,'_') || strstr($name,' ')) { + $tagcid = 0; + if(strrpos($newname,'+')) { + $tagcid = intval(substr($newname,strrpos($newname,'+') + 1)); + if(strpos($name,' ')) + $name = substr($name,0,strpos($name,' ')); + } + if($tagcid) { + $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($tagcid), + intval($profile_uid) + ); + } + elseif(strstr($name,'_') || strstr($name,' ')) { $newname = str_replace('_',' ',$name); $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1", dbesc($newname), @@ -440,17 +458,23 @@ function item_post(&$a) { if($profile) { $body = str_replace('@' . $name, '@' . '[url=' . $profile . ']' . $newname . '[/url]', $body); $profile = str_replace(',','%2c',$profile); - if(strlen($str_tags)) - $str_tags .= ','; - $str_tags .= '@[url=' . $profile . ']' . $newname . '[/url]'; + $newtag = '@[url=' . $profile . ']' . $newname . '[/url]'; + if(! stristr($str_tags,$newtag)) { + if(strlen($str_tags)) + $str_tags .= ','; + $str_tags .= $newtag; + } // Status.Net seems to require the numeric ID URL in a mention if the person isn't // subscribed to you. But the nickname URL is OK if they are. Grrr. We'll tag both. if(strlen($alias)) { - if(strlen($str_tags)) - $str_tags .= ','; - $str_tags .= '@[url=' . $alias . ']' . $newname . '[/url]'; + $newtag = '@[url=' . $alias . ']' . $newname . '[/url]'; + if(! stristr($str_tags,$newtag)) { + if(strlen($str_tags)) + $str_tags .= ','; + $str_tags .= $newtag; + } } } } diff --git a/mod/like.php b/mod/like.php index 5c3dd323e..6b97fafb5 100644 --- a/mod/like.php +++ b/mod/like.php @@ -197,5 +197,6 @@ EOT; proc_run('php',"include/notifier.php","like","$post_id"); - return; // NOTREACHED + killme(); +// return; // NOTREACHED }
\ No newline at end of file diff --git a/mod/network.php b/mod/network.php index 04c2a1782..9fed8592e 100644 --- a/mod/network.php +++ b/mod/network.php @@ -328,15 +328,21 @@ function network_content(&$a, $update = 0) { } } - if((! $group) && (! $cid) && (! $update)) + if((! $group) && (! $cid) && (! $update)) { $o .= get_birthdays(); + $o .= get_events(); + } $sql_extra2 = (($nouveau) ? '' : " AND `item`.`parent` = `item`.`id` "); - if(x($_GET,'search')) - $sql_extra .= " AND `item`.`body` REGEXP '" . dbesc(escape_tags($_GET['search'])) . "' "; + if(x($_GET,'search')) { + $search = escape_tags($_GET['search']); + $sql_extra .= sprintf(" AND ( `item`.`body` REGEXP '%s' OR `item`.`tag` REGEXP '%s' ) ", + dbesc($search), + dbesc('\\]' . $search . '\\[') + ); + } - $r = q("SELECT COUNT(*) AS `total` FROM `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` WHERE `item`.`uid` = %d AND `item`.`visible` = 1 AND `item`.`deleted` = 0 diff --git a/mod/parse_url.php b/mod/parse_url.php index a238ecb2f..2df9de476 100644 --- a/mod/parse_url.php +++ b/mod/parse_url.php @@ -46,6 +46,7 @@ function parse_url_content(&$a) { killme(); } + if($url && $title && $text) { $text = '<br /><br /><blockquote>' . $text . '</blockquote><br />'; @@ -67,13 +68,26 @@ function parse_url_content(&$a) { killme(); } - logger('parse_url: data: ' . $s, LOGGER_DATA); +// logger('parse_url: data: ' . $s, LOGGER_DATA); if(! $s) { echo sprintf($template,$url,$url,'') . $str_tags; killme(); } + $matches = ''; + $c = preg_match('/\<head(.*?)\>(.*?)\<\/head\>/ism',$s,$matches); + if($c) { +// logger('parse_url: header: ' . $matches[2], LOGGER_DATA); + try { + $domhead = HTML5_Parser::parse($matches[2]); + } catch (DOMException $e) { + logger('scrape_dfrn: parse error: ' . $e); + } + if($domhead) + logger('parsed header'); + } + if(! $title) { if(strpos($s,'<title>')) { $title = substr($s,strpos($s,'<title>')+7,64); @@ -84,13 +98,16 @@ function parse_url_content(&$a) { $config = HTMLPurifier_Config::createDefault(); $config->set('Cache.DefinitionImpl', null); - $purifier = new HTMLPurifier($config); $s = $purifier->purify($s); -// logger('parse_url: purified: ' . $s, LOGGER_DATA); +// logger('purify_output: ' . $s); - $dom = @HTML5_Parser::parse($s); + try { + $dom = HTML5_Parser::parse($s); + } catch (DOMException $e) { + logger('scrape_dfrn: parse error: ' . $e); + } if(! $dom) { echo sprintf($template,$url,$url,'') . $str_tags; @@ -155,10 +172,63 @@ function parse_url_content(&$a) { } } + if(! $text) { + logger('parsing meta'); + $items = $domhead->getElementsByTagName('meta'); + if($items) { + foreach($items as $item) { + $property = $item->getAttribute('property'); + if($property && (stristr($property,':description'))) { + + $text = $item->getAttribute('content'); + if(stristr($text,'<script')) { + $text = ''; + continue; + } + $text = strip_tags($text); + + + $text = substr($text,0,250) . '...' ; + } + if($property && (stristr($property,':image'))) { + + $image = $item->getAttribute('content'); + if(stristr($text,'<script')) { + $image = ''; + continue; + } + $image = strip_tags($image); + + $i = fetch_url($image); + if($i) { + require_once('include/Photo.php'); + $ph = new Photo($i); + if($ph->is_valid()) { + if($ph->getWidth() > 300 || $ph->getHeight() > 300) { + $ph->scaleImage(300); + $new_width = $ph->getWidth(); + $new_height = $ph->getHeight(); + $image = '<br /><br /><img height="' . $new_height . '" width="' . $new_width . '" src="' .$image . '" alt="photo" />'; + } + else + $image = '<br /><br /><img src="' . $image . '" alt="photo" />'; + } + else + $image = ''; + + } + } + } + } + } + if(strlen($text)) { $text = '<br /><br /><blockquote>' . $text . '</blockquote><br />'; } + if($image) { + $text = $image . '<br />' . $text; + } $title = str_replace(array("\r","\n"),array('',''),$title); $result = sprintf($template,$url,($title) ? $title : $url,$text) . $str_tags; diff --git a/mod/photos.php b/mod/photos.php index 663d0a40c..51d6a4b65 100644 --- a/mod/photos.php +++ b/mod/photos.php @@ -408,7 +408,18 @@ function photos_post(&$a) { } else { $newname = $name; - if(strstr($name,'_') || strstr($name,' ')) { + $alias = ''; + $tagcid = 0; + if(strrpos($newname,'+')) + $tagcid = intval(substr($newname,strrpos($newname,'+') + 1)); + + if($tagcid) { + $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($tagcid), + intval($profile_uid) + ); + } + elseif(strstr($name,'_') || strstr($name,' ')) { $newname = str_replace('_',' ',$name); $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1", dbesc($newname), @@ -581,8 +592,8 @@ function photos_post(&$a) { $visible = 1; else $visible = 0; - - if(intval($_REQUEST['not_visible'])) + + if(intval($_REQUEST['not_visible']) || $_REQUEST['not_visible'] === 'true') $visible = 0; $str_group_allow = perms2str(((is_array($_REQUEST['group_allow'])) ? $_REQUEST['group_allow'] : explode(',',$_REQUEST['group_allow']))); diff --git a/mod/poco.php b/mod/poco.php new file mode 100644 index 000000000..21ee4df69 --- /dev/null +++ b/mod/poco.php @@ -0,0 +1,129 @@ +<?php + +function poco_init(&$a) { + + if($a->argc > 1) { + $user = notags(trim($a->argv[1])); + } + if(! x($user) || get_config('system','block_public')) + http_status_exit(401); + + $format = (($_GET['format']) ? $_GET['format'] : 'json'); + + $justme = false; + + if($a->argc > 2 && $a->argv[2] === '@me') + $justme = true; + if($a->argc > 3 && $a->argv[3] === '@all') + $justme = false; + if($a->argc > 3 && $a->argv[3] === '@self') + $justme = true; + if($a->argc > 4 && intval($a->argv[4]) && $justme == false) + $cid = intval($a->argv[4]); + + + $r = q("SELECT `user`.*,`profile`.`hide-friends` from user left join profile on `user`.`uid` = `profile`.`uid` + where `user`.`nickname` = '%s' and `profile`.`is-default` = 1 limit 1", + dbesc($user) + ); + if(! count($r) || $r[0]['hidewall'] || $r[0]['hide-friends']) + http_status_exit(404); + + $user = $r[0]; + + if($justme) + $sql_extra = " and `contact`.`self` = 1 "; + + if($cid) + $sql_extra = sprintf(" and `contact`.`id` = %d ",intval($cid)); + + $r = q("SELECT count(*) as `total` from `contact` where `uid` = %d and blocked = 0 and pending = 0 + $sql_extra ", + intval($user['uid']) + ); + if(count($r)) + $totalResults = intval($r[0]['total']); + else + $totalResults = 0; + + $startIndex = intval($_GET['startIndex']); + if(! $startIndex) + $startIndex = 0; + $itemsPerPage = ((x($_GET,'count') && intval($_GET['count'])) ? intval($_GET['count']) : $totalResults); + + $r = q("SELECT * from `contact` where `uid` = %d and blocked = 0 and pending = 0 + $sql_extra LIMIT %d, %d", + intval($user['uid']), + intval($startIndex), + intval($itemsPerPage) + ); + + $ret = array(); + if(x($_GET,'sorted')) + $ret['sorted'] = 'false'; + if(x($_GET,'filtered')) + $ret['filtered'] = 'false'; + if(x($_GET,'updatedSince')) + $ret['updateSince'] = 'false'; + + $ret['startIndex'] = (string) $startIndex; + $ret['itemsPerPage'] = (string) $itemsPerPage; + $ret['totalResults'] = (string) $totalResults; + $ret['entry'] = array(); + + + $fields_ret = array( + 'id' => false, + 'displayName' => false, + 'urls' => false, + 'preferredUsername' => false, + 'photos' => false + ); + + if((! x($_GET,'fields')) || ($_GET['fields'] === '@all')) + foreach($fields_ret as $k => $v) + $fields_ret[$k] = true; + else { + $fields_req = explode(',',$_GET['fields']); + foreach($fields_req as $f) + $fields_ret[trim($f)] = true; + } + + if(is_array($r)) { + if(count($r)) { + foreach($r as $rr) { + $entry = array(); + if($fields_ret['id']) + $entry['id'] = $rr['id']; + if($fields_ret['displayName']) + $entry['displayName'] = $rr['name']; + if($fields_ret['urls']) + $entry['urls'] = array(array('value' => $rr['url'], 'type' => 'profile')); + if($fields_ret['preferredUsername']) + $entry['preferredUsername'] = $rr['nick']; + if($fields_ret['photos']) + $entry['photos'] = array(array('value' => $rr['photo'], 'type' => 'profile')); + $ret['entry'][] = $entry; + } + } + else + $ret['entry'][] = array(); + } + else + http_status_exit(500); + + if($format === 'xml') { + header('Content-type: text/xml'); + echo replace_macros(get_markup_template('poco_xml.tpl'),array_xmlify(array('$response' => $ret))); + http_status_exit(500); + } + if($format === 'json') { + header('Content-type: application/json'); + echo json_encode($ret); + killme(); + } + else + http_status_exit(500); + + +}
\ No newline at end of file diff --git a/mod/profile.php b/mod/profile.php index a453f72f1..f68006af5 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -46,6 +46,7 @@ function profile_init(&$a) { $dfrn_pages = array('request', 'confirm', 'notify', 'poll'); foreach($dfrn_pages as $dfrn) $a->page['htmlhead'] .= "<link rel=\"dfrn-{$dfrn}\" href=\"".$a->get_baseurl()."/dfrn_{$dfrn}/{$which}\" />\r\n"; + $a->page['htmlhead'] .= "<link rel=\"dfrn-poco\" href=\"".$a->get_baseurl()."/poco/{$which}\" />\r\n"; } @@ -223,8 +224,10 @@ function profile_content(&$a, $update = 0) { ); } - if($is_owner && ! $update) + if($is_owner && ! $update) { $o .= get_birthdays(); + $o .= get_events(); + } $o .= conversation($a,$r,'profile',$update); diff --git a/mod/profile_photo.php b/mod/profile_photo.php index 4de3aaa3e..47f0f8d8e 100644 --- a/mod/profile_photo.php +++ b/mod/profile_photo.php @@ -90,6 +90,9 @@ function profile_photo_post(&$a) { $url = $a->get_baseurl() . '/profile/' . $a->user['nickname']; if($url && strlen(get_config('system','directory_submit_url'))) proc_run('php',"include/directory.php","$url"); + + require_once('include/profile_update.php'); + profile_change(); } else notice( t('Unable to process image') . EOL); diff --git a/mod/profiles.php b/mod/profiles.php index f5f335c7e..ccd7d5474 100644 --- a/mod/profiles.php +++ b/mod/profiles.php @@ -210,6 +210,9 @@ function profiles_post(&$a) { $url = $_SESSION['my_url']; if($url && strlen(get_config('system','directory_submit_url'))) proc_run('php',"include/directory.php","$url"); + + require_once('include/profile_update.php'); + profile_change(); } } } @@ -455,7 +458,7 @@ function profiles_content(&$a) { $tpl_header = get_markup_template('profile_listing_header.tpl'); $o .= replace_macros($tpl_header,array( - '$header' => t('Profiles'), + '$header' => t('Edit/Manage Profiles'), '$chg_photo' => t('Change profile photo'), '$cr_new' => t('Create New Profile') )); diff --git a/mod/register.php b/mod/register.php index 85e1f9faa..6ebe35dbf 100644 --- a/mod/register.php +++ b/mod/register.php @@ -268,9 +268,9 @@ function register_post(&$a) { intval($newuid)); return; } - $r = q("INSERT INTO `contact` ( `uid`, `created`, `self`, `name`, `nick`, `photo`, `thumb`, `micro`, `blocked`, `pending`, `url`, - `request`, `notify`, `poll`, `confirm`, `name-date`, `uri-date`, `avatar-date` ) - VALUES ( %d, '%s', 1, '%s', '%s', '%s', '%s', '%s', 0, 0, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", + $r = q("INSERT INTO `contact` ( `uid`, `created`, `self`, `name`, `nick`, `photo`, `thumb`, `micro`, `blocked`, `pending`, `url`, `nurl`, + `request`, `notify`, `poll`, `confirm`, `poco`, `name-date`, `uri-date`, `avatar-date` ) + VALUES ( %d, '%s', 1, '%s', '%s', '%s', '%s', '%s', 0, 0, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($newuid), datetime_convert(), dbesc($username), @@ -279,10 +279,12 @@ function register_post(&$a) { dbesc($a->get_baseurl() . "/photo/avatar/{$newuid}.jpg"), dbesc($a->get_baseurl() . "/photo/micro/{$newuid}.jpg"), dbesc($a->get_baseurl() . "/profile/$nickname"), + dbesc(normalise_link($a->get_baseurl() . "/profile/$nickname")), dbesc($a->get_baseurl() . "/dfrn_request/$nickname"), dbesc($a->get_baseurl() . "/dfrn_notify/$nickname"), dbesc($a->get_baseurl() . "/dfrn_poll/$nickname"), dbesc($a->get_baseurl() . "/dfrn_confirm/$nickname"), + dbesc($a->get_baseurl() . "/poco/$nickname"), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()) diff --git a/mod/search.php b/mod/search.php index 2a8bf1484..819100204 100644 --- a/mod/search.php +++ b/mod/search.php @@ -96,12 +96,16 @@ function search_content(&$a) { // Only public wall posts can be shown // OR your own posts if you are a logged in member - $s_bool = "AND MATCH (`item`.`body`) AGAINST ( '%s' IN BOOLEAN MODE )"; - $s_regx = "AND `item`.`body` REGEXP '%s' "; + $escaped_search = str_replace(array('[',']'),array('\\[','\\]'),$search); + +// $s_bool = sprintf("AND MATCH (`item`.`body`) AGAINST ( '%s' IN BOOLEAN MODE )", dbesc($search)); + $s_regx = sprintf("AND ( `item`.`body` REGEXP '%s' OR `item`.`tag` REGEXP '%s' )", + dbesc($escaped_search), dbesc('\\]' . $escaped_search . '\\[')); + +// if(mb_strlen($search) >= 3) +// $search_alg = $s_bool; +// else - if(mb_strlen($search) >= 3) - $search_alg = $s_bool; - else $search_alg = $s_regx; $r = q("SELECT COUNT(*) AS `total` @@ -111,8 +115,7 @@ function search_content(&$a) { OR `item`.`uid` = %d ) AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 $search_alg ", - intval(local_user()), - dbesc($search) + intval(local_user()) ); if(count($r)) @@ -137,7 +140,6 @@ function search_content(&$a) { $search_alg ORDER BY `received` DESC LIMIT %d , %d ", intval(local_user()), - dbesc($search), intval($a->pager['start']), intval($a->pager['itemspage']) diff --git a/mod/settings.php b/mod/settings.php index 2b9cde735..938f6a0d5 100644 --- a/mod/settings.php +++ b/mod/settings.php @@ -222,6 +222,7 @@ function settings_post(&$a) { $old_visibility = (((x($_POST,'visibility')) && (intval($_POST['visibility']) == 1)) ? 1 : 0); $page_flags = (((x($_POST,'page-flags')) && (intval($_POST['page-flags']))) ? intval($_POST['page-flags']) : 0); $blockwall = (((x($_POST,'blockwall')) && (intval($_POST['blockwall']) == 1)) ? 0: 1); // this setting is inverted! + $blocktags = (((x($_POST,'blocktags')) && (intval($_POST['blocktags']) == 1)) ? 0: 1); // this setting is inverted! $hide_friends = (($_POST['hide-friends'] == 1) ? 1: 0); $hidewall = (($_POST['hidewall'] == 1) ? 1: 0); @@ -296,7 +297,7 @@ function settings_post(&$a) { $openidserver = ''; } - $r = q("UPDATE `user` SET `username` = '%s', `email` = '%s', `openid` = '%s', `timezone` = '%s', `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s', `notify-flags` = %d, `page-flags` = %d, `default-location` = '%s', `allow_location` = %d, `theme` = '%s', `maxreq` = %d, `expire` = %d, `openidserver` = '%s', `blockwall` = %d, `hidewall` = %d WHERE `uid` = %d LIMIT 1", + $r = q("UPDATE `user` SET `username` = '%s', `email` = '%s', `openid` = '%s', `timezone` = '%s', `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s', `notify-flags` = %d, `page-flags` = %d, `default-location` = '%s', `allow_location` = %d, `theme` = '%s', `maxreq` = %d, `expire` = %d, `openidserver` = '%s', `blockwall` = %d, `hidewall` = %d, `blocktags` = %d WHERE `uid` = %d LIMIT 1", dbesc($username), dbesc($email), dbesc($openid), @@ -315,6 +316,7 @@ function settings_post(&$a) { dbesc($openidserver), intval($blockwall), intval($hidewall), + intval($blocktags), intval(local_user()) ); if($r) @@ -348,9 +350,9 @@ function settings_post(&$a) { } -// not yet ready for prime time -// require_once('include/profile_update.php'); -// profile_change(); + + require_once('include/profile_update.php'); + profile_change(); $_SESSION['theme'] = $theme; if($email_changed && $a->config['register_policy'] == REGISTER_VERIFY) { @@ -582,6 +584,7 @@ function settings_content(&$a) { $maxreq = $a->user['maxreq']; $expire = ((intval($a->user['expire'])) ? $a->user['expire'] : ''); $blockwall = $a->user['blockwall']; + $blocktags = $a->user['blocktags']; if(! strlen($a->user['timezone'])) $timezone = date_default_timezone_get(); @@ -645,6 +648,17 @@ function settings_content(&$a) { )); + $blockwall = replace_macros($opt_tpl,array( + '$field' => array('blockwall', t('Allow friends to post to your profile page?'), ! $a->user['blockwall'], '', array(t('No'),t('Yes'))), + + )); + + + $blocktags = replace_macros($opt_tpl,array( + '$field' => array('blocktags', t('Allow friends to tag your posts?'), ! $a->user['blocktags'], '', array(t('No'),t('Yes'))), + + )); + $invisible = (((! $profile['publish']) && (! $profile['net-publish'])) ? true : false); @@ -720,7 +734,8 @@ function settings_content(&$a) { '$visibility' => $profile['net-publish'], '$aclselect' => populate_acl($a->user,$celeb), - '$blockwall'=> array('blockwall', t('Allow friends to post to your profile page:'), !$blockwall, ''), + '$blockwall'=> $blockwall, // array('blockwall', t('Allow friends to post to your profile page:'), !$blockwall, ''), + '$blocktags'=> $blocktags, // array('blocktags', t('Allow friends to tag your posts:'), !$blocktags, ''), '$expire' => array('expire', t("Automatically expire posts after days:"), $expire, t('If empty, posts will not expire. Expired posts will be deleted')), '$profile_in_dir' => $profile_in_dir, diff --git a/mod/suggest.php b/mod/suggest.php new file mode 100644 index 000000000..aedf3fd46 --- /dev/null +++ b/mod/suggest.php @@ -0,0 +1,62 @@ +<?php + +require_once('include/socgraph.php'); +require_once('include/contact_widgets.php'); + + +function suggest_init(&$a) { + if(! local_user()) + return; + + if(x($_GET,'ignore') && intval($_GET['ignore'])) { + q("insert into gcign ( uid, gcid ) values ( %d, %d ) ", + intval(local_user()), + intval($_GET['ignore']) + ); + } + +} + + + + + +function suggest_content(&$a) { + + $o = ''; + if(! local_user()) { + notice( t('Permission denied.') . EOL); + return; + } + + $a->page['aside'] .= follow_widget(); + $a->page['aside'] .= findpeople_widget(); + + + $o .= '<h2>' . t('Friend Suggestions') . '</h2>'; + + + $r = suggestion_query(local_user()); + + if(! count($r)) { + $o .= t('No suggestions. This works best when you have more than one contact/friend.'); + return $o; + } + + $tpl = get_markup_template('suggest_friends.tpl'); + + foreach($r as $rr) { + + $o .= replace_macros($tpl,array( + '$url' => $rr['url'], + '$name' => $rr['name'], + '$photo' => $rr['photo'], + '$ignlnk' => $a->get_baseurl() . '/suggest?ignore=' . $rr['id'], + '$ignore' => t('Ignore/Hide') + )); + } + + $o .= cleardiv(); +// $o .= paginate($a); + return $o; +} diff --git a/mod/tagger.php b/mod/tagger.php new file mode 100644 index 000000000..da4e74c61 --- /dev/null +++ b/mod/tagger.php @@ -0,0 +1,198 @@ +<?php + +require_once('include/security.php'); +require_once('include/bbcode.php'); +require_once('include/items.php'); + + +function tagger_content(&$a) { + + if(! local_user() && ! remote_user()) { + return; + } + + $term = notags(trim($_GET['term'])); + // no commas allowed + $term = str_replace(array(',',' '),array('','_'),$term); + + if(! $term) + return; + + $item_id = (($a->argc > 1) ? notags(trim($a->argv[1])) : 0); + + logger('tagger: tag ' . $term . ' item ' . $item_id); + + + $r = q("SELECT * FROM `item` WHERE `id` = '%s' LIMIT 1", + dbesc($item_id) + ); + + if(! $item_id || (! count($r))) { + logger('tagger: no item ' . $item_id); + return; + } + + $item = $r[0]; + + $owner_uid = $item['uid']; + + $r = q("select `nickname`,`blocktags` from user where uid = %d limit 1", + intval($owner_uid) + ); + if(count($r)) { + $owner_nick = $r[0]['nickname']; + $blocktags = $r[0]['blocktags']; + } + + if(local_user() != $owner_uid) + return; + + if(remote_user()) { + $r = q("select * from contact where id = %d AND `uid` = %d limit 1", + intval(remote_user()), + intval($item['uid']) + ); + } + else { + $r = q("select * from contact where self = 1 and uid = %d limit 1", + intval(local_user()) + ); + } + if(count($r)) + $contact = $r[0]; + else { + logger('tagger: no contact_id'); + return; + } + + $uri = item_new_uri($a->get_hostname(),$owner_uid); + + $post_type = (($item['resource-id']) ? t('photo') : t('status')); + $targettype = (($item['resource-id']) ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); + + $link = xmlify('<link rel="alternate" type="text/html" href="' + . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . '" />' . "\n") ; + + $body = $item['body']; + + $target = <<< EOT + <target> + <type>$targettype</type> + <local>1</local> + <id>{$item['uri']}</id> + <link>$link</link> + <title></title> + <content>$body</content> + </target> +EOT; + + $tagid = $a->get_baseurl() . '/search?search=' . $term; + $objtype = ACTIVITY_OBJ_TAGTERM; + + $obj = <<< EOT + <object> + <type>$objtype</type> + <local>1</local> + <id>$tagid</id> + <link>$tagid</link> + <title>$term</title> + <content>$term</content> + </object> +EOT; + + $bodyverb = t('%1$s tagged %2$s\'s %3$s with %4$s'); + + if(! isset($bodyverb)) + return; + + $termlink = '#[url=' . $a->get_baseurl() . '/search?search=' . urlencode($term) . ']'. $term . '[/url]'; + + $arr = array(); + + $arr['uri'] = $uri; + $arr['uid'] = $owner_uid; + $arr['contact-id'] = $contact['id']; + $arr['type'] = 'activity'; + $arr['wall'] = $item['wall']; + $arr['gravity'] = GRAVITY_COMMENT; + $arr['parent'] = $item['id']; + $arr['parent-uri'] = $item['uri']; + $arr['owner-name'] = $item['author-name']; + $arr['owner-link'] = $item['author-link']; + $arr['owner-avatar'] = $item['author-avatar']; + $arr['author-name'] = $contact['name']; + $arr['author-link'] = $contact['url']; + $arr['author-avatar'] = $contact['thumb']; + + $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]'; + $alink = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]'; + $plink = '[url=' . $item['plink'] . ']' . $post_type . '[/url]'; + $arr['body'] = sprintf( $bodyverb, $ulink, $alink, $plink, $termlink ); + + $arr['verb'] = ACTIVITY_TAG; + $arr['target-type'] = $targettype; + $arr['target'] = $target; + $arr['object-type'] = $objtype; + $arr['object'] = $obj; + $arr['allow_cid'] = $item['allow_cid']; + $arr['allow_gid'] = $item['allow_gid']; + $arr['deny_cid'] = $item['deny_cid']; + $arr['deny_gid'] = $item['deny_gid']; + $arr['visible'] = 1; + $arr['unseen'] = 1; + $arr['last-child'] = 1; + $arr['origin'] = 1; + + $post_id = item_store($arr); + + q("UPDATE `item` set plink = '%s' where id = %d limit 1", + dbesc($a->get_baseurl() . '/display/' . $owner_nick . '/' . $post_id), + intval($post_id) + ); + + + if(! $item['visible']) { + $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($item['id']), + intval($owner_uid) + ); + } + + if((! $blocktags) && (! stristr($item['tag'], ']' . $term . '[' ))) { + q("update item set tag = '%s' where id = %d limit 1", + dbesc($item['tag'] . (strlen($item['tag']) ? ',' : '') . '#[url=' . $a->get_baseurl() . '/search?search=' . $term . ']'. $term . '[/url]'), + intval($item['id']) + ); + } + + // if the original post is on this site, update it. + + $r = q("select `tag`,`id`,`uid` from item where `origin` = 1 AND `uri` = '%s' LIMIT 1", + dbesc($item['uri']) + ); + if(count($r)) { + $x = q("SELECT `blocktags` FROM `user` WHERE `uid` = %d limit 1", + intval($r[0]['uid']) + ); + if(count($x) && !$x[0]['blocktags'] && (! stristr($r[0]['tag'], ']' . $term . '['))) { + q("update item set tag = '%s' where id = %d limit 1", + dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . '#[url=' . $a->get_baseurl() . '/search?search=' . $term . ']'. $term . '[/url]'), + intval($r[0]['id']) + ); + } + + } + + + $arr['id'] = $post_id; + + call_hooks('post_local_end', $arr); + + proc_run('php',"include/notifier.php","tag","$post_id"); + + killme(); + + return; // NOTREACHED + + +}
\ No newline at end of file diff --git a/mod/viewsrc.php b/mod/viewsrc.php new file mode 100644 index 000000000..8900e44db --- /dev/null +++ b/mod/viewsrc.php @@ -0,0 +1,30 @@ +<?php + + +function viewsrc_content(&$a) { + + if(! local_user()) { + notice( t('Access denied.') . EOL); + return; + } + + $item_id = (($a->argc > 1) ? intval($a->argv[1]) : 0); + + if(! $item_id) { + $a->error = 404; + notice( t('Item not found.') . EOL); + return; + } + + $r = q("SELECT `item`.`body` FROM `item` + WHERE `item`.`uid` = %d AND `item`.`visible` = 1 AND `item`.`deleted` = 0 + AND `item`.`id` = '%s' LIMIT 1", + intval(local_user()), + dbesc($item_id) + ); + + if(count($r)) + $o .= str_replace("\n",'<br />',$r[0]['body']); + return $o; +} + diff --git a/mod/xrd.php b/mod/xrd.php index a416a2cf3..2fa6bcd99 100644 --- a/mod/xrd.php +++ b/mod/xrd.php @@ -47,6 +47,7 @@ function xrd_init(&$a) { '$hcard_url' => $a->get_baseurl() . '/hcard/' . $r[0]['nickname'], '$atom' => $a->get_baseurl() . '/dfrn_poll/' . $r[0]['nickname'], '$zot_post' => $a->get_baseurl() . '/post/' . $r[0]['nickname'], + '$poco_url' => $a->get_baseurl() . '/poco/' . $r[0]['nickname'], '$photo' => $a->get_baseurl() . '/photo/profile/' . $r[0]['uid'] . '.jpg', '$dspr' => $dspr, '$salmon' => $a->get_baseurl() . '/salmon/' . $r[0]['nickname'], diff --git a/update.php b/update.php index ed6b9e05e..67017fa03 100644 --- a/update.php +++ b/update.php @@ -1,6 +1,6 @@ <?php -define( 'UPDATE_VERSION' , 1097 ); +define( 'UPDATE_VERSION' , 1102 ); /** * @@ -800,4 +800,83 @@ function update_1096() { q("ALTER TABLE `item` ADD `origin` TINYINT( 1 ) NOT NULL DEFAULT '0' AFTER `deleted` , ADD INDEX ( `origin` ) "); } +function update_1097() { + q("ALTER TABLE `queue` + ADD INDEX (`cid`), + ADD INDEX (`created`), + ADD INDEX (`last`), + ADD INDEX (`network`), + ADD INDEX (`batch`) + "); +} + +function update_1098() { + q("ALTER TABLE `contact` + ADD INDEX (`network`), + ADD INDEX (`name`), + ADD INDEX (`nick`), + ADD INDEX (`attag`), + ADD INDEX (`url`), + ADD INDEX (`addr`), + ADD INDEX (`batch`) + "); +} + +function update_1099() { + q("CREATE TABLE IF NOT EXISTS `gcontact` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , + `name` CHAR( 255 ) NOT NULL , + `url` CHAR( 255 ) NOT NULL , + `nurl` CHAR( 255 ) NOT NULL , + `photo` CHAR( 255 ) NOT NULL + ) ENGINE = MYISAM "); + + q("CREATE TABLE IF NOT EXISTS `glink` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , + `cid` INT NOT NULL , + `uid` INT NOT NULL , + `gcid` INT NOT NULL, + `updated` DATETIME NOT NULL + ) ENGINE = MYISAM "); + + q("ALTER TABLE `gcontact` ADD INDEX (`nurl`) "); + q("ALTER TABLE `glink` ADD INDEX (`cid`), ADD INDEX (`uid`), ADD INDEX (`gcid`), ADD INDEX (`updated`) "); + + q("ALTER TABLE `contact` ADD `poco` TEXT NOT NULL AFTER `confirm` "); + +} + +function update_1100() { + q("ALTER TABLE `contact` ADD `nurl` CHAR( 255 ) NOT NULL AFTER `url` "); + q("alter table contact add index (`nurl`) "); + + require_once('include/text.php'); + + $r = q("select id, url from contact where url != '' and nurl = '' "); + if(count($r)) { + foreach($r as $rr) { + q("update contact set nurl = '%s' where id = %d limit 1", + dbesc(normalise_link($rr['url'])), + intval($rr['id']) + ); + } + } +} + + +function update_1101() { + q("CREATE TABLE IF NOT EXISTS `gcign` ( + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , + `uid` INT NOT NULL , + `gcid` INT NOT NULL + ) ENGINE = MYISAM "); + + q("ALTER TABLE `gcign` ADD INDEX (`uid`), ADD INDEX (`gcid`) "); +} + + + + + + diff --git a/view/common_friends.tpl b/view/common_friends.tpl new file mode 100644 index 000000000..1f610d8c4 --- /dev/null +++ b/view/common_friends.tpl @@ -0,0 +1,12 @@ +<div class="profile-match-wrapper"> + <div class="profile-match-photo"> + <a href="$url"> + <img src="$photo" alt="$name" width="80" height="80" title="$name [$url]" /> + </a> + </div> + <div class="profile-match-break"></div> + <div class="profile-match-name"> + <a href="$url" title="$name[$tags]">$name</a> + </div> + <div class="profile-match-end"></div> +</div>
\ No newline at end of file diff --git a/view/contact_edit.tpl b/view/contact_edit.tpl index 248140a6b..c2e3e36fb 100644 --- a/view/contact_edit.tpl +++ b/view/contact_edit.tpl @@ -19,6 +19,7 @@ $nettype </div> <div id="contact-edit-nav-wrapper" > + <div id="contact-edit-links" > <a href="contacts/$contact_id/block" class="icon block" id="contact-edit-block-link" title="$block_text"></a> <a href="contacts/$contact_id/ignore" class="icon no" id="contact-edit-ignore-link" title="$ignore_text"></a> @@ -41,6 +42,14 @@ $nettype </div> <div id="contact-edit-end" ></div> + + {{ if $common_text }} + <div id="contact-edit-common"> + <a href="$common_link">$common_text</a> + </a> + {{ endif }} + + $insecure $blocked $ignored diff --git a/view/custom_tinymce.css b/view/custom_tinymce.css index 48621c42c..7932653b6 100644 --- a/view/custom_tinymce.css +++ b/view/custom_tinymce.css @@ -33,3 +33,9 @@ scrollbar-track-color:#F5F5F5; img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px} font[face=mceinline] {font-family:inherit !important} + + +object { + display: block; width: 400px; + background: #cccccc url(../images/plugin.png) no-repeat center center; +} diff --git a/view/diaspora_like.tpl b/view/diaspora_like.tpl index 76356eb29..a777aeebe 100644 --- a/view/diaspora_like.tpl +++ b/view/diaspora_like.tpl @@ -1,7 +1,7 @@ <XML> <post> <like> - <target_type>$type</target_type> + <target_type>$target_type</target_type> <guid>$guid</guid> <parent_guid>$parent_guid</parent_guid> <author_signature>$authorsig</author_signature> diff --git a/view/diaspora_like_relay.tpl b/view/diaspora_like_relay.tpl index 6feba96ad..65559b05b 100644 --- a/view/diaspora_like_relay.tpl +++ b/view/diaspora_like_relay.tpl @@ -2,7 +2,7 @@ <post> <like> <guid>$guid</guid> - <target_type>$type</target_type> + <target_type>$target_type</target_type> <parent_guid>$parent_guid</parent_guid> <parent_author_signature>$parentsig</parent_author_signature> <author_signature>$authrosig</author_signature> diff --git a/view/diaspora_signed_retract.tpl b/view/diaspora_signed_retract.tpl new file mode 100644 index 000000000..22120e287 --- /dev/null +++ b/view/diaspora_signed_retract.tpl @@ -0,0 +1,10 @@ +<XML> + <post> + <signed_retraction> + <target_guid>$guid</target_guid> + <target_type>$type</target_type> + <sender_handle>$handle</sender_handle> + <target_author_signature>$signature</target_author_signature> + </signed_retraction> + </post> +</XML> diff --git a/view/diaspora_vcard.tpl b/view/diaspora_vcard.tpl index 684b1d18d..e71fc33ef 100644 --- a/view/diaspora_vcard.tpl +++ b/view/diaspora_vcard.tpl @@ -33,19 +33,19 @@ <dl class="entity_photo"> <dt>Photo</dt> <dd> - <img class="photo avatar" height="300px" width="300px" src="$diaspora.photo300"> + <img class="photo avatar" height="300" width="300" src="$diaspora.photo300"> </dd> </dl> <dl class="entity_photo_medium"> <dt>Photo</dt> <dd> - <img class="photo avatar" height="100px" width="100px" src="$diaspora.photo100"> + <img class="photo avatar" height="100" width="100" src="$diaspora.photo100"> </dd> </dl> <dl class="entity_photo_small"> <dt>Photo</dt> <dd> - <img class="photo avatar" height="50px" width="50px" src="$diaspora.photo50"> + <img class="photo avatar" height="50" width="50" src="$diaspora.photo50"> </dd> </dl> <dl class="entity_searchable"> diff --git a/view/head.tpl b/view/head.tpl index b6d78da39..752915b14 100644 --- a/view/head.tpl +++ b/view/head.tpl @@ -17,11 +17,14 @@ <script type="text/javascript" src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <script type="text/javascript" src="$baseurl/js/jquery.js" ></script> +<script type="text/javascript" src="$baseurl/js/jquery.textinputs.js" ></script> +<script type="text/javascript" src="$baseurl/js/fk.autocomplete.js" ></script> <script type="text/javascript" src="$baseurl/library/fancybox/jquery.fancybox-1.3.4.pack.js"></script> <script type="text/javascript" src="$baseurl/library/tiptip/jquery.tipTip.minified.js"></script> <script type="text/javascript" src="$baseurl/library/jgrowl/jquery.jgrowl_minimized.js"></script> <script type="text/javascript" src="$baseurl/library/tinymce/jscripts/tiny_mce/tiny_mce_src.js" ></script> <script type="text/javascript" src="$baseurl/js/acl.js" ></script> +<script type="text/javascript" src="$baseurl/js/webtoolkit.base64.js" ></script> <script type="text/javascript" src="$baseurl/js/main.js" ></script> <script> diff --git a/view/jot-header.tpl b/view/jot-header.tpl index 22bd0aa5b..9ded3e9b4 100644 --- a/view/jot-header.tpl +++ b/view/jot-header.tpl @@ -30,9 +30,26 @@ function initEditor(cb){ content_css: "$baseurl/view/custom_tinymce.css", theme_advanced_path : false, setup : function(ed) { - //Character count + cPopup = null; + ed.onKeyDown.add(function(ed,e) { + if(cPopup !== null) + cPopup.onkey(e); + }); + ed.onKeyUp.add(function(ed, e) { var txt = tinyMCE.activeEditor.getContent(); + match = txt.match(/@([^ \n]+)$/); + if(match!==null) { + if(cPopup === null) { + cPopup = new ACPopup(this,baseurl+"/acl"); + } + if(cPopup.ready && match[1]!==cPopup.searchText) cPopup.search(match[1]); + if(! cPopup.ready) cPopup = null; + } + else { + if(cPopup !== null) { cPopup.close(); cPopup = null; } + } + textlen = txt.length; if(textlen != 0 && $('#jot-perms-icon').is('.unlock')) { $('#profile-jot-desc').html(ispublic); @@ -41,6 +58,8 @@ function initEditor(cb){ $('#profile-jot-desc').html(' '); } + //Character count + if(textlen <= 140) { $('#character-counter').removeClass('red'); $('#character-counter').removeClass('orange'); @@ -71,8 +90,8 @@ function initEditor(cb){ editor = true; // setup acl popup $("a#jot-perms-icon").fancybox({ - 'transitionIn' : 'none', - 'transitionOut' : 'none' + 'transitionIn' : 'elastic', + 'transitionOut' : 'elastic' }); } else { if (typeof cb!="undefined") cb(); @@ -214,6 +233,19 @@ function initEditor(cb){ } } + function itemTag(id) { + $('#like-rotator-' + id).show(); + reply = prompt("$term"); + if(reply && reply.length) { + reply = reply.replace('#',''); + if(reply.length) { + $.get('tagger/' + id + '?term=' + reply, function(data) { + $('#like-rotator-' + id).hide(); + }); + } + } + } + function jotClearLocation() { $('#jot-coord').val(''); $('#profile-nolocation-wrapper').hide(); diff --git a/view/nav.tpl b/view/nav.tpl index 16aa99cb3..d0c640db1 100644 --- a/view/nav.tpl +++ b/view/nav.tpl @@ -47,16 +47,7 @@ <li class="empty">$emptynotifications</li> </ul> </li> - {{ endif }} - - - - - - - - - + {{ endif }} <li id="nav-site-linkmenu" class="nav-menu-icon"><a href="#" rel="#nav-site-menu"><span class="icon s22 gear">Site</span></a> <ul id="nav-site-menu" class="menu-popup"> diff --git a/view/oembed_video.tpl b/view/oembed_video.tpl new file mode 100644 index 000000000..5824d8d4e --- /dev/null +++ b/view/oembed_video.tpl @@ -0,0 +1,4 @@ +<a href='$embedurl' onclick='this.innerHTML=Base64.decode("$escapedhtml"); return false;' style='float:left; margin: 1em; position: relative;'> + <img width='$tw' height='$th' src='$turl' > + <div style='position: absolute; top: 0px; left: 0px; width: $twpx; height: $thpx; background: url(images/icons/48/play.png) no-repeat center center;'></div> +</a> diff --git a/view/peoplefind.tpl b/view/peoplefind.tpl index 4b3f01b88..eeae2a29a 100644 --- a/view/peoplefind.tpl +++ b/view/peoplefind.tpl @@ -5,6 +5,7 @@ <input id="side-peoplefind-url" type="text" name="search" size="24" title="$hint" /><input id="side-peoplefind-submit" type="submit" name="submit" value="$findthem" /> </form> <div class="side-link" id="side-match-link"><a href="match" >$similar</a></div> + <div class="side-link" id="side-suggest-link"><a href="suggest" >$suggest</a></div> {{ if $inv }} <div class="side-link" id="side-invite-link" ><a href="invite" >$inv</a></div> {{ endif }} diff --git a/view/poco_entry_xml.tpl b/view/poco_entry_xml.tpl new file mode 100644 index 000000000..8d5515152 --- /dev/null +++ b/view/poco_entry_xml.tpl @@ -0,0 +1,7 @@ +<entry> +{{ if $entry.id }}<id>$entry.id</id>{{ endif }} +{{ if $entry.displayName }}<displayName>$entry.displayName</displayName>{{ endif }} +{{ if $entry.preferredUsername }}<preferredUsername>$entry.preferredUsername</preferredUsername>{{ endif }} +{{ if $entry.urls }}<urls><value>$entry.urls.value</value><type>$entry.urls.type</type></urls>{{ endif }} +{{ if $entry.photos }}<photos><value>$entry.photos.value</value><type>$entry.photos.type</type></photos>{{ endif }} +</entry> diff --git a/view/poco_xml.tpl b/view/poco_xml.tpl new file mode 100644 index 000000000..9549b695d --- /dev/null +++ b/view/poco_xml.tpl @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<response> +{{ if $response.sorted }}<sorted>$response.sorted</sorted>{{ endif }} +{{ if $response.filtered }}<filtered>$response.filtered</filtered>{{ endif }} +{{ if $response.updatedSince }}<updatedSince>$response.updatedSince</updatedSince>{{ endif }} +<startIndex>$response.startIndex</startIndex> +<itemsPerPage>$response.itemsPerPage</itemsPerPage> +<totalResults>$response.totalResults</totalResults> + + +{{ if $response.totalResults }} +{{ for $response.entry as $entry }} +{{ inc poco_entry_xml.tpl }}{{ endinc }} +{{ endfor }} +{{ else }} +<entry></entry> +{{ endif }} +</response> diff --git a/view/profile_edlink.tpl b/view/profile_edlink.tpl new file mode 100644 index 000000000..ea787b9f5 --- /dev/null +++ b/view/profile_edlink.tpl @@ -0,0 +1,2 @@ +<div class="profile-edit-side-div"><a class="profile-edit-side-link icon edit" title="$editprofile" href="profiles/$profid" ></a></div> +<div class="clear"></div>
\ No newline at end of file diff --git a/view/profile_listing_header.tpl b/view/profile_listing_header.tpl index 95d0f177c..09e4fc9b2 100644 --- a/view/profile_listing_header.tpl +++ b/view/profile_listing_header.tpl @@ -2,7 +2,7 @@ <p id="profile-listing-desc" class="button" > <a href="profile_photo" >$chg_photo</a> </p> -<div id="profile-listing-new-link-wrapper" class="button > +<div id="profile-listing-new-link-wrapper" class="button" > <a href="profiles/new" id="profile-listing-new-link" title="$cr_new" >$cr_new</a> </div> diff --git a/view/profile_vcard.tpl b/view/profile_vcard.tpl index d65b65784..c78eb9b7f 100644 --- a/view/profile_vcard.tpl +++ b/view/profile_vcard.tpl @@ -21,7 +21,7 @@ {{ if $pdesc }}<div class="title">$profile.pdesc</div>{{ endif }} - <div id="profile-photo-wrapper"><img class="photo" width="175" height="175" src="$profile.photo" alt="$profile.name"></div> + <div id="profile-photo-wrapper"><img class="photo" width="175" height="175" src="$profile.photo" alt="$profile.name" /></div> diff --git a/view/settings.tpl b/view/settings.tpl index 3bbfc6ffd..52f989f99 100644 --- a/view/settings.tpl +++ b/view/settings.tpl @@ -51,6 +51,12 @@ $hide_friends $hide_wall +$blockwall + +$blocktags + +{{inc field_input.tpl with $field=$expire }}{{endinc}} + <div id="settings-default-perms" class="settings-default-perms" > <div id="settings-default-perms-menu" class="fakelink" onClick="openClose('settings-default-perms-select');" >$permissions $permdesc</div> <div id="settings-default-perms-menu-end"></div> @@ -63,11 +69,6 @@ $hide_wall </div> <div id="settings-default-perms-end"></div> -{{inc field_checkbox.tpl with $field=$blockwall }}{{endinc}} - -{{inc field_input.tpl with $field=$expire }}{{endinc}} - - <div class="settings-submit-wrapper" > <input type="submit" name="submit" class="settings-submit" value="Submit" /> diff --git a/view/suggest_friends.tpl b/view/suggest_friends.tpl new file mode 100644 index 000000000..8e6056494 --- /dev/null +++ b/view/suggest_friends.tpl @@ -0,0 +1,13 @@ +<div class="profile-match-wrapper"> + <a href="$ignlnk" title="$ignore" class="icon drophide profile-match-ignore" onmouseout="imgdull(this);" onmouseover="imgbright(this);" onclick="return confirmDelete();" ></a> + <div class="profile-match-photo"> + <a href="$url"> + <img src="$photo" alt="$name" width="80" height="80" title="$name [$url]" /> + </a> + </div> + <div class="profile-match-break"></div> + <div class="profile-match-name"> + <a href="$url" title="$name">$name</a> + </div> + <div class="profile-match-end"></div> +</div>
\ No newline at end of file diff --git a/view/theme/darkzero/style.css b/view/theme/darkzero/style.css index 454c578b0..1aa1efe87 100644 --- a/view/theme/darkzero/style.css +++ b/view/theme/darkzero/style.css @@ -66,3 +66,7 @@ input#dfrn-url { background-color: #222222; color: #FFFFFF !important; } +.pager_first a, .pager_last a, .pager_prev a, .pager_next a, .pager_n a, .pager_current { + color: #000088; +} + diff --git a/view/theme/dispy/style.css b/view/theme/dispy/style.css index 3c92a877b..0d8b54698 100644 --- a/view/theme/dispy/style.css +++ b/view/theme/dispy/style.css @@ -1250,3 +1250,24 @@ footer { display: block; margin: 50px 20%; clear: both; } /** /acl **/ +/* autocomplete popup */ +.acpopup { + max-height:150px; + background-color:#555753; + color: #FFFFFF; + overflow:auto; + z-index:100000; + border:1px solid #cccccc; +} +.acpopupitem { + background-color:#555753; padding: 4px; + clear:left; +} +.acpopupitem img { + float: left; + margin-right: 4px; +} + +.acpopupitem.selected { + color: #2e3436; background-color: #eeeeec; +} diff --git a/view/theme/duepuntozero/style.css b/view/theme/duepuntozero/style.css index 7e7adbadc..e9c0817f4 100644 --- a/view/theme/duepuntozero/style.css +++ b/view/theme/duepuntozero/style.css @@ -228,6 +228,9 @@ footer { } +.birthday-today, .event-today { + font-weight: bold; +} div.wall-item-content-wrapper.shiny { background-image: url('shiny.png'); @@ -514,6 +517,17 @@ input#dfrn-url { #profile-edit-links li { margin-top: 10px; } +.profile-edit-side-div { + float: right; +} +.profile-edit-side-link { + opacity: 0.3; + filter:alpha(opacity=30); +} +.profile-edit-side-link:hover { + opacity: 1.0; + filter:alpha(opacity=100); +} .view-contact-wrapper { margin-top: 20px; @@ -958,6 +972,11 @@ input#dfrn-url { margin-left: 10px; float: left; } +.tag-item { + margin-left: 10px; + float: left; +} + .wall-item-links-wrapper { float: left; @@ -2534,6 +2553,16 @@ a.mail-list-link { margin-top: 10px; } +.body-tag { + opacity: 0.5; + filter:alpha(opacity=50); +} + +.body-tag:hover { + opacity: 1.0 !important; + filter:alpha(opacity=100) !important; +} + .item-select { opacity: 0.1; filter:alpha(opacity=10); @@ -2837,3 +2866,24 @@ a.mail-list-link { .type-text { background-position: -60px 0px; } .type-unkn { background-position: -80px 0px; } + +/* autocomplete popup */ +.acpopup { + max-height:150px; + background-color:#ffffff; + overflow:auto; + z-index:100000; + border:1px solid #cccccc; +} +.acpopupitem { + background-color:#ffffff; padding: 4px; + clear:left; +} +.acpopupitem img { + float: left; + margin-right: 4px; +} + +.acpopupitem.selected { + color: #FFFFFF; background: #3465A4; +} diff --git a/view/theme/duepuntozero/wall_item.tpl b/view/theme/duepuntozero/wall_item.tpl index d264d3999..3a4a49729 100644 --- a/view/theme/duepuntozero/wall_item.tpl +++ b/view/theme/duepuntozero/wall_item.tpl @@ -49,6 +49,7 @@ {{ if $star }} <a href="#" id="starred-$id" onclick="dostar($id); return false;" class="star-item icon $isstarred" title="$star.toggle"></a> + <a href="#" id="tagger-$id" onclick="itemTag($id); return false;" class="tag-item icon tagged" title="$star.tagger"></a> {{ endif }} <div class="wall-item-delete-wrapper" id="wall-item-delete-wrapper-$id" > diff --git a/view/theme/loozah/style.css b/view/theme/loozah/style.css index 447072390..c978e140a 100644 --- a/view/theme/loozah/style.css +++ b/view/theme/loozah/style.css @@ -623,6 +623,10 @@ input#dfrn-url { margin-top: 10px; } +.profile-edit-side-div { + float: right; +} + .view-contact-wrapper { margin-top: 20px; float: left; @@ -2745,9 +2749,31 @@ a.mail-list-link { margin-top: 10px; } -.type-video { background-position: 0px; 0px; } -.type-image { background-position: -20px; 0px; } -.type-audio { background-position: -40px; 0px; } -.type-text { background-position: -60px; 0px; } -.type-unkn { background-position: -80px; 0px; } +.type-video { background-position: 0px 0px; } +.type-image { background-position: -20px 0px; } +.type-audio { background-position: -40px 0px; } +.type-text { background-position: -60px 0px; } +.type-unkn { background-position: -80px 0px; } + +/* autocomplete popup */ +.acpopup { + max-height:150px; + background-color:#ffffff; + overflow:auto; + z-index:100000; + border:1px solid #cccccc; +} +.acpopupitem { + background-color:#ffffff; padding: 4px; + clear:left; +} +.acpopupitem img { + float: left; + margin-right: 4px; +} + +.acpopupitem.selected { + color: #FFFFFF; background: #3465A4; +} + diff --git a/view/theme/quattro/quattro.less b/view/theme/quattro/quattro.less index 1fbeb7ae2..ea699d5c6 100644 --- a/view/theme/quattro/quattro.less +++ b/view/theme/quattro/quattro.less @@ -192,6 +192,29 @@ ul.menu-popup { } +/* autocomplete popup */ +.acpopup { + max-height:150px; + background-color:@MenuBg; + color: @Menu; + border:1px solid #MenuBorder; + overflow:auto; + z-index:100000; + .shadow(); +} +.acpopupitem { + color: @MenuItem; padding: 4px; + clear:left; + img { + float: left; + margin-right: 4px; + } + &.selected{ + background-color: @MenuItemHoverBg; + } +} + + #nav-notifications-menu { width: 400px; img { float: left; margin-right: 5px; } diff --git a/view/theme/quattro/style.css b/view/theme/quattro/style.css index 585214233..95c3d087e 100644 --- a/view/theme/quattro/style.css +++ b/view/theme/quattro/style.css @@ -388,6 +388,30 @@ ul.menu-popup .empty { text-align: center; color: #9eabb0; } +/* autocomplete popup */ +.acpopup { + max-height: 150px; + background-color: #ffffff; + color: #2d2d2d; + border: 1px solid #MenuBorder; + overflow: auto; + z-index: 100000; + -webkit-box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.7); + -moz-box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.7); + box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.7); +} +.acpopupitem { + color: #2d2d2d; + padding: 4px; + clear: left; +} +.acpopupitem img { + float: left; + margin-right: 4px; +} +.acpopupitem.selected { + background-color: #bdcdd4; +} #nav-notifications-menu { width: 400px; } diff --git a/view/theme/testbubble/style.css b/view/theme/testbubble/style.css index b7c20ab17..91920e84d 100644 --- a/view/theme/testbubble/style.css +++ b/view/theme/testbubble/style.css @@ -823,7 +823,7 @@ profile-jot-banner-wrapper { /* ======== */ .tabs { - width: 500px; + min-width: 500px; list-style: none; padding: 10px; margin: 0px 0px 10px 0px; @@ -1244,6 +1244,12 @@ div[id$="wrapper"] br { clear: left; } background-color: #b20202; } +.profile-edit-side-div { + margin-top: 5px; + margin-right: 30px; + float: right; +} + #cropimage-wrapper { float:left; } #crop-image-form { clear:both; } @@ -3086,3 +3092,41 @@ ul.menu-popup { #jGrowl { z-index: 20000; } + +/* autocomplete popup */ +.acpopup { + max-height:150px; + overflow:auto; + z-index:100000; + + color: #2e3436; + border-top: 0px; + background: #eeeeee; + border-right: 1px solid #dddddd; + border-left: 1px solid #dddddd; + border-bottom: 1px solid #dddddd; + -webkit-border-radius: 0px 5px 5px 5px; + -moz-border-radius: 0px 5px 5px 5px; + border-radius: 0px 5px 5px 5px; + -moz-box-shadow: 3px 3px 4px #959494; + -webkit-box-shadow: 3px 3px 4px #959494; + box-shadow: 3px 3px 4px #959494; + +} +.acpopupitem { + color: #2e3436; padding: 4px; + clear:left; +} +.acpopupitem img { + float: left; + margin-right: 4px; +} + +.acpopupitem.selected { + color: #efefef; + background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #b20202), color-stop(1, #d60808) ); + background:-moz-linear-gradient( center top, #b20202 5%, #d60808 100% ); + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#b20202', endColorstr='#d60808'); + background-color:#b20202; + order-bottom: none; +} diff --git a/view/wall_item.tpl b/view/wall_item.tpl index cec5e5404..ef822750a 100644 --- a/view/wall_item.tpl +++ b/view/wall_item.tpl @@ -40,6 +40,7 @@ {{ if $star }} <a href="#" id="star-$id" onclick="dostar($id); return false;" class="$star.classdo" title="$star.do">$star.do</a> <a href="#" id="unstar-$id" onclick="dostar($id); return false;" class="$star.classundo" title="$star.undo">$star.undo</a> + <a href="#" id="tagger-$id" onclick="itemTag($id); return false;" class="$star.classtagger" title="$star.tagger">$star.tagger</a> {{ endif }} {{ if $vote }} diff --git a/view/xrd_person.tpl b/view/xrd_person.tpl index 2b5af3d0d..a4b921fe1 100644 --- a/view/xrd_person.tpl +++ b/view/xrd_person.tpl @@ -27,6 +27,8 @@ <Link rel="http://microformats.org/profile/hcard" type="text/html" href="$hcard_url" /> + <Link rel="http://portablecontacts.net/spec/1.0" + href="$poco_url" /> <Link rel="http://webfinger.net/rel/avatar" type="image/jpeg" href="$photo" /> |