diff --git a/boot.php b/boot.php index be47184aa2..effe237852 100644 --- a/boot.php +++ b/boot.php @@ -10,9 +10,9 @@ require_once('include/nav.php'); require_once('include/cache.php'); define ( 'FRIENDICA_PLATFORM', 'Friendica'); -define ( 'FRIENDICA_VERSION', '3.0.1382' ); +define ( 'FRIENDICA_VERSION', '3.0.1395' ); define ( 'DFRN_PROTOCOL_VERSION', '2.23' ); -define ( 'DB_UPDATE_VERSION', 1149 ); +define ( 'DB_UPDATE_VERSION', 1153 ); define ( 'EOL', "
\r\n" ); define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' ); @@ -34,6 +34,24 @@ define ( 'JPEG_QUALITY', 100 ); */ define ( 'PNG_QUALITY', 8 ); +/** + * + * An alternate way of limiting picture upload sizes. Specify the maximum pixel + * length that pictures are allowed to be (for non-square pictures, it will apply + * to the longest side). Pictures longer than this length will be resized to be + * this length (on the longest side, the other side will be scaled appropriately). + * Modify this value using + * + * $a->config['system']['max_image_length'] = n; + * + * in .htconfig.php + * + * If you don't want to set a maximum length, set to -1. The default value is + * defined by 'MAX_IMAGE_LENGTH' below. + * + */ +define ( 'MAX_IMAGE_LENGTH', -1 ); + /** * Not yet used @@ -177,6 +195,22 @@ define ( 'NOTIFY_TAGSHARE', 0x0100 ); define ( 'NOTIFY_SYSTEM', 0x8000 ); +/** + * Tag/term types + */ + +define ( 'TERM_UNKNOWN', 0 ); +define ( 'TERM_HASHTAG', 1 ); +define ( 'TERM_MENTION', 2 ); +define ( 'TERM_CATEGORY', 3 ); +define ( 'TERM_PCATEGORY', 4 ); +define ( 'TERM_FILE', 5 ); + +define ( 'TERM_OBJ_POST', 1 ); +define ( 'TERM_OBJ_PHOTO', 2 ); + + + /** * various namespaces we may need to parse */ @@ -352,6 +386,16 @@ if(! class_exists('App')) { if(x($_SERVER,'SERVER_NAME')) { $this->hostname = $_SERVER['SERVER_NAME']; + + // See bug 437 - this didn't work so disabling it + //if(stristr($this->hostname,'xn--')) { + // PHP or webserver may have converted idn to punycode, so + // convert punycode back to utf-8 + // require_once('library/simplepie/idn/idna_convert.class.php'); + // $x = new idna_convert(); + // $this->hostname = $x->decode($_SERVER['SERVER_NAME']); + //} + if(x($_SERVER,'SERVER_PORT') && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) $this->hostname .= ':' . $_SERVER['SERVER_PORT']; /** @@ -434,6 +478,8 @@ if(! class_exists('App')) { $this->pager['page'] = ((x($_GET,'page') && intval($_GET['page']) > 0) ? intval($_GET['page']) : 1); $this->pager['itemspage'] = 50; $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage']; + if($this->pager['start'] < 0) + $this->pager['start'] = 0; $this->pager['total'] = 0; } @@ -1252,6 +1298,9 @@ if(! function_exists('get_birthdays')) { '$event_reminders' => t('Birthday Reminders'), '$event_title' => t('Birthdays this week:'), '$events' => $r, + '$lbr' => '{', // raw brackets mess up if/endif macro processing + '$rbr' => '}' + )); } } @@ -1374,9 +1423,9 @@ if(! function_exists('proc_run')) { if(count($args) && $args[0] === 'php') $args[0] = ((x($a->config,'php_path')) && (strlen($a->config['php_path'])) ? $a->config['php_path'] : 'php'); - foreach ($args as $arg){ - $arg = escapeshellarg($arg); - } + for($x = 0; $x < count($args); $x ++) + $args[$x] = escapeshellarg($args[$x]); + $cmdline = implode($args," "); proc_close(proc_open($cmdline." &",array(),$foo)); } diff --git a/database.sql b/database.sql index 53dc0c5b21..1d0a321760 100644 --- a/database.sql +++ b/database.sql @@ -254,6 +254,7 @@ CREATE TABLE IF NOT EXISTS `event` ( `edited` datetime NOT NULL, `start` datetime NOT NULL, `finish` datetime NOT NULL, + `summary` text NOT NULL, `desc` text NOT NULL, `location` text NOT NULL, `type` char(255) NOT NULL, @@ -263,7 +264,14 @@ CREATE TABLE IF NOT EXISTS `event` ( `allow_gid` mediumtext NOT NULL, `deny_cid` mediumtext NOT NULL, `deny_gid` mediumtext NOT NULL, - PRIMARY KEY (`id`) + PRIMARY KEY (`id`), + KEY `uid` ( `uid` ), + KEY `cid` ( `cid` ), + KEY `uri` ( `uri` ), + KEY `type` ( `type` ), + KEY `start` ( `start` ), + KEY `finish` ( `finish` ), + KEY `adjust` ( `adjust` ) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- -------------------------------------------------------- @@ -590,6 +598,19 @@ CREATE TABLE IF NOT EXISTS `item_id` ( -- -------------------------------------------------------- +-- +-- Table structure for table `locks` +-- + +CREATE TABLE `locks` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` char(128) NOT NULL, + `locked` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + -- -- Table structure for table `mail` -- @@ -831,6 +852,8 @@ CREATE TABLE IF NOT EXISTS `profile` ( `religion` char(255) NOT NULL, `pub_keywords` text NOT NULL, `prv_keywords` text NOT NULL, + `likes` text NOT NULL, + `dislikes` text NOT NULL, `about` text NOT NULL, `summary` char(255) NOT NULL, `music` text NOT NULL, @@ -977,6 +1000,26 @@ CREATE TABLE IF NOT EXISTS `spam` ( -- -------------------------------------------------------- +-- +-- Table structure for table `term` +-- + +CREATE TABLE IF NOT EXISTS `term` ( + `tid` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `oid` INT UNSIGNED NOT NULL , + `otype` TINYINT( 3 ) UNSIGNED NOT NULL , + `type` TINYINT( 3 ) UNSIGNED NOT NULL , + `term` CHAR( 255 ) NOT NULL , + `url` CHAR( 255 ) NOT NULL, + PRIMARY KEY (`tid`), + KEY `oid` ( `oid` ), + KEY `otype` ( `otype` ), + KEY `type` ( `type` ), + KEY `term` ( `term` ) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + -- -- Table structure for table `tokens` -- diff --git a/include/Scrape.php b/include/Scrape.php index 4f53effe92..b784650cd1 100644 --- a/include/Scrape.php +++ b/include/Scrape.php @@ -432,7 +432,7 @@ function probe_url($url, $mode = PROBE_NORMAL) { intval(local_user()) ); if(count($x) && count($r)) { - $mailbox = construct_mailbox_name($r[0]); + $mailbox = construct_mailbox_name($r[0]); $password = ''; openssl_private_decrypt(hex2bin($r[0]['pass']),$password,$x[0]['prvkey']); $mbox = email_connect($mailbox,$r[0]['user'],$password); diff --git a/include/api.php b/include/api.php index b77156dfae..d790b4b875 100644 --- a/include/api.php +++ b/include/api.php @@ -565,18 +565,19 @@ if(requestdata('lat') && requestdata('long')) $_REQUEST['coord'] = sprintf("%s %s",requestdata('lat'),requestdata('long')); $_REQUEST['profile_uid'] = local_user(); - if(requestdata('parent')) + + if($parent) $_REQUEST['type'] = 'net-comment'; else { $_REQUEST['type'] = 'wall'; - if(x($_FILES,'media')) { - // upload the image if we have one - $_REQUEST['hush']='yeah'; //tell wall_upload function to return img info instead of echo - require_once('mod/wall_upload.php'); - $media = wall_upload_post($a); - if(strlen($media)>0) - $_REQUEST['body'] .= "\n\n".$media; - } + if(x($_FILES,'media')) { + // upload the image if we have one + $_REQUEST['hush']='yeah'; //tell wall_upload function to return img info instead of echo + require_once('mod/wall_upload.php'); + $media = wall_upload_post($a); + if(strlen($media)>0) + $_REQUEST['body'] .= "\n\n".$media; + } } // set this so that the item_post() function is quiet and doesn't redirect or emit json @@ -864,8 +865,13 @@ logger('API: api_statuses_show: '.$id); //$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false); - //$sql_extra = ""; - if ($_GET["conversation"] == "true") $sql_extra .= " AND `item`.`parent` = %d ORDER BY `received` ASC "; else $sql_extra .= " AND `item`.`id` = %d"; + $conversation = (x($_REQUEST,'conversation')?1:0); + + $sql_extra = ''; + if ($conversation) + $sql_extra .= " AND `item`.`parent` = %d ORDER BY `received` ASC "; + else + $sql_extra .= " AND `item`.`id` = %d"; $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`, @@ -875,16 +881,15 @@ WHERE `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0 AND `contact`.`id` = `item`.`contact-id` AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 - $sql_extra - ", + $sql_extra", intval($id) ); -//var_dump($r); + $ret = api_format_items($r,$user_info); -//var_dump($ret); - if ($_GET["conversation"] == "true") { + + if ($conversation) { $data = array('$statuses' => $ret); - return api_apply_template("timeline", $type, $data); + return api_apply_template("timeline", $type, $data); } else { $data = array('$status' => $ret[0]); /*switch($type){ @@ -1233,6 +1238,40 @@ return($as); } + function api_format_messages($item, $recipient, $sender) { + // standard meta information + $ret=Array( + 'id' => $item['id'], + 'created_at' => api_date($item['created']), + 'sender_id' => $sender['id'] , + 'sender_screen_name' => $sender['screen_name'], + 'sender' => $sender, + 'recipient_id' => $recipient['id'], + 'recipient_screen_name' => $recipient['screen_name'], + 'recipient' => $recipient, + ); + + //don't send title to regular StatusNET requests to avoid confusing these apps + if (x($_GET, 'getText')) { + $ret['title'] = $item['title'] ; + if ($_GET["getText"] == "html") { + $ret['text'] = bbcode($item['body']); + } + elseif ($_GET["getText"] == "plain") { + $ret['text'] = html2plain(bbcode($item['body']), 0); + } + } + else { + $ret['text'] = $item['title']."\n".html2plain(bbcode($item['body']), 0); + } + if (isset($_GET["getUserObjects"]) && $_GET["getUserObjects"] == "false") { + unset($ret['sender']); + unset($ret['recipient']); + } + + return $ret; + } + function api_format_items($r,$user_info) { //logger('api_format_items: ' . print_r($r,true)); @@ -1429,7 +1468,13 @@ 'logo' => $logo, 'fancy' => 'true', 'language' => 'en', 'email' => $email, 'broughtby' => '', 'broughtbyurl' => '', 'timezone' => 'UTC', 'closed' => $closed, 'inviteonly' => 'false', 'private' => $private, 'textlimit' => $textlimit, 'sslserver' => $sslserver, 'ssl' => $ssl, - 'shorturllength' => '30' + 'shorturllength' => '30', + 'friendica' => array( + 'FRIENDICA_PLATFORM' => FRIENDICA_PLATFORM, + 'FRIENDICA_VERSION' => FRIENDICA_VERSION, + 'DFRN_PROTOCOL_VERSION' => DFRN_PROTOCOL_VERSION, + 'DB_UPDATE_VERSION' => DB_UPDATE_VERSION + ) ), ); @@ -1503,37 +1548,39 @@ if (local_user()===false) return false; if (!x($_POST, "text") || !x($_POST,"screen_name")) return; - + $sender = api_get_user($a); + require_once("include/message.php"); + $r = q("SELECT `id` FROM `contact` WHERE `uid`=%d AND `nick`='%s'", intval(local_user()), dbesc($_POST['screen_name'])); - - $recipient = api_get_user($a, $r[0]['id']); - - require_once("include/message.php"); - $sub = ( (strlen($_POST['text'])>10)?substr($_POST['text'],0,10)."...":$_POST['text']); - $id = send_message($recipient['id'], $_POST['text'], $sub); - - + $recipient = api_get_user($a, $r[0]['id']); + $replyto = ''; + $sub = ''; + if (x($_REQUEST,'replyto')) { + $r = q('SELECT `parent-uri`, `title` FROM `mail` WHERE `uid`=%d AND `id`=%d', + intval(local_user()), + intval($_REQUEST['replyto'])); + $replyto = $r[0]['parent-uri']; + $sub = $r[0]['title']; + } + else { + if (x($_REQUEST,'title')) { + $sub = $_REQUEST['title']; + } + else { + $sub = ((strlen($_POST['text'])>10)?substr($_POST['text'],0,10)."...":$_POST['text']); + } + } + + $id = send_message($recipient['id'], $_POST['text'], $sub, $replyto); + if ($id>-1) { $r = q("SELECT * FROM `mail` WHERE id=%d", intval($id)); - $item = $r[0]; - $ret=Array( - 'id' => $item['id'], - 'created_at'=> api_date($item['created']), - 'sender_id'=> $sender['id'] , - 'sender_screen_name'=> $sender['screen_name'], - 'sender'=> $sender, - 'recipient_id'=> $recipient['id'], - 'recipient_screen_name'=> $recipient['screen_name'], - 'recipient'=> $recipient, - - 'text'=> $item['title']."\n".html2plain(bbcode($item['body']), 0) , - - ); + $ret = api_format_messages($r[0], $recipient, $sender); } else { $ret = array("error"=>$id); @@ -1552,7 +1599,7 @@ } api_register_func('api/direct_messages/new','api_direct_messages_new',true); - function api_direct_messages_box(&$a, $type, $box) { + function api_direct_messages_box(&$a, $type, $box) { if (local_user()===false) return false; $user_info = api_get_user($a); @@ -1564,46 +1611,37 @@ $start = $page*$count; - + $profile_url = $a->get_baseurl() . '/profile/' . $a->user['nickname']; if ($box=="sentbox") { - $sql_extra = "`from-url`='%s'"; - } else { - $sql_extra = "`from-url`!='%s'"; + $sql_extra = "`from-url`='".dbesc( $profile_url )."'"; + } + elseif ($box=="conversation") { + $sql_extra = "`parent-uri`='".dbesc( $_GET["uri"] ) ."'"; + } + elseif ($box=="all") { + $sql_extra = "true"; + } + elseif ($box=="inbox") { + $sql_extra = "`from-url`!='".dbesc( $profile_url )."'"; } $r = q("SELECT * FROM `mail` WHERE uid=%d AND $sql_extra ORDER BY created DESC LIMIT %d,%d", intval(local_user()), - dbesc( $a->get_baseurl() . '/profile/' . $a->user['nickname'] ), intval($start), intval($count) - ); + ); $ret = Array(); - foreach($r as $item){ - switch ($box){ - case "inbox": - $recipient = $user_info; - $sender = api_get_user($a,$item['contact-id']); - break; - case "sentbox": - $recipient = api_get_user($a,$item['contact-id']); - $sender = $user_info; - break; + foreach($r as $item) { + if ($box == "inbox" || $item['from-url'] != $profile_url){ + $recipient = $user_info; + $sender = api_get_user($a,$item['contact-id']); } - - $ret[]=Array( - 'id' => $item['id'], - 'created_at'=> api_date($item['created']), - 'sender_id'=> $sender['id'] , - 'sender_screen_name'=> $sender['screen_name'], - 'sender'=> $sender, - 'recipient_id'=> $recipient['id'], - 'recipient_screen_name'=> $recipient['screen_name'], - 'recipient'=> $recipient, - - 'text'=> $item['title']."\n".html2plain(bbcode($item['body']), 0) , - - ); - + elseif ($box == "sentbox" || $item['from-url'] != $profile_url){ + $recipient = api_get_user($a,$item['contact-id']); + $sender = $user_info; + } + + $ret[]=api_format_messages($item, $recipient, $sender); } @@ -1624,6 +1662,14 @@ function api_direct_messages_inbox(&$a, $type){ return api_direct_messages_box($a, $type, "inbox"); } + function api_direct_messages_all(&$a, $type){ + return api_direct_messages_box($a, $type, "all"); + } + function api_direct_messages_conversation(&$a, $type){ + return api_direct_messages_box($a, $type, "conversation"); + } + api_register_func('api/direct_messages/conversation','api_direct_messages_conversation',true); + api_register_func('api/direct_messages/all','api_direct_messages_all',true); api_register_func('api/direct_messages/sent','api_direct_messages_sentbox',true); api_register_func('api/direct_messages','api_direct_messages_inbox',true); diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index d86ba45437..042177fd96 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -1,10 +1,11 @@ ',$s); +// we seem to have double linebreaks +// $s = str_replace("\n",'
',$s); $s = html2bbcode($s); // $s = str_replace('*','*',$s); + // protect the recycle symbol from turning into a tag, but without unescaping angles and naked ampersands + $s = str_replace('♲',html_entity_decode('♲',ENT_QUOTES,'UTF-8'),$s); + // Convert everything that looks like a link to a link $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3]$2$3[/url]',$s); @@ -66,9 +70,124 @@ function stripdcode_br_cb($s) { } +////////////////////// +// The following "diaspora_ul" and "diaspora_ol" are only appropriate for the +// pre-Markdownify conversion. If Markdownify isn't used, use the non-Markdownify +// versions below +////////////////////// +/* +function diaspora_ul($s) { + // Replace "[*]" followed by any number (including zero) of + // spaces by "* " to match Diaspora's list format + if( strpos($s[0], "[list]") === 0 ) + return ''; + elseif( strpos($s[0], "[ul]") === 0 ) + return ''; + else + return $s[0]; +} + + +function diaspora_ol($s) { + // A hack: Diaspora will create a properly-numbered ordered list even + // if you use '1.' for each element of the list, like: + // 1. First element + // 1. Second element + // 1. Third element + if( strpos($s[0], "[list=1]") === 0 ) + return ''; + elseif( strpos($s[0], "[list=i]") === 0 ) + return ''; + elseif( strpos($s[0], "[list=I]") === 0 ) + return ''; + elseif( strpos($s[0], "[list=a]") === 0 ) + return ''; + elseif( strpos($s[0], "[list=A]") === 0 ) + return ''; + elseif( strpos($s[0], "[ol]") === 0 ) + return ''; + else + return $s[0]; +} +*/ + +////////////////////// +// Non-Markdownify versions of "diaspora_ol" and "diaspora_ul" +////////////////////// +function diaspora_ul($s) { + // Replace "[\\*]" followed by any number (including zero) of + // spaces by "* " to match Diaspora's list format + return preg_replace("/\[\\\\\*\]( *)/", "* ", $s[1]); +} + +function diaspora_ol($s) { + // A hack: Diaspora will create a properly-numbered ordered list even + // if you use '1.' for each element of the list, like: + // 1. First element + // 1. Second element + // 1. Third element + return preg_replace("/\[\\\\\*\]( *)/", "1. ", $s[1]); +} + function bb2diaspora($Text,$preserve_nl = false) { +////////////////////// +// An attempt was made to convert bbcode to html and then to markdown +// consisting of the following lines. +// I'm undoing this as we have a lot of bbcode constructs which +// were simply getting lost, for instance bookmark, vimeo, video, youtube, events, etc. +// We can try this again, but need a very good test sequence to verify +// all the major bbcode constructs that we use are getting through. +////////////////////// +/* + // bbcode() will convert "[*]" into "
  • " with no closing "
  • " + // Markdownify() is unable to handle these, as it makes each new + // "
  • " into a deeper nested element until it crashes. So pre-format + // the lists as Diaspora lists before sending the $Text to bbcode() + // + // Note that to get nested lists to work for Diaspora, we would need + // to define the closing tag for the list elements. So nested lists + // are going to be flattened out in Diaspora for now + + $endlessloop = 0; + while ((((strpos($Text, "[/list]") !== false) && (strpos($Text, "[list") !== false)) || + ((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) || + ((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false))) && (++$endlessloop < 20)) { + $Text = preg_replace_callback("/\[list\](.*?)\[\/list\]/is", 'diaspora_ul', $Text); + $Text = preg_replace_callback("/\[list=1\](.*?)\[\/list\]/is", 'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[list=i\](.*?)\[\/list\]/s",'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[list=I\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[list=a\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[list=A\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[ul\](.*?)\[\/ul\]/is", 'diaspora_ul', $Text); + $Text = preg_replace_callback("/\[ol\](.*?)\[\/ol\]/is", 'diaspora_ol', $Text); + } + +*/ + + // Convert it to HTML - don't try oembed +// $Text = bbcode($Text, $preserve_nl, false); + + // Now convert HTML to Markdown +// $md = new Markdownify(false, false, false); +// $Text = $md->parseString($Text); + + // If the text going into bbcode() has a plain URL in it, i.e. + // with no [url] tags around it, it will come out of parseString() + // looking like: , which gets removed by strip_tags(). + // So take off the angle brackets of any such URL +// $Text = preg_replace("//is", "http$1", $Text); + + // Remove all unconverted tags +// $Text = strip_tags($Text); + +////// +// end of bb->html->md conversion attempt +////// + + + $ev = bbtoevent($Text); // Replace any html brackets with HTML Entities to prevent executing HTML or script @@ -78,12 +197,17 @@ function bb2diaspora($Text,$preserve_nl = false) { $Text = str_replace(">", ">", $Text); // If we find any event code, turn it into an event. - // After we're finished processing the bbcode we'll + // After we're finished processing the bbcode we'll // replace all of the event code with a reformatted version. - if($preserve_nl) $Text = str_replace(array("\n","\r"), array('',''),$Text); + else + // Remove the "return" character, as Diaspora uses only the "newline" + // character, so having the "return" character can cause signature + // failures + $Text = str_replace("\r", "", $Text); + // Set up the parameters for a URL search string $URLSearchString = "^\[\]"; @@ -98,7 +222,7 @@ function bb2diaspora($Text,$preserve_nl = false) { // new javascript markdown processor to handle links with images as the link "text" // It is not optimal and may be removed if this ability is restored in the future - $Text = preg_replace("/\[url\=([$URLSearchString]*)\]\[img\](.*?)\[\/img\]\[\/url\]/ism", + $Text = preg_replace("/\[url\=([$URLSearchString]*)\]\[img\](.*?)\[\/img\]\[\/url\]/ism", '![' . t('image/photo') . '](' . '$2' . ')' . "\n" . '[' . t('link') . '](' . '$1' . ')', $Text); $Text = preg_replace("/\[bookmark\]([$URLSearchString]*)\[\/bookmark\]/ism", '[$1]($1)', $Text); @@ -115,7 +239,7 @@ function bb2diaspora($Text,$preserve_nl = false) { // Perform MAIL Search $Text = preg_replace("(\[mail\]([$MAILSearchString]*)\[/mail\])", '[$1](mailto:$1)', $Text); $Text = preg_replace("/\[mail\=([$MAILSearchString]*)\](.*?)\[\/mail\]/", '[$2](mailto:$1)', $Text); - + $Text = str_replace('*', '\\*', $Text); $Text = str_replace('_', '\\_', $Text); @@ -124,48 +248,61 @@ function bb2diaspora($Text,$preserve_nl = false) { // Check for bold text $Text = preg_replace("(\[b\](.*?)\[\/b\])is",'**$1**',$Text); - // Check for Italics text + // Check for italics text $Text = preg_replace("(\[i\](.*?)\[\/i\])is",'_$1_',$Text); - // Check for Underline text -// $Text = preg_replace("(\[u\](.*?)\[\/u\])is",'$1',$Text); + // Check for underline text + // Replace with italics since Diaspora doesn't have underline + $Text = preg_replace("(\[u\](.*?)\[\/u\])is",'_$1_',$Text); // Check for strike-through text -// $Text = preg_replace("(\[s\](.*?)\[\/s\])is",'$1',$Text); + $Text = preg_replace("(\[s\](.*?)\[\/s\])is",'**[strike]**$1**[/strike]**',$Text); // Check for over-line text // $Text = preg_replace("(\[o\](.*?)\[\/o\])is",'$1',$Text); // Check for colored text -// $Text = preg_replace("(\[color=(.*?)\](.*?)\[\/color\])is","$2",$Text); + // Remove color since Diaspora doesn't support it + $Text = preg_replace("(\[color=(.*?)\](.*?)\[\/color\])is","$2",$Text); // Check for sized text -// $Text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])is","$2",$Text); + // Remove it since Diaspora doesn't support sizes very well + $Text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])is","$2",$Text); // Check for list text -// $Text = preg_replace("/\[list\](.*?)\[\/list\]/is", '
      $1
    ' ,$Text); -// $Text = preg_replace("/\[list=1\](.*?)\[\/list\]/is", '
      $1
    ' ,$Text); -// $Text = preg_replace("/\[list=i\](.*?)\[\/list\]/s",'
      $1
    ' ,$Text); -// $Text = preg_replace("/\[list=I\](.*?)\[\/list\]/s", '
      $1
    ' ,$Text); -// $Text = preg_replace("/\[list=a\](.*?)\[\/list\]/s", '
      $1
    ' ,$Text); -// $Text = preg_replace("/\[list=A\](.*?)\[\/list\]/s", '
      $1
    ' ,$Text); -// $Text = preg_replace("/\[li\](.*?)\[\/li\]/s", '
  • $1
  • ' ,$Text); + $endlessloop = 0; + while ((((strpos($Text, "[/list]") !== false) && (strpos($Text, "[list") !== false)) || + ((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) || + ((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false)) || + ((strpos($Text, "[/li]") !== false) && (strpos($Text, "[li]") !== false))) && (++$endlessloop < 20)) { + $Text = preg_replace_callback("/\[list\](.*?)\[\/list\]/is", 'diaspora_ul', $Text); + $Text = preg_replace_callback("/\[list=1\](.*?)\[\/list\]/is", 'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[list=i\](.*?)\[\/list\]/s",'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[list=I\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[list=a\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[list=A\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[ul\](.*?)\[\/ul\]/is", 'diaspora_ul', $Text); + $Text = preg_replace_callback("/\[ol\](.*?)\[\/ol\]/is", 'diaspora_ol', $Text); + $Text = preg_replace("/\[li\]( *)(.*?)\[\/li\]/s", '* $2' ,$Text); + } -// $Text = preg_replace("/\[td\](.*?)\[\/td\]/s", '$1' ,$Text); -// $Text = preg_replace("/\[tr\](.*?)\[\/tr\]/s", '$1' ,$Text); -// $Text = preg_replace("/\[table\](.*?)\[\/table\]/s", '$1
    ' ,$Text); + // Just get rid of table tags since Diaspora doesn't support tables + $Text = preg_replace("/\[th\](.*?)\[\/th\]/s", '$1' ,$Text); + $Text = preg_replace("/\[td\](.*?)\[\/td\]/s", '$1' ,$Text); + $Text = preg_replace("/\[tr\](.*?)\[\/tr\]/s", '$1' ,$Text); + $Text = preg_replace("/\[table\](.*?)\[\/table\]/s", '$1' ,$Text); -// $Text = preg_replace("/\[table border=1\](.*?)\[\/table\]/s", '$1
    ' ,$Text); + $Text = preg_replace("/\[table border=(.*?)\](.*?)\[\/table\]/s", '$2' ,$Text); // $Text = preg_replace("/\[table border=0\](.*?)\[\/table\]/s", '$1
    ' ,$Text); - + // $Text = str_replace("[*]", "
  • ", $Text); // Check for font change text // $Text = preg_replace("(\[font=(.*?)\](.*?)\[\/font\])","$2",$Text); - $Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/is",'stripdcode_br_cb',$Text); + $Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/is",'stripdcode_br_cb',$Text); // Check for [code] text $Text = preg_replace("/(\[code\])+(.*?)(\[\/code\])+/is","\t$2\n", $Text); @@ -174,10 +311,11 @@ function bb2diaspora($Text,$preserve_nl = false) { // Declare the format for [quote] layout - // $QuoteLayout = '
    $1
    '; + // $QuoteLayout = '
    $1
    '; // Check for [quote] text $Text = preg_replace("/\[quote\](.*?)\[\/quote\]/is",">$1\n\n", $Text); - + $Text = preg_replace("/\[quote=(.*?)\](.*?)\[\/quote\]/is",">$2\n\n", $Text); + // Images // html5 video and audio @@ -187,13 +325,13 @@ function bb2diaspora($Text,$preserve_nl = false) { $Text = preg_replace("/\[audio\](.*?)\[\/audio\]/", '$1', $Text); // $Text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/", '', $Text); - + // [img=widthxheight]image source[/img] // $Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/", '', $Text); - $Text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/youtube\]/ism",'http://www.youtube.com/watch?v=$1',$Text); - $Text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/embed\/(.*?)\[\/youtube\]/ism",'http://www.youtube.com/watch?v=$1',$Text); - $Text = preg_replace("/\[youtube\]https?:\/\/youtu.be\/(.*?)\[\/youtube\]/ism",'http://www.youtube.com/watch?v=$1',$Text); + $Text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/youtube\]/ism",'http://www.youtube.com/watch?v=$1',$Text); + $Text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/embed\/(.*?)\[\/youtube\]/ism",'http://www.youtube.com/watch?v=$1',$Text); + $Text = preg_replace("/\[youtube\]https?:\/\/youtu.be\/(.*?)\[\/youtube\]/ism",'http://www.youtube.com/watch?v=$1',$Text); $Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", 'http://www.youtube.com/watch?v=$1', $Text); $Text = preg_replace("/\[vimeo\]https?:\/\/player.vimeo.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism",'http://vimeo.com/$1',$Text); @@ -211,9 +349,10 @@ function bb2diaspora($Text,$preserve_nl = false) { if(x($ev,'desc') && x($ev,'start')) { $sub = format_event_diaspora($ev); - - $Text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/is",$sub,$Text); - $Text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/is",'',$Text); + + $Text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/is",'',$Text); + $Text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/is",'',$Text); + $Text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/is",$sub,$Text); $Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/is",'',$Text); $Text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/is",'',$Text); $Text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/is",'',$Text); @@ -222,7 +361,12 @@ function bb2diaspora($Text,$preserve_nl = false) { $Text = preg_replace("/\<(.*?)(src|href)=(.*?)\&\;(.*?)\>/ism",'<$1$2=$3&$4>',$Text); $Text = preg_replace_callback('/\[(.*?)\]\((.*?)\)/ism','unescape_underscores_in_links',$Text); - + + + // Remove any leading or trailing whitespace, as this will mess up + // the Diaspora signature verification and cause the item to disappear + $Text = trim($Text); + call_hooks('bb2diaspora',$Text); return $Text; @@ -244,7 +388,7 @@ function format_event_diaspora($ev) { $o = 'Friendica event notification:' . "\n"; - $o .= '**' . bb2diaspora($ev['desc']) . '**' . "\n"; + $o .= '**' . (($ev['summary']) ? bb2diaspora($ev['summary']) : bb2diaspora($ev['desc'])) . '**' . "\n"; $o .= t('Starts:') . ' ' . '[' . (($ev['adjust']) ? day_translate(datetime_convert('UTC', 'UTC', diff --git a/include/bbcode.php b/include/bbcode.php index efc362880f..55a8794976 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -50,7 +50,7 @@ function bb_unspacefy_and_trim($st) { // BBcode 2 HTML was written by WAY2WEB.net // extended to work with Mistpark/Friendica - Mike Macgirvin -function bbcode($Text,$preserve_nl = false) { +function bbcode($Text,$preserve_nl = false, $tryoembed = true) { $a = get_app(); @@ -93,11 +93,19 @@ function bbcode($Text,$preserve_nl = false) { // Convert new line chars to html
    tags - $Text = nl2br($Text); + // nlbr seems to be hopelessly messed up + // $Text = nl2br($Text); + + // We'll emulate it. + + $Text = str_replace("\r\n","\n", $Text); + $Text = str_replace(array("\r","\n"), array('
    ','
    '), $Text); + if($preserve_nl) $Text = str_replace(array("\n","\r"), array('',''),$Text); + // Set up the parameters for a URL search string $URLSearchString = "^\[\]"; // Set up the parameters for a MAIL search string @@ -108,10 +116,14 @@ function bbcode($Text,$preserve_nl = false) { $Text = preg_replace("/([^\]\=]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1$2', $Text); - $Text = preg_replace_callback("/\[bookmark\=([^\]]*)\].*?\[\/bookmark\]/ism",'tryoembed',$Text); + if ($tryoembed) + $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); + if ($tryoembed) + $Text = preg_replace_callback("/\[url\]([$URLSearchString]*)\[\/url\]/ism",'tryoembed',$Text); + $Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '$1', $Text); $Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$2', $Text); //$Text = preg_replace("/\[url\=([$URLSearchString]*)\]([$URLSearchString]*)\[\/url\]/ism", '$2', $Text); @@ -154,11 +166,14 @@ function bbcode($Text,$preserve_nl = false) { // Check for list text $Text = str_replace("[*]", "
  • ", $Text); - $Text = preg_replace("/\[li\](.*?)\[\/li\]/ism", '
  • $1
  • ' ,$Text); // handle nested lists $endlessloop = 0; - while ((strpos($Text, "[/list]") !== false) and (strpos($Text, "[list") !== false) and (++$endlessloop < 20)) { + + while ((((strpos($Text, "[/list]") !== false) && (strpos($Text, "[list") !== false)) || + ((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) || + ((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false)) || + ((strpos($Text, "[/li]") !== false) && (strpos($Text, "[li]") !== false))) && (++$endlessloop < 20)) { $Text = preg_replace("/\[list\](.*?)\[\/list\]/ism", '' ,$Text); $Text = preg_replace("/\[list=\](.*?)\[\/list\]/ism", '' ,$Text); $Text = preg_replace("/\[list=1\](.*?)\[\/list\]/ism", '' ,$Text); @@ -166,11 +181,11 @@ function bbcode($Text,$preserve_nl = false) { $Text = preg_replace("/\[list=((?-i)I)\](.*?)\[\/list\]/ism", '' ,$Text); $Text = preg_replace("/\[list=((?-i)a)\](.*?)\[\/list\]/ism", '' ,$Text); $Text = preg_replace("/\[list=((?-i)A)\](.*?)\[\/list\]/ism", '' ,$Text); + $Text = preg_replace("/\[ul\](.*?)\[\/ul\]/ism", '' ,$Text); + $Text = preg_replace("/\[ol\](.*?)\[\/ol\]/ism", '' ,$Text); + $Text = preg_replace("/\[li\](.*?)\[\/li\]/ism", '
  • $1
  • ' ,$Text); } - $Text = preg_replace("/\[ul\](.*?)\[\/ul\]/ism", '' ,$Text); - $Text = preg_replace("/\[ol\](.*?)\[\/ol\]/ism", '' ,$Text); - $Text = preg_replace("/\[th\](.*?)\[\/th\]/sm", '$1' ,$Text); $Text = preg_replace("/\[td\](.*?)\[\/td\]/sm", '$1' ,$Text); $Text = preg_replace("/\[tr\](.*?)\[\/tr\]/sm", '$1' ,$Text); @@ -190,7 +205,7 @@ function bbcode($Text,$preserve_nl = false) { // Declare the format for [code] layout - $Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/ism",'stripcode_br_cb',$Text); +// $Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/ism",'stripcode_br_cb',$Text); $CodeLayout = '$1'; // Check for [code] text @@ -250,31 +265,35 @@ function bbcode($Text,$preserve_nl = false) { $Text = preg_replace("/\[audio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3))\[\/audio\]/ism", '', $Text); // Try to Oembed - $Text = preg_replace_callback("/\[video\](.*?)\[\/video\]/ism", 'tryoembed', $Text); - $Text = preg_replace_callback("/\[audio\](.*?)\[\/audio\]/ism", 'tryoembed', $Text); - + if ($tryoembed) { + $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("/\[iframe\](.*?)\[\/iframe\]/ism", '', $Text); - + // Youtube extensions - $Text = preg_replace_callback("/\[youtube\](https?:\/\/www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", 'tryoembed', $Text); - $Text = preg_replace_callback("/\[youtube\](www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", 'tryoembed', $Text); - $Text = preg_replace_callback("/\[youtube\](https?:\/\/youtu.be\/.*?)\[\/youtube\]/ism",'tryoembed',$Text); - + if ($tryoembed) { + $Text = preg_replace_callback("/\[youtube\](https?:\/\/www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", 'tryoembed', $Text); + $Text = preg_replace_callback("/\[youtube\](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\]https?:\/\/youtu.be\/(.*?)\[\/youtube\]/ism",'[youtube]$1[/youtube]',$Text); + $Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '', $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); + if ($tryoembed) { + $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); @@ -287,12 +306,16 @@ function bbcode($Text,$preserve_nl = false) { $Text = oembed_bbcode2html($Text); // If we found an event earlier, strip out all the event code and replace with a reformatted version. + // Replace the event-start section with the entire formatted event. The other bbcode is stripped. + // Summary (e.g. title) is required, earlier revisions only required description (in addition to + // start which is always required). Allow desc with a missing summary for compatibility. - if(x($ev,'desc') && x($ev,'start')) { + if((x($ev,'desc') || x($ev,'summary')) && x($ev,'start')) { $sub = format_event_html($ev); - $Text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism",$sub,$Text); - $Text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/ism",'',$Text); + $Text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism",'',$Text); + $Text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism",'',$Text); + $Text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/ism",$sub,$Text); $Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism",'',$Text); $Text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism",'',$Text); $Text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/ism",'',$Text); diff --git a/include/conversation.php b/include/conversation.php index 2244e8df7f..bbb6a1f85b 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -432,7 +432,7 @@ function conversation(&$a, $items, $mode, $update, $preview = false) { continue; $toplevelpost = (($item['id'] == $item['parent']) ? true : false); - $toplevelprivate = false; + // Take care of author collapsing and comment collapsing // (author collapsing is currently disabled) @@ -440,7 +440,7 @@ function conversation(&$a, $items, $mode, $update, $preview = false) { // If there are more than two comments, squash all but the last 2. if($toplevelpost) { - $toplevelprivate = (($toplevelpost && $item['private']) ? true : false); + $item_writeable = (($item['writable'] || $item['self']) ? true : false); $comments_seen = 0; @@ -485,7 +485,7 @@ function conversation(&$a, $items, $mode, $update, $preview = false) { $redirect_url = $a->get_baseurl($ssl_state) . '/redir/' . $item['cid'] ; - $lock = ((($item['private']) || (($item['uid'] == local_user()) && (strlen($item['allow_cid']) || strlen($item['allow_gid']) + $lock = ((($item['private'] == 1) || (($item['uid'] == local_user()) && (strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])))) ? t('Private Message') : false); @@ -546,16 +546,16 @@ function conversation(&$a, $items, $mode, $update, $preview = false) { } $likebuttons = ''; - $shareable = ((($profile_owner == local_user()) && ((! $item['private']) || $item['network'] === NETWORK_FEED)) ? true : false); + $shareable = ((($profile_owner == local_user()) && ($item['private'] != 1)) ? true : false); if($page_writeable) { - if($toplevelpost) { +/* if($toplevelpost) { */ $likebuttons = array( 'like' => array( t("I like this \x28toggle\x29"), t("like")), 'dislike' => array( t("I don't like this \x28toggle\x29"), t("dislike")), ); if ($shareable) $likebuttons['share'] = array( t('Share this'), t('share')); - } +/* } */ $qc = $qcomment = null; @@ -659,8 +659,8 @@ function conversation(&$a, $items, $mode, $update, $preview = false) { else $profile_avatar = (((strlen($item['author-avatar'])) && $diff_author) ? $item['author-avatar'] : $a->get_cached_avatar_image($thumb)); - $like = ((x($alike,$item['id'])) ? format_like($alike[$item['id']],$alike[$item['id'] . '-l'],'like',$item['id']) : ''); - $dislike = ((x($dlike,$item['id'])) ? format_like($dlike[$item['id']],$dlike[$item['id'] . '-l'],'dislike',$item['id']) : ''); + $like = ((x($alike,$item['uri'])) ? format_like($alike[$item['uri']],$alike[$item['uri'] . '-l'],'like',$item['uri']) : ''); + $dislike = ((x($dlike,$item['uri'])) ? format_like($dlike[$item['uri']],$dlike[$item['uri'] . '-l'],'dislike',$item['uri']) : ''); $locate = array('location' => $item['location'], 'coord' => $item['coord'], 'html' => ''); call_hooks('render_location',$locate); @@ -876,13 +876,17 @@ function like_puller($a,$item,&$arr,$mode) { } else $url = zrl($url); - if(! ((isset($arr[$item['parent'] . '-l'])) && (is_array($arr[$item['parent'] . '-l'])))) - $arr[$item['parent'] . '-l'] = array(); - if(! isset($arr[$item['parent']])) - $arr[$item['parent']] = 1; + + if(! $item['thr-parent']) + $item['thr-parent'] = $item['parent-uri']; + + if(! ((isset($arr[$item['thr-parent'] . '-l'])) && (is_array($arr[$item['thr-parent'] . '-l'])))) + $arr[$item['thr-parent'] . '-l'] = array(); + if(! isset($arr[$item['thr-parent']])) + $arr[$item['thr-parent']] = 1; else - $arr[$item['parent']] ++; - $arr[$item['parent'] . '-l'][] = '' . $item['author-name'] . ''; + $arr[$item['thr-parent']] ++; + $arr[$item['thr-parent'] . '-l'][] = '' . $item['author-name'] . ''; } return; }} diff --git a/include/crypto.php b/include/crypto.php index 6fc9a287e4..ed0a35704e 100644 --- a/include/crypto.php +++ b/include/crypto.php @@ -261,39 +261,6 @@ function aes_unencapsulate($data,$prvkey) { return AES256CBC_decrypt(base64url_decode($data['data']),$k,$i); } - -// This has been superceded. - -function zot_encapsulate($data,$envelope,$pubkey) { -$res = aes_encapsulate($data,$pubkey); - -return <<< EOT - - - {$res['key']} - {$res['iv']} - $s1 - $sig - AES-256-CBC - {$res['data']} - -EOT; - -} - -// so has this - -function zot_unencapsulate($data,$prvkey) { - $ret = array(); - $c = array(); - $x = parse_xml_string($data); - $c = array('key' => $x->key,'iv' => $x->iv,'data' => $x->data); - openssl_private_decrypt(base64url_decode($x->sender),$s,$prvkey); - $ret['sender'] = $s; - $ret['data'] = aes_unencapsulate($x,$prvkey); - return $ret; -} - function new_keypair($bits) { $openssl_options = array( diff --git a/include/datetime.php b/include/datetime.php index 58a6186108..75ae685f3a 100644 --- a/include/datetime.php +++ b/include/datetime.php @@ -447,11 +447,13 @@ function update_contact_birthdays() { * */ - $bdtext = t('Birthday:') . ' [url=' . $rr['url'] . ']' . $rr['name'] . '[/url]' ; + $bdtext = sprintf( t('%s\'s birthday'), $rr['name']); + $bdtext2 = sprintf( t('Happy Birthday %s'), ' [url=' . $rr['url'] . ']' . $rr['name'] . '[/url]') ; - $r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`desc`,`type`,`adjust`) - VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%d' ) ", + + $r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`,`adjust`) + VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d' ) ", intval($rr['uid']), intval($rr['id']), dbesc(datetime_convert()), @@ -459,6 +461,7 @@ function update_contact_birthdays() { dbesc(datetime_convert('UTC','UTC', $nextbd)), dbesc(datetime_convert('UTC','UTC', $nextbd . ' + 1 day ')), dbesc($bdtext), + dbesc($bdtext2), dbesc('birthday'), intval(0) ); diff --git a/include/dba.php b/include/dba.php index 881097f30c..71c1ba8591 100644 --- a/include/dba.php +++ b/include/dba.php @@ -275,3 +275,9 @@ function dbesc_array(&$arr) { array_walk($arr,'dbesc_array_cb'); } }} + + +function dba_timer() { + return microtime(true); +} + diff --git a/include/delivery.php b/include/delivery.php index e6cfc81554..1328771a67 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -113,7 +113,7 @@ function delivery_run($argv, $argc){ $uid = $r[0]['uid']; $updated = $r[0]['edited']; - // The following seems superfluous. We've already checked for "if (! intval($r[0]['parent']))" a few lines up + // POSSIBLE CLEANUP --> The following seems superfluous. We've already checked for "if (! intval($r[0]['parent']))" a few lines up if(! $parent_id) continue; @@ -280,7 +280,7 @@ function delivery_run($argv, $argc){ continue; // private emails may be in included in public conversations. Filter them. - if(($public_message) && $item['private']) + if(($public_message) && $item['private'] == 1) continue; $item_contact = get_item_contact($item,$icontacts); @@ -383,7 +383,7 @@ function delivery_run($argv, $argc){ continue; // private emails may be in included in public conversations. Filter them. - if(($public_message) && $item['private']) + if(($public_message) && $item['private'] == 1) continue; $item_contact = get_item_contact($item,$icontacts); diff --git a/include/diaspora.php b/include/diaspora.php index 0ca9163a85..7551ea9b3a 100755 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -5,6 +5,7 @@ require_once('include/items.php'); require_once('include/bb2diaspora.php'); require_once('include/contact_selectors.php'); require_once('include/queue_fn.php'); +require_once('include/lock.php'); function diaspora_dispatch_public($msg) { @@ -113,27 +114,93 @@ function diaspora_get_contact_by_handle($uid,$handle) { } function find_diaspora_person_by_handle($handle) { + + $person = false; $update = false; - $r = q("select * from fcontact where network = '%s' and addr = '%s' limit 1", - dbesc(NETWORK_DIASPORA), - 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)) { - add_fcontact($r,$update); - return ($r); - } - return false; + $got_lock = false; + + $endlessloop = 0; + $maxloops = 10; + + do { + $r = q("select * from fcontact where network = '%s' and addr = '%s' limit 1", + dbesc(NETWORK_DIASPORA), + dbesc($handle) + ); + if(count($r)) { + $person = $r[0]; + 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($person['updated'] . ' +00:00'); + if($d < strtotime('now - 14 days')) + $update = true; + } + + + // FETCHING PERSON INFORMATION FROM REMOTE SERVER + // + // If the person isn't in our 'fcontact' table, or if he/she is but + // his/her information hasn't been updated for more than 14 days, then + // we want to fetch the person's information from the remote server. + // + // Note that $person isn't changed by this block of code unless the + // person's information has been successfully fetched from the remote + // server. So if $person was 'false' to begin with (because he/she wasn't + // in the local cache), it'll stay false, and if $person held the local + // cache information to begin with, it'll keep that information. That way + // if there's a problem with the remote fetch, we can at least use our + // cached information--it's better than nothing. + + if((! $person) || ($update)) { + // Lock the function to prevent race conditions if multiple items + // come in at the same time from a person who doesn't exist in + // fcontact + // + // Don't loop forever. On the last loop, try to create the contact + // whether the function is locked or not. Maybe the locking thread + // has died or something. At any rate, a duplicate in 'fcontact' + // is a much smaller problem than a deadlocked thread + $got_lock = lock_function('find_diaspora_person_by_handle', false); + if(($endlessloop + 1) >= $maxloops) + $got_lock = true; + + if($got_lock) { + logger('find_diaspora_person_by_handle: create or refresh', LOGGER_DEBUG); + require_once('include/Scrape.php'); + $r = probe_url($handle, PROBE_DIASPORA); + + // Note that Friendica contacts can return a "Diaspora person" + // if Diaspora connectivity is enabled on their server + if((count($r)) && ($r['network'] === NETWORK_DIASPORA)) { + add_fcontact($r,$update); + $person = ($r); + } + + unlock_function('find_diaspora_person_by_handle'); + } + else { + logger('find_diaspora_person_by_handle: couldn\'t lock function', LOGGER_DEBUG); + if(! $person) + block_on_function_lock('find_diaspora_person_by_handle'); + } + } + } while((! $person) && (! $got_lock) && (++$endlessloop < $maxloops)); + // We need to try again if the person wasn't in 'fcontact' but the function was locked. + // The fact that the function was locked may mean that another process was creating the + // person's record. It could also mean another process was creating or updating an unrelated + // person. + // + // At any rate, we need to keep trying until we've either got the person or had a chance to + // try to fetch his/her remote information. But we don't want to block on locking the + // function, because if the other process is creating the record, then when we acquire the lock + // we'll dive right into creating another, duplicate record. We DO want to at least wait + // until the lock is released, so we don't flood the database with requests. + // + // If the person was in the 'fcontact' table, don't try again. It's not worth the time, since + // we do have some information for the person + + return $person; } @@ -844,7 +911,7 @@ function diaspora_reshare($importer,$xml) { else $details = $orig_author; - $prefix = '♲ ' . $details . "\n"; + $prefix = html_entity_decode("♲ ", ENT_QUOTES, 'UTF-8') . $details . "\n"; // allocate a guid on our system - we aren't fixing any collisions. @@ -1560,7 +1627,8 @@ function diaspora_photo($importer,$xml,$msg) { $link_text = '[img]' . $remote_photo_path . $remote_photo_name . '[/img]' . "\n"; - $link_text = scale_external_images($link_text); + $link_text = scale_external_images($link_text, true, + array($remote_photo_name, 'scaled_full_' . $remote_photo_name)); 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", @@ -2005,6 +2073,7 @@ function diaspora_share($me,$contact) { )); $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$me,$contact,$me['prvkey'],$contact['pubkey']))); + //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$me,$contact,$me['prvkey'],$contact['pubkey'])); return(diaspora_transmit($owner,$contact,$slap, false)); } @@ -2022,6 +2091,7 @@ function diaspora_unshare($me,$contact) { )); $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$me,$contact,$me['prvkey'],$contact['pubkey']))); + //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$me,$contact,$me['prvkey'],$contact['pubkey'])); return(diaspora_transmit($owner,$contact,$slap, false)); @@ -2060,13 +2130,21 @@ function diaspora_send_status($item,$owner,$contact,$public_batch = false) { $images[] = $detail; $body = str_replace($detail['str'],$mtch[1],$body); } - } + } */ + // Removal of tags + $body = preg_replace('/#\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '#$2', $body); + + //if(strlen($title)) + // $body = "[b]".html_entity_decode($title)."[/b]\n\n".$body; + + // convert to markdown $body = xmlify(html_entity_decode(bb2diaspora($body))); + //$body = bb2diaspora($body); + // Adding the title if(strlen($title)) - $body = xmlify('**' . html_entity_decode($title) . '**' . "\n") . $body; - + $body = "## ".html_entity_decode($title)."\n\n".$body; if($item['attach']) { $cnt = preg_match_all('/href=\"(.*?)\"(.*?)title=\"(.*?)\"/ism',$item['attach'],$matches,PREG_SET_ORDER); @@ -2096,6 +2174,7 @@ function diaspora_send_status($item,$owner,$contact,$public_batch = false) { logger('diaspora_send_status: ' . $owner['username'] . ' -> ' . $contact['name'] . ' base message: ' . $msg, LOGGER_DATA); $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch))); + //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch)); $return_code = diaspora_transmit($owner,$contact,$slap,$public_batch); @@ -2140,6 +2219,7 @@ function diaspora_send_images($item,$owner,$contact,$images,$public_batch = fals logger('diaspora_send_photo: base message: ' . $msg, LOGGER_DATA); $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch))); + //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch)); diaspora_transmit($owner,$contact,$slap,$public_batch); } @@ -2203,6 +2283,7 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) { logger('diaspora_followup: base message: ' . $msg, LOGGER_DATA); $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch))); + //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch)); return(diaspora_transmit($owner,$contact,$slap,$public_batch)); } @@ -2238,7 +2319,6 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { $relay_retract = true; $target_type = ( ($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment'); - $sender_signed_text = $item['guid'] . ';' . $target_type ; $sql_sign_id = 'retract_iid'; $tpl = get_markup_template('diaspora_relayable_retraction.tpl'); @@ -2249,13 +2329,10 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { $target_type = 'Post'; // $positive = (($item['deleted']) ? 'false' : 'true'); $positive = 'true'; - $sender_signed_text = $item['guid'] . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $myaddr; $tpl = get_markup_template('diaspora_like_relay.tpl'); } else { // item is a comment - $sender_signed_text = $item['guid'] . ';' . $parent_guid . ';' . $text . ';' . $myaddr; - $tpl = get_markup_template('diaspora_comment_relay.tpl'); } @@ -2281,6 +2358,13 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { return; } + if($relay_retract) + $sender_signed_text = $item['guid'] . ';' . $target_type; + elseif($like) + $sender_signed_text = $item['guid'] . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $handle; + else + $sender_signed_text = $item['guid'] . ';' . $parent_guid . ';' . $text . ';' . $handle; + // Sign the relayable with the top-level owner's signature // // We'll use the $sender_signed_text that we just created, instead of the $signed_text @@ -2309,6 +2393,7 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch))); + //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch)); return(diaspora_transmit($owner,$contact,$slap,$public_batch)); @@ -2343,6 +2428,7 @@ function diaspora_send_retraction($item,$owner,$contact,$public_batch = false) { )); $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch))); + //$slap = 'xml=' . urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],$public_batch)); return(diaspora_transmit($owner,$contact,$slap,$public_batch)); } @@ -2403,6 +2489,7 @@ function diaspora_send_mail($item,$owner,$contact) { logger('diaspora_conversation: ' . print_r($xmsg,true), LOGGER_DATA); $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($xmsg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],false))); + //$slap = 'xml=' . urlencode(diaspora_msg_build($xmsg,$owner,$contact,$owner['uprvkey'],$contact['pubkey'],false)); return(diaspora_transmit($owner,$contact,$slap,false)); diff --git a/include/enotify.php b/include/enotify.php index 134e42f8e3..5e073bf3ca 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -54,6 +54,20 @@ function notification($params) { $parent_id = $params['parent']; + // Check to see if there was already a tag notify for this post. + // If so don't create a second notification + + $p = null; + $p = q("select id from notify where type = %d and link = '%s' and uid = %d limit 1", + intval(NOTIFY_TAGSELF), + dbesc($params['link']), + intval($params['uid']) + ); + if($p and count($p)) { + pop_lang(); + return; + } + // if it's a post figure out who's post it is. diff --git a/include/event.php b/include/event.php index 866ae8c3f0..8aef0a2636 100644 --- a/include/event.php +++ b/include/event.php @@ -12,6 +12,9 @@ function format_event_html($ev) { $o = '
    ' . "\r\n"; + + $o .= '

    ' . bbcode($ev['summary']) . '

    ' . "\r\n"; + $o .= '

    ' . bbcode($ev['desc']) . '

    ' . "\r\n"; $o .= '

    ' . t('Starts:') . ' nodeValue = str_replace("\n", "\r", $node->nodeValue); $message = $doc->saveHTML(); - $message = str_replace(array("\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"), array("<", ">", "
    ", " ", ""), $message); + $message = str_replace(array("\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"), array("<", ">", "
    ", " ", ""), $message); $message = preg_replace('= [\s]*=i', " ", $message); @$doc->loadHTML($message); diff --git a/include/items.php b/include/items.php index a0dd1c8159..cf903ac139 100755 --- a/include/items.php +++ b/include/items.php @@ -466,8 +466,8 @@ function get_atom_elements($feed,$item) { $res['last-child'] = 0; $private = $item->get_item_tags(NAMESPACE_DFRN,'private'); - if($private && $private[0]['data'] == 1) - $res['private'] = 1; + if($private && intval($private[0]['data']) > 0) + $res['private'] = intval($private[0]['data']); else $res['private'] = 0; @@ -814,7 +814,7 @@ function item_store($arr,$force_parent = false) { // email correspondents to be private even if the overall thread is not. if($r[0]['private']) - $arr['private'] = 1; + $arr['private'] = $r[0]['private']; // Edge case. We host a public forum that was originally posted to privately. // The original author commented, but as this is a comment, the permissions @@ -1457,11 +1457,12 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) * */ - $bdtext = t('Birthday:') . ' [url=' . $contact['url'] . ']' . $contact['name'] . '[/url]' ; + $bdtext = sprintf( t('%s\'s birthday'), $contact['name']); + $bdtext2 = sprintf( t('Happy Birthday %s'), ' [url=' . $contact['url'] . ']' . $contact['name'] . '[/url]' ) ; - $r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`desc`,`type`) - VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s' ) ", + $r = q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`) + VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($contact['uid']), intval($contact['id']), dbesc(datetime_convert()), @@ -1469,6 +1470,7 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) dbesc(datetime_convert('UTC','UTC', $birthday)), dbesc(datetime_convert('UTC','UTC', $birthday . ' + 1 day ')), dbesc($bdtext), + dbesc($bdtext2), dbesc('birthday') ); @@ -1658,6 +1660,21 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) continue; } + $force_parent = false; + if($contact['network'] === NETWORK_OSTATUS || stristr($contact['url'],'twitter.com')) { + if($contact['network'] === NETWORK_OSTATUS) + $force_parent = true; + if(strlen($datarray['title'])) + unset($datarray['title']); + $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", + dbesc(datetime_convert()), + dbesc($parent_uri), + intval($importer['uid']) + ); + $datarray['last-child'] = 1; + } + + $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['uid']) @@ -1701,19 +1718,6 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) continue; } - $force_parent = false; - if($contact['network'] === NETWORK_OSTATUS || stristr($contact['url'],'twitter.com')) { - if($contact['network'] === NETWORK_OSTATUS) - $force_parent = true; - if(strlen($datarray['title'])) - unset($datarray['title']); - $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", - dbesc(datetime_convert()), - dbesc($parent_uri), - intval($importer['uid']) - ); - $datarray['last-child'] = 1; - } if(($contact['network'] === NETWORK_FEED) || (! strlen($contact['notify']))) { // one way feed - no remote comment ability @@ -1726,10 +1730,12 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) $datarray['type'] = 'activity'; $datarray['gravity'] = GRAVITY_LIKE; // only one like or dislike per person - $r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 limit 1", + $r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 and (`parent-uri` = '%s' OR `thr-parent` = '%s') limit 1", intval($datarray['uid']), intval($datarray['contact-id']), - dbesc($datarray['verb']) + dbesc($datarray['verb']), + dbesc($parent_uri), + dbesc($parent_uri) ); if($r && count($r)) continue; @@ -1809,6 +1815,13 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) } } + if($contact['network'] === NETWORK_OSTATUS || stristr($contact['url'],'twitter.com')) { + if(strlen($datarray['title'])) + unset($datarray['title']); + $datarray['last-child'] = 1; + } + + $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['uid']) @@ -1871,24 +1884,23 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) if(! is_array($contact)) return; - if($contact['network'] === NETWORK_OSTATUS || stristr($contact['url'],'twitter.com')) { - if(strlen($datarray['title'])) - unset($datarray['title']); - $datarray['last-child'] = 1; - } if(($contact['network'] === NETWORK_FEED) || (! strlen($contact['notify']))) { // one way feed - no remote comment ability $datarray['last-child'] = 0; } if($contact['network'] === NETWORK_FEED) - $datarray['private'] = 1; + $datarray['private'] = 2; // This is my contact on another system, but it's really me. // Turn this into a wall post. - if($contact['remote_self']) + if($contact['remote_self']) { $datarray['wall'] = 1; + if($contact['network'] === NETWORK_FEED) { + $datarray['private'] = 0; + } + } $datarray['parent-uri'] = $item_id; $datarray['uid'] = $importer['uid']; @@ -2146,6 +2158,67 @@ function local_delivery($importer,$data) { } if($deleted) { + // check for relayed deletes to our conversation + + $is_reply = false; + $r = q("select * from item where uri = '%s' and uid = %d limit 1", + dbesc($uri), + intval($importer['importer_uid']) + ); + if(count($r)) { + $parent_uri = $r[0]['parent-uri']; + if($r[0]['id'] != $r[0]['parent']) + $is_reply = true; + } + + if($is_reply) { + $community = false; + + if($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP ) { + $sql_extra = ''; + $community = true; + logger('local_delivery: possible community delete'); + } + else + $sql_extra = " and contact.self = 1 and item.wall = 1 "; + + // was the top-level post for this reply written by somebody on this site? + // Specifically, the recipient? + + $is_a_remote_delete = false; + + $r = q("select `item`.`id`, `item`.`uri`, `item`.`tag`, `item`.`forum_mode`,`item`.`origin`,`item`.`wall`, + `contact`.`name`, `contact`.`url`, `contact`.`thumb` from `item` + LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` + WHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' or `item`.`thr-parent` = '%s') + AND `item`.`uid` = %d + $sql_extra + LIMIT 1", + dbesc($parent_uri), + dbesc($parent_uri), + dbesc($parent_uri), + intval($importer['importer_uid']) + ); + if($r && count($r)) + $is_a_remote_delete = true; + + // Does this have the characteristics of a community or private group comment? + // If it's a reply to a wall post on a community/prvgroup page it's a + // valid community comment. Also forum_mode makes it valid for sure. + // If neither, it's not. + + if($is_a_remote_delete && $community) { + if((! $r[0]['forum_mode']) && (! $r[0]['wall'])) { + $is_a_remote_delete = false; + logger('local_delivery: not a community delete'); + } + } + + if($is_a_remote_delete) { + logger('local_delivery: received remote delete'); + } + } + $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 AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", dbesc($uri), @@ -2198,7 +2271,8 @@ function local_delivery($importer,$data) { } if($item['uri'] == $item['parent-uri']) { - $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' + $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', + `body` = '', `title` = '' WHERE `parent-uri` = '%s' AND `uid` = %d", dbesc($when), dbesc(datetime_convert()), @@ -2207,7 +2281,8 @@ function local_delivery($importer,$data) { ); } else { - $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' + $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', + `body` = '', `title` = '' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($when), dbesc(datetime_convert()), @@ -2233,7 +2308,11 @@ function local_delivery($importer,$data) { ); } } - } + // if this is a relayed delete, propagate it to other recipients + + if($is_a_remote_delete) + proc_run('php',"include/notifier.php","drop",$item['id']); + } } } } @@ -2266,15 +2345,17 @@ function local_delivery($importer,$data) { $is_a_remote_comment = false; + // POSSIBLE CLEANUP --> Why select so many fields when only forum_mode and wall are used? $r = q("select `item`.`id`, `item`.`uri`, `item`.`tag`, `item`.`forum_mode`,`item`.`origin`,`item`.`wall`, `contact`.`name`, `contact`.`url`, `contact`.`thumb` from `item` LEFT JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - WHERE `item`.`uri` = '%s' AND `item`.`parent-uri` = '%s' + WHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' or `item`.`thr-parent` = '%s') AND `item`.`uid` = %d $sql_extra LIMIT 1", dbesc($parent_uri), dbesc($parent_uri), + dbesc($parent_uri), intval($importer['importer_uid']) ); if($r && count($r)) @@ -2362,10 +2443,13 @@ function local_delivery($importer,$data) { $datarray['gravity'] = GRAVITY_LIKE; $datarray['last-child'] = 0; // only one like or dislike per person - $r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 limit 1", + $r = q("select id from item where uid = %d and `contact-id` = %d and verb = '%s' and (`thr-parent` = '%s' or `parent-uri` = '%s') and deleted = 0 limit 1", intval($datarray['uid']), intval($datarray['contact-id']), - dbesc($datarray['verb']) + dbesc($datarray['verb']), + dbesc($datarray['parent-uri']), + dbesc($datarray['parent-uri']) + ); if($r && count($r)) continue; @@ -2533,10 +2617,12 @@ function local_delivery($importer,$data) { $datarray['type'] = 'activity'; $datarray['gravity'] = GRAVITY_LIKE; // only one like or dislike per person - $r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 limit 1", + $r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 and (`parent-uri` = '%s' OR `thr-parent` = '%s') limit 1", intval($datarray['uid']), intval($datarray['contact-id']), - dbesc($datarray['verb']) + dbesc($datarray['verb']), + dbesc($parent_uri), + dbesc($parent_uri) ); if($r && count($r)) continue; @@ -2931,8 +3017,10 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { if(strlen($item['owner-name'])) $o .= atom_author('dfrn:owner',$item['owner-name'],$item['owner-link'],80,80,$item['owner-avatar']); - if(($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri'])) - $o .= '' . "\r\n"; + if(($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri']) || ($item['thr-parent'])) { + $parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']); + $o .= '' . "\r\n"; + } $o .= '' . xmlify($item['uri']) . '' . "\r\n"; $o .= '' . xmlify($item['title']) . '' . "\r\n"; @@ -2953,7 +3041,7 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { $o .= '' . xmlify($item['coord']) . '' . "\r\n"; if(($item['private']) || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) - $o .= '1' . "\r\n"; + $o .= '' . (($item['private']) ? $item['private'] : 1) . '' . "\r\n"; if($item['extid']) $o .= '' . xmlify($item['extid']) . '' . "\r\n"; @@ -3349,40 +3437,8 @@ function drop_item($id,$interactive = true) { ); } - // Add a relayable_retraction signature for Diaspora. Note that we can't add a target_author_signature - // if the comment was deleted by a remote user. That should be ok, because if a remote user is deleting - // the comment, that means we're the home of the post, and Diaspora will only - // check the parent_author_signature of retractions that it doesn't have to relay further - // - // I don't think this function gets called for an "unlike," but I'll check anyway - $signed_text = $item['guid'] . ';' . ( ($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment'); - - if(local_user() == $item['uid']) { - - $handle = $a->user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); - $authorsig = base64_encode(rsa_sign($signed_text,$a->user['prvkey'],'sha256')); - } - else { - $r = q("SELECT `nick`, `url` FROM `contact` WHERE `id` = '%d' LIMIT 1", - $item['contact-id'] - ); - if(count($r)) { - // The below handle only works for NETWORK_DFRN. I think that's ok, because this function - // only handles DFRN deletes - $handle_baseurl_start = strpos($r['url'],'://') + 3; - $handle_baseurl_length = strpos($r['url'],'/profile') - $handle_baseurl_start; - $handle = $r['nick'] . '@' . substr($r['url'], $handle_baseurl_start, $handle_baseurl_length); - $authorsig = ''; - } - } - - if(isset($handle)) - q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", - intval($item['id']), - dbesc($signed_text), - dbesc($authorsig), - dbesc($handle) - ); + // Add a relayable_retraction signature for Diaspora. + store_diaspora_retract_sig($item, $a->user, $a->get_baseurl()); } $drop_id = intval($item['id']); @@ -3469,4 +3525,53 @@ function posted_date_widget($url,$uid,$wall) { '$dates' => $ret )); return $o; -} \ No newline at end of file +} + + +function store_diaspora_retract_sig($item, $user, $baseurl) { + // Note that we can't add a target_author_signature + // if the comment was deleted by a remote user. That should be ok, because if a remote user is deleting + // the comment, that means we're the home of the post, and Diaspora will only + // check the parent_author_signature of retractions that it doesn't have to relay further + // + // I don't think this function gets called for an "unlike," but I'll check anyway + + $enabled = intval(get_config('system','diaspora_enabled')); + if(! $enabled) { + logger('drop_item: diaspora support disabled, not storing retraction signature', LOGGER_DEBUG); + return; + } + + logger('drop_item: storing diaspora retraction signature'); + + $signed_text = $item['guid'] . ';' . ( ($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment'); + + if(local_user() == $item['uid']) { + + $handle = $user['nickname'] . '@' . substr($baseurl, strpos($baseurl,'://') + 3); + $authorsig = base64_encode(rsa_sign($signed_text,$user['prvkey'],'sha256')); + } + else { + $r = q("SELECT `nick`, `url` FROM `contact` WHERE `id` = '%d' LIMIT 1", + $item['contact-id'] + ); + if(count($r)) { + // The below handle only works for NETWORK_DFRN. I think that's ok, because this function + // only handles DFRN deletes + $handle_baseurl_start = strpos($r['url'],'://') + 3; + $handle_baseurl_length = strpos($r['url'],'/profile') - $handle_baseurl_start; + $handle = $r['nick'] . '@' . substr($r['url'], $handle_baseurl_start, $handle_baseurl_length); + $authorsig = ''; + } + } + + if(isset($handle)) + q("insert into sign (`retract_iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", + intval($item['id']), + dbesc($signed_text), + dbesc($authorsig), + dbesc($handle) + ); + + return; +} diff --git a/include/lock.php b/include/lock.php new file mode 100644 index 0000000000..5f1ca63231 --- /dev/null +++ b/include/lock.php @@ -0,0 +1,77 @@ + diff --git a/include/markdownify/LICENSE_LGPL.txt b/include/markdownify/LICENSE_LGPL.txt new file mode 100644 index 0000000000..5ab7695ab8 --- /dev/null +++ b/include/markdownify/LICENSE_LGPL.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/include/markdownify/TODO b/include/markdownify/TODO new file mode 100644 index 0000000000..06ec8508ba --- /dev/null +++ b/include/markdownify/TODO @@ -0,0 +1,29 @@ +Markdownify +=========== +* handle non-markdownifiable lists (i.e. `

    `) +* organize methods better (i.e. flushlinebreaks & setlinebreaks close to each other) +* take a look at function names etc. +* is the new (in rev. 93) lastclosedtag property needed? +* word wrapping (some work is done but it's still very buggy) + + +Markdownify Extra +================= + +* handle table alignment with KEEP_HTML=false +* handle tables without headings when KEEP_HTML=false is set +* handle Markdown inside non-markdownable tags + + +Implementation Thoughts +======================= +* non-markdownifiable lists and markdown inside non-markdownable tags as well as the current + table implementation could be rewritten by using a rollback mechanism. + + example: + + + + we come to `
    - -
    $item.dislike
    -
    + +
    $item.dislike
    +
    $item.comment
    diff --git a/view/theme/dispy/wallwall_item.tpl b/view/theme/dispy/wallwall_item.tpl index da5fa13b3e..84da598cd6 100644 --- a/view/theme/dispy/wallwall_item.tpl +++ b/view/theme/dispy/wallwall_item.tpl @@ -64,7 +64,7 @@ class="icon recycle wall-item-share-buttons" title="$item.vote.share.0" onclick {{ if $item.edpost }}
  • {{ endif }} - +
  • {{ if $item.drop.dropping }}{{ endif }} {{ if $item.drop.dropping }}{{ endif }} @@ -86,8 +86,8 @@ class="icon recycle wall-item-share-buttons" title="$item.vote.share.0" onclick
  • - -
    $item.dislike
    + +
    $item.dislike
    $item.comment diff --git a/view/theme/duepuntozero/style.css b/view/theme/duepuntozero/style.css index be755d4111..1be81d738e 100644 --- a/view/theme/duepuntozero/style.css +++ b/view/theme/duepuntozero/style.css @@ -560,7 +560,12 @@ input#dfrn-url { clear: both; margin-bottom: 30px; } - +.aprofile dt { + font-weight: bold; +} +#page-profile .title { + font-weight: bold; +} #profile-vcard-break { clear: both; } @@ -935,6 +940,10 @@ input#dfrn-url { background: #EEEEEE; } +.wall-item-like.comment, .wall-item-dislike.comment { + margin-left: 50px; +} + .wall-item-info { display: block; float: left; @@ -1640,6 +1649,9 @@ input#dfrn-url { display:block!important; } +#photos-usage-message { + margin-bottom: 15px; +} #acl-wrapper { @@ -2414,9 +2426,40 @@ aside input[type='text'] { font-size: 20px; } +#event-summary-text { + margin-top: 15px; +} + +#event-share-checkbox { + float: left; + margin-top: 10px; +} + +#event-share-text { + float: left; + margin-top: 10px; + margin-left: 5px; +} + +#event-share-break { + clear: both; + margin-bottom: 10px; +} + +#event-summary { + width: 400px; +} + .vevent { border: 1px solid #CCCCCC; } + +.vevent .event-summary { + margin-left: 10px; + margin-right: 10px; + font-weight: bold; +} + .vevent .event-description, .vevent .event-location { margin-left: 10px; margin-right: 10px; diff --git a/view/theme/facepark/screenshot.jpg b/view/theme/facepark/screenshot.jpg new file mode 100644 index 0000000000..37adcc54f3 Binary files /dev/null and b/view/theme/facepark/screenshot.jpg differ diff --git a/view/theme/quattro/Makefile b/view/theme/quattro/Makefile new file mode 100644 index 0000000000..5df58c821b --- /dev/null +++ b/view/theme/quattro/Makefile @@ -0,0 +1,5 @@ +all: + cd dark; make; cd .. + cd green; make; cd .. + + diff --git a/view/theme/quattro/dark/style.css b/view/theme/quattro/dark/style.css index 803a2c2f7b..35595c8bc5 100644 --- a/view/theme/quattro/dark/style.css +++ b/view/theme/quattro/dark/style.css @@ -10,10 +10,72 @@ overflow: hidden; text-indent: -9999px; padding: 1px; + min-width: 22px; + height: 22px; } .icon.text { text-indent: 0px; } +.icon.notify { + background-image: url("../../../images/icons/22/notify_off.png"); +} +.icon.gear { + background-image: url("../../../images/icons/22/gear.png"); +} +.icon.like { + background-image: url("icons/like.png"); +} +.icon.dislike { + background-image: url("icons/dislike.png"); +} +.icon.add { + background-image: url("../../../images/icons/22/add.png"); +} +.icon.delete { + background-image: url("../../../images/icons/22/delete.png"); +} +.icon.edit { + background-image: url("../../../images/icons/22/edit.png"); +} +.icon.star { + background-image: url("../../../images/icons/22/star.png"); +} +.icon.menu { + background-image: url("../../../images/icons/22/menu.png"); +} +.icon.link { + background-image: url("../../../images/icons/22/link.png"); +} +.icon.lock { + background-image: url("../../../images/icons/22/lock.png"); +} +.icon.unlock { + background-image: url("../../../images/icons/22/unlock.png"); +} +.icon.plugin { + background-image: url("../../../images/icons/22/plugin.png"); +} +.icon.type-unkn { + background-image: url("../../../images/icons/22/zip.png"); +} +.icon.type-audio { + background-image: url("../../../images/icons/22/audio.png"); +} +.icon.type-video { + background-image: url("../../../images/icons/22/video.png"); +} +.icon.type-image { + background-image: url("../../../images/icons/22/image.png"); +} +.icon.type-text { + background-image: url("../../../images/icons/22/text.png"); +} +.icon.language { + background-image: url("icons/language.png"); +} +.icon.text { + padding: 10px 0px 0px 25px; +} .icon.s10 { min-width: 10px; height: 10px; @@ -24,6 +86,12 @@ .icon.s10.gear { background-image: url("../../../images/icons/10/gear.png"); } +.icon.s10.like { + background-image: url("icons/like.png"); +} +.icon.s10.dislike { + background-image: url("icons/dislike.png"); +} .icon.s10.add { background-image: url("../../../images/icons/10/add.png"); } @@ -82,6 +150,12 @@ .icon.s16.gear { background-image: url("../../../images/icons/16/gear.png"); } +.icon.s16.like { + background-image: url("icons/like.png"); +} +.icon.s16.dislike { + background-image: url("icons/dislike.png"); +} .icon.s16.add { background-image: url("../../../images/icons/16/add.png"); } @@ -140,6 +214,12 @@ .icon.s22.gear { background-image: url("../../../images/icons/22/gear.png"); } +.icon.s22.like { + background-image: url("icons/like.png"); +} +.icon.s22.dislike { + background-image: url("icons/dislike.png"); +} .icon.s22.add { background-image: url("../../../images/icons/22/add.png"); } @@ -198,6 +278,12 @@ .icon.s48.gear { background-image: url("../../../images/icons/48/gear.png"); } +.icon.s48.like { + background-image: url("icons/like.png"); +} +.icon.s48.dislike { + background-image: url("icons/dislike.png"); +} .icon.s48.add { background-image: url("../../../images/icons/48/add.png"); } @@ -267,7 +353,8 @@ body { h4 { font-size: 1.1em; } -a, a:link { +a, +a:link { color: #005c94; text-decoration: none; } @@ -336,6 +423,9 @@ code { .tool .action { float: right; } +.tool > img { + float: left; +} /* popup notifications */ #jGrowl.top-right { top: 30px; @@ -489,7 +579,8 @@ nav #nav-site-linkmenu .menu-popup { right: 0px; left: auto; } -nav #nav-notifications-linkmenu.on .icon.s22.notify, nav #nav-notifications-linkmenu.selected .icon.s22.notify { +nav #nav-notifications-linkmenu.on .icon.s22.notify, +nav #nav-notifications-linkmenu.selected .icon.s22.notify { background-image: url("../../../images/icons/22/notify_on.png"); } nav #nav-apps-link.selected { @@ -599,6 +690,9 @@ aside { padding: 0px 10px 0px 20px; border-right: 1px solid #bdcdd4; } +aside .profile-edit-side-div { + display: none; +} aside .vcard .fn { font-size: 16px; font-weight: bold; @@ -678,11 +772,15 @@ aside #profiles-menu { height: 48px; } /* group member */ -#contact-edit-drop-link, .mail-list-delete-wrapper, .group-delete-wrapper { +#contact-edit-drop-link, +.mail-list-delete-wrapper, +.group-delete-wrapper { float: right; margin-right: 50px; } -#contact-edit-drop-link .drophide, .mail-list-delete-wrapper .drophide, .group-delete-wrapper .drophide { +#contact-edit-drop-link .drophide, +.mail-list-delete-wrapper .drophide, +.group-delete-wrapper .drophide { background-image: url('../../../images/icons/22/delete.png'); display: block; width: 22px; @@ -691,7 +789,9 @@ aside #profiles-menu { position: relative; top: -50px; } -#contact-edit-drop-link .drop, .mail-list-delete-wrapper .drop, .group-delete-wrapper .drop { +#contact-edit-drop-link .drop, +.mail-list-delete-wrapper .drop, +.group-delete-wrapper .drop { background-image: url('../../../images/icons/22/delete.png'); display: block; width: 22px; @@ -821,7 +921,8 @@ section { display: table; width: 750px; } -.wall-item-container .wall-item-item, .wall-item-container .wall-item-bottom { +.wall-item-container .wall-item-item, +.wall-item-container .wall-item-bottom { display: table-row; } .wall-item-container .wall-item-bottom { @@ -859,11 +960,13 @@ section { .wall-item-container .wall-item-content img { max-width: 710px; } -.wall-item-container .wall-item-links, .wall-item-container .wall-item-actions { +.wall-item-container .wall-item-links, +.wall-item-container .wall-item-actions { display: table-cell; vertical-align: middle; } -.wall-item-container .wall-item-links .icon, .wall-item-container .wall-item-actions .icon { +.wall-item-container .wall-item-links .icon, +.wall-item-container .wall-item-actions .icon { opacity: 0.5; -webkit-transition: all 0.2s ease-in-out; -moz-transition: all 0.2s ease-in-out; @@ -871,7 +974,8 @@ section { -ms-transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out; } -.wall-item-container .wall-item-links .icon:hover, .wall-item-container .wall-item-actions .icon:hover { +.wall-item-container .wall-item-links .icon:hover, +.wall-item-container .wall-item-actions .icon:hover { opacity: 1; -webkit-transition: all 0.2s ease-in-out; -moz-transition: all 0.2s ease-in-out; @@ -1015,9 +1119,6 @@ section { opacity: 0.5; } .wwto { - position: absolute !important; - width: 25px; - height: 25px; background: #FFFFFF; border: 2px solid #364e59; height: 25px; @@ -1248,7 +1349,9 @@ section { height: 18px; }*/ /** acl **/ -#photo-edit-perms-select, #photos-upload-permissions-wrapper, #profile-jot-acl-wrapper { +#photo-edit-perms-select, +#photos-upload-permissions-wrapper, +#profile-jot-acl-wrapper { display: block!important; } #acl-wrapper { @@ -1407,10 +1510,12 @@ ul.tabs li .active { float: left; width: 200px; } -.field input, .field textarea { +.field input, +.field textarea { width: 400px; } -.field input[type="checkbox"], .field input[type="radio"] { +.field input[type="checkbox"], +.field input[type="radio"] { width: auto; } .field textarea { @@ -1537,10 +1642,126 @@ ul.tabs li .active { width: 50px; float: left; } -/* photo */ -.lframe { +/* photo albums */ +#photo-edit-link-wrap { + margin-bottom: 10px; +} +#album-edit-link { + border-right: 1px solid #364e59; + float: left; + padding-right: 5px; + margin-right: 5px; +} +#photo-edit-link, +#album-edit-link a { + background: url("../../../images/icons/16/edit.png") no-repeat left center; + padding-left: 18px; +} +#photo-toprofile-link { + background: url("../../../images/icons/16/user.png") no-repeat left center; + padding-left: 18px; +} +.photos-upload-link a, +#photo-top-upload-link { + background: url("../../../images/icons/16/add.png") no-repeat left center; + padding-left: 18px; +} +.photo-top-image-wrapper, +.photo-album-image-wrapper { float: left; margin: 0px 10px 10px 0px; + width: 150px; + height: 150px; + position: relative; + overflow: hidden; +} +.photo-top-image-wrapper img, +.photo-album-image-wrapper img { + width: 150px; +} +.photo-top-image-wrapper .photo-top-album-name, +.photo-album-image-wrapper .photo-top-album-name, +.photo-top-image-wrapper .caption, +.photo-album-image-wrapper .caption { + position: absolute; + color: #2d2d2d; + background-color: #ffffff; + width: 100%; + -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); + -webkit-transition: all 0.5s ease-in-out; + -moz-transition: all 0.5s ease-in-out; + -o-transition: all 0.5s ease-in-out; + -ms-transition: all 0.5s ease-in-out; + transition: all 0.5s ease-in-out; + bottom: -150px; +} +.photo-top-image-wrapper:hover .photo-top-album-name, +.photo-album-image-wrapper:hover .photo-top-album-name, +.photo-top-image-wrapper:hover .caption, +.photo-album-image-wrapper:hover .caption { + bottom: 0px; + -webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.7); + -moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.7); + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.7); + -webkit-transition: all 0.5s ease-in-out; + -moz-transition: all 0.5s ease-in-out; + -o-transition: all 0.5s ease-in-out; + -ms-transition: all 0.5s ease-in-out; + transition: all 0.5s ease-in-out; +} +#photo-photo { + display: block; + width: 660px; + padding: 50px; + margin-bottom: 0px; + text-align: center; + background-color: #999999; +} +#photo-photo img { + max-width: 560px; +} +#photo-album-title { + background: url("../../../images/icons/22/image.png") no-repeat top left; + padding-left: 23px; + min-height: 22px; +} +#photo-album-title a { + display: block; + padding-top: 5px; +} +#photo-caption { + display: block; + width: 660px; + min-height: 55px; + background-color: #cccccc; + padding: 0 50px 0 50px; +} +#photo-next-link > a > div { + background: url("icons/next.png") no-repeat center center; + float: right; + width: 50px; + height: 50px; +} +#photo-prev-link > a > div { + background: url("icons/prev.png") no-repeat center center; + float: left; + width: 50px; + height: 50px; +} +#photo-like-div { + display: block; + width: 660px; + height: 30px; + background-color: #cccccc; + padding: 0 50px 0 50px; +} +#photo-like-div .icon { + float: left; +} +#photo-like-div .like-rotator { + float: right; } /* profile match wrapper */ .profile-match-wrapper { @@ -1641,13 +1862,15 @@ ul.tabs li .active { transition: all 0.2s ease-in-out; } /* theme screenshot */ -.screenshot, #theme-preview { +.screenshot, +#theme-preview { position: absolute; width: 202px; left: 70%; top: 50px; } -.screenshot img, #theme-preview img { +.screenshot img, +#theme-preview img { width: 200px; height: 150px; } diff --git a/view/theme/quattro/green/style.css b/view/theme/quattro/green/style.css index ecf4ff9860..57fa38aa19 100644 --- a/view/theme/quattro/green/style.css +++ b/view/theme/quattro/green/style.css @@ -10,10 +10,72 @@ overflow: hidden; text-indent: -9999px; padding: 1px; + min-width: 22px; + height: 22px; } .icon.text { text-indent: 0px; } +.icon.notify { + background-image: url("../../../images/icons/22/notify_off.png"); +} +.icon.gear { + background-image: url("../../../images/icons/22/gear.png"); +} +.icon.like { + background-image: url("icons/like.png"); +} +.icon.dislike { + background-image: url("icons/dislike.png"); +} +.icon.add { + background-image: url("../../../images/icons/22/add.png"); +} +.icon.delete { + background-image: url("../../../images/icons/22/delete.png"); +} +.icon.edit { + background-image: url("../../../images/icons/22/edit.png"); +} +.icon.star { + background-image: url("../../../images/icons/22/star.png"); +} +.icon.menu { + background-image: url("../../../images/icons/22/menu.png"); +} +.icon.link { + background-image: url("../../../images/icons/22/link.png"); +} +.icon.lock { + background-image: url("../../../images/icons/22/lock.png"); +} +.icon.unlock { + background-image: url("../../../images/icons/22/unlock.png"); +} +.icon.plugin { + background-image: url("../../../images/icons/22/plugin.png"); +} +.icon.type-unkn { + background-image: url("../../../images/icons/22/zip.png"); +} +.icon.type-audio { + background-image: url("../../../images/icons/22/audio.png"); +} +.icon.type-video { + background-image: url("../../../images/icons/22/video.png"); +} +.icon.type-image { + background-image: url("../../../images/icons/22/image.png"); +} +.icon.type-text { + background-image: url("../../../images/icons/22/text.png"); +} +.icon.language { + background-image: url("icons/language.png"); +} +.icon.text { + padding: 10px 0px 0px 25px; +} .icon.s10 { min-width: 10px; height: 10px; @@ -24,6 +86,12 @@ .icon.s10.gear { background-image: url("../../../images/icons/10/gear.png"); } +.icon.s10.like { + background-image: url("icons/like.png"); +} +.icon.s10.dislike { + background-image: url("icons/dislike.png"); +} .icon.s10.add { background-image: url("../../../images/icons/10/add.png"); } @@ -82,6 +150,12 @@ .icon.s16.gear { background-image: url("../../../images/icons/16/gear.png"); } +.icon.s16.like { + background-image: url("icons/like.png"); +} +.icon.s16.dislike { + background-image: url("icons/dislike.png"); +} .icon.s16.add { background-image: url("../../../images/icons/16/add.png"); } @@ -140,6 +214,12 @@ .icon.s22.gear { background-image: url("../../../images/icons/22/gear.png"); } +.icon.s22.like { + background-image: url("icons/like.png"); +} +.icon.s22.dislike { + background-image: url("icons/dislike.png"); +} .icon.s22.add { background-image: url("../../../images/icons/22/add.png"); } @@ -198,6 +278,12 @@ .icon.s48.gear { background-image: url("../../../images/icons/48/gear.png"); } +.icon.s48.like { + background-image: url("icons/like.png"); +} +.icon.s48.dislike { + background-image: url("icons/dislike.png"); +} .icon.s48.add { background-image: url("../../../images/icons/48/add.png"); } @@ -267,7 +353,8 @@ body { h4 { font-size: 1.1em; } -a, a:link { +a, +a:link { color: #009100; text-decoration: none; } @@ -336,6 +423,9 @@ code { .tool .action { float: right; } +.tool > img { + float: left; +} /* popup notifications */ #jGrowl.top-right { top: 30px; @@ -489,7 +579,8 @@ nav #nav-site-linkmenu .menu-popup { right: 0px; left: auto; } -nav #nav-notifications-linkmenu.on .icon.s22.notify, nav #nav-notifications-linkmenu.selected .icon.s22.notify { +nav #nav-notifications-linkmenu.on .icon.s22.notify, +nav #nav-notifications-linkmenu.selected .icon.s22.notify { background-image: url("../../../images/icons/22/notify_on.png"); } nav #nav-apps-link.selected { @@ -599,6 +690,9 @@ aside { padding: 0px 10px 0px 20px; border-right: 1px solid #bdcdd4; } +aside .profile-edit-side-div { + display: none; +} aside .vcard .fn { font-size: 16px; font-weight: bold; @@ -678,11 +772,15 @@ aside #profiles-menu { height: 48px; } /* group member */ -#contact-edit-drop-link, .mail-list-delete-wrapper, .group-delete-wrapper { +#contact-edit-drop-link, +.mail-list-delete-wrapper, +.group-delete-wrapper { float: right; margin-right: 50px; } -#contact-edit-drop-link .drophide, .mail-list-delete-wrapper .drophide, .group-delete-wrapper .drophide { +#contact-edit-drop-link .drophide, +.mail-list-delete-wrapper .drophide, +.group-delete-wrapper .drophide { background-image: url('../../../images/icons/22/delete.png'); display: block; width: 22px; @@ -691,7 +789,9 @@ aside #profiles-menu { position: relative; top: -50px; } -#contact-edit-drop-link .drop, .mail-list-delete-wrapper .drop, .group-delete-wrapper .drop { +#contact-edit-drop-link .drop, +.mail-list-delete-wrapper .drop, +.group-delete-wrapper .drop { background-image: url('../../../images/icons/22/delete.png'); display: block; width: 22px; @@ -821,7 +921,8 @@ section { display: table; width: 750px; } -.wall-item-container .wall-item-item, .wall-item-container .wall-item-bottom { +.wall-item-container .wall-item-item, +.wall-item-container .wall-item-bottom { display: table-row; } .wall-item-container .wall-item-bottom { @@ -859,11 +960,13 @@ section { .wall-item-container .wall-item-content img { max-width: 710px; } -.wall-item-container .wall-item-links, .wall-item-container .wall-item-actions { +.wall-item-container .wall-item-links, +.wall-item-container .wall-item-actions { display: table-cell; vertical-align: middle; } -.wall-item-container .wall-item-links .icon, .wall-item-container .wall-item-actions .icon { +.wall-item-container .wall-item-links .icon, +.wall-item-container .wall-item-actions .icon { opacity: 0.5; -webkit-transition: all 0.2s ease-in-out; -moz-transition: all 0.2s ease-in-out; @@ -871,7 +974,8 @@ section { -ms-transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out; } -.wall-item-container .wall-item-links .icon:hover, .wall-item-container .wall-item-actions .icon:hover { +.wall-item-container .wall-item-links .icon:hover, +.wall-item-container .wall-item-actions .icon:hover { opacity: 1; -webkit-transition: all 0.2s ease-in-out; -moz-transition: all 0.2s ease-in-out; @@ -1015,9 +1119,6 @@ section { opacity: 0.5; } .wwto { - position: absolute !important; - width: 25px; - height: 25px; background: #FFFFFF; border: 2px solid #364e59; height: 25px; @@ -1248,7 +1349,9 @@ section { height: 18px; }*/ /** acl **/ -#photo-edit-perms-select, #photos-upload-permissions-wrapper, #profile-jot-acl-wrapper { +#photo-edit-perms-select, +#photos-upload-permissions-wrapper, +#profile-jot-acl-wrapper { display: block!important; } #acl-wrapper { @@ -1407,10 +1510,12 @@ ul.tabs li .active { float: left; width: 200px; } -.field input, .field textarea { +.field input, +.field textarea { width: 400px; } -.field input[type="checkbox"], .field input[type="radio"] { +.field input[type="checkbox"], +.field input[type="radio"] { width: auto; } .field textarea { @@ -1537,10 +1642,126 @@ ul.tabs li .active { width: 50px; float: left; } -/* photo */ -.lframe { +/* photo albums */ +#photo-edit-link-wrap { + margin-bottom: 10px; +} +#album-edit-link { + border-right: 1px solid #364e59; + float: left; + padding-right: 5px; + margin-right: 5px; +} +#photo-edit-link, +#album-edit-link a { + background: url("../../../images/icons/16/edit.png") no-repeat left center; + padding-left: 18px; +} +#photo-toprofile-link { + background: url("../../../images/icons/16/user.png") no-repeat left center; + padding-left: 18px; +} +.photos-upload-link a, +#photo-top-upload-link { + background: url("../../../images/icons/16/add.png") no-repeat left center; + padding-left: 18px; +} +.photo-top-image-wrapper, +.photo-album-image-wrapper { float: left; margin: 0px 10px 10px 0px; + width: 150px; + height: 150px; + position: relative; + overflow: hidden; +} +.photo-top-image-wrapper img, +.photo-album-image-wrapper img { + width: 150px; +} +.photo-top-image-wrapper .photo-top-album-name, +.photo-album-image-wrapper .photo-top-album-name, +.photo-top-image-wrapper .caption, +.photo-album-image-wrapper .caption { + position: absolute; + color: #2d2d2d; + background-color: #ffffff; + width: 100%; + -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); + -webkit-transition: all 0.5s ease-in-out; + -moz-transition: all 0.5s ease-in-out; + -o-transition: all 0.5s ease-in-out; + -ms-transition: all 0.5s ease-in-out; + transition: all 0.5s ease-in-out; + bottom: -150px; +} +.photo-top-image-wrapper:hover .photo-top-album-name, +.photo-album-image-wrapper:hover .photo-top-album-name, +.photo-top-image-wrapper:hover .caption, +.photo-album-image-wrapper:hover .caption { + bottom: 0px; + -webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.7); + -moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.7); + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.7); + -webkit-transition: all 0.5s ease-in-out; + -moz-transition: all 0.5s ease-in-out; + -o-transition: all 0.5s ease-in-out; + -ms-transition: all 0.5s ease-in-out; + transition: all 0.5s ease-in-out; +} +#photo-photo { + display: block; + width: 660px; + padding: 50px; + margin-bottom: 0px; + text-align: center; + background-color: #999999; +} +#photo-photo img { + max-width: 560px; +} +#photo-album-title { + background: url("../../../images/icons/22/image.png") no-repeat top left; + padding-left: 23px; + min-height: 22px; +} +#photo-album-title a { + display: block; + padding-top: 5px; +} +#photo-caption { + display: block; + width: 660px; + min-height: 55px; + background-color: #cccccc; + padding: 0 50px 0 50px; +} +#photo-next-link > a > div { + background: url("icons/next.png") no-repeat center center; + float: right; + width: 50px; + height: 50px; +} +#photo-prev-link > a > div { + background: url("icons/prev.png") no-repeat center center; + float: left; + width: 50px; + height: 50px; +} +#photo-like-div { + display: block; + width: 660px; + height: 30px; + background-color: #cccccc; + padding: 0 50px 0 50px; +} +#photo-like-div .icon { + float: left; +} +#photo-like-div .like-rotator { + float: right; } /* profile match wrapper */ .profile-match-wrapper { @@ -1641,13 +1862,15 @@ ul.tabs li .active { transition: all 0.2s ease-in-out; } /* theme screenshot */ -.screenshot, #theme-preview { +.screenshot, +#theme-preview { position: absolute; width: 202px; left: 70%; top: 50px; } -.screenshot img, #theme-preview img { +.screenshot img, +#theme-preview img { width: 200px; height: 150px; } diff --git a/view/theme/quattro/icons.less b/view/theme/quattro/icons.less index ae7459dfc6..f9be4cc723 100644 --- a/view/theme/quattro/icons.less +++ b/view/theme/quattro/icons.less @@ -5,6 +5,9 @@ &.notify { background-image: url("../../../images/icons/@{size}/notify_off.png"); } &.gear { background-image: url("../../../images/icons/@{size}/gear.png"); } + &.like { background-image: url("icons/like.png"); } + &.dislike { background-image: url("icons/dislike.png"); } + &.add { background-image: url("../../../images/icons/@{size}/add.png"); } &.delete { background-image: url("../../../images/icons/@{size}/delete.png"); } &.edit { background-image: url("../../../images/icons/@{size}/edit.png"); } @@ -40,6 +43,10 @@ text-indent: 0px; } + min-width:22px; height: 22px; + .icons(22); + &.text { padding: 10px 0px 0px 25px; } + &.s10 { min-width:10px; height: 10px; .icons(10); diff --git a/view/theme/quattro/icons/addon_off.png b/view/theme/quattro/icons/addon_off.png index 40b53259a2..0fcce4d5ab 100644 Binary files a/view/theme/quattro/icons/addon_off.png and b/view/theme/quattro/icons/addon_off.png differ diff --git a/view/theme/quattro/icons/addon_on.png b/view/theme/quattro/icons/addon_on.png index 3d9490f152..79ce07f0e3 100644 Binary files a/view/theme/quattro/icons/addon_on.png and b/view/theme/quattro/icons/addon_on.png differ diff --git a/view/theme/quattro/icons/dislike.png b/view/theme/quattro/icons/dislike.png new file mode 100644 index 0000000000..23de426c5a Binary files /dev/null and b/view/theme/quattro/icons/dislike.png differ diff --git a/view/theme/quattro/icons/like.png b/view/theme/quattro/icons/like.png new file mode 100644 index 0000000000..b65edccc07 Binary files /dev/null and b/view/theme/quattro/icons/like.png differ diff --git a/view/theme/quattro/icons/next.png b/view/theme/quattro/icons/next.png new file mode 100644 index 0000000000..7b5e25b905 Binary files /dev/null and b/view/theme/quattro/icons/next.png differ diff --git a/view/theme/quattro/icons/prev.png b/view/theme/quattro/icons/prev.png new file mode 100644 index 0000000000..55c1464ba0 Binary files /dev/null and b/view/theme/quattro/icons/prev.png differ diff --git a/view/theme/quattro/photo_view.tpl b/view/theme/quattro/photo_view.tpl new file mode 100644 index 0000000000..3b7a662716 --- /dev/null +++ b/view/theme/quattro/photo_view.tpl @@ -0,0 +1,37 @@ +
    +

    $album.1

    + + + +
    +{{ if $prevlink }}{{ endif }} +{{ if $nextlink }}{{ endif }} +
    $desc
    +{{ if $tags }} +
    $tags.0
    +
    $tags.1
    +{{ endif }} +{{ if $tags.2 }}{{ endif }} + +{{ if $edit }}$edit{{ endif }} + +{{ if $likebuttons }} +
    + $likebuttons + $like + $dislike +
    +{{ endif }} +
    + $comments +
    + +$paginate + diff --git a/view/theme/quattro/quattro.less b/view/theme/quattro/quattro.less index 9099f0be16..0dac79bf9c 100644 --- a/view/theme/quattro/quattro.less +++ b/view/theme/quattro/quattro.less @@ -27,13 +27,17 @@ h4 { font-size: 1.1em } .opaque(@v: 0.5){ opacity: @v; - -webkit-transition: all 0.2s ease-in-out; - -moz-transition: all 0.2s ease-in-out; - -o-transition: all 0.2s ease-in-out; - -ms-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; + .transition(); } +.transition(@d: 0.2s){ + -webkit-transition: all @d ease-in-out; + -moz-transition: all @d ease-in-out; + -o-transition: all @d ease-in-out; + -ms-transition: all @d ease-in-out; + transition: all @d ease-in-out; +} + a, a:link { color: @Link; text-decoration: none; } a:visited { color: @LinkVisited; text-decoration: none; } @@ -81,6 +85,7 @@ code { height: auto; overflow: auto; .label { float: left;} .action { float: right; } + > img { float: left; } } @@ -282,6 +287,8 @@ aside { padding:0px 10px 0px 20px; border-right: 1px solid @AsideBorder; + .profile-edit-side-div { display: none; } + .vcard { .fn { font-size: 16px; font-weight: bold; margin-bottom: 5px; } .title { margin-bottom: 5px; } @@ -1068,12 +1075,102 @@ ul.tabs { width: 50px; float: left; } -/* photo */ -.lframe { +/* photo albums */ +@photosize: 150px; + +#photo-edit-link-wrap { margin-bottom: 10px; } + +#album-edit-link { + border-right: 1px solid @MenuBorder; float: left; - margin: 0px 10px 10px 0px; + padding-right: 5px; + margin-right: 5px; +} +#photo-edit-link, +#album-edit-link a { + background: url("../../../images/icons/16/edit.png") no-repeat left center; + padding-left: 18px; +} +#photo-toprofile-link { + background: url("../../../images/icons/16/user.png") no-repeat left center; + padding-left: 18px; } +.photos-upload-link a, +#photo-top-upload-link { + background: url("../../../images/icons/16/add.png") no-repeat left center; + padding-left: 18px; +} + + +.photo-top-image-wrapper, +.photo-album-image-wrapper { + float: left; + margin: 0px 10px 10px 0px; + width:@photosize; height: @photosize; + position: relative; + overflow: hidden; + + img { width: @photosize; } + + .photo-top-album-name, + .caption{ + position: absolute; + color: @Menu; + background-color: @MenuBg; + + width: 100%; + .shadow(0px, 5px); + .transition(0.5s); + bottom: -@photosize; + } + + &:hover .photo-top-album-name, + &:hover .caption { + bottom: 0px; + .shadow(0px, 0px); + .transition(0.5s); + } +} + +#photo-photo { + display: block; width: 660px; + padding: 50px; margin-bottom: 0px; + text-align: center; + background-color: @Grey3; + img { max-width: 560px; } +} +#photo-album-title { + background: url("../../../images/icons/22/image.png") no-repeat top left; + padding-left: 23px; + min-height: 22px; + a { display: block; padding-top: 5px; } +} + +#photo-caption { + display: block; width: 660px; + min-height: 55px; + background-color: @Grey2; + padding:0 50px 0 50px; +} +#photo-next-link > a > div { + background: url("icons/next.png") no-repeat center center; + float: right; + width: 50px; height: 50px; +} +#photo-prev-link > a > div { + background: url("icons/prev.png") no-repeat center center; + float: left; + width: 50px; height: 50px; +} +#photo-like-div { + display: block; width: 660px; + height: 30px; + background-color: @Grey2; + padding:0 50px 0 50px; + .icon {float: left;} + .like-rotator {float: right;} +} /* profile match wrapper */ .profile-match-wrapper { float: left; diff --git a/view/theme/slackr/birthdays_reminder.tpl b/view/theme/slackr/birthdays_reminder.tpl index 8b13789179..1dc65295a9 100644 --- a/view/theme/slackr/birthdays_reminder.tpl +++ b/view/theme/slackr/birthdays_reminder.tpl @@ -1 +1,8 @@ +{{ if $classtoday }} + +{{ endif }} diff --git a/view/theme/slackr/style.css b/view/theme/slackr/style.css index ea10cc377a..73b436fc61 100644 --- a/view/theme/slackr/style.css +++ b/view/theme/slackr/style.css @@ -12,6 +12,10 @@ .wall-item-tools { background: none; } +.wall-item-body a:hover { + color: #ff6600; +} + .widget { /* box-shadow: 4px 4px 3px 0 #444444; */ @@ -67,6 +71,8 @@ nav #site-location { opacity: 1.0; filter:alpha(opacity=100); box-shadow: 4px 4px 3px 0 #444444; + margin-left: 0px; + margin-top: 0px; } #events-reminder:hover { @@ -108,6 +114,8 @@ nav #site-location { #posted-date-selector { margin-left: 30px !important; margin-top: 5px !important; + margin-right: 0px !important; + margin-bottom: 0px !important; } @@ -115,6 +123,9 @@ nav #site-location { box-shadow: 4px 4px 3px 0 #444444; margin-left: 25px !important; margin-top: 0px !important; + margin-right: 5px !important; + margin-bottom: 5px !important; + } .contact-entry-photo img, .profile-match-photo img, #photo-photo img, .directory-photo-img, .photo-album-photo, .photo-top-photo, .profile-jot-text, .group-selected, .nets-selected, .fileas-selected, #profile-jot-submit, .categories-selected { diff --git a/view/theme/testbubble/style.css b/view/theme/testbubble/style.css index 1e63c7ef63..58f31971bf 100644 --- a/view/theme/testbubble/style.css +++ b/view/theme/testbubble/style.css @@ -3280,3 +3280,9 @@ ul.menu-popup { .notify-seen { background: #000; } + + +/* Pages profile widget */ +#page-profile div#profile-page-list{ +margin-left: 45px; +} \ No newline at end of file diff --git a/view/wall_item.tpl b/view/wall_item.tpl index a6a96d8792..dae33b3f75 100644 --- a/view/wall_item.tpl +++ b/view/wall_item.tpl @@ -69,8 +69,8 @@
    - -
    $item.dislike
    + +
    $item.dislike
    $item.comment
    diff --git a/view/wallwall_item.tpl b/view/wallwall_item.tpl index 9cbfc991ea..a48acfec5b 100644 --- a/view/wallwall_item.tpl +++ b/view/wallwall_item.tpl @@ -74,8 +74,8 @@
    - -
    $item.dislike
    + +
    $item.dislike
    $item.comment diff --git a/view/xrd_host.tpl b/view/xrd_host.tpl index dbb20256f9..94e3c2146e 100644 --- a/view/xrd_host.tpl +++ b/view/xrd_host.tpl @@ -10,17 +10,6 @@ - - - - - - $bigkey diff --git a/view/xrd_person.tpl b/view/xrd_person.tpl index a4b921fe10..d79203465b 100644 --- a/view/xrd_person.tpl +++ b/view/xrd_person.tpl @@ -5,17 +5,6 @@ $accturi $profile_url - - - - - -