diff options
author | Mario Vavti <mario@mariovavti.com> | 2019-06-04 10:19:04 +0200 |
---|---|---|
committer | Mario Vavti <mario@mariovavti.com> | 2019-06-04 10:19:04 +0200 |
commit | e4ca3609d90bb437061e4b8db95ed0424b25eb76 (patch) | |
tree | aa070e40ab01cb1354cbf879a0fb8b2f570631d5 /include | |
parent | 071fba2f7121aeb9690a21398935a53deac09af8 (diff) | |
parent | bc092d8d7815195d62299c0ea54caa4759e6f2e7 (diff) | |
download | volse-hubzilla-4.2.tar.gz volse-hubzilla-4.2.tar.bz2 volse-hubzilla-4.2.zip |
Merge branch '4.2RC'4.2
Diffstat (limited to 'include')
-rw-r--r-- | include/attach.php | 11 | ||||
-rw-r--r-- | include/bbcode.php | 34 | ||||
-rw-r--r-- | include/connections.php | 33 | ||||
-rw-r--r-- | include/datetime.php | 3 | ||||
-rwxr-xr-x | include/dba/dba_driver.php | 25 | ||||
-rwxr-xr-x | include/dba/dba_pdo.php | 2 | ||||
-rw-r--r-- | include/event.php | 98 | ||||
-rw-r--r-- | include/features.php | 34 | ||||
-rw-r--r-- | include/follow.php | 15 | ||||
-rw-r--r-- | include/import.php | 52 | ||||
-rwxr-xr-x | include/items.php | 2 | ||||
-rw-r--r-- | include/js_strings.php | 1 | ||||
-rw-r--r-- | include/markdown.php | 4 | ||||
-rwxr-xr-x | include/oembed.php | 31 | ||||
-rw-r--r-- | include/photos.php | 9 | ||||
-rw-r--r-- | include/text.php | 34 | ||||
-rw-r--r-- | include/zot.php | 82 |
17 files changed, 321 insertions, 149 deletions
diff --git a/include/attach.php b/include/attach.php index f6594b154..f169e0669 100644 --- a/include/attach.php +++ b/include/attach.php @@ -1521,6 +1521,17 @@ function attach_drop_photo($channel_id,$resource) { if($x) { drop_item($x[0]['id'],false,(($x[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1),true); } + + $r = q("SELECT content FROM photo WHERE resource_id = '%s' AND uid = %d AND os_storage = 1", + dbesc($resource), + intval($channel_id) + ); + if($r) { + foreach($r as $i) { + @unlink(dbunescbin($i['content'])); + } + } + q("DELETE FROM photo WHERE uid = %d AND resource_id = '%s'", intval($channel_id), dbesc($resource) diff --git a/include/bbcode.php b/include/bbcode.php index 36f943e46..485a1f5b2 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -87,12 +87,11 @@ function nakedoembed($match) { $strip_url = strip_escaped_zids($url); - $o = oembed_fetch_url($strip_url); - - if ($o['type'] == 'error') - return str_replace($url,$strip_url,$match[0]); - - return '[embed]' . $strip_url . '[/embed]'; + // this function no longer performs oembed on naked links + // because they author may have created naked links intentionally. + // Now it just strips zids on naked links. + + return str_replace($url,$strip_url,$match[0]); } function tryzrlaudio($match) { @@ -986,17 +985,22 @@ function bbcode($Text, $options = []) { // leave open the posibility of [map=something] // this is replaced in prepare_body() which has knowledge of the item location - - if (strpos($Text,'[/map]') !== false) { - $Text = preg_replace_callback("/\[map\](.*?)\[\/map\]/ism", 'bb_map_location', $Text); - } - if (strpos($Text,'[map=') !== false) { - $Text = preg_replace_callback("/\[map=(.*?)\]/ism", 'bb_map_coords', $Text); + if ($cache) { + $Text = str_replace([ '[map]','[/map]' ], [ '','' ], $Text); + $Text = preg_replace('/\[map=(.*?)\]/ism','$1',$Text); } - if (strpos($Text,'[map]') !== false) { - $Text = preg_replace("/\[map\]/", '<div class="map"></div>', $Text); + else { + if (strpos($Text,'[/map]') !== false) { + $Text = preg_replace_callback("/\[map\](.*?)\[\/map\]/ism", 'bb_map_location', $Text); + } + if (strpos($Text,'[map=') !== false) { + $Text = preg_replace_callback("/\[map=(.*?)\]/ism", 'bb_map_coords', $Text); + } + if (strpos($Text,'[map]') !== false) { + $Text = preg_replace("/\[map\]/", '<div class="map"></div>', $Text); + } } - + // Check for bold text if (strpos($Text,'[b]') !== false) { $Text = preg_replace("(\[b\](.*?)\[\/b\])ism", '<strong>$1</strong>', $Text); diff --git a/include/connections.php b/include/connections.php index d97ea3887..e942503f0 100644 --- a/include/connections.php +++ b/include/connections.php @@ -373,19 +373,46 @@ function contact_remove($channel_id, $abook_id) { if(intval($abook['abook_self'])) return false; - $r = q("select id from item where (owner_xchan = '%s' or author_xchan = '%s') and uid = %d and item_retained = 0 and item_starred = 0", + $r = q("select id, parent from item where (owner_xchan = '%s' or author_xchan = '%s') and uid = %d and item_retained = 0 and item_starred = 0", dbesc($abook['abook_xchan']), dbesc($abook['abook_xchan']), intval($channel_id) ); if($r) { + $already_saved = []; foreach($r as $rr) { - $x = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1", + $w = $x = $y = null; + + // optimise so we only process newly seen parent items + if (in_array($rr['parent'],$already_saved)) { + continue; + } + // if this isn't the parent, fetch the parent's item_retained and item_starred to see if the conversation + // should be retained + if($rr['id'] != $rr['parent']) { + $w = q("select id, item_retained, item_starred from item where id = %d", + intval($rr['parent']) + ); + if($w) { + // see if the conversation was filed + $x = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1", + intval(TERM_OBJ_POST), + intval($w[0]['id']), + intval(TERM_FILE) + ); + if (intval($w[0]['item_retained']) || intval($w[0]['item_starred']) || $x) { + $already_saved[] = $rr['parent']; + continue; + } + } + } + // see if this item was filed + $y = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1", intval(TERM_OBJ_POST), intval($rr['id']), intval(TERM_FILE) ); - if($x) { + if ($y) { continue; } drop_item($rr['id'],false); diff --git a/include/datetime.php b/include/datetime.php index 3a07f1ccf..ef0927ea4 100644 --- a/include/datetime.php +++ b/include/datetime.php @@ -516,13 +516,14 @@ function update_birthdays() { 'event_xchan' => $rr['xchan_hash'], 'dtstart' => datetime_convert('UTC', 'UTC', $rr['abook_dob']), 'dtend' => datetime_convert('UTC', 'UTC', $rr['abook_dob'] . ' + 1 day '), - 'adjust' => intval(feature_enabled($rr['abook_channel'],'smart_birthdays')), + 'adjust' => 0, 'summary' => sprintf( t('%1$s\'s birthday'), $rr['xchan_name']), 'description' => sprintf( t('Happy Birthday %1$s'), '[zrl=' . $rr['xchan_url'] . ']' . $rr['xchan_name'] . '[/zrl]'), 'etype' => 'birthday', ]; $z = event_store_event($ev); + if ($z) { $item_id = event_store_item($ev, $z); q("update abook set abook_dob = '%s' where abook_id = %d", diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php index ee0e06a91..cfb208e2d 100755 --- a/include/dba/dba_driver.php +++ b/include/dba/dba_driver.php @@ -485,3 +485,28 @@ function db_columns($table) { return []; } + + +function db_indexes($table) { + + if($table) { + if(ACTIVE_DBTYPE === DBTYPE_POSTGRES) { + $r = q("SELECT indexname from pg_indexes where tablename = '%s'", + dbesc($table) + ); + if($r) { + return ids_to_array($r,'indexname'); + } + } + else { + $r = q("show index from %s", + dbesc($table) + ); + if($r) { + return ids_to_array($r,'Key_name'); + } + } + } + + return []; +} diff --git a/include/dba/dba_pdo.php b/include/dba/dba_pdo.php index ef8063428..0279342ec 100755 --- a/include/dba/dba_pdo.php +++ b/include/dba/dba_pdo.php @@ -19,7 +19,7 @@ class dba_pdo extends dba_driver { $this->driver_dbtype = $scheme; if(strpbrk($server,':;')) { - $dsn = $server; + $dsn = $this->driver_dbtype . ':unix_socket=' . trim($server, ':;'); } else { $dsn = $this->driver_dbtype . ':host=' . $server . (intval($port) ? ';port=' . $port : ''); diff --git a/include/event.php b/include/event.php index 77118c329..6689919cf 100644 --- a/include/event.php +++ b/include/event.php @@ -27,6 +27,7 @@ function format_event_html($ev) { if(! ((is_array($ev)) && count($ev))) return ''; + $tz = (($ev['timezone']) ? $ev['timezone'] : 'UTC'); $bd_format = t('l F d, Y \@ g:i A') ; // Friday January 18, 2011 @ 8:01 AM @@ -39,7 +40,7 @@ function format_event_html($ev) { $o .= '<div class="event-start"><span class="event-label">' . t('Starts:') . '</span> <span class="dtstart" title="' . datetime_convert('UTC', 'UTC', $ev['dtstart'], (($ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )) . '" >' - . (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), + . (($ev['adjust']) ? day_translate(datetime_convert($tz, date_default_timezone_get(), $ev['dtstart'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $ev['dtstart'] , $bd_format))) @@ -49,7 +50,7 @@ function format_event_html($ev) { $o .= '<div class="event-end" ><span class="event-label">' . t('Finishes:') . '</span> <span class="dtend" title="' . datetime_convert('UTC','UTC',$ev['dtend'], (($ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )) . '" >' - . (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), + . (($ev['adjust']) ? day_translate(datetime_convert($tz, date_default_timezone_get(), $ev['dtend'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $ev['dtend'] , $bd_format ))) @@ -75,17 +76,35 @@ function format_event_obj($jobject) { //ensure compatibility with older items - this check can be removed at a later point if(array_key_exists('description', $object)) { - $bd_format = t('l F d, Y \@ g:i A'); // Friday January 18, 2011 @ 8:01 AM + $tz = (($object['timezone']) ? $object['timezone'] : 'UTC'); + $allday = (($object['adjust']) ? false : true); + + $dtstart = new DateTime($object['dtstart']); + $dtend = new DateTime($object['dtend']); + $dtdiff = $dtstart->diff($dtend); + + if($allday && ($dtdiff->days < 2)) + $oneday = true; + + if($allday && !$oneday) { + // Subtract one day from the end date so we can use the "first day - last day" format for display. + $dtend->modify('-1 day'); + $object['dtend'] = datetime_convert('UTC', 'UTC', $dtend->format('Y-m-d H:i:s')); + } + + $bd_format = (($allday) ? t('l F d, Y') : t('l F d, Y \@ g:i A')); // Friday January 18, 2011 @ 8:01 AM or Friday January 18, 2011 for allday events $event['header'] = replace_macros(get_markup_template('event_item_header.tpl'),array( '$title' => zidify_links(smilies(bbcode($object['title']))), - '$dtstart_label' => t('Starts:'), - '$dtstart_title' => datetime_convert('UTC', 'UTC', $object['dtstart'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )), - '$dtstart_dt' => (($object['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $object['dtstart'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['dtstart'] , $bd_format))), + '$dtstart_label' => t('Start:'), + '$dtstart_title' => datetime_convert($tz, date_default_timezone_get(), $object['dtstart'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )), + '$dtstart_dt' => (($object['adjust']) ? day_translate(datetime_convert($tz, date_default_timezone_get(), $object['dtstart'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['dtstart'] , $bd_format))), '$finish' => (($object['nofinish']) ? false : true), - '$dtend_label' => t('Finishes:'), - '$dtend_title' => datetime_convert('UTC','UTC',$object['dtend'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )), - '$dtend_dt' => (($object['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $object['dtend'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['dtend'] , $bd_format ))) + '$dtend_label' => t('End:'), + '$dtend_title' => datetime_convert($tz, date_default_timezone_get(), $object['dtend'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )), + '$dtend_dt' => (($object['adjust']) ? day_translate(datetime_convert($tz, date_default_timezone_get(), $object['dtend'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['dtend'] , $bd_format ))), + '$allday' => $allday, + '$oneday' => $oneday )); $event['content'] = replace_macros(get_markup_template('event_item_content.tpl'),array( @@ -125,6 +144,12 @@ function format_event_ical($ev) { if($ev['etype'] === 'task') return format_todo_ical($ev); + $tz = get_iconfig($ev['item_id'], 'event', 'timezone'); + if(! $tz) + $tz = 'UTC'; + + $tzid = ';TZID=' . $tz; + $o = ''; $o .= "\r\nBEGIN:VEVENT"; @@ -132,10 +157,19 @@ function format_event_ical($ev) { $o .= "\r\nCREATED:" . datetime_convert('UTC','UTC', $ev['created'],'Ymd\\THis\\Z'); $o .= "\r\nLAST-MODIFIED:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z'); $o .= "\r\nDTSTAMP:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z'); - if($ev['dtstart']) - $o .= "\r\nDTSTART:" . datetime_convert('UTC','UTC', $ev['dtstart'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : '')); - if($ev['dtend'] && ! $ev['nofinish']) - $o .= "\r\nDTEND:" . datetime_convert('UTC','UTC', $ev['dtend'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : '')); + + if($ev['adjust']) { + if($ev['dtstart']) + $o .= "\r\nDTSTART$tzid:" . datetime_convert($tz,'UTC', $ev['dtstart'],'Ymd\\THis\\Z'); + if($ev['dtend'] && ! $ev['nofinish']) + $o .= "\r\nDTEND$tzid:" . datetime_convert($tz,'UTC', $ev['dtend'],'Ymd\\THis\\Z'); + } + else { + if($ev['dtstart']) + $o .= "\r\nDTSTART;VALUE=DATE:" . datetime_convert('UTC','UTC', $ev['dtstart'],'Ymd'); + if($ev['dtend'] && ! $ev['nofinish']) + $o .= "\r\nDTEND;VALUE=DATE:" . datetime_convert('UTC','UTC', $ev['dtend'],'Ymd'); + } if($ev['summary']) { $o .= "\r\nSUMMARY:" . format_ical_text($ev['summary']); $o .= "\r\nX-ZOT-SUMMARY:" . format_ical_sourcetext($ev['summary']); @@ -723,17 +757,9 @@ function parse_vobject($ical, $type) { function parse_ical_file($f,$uid) { - require_once('vendor/autoload.php'); $s = @file_get_contents($f); - // Change the current timezone to something besides UTC. - // Doesn't matter what it is, as long as it isn't UTC. - // Save the current timezone so we can reset it when we're done processing. - - $saved_timezone = date_default_timezone_get(); - date_default_timezone_set('Australia/Sydney'); - $ical = VObject\Reader::read($s); if($ical) { @@ -749,8 +775,6 @@ function parse_ical_file($f,$uid) { } } - date_default_timezone_set($saved_timezone); - if($ical) return true; @@ -782,12 +806,23 @@ function event_import_ical($ical, $uid) { // logger('dtstart: ' . var_export($dtstart,true)); - $ev['dtstart'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC', + $ev['timezone'] = 'UTC'; + + // Try to get an usable olson format timezone + if($ev['adjust']) { + //TODO: we should pass the vcalendar to getTimeZone() to be more accurate + // we do not have it here since parse_ical_file() is passing the vevent only. + $timezone_obj = \Sabre\VObject\TimeZoneUtil::getTimeZone($ical->DTSTART['TZID']); + $timezone = $timezone_obj->getName(); + $ev['timezone'] = $timezone; + } + + $ev['dtstart'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),$ev['timezone'], $dtstart->format(\DateTime::W3C)); if(isset($ical->DTEND)) { $dtend = $ical->DTEND->getDateTime(); - $ev['dtend'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC', + $ev['dtend'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),$ev['timezone'], $dtend->format(\DateTime::W3C)); } else { @@ -1042,6 +1077,7 @@ function event_store_item($arr, $event) { 'type' => ACTIVITY_OBJ_EVENT, 'id' => z_root() . '/event/' . $r[0]['resource_id'], 'title' => $arr['summary'], + 'timezone' => $arr['timezone'], 'dtstart' => $arr['dtstart'], 'dtend' => $arr['dtend'], 'nofinish' => $arr['nofinish'], @@ -1107,6 +1143,8 @@ function event_store_item($arr, $event) { } $item_id = $r[0]['id']; + set_iconfig($item_id, 'event', 'timezone', $arr['timezone'], true); + /** * @hooks event_updated * Called when an event record is modified. @@ -1163,7 +1201,7 @@ function event_store_item($arr, $event) { $item_arr['item_thread_top'] = $item_thread_top; $attach = array(array( - 'href' => z_root() . '/events/ical/' . urlencode($event['event_hash']), + 'href' => z_root() . '/channel_calendar/ical/' . urlencode($event['event_hash']), 'length' => 0, 'type' => 'text/calendar', 'title' => t('event') . '-' . $event['event_hash'], @@ -1185,7 +1223,7 @@ function event_store_item($arr, $event) { // otherwise we'll fallback to /display/$message_id if($wall) - $item_arr['plink'] = z_root() . '/channel/' . $z[0]['channel_address'] . '/?f=&mid=' . urlencode($item_arr['mid']); + $item_arr['plink'] = z_root() . '/channel/' . $z[0]['channel_address'] . '/?f=&mid=' . gen_link_id($item_arr['mid']); else $item_arr['plink'] = z_root() . '/display/' . gen_link_id($item_arr['mid']); @@ -1197,6 +1235,7 @@ function event_store_item($arr, $event) { 'type' => ACTIVITY_OBJ_EVENT, 'id' => z_root() . '/event/' . $event['event_hash'], 'title' => $arr['summary'], + 'timezone' => $arr['timezone'], 'dtstart' => $arr['dtstart'], 'dtend' => $arr['dtend'], 'nofinish' => $arr['nofinish'], @@ -1223,6 +1262,7 @@ function event_store_item($arr, $event) { // activities refer to the item message_id as the parent. set_iconfig($item_arr, 'system','event_id',$event['event_hash'],true); + set_iconfig($item_arr, 'event','timezone',$arr['timezone'],true); $res = item_store($item_arr); @@ -1284,6 +1324,10 @@ function cdav_principal($uri) { } function cdav_perms($needle, $haystack, $check_rw = false) { + + if($needle == 'channel_calendar') + return true; + foreach ($haystack as $item) { if($check_rw) { if(is_array($item['id'])) { diff --git a/include/features.php b/include/features.php index d021f9394..9528d3418 100644 --- a/include/features.php +++ b/include/features.php @@ -79,7 +79,7 @@ function get_features($filtered = true, $level = (-1)) { 'calendar' => [ - t('CalDAV'), + t('Calendar'), [ 'cal_first_day', @@ -87,6 +87,14 @@ function get_features($filtered = true, $level = (-1)) { t('Default is Sunday'), false, get_config('feature_lock','cal_first_day') + ], + + [ + 'event_tz_select', + t('Event Timezone Selection'), + t('Allow event creation in timezones other than your own.'), + false, + get_config('feature_lock','event_tz_select'), ] ], @@ -167,6 +175,14 @@ function get_features($filtered = true, $level = (-1)) { t('Ability to mark special posts with a star indicator'), false, get_config('feature_lock','star_posts'), + ], + + [ + 'reply_to', + t('Reply on comment'), + t('Ability to reply on selected comment'), + false, + get_config('feature_lock','reply_to'), ] ], @@ -274,22 +290,6 @@ function get_features($filtered = true, $level = (-1)) { t('Default is Sunday'), false, get_config('feature_lock','events_cal_first_day') - ], - - [ - 'smart_birthdays', - t('Smart Birthdays'), - t('Make birthday events timezone aware in case your friends are scattered across the planet.'), - true, - get_config('feature_lock','smart_birthdays'), - ], - - [ - 'event_tz_select', - t('Event Timezone Selection'), - t('Allow event creation in timezones other than your own.'), - false, - get_config('feature_lock','event_tz_select'), ] ], diff --git a/include/follow.php b/include/follow.php index 1b35f1b32..50b952881 100644 --- a/include/follow.php +++ b/include/follow.php @@ -142,7 +142,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) $sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : ''); - $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' $sql_options limit 1", + $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' $sql_options ", dbesc($url), dbesc($url) ); @@ -169,18 +169,19 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) } if($wf || $d) { - $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1", + $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s'", dbesc(($wf) ? $wf : $url), dbesc($url) ); } } + $xchan = zot_record_preferred($r,'xchan_network'); + // if discovery was a success we should have an xchan record in $r - if($r) { - $xchan = $r[0]; - $xchan_hash = $r[0]['xchan_hash']; + if($xchan) { + $xchan_hash = $xchan['xchan_hash']; $their_perms = 0; } } @@ -191,9 +192,9 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) return $result; } - $allowed = (($is_zot || in_array($r[0]['xchan_network'],['rss','zot6'])) ? 1 : 0); + $allowed = (($is_zot || in_array($xchan['xchan_network'],['rss','zot6'])) ? 1 : 0); - $x = array('channel_id' => $uid, 'follow_address' => $url, 'xchan' => $r[0], 'allowed' => $allowed, 'singleton' => 0); + $x = array('channel_id' => $uid, 'follow_address' => $url, 'xchan' => $xchan, 'allowed' => $allowed, 'singleton' => 0); call_hooks('follow_allow',$x); diff --git a/include/import.php b/include/import.php index 7a1e9aa55..4da0d1a0b 100644 --- a/include/import.php +++ b/include/import.php @@ -94,7 +94,8 @@ function import_channel($channel, $account_id, $seize, $newname = '') { 'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall', 'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish', 'channel_a_delegate', 'perm_limits', 'channel_password', 'channel_salt', - 'channel_moved', 'channel_removed', 'channel_deleted', 'channel_system' + 'channel_moved', 'channel_removed', 'channel_deleted', 'channel_system', + 'channel_r_photos', 'channel_w_photos' ]; $clean = array(); @@ -896,9 +897,9 @@ function import_menus($channel, $menus) { $m['menu_name'] = $menu['pagetitle']; $m['menu_desc'] = $menu['desc']; if($menu['created']) - $m['menu_created'] = datetime_convert($menu['created']); + $m['menu_created'] = datetime_convert('UTC','UTC',$menu['created']); if($menu['edited']) - $m['menu_edited'] = datetime_convert($menu['edited']); + $m['menu_edited'] = datetime_convert('UTC','UTC',$menu['edited']); $m['menu_flags'] = 0; if($menu['flags']) { @@ -954,9 +955,9 @@ function sync_menus($channel, $menus) { $m['menu_name'] = $menu['pagetitle']; $m['menu_desc'] = $menu['desc']; if($menu['created']) - $m['menu_created'] = datetime_convert($menu['created']); + $m['menu_created'] = datetime_convert('UTC','UTC',$menu['created']); if($menu['edited']) - $m['menu_edited'] = datetime_convert($menu['edited']); + $m['menu_edited'] = datetime_convert('UTC','UTC',$menu['edited']); $m['menu_flags'] = 0; if($menu['flags']) { @@ -1345,6 +1346,7 @@ function sync_files($channel, $files) { logger('attachment store failed',LOGGER_NORMAL,LOG_ERR); } if($f['photo']) { + foreach($f['photo'] as $p) { unset($p['id']); $p['aid'] = $channel['channel_account_id']; @@ -1366,6 +1368,7 @@ function sync_files($channel, $files) { dbesc($p['resource_id']), intval($channel['channel_id']) ); + $update_xchan = $p['edited']; } // same for cover photos @@ -1385,19 +1388,20 @@ function sync_files($channel, $files) { else $p['content'] = (($p['content'])? base64_decode($p['content']) : ''); - if(intval($p['imgscale']) && (! $p['content'])) { + if(intval($p['imgscale']) && (! empty($p['content']))) { $time = datetime_convert(); - $parr = array('hash' => $channel['channel_hash'], + $parr = array( + 'hash' => $channel['channel_hash'], 'time' => $time, - 'resource' => $att['hash'], + 'resource' => $p['resource_id'], 'revision' => 0, 'signature' => base64url_encode(rsa_sign($channel['channel_hash'] . '.' . $time, $channel['channel_prvkey'])), - 'resolution' => $p['imgscale'] + 'resolution' => intval($p['imgscale']) ); - $stored_image = $newfname . '-' . intval($p['imgscale']); + $stored_image = $newfname . '-' . $p['imgscale']; $fp = fopen($stored_image,'w'); if(! $fp) { @@ -1406,7 +1410,6 @@ function sync_files($channel, $files) { } $redirects = 0; - $headers = []; $headers['Accept'] = 'application/x-zot+json' ; $headers['Sigtoken'] = random_string(); @@ -1414,8 +1417,17 @@ function sync_files($channel, $files) { $x = z_post_url($fetch_url,$parr,$redirects,[ 'filep' => $fp, 'headers' => $headers]); fclose($fp); - $p['content'] = file_get_contents($stored_image); - unlink($stored_image); + + // Override remote hub thumbnails storage settings + if(! boolval(get_config('system','filesystem_storage_thumbnails', 0))) { + $p['os_storage'] = 0; + $p['content'] = file_get_contents($stored_image); + @unlink($stored_image); + } + else { + $p['os_storage'] = 1; + $p['content'] = $stored_image; + } } if(!isset($p['display_path'])) @@ -1447,6 +1459,16 @@ function sync_files($channel, $files) { create_table_from_array('photo',$p, [ 'content' ] ); } } + + } + + // Set xchan photo date to prevent thumbnails fetch for clones on profile update packet recieve + if(isset($update_xchan)) { + + $x = q("UPDATE xchan SET xchan_photo_date = '%s' WHERE xchan_hash = '%s'", + dbescdate($update_xchan), + dbesc($channel['channel_hash']) + ); } \Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $att['hash'] ]); @@ -1621,12 +1643,12 @@ function import_webpage_element($element, $channel, $type) { $arr['created'] = $iteminfo[0]['created']; } else { // otherwise, generate the creation times and unique id - $arr['created'] = datetime_convert('UTC', 'UTC'); + $arr['created'] = datetime_convert(); $arr['uuid'] = item_message_id(); $arr['mid'] = $arr['parent_mid'] = z_root() . '/item/' . $arr['uuid']; } // Update the edited time whether or not the element already exists - $arr['edited'] = datetime_convert('UTC', 'UTC'); + $arr['edited'] = datetime_convert(); // Import the actual element content $arr['body'] = file_get_contents($element['path']); // The element owner is the channel importing the elements diff --git a/include/items.php b/include/items.php index c08deb3a0..95b696034 100755 --- a/include/items.php +++ b/include/items.php @@ -4278,7 +4278,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C if($arr['mid']) $sql_options .= " and parent_mid = '" . dbesc($arr['mid']) . "' "; - $sql_extra = " AND item.parent IN ( SELECT parent FROM item WHERE item_thread_top = 1 $sql_options $item_normal ) "; + $sql_extra = " AND item.parent IN ( SELECT parent FROM item WHERE $item_uids and item_thread_top = 1 $sql_options $item_normal ) "; if($arr['since_id']) $sql_extra .= " and item.id > " . $since_id . " "; diff --git a/include/js_strings.php b/include/js_strings.php index c053e5666..f01fa87ae 100644 --- a/include/js_strings.php +++ b/include/js_strings.php @@ -33,6 +33,7 @@ function js_strings() { '$name_empty' => t('A channel name is required.'), '$name_ok1' => t('This is a '), '$name_ok2' => t(' channel name'), + '$to_reply' => t('Back to reply'), // translatable prefix and suffix strings for jquery.timeago - // using the defaults set below if left untranslated, empty strings if diff --git a/include/markdown.php b/include/markdown.php index 2513a7d77..7d1f16958 100644 --- a/include/markdown.php +++ b/include/markdown.php @@ -76,6 +76,8 @@ function markdown_to_bb($s, $use_zrl = false, $options = []) { $s = html2bbcode($s); + $s = bb_code_protect($s); + // Convert everything that looks like a link to a link if($use_zrl) { if (strpos($s,'[/img]') !== false) { @@ -88,6 +90,8 @@ function markdown_to_bb($s, $use_zrl = false, $options = []) { $s = preg_replace("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", '$1[url=$2$3]$2$3[/url]',$s); } + $s = bb_code_unprotect($s); + // remove duplicate adjacent code tags $s = preg_replace("/(\[code\])+(.*?)(\[\/code\])+/ism","[code]$2[/code]", $s); diff --git a/include/oembed.php b/include/oembed.php index 426197c5f..ee9e57c3f 100755 --- a/include/oembed.php +++ b/include/oembed.php @@ -1,6 +1,6 @@ <?php /** @file */ -use Zotlabs\Lib as Zlib; +use Zotlabs\Lib\Cache; function oembed_replacecb($matches){ @@ -133,7 +133,6 @@ function oembed_fetch_url($embedurl){ } } - $txt = null; // we should try to cache this and avoid a lookup on each render @@ -143,10 +142,22 @@ function oembed_fetch_url($embedurl){ $furl = ((local_channel() && $zrl) ? zid($embedurl) : $embedurl); - if($action !== 'block') { - $txt = Zlib\Cache::get('[' . App::$videowidth . '] ' . $furl); + if($action !== 'block' && (! get_config('system','oembed_cache_disable'))) { + $txt = Cache::get('[' . App::$videowidth . '] ' . $furl); } + + if(strpos(strtolower($embedurl),'.pdf') !== false) { + $action = 'allow'; + $j = [ + 'html' => '<object data="' . $embedurl . '" type="application/pdf" style="width: 100%; height: 300px;"></object>', + 'title' => t('View PDF'), + 'type' => 'pdf' + ]; + // set $txt to something so that we don't attempt to fetch what could be a lengthy pdf. + $txt = EMPTY_STR; + } + if(is_null($txt)) { $txt = ""; @@ -215,20 +226,10 @@ function oembed_fetch_url($embedurl){ // save in cache if(! get_config('system','oembed_cache_disable')) - Zlib\Cache::set('[' . App::$videowidth . '] ' . $furl, $txt); + Cache::set('[' . App::$videowidth . '] ' . $furl, $txt); } - if(strpos(strtolower($embedurl),'.pdf') !== false) { - $action = 'allow'; - $j = [ - 'html' => '<object data="' . $embedurl . '" type="application/pdf" style="width: 100%; height: 300px;"></object>', - 'title' => t('View PDF'), - 'type' => 'pdf' - ]; - - } - if(! $j) { $j = json_decode($txt,true); } diff --git a/include/photos.php b/include/photos.php index 44406e0b0..7ea2729ae 100644 --- a/include/photos.php +++ b/include/photos.php @@ -277,8 +277,7 @@ function photo_upload($channel, $observer, $args) { if(($width > 1024 || $height > 1024) && (! $errors)) $ph->scaleImage(1024); - $p['imgscale'] = 1; - $r1 = $ph->save($p); + $r1 = $ph->storeThumbnail($p, PHOTO_RES_1024); $link[1] = array( 'rel' => 'alternate', 'type' => 'text/html', @@ -292,8 +291,7 @@ function photo_upload($channel, $observer, $args) { if(($width > 640 || $height > 640) && (! $errors)) $ph->scaleImage(640); - $p['imgscale'] = 2; - $r2 = $ph->save($p); + $r2 = $ph->storeThumbnail($p, PHOTO_RES_640); $link[2] = array( 'rel' => 'alternate', 'type' => 'text/html', @@ -307,8 +305,7 @@ function photo_upload($channel, $observer, $args) { if(($width > 320 || $height > 320) && (! $errors)) $ph->scaleImage(320); - $p['imgscale'] = 3; - $r3 = $ph->save($p); + $r3 = $ph->storeThumbnail($p, PHOTO_RES_320); $link[3] = array( 'rel' => 'alternate', 'type' => 'text/html', diff --git a/include/text.php b/include/text.php index 41603f6e4..a2dfda952 100644 --- a/include/text.php +++ b/include/text.php @@ -409,7 +409,8 @@ function autoname($len) { * @return string Escaped text. */ function xmlify($str) { - $buffer = ''; + + //$buffer = ''; if(is_array($str)) { @@ -418,7 +419,7 @@ function xmlify($str) { btlogger('xmlify called with array: ' . print_r($str,true), LOGGER_NORMAL, LOG_WARNING); } - +/* $len = mb_strlen($str); for($x = 0; $x < $len; $x ++) { $char = mb_substr($str,$x,1); @@ -452,6 +453,11 @@ function xmlify($str) { $buffer = trim($buffer); return($buffer); +*/ + $buffer = htmlspecialchars($str, ENT_QUOTES, "UTF-8"); + $buffer = trim($buffer); + return $buffer; + } /** @@ -464,10 +470,23 @@ function xmlify($str) { * @return string */ function unxmlify($s) { +/* $ret = str_replace('&', '&', $s); $ret = str_replace(array('<', '>', '"', '''), array('<', '>', '"', "'"), $ret); return $ret; +*/ + + if(is_array($s)) { + + // allow to fall through so we ge a PHP error, as the log statement will + // probably get lost in the noise unless we're specifically looking for it. + + btlogger('unxmlify called with array: ' . print_r($s,true), LOGGER_NORMAL, LOG_WARNING); + } + + $ret = htmlspecialchars_decode($s, ENT_QUOTES); + return $ret; } /** @@ -3071,13 +3090,12 @@ function item_url_replace($channel,&$item,$old,$new,$oldnick = '') { if($oldnick) json_url_replace('/' . $oldnick . '/' ,'/' . $channel['channel_address'] . '/' ,$item['target']); } + + $item['body'] = preg_replace("/(\[zrl=".preg_quote($old,'/')."\/(photo|photos|gallery)\/".$channel['channel_address'].".+\]\[zmg=\d+x\d+\])".preg_quote($old,'/')."\/(.+\[\/zmg\])/", '${1}'.$new.'/${3}', $item['body']); + $item['body'] = preg_replace("/".preg_quote($old,'/')."\/(search|\w+\/".$channel['channel_address'].")/", $new.'/${1}', $item['body']); - $x = preg_replace("/".preg_quote($old,'/')."\/(search|\w+\/".$channel['channel_address'].")/", $new.'/${1}', $item['body']); - if($x) { - $item['body'] = $x; - $item['sig'] = base64url_encode(rsa_sign($item['body'],$channel['channel_prvkey'])); - $item['item_verified'] = 1; - } + $item['sig'] = base64url_encode(rsa_sign($item['body'],$channel['channel_prvkey'])); + $item['item_verified'] = 1; $item['plink'] = str_replace($old,$new,$item['plink']); if($oldnick) diff --git a/include/zot.php b/include/zot.php index 5ced4ee8c..a37b7cdb5 100644 --- a/include/zot.php +++ b/include/zot.php @@ -925,46 +925,62 @@ function import_xchan($arr, $ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { $local = q("select channel_account_id, channel_id from channel where channel_hash = '%s' limit 1", dbesc($xchan_hash) ); + if($local) { + // @FIXME This should be removed in future when profile photo update by file sync procedure will be applied + // on most hubs in the network + // <--- $ph = z_fetch_url($arr['photo'], true); + if($ph['success']) { + + // Do not fetch already received thumbnails + $x = q("SELECT resource_id FROM photo WHERE uid = %d AND imgscale = %d AND filesize = %d LIMIT 1", + intval($local[0]['channel_id']), + intval(PHOTO_RES_PROFILE_300), + strlen($ph['body']) + ); + + if($x) + $hash = $x[0]['resource_id']; + else + $hash = import_channel_photo($ph['body'], $arr['photo_mimetype'], $local[0]['channel_account_id'], $local[0]['channel_id']); + } + + if($hash) { + // unless proven otherwise + $is_default_profile = 1; + + $profile = q("select is_default from profile where aid = %d and uid = %d limit 1", + intval($local[0]['channel_account_id']), + intval($local[0]['channel_id']) + ); + if($profile) { + if(! intval($profile[0]['is_default'])) + $is_default_profile = 0; + } - $hash = import_channel_photo($ph['body'], $arr['photo_mimetype'], $local[0]['channel_account_id'], $local[0]['channel_id']); - - if($hash) { - // unless proven otherwise - $is_default_profile = 1; - - $profile = q("select is_default from profile where aid = %d and uid = %d limit 1", + // If setting for the default profile, unset the profile photo flag from any other photos I own + if($is_default_profile) { + q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND resource_id != '%s' AND aid = %d AND uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + dbesc($hash), intval($local[0]['channel_account_id']), intval($local[0]['channel_id']) ); - if($profile) { - if(! intval($profile[0]['is_default'])) - $is_default_profile = 0; - } - - // If setting for the default profile, unset the profile photo flag from any other photos I own - if($is_default_profile) { - q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND resource_id != '%s' AND aid = %d AND uid = %d", - intval(PHOTO_NORMAL), - intval(PHOTO_PROFILE), - dbesc($hash), - intval($local[0]['channel_account_id']), - intval($local[0]['channel_id']) - ); - } } - - // reset the names in case they got messed up when we had a bug in this function - $photos = array( - z_root() . '/photo/profile/l/' . $local[0]['channel_id'], - z_root() . '/photo/profile/m/' . $local[0]['channel_id'], - z_root() . '/photo/profile/s/' . $local[0]['channel_id'], - $arr['photo_mimetype'], - false - ); } + // ---> + + // reset the names in case they got messed up when we had a bug in this function + $photos = array( + z_root() . '/photo/profile/l/' . $local[0]['channel_id'], + z_root() . '/photo/profile/m/' . $local[0]['channel_id'], + z_root() . '/photo/profile/s/' . $local[0]['channel_id'], + $arr['photo_mimetype'], + false + ); } else { $photos = import_xchan_photo($arr['photo'], $xchan_hash); @@ -3634,7 +3650,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { 'channel_r_storage', 'channel_r_pages', 'channel_w_stream', 'channel_w_wall', 'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall', 'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish', - 'channel_a_delegate', 'channel_moved' + 'channel_a_delegate', 'channel_moved', 'channel_r_photos', 'channel_w_photos' ]; $clean = array(); @@ -4414,7 +4430,7 @@ function zotinfo($arr) { $profile['description'] = $p[0]['pdesc']; $profile['birthday'] = $p[0]['dob']; - if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],$e['channel_timezone'])) !== '')) + if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],'UTC')) !== '')) $profile['next_birthday'] = $bd; if($age = age($p[0]['dob'],$e['channel_timezone'],'')) |