diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/Contact.php | 2 | ||||
-rw-r--r-- | include/ConversationObject.php | 10 | ||||
-rw-r--r-- | include/api.php | 17 | ||||
-rw-r--r-- | include/bbcode.php | 8 | ||||
-rw-r--r-- | include/cache.php | 47 | ||||
-rw-r--r-- | include/conversation.php | 113 | ||||
-rw-r--r-- | include/directory.php | 5 | ||||
-rw-r--r-- | include/enotify.php | 30 | ||||
-rw-r--r-- | include/expire.php | 29 | ||||
-rw-r--r-- | include/externals.php | 97 | ||||
-rw-r--r-- | include/follow.php | 6 | ||||
-rw-r--r-- | include/hubloc.php | 33 | ||||
-rw-r--r-- | include/identity.php | 63 | ||||
-rwxr-xr-x | include/items.php | 183 | ||||
-rw-r--r-- | include/nav.php | 2 | ||||
-rw-r--r-- | include/network.php | 38 | ||||
-rw-r--r-- | include/notifier.php | 11 | ||||
-rwxr-xr-x | include/oembed.php | 5 | ||||
-rw-r--r-- | include/permissions.php | 28 | ||||
-rw-r--r-- | include/photos.php | 13 | ||||
-rw-r--r-- | include/poller.php | 22 | ||||
-rw-r--r-- | include/probe.php | 99 | ||||
-rw-r--r-- | include/queue.php | 8 | ||||
-rw-r--r-- | include/reddav.php | 18 | ||||
-rw-r--r-- | include/security.php | 16 | ||||
-rw-r--r-- | include/socgraph.php | 5 | ||||
-rwxr-xr-x | include/text.php | 63 | ||||
-rw-r--r-- | include/widgets.php | 2 | ||||
-rw-r--r-- | include/zot.php | 130 |
29 files changed, 851 insertions, 252 deletions
diff --git a/include/Contact.php b/include/Contact.php index 9883c598d..540e1169d 100644 --- a/include/Contact.php +++ b/include/Contact.php @@ -263,7 +263,7 @@ function channel_remove($channel_id, $local = true) { q("DELETE FROM `event` WHERE `uid` = %d", intval($channel_id)); q("DELETE FROM `item` WHERE `uid` = %d", intval($channel_id)); q("DELETE FROM `item_id` WHERE `uid` = %d", intval($channel_id)); - q("DELETE FROM `mail` WHERE `uid` = %d", intval($channel_id)); + q("DELETE FROM `mail` WHERE `channel_id` = %d", intval($channel_id)); q("DELETE FROM `notify` WHERE `uid` = %d", intval($channel_id)); q("DELETE FROM `photo` WHERE `uid` = %d", intval($channel_id)); q("DELETE FROM `attach` WHERE `uid` = %d", intval($channel_id)); diff --git a/include/ConversationObject.php b/include/ConversationObject.php index 103c3664b..d97438a5d 100644 --- a/include/ConversationObject.php +++ b/include/ConversationObject.php @@ -52,8 +52,14 @@ class Conversation extends BaseObject { switch($mode) { case 'network': - $this->profile_owner = local_user(); - $this->writable = true; + if(array_key_exists('firehose',$a->data) && intval($a->data['firehose'])) { + $this->profile_owner = intval($a->data['firehose']); + $this->writable = false; + } + else { + $this->profile_owner = local_user(); + $this->writable = true; + } break; case 'channel': $this->profile_owner = $a->profile['profile_uid']; diff --git a/include/api.php b/include/api.php index 47c78113a..57551a3b0 100644 --- a/include/api.php +++ b/include/api.php @@ -533,12 +533,6 @@ require_once('include/items.php'); api_register_func('api/red/channel/export/basic','api_export_basic', true); - - - - - - function api_channel_stream(&$a, $type) { if(api_user() === false) { logger('api_channel_stream: no user'); @@ -700,12 +694,12 @@ require_once('include/items.php'); function red_item_new(&$a, $type) { if (api_user() === false) { - logger('api_statuses_update: no user'); + logger('api_red_item_new: no user'); return false; } - logger('api_statuses_update: REQUEST ' . print_r($_REQUEST,true)); - logger('api_statuses_update: FILES ' . print_r($_FILES,true)); + logger('api_red_item_new: REQUEST ' . print_r($_REQUEST,true)); + logger('api_red_item_new: FILES ' . print_r($_FILES,true)); // set this so that the item_post() function is quiet and doesn't redirect or emit json @@ -1552,7 +1546,8 @@ require_once('include/items.php'); 'geo' => '', 'favorited' => (($item['item_flags'] & ITEM_STARRED) ? true : false), 'user' => $status_user , - 'statusnet_html' => trim(prepare_text($item['body']),$item['mimetype']), + 'statusnet_html' => trim(prepare_text($item['body'],$item['mimetype'])), + 'statusnet_conversation_id' => $item['parent'], ); @@ -1697,7 +1692,7 @@ require_once('include/items.php'); 'broughtbyurl' => '', 'timezone' => 'UTC', 'closed' => $closed, 'inviteonly' => 'false', 'private' => $private, 'textlimit' => $textlimit, 'sslserver' => $sslserver, 'ssl' => $ssl, 'shorturllength' => '30', - 'friendica' => array( + 'redmatrix' => array( 'RED_PLATFORM' => RED_PLATFORM, 'RED_VERSION' => RED_VERSION, 'ZOT_REVISION' => ZOT_REVISION, diff --git a/include/bbcode.php b/include/bbcode.php index cd0bf527e..96242fdac 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -229,9 +229,11 @@ function bb_location($match) { function bbiframe($match) { $a = get_app(); - if(strpos($match[1],get_app()->get_hostname())) - return '<a href="' . $match[1] . '">' . $match[1] . '</a>'; - return '<iframe src="' . $match[1] . '" width="' . $a->videowidth . '" height="' . $a->videoheight . '"><a href="' . $match[1] . '">' . $match[1] . '</a></iframe>'; + + + $sandbox = ((strpos($match[1],get_app()->get_hostname())) ? ' sandbox="allow-scripts" ' : ''); + + return '<iframe ' . $sandbox . ' src="' . $match[1] . '" width="' . $a->videowidth . '" height="' . $a->videoheight . '"><a href="' . $match[1] . '">' . $match[1] . '</a></iframe>'; } function bb_ShareAttributesSimple($match) { diff --git a/include/cache.php b/include/cache.php index b546cd0e9..a70650b5e 100644 --- a/include/cache.php +++ b/include/cache.php @@ -6,52 +6,37 @@ class Cache { public static function get($key){ - $r = q("SELECT `v` FROM `cache` WHERE `k`='%s' limit 1", + $r = q("SELECT v FROM cache WHERE k = '%s' limit 1", dbesc($key) ); - if (count($r)) return $r[0]['v']; + if ($r) + return $r[0]['v']; return null; } public static function set($key,$value) { - q("REPLACE INTO `cache` (`k`,`v`,`updated`) VALUES ('%s','%s','%s')", + $r = q("SELECT * FROM cache WHERE k = '%s' limit 1", + dbesc($key) + ); + if($r) { + q("UPDATE cache SET v = '%s', updated = '%s' WHERE k = '%s' limit 1", + dbesc($value), + dbesc(datetime_convert()), + dbesc($key)); + } + else { + q("INSERT INTO cache ( k, v, updated) VALUES ('%s','%s','%s')", dbesc($key), dbesc($value), dbesc(datetime_convert())); + } } -/* - * - * Leaving this legacy code temporaily to see how REPLACE fares - * as opposed to non-atomic checks when faced with fast moving key duplication. - * As a MySQL extension it isn't portable, but we're not yet very portable. - */ - -/* - * $r = q("SELECT * FROM `cache` WHERE `k`='%s' limit 1", - * dbesc($key) - * ); - * if(count($r)) { - * q("UPDATE `cache` SET `v` = '%s', `updated = '%s' WHERE `k` = '%s' limit 1", - * dbesc($value), - * dbesc(datetime_convert()), - * dbesc($key)); - * } - * else { - * q("INSERT INTO `cache` (`k`,`v`,`updated`) VALUES ('%s','%s','%s')", - * dbesc($key), - * dbesc($value), - * dbesc(datetime_convert())); - * } - * } - */ - - public static function clear(){ - q("DELETE FROM `cache` WHERE `updated` < '%s'", + q("DELETE FROM cache WHERE updated < '%s'", dbesc(datetime_convert('UTC','UTC',"now - 30 days"))); } diff --git a/include/conversation.php b/include/conversation.php index 16ac4e909..9ffa1e77a 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -635,7 +635,11 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $ $star = false; $isstarred = "unstarred icon-star-empty"; - $lock = false; + $lock = (($item['item_private'] || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) + ? t('Private Message') + : false + ); + $likebuttons = false; $shareable = false; @@ -911,7 +915,7 @@ function item_photo_menu($item){ } } - $profile_link = z_root() . "/chanview/?f=&hash=" . $item['author_xchan']; + $profile_link = chanlink_hash($item['author_xchan']); $pm_url = $a->get_baseurl($ssl_state) . '/mail/new/?f=&hash=' . $item['author_xchan']; if($a->contacts && array_key_exists($item['author_xchan'],$a->contacts)) @@ -964,13 +968,7 @@ function like_puller($a,$item,&$arr,$mode) { $verb = (($mode === 'like') ? ACTIVITY_LIKE : ACTIVITY_DISLIKE); if((activity_match($item['verb'],$verb)) && ($item['id'] != $item['parent'])) { - $url = $item['author']['xchan_url']; - if((local_user()) && (local_user() == $item['uid']) && ($item['network'] === 'dfrn') && (! $item['self']) && (link_compare($item['author-link'],$item['url']))) { - $url = $a->get_baseurl(true) . '/redir/' . $item['contact-id']; - $sparkle = ' class="sparkle" '; - } - else - $url = zid($url); + $url = chanlink_url($item['author']['xchan_url']); if(! $item['thr_parent']) $item['thr_parent'] = $item['parent_mid']; @@ -981,7 +979,7 @@ function like_puller($a,$item,&$arr,$mode) { $arr[$item['thr_parent']] = 1; else $arr[$item['thr_parent']] ++; - $arr[$item['thr_parent'] . '-l'][] = '<a href="'. $url . '"'. $sparkle .'>' . $item['author']['xchan_name'] . '</a>'; + $arr[$item['thr_parent'] . '-l'][] = '<a href="'. $url . '">' . $item['author']['xchan_name'] . '</a>'; } return; } @@ -1052,6 +1050,13 @@ function status_editor($a,$x,$popup=false) { } + if(array_key_exists('channel_select',$x) && $x['channel_select']) { + require_once('include/identity.php'); + $id_select = identity_selector(); + } + else + $id_select = ''; + $webpage = ((x($x,'webpage')) ? $x['webpage'] : ''); @@ -1098,6 +1103,8 @@ function status_editor($a,$x,$popup=false) { '$webpage' => $webpage, '$placeholdpagetitle' => ((x($x,'ptlabel')) ? $x['ptlabel'] : t('Page link title')), '$pagetitle' => (x($x,'pagetitle') ? $x['pagetitle'] : ''), + '$id_select' => $id_select, + '$id_seltext' => t('Post as'), '$upload' => t('Upload photo'), '$shortupload' => t('upload photo'), '$attach' => t('Attach file'), @@ -1126,7 +1133,6 @@ function status_editor($a,$x,$popup=false) { '$baseurl' => $a->get_baseurl(true), '$defloc' => $x['default_location'], '$visitor' => $x['visitor'], - '$pvisit' => (($notes_cid) ? 'none' : $x['visitor']), '$public' => t('Public post'), '$jotnets' => $jotnets, '$emtitle' => t('Example: bob@example.com, mary@example.com'), @@ -1134,16 +1140,16 @@ function status_editor($a,$x,$popup=false) { '$acl' => $x['acl'], '$mimeselect' => $mimeselect, '$layoutselect' => $layoutselect, - '$showacl' => ((array_key_exists('showacl',$x)) ? $x['showacl'] : 'yes'), + '$showacl' => ((array_key_exists('showacl',$x)) ? $x['showacl'] : true), '$bang' => $x['bang'], '$profile_uid' => $x['profile_uid'], '$preview' => $preview, '$source' => ((x($x,'source')) ? $x['source'] : ''), '$jotplugins' => $jotplugins, '$defexpire' => '', - '$feature_expire' => ((feature_enabled($x['profile_uid'],'content_expire') && (! $webpage)) ? 'block' : 'none'), + '$feature_expire' => ((feature_enabled($x['profile_uid'],'content_expire') && (! $webpage)) ? true : false), '$expires' => t('Set expiration date'), - '$feature_encrypt' => ((feature_enabled($x['profile_uid'],'content_encrypt') && (! $webpage)) ? 'block' : 'none'), + '$feature_encrypt' => ((feature_enabled($x['profile_uid'],'content_encrypt') && (! $webpage)) ? true : false), '$encrypt' => t('Encrypt text'), '$cipher' => $cipher, '$expiryModalOK' => t('OK'), @@ -1287,7 +1293,7 @@ function render_location_default($item) { if($coord) { if($location) - $location .= '<br /><span class="smalltext">(' . $coord . ')</span>'; + $location .= ' <span class="smalltext">(' . $coord . ')</span>'; else $location = '<span class="smalltext">' . $coord . '</span>'; } @@ -1333,6 +1339,7 @@ function network_tabs() { $conv_active = ''; $spam_active = ''; $postord_active = ''; + $public_active = ''; if(x($_GET,'new')) { $new_active = 'active'; @@ -1354,13 +1361,18 @@ function network_tabs() { $spam_active = 'active'; } + if(x($_GET,'fh')) { + $public_active = 'active'; + } + if (($new_active == '') && ($starred_active == '') && ($conv_active == '') && ($search_active == '') - && ($spam_active == '')) { + && ($spam_active == '') + && ($public_active == '')) { $no_active = 'active'; } @@ -1376,52 +1388,67 @@ function network_tabs() { $cmd = $a->cmd; // tabs - $tabs = array( - array( - 'label' => t('Commented Order'), - 'url'=>$a->get_baseurl(true) . '/' . $cmd . '?f=&order=comment' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . ((x($_GET,'gid')) ? '&gid=' . $_GET['gid'] : ''), - 'sel'=>$all_active, - 'title'=> t('Sort by Comment Date'), - ), - array( - 'label' => t('Posted Order'), - 'url'=>$a->get_baseurl(true) . '/' . $cmd . '?f=&order=post' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . ((x($_GET,'gid')) ? '&gid=' . $_GET['gid'] : ''), - 'sel'=>$postord_active, - 'title' => t('Sort by Post Date'), - ), + $tabs = array(); - array( + if(! get_config('system','disable_discover_tab')) { + $tabs[] = array( + 'label' => t('Discover'), + 'url'=>$a->get_baseurl(true) . '/' . $cmd . '?f=&fh=1' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . ((x($_GET,'gid')) ? '&gid=' . $_GET['gid'] : ''), + 'sel'=> $public_active, + 'title'=> t('Imported public streams'), + ); + } + + $tabs[] = array( + 'label' => t('Commented Order'), + 'url'=>$a->get_baseurl(true) . '/' . $cmd . '?f=&order=comment' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . ((x($_GET,'gid')) ? '&gid=' . $_GET['gid'] : ''), + 'sel'=>$all_active, + 'title'=> t('Sort by Comment Date'), + ); + + $tabs[] = array( + 'label' => t('Posted Order'), + 'url'=>$a->get_baseurl(true) . '/' . $cmd . '?f=&order=post' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . ((x($_GET,'gid')) ? '&gid=' . $_GET['gid'] : ''), + 'sel'=>$postord_active, + 'title' => t('Sort by Post Date'), + ); + + if(feature_enabled(local_user(),'personal_tab')) { + $tabs[] = array( 'label' => t('Personal'), 'url' => $a->get_baseurl(true) . '/' . $cmd . '?f=' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . '&conv=1', 'sel' => $conv_active, 'title' => t('Posts that mention or involve you'), - ), - array( + ); + } + + if(feature_enabled(local_user(),'new_tab')) { + $tabs[] = array( 'label' => t('New'), 'url' => $a->get_baseurl(true) . '/' . $cmd . '?f=' . ((x($_GET,'cid')) ? '&cid=' . $_GET['cid'] : '') . '&new=1' . ((x($_GET,'gid')) ? '&gid=' . $_GET['gid'] : ''), 'sel' => $new_active, 'title' => t('Activity Stream - by date'), - ), - - ); + ); + } - if(feature_enabled(local_user(),'star_posts')) + if(feature_enabled(local_user(),'star_posts')) { $tabs[] = array( 'label' => t('Starred'), 'url'=>$a->get_baseurl(true) . '/' . $cmd . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : '') . '&star=1', 'sel'=>$starred_active, 'title' => t('Favourite Posts'), ); - + } // Not yet implemented - if(feature_enabled(local_user(),'spam_filter')) + if(feature_enabled(local_user(),'spam_filter')) { $tabs[] = array( 'label' => t('Spam'), 'url'=>$a->get_baseurl(true) . '/network?f=&spam=1', 'sel'=> $spam_active, 'title' => t('Posts flagged as SPAM'), - ); + ); + } $arr = array('tabs' => $tabs); call_hooks('network_tabs', $arr); @@ -1442,6 +1469,8 @@ function profile_tabs($a, $is_owner=False, $nickname=Null){ if (is_null($nickname)) $nickname = $channel['channel_address']; + + $uid = (($a->profile['profile_uid']) ? $a->profile['profile_uid'] : local_user()); if(x($_GET,'tab')) $tab = notags(trim($_GET['tab'])); @@ -1459,7 +1488,7 @@ function profile_tabs($a, $is_owner=False, $nickname=Null){ ), ); - $p = get_all_perms($a->profile['profile_uid'],get_observer_hash()); + $p = get_all_perms($uid,get_observer_hash()); if($p['view_profile']) { $tabs[] = array( @@ -1490,7 +1519,7 @@ function profile_tabs($a, $is_owner=False, $nickname=Null){ } require_once('include/chat.php'); - $chats = chatroom_list($a->profile['profile_uid']); + $chats = chatroom_list($uid); $subdued = ((count($chats)) ? '' : ' subdued'); $tabs[] = array( 'label' => t('Chatrooms'), @@ -1520,7 +1549,7 @@ function profile_tabs($a, $is_owner=False, $nickname=Null){ } - if($is_owner && feature_enabled($a->profile['profile_uid'],'webpages')) { + if($is_owner && feature_enabled($uid,'webpages')) { $tabs[] = array( 'label' => t('Webpages'), 'url' => $a->get_baseurl() . '/webpages/' . $nickname, diff --git a/include/directory.php b/include/directory.php index 794420b6f..c69fb1f4b 100644 --- a/include/directory.php +++ b/include/directory.php @@ -69,11 +69,12 @@ function directory_run($argv, $argc){ // the directory packet. That means we'll try again on the next poll run. $hash = random_string(); - q("insert into outq ( outq_hash, outq_account, outq_channel, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) - values ( '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s' )", + q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) + values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", dbesc($hash), intval($channel['channel_account_id']), intval($channel['channel_id']), + dbesc('zot'), dbesc($url), intval(1), dbesc(datetime_convert()), diff --git a/include/enotify.php b/include/enotify.php index 036d5275e..7ab4fe5ed 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -18,8 +18,9 @@ function notification($params) { } if($params['to_xchan']) { $y = q("select channel.*, account.* from channel left join account on channel_account_id = account_id - where channel_hash = '%s' limit 1", - dbesc($params['to_xchan']) + where channel_hash = '%s' and not (channel_pageflags & %d) limit 1", + dbesc($params['to_xchan']), + intval(PAGE_REMOVED) ); } if($x & $y) { @@ -88,7 +89,7 @@ function notification($params) { $sitelink = t('Please visit %s to view and/or reply to your private messages.'); $tsitelink = sprintf( $sitelink, $siteurl . '/mail/' . $params['item']['id'] ); $hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '/mail/' . $params['item']['id'] . '">' . $sitename . '</a>'); - $itemlink = $siteurl . '/message/' . $params['item']['id']; + $itemlink = $siteurl . '/mail/' . $params['item']['id']; } if($params['type'] == NOTIFY_COMMENT) { @@ -102,7 +103,7 @@ function notification($params) { if(array_key_exists('item',$params) && (! visible_activity($params['item']))) return; - $parent_id = $params['parent']; + $parent_mid = $params['parent_mid']; // Check to see if there was already a notify for this post. // If so don't create a second notification @@ -123,9 +124,9 @@ function notification($params) { $p = null; - if($params['otype'] === 'item' && $parent_id) { - $p = q("select * from item where id = %d and uid = %d limit 1", - intval($parent_id), + if($params['otype'] === 'item' && $parent_mid) { + $p = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc($parent_mid), intval($recip['channel_id']) ); } @@ -135,6 +136,7 @@ function notification($params) { $item_post_type = item_post_type($p[0]); $private = $p[0]['item_private']; + $parent_id = $p[0]['id']; //$possess_desc = str_replace('<!item_type!>',$possess_desc); @@ -253,14 +255,14 @@ function notification($params) { if($params['type'] == NOTIFY_INTRO) { $subject = sprintf( t('[Red:Notify] Introduction received')); - $preamble = sprintf( t('%1$s, you\'ve received an introduction from \'%2$s\' at %3$s'), $recip['channel_name'], $sender['xchan_name'], $sitename); - $epreamble = sprintf( t('%1$s, you\'ve received [zrl=%2$s]an introduction[/zrl] from %3$s.'), + $preamble = sprintf( t('%1$s, you\'ve received an new connection request from \'%2$s\' at %3$s'), $recip['channel_name'], $sender['xchan_name'], $sitename); + $epreamble = sprintf( t('%1$s, you\'ve received [zrl=%2$s]a new connection request[/zrl] from %3$s.'), $recip['channel_name'], $itemlink, '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]'); $body = sprintf( t('You may visit their profile at %s'),$sender['xchan_url']); - $sitelink = t('Please visit %s to approve or reject the introduction.'); + $sitelink = t('Please visit %s to approve or reject the connection request.'); $tsitelink = sprintf( $sitelink, $siteurl ); $hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>'); $itemlink = $params['link']; @@ -338,7 +340,7 @@ function notification($params) { $datarray['aid'] = $recip['channel_account_id']; $datarray['uid'] = $recip['channel_id']; $datarray['link'] = $itemlink; - $datarray['parent'] = $parent_id; + $datarray['parent'] = $parent_mid; $datarray['type'] = $params['type']; $datarray['verb'] = $params['verb']; $datarray['otype'] = $params['otype']; @@ -355,7 +357,7 @@ function notification($params) { // create notification entry in DB $r = q("insert into notify (hash,name,url,photo,date,aid,uid,link,parent,type,verb,otype) - values('%s','%s','%s','%s','%s',%d,%d,'%s',%d,%d,'%s','%s')", + values('%s','%s','%s','%s','%s',%d,%d,'%s','%s',%d,'%s','%s')", dbesc($datarray['hash']), dbesc($datarray['name']), dbesc($datarray['url']), @@ -364,7 +366,7 @@ function notification($params) { intval($datarray['aid']), intval($datarray['uid']), dbesc($datarray['link']), - intval($datarray['parent']), + dbesc($datarray['parent']), intval($datarray['type']), dbesc($datarray['verb']), dbesc($datarray['otype']) @@ -432,7 +434,7 @@ function notification($params) { $datarray['sitename'] = $sitename; $datarray['siteurl'] = $siteurl; $datarray['type'] = $params['type']; - $datarray['parent'] = $params['parent']; + $datarray['parent'] = $params['parent_mid']; $datarray['source_name'] = $sender['xchan_name']; $datarray['source_link'] = $sender['xchan_url']; $datarray['source_photo'] = $sender['xchan_photo_s']; diff --git a/include/expire.php b/include/expire.php index 2d94d64c0..442914a39 100644 --- a/include/expire.php +++ b/include/expire.php @@ -7,10 +7,20 @@ function expire_run($argv, $argc){ cli_startup(); + $r = q("select id from item where (item_restrict & %d) and not (item_restrict & %d) and changed < UTC_TIMESTAMP() - INTERVAL 10 DAY", + intval(ITEM_DELETED), + intval(ITEM_PENDING_REMOVE) + ); + if($r) { + foreach($r as $rr) { + drop_item($rr['id'],false,DROPITEM_PHASE2); + } + } + // physically remove anything that has been deleted for more than two months - $r = q("delete from item where ( item_flags & %d ) and changed < UTC_TIMESTAMP() - INTERVAL 60 DAY", - intval(ITEM_DELETED) + $r = q("delete from item where ( item_restrict & %d ) and changed < UTC_TIMESTAMP() - INTERVAL 36 DAY", + intval(ITEM_PENDING_REMOVE) ); // make this optional as it could have a performance impact on large sites @@ -29,6 +39,21 @@ function expire_run($argv, $argc){ } } + + $x = get_sys_channel(); + if($x) { + + // this should probably just fetch the channel_expire_days from the sys channel, + // but there's no convenient way to set it. + + $expire_days = get_config('externals','expire_days'); + if($expire_days === false) + $expire_days = 30; + if($expire_days) + item_expire($x['channel_id'],$expire_days); + } + + return; } diff --git a/include/externals.php b/include/externals.php new file mode 100644 index 000000000..96644d68d --- /dev/null +++ b/include/externals.php @@ -0,0 +1,97 @@ +<?php /** @file */ + +require_once('boot.php'); +require_once('include/cli_startup.php'); +require_once('include/zot.php'); +require_once('include/identity.php'); + +function externals_run($argv, $argc){ + + cli_startup(); + $a = get_app(); + + + $total = 0; + $attempts = 0; + + // pull in some public posts + + + while($total == 0 && $attempts < 3) { + $arr = array('url' => ''); + call_hooks('externals_url_select',$arr); + + if($arr['url']) { + $url = $arr['url']; + } + else { + $r = q("select site_url, site_pull from site where site_url != '%s' and site_flags != %d order by rand() limit 1", + dbesc(z_root()), + intval(DIRECTORY_MODE_STANDALONE) + ); + if($r) + $url = $r[0]['site_url']; + } + + $attempts ++; + + if($url) { + if($r[0]['site_pull'] !== '0000-00-00 00:00:00') + $mindate = urlencode($r[0]['site_pull']); + else { + $days = get_config('externals','since_days'); + if($days === false) + $days = 15; + $mindate = urlencode(datetime_convert('','','now - ' . intval($days) . ' days')); + } + + $feedurl = $url . '/zotfeed?f=&mindate=' . $mindate; + + logger('externals: pulling public content from ' . $feedurl, LOGGER_DEBUG); + + $x = z_fetch_url($feedurl); + if(($x) && ($x['success'])) { + + q("update site set site_pull = '%s' where site_url = '%s' limit 1", + dbesc(datetime_convert()), + dbesc($url) + ); + + $j = json_decode($x['body'],true); + if($j['success'] && $j['messages']) { + $sys = get_sys_channel(); + foreach($j['messages'] as $message) { + $results = process_delivery(array('hash' => 'undefined'), get_item_elements($message), + array(array('hash' => $sys['xchan_hash'])), false, true); + $total ++; + $z = q("select id from item where mid = '%s' and uid = %d limit 1", + dbesc($message['message_id']), + intval($sys['channel_id']) + ); + if($z) { + $flag_bits = ITEM_WALL|ITEM_ORIGIN|ITEM_UPLINK; + // preserve the source + + $r = q("update item set source_xchan = owner_xchan where id = %d limit 1", + intval($z[0]['id']) + ); + + $r = q("update item set item_flags = ( item_flags | %d ), owner_xchan = '%s' + where id = %d limit 1", + intval($flag_bits), + dbesc($sys['xchan_hash']), + intval($z[0]['id']) + ); + } + } + logger('externals: import_public_posts: ' . $total . ' messages imported', LOGGER_DEBUG); + } + } + } + } +} + +if (array_search(__file__,get_included_files())===0){ + externals_run($argv,$argc); + killme(); +} diff --git a/include/follow.php b/include/follow.php index 0508a8b37..d98a58198 100644 --- a/include/follow.php +++ b/include/follow.php @@ -75,11 +75,17 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) return $result; } + // do we have an xchan and hubloc? // If not, create them. $x = import_xchan($j); + if(array_key_exists('deleted',$j) && intval($j['deleted'])) { + $result['message'] = t('Channel was deleted and no longer exists.'); + return $result; + } + if(! $x['success']) return $x; diff --git a/include/hubloc.php b/include/hubloc.php new file mode 100644 index 000000000..35d9dbeb1 --- /dev/null +++ b/include/hubloc.php @@ -0,0 +1,33 @@ +<?php /** @file */ + + + +function prune_hub_reinstalls() { + + $r = q("select site_url from site where true"); + if($r) { + foreach($r as $rr) { + $x = q("select count(*) as t, hubloc_sitekey, max(hubloc_connected) as c from hubloc where hubloc_url = '%s' group by hubloc_sitekey order by c", + dbesc($rr['site_url']) + ); + + // see if this url has more than one sitekey, indicating it has been re-installed. + + if(count($x) > 1) { + + $d1 = datetime_convert('UTC','UTC',$x[0]['c']); + $d2 = datetime_convert('UTC','UTC','now - 3 days'); + + // allow some slop period, say 3 days - just in case this is a glitch or transient occurrence + // Then remove any hublocs pointing to the oldest entry. + + if($d1 < $d2) { + logger('prune_hub_reinstalls: removing dead hublocs at ' . $rr['site_url']); + $y = q("delete from hubloc where hubloc_sitekey = '%s'", + dbesc($x[0]['hubloc_sitekey']) + ); + } + } + } + } +}
\ No newline at end of file diff --git a/include/identity.php b/include/identity.php index efc0d7d87..e773bb314 100644 --- a/include/identity.php +++ b/include/identity.php @@ -80,6 +80,16 @@ function validate_channelname($name) { function create_sys_channel() { if(get_sys_channel()) return; + + // Ensure that there is a host keypair. + + if((! get_config('system','pubkey')) && (! get_config('system','prvkey'))) { + require_once('include/crypto.php'); + $hostkey = new_keypair(4096); + set_config('system','pubkey',$hostkey['pubkey']); + set_config('system','prvkey',$hostkey['prvkey']); + } + create_identity(array( 'account_id' => 'xxx', // This will create an identity with an (integer) account_id of 0, but account_id is required 'nickname' => 'sys', @@ -99,6 +109,15 @@ function get_sys_channel() { return false; } +function is_sys_channel($channel_id) { + $r = q("select channel_pageflags from channel where channel_id = %d limit 1", + intval($channel_id) + ); + if(($r) && ($r[0]['channel_pageflags'] & PAGE_SYSTEM)) + return true; + return false; +} + /** * @channel_total() @@ -167,6 +186,11 @@ function create_identity($arr) { return $ret; } + if($nick === 'sys' && (! ($pageflags & PAGE_SYSTEM))) { + $ret['message'] = t('Reserved nickname. Please choose another.'); + return $ret; + } + if(check_webbie(array($nick)) !== $nick) { $ret['message'] = t('Nickname has unsupported characters or is already being used on this site.'); return $ret; @@ -200,10 +224,13 @@ function create_identity($arr) { $perms_vals .= ', ' . intval($v); } + $expire = get_config('system', 'default_expire_days'); + $expire = (($expire===false)? '0': $expire); + $r = q("insert into channel ( channel_account_id, channel_primary, channel_name, channel_address, channel_guid, channel_guid_sig, - channel_hash, channel_prvkey, channel_pubkey, channel_pageflags $perms_keys ) - values ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d $perms_vals ) ", + channel_hash, channel_prvkey, channel_pubkey, channel_pageflags, channel_expire_days $perms_keys ) + values ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d $perms_vals ) ", intval($arr['account_id']), intval($primary), @@ -214,7 +241,8 @@ function create_identity($arr) { dbesc($hash), dbesc($key['prvkey']), dbesc($key['pubkey']), - intval($pageflags) + intval($pageflags), + intval($expire) ); @@ -523,12 +551,20 @@ function profile_load(&$a, $nickname, $profile = '') { ); } + if(! $p) { logger('profile error: ' . $a->query_string, LOGGER_DEBUG); notice( t('Requested profile is not available.') . EOL ); $a->error = 404; return; } + + $z = q("select xchan_photo_date from xchan where xchan_hash = '%s' limit 1", + dbesc($p[0]['channel_hash']) + ); + if($z) + $p[0]['picdate'] = $z[0]['xchan_photo_date']; + // fetch user tags if this isn't the default profile @@ -1221,3 +1257,24 @@ function get_channel_by_nick($nick) { return(($r) ? $r[0] : false); } + + +function identity_selector() { + if(local_user()) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d and not ( channel_pageflags & %d ) order by channel_name ", + intval(get_account_id()), + intval(PAGE_REMOVED) + ); + if(count($r) > 1) { + $selected_channel = null; + $account = get_app()->get_account(); + $o = replace_macros(get_markup_template('channel_id_select.tpl'),array( + '$channels' => $r, + '$selected' => local_user() + )); + return $o; + } + } + + return ''; +}
\ No newline at end of file diff --git a/include/items.php b/include/items.php index 70e098415..a7d3a21ce 100755 --- a/include/items.php +++ b/include/items.php @@ -81,6 +81,19 @@ function collect_recipients($item,&$private) { $recipients = check_list_permissions($item['uid'],$recipients,'view_stream'); + // remove any upstream recipients from our list. + // If it is ourself we'll add it back in a second. + // This should prevent complex delivery chains from getting overly complex by not + // sending to anybody who is on our list of those who sent it to us. + + if($item['route']) { + $route = explode(',',$item['route']); + if(count($route)) { + $route = array_unique($route); + $recipients = array_diff($recipients,$route); + } + } + // add ourself just in case we have nomadic clones that need to get a copy. $recipients[] = $item['author_xchan']; @@ -141,6 +154,25 @@ function can_comment_on_post($observer_xchan,$item) { } +function add_source_route($iid,$hash) { +// logger('add_source_route ' . $iid . ' ' . $hash, LOGGER_DEBUG); + + if((! $iid) || (! $hash)) + return; + $r = q("select route from item where id = %d limit 1", + intval($iid) + ); + if($r) { + $new_route = (($r[0]['route']) ? $r[0]['route'] . ',' : '') . $hash; + q("update item set route = '%s' where id = %d limit 1", + (dbesc($new_route)), + intval($iid) + ); + } +} + + + /** * @function red_zrl_callback * preg_match function when fixing 'naked' links in mod item.php @@ -636,6 +668,7 @@ function get_item_elements($x) { $arr['app'] = (($x['app']) ? htmlspecialchars($x['app'], ENT_COMPAT,'UTF-8',false) : ''); + $arr['route'] = (($x['route']) ? htmlspecialchars($x['route'], ENT_COMPAT,'UTF-8',false) : ''); $arr['mid'] = (($x['message_id']) ? htmlspecialchars($x['message_id'], ENT_COMPAT,'UTF-8',false) : ''); $arr['parent_mid'] = (($x['message_top']) ? htmlspecialchars($x['message_top'], ENT_COMPAT,'UTF-8',false) : ''); $arr['thr_parent'] = (($x['message_parent']) ? htmlspecialchars($x['message_parent'], ENT_COMPAT,'UTF-8',false) : ''); @@ -647,7 +680,7 @@ function get_item_elements($x) { $arr['mimetype'] = (($x['mimetype']) ? htmlspecialchars($x['mimetype'], ENT_COMPAT,'UTF-8',false) : ''); $arr['obj_type'] = (($x['object_type']) ? htmlspecialchars($x['object_type'], ENT_COMPAT,'UTF-8',false) : ''); $arr['tgt_type'] = (($x['target_type']) ? htmlspecialchars($x['target_type'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['comment_policy'] = (($x['comment_scope']) ? htmlspecialchars($x['comment_scope'], ENT_COMPAT,'UTF-8',false) : 'contacts'); + $arr['comment_policy'] = (($x['comment_scope']) ? htmlspecialchars($x['comment_scope'], ENT_COMPAT,'UTF-8',false) : 'contacts'); $arr['sig'] = (($x['signature']) ? htmlspecialchars($x['signature'], ENT_COMPAT,'UTF-8',false) : ''); @@ -809,14 +842,6 @@ function encode_item($item) { $item['body'] = crypto_unencapsulate(json_decode_plus($item['body']),$key); } - if($item['item_restrict'] & ITEM_DELETED) { - $x['message_id'] = $item['mid']; - $x['created'] = $item['created']; - $x['flags'] = array('deleted'); - $x['owner'] = encode_item_xchan($item['owner']); - $x['author'] = encode_item_xchan($item['author']); - return $x; - } $x['message_id'] = $item['mid']; $x['message_top'] = $item['parent_mid']; @@ -836,6 +861,7 @@ function encode_item($item) { $x['location'] = $item['location']; $x['longlat'] = $item['coord']; $x['signature'] = $item['sig']; + $x['route'] = $item['route']; $x['owner'] = encode_item_xchan($item['owner']); $x['author'] = encode_item_xchan($item['author']); @@ -859,7 +885,7 @@ function encode_item($item) { if($item['term']) $x['tags'] = encode_item_terms($item['term']); - logger('encode_item: ' . print_r($x,true)); + logger('encode_item: ' . print_r($x,true), LOGGER_DATA); return $x; @@ -1000,9 +1026,11 @@ function encode_item_flags($item) { // most of item_flags and item_restrict are local settings which don't apply when transmitted. // We may need those for the case of syncing other hub locations which you are attached to. -// ITEM_DELETED is handled in encode_item directly so we don't need to handle it here. $ret = array(); + + if($item['item_restrict'] & ITEM_DELETED) + $ret[] = 'deleted'; if($item['item_flags'] & ITEM_THREAD_TOP) $ret[] = 'thread_parent'; if($item['item_flags'] & ITEM_NSFW) @@ -2294,6 +2322,7 @@ function tag_deliver($uid,$item_id) { logger('tag_deliver: community tag activity received'); if(($item['owner_xchan'] === $u[0]['channel_hash']) && (! get_pconfig($u[0]['channel_id'],'system','blocktags'))) { + logger('tag_deliver: community tag recipient: ' . $u[0]['channel_name']); $j_tgt = json_decode_plus($item['target']); if($j_tgt && $j_tgt['id']) { $p = q("select * from item where mid = '%s' and uid = %d limit 1", @@ -2306,6 +2335,7 @@ function tag_deliver($uid,$item_id) { if($j_obj && $j_obj['id'] && $j_obj['title']) { if(is_array($j_obj['link'])) $taglink = get_rel_link($j_obj['link'],'alternate'); + store_item_tag($u[0]['channel_id'],$p[0]['id'],TERM_OBJ_POST,TERM_HASHTAG,$j_obj['title'],$j_obj['id']); $x = q("update item set edited = '%s', received = '%s', changed = '%s' where mid = '%s' and uid = %d limit 1", dbesc(datetime_convert()), @@ -3493,7 +3523,12 @@ function drop_items($items) { // permissions to carry out this act. If it is non-interactive, we are deleting something at the // system's request and do not check permission. This is very important to know. -function drop_item($id,$interactive = true) { +// Some deletion requests (those coming from remote sites) must be staged. +// $stage = 0 => unstaged +// $stage = 1 => set deleted flag on the item and perform intial notifications +// $stage = 2 => perform low level delete at a later stage + +function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL) { $a = get_app(); @@ -3503,7 +3538,7 @@ function drop_item($id,$interactive = true) { intval($id) ); - if((! $r) || ($r[0]['item_restrict'] & ITEM_DELETED)) { + if((! $r) || (($r[0]['item_restrict'] & ITEM_DELETED) && ($stage === DROPITEM_NORMAL))) { if(! $interactive) return 0; notice( t('Item not found.') . EOL); @@ -3537,7 +3572,7 @@ function drop_item($id,$interactive = true) { intval($item['id']) ); - $arr = array('item' => $item); + $arr = array('item' => $item, 'interactive' => $interactive, 'stage' => $stage); call_hooks('drop_item', $arr ); $notify_id = intval($item['id']); @@ -3548,10 +3583,10 @@ function drop_item($id,$interactive = true) { ); if($items) { foreach($items as $i) - delete_item_lowlevel($i); + delete_item_lowlevel($i,$stage); } else - delete_item_lowlevel($item); + delete_item_lowlevel($item,$stage); if(! $interactive) return 1; @@ -3559,7 +3594,7 @@ function drop_item($id,$interactive = true) { // send the notification upstream/downstream as the case may be // only send notifications to others if this is the owner's wall item. - if($item['item_flags'] & ITEM_WALL) + if(($item['item_flags'] & ITEM_WALL) && ($stage != DROPITEM_PHASE2)) proc_run('php','include/notifier.php','drop',$notify_id); goaway($a->get_baseurl() . '/' . $_SESSION['return_url']); @@ -3578,15 +3613,47 @@ function drop_item($id,$interactive = true) { // It merely destroys all resources associated with an item. // Please do not use without a suitable wrapper. -function delete_item_lowlevel($item) { +function delete_item_lowlevel($item,$stage = DROPITEM_NORMAL) { - $r = q("UPDATE item SET item_restrict = ( item_restrict | %d ), title = '', body = '', - changed = '%s', edited = '%s' WHERE id = %d LIMIT 1", - intval(ITEM_DELETED), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - intval($item['id']) - ); + + switch($stage) { + case DROPITEM_PHASE2: + $r = q("UPDATE item SET item_restrict = ( item_restrict | %d ), body = '', title = '', + changed = '%s', edited = '%s' WHERE id = %d LIMIT 1", + intval(ITEM_PENDING_REMOVE), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + intval($item['id']) + ); + break; + + case DROPITEM_PHASE1: + $r = q("UPDATE item SET item_restrict = ( item_restrict | %d ), + changed = '%s', edited = '%s' WHERE id = %d LIMIT 1", + intval(ITEM_DELETED), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + intval($item['id']) + ); + break; + + case DROPITEM_NORMAL: + default: + $r = q("UPDATE item SET item_restrict = ( item_restrict | %d ), body = '', title = '', + changed = '%s', edited = '%s' WHERE id = %d LIMIT 1", + intval(ITEM_DELETED), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + intval($item['id']) + ); + break; + } + + // network deletion request. Keep the message structure so that we can deliver delete notifications. + // Come back after several days (or perhaps a month) to do the lowlevel delete (DROPITEM_PHASE2). + + if($stage == DROPITEM_PHASE1) + return true; $r = q("delete from term where otype = %d and oid = %d limit 1", intval(TERM_OBJ_POST), @@ -3751,8 +3818,10 @@ function zot_feed($uid,$observer_xchan,$mindate) { return $result; } - require_once('include/security.php'); - $sql_extra = item_permissions_sql($uid); + if(! is_sys_channel($uid)) { + require_once('include/security.php'); + $sql_extra = item_permissions_sql($uid); + } if($mindate != '0000-00-00 00:00:00') { $sql_extra .= " and created > '$mindate' "; @@ -3763,24 +3832,34 @@ function zot_feed($uid,$observer_xchan,$mindate) { $items = array(); - $r = q("SELECT item.*, item.id as item_id from item - WHERE uid = %d AND item_restrict = 0 and id = parent - AND (item_flags & %d) - $sql_extra ORDER BY created ASC $limit", - intval($uid), - intval(ITEM_WALL) - ); - if($r) { + if(is_sys_channel($uid)) { + require_once('include/security.php'); + $r = q("SELECT item.*, item.id as item_id from item + WHERE uid in (" . stream_perms_api_uids(PERMS_PUBLIC) . ") AND item_restrict = 0 and id = parent + AND (item_flags & %d) + and item_private = 0 $sql_extra ORDER BY created ASC $limit", + intval(ITEM_WALL) + ); + } + else { + $r = q("SELECT item.*, item.id as item_id from item + WHERE uid = %d AND item_restrict = 0 and id = parent + AND (item_flags & %d) + $sql_extra ORDER BY created ASC $limit", + intval($uid), + intval(ITEM_WALL) + ); + } + + if($r) { $parents_str = ids_to_querystr($r,'id'); $items = q("SELECT `item`.*, `item`.`id` AS `item_id` FROM `item` - WHERE `item`.`uid` = %d AND `item`.`item_restrict` = 0 + WHERE `item`.`item_restrict` = 0 AND `item`.`parent` IN ( %s ) ", - intval($uid), dbesc($parents_str) ); - } if($items) { @@ -3931,23 +4010,25 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C if(isset($arr['start']) && isset($arr['records'])) $pager_sql = sprintf(" LIMIT %d, %d ",intval($arr['start']), intval($arr['records'])); - if(($arr['cmin'] != 0) || ($arr['cmax'] != 99)) { + if(array_key_exists('cmin',$arr) || array_key_exists('cmax',$arr)) { + if(($arr['cmin'] != 0) || ($arr['cmax'] != 99)) { - // Not everybody who shows up in the network stream will be in your address book. - // By default those that aren't are assumed to have closeness = 99; but this isn't - // recorded anywhere. So if cmax is 99, we'll open the search up to anybody in - // the stream with a NULL address book entry. + // Not everybody who shows up in the network stream will be in your address book. + // By default those that aren't are assumed to have closeness = 99; but this isn't + // recorded anywhere. So if cmax is 99, we'll open the search up to anybody in + // the stream with a NULL address book entry. - $sql_nets .= " AND "; + $sql_nets .= " AND "; - if($arr['cmax'] == 99) - $sql_nets .= " ( "; + if($arr['cmax'] == 99) + $sql_nets .= " ( "; - $sql_nets .= "( abook.abook_closeness >= " . intval($arr['cmin']) . " "; - $sql_nets .= " AND abook.abook_closeness <= " . intval($arr['cmax']) . " ) "; - if($cmax == 99) - $sql_nets .= " OR abook.abook_closeness IS NULL ) "; - } + $sql_nets .= "( abook.abook_closeness >= " . intval($arr['cmin']) . " "; + $sql_nets .= " AND abook.abook_closeness <= " . intval($arr['cmax']) . " ) "; + if($cmax == 99) + $sql_nets .= " OR abook.abook_closeness IS NULL ) "; + } + } $simple_update = (($client_mode & CLIENT_MODE_UPDATE) ? " and ( item.item_flags & " . intval(ITEM_UNSEEN) . " ) " : ''); if($client_mode & CLIENT_MODE_LOAD) diff --git a/include/nav.php b/include/nav.php index 3aa50226d..a97b434bc 100644 --- a/include/nav.php +++ b/include/nav.php @@ -162,7 +162,7 @@ EOT; $nav['home']['mark'] = array('', t('Mark all channel notifications seen'), '',''); - $nav['intros'] = array('connections/pending', t('Intros'), "", t('New Connections')); + $nav['intros'] = array('connections/ifpending', t('Connections'), "", t('Connections')); $nav['notifications'] = array('notifications/system', t('Notices'), "", t('Notifications')); diff --git a/include/network.php b/include/network.php index 1fb4beaa7..9f68328b7 100644 --- a/include/network.php +++ b/include/network.php @@ -43,8 +43,12 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) { @curl_setopt($ch, CURLOPT_RETURNTRANSFER,true); @curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; Red)"); + $ciphers = @get_config('system','curl_ssl_ciphers'); + if($ciphers) + @curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers); + if (x($opts,'accept_content')){ - curl_setopt($ch,CURLOPT_HTTPHEADER, array ( + @curl_setopt($ch,CURLOPT_HTTPHEADER, array ( "Accept: " . $opts['accept_content'] )); } @@ -115,7 +119,9 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) { $ret['return_code'] = $rc; $ret['success'] = (($rc >= 200 && $rc <= 299) ? true : false); if(! $ret['success']) { + $ret['error'] = curl_error($ch); $ret['debug'] = $curl_info; + logger('z_fetch_url: error:' . $ret['error'], LOGGER_DEBUG); logger('z_fetch_url: debug:' . print_r($curl_info,true), LOGGER_DATA); } $ret['body'] = substr($s,strlen($header)); @@ -136,21 +142,25 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) { if(($redirects > 8) || (! $ch)) return ret; - curl_setopt($ch, CURLOPT_HEADER, true); + @curl_setopt($ch, CURLOPT_HEADER, true); @curl_setopt($ch, CURLOPT_CAINFO, get_capath()); - curl_setopt($ch, CURLOPT_RETURNTRANSFER,true); - curl_setopt($ch, CURLOPT_POST,1); - curl_setopt($ch, CURLOPT_POSTFIELDS,$params); - curl_setopt($ch, CURLOPT_USERAGENT, "Red"); + @curl_setopt($ch, CURLOPT_RETURNTRANSFER,true); + @curl_setopt($ch, CURLOPT_POST,1); + @curl_setopt($ch, CURLOPT_POSTFIELDS,$params); + @curl_setopt($ch, CURLOPT_USERAGENT, "Red"); + + $ciphers = @get_config('system','curl_ssl_ciphers'); + if($ciphers) + @curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers); if (x($opts,'accept_content')){ - curl_setopt($ch,CURLOPT_HTTPHEADER, array ( + @curl_setopt($ch,CURLOPT_HTTPHEADER, array ( "Accept: " . $opts['accept_content'] )); } if(x($opts,'headers')) - curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']); + @curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']); if(x($opts,'timeout') && intval($opts['timeout'])) { @curl_setopt($ch, CURLOPT_TIMEOUT, $opts['timeout']); @@ -170,11 +180,11 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) { $prx = get_config('system','proxy'); if(strlen($prx)) { - curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1); - curl_setopt($ch, CURLOPT_PROXY, $prx); + @curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1); + @curl_setopt($ch, CURLOPT_PROXY, $prx); $prxusr = get_config('system','proxyuser'); if(strlen($prxusr)) - curl_setopt($ch, CURLOPT_PROXYUSERPWD, $prxusr); + @curl_setopt($ch, CURLOPT_PROXYUSERPWD, $prxusr); } // don't let curl abort the entire application @@ -183,7 +193,7 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) { $s = @curl_exec($ch); $base = $s; - $curl_info = curl_getinfo($ch); + $curl_info = @curl_getinfo($ch); $http_code = $curl_info['http_code']; $header = ''; @@ -217,8 +227,10 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) { $ret['return_code'] = $rc; $ret['success'] = (($rc >= 200 && $rc <= 299) ? true : false); if(! $ret['success']) { + $ret['error'] = curl_error($ch); $ret['debug'] = $curl_info; - logger('z_fetch_url: debug:' . print_r($curl_info,true), LOGGER_DATA); + logger('z_post_url: error:' . $ret['error'], LOGGER_DEBUG); + logger('z_post_url: debug:' . print_r($curl_info,true), LOGGER_DATA); } $ret['body'] = substr($s,strlen($header)); diff --git a/include/notifier.php b/include/notifier.php index 81f971107..4bf2ac153 100644 --- a/include/notifier.php +++ b/include/notifier.php @@ -288,6 +288,11 @@ function notifier_run($argv, $argc){ if($s) $channel = $s[0]; + if($channel['channel_hash'] !== $target_item['author_xchan'] && $channel['channel_hash'] !== $target_item['owner_xchan']) { + logger("notifier: Sending channel {$channel['channel_hash']} is not owner {$target_item['owner_xchan']} or author {$target_item['author_xchan']}"); + return; + } + if($target_item['id'] == $target_item['parent']) { $parent_item = $target_item; @@ -481,10 +486,11 @@ function notifier_run($argv, $argc){ $hash = random_string(); if($packet_type === 'refresh' || $packet_type === 'purge') { $n = zot_build_packet($channel,$packet_type); - q("insert into outq ( outq_hash, outq_account, outq_channel, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s' )", + q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", dbesc($hash), intval($channel['channel_account_id']), intval($channel['channel_id']), + dbesc('zot'), dbesc($hub['hubloc_callback']), intval(1), dbesc(datetime_convert()), @@ -495,10 +501,11 @@ function notifier_run($argv, $argc){ } else { $n = zot_build_packet($channel,'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash); - q("insert into outq ( outq_hash, outq_account, outq_channel, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s' )", + q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", dbesc($hash), intval($target_item['aid']), intval($target_item['uid']), + dbesc('zot'), dbesc($hub['hubloc_callback']), intval(1), dbesc(datetime_convert()), diff --git a/include/oembed.php b/include/oembed.php index 57631b051..42a9881ed 100755 --- a/include/oembed.php +++ b/include/oembed.php @@ -164,8 +164,11 @@ function oembed_iframe($src,$width,$height) { $a = get_app(); + $sandbox = ((strpos($src,get_app()->get_hostname())) ? ' sandbox="allow-scripts" ' : ''); + $s = $a->get_baseurl()."/oembed/".base64url_encode($src); - return '<iframe height="' . $height . '" width="' . $width . '" src="' . $s . '" frameborder="no" >' . t('Embedded content') . '</iframe>'; + + return '<iframe ' . $sandbox . ' height="' . $height . '" width="' . $width . '" src="' . $s . '" frameborder="no" >' . t('Embedded content') . '</iframe>'; } diff --git a/include/permissions.php b/include/permissions.php index eb1a7966f..01dd18f8d 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -100,6 +100,13 @@ function get_all_perms($uid,$observer_xchan,$internal_use = true) { dbesc($observer_xchan), intval(ABOOK_FLAG_SELF) ); + if(! $x) { + // not in address book, see if they've got an xchan + $y = q("select xchan_network from xchan where xchan_hash = '%s' limit 1", + dbesc($observer_xchan) + ); + } + $abook_checked = true; } @@ -144,9 +151,11 @@ function get_all_perms($uid,$observer_xchan,$internal_use = true) { // If we're still here, we have an observer, check the network. - if(($r[0][$channel_perm] & PERMS_NETWORK) && ($x[0]['xchan_network'] === 'zot')) { - $ret[$perm_name] = true; - continue; + if($r[0][$channel_perm] & PERMS_NETWORK) { + if(($x && $x[0]['xchan_network'] === 'zot') || ($y && $y[0]['xchan_network'] === 'zot')) { + $ret[$perm_name] = true; + continue; + } } // If PERMS_SITE is specified, find out if they've got an account on this hub @@ -263,6 +272,12 @@ function perm_is_allowed($uid,$observer_xchan,$permission) { if(($x) && (! $global_perms[$permission][2]) && ($x[0]['abook_flags'] & ABOOK_FLAG_IGNORED)) return false; + if(! $x) { + // not in address book, see if they've got an xchan + $y = q("select xchan_network from xchan where xchan_hash = '%s' limit 1", + dbesc($observer_xchan) + ); + } } @@ -283,9 +298,10 @@ function perm_is_allowed($uid,$observer_xchan,$permission) { // If we're still here, we have an observer, check the network. - if(($r[0][$channel_perm] & PERMS_NETWORK) && ($x[0]['xchan_network'] === 'zot')) - return true; - + if($r[0][$channel_perm] & PERMS_NETWORK) { + if (($x && $x[0]['xchan_network'] === 'zot') || ($y && $y[0]['xchan_network'] === 'zot')) + return true; + } // If PERMS_SITE is specified, find out if they've got an account on this hub diff --git a/include/photos.php b/include/photos.php index 82af4aaeb..65532e6c2 100644 --- a/include/photos.php +++ b/include/photos.php @@ -176,6 +176,7 @@ function photo_upload($channel, $observer, $args) { if(! $r3) $errors = true; } + if($errors) { q("delete from photo where resource_id = '%s' and uid = %d", @@ -188,6 +189,10 @@ function photo_upload($channel, $observer, $args) { return $ret; } + // This will be the width and height of the smallest representation + + $width_x_height = $ph->getWidth() . 'x' . $ph->getHeight(); + $basename = basename($filename); $mid = item_message_id(); @@ -219,9 +224,13 @@ function photo_upload($channel, $observer, $args) { $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid']; + if ($width_x_height) + $tag = '[zmg=' . $width_x_height. ']'; + else + $tag = '[zmg]'; $arr['body'] = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo_hash . ']' - . '[zmg]' . z_root() . "/photo/{$photo_hash}-{$smallest}.".$ph->getExt() . '[/zmg]' + . $tag . z_root() . "/photo/{$photo_hash}-{$smallest}.".$ph->getExt() . '[/zmg]' . '[/zrl]'; $result = item_store($arr); @@ -426,4 +435,4 @@ function photos_create_item($channel, $creator_hash, $photo, $visible = false) { $item_id = $result['item_id']; return $item_id; -}
\ No newline at end of file +} diff --git a/include/poller.php b/include/poller.php index 423ee46c1..9592c29e4 100644 --- a/include/poller.php +++ b/include/poller.php @@ -105,6 +105,23 @@ function poller_run($argv, $argc){ if($d2 != intval($d1)) { + $d3 = intval(datetime_convert('UTC','UTC','now','N')); + if($d3 == 7) { + + /** + * Cron Weekly + * + * Actions in the following block are executed once per day only on Sunday (once per week). + * + */ + + require_once('include/hubloc.php'); + prune_hub_reinstalls(); + + + } + + // expire any read notifications over a month old q("delete from notify where seen = 1 and date < UTC_TIMESTAMP() - INTERVAL 30 DAY"); @@ -151,6 +168,11 @@ function poller_run($argv, $argc){ } + // pull in some public posts + if(! get_config('system','disable_discover_tab')) + proc_run('php','include/externals.php'); + + $manual_id = 0; $generation = 0; diff --git a/include/probe.php b/include/probe.php new file mode 100644 index 000000000..29635f963 --- /dev/null +++ b/include/probe.php @@ -0,0 +1,99 @@ +<?php /** @file */ + + +/** + * Functions to assist in probing various legacy networks to figure out what kind of capabilities might be present. + */ + + +function net_have_driver($net) { + + if(function_exists('net_discover_' . $net)) + return true; + return false; +} + +function probe_well_known($addr) { + + $ret = array(); + + $ret['src'] = $addr; + + if(strpos($addr,'@') !== false) { + $ret['address'] = $addr; + } + else { + $ret['url'] = $addr; + } + + if(stristr($addr,'facebook.com')) { + $ret['network'] = 'facebook'; + } + if(stristr($addr,'google.com')) { + $ret['network'] = 'google'; + } + if(stristr($addr,'linkedin.com')) { + $ret['network'] = 'linkedin'; + } + + call_hooks('probe_well_known', $ret); + + if(array_key_exists('network',$ret) && net_have_driver($ret['network'])) { + $fn = 'net_discover_' . $ret['network']; + $ret = $fn($ret); + } + + + return $ret; + +} + + + + +function probe_webfinger($addr) { + + + + + +} + + +function probe_legacy_webfinger($addr) { + + + + +} + +function probe_zot($addr) { + + + +} + +function probe_dfrn($addr) { + + +} + + +function probe_diaspora($addr) { + + +} + + +function probe_legacy_feed($addr) { + + + +} + + +function probe_activity_stream($addr) { + + +} + diff --git a/include/queue.php b/include/queue.php index ec7246cb2..239d61fc0 100644 --- a/include/queue.php +++ b/include/queue.php @@ -33,8 +33,12 @@ function queue_run($argv, $argc){ // For the first 12 hours we'll try to deliver every 15 minutes // After that, we'll only attempt delivery once per hour. - - $r = q("SELECT * FROM outq WHERE outq_delivered = 0 and (( outq_created > UTC_TIMESTAMP() - INTERVAL 12 HOUR and outq_updated < UTC_TIMESTAMP() - INTERVAL 15 MINUTE ) OR ( outq_updated < UTC_TIMESTAMP() - INTERVAL 1 HOUR ))"); + // This currently only handles the default queue drivers ('zot' or '') which we will group by posturl + // so that we don't start off a thousand deliveries for a couple of dead hubs. + // The zot driver will deliver everything destined for a single hub once contact is made (*if* contact is made). + // Other drivers will have to do something different here and may need their own query. + + $r = q("SELECT * FROM outq WHERE outq_delivered = 0 and (( outq_created > UTC_TIMESTAMP() - INTERVAL 12 HOUR and outq_updated < UTC_TIMESTAMP() - INTERVAL 15 MINUTE ) OR ( outq_updated < UTC_TIMESTAMP() - INTERVAL 1 HOUR )) and outq_driver in ('','zot') group by outq_posturl"); } if(! $r) return; diff --git a/include/reddav.php b/include/reddav.php index 2a26ac42a..03cfe1aab 100644 --- a/include/reddav.php +++ b/include/reddav.php @@ -276,7 +276,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { for($x = 1; $x < count($path_arr); $x ++) { - $r = q("select id, hash, filename, flags from attach where folder = '%s' and filename = '%s' and (flags & %d)", + $r = q("select id, hash, filename, flags from attach where folder = '%s' and filename = '%s' and uid = %d and (flags & %d)", dbesc($folder), dbesc($path_arr[$x]), intval($channel_id), @@ -581,17 +581,19 @@ function RedCollectionData($file,&$auth) { for($x = 1; $x < count($path_arr); $x ++) { - $r = q("select id, hash, filename, flags from attach where folder = '%s' and filename = '%s' and (flags & %d) $perms limit 1", + $r = q("select id, hash, filename, flags from attach where folder = '%s' and filename = '%s' and uid = %d and (flags & %d) $perms limit 1", dbesc($folder), dbesc($path_arr[$x]), + intval($channel_id), intval(ATTACH_FLAG_DIR) ); if(! $r) { // path wasn't found. Try without permissions to see if it was the result of permissions. $errors = true; - $r = q("select id, hash, filename, flags from attach where folder = '%s' and filename = '%s' and (flags & %d) limit 1", + $r = q("select id, hash, filename, flags from attach where folder = '%s' and filename = '%s' and uid = %d and (flags & %d) limit 1", dbesc($folder), basename($path_arr[$x]), + intval($channel_id), intval(ATTACH_FLAG_DIR) ); if($r) { @@ -708,7 +710,7 @@ function RedFileData($file, &$auth,$test = false) { $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, created, edited from attach where folder = '%s' and filename = '%s' and uid = %d $perms group by filename limit 1", dbesc($folder), - basename($file), + dbesc(basename($file)), intval($channel_id) ); @@ -719,7 +721,7 @@ function RedFileData($file, &$auth,$test = false) { $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, created, edited from attach where folder = '%s' and filename = '%s' and uid = %d group by filename limit 1", dbesc($folder), - basename($file), + dbesc(basename($file)), intval($channel_id) ); if($r) @@ -882,8 +884,12 @@ class RedBrowser extends DAV\Browser\Plugin { date_default_timezone_set($this->auth->timezone); $version = ''; + require_once('include/conversation.php'); + + if($this->auth->channel_name) + $html = profile_tabs(get_app(),(($this->auth->owner_id == local_user()) ? true : false),$this->auth->owner_nick); - $html = " + $html .= " <body> <h1>Index for " . $this->escapeHTML($path) . "/</h1> <table> diff --git a/include/security.php b/include/security.php index f52615357..282c8ab73 100644 --- a/include/security.php +++ b/include/security.php @@ -346,8 +346,10 @@ function stream_perms_api_uids($perms_min = PERMS_SITE) { $ret = array(); if(local_user()) $ret[] = local_user(); - $r = q("select channel_id from channel where channel_r_stream > 0 and channel_r_stream <= %d", - intval($perms_min) + $r = q("select channel_id from channel where channel_r_stream > 0 and channel_r_stream <= %d and not (channel_pageflags & %d) and not (channel_pageflags & %d)", + intval($perms_min), + intval(PAGE_CENSORED), + intval(PAGE_SYSTEM) ); if($r) foreach($r as $rr) @@ -361,7 +363,7 @@ function stream_perms_api_uids($perms_min = PERMS_SITE) { $str .= ','; $str .= intval($rr); } -logger('stream_perms_api_uids: ' . $str); +logger('stream_perms_api_uids: ' . $str, LOGGER_DEBUG); return $str; } @@ -370,8 +372,10 @@ function stream_perms_xchans($perms_min = PERMS_SITE) { if(local_user()) $ret[] = get_observer_hash(); - $r = q("select channel_hash from channel where channel_r_stream > 0 and channel_r_stream <= %d", - intval($perms_min) + $r = q("select channel_hash from channel where channel_r_stream > 0 and channel_r_stream <= %d and not (channel_pageflags & %d) and not (channel_pageflags & %d)", + intval($perms_min), + intval(PAGE_CENSORED), + intval(PAGE_SYSTEM) ); if($r) foreach($r as $rr) @@ -385,6 +389,6 @@ function stream_perms_xchans($perms_min = PERMS_SITE) { $str .= ','; $str .= "'" . dbesc($rr) . "'"; } -logger('stream_perms_xchans: ' . $str); +logger('stream_perms_xchans: ' . $str, LOGGER_DEBUG); return $str; } diff --git a/include/socgraph.php b/include/socgraph.php index 10d52da66..65e23f9df 100644 --- a/include/socgraph.php +++ b/include/socgraph.php @@ -62,6 +62,11 @@ function poco_load($xchan = '',$url = null) { $j = json_decode($s['body'],true); + if(! $j) { + logger('poco_load: unable to json_decode returned data.'); + return; + } + logger('poco_load: ' . print_r($j,true),LOGGER_DATA); if($xchan) { diff --git a/include/text.php b/include/text.php index 53b92c05f..520c9c506 100755 --- a/include/text.php +++ b/include/text.php @@ -278,6 +278,11 @@ function hex2bin($s) { if(! (is_string($s) && strlen($s))) return ''; + if(strlen($s) & 1) { + logger('hex2bin: illegal hex string: ' . $s); + return $s; + } + if(! ctype_xdigit($s)) { return($s); } @@ -614,12 +619,28 @@ function get_tags($s) { } } + // make sure the longer tags are returned first so that if two or more have common substrings + // we'll replace the longest ones first. Otherwise the common substring would be found in + // both strings and the string replacement would link both to the shorter strings and + // fail to link the longer string. RedMatrix github issue #378 + + usort($ret,'tag_sort_length'); - // logger('get_tags: ' . print_r($ret,true)); + + //logger('get_tags: ' . print_r($ret,true)); return $ret; } +function tag_sort_length($a,$b) { + if(mb_strlen($a) == mb_strlen($b)) + return 0; + return((mb_strlen($b) < mb_strlen($a)) ? (-1) : 1); +} + + + + function strip_zids($s) { return preg_replace('/[\?&]zid=(.*?)(&|$)/ism','$2',$s); @@ -780,9 +801,9 @@ function searchbox($s,$id='search-box',$url='/search',$save = false) { $o .= '<form action="' . z_root() . '/' . $url . '" method="get" >'; $o .= '<input type="hidden" name="f" value="" />'; $o .= '<input type="text" class="icon-search" name="search" id="search-text" placeholder="" value="' . $s .'" onclick="this.submit();" />'; - $o .= '<input type="submit" name="submit" id="search-submit" value="' . t('Search') . '" />'; + $o .= '<input type="submit" name="submit" class="btn btn-default" id="search-submit" value="' . t('Search') . '" />'; if(feature_enabled(local_user(),'savedsearch')) - $o .= '<input type="submit" name="searchsave" id="search-save" value="' . t('Save') . '" />'; + $o .= '<input type="submit" name="searchsave" class="btn btn-default" id="search-save" value="' . t('Save') . '" />'; $o .= '</form></div>'; return $o; } @@ -1169,6 +1190,33 @@ function format_categories(&$item,$writeable) { return $s; } +// Add any hashtags which weren't mentioned in the message body, e.g. community tags + +function format_hashtags(&$item) { + + $s = ''; + $terms = get_terms_oftype($item['term'],TERM_HASHTAG); + if($terms) { + $categories = array(); + foreach($terms as $t) { + $term = htmlspecialchars($t['term'],ENT_COMPAT,'UTF-8',false) ; + if(! trim($term)) + continue; + if(strpos($item['body'], $t['url'])) + continue; + + if($s) + $s .= ' '; + + $s .= '#<a href="' . zid($t['url']) . '" >' . $term . '</a>'; + } + } + return $s; +} + + + + function format_filer(&$item) { @@ -1221,6 +1269,9 @@ function prepare_body(&$item,$attach = false) { $writeable = ((get_observer_hash() == $item['owner_xchan']) ? true : false); + + $s .= format_hashtags($item); + $s .= format_categories($item,$writeable); if(local_user() == $item['uid']) @@ -1712,6 +1763,7 @@ function check_webbie($arr) { $str .= "'" . dbesc($y) . "'"; } } + if(strlen($str)) { $r = q("select channel_address from channel where channel_address in ( $str ) "); if(count($r)) { @@ -1720,8 +1772,9 @@ function check_webbie($arr) { } } foreach($arr as $x) { - if(! in_array($x,$taken)) { - return $x; + $y = legal_webbie($x); + if(! in_array($y,$taken)) { + return $y; } } } diff --git a/include/widgets.php b/include/widgets.php index 90586397f..82769d925 100644 --- a/include/widgets.php +++ b/include/widgets.php @@ -306,6 +306,7 @@ function widget_archive($arr) { $wall = ((array_key_exists('wall', $arr)) ? intval($arr['wall']) : 0); + $style = ((array_key_exists('style', $arr)) ? $arr['style'] : 'select'); $url = z_root() . '/' . $a->cmd; @@ -318,6 +319,7 @@ function widget_archive($arr) { '$title' => t('Archives'), '$size' => ((count($ret) > 6) ? 6 : count($ret)), '$url' => $url, + '$style' => $style, '$dates' => $ret )); return $o; diff --git a/include/zot.php b/include/zot.php index 934348d2d..c0916755f 100644 --- a/include/zot.php +++ b/include/zot.php @@ -425,6 +425,15 @@ function zot_refresh($them,$channel = null, $force = false) { intval($channel['channel_id']), dbesc($x['hash']) ); + if(($new_connection) && (! $default_perms)) { + require_once('include/enotify.php'); + notification(array( + 'type' => NOTIFY_INTRO, + 'from_xchan' => $x['hash'], + 'to_xchan' => $channel['channel_hash'], + 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'], + )); + } if($new_connection && (! ($new_connection[0]['abook_flags'] & ABOOK_FLAG_PENDING)) && ($their_perms & PERMS_R_STREAM)) proc_run('php','include/onepoll.php',$new_connection[0]['abook_id']); @@ -623,6 +632,10 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED) { if($adult_changed) $new_flags = $new_flags ^ XCHAN_FLAGS_SELFCENSORED; + $deleted = (($r[0]['xchan_flags'] & XCHAN_FLAGS_DELETED) ? true : false); + $deleted_changed = ((intval($deleted) != intval($arr['deleted'])) ? true : false); + if($deleted_changed) + $new_flags = $new_flags ^ XCHAN_FLAGS_DELETED; if(($r[0]['xchan_name_date'] != $arr['name_updated']) || ($r[0]['xchan_connurl'] != $arr['connections_url']) @@ -667,6 +680,8 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED) { $new_flags = 0; if($arr['adult_content']) $new_flags |= XCHAN_FLAGS_SELFCENSORED; + if(array_key_exists('deleted',$arr) && $arr['deleted']) + $new_flags |= XCHAN_FLAGS_DELETED; $x = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_mimetype, xchan_photo_l, xchan_addr, xchan_url, xchan_connurl, xchan_follow, xchan_connpage, xchan_name, xchan_network, xchan_photo_date, xchan_name_date, xchan_flags) @@ -872,21 +887,28 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED) { } // get rid of any hubs we have for this channel which weren't reported. + // This was needed at one time to resolve complicated cross-site inconsistencies, but can cause sync conflict. + // currently disabled. + +// if($xisting) { +// foreach($xisting as $x) { +// if(! array_key_exists('updated',$x)) { +// logger('import_xchan: removing unreferenced hub location ' . $x['hubloc_url']); +// $r = q("delete from hubloc where hubloc_id = %d limit 1", +// intval($x['hubloc_id']) +// ); +// $what .= 'removed_hub'; +// $changed = true; +// } +// } +// } - if($xisting) { - foreach($xisting as $x) { - if(! array_key_exists('updated',$x)) { - logger('import_xchan: removing unreferenced hub location ' . $x['hubloc_url']); - $r = q("delete from hubloc where hubloc_id = %d limit 1", - intval($x['hubloc_id']) - ); - $what .= 'removed_hub'; - $changed = true; - } - } - } } + + + + // Are we a directory server of some kind? if($dirmode != DIRECTORY_MODE_NORMAL) { @@ -936,6 +958,8 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED) { $ret['hash'] = $xchan_hash; } + + logger('import_xchan: result: ' . print_r($ret,true), LOGGER_DATA); return $ret; } @@ -1345,16 +1369,18 @@ function allowed_public_recips($msg) { } -function process_delivery($sender,$arr,$deliveries,$relay) { +function process_delivery($sender,$arr,$deliveries,$relay,$public = false) { $result = array(); // We've validated the sender. Now make sure that the sender is the owner or author - if($sender['hash'] != $arr['owner_xchan'] && $sender['hash'] != $arr['author_xchan']) { - logger('process_delivery: sender is not owner or author'); - return; + if(! $public) { + if($sender['hash'] != $arr['owner_xchan'] && $sender['hash'] != $arr['author_xchan']) { + logger("process_delivery: sender {$sender['hash']} is not owner {$arr['owner_xchan']} or author {$arr['author_xchan']} - mid {$arr['mid']}"); + return; + } } foreach($deliveries as $d) { @@ -1385,9 +1411,9 @@ function process_delivery($sender,$arr,$deliveries,$relay) { } } - if((! perm_is_allowed($channel['channel_id'],$sender['hash'],$perm)) && (! $tag_delivery)) { - logger("permission denied for delivery {$channel['channel_id']}"); - $result[] = array($d['hash'],'permission denied',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>'); + if((! perm_is_allowed($channel['channel_id'],$sender['hash'],$perm)) && (! $tag_delivery) && (! $public)) { + logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}"); + $result[] = array($d['hash'],'permission denied',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>',$arr['mid']); continue; } @@ -1397,12 +1423,12 @@ function process_delivery($sender,$arr,$deliveries,$relay) { remove_community_tag($sender,$arr,$channel['channel_id']); $item_id = delete_imported_item($sender,$arr,$channel['channel_id']); - $result[] = array($d['hash'],(($item_id) ? 'deleted' : 'delete_failed'),$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>'); + $result[] = array($d['hash'],(($item_id) ? 'deleted' : 'delete_failed'),$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>',$arr['mid']); if($relay && $item_id) { logger('process_delivery: invoking relay'); proc_run('php','include/notifier.php','relay',intval($item_id)); - $result[] = array($d['hash'],'relayed',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>'); + $result[] = array($d['hash'],'relayed',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>',$arr['mid']); } continue; @@ -1432,8 +1458,9 @@ function process_delivery($sender,$arr,$deliveries,$relay) { } $xyz = event_store($ev); + add_source_route($xyz,$sender['hash']); - $result = array($d['hash'],'event processed',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>'); + $result = array($d['hash'],'event processed',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>',$arr['mid']); continue; } } @@ -1448,7 +1475,7 @@ function process_delivery($sender,$arr,$deliveries,$relay) { $arr['uid'] = $channel['channel_id']; update_imported_item($sender,$arr,$channel['channel_id']); } - $result[] = array($d['hash'],'updated',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>'); + $result[] = array($d['hash'],'updated',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>',$arr['mid']); $item_id = $r[0]['id']; } else { @@ -1456,18 +1483,20 @@ function process_delivery($sender,$arr,$deliveries,$relay) { $arr['uid'] = $channel['channel_id']; $item_result = item_store($arr); $item_id = $item_result['item_id']; - $result[] = array($d['hash'],(($item_id) ? 'posted' : 'storage failed:' . $item_result['message']),$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>'); + add_source_route($item_id,$sender['hash']); + + $result[] = array($d['hash'],(($item_id) ? 'posted' : 'storage failed:' . $item_result['message']),$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>',$arr['mid']); } if($relay && $item_id) { logger('process_delivery: invoking relay'); proc_run('php','include/notifier.php','relay',intval($item_id)); - $result[] = array($d['hash'],'relayed',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>'); + $result[] = array($d['hash'],'relayed',$channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>',$arr['mid']); } } if(! $deliveries) - $result[] = array('','no recipients'); + $result[] = array('','no recipients','',$arr['mid']); logger('process_delivery: local results: ' . print_r($result,true), LOGGER_DEBUG); @@ -1571,7 +1600,16 @@ function delete_imported_item($sender,$item,$uid) { } require_once('include/items.php'); - drop_item($r[0]['id'],false); + + // FIXME issue #230 is related + // Chicken/egg problem because we have to drop_item, but this removes information that tag_deliver may need to do its stuff. + // We can't reverse the order because drop_item refuses to run if the item already has the deleted flag set and we need to + // set that flag prior to calling tag_deliver. + + // Use phased deletion to set the deleted flag, call both tag_deliver and the notifier to notify downstream channels + // and then clean up after ourselves with a cron job after several days to do the delete_item_lowlevel() (DROPITEM_PHASE2). + + drop_item($r[0]['id'],false, DROPITEM_PHASE1); tag_deliver($uid,$r[0]['id']); @@ -1605,7 +1643,7 @@ function process_mail_delivery($sender,$arr,$deliveries) { if(! perm_is_allowed($channel['channel_id'],$sender['hash'],'post_mail')) { logger("permission denied for mail delivery {$channel['channel_id']}"); - $result[] = array($d['hash'],'permission denied',$channel['channel_name']); + $result[] = array($d['hash'],'permission denied',$channel['channel_name'],$arr['mid']); continue; } @@ -1619,11 +1657,11 @@ function process_mail_delivery($sender,$arr,$deliveries) { intval($r[0]['id']), intval($channel['channel_id']) ); - $result[] = array($d['hash'],'mail recalled',$channel['channel_name']); + $result[] = array($d['hash'],'mail recalled',$channel['channel_name'],$arr['mid']); logger('mail_recalled'); } else { - $result[] = array($d['hash'],'duplicate mail received',$channel['channel_name']); + $result[] = array($d['hash'],'duplicate mail received',$channel['channel_name'],$arr['mid']); logger('duplicate mail received'); } continue; @@ -1632,7 +1670,7 @@ function process_mail_delivery($sender,$arr,$deliveries) { $arr['account_id'] = $channel['channel_account_id']; $arr['channel_id'] = $channel['channel_id']; $item_id = mail_store($arr); - $result[] = array($d['hash'],'mail delivered',$channel['channel_name']); + $result[] = array($d['hash'],'mail delivered',$channel['channel_name'],$arr['mid']); } } @@ -1669,20 +1707,19 @@ function import_directory_profile($hash,$profile,$addr,$ud_flags = UPDATE_FLAGS_ $arr = array(); $arr['xprof_hash'] = $hash; - $arr['xprof_desc'] = (($profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : ''); $arr['xprof_dob'] = datetime_convert('','',$profile['birthday'],'Y-m-d'); // !!!! check this for 0000 year - $arr['xprof_age'] = (($profile['age']) ? intval($profile['age']) : 0); - $arr['xprof_gender'] = (($profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_marital'] = (($profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_sexual'] = (($profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_locale'] = (($profile['locale']) ? htmlspecialchars($profile['locale'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_region'] = (($profile['region']) ? htmlspecialchars($profile['region'], ENT_COMPAT,'UTF-8',false) : ''); + $arr['xprof_age'] = (($profile['age']) ? intval($profile['age']) : 0); + $arr['xprof_desc'] = (($profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : ''); + $arr['xprof_gender'] = (($profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT,'UTF-8',false) : ''); + $arr['xprof_marital'] = (($profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT,'UTF-8',false) : ''); + $arr['xprof_sexual'] = (($profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT,'UTF-8',false) : ''); + $arr['xprof_locale'] = (($profile['locale']) ? htmlspecialchars($profile['locale'], ENT_COMPAT,'UTF-8',false) : ''); + $arr['xprof_region'] = (($profile['region']) ? htmlspecialchars($profile['region'], ENT_COMPAT,'UTF-8',false) : ''); $arr['xprof_postcode'] = (($profile['postcode']) ? htmlspecialchars($profile['postcode'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_country'] = (($profile['country']) ? htmlspecialchars($profile['country'], ENT_COMPAT,'UTF-8',false) : ''); - - $arr['xprof_about'] = (($profile['about']) ? htmlspecialchars($profile['about'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_homepage'] = (($profile['homepage']) ? htmlspecialchars($profile['homepage'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_hometown'] = (($profile['hometown']) ? htmlspecialchars($profile['hometown'], ENT_COMPAT,'UTF-8',false) : ''); + $arr['xprof_country'] = (($profile['country']) ? htmlspecialchars($profile['country'], ENT_COMPAT,'UTF-8',false) : ''); + $arr['xprof_about'] = (($profile['about']) ? htmlspecialchars($profile['about'], ENT_COMPAT,'UTF-8',false) : ''); + $arr['xprof_homepage'] = (($profile['homepage']) ? htmlspecialchars($profile['homepage'], ENT_COMPAT,'UTF-8',false) : ''); + $arr['xprof_hometown'] = (($profile['hometown']) ? htmlspecialchars($profile['hometown'], ENT_COMPAT,'UTF-8',false) : ''); $clean = array(); if(array_key_exists('keywords',$profile) and is_array($profile['keywords'])) { @@ -2057,10 +2094,11 @@ function build_sync_packet($uid = 0, $packet = null) { foreach($synchubs as $hub) { $hash = random_string(); $n = zot_build_packet($channel,'notify',$env_recips,$hub['hubloc_sitekey'],$hash); - q("insert into outq ( outq_hash, outq_account, outq_channel, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s' )", + q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", dbesc($hash), intval($channel['channel_account']), intval($channel['channel_id']), + dbesc('zot'), dbesc($hub['hubloc_callback']), intval(1), dbesc(datetime_convert()), @@ -2098,7 +2136,7 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { if($channel['channel_hash'] != $sender['hash']) { logger('process_channel_sync_delivery: possible forgery. Sender ' . $sender['hash'] . ' is not ' . $channel['channel_hash']); - $result[] = array($d['hash'],'channel mismatch',$channel['channel_name']); + $result[] = array($d['hash'],'channel mismatch',$channel['channel_name'],''); continue; } @@ -2193,7 +2231,7 @@ function process_channel_sync_delivery($sender,$arr,$deliveries) { } } - $result[] = array($d['hash'],'channel sync updated',$channel['channel_name']); + $result[] = array($d['hash'],'channel sync updated',$channel['channel_name'],''); } |