2011-11-01 03:39:04 +00:00
< ? php
2015-12-25 22:17:34 +00:00
/**
* @ file include / socgraph . php
2017-04-30 04:01:26 +00:00
*
2015-12-25 22:17:34 +00:00
* @ todo Move GNU Social URL schemata ( http :// server . tld / user / number ) to http :// server . tld / username
* @ todo Fetch profile data from profile page for Redmatrix users
* @ todo Detect if it is a forum
*/
2011-11-01 03:39:04 +00:00
2017-04-30 04:07:00 +00:00
use Friendica\App ;
2017-08-26 06:04:21 +00:00
use Friendica\Core\System ;
2017-04-30 04:01:26 +00:00
use Friendica\Core\Config ;
2017-11-05 12:15:53 +00:00
use Friendica\Core\Worker ;
2017-05-07 18:44:30 +00:00
use Friendica\Network\Probe ;
2017-05-07 18:40:23 +00:00
require_once 'include/datetime.php' ;
require_once 'include/network.php' ;
require_once 'include/html2bbcode.php' ;
require_once 'include/Contact.php' ;
require_once 'include/Photo.php' ;
2015-07-22 09:51:37 +00:00
2017-03-19 21:32:11 +00:00
/**
* @ brief Fetch POCO data
*
* @ param integer $cid Contact ID
* @ param integer $uid User ID
* @ param integer $zcid Global Contact ID
* @ param integer $url POCO address that should be polled
2011-11-01 03:39:04 +00:00
*
* Given a contact - id ( minimum ), load the PortableContacts friend list for that contact ,
* and add the entries to the gcontact ( Global Contact ) table , or update existing entries
* if anything ( name or photo ) has changed .
* We use normalised urls for comparison which ignore http vs https and www . domain vs domain
*
* Once the global contact is stored add ( if necessary ) the contact linkage which associates
* the given uid , cid to the global contact entry . There can be many uid / cid combinations
2015-01-08 06:59:20 +00:00
* pointing to the same global contact id .
2011-11-01 03:39:04 +00:00
*
*/
2017-03-19 21:32:11 +00:00
function poco_load ( $cid , $uid = 0 , $zcid = 0 , $url = null ) {
// Call the function "poco_load_worker" via the worker
2017-11-05 12:15:53 +00:00
Worker :: add ( PRIORITY_LOW , " discover_poco " , " poco_load " , ( int ) $cid , ( int ) $uid , ( int ) $zcid , $url );
2017-03-19 21:32:11 +00:00
}
2015-01-08 06:59:20 +00:00
2017-03-19 21:32:11 +00:00
/**
* @ brief Fetch POCO data from the worker
*
* @ param integer $cid Contact ID
* @ param integer $uid User ID
* @ param integer $zcid Global Contact ID
* @ param integer $url POCO address that should be polled
*
*/
function poco_load_worker ( $cid , $uid , $zcid , $url ) {
2011-11-01 03:39:04 +00:00
$a = get_app ();
2011-11-29 03:28:33 +00:00
2017-04-04 17:48:25 +00:00
if ( $cid ) {
if (( ! $url ) || ( ! $uid )) {
2011-11-29 03:28:33 +00:00
$r = q ( " select `poco`, `uid` from `contact` where `id` = %d limit 1 " ,
intval ( $cid )
);
2016-12-14 08:42:36 +00:00
if ( dbm :: is_result ( $r )) {
2011-11-29 03:28:33 +00:00
$url = $r [ 0 ][ 'poco' ];
$uid = $r [ 0 ][ 'uid' ];
}
2011-11-01 03:39:04 +00:00
}
2017-06-18 20:10:03 +00:00
if ( ! $uid ) {
2011-11-29 03:28:33 +00:00
return ;
2017-06-18 20:10:03 +00:00
}
2011-11-01 03:39:04 +00:00
}
2011-11-29 03:28:33 +00:00
2017-06-18 20:10:03 +00:00
if ( ! $url ) {
2011-11-01 03:39:04 +00:00
return ;
2017-06-18 20:10:03 +00:00
}
2011-11-29 03:28:33 +00:00
2016-10-04 03:48:01 +00:00
$url = $url . (( $uid ) ? '/@me/@all?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation' : '?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation' ) ;
2011-11-29 03:28:33 +00:00
2011-12-19 08:40:00 +00:00
logger ( 'poco_load: ' . $url , LOGGER_DEBUG );
2011-12-15 21:52:52 +00:00
2011-12-19 08:40:00 +00:00
$s = fetch_url ( $url );
logger ( 'poco_load: returns ' . $s , LOGGER_DATA );
logger ( 'poco_load: return code: ' . $a -> get_curl_code (), LOGGER_DEBUG );
2011-11-01 03:39:04 +00:00
2017-06-18 20:10:03 +00:00
if (( $a -> get_curl_code () > 299 ) || ( ! $s )) {
2011-11-01 03:39:04 +00:00
return ;
2017-06-18 20:10:03 +00:00
}
2011-12-19 08:40:00 +00:00
2011-11-01 03:39:04 +00:00
$j = json_decode ( $s );
2011-12-19 08:40:00 +00:00
logger ( 'poco_load: json: ' . print_r ( $j , true ), LOGGER_DATA );
2017-06-18 20:10:03 +00:00
if ( ! isset ( $j -> entry )) {
2011-12-20 00:51:57 +00:00
return ;
2017-06-18 20:10:03 +00:00
}
2011-12-20 00:51:57 +00:00
2011-12-19 08:40:00 +00:00
$total = 0 ;
2017-04-04 17:48:25 +00:00
foreach ( $j -> entry as $entry ) {
2011-11-01 03:39:04 +00:00
2011-12-19 08:40:00 +00:00
$total ++ ;
2011-11-01 03:39:04 +00:00
$profile_url = '' ;
$profile_photo = '' ;
2011-12-18 08:50:17 +00:00
$connect_url = '' ;
2011-11-01 03:39:04 +00:00
$name = '' ;
2015-01-08 06:59:20 +00:00
$network = '' ;
2017-02-27 23:37:15 +00:00
$updated = NULL_DATE ;
2015-01-25 01:29:46 +00:00
$location = '' ;
$about = '' ;
2015-01-25 12:19:37 +00:00
$keywords = '' ;
$gender = '' ;
2016-10-04 03:48:01 +00:00
$contact_type = - 1 ;
2015-02-15 09:52:45 +00:00
$generation = 0 ;
2011-11-01 03:39:04 +00:00
$name = $entry -> displayName ;
2016-12-20 16:43:46 +00:00
if ( isset ( $entry -> urls )) {
foreach ( $entry -> urls as $url ) {
2016-12-20 10:36:03 +00:00
if ( $url -> type == 'profile' ) {
2012-05-23 04:20:31 +00:00
$profile_url = $url -> value ;
continue ;
}
2016-12-20 10:36:03 +00:00
if ( $url -> type == 'webfinger' ) {
2012-05-23 04:20:31 +00:00
$connect_url = str_replace ( 'acct:' , '' , $url -> value );
continue ;
}
2011-11-01 03:39:04 +00:00
}
2012-05-23 04:20:31 +00:00
}
2016-12-20 10:36:03 +00:00
if ( isset ( $entry -> photos )) {
2016-12-20 16:43:46 +00:00
foreach ( $entry -> photos as $photo ) {
2016-12-20 10:36:03 +00:00
if ( $photo -> type == 'profile' ) {
2012-05-23 04:20:31 +00:00
$profile_photo = $photo -> value ;
continue ;
}
2011-11-01 03:39:04 +00:00
}
}
2016-12-20 16:43:46 +00:00
if ( isset ( $entry -> updated )) {
2015-01-04 18:19:47 +00:00
$updated = date ( " Y-m-d H:i:s " , strtotime ( $entry -> updated ));
2016-12-20 16:43:46 +00:00
}
2015-01-04 18:19:47 +00:00
2016-12-20 16:43:46 +00:00
if ( isset ( $entry -> network )) {
2015-01-08 06:59:20 +00:00
$network = $entry -> network ;
2016-12-20 16:43:46 +00:00
}
2015-01-08 06:59:20 +00:00
2016-12-20 16:43:46 +00:00
if ( isset ( $entry -> currentLocation )) {
2015-01-25 01:29:46 +00:00
$location = $entry -> currentLocation ;
2016-12-20 16:43:46 +00:00
}
2015-01-25 01:29:46 +00:00
2016-12-20 16:43:46 +00:00
if ( isset ( $entry -> aboutMe )) {
2015-02-04 18:49:43 +00:00
$about = html2bbcode ( $entry -> aboutMe );
2016-12-20 16:43:46 +00:00
}
2015-01-25 01:29:46 +00:00
2016-12-20 16:43:46 +00:00
if ( isset ( $entry -> gender )) {
2015-01-25 12:19:37 +00:00
$gender = $entry -> gender ;
2016-12-20 16:43:46 +00:00
}
2015-01-25 01:29:46 +00:00
2017-06-08 02:00:59 +00:00
if ( isset ( $entry -> generation ) && ( $entry -> generation > 0 )) {
2015-02-15 09:52:45 +00:00
$generation = ++ $entry -> generation ;
2016-12-20 16:43:46 +00:00
}
2015-02-15 09:52:45 +00:00
2016-12-20 16:43:46 +00:00
if ( isset ( $entry -> tags )) {
2017-04-04 17:48:25 +00:00
foreach ( $entry -> tags as $tag ) {
2015-01-25 15:40:20 +00:00
$keywords = implode ( " , " , $tag );
2016-12-20 16:43:46 +00:00
}
}
2015-01-25 15:40:20 +00:00
2017-06-18 20:10:03 +00:00
if ( isset ( $entry -> contactType ) && ( $entry -> contactType >= 0 )) {
2016-10-04 03:48:01 +00:00
$contact_type = $entry -> contactType ;
2017-06-18 20:10:03 +00:00
}
2016-10-04 03:48:01 +00:00
2017-03-23 06:23:23 +00:00
$gcontact = array ( " url " => $profile_url ,
" name " => $name ,
" network " => $network ,
" photo " => $profile_photo ,
" about " => $about ,
" location " => $location ,
" gender " => $gender ,
" keywords " => $keywords ,
" connect " => $connect_url ,
" updated " => $updated ,
" contact-type " => $contact_type ,
" generation " => $generation );
2017-03-25 16:56:04 +00:00
try {
$gcontact = sanitize_gcontact ( $gcontact );
2017-03-23 06:23:23 +00:00
$gcid = update_gcontact ( $gcontact );
link_gcontact ( $gcid , $uid , $cid , $zcid );
2017-03-25 16:56:04 +00:00
} catch ( Exception $e ) {
logger ( $e -> getMessage (), LOGGER_DEBUG );
2017-03-23 06:23:23 +00:00
}
2011-11-01 03:39:04 +00:00
}
2011-12-19 08:40:00 +00:00
logger ( " poco_load: loaded $total entries " , LOGGER_DEBUG );
2011-11-01 03:39:04 +00:00
2015-01-05 07:03:29 +00:00
q ( " DELETE FROM `glink` WHERE `cid` = %d AND `uid` = %d AND `zcid` = %d AND `updated` < UTC_TIMESTAMP - INTERVAL 2 DAY " ,
2012-05-01 08:34:47 +00:00
intval ( $cid ),
intval ( $uid ),
intval ( $zcid )
);
2011-11-01 03:39:04 +00:00
2011-11-02 02:16:33 +00:00
}
2017-03-22 23:13:32 +00:00
/**
2017-03-23 06:23:23 +00:00
* @ brief Sanitize the given gcontact data
2017-03-22 23:13:32 +00:00
*
* @ param array $gcontact array with gcontact data
2017-03-25 18:00:56 +00:00
* @ throw Exception
2017-03-22 23:13:32 +00:00
*
* Generation :
* 0 : No definition
* 1 : Profiles on this server
* 2 : Contacts of profiles on this server
* 3 : Contacts of contacts of profiles on this server
* 4 : ...
*
*/
2017-03-25 18:00:56 +00:00
function sanitize_gcontact ( $gcontact ) {
2017-03-22 23:13:32 +00:00
if ( $gcontact [ 'url' ] == " " ) {
2017-03-25 16:56:04 +00:00
throw new Exception ( 'URL is empty' );
2017-03-22 23:13:32 +00:00
}
$urlparts = parse_url ( $gcontact [ 'url' ]);
if ( ! isset ( $urlparts [ " scheme " ])) {
2017-03-25 16:56:04 +00:00
throw new Exception ( " This ( " . $gcontact [ 'url' ] . " ) doesn't seem to be an url. " );
2017-03-22 23:13:32 +00:00
}
if ( in_array ( $urlparts [ " host " ], array ( " www.facebook.com " , " facebook.com " , " twitter.com " ,
" identi.ca " , " alpha.app.net " ))) {
2017-03-25 16:56:04 +00:00
throw new Exception ( 'Contact from a non federated network ignored. (' . $gcontact [ 'url' ] . ')' );
2017-03-22 23:13:32 +00:00
}
// Don't store the statusnet connector as network
// We can't simply set this to NETWORK_OSTATUS since the connector could have fetched posts from friendica as well
if ( $gcontact [ 'network' ] == NETWORK_STATUSNET ) {
$gcontact [ 'network' ] = " " ;
}
// Assure that there are no parameter fragments in the profile url
if ( in_array ( $gcontact [ 'network' ], array ( NETWORK_DFRN , NETWORK_DIASPORA , NETWORK_OSTATUS , " " ))) {
$gcontact [ 'url' ] = clean_contact_url ( $gcontact [ 'url' ]);
}
$alternate = poco_alternate_ostatus_url ( $gcontact [ 'url' ]);
// The global contacts should contain the original picture, not the cached one
2017-08-26 07:32:10 +00:00
if (( $gcontact [ 'generation' ] != 1 ) && stristr ( normalise_link ( $gcontact [ 'photo' ]), normalise_link ( System :: baseUrl () . " /photo/ " ))) {
2017-03-22 23:13:32 +00:00
$gcontact [ 'photo' ] = " " ;
}
if ( ! isset ( $gcontact [ 'network' ])) {
$r = q ( " SELECT `network` FROM `contact` WHERE `uid` = 0 AND `nurl` = '%s' AND `network` != '' AND `network` != '%s' LIMIT 1 " ,
dbesc ( normalise_link ( $gcontact [ 'url' ])), dbesc ( NETWORK_STATUSNET )
);
if ( dbm :: is_result ( $r )) {
$gcontact [ 'network' ] = $r [ 0 ][ " network " ];
}
2017-06-08 02:00:59 +00:00
if (( $gcontact [ 'network' ] == " " ) || ( $gcontact [ 'network' ] == NETWORK_OSTATUS )) {
2017-03-22 23:13:32 +00:00
$r = q ( " SELECT `network`, `url` FROM `contact` WHERE `uid` = 0 AND `alias` IN ('%s', '%s') AND `network` != '' AND `network` != '%s' LIMIT 1 " ,
dbesc ( $gcontact [ 'url' ]), dbesc ( normalise_link ( $gcontact [ 'url' ])), dbesc ( NETWORK_STATUSNET )
);
if ( dbm :: is_result ( $r )) {
$gcontact [ 'network' ] = $r [ 0 ][ " network " ];
}
}
}
2017-03-23 22:56:22 +00:00
$gcontact [ 'server_url' ] = '' ;
$gcontact [ 'network' ] = '' ;
2017-03-22 23:13:32 +00:00
$x = q ( " SELECT * FROM `gcontact` WHERE `nurl` = '%s' LIMIT 1 " ,
dbesc ( normalise_link ( $gcontact [ 'url' ]))
);
2017-06-18 20:10:03 +00:00
if ( dbm :: is_result ( $x )) {
2017-06-08 02:00:59 +00:00
if ( ! isset ( $gcontact [ 'network' ]) && ( $x [ 0 ][ " network " ] != NETWORK_STATUSNET )) {
2017-03-22 23:13:32 +00:00
$gcontact [ 'network' ] = $x [ 0 ][ " network " ];
}
if ( $gcontact [ 'updated' ] <= NULL_DATE ) {
$gcontact [ 'updated' ] = $x [ 0 ][ " updated " ];
}
2017-06-08 02:00:59 +00:00
if ( ! isset ( $gcontact [ 'server_url' ]) && ( normalise_link ( $x [ 0 ][ " server_url " ]) != normalise_link ( $x [ 0 ][ " url " ]))) {
2017-03-22 23:13:32 +00:00
$gcontact [ 'server_url' ] = $x [ 0 ][ " server_url " ];
}
if ( ! isset ( $gcontact [ 'addr' ])) {
$gcontact [ 'addr' ] = $x [ 0 ][ " addr " ];
}
}
2017-06-08 02:00:59 +00:00
if (( ! isset ( $gcontact [ 'network' ]) || ! isset ( $gcontact [ 'name' ]) || ! isset ( $gcontact [ 'addr' ]) || ! isset ( $gcontact [ 'photo' ]) || ! isset ( $gcontact [ 'server_url' ]) || $alternate )
&& poco_reachable ( $gcontact [ 'url' ], $gcontact [ 'server_url' ], $gcontact [ 'network' ], false )) {
2017-03-22 23:13:32 +00:00
$data = Probe :: uri ( $gcontact [ 'url' ]);
if ( $data [ " network " ] == NETWORK_PHANTOM ) {
2017-03-25 16:56:04 +00:00
throw new Exception ( 'Probing for URL ' . $gcontact [ 'url' ] . ' failed' );
2017-03-22 23:13:32 +00:00
}
$orig_profile = $gcontact [ 'url' ];
$gcontact [ " server_url " ] = $data [ " baseurl " ];
$gcontact = array_merge ( $gcontact , $data );
2017-06-08 02:00:59 +00:00
if ( $alternate && ( $gcontact [ 'network' ] == NETWORK_OSTATUS )) {
2017-03-22 23:13:32 +00:00
// Delete the old entry - if it exists
$r = q ( " SELECT `id` FROM `gcontact` WHERE `nurl` = '%s' " , dbesc ( normalise_link ( $orig_profile )));
2017-06-18 20:10:03 +00:00
if ( dbm :: is_result ( $r )) {
2017-03-22 23:13:32 +00:00
q ( " DELETE FROM `gcontact` WHERE `nurl` = '%s' " , dbesc ( normalise_link ( $orig_profile )));
q ( " DELETE FROM `glink` WHERE `gcid` = %d " , intval ( $r [ 0 ][ " id " ]));
}
}
}
2017-06-08 02:00:59 +00:00
if ( ! isset ( $gcontact [ 'name' ]) || ! isset ( $gcontact [ 'photo' ])) {
2017-03-25 16:56:04 +00:00
throw new Exception ( 'No name and photo for URL ' . $gcontact [ 'url' ]);
2017-03-22 23:13:32 +00:00
}
if ( ! in_array ( $gcontact [ 'network' ], array ( NETWORK_DFRN , NETWORK_OSTATUS , NETWORK_DIASPORA ))) {
2017-03-25 16:56:04 +00:00
throw new Exception ( 'No federated network (' . $gcontact [ 'network' ] . ') detected for URL ' . $gcontact [ 'url' ]);
2017-03-22 23:13:32 +00:00
}
if ( ! isset ( $gcontact [ 'server_url' ])) {
// We check the server url to be sure that it is a real one
$server_url = poco_detect_server ( $gcontact [ 'url' ]);
// We are now sure that it is a correct URL. So we use it in the future
if ( $server_url != " " ) {
$gcontact [ 'server_url' ] = $server_url ;
}
}
// The server URL doesn't seem to be valid, so we don't store it.
if ( ! poco_check_server ( $gcontact [ 'server_url' ], $gcontact [ 'network' ])) {
$gcontact [ 'server_url' ] = " " ;
}
2017-03-25 16:56:04 +00:00
return $gcontact ;
2017-03-22 23:13:32 +00:00
}
2011-11-02 02:16:33 +00:00
2017-03-23 06:23:23 +00:00
/**
* @ brief Link the gcontact entry with user , contact and global contact
*
* @ param integer $gcid Global contact ID
* @ param integer $cid Contact ID
* @ param integer $uid User ID
* @ param integer $zcid Global Contact ID
* *
*/
function link_gcontact ( $gcid , $uid = 0 , $cid = 0 , $zcid = 0 ) {
2017-03-04 13:30:34 +00:00
2017-03-23 06:23:23 +00:00
if ( $gcid <= 0 ) {
return ;
2017-03-04 13:30:34 +00:00
}
2015-01-06 07:16:15 +00:00
$r = q ( " SELECT * FROM `glink` WHERE `cid` = %d AND `uid` = %d AND `gcid` = %d AND `zcid` = %d LIMIT 1 " ,
intval ( $cid ),
intval ( $uid ),
intval ( $gcid ),
intval ( $zcid )
);
2017-06-18 20:10:03 +00:00
2017-03-22 05:26:44 +00:00
if ( ! dbm :: is_result ( $r )) {
q ( " INSERT INTO `glink` (`cid`, `uid`, `gcid`, `zcid`, `updated`) VALUES (%d, %d, %d, %d, '%s') " ,
2015-01-06 07:16:15 +00:00
intval ( $cid ),
intval ( $uid ),
intval ( $gcid ),
intval ( $zcid ),
dbesc ( datetime_convert ())
);
} else {
q ( " UPDATE `glink` SET `updated` = '%s' WHERE `cid` = %d AND `uid` = %d AND `gcid` = %d AND `zcid` = %d " ,
dbesc ( datetime_convert ()),
intval ( $cid ),
intval ( $uid ),
intval ( $gcid ),
intval ( $zcid )
);
}
2015-01-06 06:23:11 +00:00
}
2011-11-02 02:16:33 +00:00
2015-07-25 18:10:42 +00:00
function poco_reachable ( $profile , $server = " " , $network = " " , $force = false ) {
2015-07-22 09:51:37 +00:00
2017-04-04 17:48:25 +00:00
if ( $server == " " ) {
2015-07-22 09:51:37 +00:00
$server = poco_detect_server ( $profile );
2017-04-04 17:48:25 +00:00
}
2015-07-22 09:51:37 +00:00
2017-04-04 17:48:25 +00:00
if ( $server == " " ) {
2015-07-22 09:51:37 +00:00
return true ;
2017-04-04 17:48:25 +00:00
}
2015-07-22 09:51:37 +00:00
2015-07-25 18:10:42 +00:00
return poco_check_server ( $server , $network , $force );
2015-07-22 09:51:37 +00:00
}
function poco_detect_server ( $profile ) {
// Try to detect the server path based upon some known standard paths
$server_url = " " ;
if ( $server_url == " " ) {
$friendica = preg_replace ( " =(https?://)(.*)/profile/(.*)=ism " , " $ 1 $ 2 " , $profile );
if ( $friendica != $profile ) {
$server_url = $friendica ;
$network = NETWORK_DFRN ;
}
}
if ( $server_url == " " ) {
$diaspora = preg_replace ( " =(https?://)(.*)/u/(.*)=ism " , " $ 1 $ 2 " , $profile );
if ( $diaspora != $profile ) {
$server_url = $diaspora ;
$network = NETWORK_DIASPORA ;
}
}
if ( $server_url == " " ) {
$red = preg_replace ( " =(https?://)(.*)/channel/(.*)=ism " , " $ 1 $ 2 " , $profile );
if ( $red != $profile ) {
$server_url = $red ;
$network = NETWORK_DIASPORA ;
}
}
2016-12-12 06:46:02 +00:00
// Mastodon
if ( $server_url == " " ) {
2017-03-04 13:30:34 +00:00
$mastodon = preg_replace ( " =(https?://)(.*)/users/(.*)=ism " , " $ 1 $ 2 " , $profile );
if ( $mastodon != $profile ) {
$server_url = $mastodon ;
2016-12-12 06:46:02 +00:00
$network = NETWORK_OSTATUS ;
}
}
2017-03-04 13:30:34 +00:00
// Numeric OStatus variant
if ( $server_url == " " ) {
$ostatus = preg_replace ( " =(https?://)(.*)/user/(.*)=ism " , " $ 1 $ 2 " , $profile );
if ( $ostatus != $profile ) {
$server_url = $ostatus ;
2016-12-12 06:46:02 +00:00
$network = NETWORK_OSTATUS ;
}
}
2017-03-04 13:30:34 +00:00
// Wild guess
if ( $server_url == " " ) {
$base = preg_replace ( " =(https?://)(.*?)/(.*)=ism " , " $ 1 $ 2 " , $profile );
2017-03-13 06:32:33 +00:00
if ( $base != $profile ) {
2017-03-04 13:30:34 +00:00
$server_url = $base ;
$network = NETWORK_PHANTOM ;
}
}
if ( $server_url == " " ) {
return " " ;
}
$r = q ( " SELECT `id` FROM `gserver` WHERE `nurl` = '%s' AND `last_contact` > `last_failure` " ,
dbesc ( normalise_link ( $server_url )));
if ( dbm :: is_result ( $r )) {
return $server_url ;
}
// Fetch the host-meta to check if this really is a server
$serverret = z_fetch_url ( $server_url . " /.well-known/host-meta " );
if ( ! $serverret [ " success " ]) {
return " " ;
}
2015-07-22 09:51:37 +00:00
return $server_url ;
}
2015-08-24 14:35:05 +00:00
function poco_alternate_ostatus_url ( $url ) {
return ( preg_match ( " =https?://.+/user/ \ d+=ism " , $url , $matches ));
}
2015-07-27 06:14:04 +00:00
function poco_last_updated ( $profile , $force = false ) {
2015-07-19 19:29:24 +00:00
$gcontacts = q ( " SELECT * FROM `gcontact` WHERE `nurl` = '%s' " ,
dbesc ( normalise_link ( $profile )));
2017-03-23 22:56:22 +00:00
if ( ! dbm :: is_result ( $gcontacts )) {
return false ;
}
$contact = array ( " url " => $profile );
2017-03-19 08:04:04 +00:00
if ( $gcontacts [ 0 ][ " created " ] <= NULL_DATE ) {
2017-03-23 22:56:22 +00:00
$contact [ 'created' ] = datetime_convert ();
}
if ( $force ) {
$server_url = normalise_link ( poco_detect_server ( $profile ));
2017-03-19 08:04:04 +00:00
}
2017-03-23 22:56:22 +00:00
2017-06-08 02:00:59 +00:00
if (( $server_url == '' ) && ( $gcontacts [ 0 ][ " server_url " ] != " " )) {
2015-07-23 08:28:40 +00:00
$server_url = $gcontacts [ 0 ][ " server_url " ];
2017-03-04 13:30:34 +00:00
}
2017-03-23 22:56:22 +00:00
2017-06-08 02:00:59 +00:00
if ( ! $force && (( $server_url == '' ) || ( $gcontacts [ 0 ][ " server_url " ] == $gcontacts [ 0 ][ " nurl " ]))) {
2017-03-23 22:56:22 +00:00
$server_url = normalise_link ( poco_detect_server ( $profile ));
2017-03-04 13:30:34 +00:00
}
2015-07-23 08:28:40 +00:00
2016-04-23 08:46:16 +00:00
if ( ! in_array ( $gcontacts [ 0 ][ " network " ], array ( NETWORK_DFRN , NETWORK_DIASPORA , NETWORK_FEED , NETWORK_OSTATUS , " " ))) {
logger ( " Profile " . $profile . " : Network type " . $gcontacts [ 0 ][ " network " ] . " can't be checked " , LOGGER_DEBUG );
return false ;
}
2015-07-28 13:28:58 +00:00
if ( $server_url != " " ) {
2015-07-28 16:26:30 +00:00
if ( ! poco_check_server ( $server_url , $gcontacts [ 0 ][ " network " ], $force )) {
2017-03-23 22:56:22 +00:00
if ( $force ) {
2015-07-28 16:26:30 +00:00
q ( " UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s' " ,
dbesc ( datetime_convert ()), dbesc ( normalise_link ( $profile )));
2017-03-23 22:56:22 +00:00
}
2015-07-28 16:26:30 +00:00
2016-04-23 08:46:16 +00:00
logger ( " Profile " . $profile . " : Server " . $server_url . " wasn't reachable. " , LOGGER_DEBUG );
2015-07-19 19:29:24 +00:00
return false ;
2015-07-28 16:26:30 +00:00
}
2017-03-23 22:56:22 +00:00
$contact [ 'server_url' ] = $server_url ;
2015-07-28 13:28:58 +00:00
}
if ( in_array ( $gcontacts [ 0 ][ " network " ], array ( " " , NETWORK_FEED ))) {
$server = q ( " SELECT `network` FROM `gserver` WHERE `nurl` = '%s' AND `network` != '' " ,
dbesc ( normalise_link ( $server_url )));
2017-03-23 22:56:22 +00:00
if ( $server ) {
$contact [ 'network' ] = $server [ 0 ][ " network " ];
} else {
2016-04-23 08:46:16 +00:00
return false ;
2017-03-23 22:56:22 +00:00
}
2015-07-28 13:28:58 +00:00
}
2015-07-20 22:05:44 +00:00
// noscrape is really fast so we don't cache the call.
2017-06-08 02:00:59 +00:00
if (( $server_url != " " ) && ( $gcontacts [ 0 ][ " nick " ] != " " )) {
2015-07-20 22:05:44 +00:00
// Use noscrape if possible
2017-03-23 22:56:22 +00:00
$server = q ( " SELECT `noscrape`, `network` FROM `gserver` WHERE `nurl` = '%s' AND `noscrape` != '' " , dbesc ( normalise_link ( $server_url )));
2015-07-20 22:05:44 +00:00
if ( $server ) {
$noscraperet = z_fetch_url ( $server [ 0 ][ " noscrape " ] . " / " . $gcontacts [ 0 ][ " nick " ]);
2015-07-30 14:30:18 +00:00
2017-06-08 02:00:59 +00:00
if ( $noscraperet [ " success " ] && ( $noscraperet [ " body " ] != " " )) {
2015-08-24 12:23:30 +00:00
2015-07-20 22:05:44 +00:00
$noscrape = json_decode ( $noscraperet [ " body " ], true );
2016-02-18 06:41:08 +00:00
if ( is_array ( $noscrape )) {
2017-03-23 22:56:22 +00:00
$contact [ " network " ] = $server [ 0 ][ " network " ];
2016-02-18 06:41:08 +00:00
2017-03-23 22:56:22 +00:00
if ( isset ( $noscrape [ " fn " ])) {
2016-05-04 21:50:31 +00:00
$contact [ " name " ] = $noscrape [ " fn " ];
2017-03-23 22:56:22 +00:00
}
if ( isset ( $noscrape [ " comm " ])) {
2016-05-04 21:50:31 +00:00
$contact [ " community " ] = $noscrape [ " comm " ];
2017-03-23 22:56:22 +00:00
}
2016-02-18 06:41:08 +00:00
if ( isset ( $noscrape [ " tags " ])) {
$keywords = implode ( " " , $noscrape [ " tags " ]);
2017-03-23 22:56:22 +00:00
if ( $keywords != " " ) {
2016-02-18 06:41:08 +00:00
$contact [ " keywords " ] = $keywords ;
2017-03-23 22:56:22 +00:00
}
2016-02-18 06:41:08 +00:00
}
$location = formatted_location ( $noscrape );
2017-03-23 22:56:22 +00:00
if ( $location ) {
2016-02-18 06:41:08 +00:00
$contact [ " location " ] = $location ;
2017-03-23 22:56:22 +00:00
}
if ( isset ( $noscrape [ " dfrn-notify " ])) {
2016-05-04 21:50:31 +00:00
$contact [ " notify " ] = $noscrape [ " dfrn-notify " ];
2017-03-23 22:56:22 +00:00
}
2016-02-18 06:41:08 +00:00
// Remove all fields that are not present in the gcontact table
unset ( $noscrape [ " fn " ]);
unset ( $noscrape [ " key " ]);
unset ( $noscrape [ " homepage " ]);
unset ( $noscrape [ " comm " ]);
unset ( $noscrape [ " tags " ]);
unset ( $noscrape [ " locality " ]);
unset ( $noscrape [ " region " ]);
unset ( $noscrape [ " country-name " ]);
unset ( $noscrape [ " contacts " ]);
unset ( $noscrape [ " dfrn-request " ]);
unset ( $noscrape [ " dfrn-confirm " ]);
unset ( $noscrape [ " dfrn-notify " ]);
unset ( $noscrape [ " dfrn-poll " ]);
2016-04-23 08:46:16 +00:00
// Set the date of the last contact
/// @todo By now the function "update_gcontact" doesn't work with this field
//$contact["last_contact"] = datetime_convert();
2016-02-18 06:41:08 +00:00
$contact = array_merge ( $contact , $noscrape );
update_gcontact ( $contact );
2016-04-23 08:46:16 +00:00
if ( trim ( $noscrape [ " updated " ]) != " " ) {
q ( " UPDATE `gcontact` SET `last_contact` = '%s' WHERE `nurl` = '%s' " ,
dbesc ( datetime_convert ()), dbesc ( normalise_link ( $profile )));
logger ( " Profile " . $profile . " was last updated at " . $noscrape [ " updated " ] . " (noscrape) " , LOGGER_DEBUG );
return $noscrape [ " updated " ];
}
2015-07-20 22:05:44 +00:00
}
}
}
2015-07-19 19:29:24 +00:00
}
2015-07-20 22:05:44 +00:00
// If we only can poll the feed, then we only do this once a while
2017-06-08 02:00:59 +00:00
if ( ! $force && ! poco_do_update ( $gcontacts [ 0 ][ " created " ], $gcontacts [ 0 ][ " updated " ], $gcontacts [ 0 ][ " last_failure " ], $gcontacts [ 0 ][ " last_contact " ])) {
2016-04-23 08:46:16 +00:00
logger ( " Profile " . $profile . " was last updated at " . $gcontacts [ 0 ][ " updated " ] . " (cached) " , LOGGER_DEBUG );
2017-03-23 22:56:22 +00:00
update_gcontact ( $contact );
2015-07-22 09:51:37 +00:00
return $gcontacts [ 0 ][ " updated " ];
2016-04-23 08:46:16 +00:00
}
2015-07-20 22:05:44 +00:00
2017-03-22 23:13:32 +00:00
$data = Probe :: uri ( $profile );
2015-07-16 23:08:28 +00:00
2015-08-24 12:23:30 +00:00
// Is the profile link the alternate OStatus link notation? (http://domain.tld/user/4711)
2015-08-24 14:35:05 +00:00
// Then check the other link and delete this one
2017-06-08 02:00:59 +00:00
if (( $data [ " network " ] == NETWORK_OSTATUS ) && poco_alternate_ostatus_url ( $profile ) &&
( normalise_link ( $profile ) == normalise_link ( $data [ " alias " ])) &&
2015-08-24 12:23:30 +00:00
( normalise_link ( $profile ) != normalise_link ( $data [ " url " ]))) {
2015-08-24 14:35:05 +00:00
// Delete the old entry
q ( " DELETE FROM `gcontact` WHERE `nurl` = '%s' " , dbesc ( normalise_link ( $profile )));
q ( " DELETE FROM `glink` WHERE `gcid` = %d " , intval ( $gcontacts [ 0 ][ " id " ]));
2017-03-23 06:23:23 +00:00
$gcontact = array_merge ( $gcontacts [ 0 ], $data );
2017-03-23 06:45:00 +00:00
$gcontact [ " server_url " ] = $data [ " baseurl " ];
2015-08-24 12:23:30 +00:00
2017-03-25 16:56:04 +00:00
try {
$gcontact = sanitize_gcontact ( $gcontact );
2017-03-23 06:23:23 +00:00
update_gcontact ( $gcontact );
poco_last_updated ( $data [ " url " ], $force );
2017-03-25 16:56:04 +00:00
} catch ( Exception $e ) {
logger ( $e -> getMessage (), LOGGER_DEBUG );
2017-03-23 06:23:23 +00:00
}
2015-08-24 12:23:30 +00:00
2016-04-23 08:46:16 +00:00
logger ( " Profile " . $profile . " was deleted " , LOGGER_DEBUG );
2015-08-24 12:23:30 +00:00
return false ;
}
2017-06-08 02:00:59 +00:00
if (( $data [ " poll " ] == " " ) || ( in_array ( $data [ " network " ], array ( NETWORK_FEED , NETWORK_PHANTOM )))) {
2015-07-19 19:29:24 +00:00
q ( " UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s' " ,
dbesc ( datetime_convert ()), dbesc ( normalise_link ( $profile )));
2016-04-23 08:46:16 +00:00
logger ( " Profile " . $profile . " wasn't reachable (profile) " , LOGGER_DEBUG );
2015-07-16 23:08:28 +00:00
return false ;
2015-07-19 19:29:24 +00:00
}
2016-02-13 11:26:58 +00:00
$contact = array_merge ( $contact , $data );
2015-07-20 22:05:44 +00:00
2016-02-13 11:26:58 +00:00
$contact [ " server_url " ] = $data [ " baseurl " ];
2015-07-19 19:29:24 +00:00
2016-02-13 11:26:58 +00:00
update_gcontact ( $contact );
2015-07-19 19:29:24 +00:00
2015-07-16 23:08:28 +00:00
$feedret = z_fetch_url ( $data [ " poll " ]);
2015-07-19 19:29:24 +00:00
if ( ! $feedret [ " success " ]) {
q ( " UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s' " ,
dbesc ( datetime_convert ()), dbesc ( normalise_link ( $profile )));
2016-04-23 08:46:16 +00:00
logger ( " Profile " . $profile . " wasn't reachable (no feed) " , LOGGER_DEBUG );
2015-07-16 23:08:28 +00:00
return false ;
2015-07-19 19:29:24 +00:00
}
2015-07-16 23:08:28 +00:00
$doc = new DOMDocument ();
@ $doc -> loadXML ( $feedret [ " body " ]);
$xpath = new DomXPath ( $doc );
$xpath -> registerNamespace ( 'atom' , " http://www.w3.org/2005/Atom " );
$entries = $xpath -> query ( '/atom:feed/atom:entry' );
$last_updated = " " ;
2017-06-18 21:14:52 +00:00
foreach ( $entries as $entry ) {
2015-07-16 23:08:28 +00:00
$published = $xpath -> query ( 'atom:published/text()' , $entry ) -> item ( 0 ) -> nodeValue ;
$updated = $xpath -> query ( 'atom:updated/text()' , $entry ) -> item ( 0 ) -> nodeValue ;
if ( $last_updated < $published )
$last_updated = $published ;
if ( $last_updated < $updated )
$last_updated = $updated ;
}
// Maybe there aren't any entries. Then check if it is a valid feed
2017-03-19 08:04:04 +00:00
if ( $last_updated == " " ) {
if ( $xpath -> query ( '/atom:feed' ) -> length > 0 ) {
2017-02-27 23:37:15 +00:00
$last_updated = NULL_DATE ;
2017-03-19 08:04:04 +00:00
}
}
2015-07-19 19:29:24 +00:00
q ( " UPDATE `gcontact` SET `updated` = '%s', `last_contact` = '%s' WHERE `nurl` = '%s' " ,
2017-02-23 05:45:06 +00:00
dbesc ( dbm :: date ( $last_updated )), dbesc ( dbm :: date ()), dbesc ( normalise_link ( $profile )));
2015-07-19 19:29:24 +00:00
2017-03-23 22:56:22 +00:00
if (( $gcontacts [ 0 ][ " generation " ] == 0 )) {
2015-07-19 22:14:14 +00:00
q ( " UPDATE `gcontact` SET `generation` = 9 WHERE `nurl` = '%s' " ,
dbesc ( normalise_link ( $profile )));
2017-03-23 22:56:22 +00:00
}
2015-07-19 22:14:14 +00:00
2016-04-23 08:46:16 +00:00
logger ( " Profile " . $profile . " was last updated at " . $last_updated , LOGGER_DEBUG );
2015-07-16 23:08:28 +00:00
return ( $last_updated );
}
2015-07-20 22:05:44 +00:00
function poco_do_update ( $created , $updated , $last_failure , $last_contact ) {
2015-07-16 23:08:28 +00:00
$now = strtotime ( datetime_convert ());
2017-06-18 20:10:03 +00:00
if ( $updated > $last_contact ) {
2015-07-16 23:08:28 +00:00
$contact_time = strtotime ( $updated );
2017-06-18 20:10:03 +00:00
} else {
2015-07-16 23:08:28 +00:00
$contact_time = strtotime ( $last_contact );
2017-06-18 20:10:03 +00:00
}
2015-07-16 23:08:28 +00:00
$failure_time = strtotime ( $last_failure );
2015-07-20 22:05:44 +00:00
$created_time = strtotime ( $created );
// If there is no "created" time then use the current time
2017-06-18 20:10:03 +00:00
if ( $created_time <= 0 ) {
2015-07-20 22:05:44 +00:00
$created_time = $now ;
2017-06-18 20:10:03 +00:00
}
2015-07-16 23:08:28 +00:00
// If the last contact was less than 24 hours then don't update
2017-06-18 20:10:03 +00:00
if (( $now - $contact_time ) < ( 60 * 60 * 24 )) {
2015-07-16 23:08:28 +00:00
return false ;
2017-06-18 20:10:03 +00:00
}
2015-07-16 23:08:28 +00:00
// If the last failure was less than 24 hours then don't update
2017-06-18 20:10:03 +00:00
if (( $now - $failure_time ) < ( 60 * 60 * 24 )) {
2015-07-16 23:08:28 +00:00
return false ;
2017-06-18 20:10:03 +00:00
}
2015-07-16 23:08:28 +00:00
// If the last contact was less than a week ago and the last failure is older than a week then don't update
2017-06-08 02:00:59 +00:00
//if ((($now - $contact_time) < (60 * 60 * 24 * 7)) && ($contact_time > $failure_time))
2015-07-24 05:23:57 +00:00
// return false;
2015-07-16 23:08:28 +00:00
2015-07-20 22:05:44 +00:00
// If the last contact time was more than a week ago and the contact was created more than a week ago, then only try once a week
2017-06-18 20:10:03 +00:00
if ((( $now - $contact_time ) > ( 60 * 60 * 24 * 7 )) && (( $now - $created_time ) > ( 60 * 60 * 24 * 7 )) && (( $now - $failure_time ) < ( 60 * 60 * 24 * 7 ))) {
2015-07-16 23:08:28 +00:00
return false ;
2017-06-18 20:10:03 +00:00
}
2015-07-16 23:08:28 +00:00
2015-07-20 22:05:44 +00:00
// If the last contact time was more than a month ago and the contact was created more than a month ago, then only try once a month
2017-06-18 20:10:03 +00:00
if ((( $now - $contact_time ) > ( 60 * 60 * 24 * 30 )) && (( $now - $created_time ) > ( 60 * 60 * 24 * 30 )) && (( $now - $failure_time ) < ( 60 * 60 * 24 * 30 ))) {
2015-07-16 23:08:28 +00:00
return false ;
2017-06-18 20:10:03 +00:00
}
2015-07-16 23:08:28 +00:00
return true ;
}
2015-07-18 18:15:21 +00:00
function poco_to_boolean ( $val ) {
2017-06-18 20:10:03 +00:00
if (( $val == " true " ) || ( $val == 1 )) {
return true ;
} elseif (( $val == " false " ) || ( $val == 0 )) {
return false ;
}
2015-07-18 18:15:21 +00:00
2017-06-18 20:10:03 +00:00
return $val ;
2015-07-18 18:15:21 +00:00
}
2017-03-04 07:57:55 +00:00
/**
* @ brief Detect server type ( Hubzilla or Friendica ) via the poco data
*
* @ param object $data POCO data
* @ return array Server data
*/
function poco_detect_poco_data ( $data ) {
$server = false ;
if ( ! isset ( $data -> entry )) {
return false ;
}
if ( count ( $data -> entry ) == 0 ) {
return false ;
}
if ( ! isset ( $data -> entry [ 0 ] -> urls )) {
return false ;
}
if ( count ( $data -> entry [ 0 ] -> urls ) == 0 ) {
return false ;
}
2017-06-18 21:14:52 +00:00
foreach ( $data -> entry [ 0 ] -> urls as $url ) {
2017-03-04 07:57:55 +00:00
if ( $url -> type == 'zot' ) {
$server = array ();
$server [ " platform " ] = 'Hubzilla' ;
$server [ " network " ] = NETWORK_DIASPORA ;
return $server ;
}
}
return false ;
}
2017-03-13 00:03:27 +00:00
/**
* @ brief Detect server type by using the nodeinfo data
*
* @ param string $server_url address of the server
* @ return array Server data
*/
function poco_fetch_nodeinfo ( $server_url ) {
$serverret = z_fetch_url ( $server_url . " /.well-known/nodeinfo " );
if ( ! $serverret [ " success " ]) {
return false ;
}
$nodeinfo = json_decode ( $serverret [ 'body' ]);
if ( ! is_object ( $nodeinfo )) {
return false ;
}
if ( ! is_array ( $nodeinfo -> links )) {
return false ;
}
$nodeinfo_url = '' ;
2017-06-18 21:14:52 +00:00
foreach ( $nodeinfo -> links as $link ) {
2017-03-13 00:03:27 +00:00
if ( $link -> rel == 'http://nodeinfo.diaspora.software/ns/schema/1.0' ) {
$nodeinfo_url = $link -> href ;
}
}
if ( $nodeinfo_url == '' ) {
return false ;
}
$serverret = z_fetch_url ( $nodeinfo_url );
if ( ! $serverret [ " success " ]) {
return false ;
}
$nodeinfo = json_decode ( $serverret [ 'body' ]);
if ( ! is_object ( $nodeinfo )) {
return false ;
}
$server = array ();
$server [ 'register_policy' ] = REGISTER_CLOSED ;
2017-06-08 02:00:59 +00:00
if ( is_bool ( $nodeinfo -> openRegistrations ) && $nodeinfo -> openRegistrations ) {
2017-03-13 00:03:27 +00:00
$server [ 'register_policy' ] = REGISTER_OPEN ;
}
if ( is_object ( $nodeinfo -> software )) {
if ( isset ( $nodeinfo -> software -> name )) {
$server [ 'platform' ] = $nodeinfo -> software -> name ;
}
if ( isset ( $nodeinfo -> software -> version )) {
$server [ 'version' ] = $nodeinfo -> software -> version ;
2017-03-16 21:34:53 +00:00
// Version numbers on Nodeinfo are presented with additional info, e.g.:
// 0.6.3.0-p1702cc1c, 0.6.99.0-p1b9ab160 or 3.4.3-2-1191.
$server [ 'version' ] = preg_replace ( " =(.+)-(. { 4,})=ism " , " $ 1 " , $server [ 'version' ]);
2017-03-13 00:03:27 +00:00
}
}
if ( is_object ( $nodeinfo -> metadata )) {
if ( isset ( $nodeinfo -> metadata -> nodeName )) {
$server [ 'site_name' ] = $nodeinfo -> metadata -> nodeName ;
}
}
$diaspora = false ;
$friendica = false ;
$gnusocial = false ;
if ( is_array ( $nodeinfo -> protocols -> inbound )) {
2017-06-18 21:14:52 +00:00
foreach ( $nodeinfo -> protocols -> inbound as $inbound ) {
2017-03-13 00:03:27 +00:00
if ( $inbound == 'diaspora' ) {
$diaspora = true ;
}
if ( $inbound == 'friendica' ) {
$friendica = true ;
}
if ( $inbound == 'gnusocial' ) {
$gnusocial = true ;
}
}
}
if ( $gnusocial ) {
$server [ 'network' ] = NETWORK_OSTATUS ;
}
if ( $diaspora ) {
$server [ 'network' ] = NETWORK_DIASPORA ;
}
if ( $friendica ) {
$server [ 'network' ] = NETWORK_DFRN ;
}
if ( ! $server ) {
return false ;
}
return $server ;
}
2017-03-02 21:20:33 +00:00
/**
* @ brief Detect server type ( Hubzilla or Friendica ) via the front page body
*
* @ param string $body Front page of the server
* @ return array Server data
*/
function poco_detect_server_type ( $body ) {
2017-02-26 18:19:20 +00:00
$server = false ;
2017-05-11 15:53:04 +00:00
$doc = new DOMDocument ();
2017-02-26 18:19:20 +00:00
@ $doc -> loadHTML ( $body );
2017-05-11 15:53:04 +00:00
$xpath = new DomXPath ( $doc );
2017-02-26 18:19:20 +00:00
$list = $xpath -> query ( " //meta[@name] " );
foreach ( $list as $node ) {
$attr = array ();
if ( $node -> attributes -> length ) {
foreach ( $node -> attributes as $attribute ) {
$attr [ $attribute -> name ] = $attribute -> value ;
}
}
if ( $attr [ 'name' ] == 'generator' ) {
$version_part = explode ( " " , $attr [ 'content' ]);
if ( count ( $version_part ) == 2 ) {
if ( in_array ( $version_part [ 0 ], array ( " Friendika " , " Friendica " ))) {
$server = array ();
$server [ " platform " ] = $version_part [ 0 ];
$server [ " version " ] = $version_part [ 1 ];
$server [ " network " ] = NETWORK_DFRN ;
}
}
}
}
2017-03-02 21:20:33 +00:00
if ( ! $server ) {
$list = $xpath -> query ( " //meta[@property] " );
foreach ( $list as $node ) {
$attr = array ();
if ( $node -> attributes -> length ) {
foreach ( $node -> attributes as $attribute ) {
$attr [ $attribute -> name ] = $attribute -> value ;
}
}
2017-06-18 20:10:03 +00:00
if ( $attr [ 'property' ] == 'generator' && in_array ( $attr [ 'content' ], array ( " hubzilla " , " BlaBlaNet " ))) {
$server = array ();
$server [ " platform " ] = $attr [ 'content' ];
$server [ " version " ] = " " ;
$server [ " network " ] = NETWORK_DIASPORA ;
2017-03-02 21:20:33 +00:00
}
}
}
2017-02-26 18:19:20 +00:00
if ( ! $server ) {
return false ;
}
$server [ " site_name " ] = $xpath -> evaluate ( $element . " //head/title/text() " , $context ) -> item ( 0 ) -> nodeValue ;
return $server ;
}
2015-07-22 09:51:37 +00:00
function poco_check_server ( $server_url , $network = " " , $force = false ) {
2015-07-18 18:15:21 +00:00
2016-01-19 14:12:18 +00:00
// Unify the server address
$server_url = trim ( $server_url , " / " );
$server_url = str_replace ( " /index.php " , " " , $server_url );
2017-06-18 20:10:03 +00:00
if ( $server_url == " " ) {
2015-07-19 19:29:24 +00:00
return false ;
2017-06-18 20:10:03 +00:00
}
2015-07-18 18:15:21 +00:00
$servers = q ( " SELECT * FROM `gserver` WHERE `nurl` = '%s' " , dbesc ( normalise_link ( $server_url )));
2017-02-01 08:43:18 +00:00
if ( dbm :: is_result ( $servers )) {
2015-07-20 22:05:44 +00:00
2017-03-19 08:04:04 +00:00
if ( $servers [ 0 ][ " created " ] <= NULL_DATE ) {
2015-07-20 22:05:44 +00:00
q ( " UPDATE `gserver` SET `created` = '%s' WHERE `nurl` = '%s' " ,
dbesc ( datetime_convert ()), dbesc ( normalise_link ( $server_url )));
2017-03-19 08:04:04 +00:00
}
2015-07-18 18:15:21 +00:00
$poco = $servers [ 0 ][ " poco " ];
$noscrape = $servers [ 0 ][ " noscrape " ];
2017-06-18 20:10:03 +00:00
if ( $network == " " ) {
2015-07-18 18:15:21 +00:00
$network = $servers [ 0 ][ " network " ];
2017-06-18 20:10:03 +00:00
}
2015-07-18 18:15:21 +00:00
$last_contact = $servers [ 0 ][ " last_contact " ];
$last_failure = $servers [ 0 ][ " last_failure " ];
$version = $servers [ 0 ][ " version " ];
$platform = $servers [ 0 ][ " platform " ];
$site_name = $servers [ 0 ][ " site_name " ];
$info = $servers [ 0 ][ " info " ];
$register_policy = $servers [ 0 ][ " register_policy " ];
2017-06-08 02:00:59 +00:00
if ( ! $force && ! poco_do_update ( $servers [ 0 ][ " created " ], " " , $last_failure , $last_contact )) {
2015-07-22 09:51:37 +00:00
logger ( " Use cached data for server " . $server_url , LOGGER_DEBUG );
2015-07-19 19:29:24 +00:00
return ( $last_contact >= $last_failure );
2015-07-22 09:51:37 +00:00
}
2015-07-18 18:15:21 +00:00
} else {
$poco = " " ;
$noscrape = " " ;
$version = " " ;
$platform = " " ;
$site_name = " " ;
$info = " " ;
$register_policy = - 1 ;
2017-02-27 23:37:15 +00:00
$last_contact = NULL_DATE ;
$last_failure = NULL_DATE ;
2015-07-18 18:15:21 +00:00
}
2015-08-25 03:31:21 +00:00
logger ( " Server " . $server_url . " is outdated or unknown. Start discovery. Force: " . $force . " Created: " . $servers [ 0 ][ " created " ] . " Failure: " . $last_failure . " Contact: " . $last_contact , LOGGER_DEBUG );
2015-07-18 18:15:21 +00:00
$failure = false ;
2017-02-26 18:19:20 +00:00
$possible_failure = false ;
2015-07-18 18:15:21 +00:00
$orig_last_failure = $last_failure ;
2017-02-26 18:19:20 +00:00
$orig_last_contact = $last_contact ;
2015-07-18 18:15:21 +00:00
// Check if the page is accessible via SSL.
2017-02-01 00:15:37 +00:00
$orig_server_url = $server_url ;
2015-07-18 18:15:21 +00:00
$server_url = str_replace ( " http:// " , " https:// " , $server_url );
2017-02-01 00:15:37 +00:00
// We set the timeout to 20 seconds since this operation should be done in no time if the server was vital
$serverret = z_fetch_url ( $server_url . " /.well-known/host-meta " , false , $redirects , array ( 'timeout' => 20 ));
// Quit if there is a timeout.
// But we want to make sure to only quit if we are mostly sure that this server url fits.
2017-06-08 02:00:59 +00:00
if ( dbm :: is_result ( $servers ) && ( $orig_server_url == $server_url ) &&
2017-02-01 08:43:18 +00:00
( $serverret [ 'errno' ] == CURLE_OPERATION_TIMEDOUT )) {
2017-02-01 00:15:37 +00:00
logger ( " Connection to server " . $server_url . " timed out. " , LOGGER_DEBUG );
2017-08-12 22:15:16 +00:00
dba :: update ( 'gserver' , array ( 'last_failure' => datetime_convert ()), array ( 'nurl' => normalise_link ( $server_url )));
2017-02-01 00:15:37 +00:00
return false ;
}
2015-07-18 18:15:21 +00:00
// Maybe the page is unencrypted only?
$xmlobj = @ simplexml_load_string ( $serverret [ " body " ], 'SimpleXMLElement' , 0 , " http://docs.oasis-open.org/ns/xri/xrd-1.0 " );
2017-06-08 02:00:59 +00:00
if ( ! $serverret [ " success " ] || ( $serverret [ " body " ] == " " ) || ( @ sizeof ( $xmlobj ) == 0 ) || ! is_object ( $xmlobj )) {
2015-07-18 18:15:21 +00:00
$server_url = str_replace ( " https:// " , " http:// " , $server_url );
2017-02-01 00:15:37 +00:00
// We set the timeout to 20 seconds since this operation should be done in no time if the server was vital
$serverret = z_fetch_url ( $server_url . " /.well-known/host-meta " , false , $redirects , array ( 'timeout' => 20 ));
// Quit if there is a timeout
if ( $serverret [ 'errno' ] == CURLE_OPERATION_TIMEDOUT ) {
logger ( " Connection to server " . $server_url . " timed out. " , LOGGER_DEBUG );
2017-08-12 22:15:16 +00:00
dba :: update ( 'gserver' , array ( 'last_failure' => datetime_convert ()), array ( 'nurl' => normalise_link ( $server_url )));
2017-02-01 00:15:37 +00:00
return false ;
}
2016-12-12 06:51:08 +00:00
2015-07-18 18:15:21 +00:00
$xmlobj = @ simplexml_load_string ( $serverret [ " body " ], 'SimpleXMLElement' , 0 , " http://docs.oasis-open.org/ns/xri/xrd-1.0 " );
}
2017-06-08 02:00:59 +00:00
if ( ! $serverret [ " success " ] || ( $serverret [ " body " ] == " " ) || ( sizeof ( $xmlobj ) == 0 ) || ! is_object ( $xmlobj )) {
2015-10-24 18:41:21 +00:00
// Workaround for bad configured servers (known nginx problem)
2017-02-10 19:23:46 +00:00
if ( ! in_array ( $serverret [ " debug " ][ " http_code " ], array ( " 403 " , " 404 " ))) {
2015-10-24 18:41:21 +00:00
$failure = true ;
}
2017-02-26 18:19:20 +00:00
$possible_failure = true ;
2017-05-05 20:51:45 +00:00
}
2015-07-18 18:15:21 +00:00
2017-03-04 07:57:55 +00:00
// If the server has no possible failure we reset the cached data
if ( ! $possible_failure ) {
$version = " " ;
$platform = " " ;
$site_name = " " ;
$info = " " ;
$register_policy = - 1 ;
}
// Look for poco
2015-07-22 22:32:41 +00:00
if ( ! $failure ) {
2017-03-04 07:57:55 +00:00
$serverret = z_fetch_url ( $server_url . " /poco " );
if ( $serverret [ " success " ]) {
$data = json_decode ( $serverret [ " body " ]);
if ( isset ( $data -> totalResults )) {
$poco = $server_url . " /poco " ;
$server = poco_detect_poco_data ( $data );
if ( $server ) {
$platform = $server [ 'platform' ];
$network = $server [ 'network' ];
$version = '' ;
$site_name = '' ;
}
}
}
}
2015-07-22 22:32:41 +00:00
if ( ! $failure ) {
2017-03-02 21:20:33 +00:00
// Test for Diaspora, Hubzilla, Mastodon or older Friendica servers
2015-07-22 22:32:41 +00:00
$serverret = z_fetch_url ( $server_url );
2017-06-08 02:00:59 +00:00
if ( ! $serverret [ " success " ] || ( $serverret [ " body " ] == " " )) {
2016-01-21 02:21:33 +00:00
$failure = true ;
2017-02-26 18:19:20 +00:00
} else {
2017-03-02 21:20:33 +00:00
$server = poco_detect_server_type ( $serverret [ " body " ]);
if ( $server ) {
$platform = $server [ 'platform' ];
$network = $server [ 'network' ];
$version = $server [ 'version' ];
$site_name = $server [ 'site_name' ];
}
2016-01-21 02:21:33 +00:00
$lines = explode ( " \n " , $serverret [ " header " ]);
2017-04-04 17:48:25 +00:00
if ( count ( $lines )) {
2017-03-21 16:02:59 +00:00
foreach ( $lines as $line ) {
2016-01-21 02:21:33 +00:00
$line = trim ( $line );
2017-04-04 17:48:25 +00:00
if ( stristr ( $line , 'X-Diaspora-Version:' )) {
2016-01-21 02:21:33 +00:00
$platform = " Diaspora " ;
$version = trim ( str_replace ( " X-Diaspora-Version: " , " " , $line ));
$version = trim ( str_replace ( " x-diaspora-version: " , " " , $version ));
$network = NETWORK_DIASPORA ;
$versionparts = explode ( " - " , $version );
$version = $versionparts [ 0 ];
}
2016-12-12 06:46:02 +00:00
2017-04-04 17:48:25 +00:00
if ( stristr ( $line , 'Server: Mastodon' )) {
2016-12-12 06:46:02 +00:00
$platform = " Mastodon " ;
$network = NETWORK_OSTATUS ;
}
2015-07-22 22:32:41 +00:00
}
2017-02-26 18:19:20 +00:00
}
2016-01-21 02:21:33 +00:00
}
2015-07-22 22:32:41 +00:00
}
2017-06-08 02:00:59 +00:00
if ( ! $failure && ( $poco == " " )) {
2015-07-18 18:15:21 +00:00
// Test for Statusnet
// Will also return data for Friendica and GNU Social - but it will be overwritten later
// The "not implemented" is a special treatment for really, really old Friendica versions
$serverret = z_fetch_url ( $server_url . " /api/statusnet/version.json " );
2017-06-08 02:00:59 +00:00
if ( $serverret [ " success " ] && ( $serverret [ " body " ] != '{"error":"not implemented"}' ) &&
( $serverret [ " body " ] != '' ) && ( strlen ( $serverret [ " body " ]) < 30 )) {
2015-07-18 18:15:21 +00:00
$platform = " StatusNet " ;
2017-03-08 05:40:57 +00:00
// Remove junk that some GNU Social servers return
$version = str_replace ( chr ( 239 ) . chr ( 187 ) . chr ( 191 ), " " , $serverret [ " body " ]);
$version = trim ( $version , '"' );
2015-07-18 18:15:21 +00:00
$network = NETWORK_OSTATUS ;
}
// Test for GNU Social
$serverret = z_fetch_url ( $server_url . " /api/gnusocial/version.json " );
2017-06-08 02:00:59 +00:00
if ( $serverret [ " success " ] && ( $serverret [ " body " ] != '{"error":"not implemented"}' ) &&
( $serverret [ " body " ] != '' ) && ( strlen ( $serverret [ " body " ]) < 30 )) {
2015-07-18 18:15:21 +00:00
$platform = " GNU Social " ;
2017-03-08 05:40:57 +00:00
// Remove junk that some GNU Social servers return
$version = str_replace ( chr ( 239 ) . chr ( 187 ) . chr ( 191 ), " " , $serverret [ " body " ]);
$version = trim ( $version , '"' );
2015-07-18 18:15:21 +00:00
$network = NETWORK_OSTATUS ;
}
2017-05-05 05:36:43 +00:00
// Test for Mastodon
2017-08-29 16:40:08 +00:00
$orig_version = $version ;
2017-05-05 05:36:43 +00:00
$serverret = z_fetch_url ( $server_url . " /api/v1/instance " );
2017-06-08 02:00:59 +00:00
if ( $serverret [ " success " ] && ( $serverret [ " body " ] != '' )) {
2017-05-05 05:36:43 +00:00
$data = json_decode ( $serverret [ " body " ]);
if ( isset ( $data -> version )) {
$platform = " Mastodon " ;
$version = $data -> version ;
$site_name = $data -> title ;
$info = $data -> description ;
$network = NETWORK_OSTATUS ;
}
2015-07-18 18:15:21 +00:00
}
2017-09-18 06:09:18 +00:00
if ( strstr ( $orig_version . $version , 'Pleroma' )) {
2017-08-29 16:40:08 +00:00
$platform = 'Pleroma' ;
2017-09-18 06:09:18 +00:00
$version = trim ( str_replace ( 'Pleroma' , '' , $version ));
2017-08-29 16:40:08 +00:00
}
2017-03-04 07:57:55 +00:00
}
2015-07-18 18:15:21 +00:00
2017-03-04 07:57:55 +00:00
if ( ! $failure ) {
2017-07-21 17:36:13 +00:00
// Test for Hubzilla and Red
2017-07-20 00:56:40 +00:00
$serverret = z_fetch_url ( $server_url . " /siteinfo.json " );
2015-07-18 18:15:21 +00:00
if ( $serverret [ " success " ]) {
$data = json_decode ( $serverret [ " body " ]);
2017-07-21 17:36:13 +00:00
if ( isset ( $data -> url )) {
2017-07-20 00:56:40 +00:00
$platform = $data -> platform ;
$version = $data -> version ;
$network = NETWORK_DIASPORA ;
}
2017-08-29 16:40:08 +00:00
if ( ! empty ( $data -> site_name )) {
$site_name = $data -> site_name ;
}
2017-07-20 00:56:40 +00:00
switch ( $data -> register_policy ) {
case " REGISTER_OPEN " :
$register_policy = REGISTER_OPEN ;
break ;
case " REGISTER_APPROVE " :
$register_policy = REGISTER_APPROVE ;
break ;
case " REGISTER_CLOSED " :
default :
$register_policy = REGISTER_CLOSED ;
break ;
}
2017-07-21 17:36:13 +00:00
} else {
// Test for Hubzilla, Redmatrix or Friendica
2017-07-20 00:56:40 +00:00
$serverret = z_fetch_url ( $server_url . " /api/statusnet/config.json " );
if ( $serverret [ " success " ]) {
$data = json_decode ( $serverret [ " body " ]);
if ( isset ( $data -> site -> server )) {
if ( isset ( $data -> site -> platform )) {
$platform = $data -> site -> platform -> PLATFORM_NAME ;
$version = $data -> site -> platform -> STD_VERSION ;
$network = NETWORK_DIASPORA ;
}
if ( isset ( $data -> site -> BlaBlaNet )) {
$platform = $data -> site -> BlaBlaNet -> PLATFORM_NAME ;
$version = $data -> site -> BlaBlaNet -> STD_VERSION ;
$network = NETWORK_DIASPORA ;
}
if ( isset ( $data -> site -> hubzilla )) {
$platform = $data -> site -> hubzilla -> PLATFORM_NAME ;
$version = $data -> site -> hubzilla -> RED_VERSION ;
$network = NETWORK_DIASPORA ;
2017-04-04 17:48:25 +00:00
}
2017-07-20 00:56:40 +00:00
if ( isset ( $data -> site -> redmatrix )) {
if ( isset ( $data -> site -> redmatrix -> PLATFORM_NAME )) {
$platform = $data -> site -> redmatrix -> PLATFORM_NAME ;
} elseif ( isset ( $data -> site -> redmatrix -> RED_PLATFORM )) {
$platform = $data -> site -> redmatrix -> RED_PLATFORM ;
}
2015-07-18 18:15:21 +00:00
2017-07-20 00:56:40 +00:00
$version = $data -> site -> redmatrix -> RED_VERSION ;
$network = NETWORK_DIASPORA ;
}
if ( isset ( $data -> site -> friendica )) {
$platform = $data -> site -> friendica -> FRIENDICA_PLATFORM ;
$version = $data -> site -> friendica -> FRIENDICA_VERSION ;
$network = NETWORK_DFRN ;
}
2015-07-18 18:15:21 +00:00
2017-07-20 00:56:40 +00:00
$site_name = $data -> site -> name ;
2015-07-18 18:15:21 +00:00
2017-07-20 00:56:40 +00:00
$data -> site -> closed = poco_to_boolean ( $data -> site -> closed );
$data -> site -> private = poco_to_boolean ( $data -> site -> private );
$data -> site -> inviteonly = poco_to_boolean ( $data -> site -> inviteonly );
2015-07-18 18:15:21 +00:00
2017-07-20 00:56:40 +00:00
if ( ! $data -> site -> closed && ! $data -> site -> private and $data -> site -> inviteonly ) {
$register_policy = REGISTER_APPROVE ;
} elseif ( ! $data -> site -> closed && ! $data -> site -> private ) {
$register_policy = REGISTER_OPEN ;
} else {
$register_policy = REGISTER_CLOSED ;
}
2017-04-04 17:48:25 +00:00
}
2015-07-18 18:15:21 +00:00
}
}
}
// Query statistics.json. Optional package for Diaspora, Friendica and Redmatrix
if ( ! $failure ) {
$serverret = z_fetch_url ( $server_url . " /statistics.json " );
if ( $serverret [ " success " ]) {
$data = json_decode ( $serverret [ " body " ]);
2017-03-16 21:34:53 +00:00
if ( isset ( $data -> version )) {
2015-07-18 18:15:21 +00:00
$version = $data -> version ;
2017-03-16 21:34:53 +00:00
// Version numbers on statistics.json are presented with additional info, e.g.:
// 0.6.3.0-p1702cc1c, 0.6.99.0-p1b9ab160 or 3.4.3-2-1191.
$version = preg_replace ( " =(.+)-(. { 4,})=ism " , " $ 1 " , $version );
}
2015-07-18 18:15:21 +00:00
2017-08-29 16:40:08 +00:00
if ( ! empty ( $data -> name )) {
$site_name = $data -> name ;
}
2015-07-18 18:15:21 +00:00
2017-08-29 16:40:08 +00:00
if ( ! empty ( $data -> network )) {
2015-07-18 18:15:21 +00:00
$platform = $data -> network ;
2017-03-16 21:34:53 +00:00
}
2015-07-18 18:15:21 +00:00
2017-03-16 21:34:53 +00:00
if ( $platform == " Diaspora " ) {
2015-07-22 22:32:41 +00:00
$network = NETWORK_DIASPORA ;
2017-03-16 21:34:53 +00:00
}
2015-07-22 22:32:41 +00:00
2017-03-16 21:34:53 +00:00
if ( $data -> registrations_open ) {
2015-07-18 18:15:21 +00:00
$register_policy = REGISTER_OPEN ;
2017-03-16 21:34:53 +00:00
} else {
2015-07-18 18:15:21 +00:00
$register_policy = REGISTER_CLOSED ;
2017-03-16 21:34:53 +00:00
}
2015-07-18 18:15:21 +00:00
}
}
2017-03-13 00:03:27 +00:00
// Query nodeinfo. Working for (at least) Diaspora and Friendica.
if ( ! $failure ) {
$server = poco_fetch_nodeinfo ( $server_url );
if ( $server ) {
$register_policy = $server [ 'register_policy' ];
2017-03-16 21:34:53 +00:00
if ( isset ( $server [ 'platform' ])) {
$platform = $server [ 'platform' ];
}
if ( isset ( $server [ 'network' ])) {
$network = $server [ 'network' ];
}
if ( isset ( $server [ 'version' ])) {
2017-03-13 00:03:27 +00:00
$version = $server [ 'version' ];
}
2017-03-16 21:34:53 +00:00
if ( isset ( $server [ 'site_name' ])) {
$site_name = $server [ 'site_name' ];
}
2017-03-13 00:03:27 +00:00
}
}
2015-07-18 18:15:21 +00:00
// Check for noscrape
// Friendica servers could be detected as OStatus servers
2017-06-08 02:00:59 +00:00
if ( ! $failure && in_array ( $network , array ( NETWORK_DFRN , NETWORK_OSTATUS ))) {
2015-07-18 18:15:21 +00:00
$serverret = z_fetch_url ( $server_url . " /friendica/json " );
2017-04-04 17:48:25 +00:00
if ( ! $serverret [ " success " ]) {
2015-07-22 22:32:41 +00:00
$serverret = z_fetch_url ( $server_url . " /friendika/json " );
2017-04-04 17:48:25 +00:00
}
2015-07-22 22:32:41 +00:00
2015-07-18 18:15:21 +00:00
if ( $serverret [ " success " ]) {
$data = json_decode ( $serverret [ " body " ]);
if ( isset ( $data -> version )) {
$network = NETWORK_DFRN ;
$noscrape = $data -> no_scrape_url ;
$version = $data -> version ;
$site_name = $data -> site_name ;
$info = $data -> info ;
$register_policy_str = $data -> register_policy ;
$platform = $data -> platform ;
switch ( $register_policy_str ) {
case " REGISTER_CLOSED " :
$register_policy = REGISTER_CLOSED ;
break ;
case " REGISTER_APPROVE " :
$register_policy = REGISTER_APPROVE ;
break ;
case " REGISTER_OPEN " :
$register_policy = REGISTER_OPEN ;
break ;
}
}
}
}
2017-06-08 02:00:59 +00:00
if ( $possible_failure && ! $failure ) {
2017-02-26 18:19:20 +00:00
$failure = true ;
}
if ( $failure ) {
$last_contact = $orig_last_contact ;
2017-05-05 20:51:45 +00:00
$last_failure = datetime_convert ();
2017-02-26 18:19:20 +00:00
} else {
2017-05-05 20:51:45 +00:00
$last_contact = datetime_convert ();
2017-02-26 18:19:20 +00:00
$last_failure = $orig_last_failure ;
}
2017-06-08 02:00:59 +00:00
if (( $last_contact <= $last_failure ) && ! $failure ) {
2017-02-26 18:19:20 +00:00
logger ( " Server " . $server_url . " seems to be alive, but last contact wasn't set - could be a bug " , LOGGER_DEBUG );
2017-06-18 20:10:03 +00:00
} elseif (( $last_contact >= $last_failure ) && $failure ) {
2017-02-26 18:19:20 +00:00
logger ( " Server " . $server_url . " seems to be dead, but last failure wasn't set - could be a bug " , LOGGER_DEBUG );
2015-07-18 18:15:21 +00:00
}
2015-07-22 09:51:37 +00:00
// Check again if the server exists
$servers = q ( " SELECT `nurl` FROM `gserver` WHERE `nurl` = '%s' " , dbesc ( normalise_link ( $server_url )));
2016-02-19 06:30:28 +00:00
$version = strip_tags ( $version );
$site_name = strip_tags ( $site_name );
$info = strip_tags ( $info );
$platform = strip_tags ( $platform );
2017-03-08 05:40:57 +00:00
if ( $servers ) {
2015-07-18 18:15:21 +00:00
q ( " UPDATE `gserver` SET `url` = '%s', `version` = '%s', `site_name` = '%s', `info` = '%s', `register_policy` = %d, `poco` = '%s', `noscrape` = '%s',
`network` = '%s' , `platform` = '%s' , `last_contact` = '%s' , `last_failure` = '%s' WHERE `nurl` = '%s' " ,
dbesc ( $server_url ),
dbesc ( $version ),
dbesc ( $site_name ),
dbesc ( $info ),
intval ( $register_policy ),
dbesc ( $poco ),
dbesc ( $noscrape ),
dbesc ( $network ),
dbesc ( $platform ),
dbesc ( $last_contact ),
dbesc ( $last_failure ),
dbesc ( normalise_link ( $server_url ))
);
2017-03-13 06:32:33 +00:00
} elseif ( ! $failure ) {
2015-07-20 22:05:44 +00:00
q ( " INSERT INTO `gserver` (`url`, `nurl`, `version`, `site_name`, `info`, `register_policy`, `poco`, `noscrape`, `network`, `platform`, `created`, `last_contact`, `last_failure`)
2015-07-22 09:51:37 +00:00
VALUES ( '%s' , '%s' , '%s' , '%s' , '%s' , % d , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' ) " ,
2015-07-18 18:15:21 +00:00
dbesc ( $server_url ),
dbesc ( normalise_link ( $server_url )),
dbesc ( $version ),
dbesc ( $site_name ),
dbesc ( $info ),
intval ( $register_policy ),
dbesc ( $poco ),
dbesc ( $noscrape ),
dbesc ( $network ),
dbesc ( $platform ),
2015-07-20 22:05:44 +00:00
dbesc ( datetime_convert ()),
2015-07-19 22:14:14 +00:00
dbesc ( $last_contact ),
dbesc ( $last_failure ),
2015-07-18 18:15:21 +00:00
dbesc ( datetime_convert ())
);
2017-03-13 06:32:33 +00:00
}
2017-06-18 20:10:03 +00:00
logger ( " End discovery for server " . $server_url , LOGGER_DEBUG );
2015-07-22 09:51:37 +00:00
2015-07-19 22:14:14 +00:00
return ! $failure ;
2015-07-18 18:15:21 +00:00
}
2017-06-18 20:10:03 +00:00
function count_common_friends ( $uid , $cid ) {
2011-11-02 02:16:33 +00:00
$r = q ( " SELECT count(*) as `total`
2014-03-09 08:19:14 +00:00
FROM `glink` INNER JOIN `gcontact` on `glink` . `gcid` = `gcontact` . `id`
2015-11-06 08:15:20 +00:00
WHERE `glink` . `cid` = % d AND `glink` . `uid` = % d AND
(( `gcontact` . `last_contact` >= `gcontact` . `last_failure` ) OR ( `gcontact` . `updated` >= `gcontact` . `last_failure` ))
AND `gcontact` . `nurl` IN ( select nurl from contact where uid = % d and self = 0 and blocked = 0 and hidden = 0 and id != % d ) " ,
2011-11-02 02:16:33 +00:00
intval ( $cid ),
intval ( $uid ),
intval ( $uid ),
intval ( $cid )
);
2017-06-18 20:10:03 +00:00
// logger("count_common_friends: $uid $cid {$r[0]['total']}");
if ( dbm :: is_result ( $r )) {
2011-11-02 02:16:33 +00:00
return $r [ 0 ][ 'total' ];
2017-06-18 20:10:03 +00:00
}
2011-11-02 02:16:33 +00:00
return 0 ;
}
2017-06-18 20:10:03 +00:00
function common_friends ( $uid , $cid , $start = 0 , $limit = 9999 , $shuffle = false ) {
2012-05-02 07:44:37 +00:00
2017-04-04 17:48:25 +00:00
if ( $shuffle ) {
2012-05-02 07:44:37 +00:00
$sql_extra = " order by rand() " ;
2017-04-04 17:48:25 +00:00
} else {
2015-01-08 06:59:20 +00:00
$sql_extra = " order by `gcontact`.`name` asc " ;
2017-04-04 17:48:25 +00:00
}
2011-11-02 02:16:33 +00:00
2015-11-01 07:54:44 +00:00
$r = q ( " SELECT `gcontact`.*, `contact`.`id` AS `cid`
FROM `glink`
INNER JOIN `gcontact` ON `glink` . `gcid` = `gcontact` . `id`
INNER JOIN `contact` ON `gcontact` . `nurl` = `contact` . `nurl`
WHERE `glink` . `cid` = % d and `glink` . `uid` = % d
AND `contact` . `uid` = % d AND `contact` . `self` = 0 AND `contact` . `blocked` = 0
AND `contact` . `hidden` = 0 AND `contact` . `id` != % d
2015-11-06 08:15:20 +00:00
AND (( `gcontact` . `last_contact` >= `gcontact` . `last_failure` ) OR ( `gcontact` . `updated` >= `gcontact` . `last_failure` ))
2015-11-01 07:54:44 +00:00
$sql_extra LIMIT % d , % d " ,
2011-11-02 02:16:33 +00:00
intval ( $cid ),
intval ( $uid ),
intval ( $uid ),
2012-05-02 04:22:27 +00:00
intval ( $cid ),
2012-05-04 08:46:36 +00:00
intval ( $start ),
2012-05-02 04:22:27 +00:00
intval ( $limit )
2011-11-02 02:16:33 +00:00
);
2017-04-04 17:48:25 +00:00
/// @TODO Check all calling-findings of this function if they properly use dbm::is_result()
2011-11-02 02:16:33 +00:00
return $r ;
2011-11-02 03:29:55 +00:00
}
2012-05-02 02:16:18 +00:00
2017-06-18 20:10:03 +00:00
function count_common_friends_zcid ( $uid , $zcid ) {
2012-05-02 02:16:18 +00:00
2015-01-08 06:59:20 +00:00
$r = q ( " SELECT count(*) as `total`
2014-03-09 08:19:14 +00:00
FROM `glink` INNER JOIN `gcontact` on `glink` . `gcid` = `gcontact` . `id`
2012-05-02 03:33:19 +00:00
where `glink` . `zcid` = % d
2012-05-02 23:15:59 +00:00
and `gcontact` . `nurl` in ( select nurl from contact where uid = % d and self = 0 and blocked = 0 and hidden = 0 ) " ,
2012-05-02 03:33:19 +00:00
intval ( $zcid ),
2012-05-02 03:36:35 +00:00
intval ( $uid )
2012-05-02 02:16:18 +00:00
);
2017-06-18 20:10:03 +00:00
if ( dbm :: is_result ( $r )) {
2012-05-02 02:16:18 +00:00
return $r [ 0 ][ 'total' ];
2017-06-18 20:10:03 +00:00
}
2012-05-02 02:16:18 +00:00
return 0 ;
}
2017-06-18 20:10:03 +00:00
function common_friends_zcid ( $uid , $zcid , $start = 0 , $limit = 9999 , $shuffle = false ) {
2012-05-02 07:44:37 +00:00
2017-06-18 20:10:03 +00:00
if ( $shuffle ) {
2012-05-02 07:44:37 +00:00
$sql_extra = " order by rand() " ;
2017-06-18 20:10:03 +00:00
} else {
2015-01-08 06:59:20 +00:00
$sql_extra = " order by `gcontact`.`name` asc " ;
2017-06-18 20:10:03 +00:00
}
2012-05-02 02:16:18 +00:00
2015-01-08 06:59:20 +00:00
$r = q ( " SELECT `gcontact`.*
2014-03-09 08:19:14 +00:00
FROM `glink` INNER JOIN `gcontact` on `glink` . `gcid` = `gcontact` . `id`
2012-05-02 03:33:19 +00:00
where `glink` . `zcid` = % d
2017-04-30 04:01:26 +00:00
and `gcontact` . `nurl` in ( select nurl from contact where uid = % d and self = 0 and blocked = 0 and hidden = 0 )
2012-05-04 08:46:36 +00:00
$sql_extra limit % d , % d " ,
2012-05-02 03:33:19 +00:00
intval ( $zcid ),
2012-05-02 02:16:18 +00:00
intval ( $uid ),
2012-05-04 08:46:36 +00:00
intval ( $start ),
2012-05-02 02:16:18 +00:00
intval ( $limit )
);
2017-04-04 17:48:25 +00:00
/// @TODO Check all calling-findings of this function if they properly use dbm::is_result()
2012-05-02 02:16:18 +00:00
return $r ;
}
2017-06-18 20:10:03 +00:00
function count_all_friends ( $uid , $cid ) {
2011-11-09 02:30:20 +00:00
$r = q ( " SELECT count(*) as `total`
2014-03-09 08:19:14 +00:00
FROM `glink` INNER JOIN `gcontact` on `glink` . `gcid` = `gcontact` . `id`
2015-11-06 08:15:20 +00:00
where `glink` . `cid` = % d and `glink` . `uid` = % d AND
(( `gcontact` . `last_contact` >= `gcontact` . `last_failure` ) OR ( `gcontact` . `updated` >= `gcontact` . `last_failure` )) " ,
2011-11-09 02:30:20 +00:00
intval ( $cid ),
intval ( $uid )
);
2017-04-04 17:48:25 +00:00
if ( dbm :: is_result ( $r )) {
2011-11-09 02:30:20 +00:00
return $r [ 0 ][ 'total' ];
2017-04-04 17:48:25 +00:00
}
2011-11-09 02:30:20 +00:00
return 0 ;
}
2017-06-18 20:10:03 +00:00
function all_friends ( $uid , $cid , $start = 0 , $limit = 80 ) {
2011-11-09 02:30:20 +00:00
2015-11-01 07:54:44 +00:00
$r = q ( " SELECT `gcontact`.*, `contact`.`id` AS `cid`
FROM `glink`
INNER JOIN `gcontact` on `glink` . `gcid` = `gcontact` . `id`
LEFT JOIN `contact` ON `contact` . `nurl` = `gcontact` . `nurl` AND `contact` . `uid` = % d
2015-11-06 08:15:20 +00:00
WHERE `glink` . `cid` = % d AND `glink` . `uid` = % d AND
(( `gcontact` . `last_contact` >= `gcontact` . `last_failure` ) OR ( `gcontact` . `updated` >= `gcontact` . `last_failure` ))
2015-11-01 07:54:44 +00:00
ORDER BY `gcontact` . `name` ASC LIMIT % d , % d " ,
intval ( $uid ),
2011-11-09 02:30:20 +00:00
intval ( $cid ),
intval ( $uid ),
intval ( $start ),
intval ( $limit )
);
2017-04-04 17:48:25 +00:00
/// @TODO Check all calling-findings of this function if they properly use dbm::is_result()
2011-11-09 02:30:20 +00:00
return $r ;
}
2011-11-02 03:29:55 +00:00
2012-03-21 02:06:26 +00:00
function suggestion_query ( $uid , $start = 0 , $limit = 80 ) {
2011-11-02 03:29:55 +00:00
2016-10-23 21:59:40 +00:00
if ( ! $uid ) {
2011-11-02 04:27:11 +00:00
return array ();
2016-10-23 21:59:40 +00:00
}
2017-06-18 20:10:03 +00:00
/*
* Uncommented because the result of the queries are to big to store it in the cache .
* We need to decide if we want to change the db column type or if we want to delete it .
*/
//$list = Cache::get("suggestion_query:".$uid.":".$start.":".$limit);
//if (!is_null($list)) {
// return $list;
//}
2011-11-02 04:27:11 +00:00
2015-01-08 10:01:55 +00:00
$network = array ( NETWORK_DFRN );
2015-01-08 06:59:20 +00:00
2017-11-07 02:22:52 +00:00
if ( Config :: get ( 'system' , 'diaspora_enabled' )) {
2015-01-08 06:59:20 +00:00
$network [] = NETWORK_DIASPORA ;
2017-04-04 17:48:25 +00:00
}
2015-01-08 06:59:20 +00:00
2017-11-07 02:22:52 +00:00
if ( ! Config :: get ( 'system' , 'ostatus_disabled' )) {
2015-01-08 06:59:20 +00:00
$network [] = NETWORK_OSTATUS ;
2017-04-04 17:48:25 +00:00
}
2015-01-08 06:59:20 +00:00
$sql_network = implode ( " ', ' " , $network );
2015-01-08 10:01:55 +00:00
$sql_network = " ' " . $sql_network . " ' " ;
2015-01-08 06:59:20 +00:00
2016-10-23 21:59:40 +00:00
/// @todo This query is really slow
// By now we cache the data for five minutes
2015-01-05 07:03:29 +00:00
$r = q ( " SELECT count(glink.gcid) as `total`, gcontact.* from gcontact
2015-12-05 22:05:48 +00:00
INNER JOIN `glink` ON `glink` . `gcid` = `gcontact` . `id`
2012-03-26 04:43:17 +00:00
where uid = % d and not gcontact . nurl in ( select nurl from contact where uid = % d )
2015-12-05 22:05:48 +00:00
AND NOT `gcontact` . `name` IN ( SELECT `name` FROM `contact` WHERE `uid` = % d )
AND NOT `gcontact` . `id` IN ( SELECT `gcid` FROM `gcign` WHERE `uid` = % d )
2017-02-27 23:37:15 +00:00
AND `gcontact` . `updated` >= '%s'
2015-07-17 06:38:20 +00:00
AND `gcontact` . `last_contact` >= `gcontact` . `last_failure`
2015-01-08 06:59:20 +00:00
AND `gcontact` . `network` IN ( % s )
2015-12-05 22:05:48 +00:00
GROUP BY `glink` . `gcid` ORDER BY `gcontact` . `updated` DESC , `total` DESC LIMIT % d , % d " ,
2011-11-02 03:29:55 +00:00
intval ( $uid ),
intval ( $uid ),
2011-11-03 23:00:52 +00:00
intval ( $uid ),
2012-03-26 04:43:17 +00:00
intval ( $uid ),
2017-02-27 23:37:15 +00:00
dbesc ( NULL_DATE ),
2015-01-08 06:59:20 +00:00
$sql_network ,
2011-11-02 03:29:55 +00:00
intval ( $start ),
intval ( $limit )
);
2016-12-13 09:44:13 +00:00
if ( dbm :: is_result ( $r ) && count ( $r ) >= ( $limit - 1 )) {
2017-06-18 20:10:03 +00:00
/*
* Uncommented because the result of the queries are to big to store it in the cache .
* We need to decide if we want to change the db column type or if we want to delete it .
*/
//Cache::set("suggestion_query:".$uid.":".$start.":".$limit, $r, CACHE_FIVE_MINUTES);
2016-11-07 21:12:11 +00:00
2011-11-29 03:28:33 +00:00
return $r ;
2016-10-23 21:59:40 +00:00
}
2011-11-29 03:28:33 +00:00
2015-12-05 22:05:48 +00:00
$r2 = q ( " SELECT gcontact.* FROM gcontact
INNER JOIN `glink` ON `glink` . `gcid` = `gcontact` . `id`
WHERE `glink` . `uid` = 0 AND `glink` . `cid` = 0 AND `glink` . `zcid` = 0 AND NOT `gcontact` . `nurl` IN ( SELECT `nurl` FROM `contact` WHERE `uid` = % d )
AND NOT `gcontact` . `name` IN ( SELECT `name` FROM `contact` WHERE `uid` = % d )
AND NOT `gcontact` . `id` IN ( SELECT `gcid` FROM `gcign` WHERE `uid` = % d )
2017-02-27 23:37:15 +00:00
AND `gcontact` . `updated` >= '%s'
2015-12-05 22:05:48 +00:00
AND `gcontact` . `last_contact` >= `gcontact` . `last_failure`
2015-01-08 06:59:20 +00:00
AND `gcontact` . `network` IN ( % s )
2015-12-05 22:05:48 +00:00
ORDER BY rand () LIMIT % d , % d " ,
2011-12-18 21:03:20 +00:00
intval ( $uid ),
2011-11-29 03:28:33 +00:00
intval ( $uid ),
2012-03-26 04:43:17 +00:00
intval ( $uid ),
2017-02-27 23:37:15 +00:00
dbesc ( NULL_DATE ),
2015-01-08 06:59:20 +00:00
$sql_network ,
2011-11-29 03:28:33 +00:00
intval ( $start ),
intval ( $limit )
);
2015-01-05 07:03:29 +00:00
$list = array ();
2017-06-18 21:14:52 +00:00
foreach ( $r2 as $suggestion ) {
2015-01-05 07:03:29 +00:00
$list [ $suggestion [ " nurl " ]] = $suggestion ;
2017-04-04 17:48:25 +00:00
}
2011-12-18 21:03:20 +00:00
2017-06-18 21:14:52 +00:00
foreach ( $r as $suggestion ) {
2015-01-05 07:03:29 +00:00
$list [ $suggestion [ " nurl " ]] = $suggestion ;
2017-04-04 17:48:25 +00:00
}
2011-11-02 03:29:55 +00:00
2017-04-04 17:48:25 +00:00
while ( sizeof ( $list ) > ( $limit )) {
2015-12-05 22:05:48 +00:00
array_pop ( $list );
2017-04-04 17:48:25 +00:00
}
2015-12-05 22:05:48 +00:00
2017-06-18 20:10:03 +00:00
/*
* Uncommented because the result of the queries are to big to store it in the cache .
* We need to decide if we want to change the db column type or if we want to delete it .
*/
//Cache::set("suggestion_query:".$uid.":".$start.":".$limit, $list, CACHE_FIVE_MINUTES);
2015-01-05 07:03:29 +00:00
return $list ;
2011-11-02 03:29:55 +00:00
}
2011-11-29 03:28:33 +00:00
function update_suggestions () {
$a = get_app ();
$done = array ();
2016-12-23 17:31:42 +00:00
/// @TODO Check if it is really neccessary to poll the own server
2017-08-26 07:32:10 +00:00
poco_load ( 0 , 0 , 0 , System :: baseUrl () . '/poco' );
2011-11-29 03:28:33 +00:00
2017-08-26 07:32:10 +00:00
$done [] = System :: baseUrl () . '/poco' ;
2011-11-29 03:28:33 +00:00
2017-11-07 02:22:52 +00:00
if ( strlen ( Config :: get ( 'system' , 'directory' ))) {
2015-08-23 09:05:10 +00:00
$x = fetch_url ( get_server () . " /pubsites " );
2016-12-20 10:38:16 +00:00
if ( $x ) {
2011-11-29 03:28:33 +00:00
$j = json_decode ( $x );
2016-12-20 10:38:16 +00:00
if ( $j -> entries ) {
2016-12-20 16:43:46 +00:00
foreach ( $j -> entries as $entry ) {
2015-07-19 08:40:33 +00:00
poco_check_server ( $entry -> url );
2011-11-29 03:28:33 +00:00
$url = $entry -> url . '/poco' ;
2016-12-20 10:38:16 +00:00
if ( ! in_array ( $url , $done )) {
2012-05-01 08:16:47 +00:00
poco_load ( 0 , 0 , 0 , $entry -> url . '/poco' );
2016-12-20 10:38:16 +00:00
}
2011-11-29 03:28:33 +00:00
}
}
}
}
2015-07-19 08:40:33 +00:00
// Query your contacts from Friendica and Redmatrix/Hubzilla for their contacts
$r = q ( " SELECT DISTINCT(`poco`) AS `poco` FROM `contact` WHERE `network` IN ('%s', '%s') " ,
dbesc ( NETWORK_DFRN ), dbesc ( NETWORK_DIASPORA )
2011-11-29 03:28:33 +00:00
);
2016-12-14 08:42:36 +00:00
if ( dbm :: is_result ( $r )) {
2016-12-20 16:43:46 +00:00
foreach ( $r as $rr ) {
2011-11-29 03:28:33 +00:00
$base = substr ( $rr [ 'poco' ], 0 , strrpos ( $rr [ 'poco' ], '/' ));
2017-04-04 17:48:25 +00:00
if ( ! in_array ( $base , $done )) {
2012-05-01 08:16:47 +00:00
poco_load ( 0 , 0 , 0 , $base );
2017-04-04 17:48:25 +00:00
}
2011-11-29 03:28:33 +00:00
}
}
}
2015-07-18 20:26:06 +00:00
2017-03-12 09:13:04 +00:00
/**
* @ brief Fetch server list from remote servers and adds them when they are new .
*
* @ param string $poco URL to the POCO endpoint
*/
function poco_fetch_serverlist ( $poco ) {
$serverret = z_fetch_url ( $poco . " /@server " );
if ( ! $serverret [ " success " ]) {
return ;
}
$serverlist = json_decode ( $serverret [ 'body' ]);
if ( ! is_array ( $serverlist )) {
return ;
}
2017-06-18 21:14:52 +00:00
foreach ( $serverlist as $server ) {
2017-03-12 09:13:04 +00:00
$server_url = str_replace ( " /index.php " , " " , $server -> url );
$r = q ( " SELECT `nurl` FROM `gserver` WHERE `nurl` = '%s' " , dbesc ( normalise_link ( $server_url )));
if ( ! dbm :: is_result ( $r )) {
logger ( " Call server check for server " . $server_url , LOGGER_DEBUG );
2017-11-05 12:15:53 +00:00
Worker :: add ( PRIORITY_LOW , " discover_poco " , " server " , $server_url );
2017-03-12 09:13:04 +00:00
}
}
}
2015-09-06 10:20:31 +00:00
function poco_discover_federation () {
2017-11-07 02:22:52 +00:00
$last = Config :: get ( 'poco' , 'last_federation_discovery' );
2015-09-06 10:20:31 +00:00
2016-12-20 16:43:46 +00:00
if ( $last ) {
2015-09-06 10:20:31 +00:00
$next = $last + ( 24 * 60 * 60 );
2017-04-04 17:48:25 +00:00
if ( $next > time ()) {
2015-09-06 10:20:31 +00:00
return ;
2017-04-04 17:48:25 +00:00
}
2015-09-06 10:20:31 +00:00
}
2016-01-19 14:12:18 +00:00
// Discover Friendica, Hubzilla and Diaspora servers
2015-09-06 10:20:31 +00:00
$serverdata = fetch_url ( " http://the-federation.info/pods.json " );
2016-01-19 14:12:18 +00:00
if ( $serverdata ) {
$servers = json_decode ( $serverdata );
2017-06-18 21:14:52 +00:00
foreach ( $servers -> pods as $server ) {
2017-11-05 12:15:53 +00:00
Worker :: add ( PRIORITY_LOW , " discover_poco " , " server " , " https:// " . $server -> host );
2017-03-12 09:13:04 +00:00
}
2016-01-19 14:12:18 +00:00
}
2015-09-06 10:20:31 +00:00
2017-04-16 07:46:04 +00:00
// Disvover Mastodon servers
if ( ! Config :: get ( 'system' , 'ostatus_disabled' )) {
$serverdata = fetch_url ( " https://instances.mastodon.xyz/instances.json " );
if ( $serverdata ) {
$servers = json_decode ( $serverdata );
2017-06-18 21:14:52 +00:00
foreach ( $servers as $server ) {
2017-04-16 07:46:04 +00:00
$url = ( is_null ( $server -> https_score ) ? 'http' : 'https' ) . '://' . $server -> name ;
2017-11-05 12:15:53 +00:00
Worker :: add ( PRIORITY_LOW , " discover_poco " , " server " , $url );
2017-04-16 07:46:04 +00:00
}
}
}
2017-03-21 16:02:59 +00:00
// Currently disabled, since the service isn't available anymore.
// It is not removed since I hope that there will be a successor.
// Discover GNU Social Servers.
2017-11-07 02:22:52 +00:00
//if (!Config::get('system','ostatus_disabled')) {
2017-03-21 16:02:59 +00:00
// $serverdata = "http://gstools.org/api/get_open_instances/";
2015-09-06 10:20:31 +00:00
2017-03-21 16:02:59 +00:00
// $result = z_fetch_url($serverdata);
// if ($result["success"]) {
// $servers = json_decode($result["body"]);
2015-09-06 10:20:31 +00:00
2017-06-18 21:14:52 +00:00
// foreach($servers->data as $server)
2017-03-21 16:02:59 +00:00
// poco_check_server($server->instance_address);
// }
//}
2015-09-06 10:20:31 +00:00
2017-11-07 02:22:52 +00:00
Config :: set ( 'poco' , 'last_federation_discovery' , time ());
2015-09-06 10:20:31 +00:00
}
2017-01-27 17:00:34 +00:00
function poco_discover_single_server ( $id ) {
$r = q ( " SELECT `poco`, `nurl`, `url`, `network` FROM `gserver` WHERE `id` = %d " , intval ( $id ));
if ( ! dbm :: is_result ( $r )) {
return false ;
}
2015-07-18 20:26:06 +00:00
2017-01-27 17:00:34 +00:00
$server = $r [ 0 ];
2015-09-06 10:20:31 +00:00
2017-03-19 17:43:59 +00:00
// Discover new servers out there (Works from Friendica version 3.5.2)
2017-03-19 15:36:41 +00:00
poco_fetch_serverlist ( $server [ " poco " ]);
2015-09-05 08:54:39 +00:00
2017-01-27 17:00:34 +00:00
// Fetch all users from the other server
$url = $server [ " poco " ] . " /?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation " ;
2015-09-05 08:54:39 +00:00
2017-03-19 17:43:59 +00:00
logger ( " Fetch all users from the server " . $server [ " url " ], LOGGER_DEBUG );
2015-09-05 08:54:39 +00:00
2017-01-27 17:00:34 +00:00
$retdata = z_fetch_url ( $url );
if ( $retdata [ " success " ]) {
$data = json_decode ( $retdata [ " body " ]);
2015-07-18 20:26:06 +00:00
2017-01-27 17:00:34 +00:00
poco_discover_server ( $data , 2 );
2015-07-22 09:51:37 +00:00
2017-11-07 02:22:52 +00:00
if ( Config :: get ( 'system' , 'poco_discovery' ) > 1 ) {
2017-01-27 17:00:34 +00:00
2017-11-07 02:22:52 +00:00
$timeframe = Config :: get ( 'system' , 'poco_discovery_since' );
2017-01-27 17:00:34 +00:00
if ( $timeframe == 0 ) {
$timeframe = 30 ;
2015-09-11 18:46:55 +00:00
}
2015-07-22 09:51:37 +00:00
2017-01-27 17:00:34 +00:00
$updatedSince = date ( " Y-m-d H:i:s " , time () - $timeframe * 86400 );
// Fetch all global contacts from the other server (Not working with Redmatrix and Friendica versions before 3.3)
$url = $server [ " poco " ] . " /@global?updatedSince= " . $updatedSince . " &fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation " ;
2015-07-18 20:26:06 +00:00
2017-01-27 17:00:34 +00:00
$success = false ;
2015-07-19 07:41:36 +00:00
2015-07-18 20:26:06 +00:00
$retdata = z_fetch_url ( $url );
if ( $retdata [ " success " ]) {
2017-01-27 17:00:34 +00:00
logger ( " Fetch all global contacts from the server " . $server [ " nurl " ], LOGGER_DEBUG );
$success = poco_discover_server ( json_decode ( $retdata [ " body " ]));
}
2015-07-22 09:51:37 +00:00
2017-11-07 02:22:52 +00:00
if ( ! $success && ( Config :: get ( 'system' , 'poco_discovery' ) > 2 )) {
2017-01-27 17:00:34 +00:00
logger ( " Fetch contacts from users of the server " . $server [ " nurl " ], LOGGER_DEBUG );
poco_discover_server_users ( $data , $server );
}
}
2015-07-19 07:41:36 +00:00
2017-01-27 17:00:34 +00:00
q ( " UPDATE `gserver` SET `last_poco_query` = '%s' WHERE `nurl` = '%s' " , dbesc ( datetime_convert ()), dbesc ( $server [ " nurl " ]));
2015-07-19 07:41:36 +00:00
2017-01-27 17:00:34 +00:00
return true ;
} else {
// If the server hadn't replied correctly, then force a sanity check
poco_check_server ( $server [ " url " ], $server [ " network " ], true );
2015-07-20 22:05:44 +00:00
2017-01-27 17:00:34 +00:00
// If we couldn't reach the server, we will try it some time later
q ( " UPDATE `gserver` SET `last_poco_query` = '%s' WHERE `nurl` = '%s' " , dbesc ( datetime_convert ()), dbesc ( $server [ " nurl " ]));
2015-07-20 22:05:44 +00:00
2017-01-27 17:00:34 +00:00
return false ;
}
}
2015-07-19 07:41:36 +00:00
2017-01-27 17:00:34 +00:00
function poco_discover ( $complete = false ) {
2015-07-22 09:51:37 +00:00
2017-01-27 17:00:34 +00:00
// Update the server list
poco_discover_federation ();
2015-07-22 09:51:37 +00:00
2017-01-27 17:00:34 +00:00
$no_of_queries = 5 ;
2015-07-18 21:33:54 +00:00
2017-11-07 02:22:52 +00:00
$requery_days = intval ( Config :: get ( " system " , " poco_requery_days " ));
2015-09-11 18:46:55 +00:00
2017-03-19 21:32:11 +00:00
if ( $requery_days == 0 ) {
2017-01-27 17:00:34 +00:00
$requery_days = 7 ;
2017-03-19 21:32:11 +00:00
}
2017-01-27 17:00:34 +00:00
$last_update = date ( " c " , time () - ( 60 * 60 * 24 * $requery_days ));
2017-03-19 17:43:59 +00:00
$r = q ( " SELECT `id`, `url`, `network` FROM `gserver` WHERE `last_contact` >= `last_failure` AND `poco` != '' AND `last_poco_query` < '%s' ORDER BY RAND() " , dbesc ( $last_update ));
2017-01-27 17:00:34 +00:00
if ( dbm :: is_result ( $r )) {
2017-06-18 21:14:52 +00:00
foreach ( $r as $server ) {
2017-03-19 17:43:59 +00:00
if ( ! poco_check_server ( $server [ " url " ], $server [ " network " ])) {
// The server is not reachable? Okay, then we will try it later
q ( " UPDATE `gserver` SET `last_poco_query` = '%s' WHERE `nurl` = '%s' " , dbesc ( datetime_convert ()), dbesc ( $server [ " nurl " ]));
continue ;
}
logger ( 'Update directory from server ' . $server [ 'url' ] . ' with ID ' . $server [ 'id' ], LOGGER_DEBUG );
2017-11-05 12:15:53 +00:00
Worker :: add ( PRIORITY_LOW , " discover_poco " , " update_server_directory " , ( int ) $server [ 'id' ]);
2017-03-19 17:43:59 +00:00
2017-06-08 02:00:59 +00:00
if ( ! $complete && ( -- $no_of_queries == 0 )) {
2017-01-27 17:00:34 +00:00
break ;
2015-09-11 18:46:55 +00:00
}
2015-07-18 20:26:06 +00:00
}
2017-01-27 17:00:34 +00:00
}
2015-07-18 20:26:06 +00:00
}
2015-07-22 09:51:37 +00:00
function poco_discover_server_users ( $data , $server ) {
2015-07-22 22:32:41 +00:00
2017-04-04 17:48:25 +00:00
if ( ! isset ( $data -> entry )) {
2015-07-22 22:32:41 +00:00
return ;
2017-04-04 17:48:25 +00:00
}
2015-07-22 22:32:41 +00:00
2017-06-18 21:14:52 +00:00
foreach ( $data -> entry as $entry ) {
2015-07-19 07:41:36 +00:00
$username = " " ;
if ( isset ( $entry -> urls )) {
2017-04-04 17:48:25 +00:00
foreach ( $entry -> urls as $url ) {
2016-12-20 10:36:03 +00:00
if ( $url -> type == 'profile' ) {
2015-07-19 07:41:36 +00:00
$profile_url = $url -> value ;
$urlparts = parse_url ( $profile_url );
$username = end ( explode ( " / " , $urlparts [ " path " ]));
}
2017-04-04 17:48:25 +00:00
}
2015-07-19 07:41:36 +00:00
}
if ( $username != " " ) {
logger ( " Fetch contacts for the user " . $username . " from the server " . $server [ " nurl " ], LOGGER_DEBUG );
// Fetch all contacts from a given user from the other server
2016-10-04 03:48:01 +00:00
$url = $server [ " poco " ] . " / " . $username . " /?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation " ;
2015-07-19 07:41:36 +00:00
$retdata = z_fetch_url ( $url );
2017-04-04 17:48:25 +00:00
if ( $retdata [ " success " ]) {
2015-07-19 07:41:36 +00:00
poco_discover_server ( json_decode ( $retdata [ " body " ]), 3 );
2017-04-04 17:48:25 +00:00
}
2015-07-19 07:41:36 +00:00
}
}
}
2015-07-18 21:33:54 +00:00
function poco_discover_server ( $data , $default_generation = 0 ) {
2015-07-18 20:26:06 +00:00
2017-06-13 21:26:06 +00:00
if ( ! isset ( $data -> entry ) || ! count ( $data -> entry )) {
2015-07-22 09:51:37 +00:00
return false ;
2017-04-04 17:48:25 +00:00
}
2015-07-22 09:51:37 +00:00
$success = false ;
2015-07-19 07:41:36 +00:00
2017-06-18 21:14:52 +00:00
foreach ( $data -> entry as $entry ) {
2015-07-18 20:26:06 +00:00
$profile_url = '' ;
$profile_photo = '' ;
$connect_url = '' ;
$name = '' ;
$network = '' ;
2017-02-27 23:37:15 +00:00
$updated = NULL_DATE ;
2015-07-18 20:26:06 +00:00
$location = '' ;
$about = '' ;
$keywords = '' ;
$gender = '' ;
2016-10-04 03:48:01 +00:00
$contact_type = - 1 ;
2015-07-18 21:33:54 +00:00
$generation = $default_generation ;
2015-07-18 20:26:06 +00:00
$name = $entry -> displayName ;
2016-12-20 16:43:46 +00:00
if ( isset ( $entry -> urls )) {
2017-04-04 17:48:25 +00:00
foreach ( $entry -> urls as $url ) {
2016-12-20 10:36:03 +00:00
if ( $url -> type == 'profile' ) {
2015-07-18 20:26:06 +00:00
$profile_url = $url -> value ;
continue ;
}
2016-12-20 10:36:03 +00:00
if ( $url -> type == 'webfinger' ) {
2015-07-18 20:26:06 +00:00
$connect_url = str_replace ( 'acct:' , '' , $url -> value );
continue ;
}
}
}
2015-07-22 09:51:37 +00:00
2016-12-20 16:43:46 +00:00
if ( isset ( $entry -> photos )) {
foreach ( $entry -> photos as $photo ) {
if ( $photo -> type == 'profile' ) {
2015-07-18 20:26:06 +00:00
$profile_photo = $photo -> value ;
continue ;
}
}
}
2016-12-20 16:43:46 +00:00
if ( isset ( $entry -> updated )) {
2015-07-18 20:26:06 +00:00
$updated = date ( " Y-m-d H:i:s " , strtotime ( $entry -> updated ));
2016-12-20 16:43:46 +00:00
}
2015-07-18 20:26:06 +00:00
2017-04-04 17:48:25 +00:00
if ( isset ( $entry -> network )) {
2015-07-18 20:26:06 +00:00
$network = $entry -> network ;
2016-12-20 16:43:46 +00:00
}
2015-07-18 20:26:06 +00:00
2017-04-04 17:48:25 +00:00
if ( isset ( $entry -> currentLocation )) {
2015-07-18 20:26:06 +00:00
$location = $entry -> currentLocation ;
2016-12-20 16:43:46 +00:00
}
2015-07-18 20:26:06 +00:00
2017-04-04 17:48:25 +00:00
if ( isset ( $entry -> aboutMe )) {
2015-07-18 20:26:06 +00:00
$about = html2bbcode ( $entry -> aboutMe );
2016-12-20 16:43:46 +00:00
}
2015-07-18 20:26:06 +00:00
2017-04-04 17:48:25 +00:00
if ( isset ( $entry -> gender )) {
2015-07-18 20:26:06 +00:00
$gender = $entry -> gender ;
2016-12-20 16:43:46 +00:00
}
2015-07-18 20:26:06 +00:00
2017-06-08 02:00:59 +00:00
if ( isset ( $entry -> generation ) && ( $entry -> generation > 0 )) {
2015-07-18 20:26:06 +00:00
$generation = ++ $entry -> generation ;
2016-12-20 16:43:46 +00:00
}
2015-07-18 20:26:06 +00:00
2017-06-08 02:00:59 +00:00
if ( isset ( $entry -> contactType ) && ( $entry -> contactType >= 0 )) {
2016-10-04 03:48:01 +00:00
$contact_type = $entry -> contactType ;
2016-12-20 16:43:46 +00:00
}
2016-10-04 03:48:01 +00:00
2017-04-04 17:48:25 +00:00
if ( isset ( $entry -> tags )) {
2016-12-20 16:43:46 +00:00
foreach ( $entry -> tags as $tag ) {
2015-07-18 20:26:06 +00:00
$keywords = implode ( " , " , $tag );
2016-12-20 16:43:46 +00:00
}
}
2015-07-18 20:26:06 +00:00
2015-07-19 07:41:36 +00:00
if ( $generation > 0 ) {
2015-07-22 09:51:37 +00:00
$success = true ;
2015-07-19 07:41:36 +00:00
logger ( " Store profile " . $profile_url , LOGGER_DEBUG );
2016-10-04 03:48:01 +00:00
2017-03-22 23:13:32 +00:00
$gcontact = array ( " url " => $profile_url ,
" name " => $name ,
" network " => $network ,
" photo " => $profile_photo ,
" about " => $about ,
" location " => $location ,
" gender " => $gender ,
" keywords " => $keywords ,
" connect " => $connect_url ,
" updated " => $updated ,
" contact-type " => $contact_type ,
" generation " => $generation );
2017-03-25 16:56:04 +00:00
try {
$gcontact = sanitize_gcontact ( $gcontact );
2017-03-22 23:13:32 +00:00
update_gcontact ( $gcontact );
2017-03-25 16:56:04 +00:00
} catch ( Exception $e ) {
logger ( $e -> getMessage (), LOGGER_DEBUG );
2017-03-22 23:13:32 +00:00
}
2016-10-04 03:48:01 +00:00
2015-07-19 07:41:36 +00:00
logger ( " Done for profile " . $profile_url , LOGGER_DEBUG );
}
2015-07-18 20:26:06 +00:00
}
2015-07-22 09:51:37 +00:00
return $success ;
2015-07-18 20:26:06 +00:00
}
2016-01-05 14:34:27 +00:00
2016-04-16 13:22:54 +00:00
/**
* @ brief Removes unwanted parts from a contact url
*
* @ param string $url Contact url
* @ return string Contact url with the wanted parts
*/
function clean_contact_url ( $url ) {
2016-05-05 13:08:05 +00:00
$parts = parse_url ( $url );
2016-04-16 13:22:54 +00:00
2017-06-13 21:26:06 +00:00
if ( ! isset ( $parts [ " scheme " ]) || ! isset ( $parts [ " host " ])) {
2016-05-05 13:08:05 +00:00
return $url ;
2017-04-04 17:48:25 +00:00
}
2016-04-16 13:22:54 +00:00
2016-05-05 13:08:05 +00:00
$new_url = $parts [ " scheme " ] . " :// " . $parts [ " host " ];
2016-04-16 13:22:54 +00:00
2017-04-04 17:48:25 +00:00
if ( isset ( $parts [ " port " ])) {
2016-05-05 13:08:05 +00:00
$new_url .= " : " . $parts [ " port " ];
2017-04-04 17:48:25 +00:00
}
2016-04-16 13:22:54 +00:00
2017-04-04 17:48:25 +00:00
if ( isset ( $parts [ " path " ])) {
2016-05-05 13:08:05 +00:00
$new_url .= $parts [ " path " ];
2017-04-04 17:48:25 +00:00
}
2016-04-16 13:22:54 +00:00
2017-04-04 17:48:25 +00:00
if ( $new_url != $url ) {
2017-08-26 10:01:50 +00:00
logger ( " Cleaned contact url " . $url . " to " . $new_url . " - Called by: " . System :: callstack (), LOGGER_DEBUG );
2017-04-04 17:48:25 +00:00
}
2016-04-20 05:48:21 +00:00
2016-05-05 13:08:05 +00:00
return $new_url ;
2016-04-16 13:22:54 +00:00
}
2016-04-20 05:26:18 +00:00
/**
* @ brief Replace alternate OStatus user format with the primary one
*
* @ param arr $contact contact array ( called by reference )
*/
2016-04-20 05:00:55 +00:00
function fix_alternate_contact_address ( & $contact ) {
2017-06-08 02:00:59 +00:00
if (( $contact [ " network " ] == NETWORK_OSTATUS ) && poco_alternate_ostatus_url ( $contact [ " url " ])) {
2017-11-07 02:22:52 +00:00
$data = Probe :: uri ( $contact [ " url " ]);
2016-04-20 05:26:18 +00:00
if ( $contact [ " network " ] == NETWORK_OSTATUS ) {
2017-08-26 10:01:50 +00:00
logger ( " Fix primary url from " . $contact [ " url " ] . " to " . $data [ " url " ] . " - Called by: " . System :: callstack (), LOGGER_DEBUG );
2016-04-20 05:00:55 +00:00
$contact [ " url " ] = $data [ " url " ];
$contact [ " addr " ] = $data [ " addr " ];
2016-04-20 05:26:18 +00:00
$contact [ " alias " ] = $data [ " alias " ];
2016-04-20 05:00:55 +00:00
$contact [ " server_url " ] = $data [ " baseurl " ];
}
}
}
2016-01-10 18:06:34 +00:00
/**
* @ brief Fetch the gcontact id , add an entry if not existed
*
* @ param arr $contact contact array
* @ return bool | int Returns false if not found , integer if contact was found
*/
2016-01-06 13:13:59 +00:00
function get_gcontact_id ( $contact ) {
2016-01-05 14:34:27 +00:00
$gcontact_id = 0 ;
2016-04-23 08:46:16 +00:00
$doprobing = false ;
2016-01-05 14:34:27 +00:00
2016-04-20 06:27:11 +00:00
if ( in_array ( $contact [ " network " ], array ( NETWORK_PHANTOM ))) {
2017-08-26 10:01:50 +00:00
logger ( " Invalid network for contact url " . $contact [ " url " ] . " - Called by: " . System :: callstack (), LOGGER_DEBUG );
2016-04-19 18:39:12 +00:00
return false ;
2016-04-20 05:48:21 +00:00
}
2016-04-19 18:39:12 +00:00
2017-04-04 17:48:25 +00:00
if ( $contact [ " network " ] == NETWORK_STATUSNET ) {
2016-01-06 13:13:59 +00:00
$contact [ " network " ] = NETWORK_OSTATUS ;
2017-04-04 17:48:25 +00:00
}
2016-01-05 14:34:27 +00:00
2016-05-04 21:21:30 +00:00
// All new contacts are hidden by default
2017-04-04 17:48:25 +00:00
if ( ! isset ( $contact [ " hide " ])) {
2016-05-04 21:21:30 +00:00
$contact [ " hide " ] = true ;
2017-04-04 17:48:25 +00:00
}
2016-05-04 21:21:30 +00:00
2016-04-20 05:00:55 +00:00
// Replace alternate OStatus user format with the primary one
fix_alternate_contact_address ( $contact );
2016-04-16 15:01:32 +00:00
// Remove unwanted parts from the contact url (e.g. "?zrl=...")
2017-04-04 17:48:25 +00:00
if ( in_array ( $contact [ " network " ], array ( NETWORK_DFRN , NETWORK_DIASPORA , NETWORK_OSTATUS ))) {
2016-04-20 07:31:36 +00:00
$contact [ " url " ] = clean_contact_url ( $contact [ " url " ]);
2017-04-04 17:48:25 +00:00
}
2016-04-16 13:22:54 +00:00
2017-06-05 14:59:53 +00:00
dba :: lock ( 'gcontact' );
$r = q ( " SELECT `id`, `last_contact`, `last_failure`, `network` FROM `gcontact` WHERE `nurl` = '%s' LIMIT 1 " ,
2016-01-06 13:13:59 +00:00
dbesc ( normalise_link ( $contact [ " url " ])));
2016-01-05 14:34:27 +00:00
2017-04-04 17:48:25 +00:00
if ( dbm :: is_result ( $r )) {
2016-01-05 14:34:27 +00:00
$gcontact_id = $r [ 0 ][ " id " ];
2016-04-23 08:46:16 +00:00
// Update every 90 days
if ( in_array ( $r [ 0 ][ " network " ], array ( NETWORK_DFRN , NETWORK_DIASPORA , NETWORK_OSTATUS , " " ))) {
$last_failure_str = $r [ 0 ][ " last_failure " ];
$last_failure = strtotime ( $r [ 0 ][ " last_failure " ]);
$last_contact_str = $r [ 0 ][ " last_contact " ];
$last_contact = strtotime ( $r [ 0 ][ " last_contact " ]);
2017-06-08 02:00:59 +00:00
$doprobing = ((( time () - $last_contact ) > ( 90 * 86400 )) && (( time () - $last_failure ) > ( 90 * 86400 )));
2016-04-23 08:46:16 +00:00
}
} else {
2016-05-04 21:21:30 +00:00
q ( " INSERT INTO `gcontact` (`name`, `nick`, `addr` , `network`, `url`, `nurl`, `photo`, `created`, `updated`, `location`, `about`, `hide`, `generation`)
VALUES ( '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , % d , % d ) " ,
2016-01-06 13:13:59 +00:00
dbesc ( $contact [ " name " ]),
dbesc ( $contact [ " nick " ]),
dbesc ( $contact [ " addr " ]),
dbesc ( $contact [ " network " ]),
dbesc ( $contact [ " url " ]),
dbesc ( normalise_link ( $contact [ " url " ])),
dbesc ( $contact [ " photo " ]),
2016-01-05 14:34:27 +00:00
dbesc ( datetime_convert ()),
dbesc ( datetime_convert ()),
2016-01-06 13:13:59 +00:00
dbesc ( $contact [ " location " ]),
dbesc ( $contact [ " about " ]),
2016-05-04 21:21:30 +00:00
intval ( $contact [ " hide " ]),
2016-01-06 13:13:59 +00:00
intval ( $contact [ " generation " ])
2016-01-05 14:34:27 +00:00
);
2016-04-23 08:46:16 +00:00
$r = q ( " SELECT `id`, `network` FROM `gcontact` WHERE `nurl` = '%s' ORDER BY `id` LIMIT 2 " ,
2016-01-06 13:13:59 +00:00
dbesc ( normalise_link ( $contact [ " url " ])));
2016-01-05 14:34:27 +00:00
2017-04-04 17:48:25 +00:00
if ( dbm :: is_result ( $r )) {
2016-01-05 14:34:27 +00:00
$gcontact_id = $r [ 0 ][ " id " ];
2016-04-20 19:47:57 +00:00
2016-04-23 08:46:16 +00:00
$doprobing = in_array ( $r [ 0 ][ " network " ], array ( NETWORK_DFRN , NETWORK_DIASPORA , NETWORK_OSTATUS , " " ));
2016-04-20 19:47:57 +00:00
}
2016-01-05 14:34:27 +00:00
}
2017-06-05 14:59:53 +00:00
dba :: unlock ();
2016-01-05 14:34:27 +00:00
2016-04-23 08:46:16 +00:00
if ( $doprobing ) {
logger ( " Last Contact: " . $last_contact_str . " - Last Failure: " . $last_failure_str . " - Checking: " . $contact [ " url " ], LOGGER_DEBUG );
2017-11-05 12:15:53 +00:00
Worker :: add ( PRIORITY_LOW , 'gprobe' , $contact [ " url " ]);
2016-04-23 08:46:16 +00:00
}
2016-01-05 14:34:27 +00:00
return $gcontact_id ;
}
2016-01-10 18:06:34 +00:00
/**
* @ brief Updates the gcontact table from a given array
*
* @ param arr $contact contact array
* @ return bool | int Returns false if not found , integer if contact was found
*/
2016-01-06 13:13:59 +00:00
function update_gcontact ( $contact ) {
2016-01-05 14:34:27 +00:00
2017-02-22 22:25:35 +00:00
// Check for invalid "contact-type" value
2017-06-08 02:00:59 +00:00
if ( isset ( $contact [ 'contact-type' ]) && ( intval ( $contact [ 'contact-type' ]) < 0 )) {
2017-02-22 22:25:35 +00:00
$contact [ 'contact-type' ] = 0 ;
}
2016-01-13 09:53:38 +00:00
/// @todo update contact table as well
2016-01-06 13:13:59 +00:00
$gcontact_id = get_gcontact_id ( $contact );
2016-01-05 14:34:27 +00:00
2017-04-04 17:48:25 +00:00
if ( ! $gcontact_id ) {
2016-01-05 14:34:27 +00:00
return false ;
2017-04-04 17:48:25 +00:00
}
2016-01-05 14:34:27 +00:00
2016-01-23 21:36:15 +00:00
$r = q ( " SELECT `name`, `nick`, `photo`, `location`, `about`, `addr`, `generation`, `birthday`, `gender`, `keywords`,
2016-10-04 03:48:01 +00:00
`contact-type` , `hide` , `nsfw` , `network` , `alias` , `notify` , `server_url` , `connect` , `updated` , `url`
2016-01-06 13:13:59 +00:00
FROM `gcontact` WHERE `id` = % d LIMIT 1 " ,
intval ( $gcontact_id ));
2016-01-23 21:36:15 +00:00
// Get all field names
$fields = array ();
2017-06-18 21:14:52 +00:00
foreach ( $r [ 0 ] as $field => $data ) {
2016-01-23 21:36:15 +00:00
$fields [ $field ] = $data ;
2017-04-04 17:48:25 +00:00
}
2016-01-06 13:13:59 +00:00
2016-01-23 21:36:15 +00:00
unset ( $fields [ " url " ]);
unset ( $fields [ " updated " ]);
2016-05-04 07:30:55 +00:00
unset ( $fields [ " hide " ]);
2016-01-05 14:34:27 +00:00
2016-02-14 11:39:57 +00:00
// Bugfix: We had an error in the storing of keywords which lead to the "0"
// This value is still transmitted via poco.
2017-04-04 17:48:25 +00:00
if ( $contact [ " keywords " ] == " 0 " ) {
2016-02-14 11:39:57 +00:00
unset ( $contact [ " keywords " ]);
2017-04-04 17:48:25 +00:00
}
2016-02-14 11:39:57 +00:00
2017-04-04 17:48:25 +00:00
if ( $r [ 0 ][ " keywords " ] == " 0 " ) {
2016-02-14 11:39:57 +00:00
$r [ 0 ][ " keywords " ] = " " ;
2017-04-04 17:48:25 +00:00
}
2016-02-14 11:39:57 +00:00
2016-01-23 21:36:15 +00:00
// assign all unassigned fields from the database entry
2017-06-18 21:15:50 +00:00
foreach ( $fields as $field => $data ) {
2017-06-13 21:26:06 +00:00
if ( ! isset ( $contact [ $field ]) || ( $contact [ $field ] == " " )) {
2016-01-23 21:36:15 +00:00
$contact [ $field ] = $r [ 0 ][ $field ];
2017-04-04 17:48:25 +00:00
}
}
2016-01-05 14:34:27 +00:00
2017-04-04 17:48:25 +00:00
if ( ! isset ( $contact [ " hide " ])) {
2016-05-04 07:30:55 +00:00
$contact [ " hide " ] = $r [ 0 ][ " hide " ];
2017-04-04 17:48:25 +00:00
}
2016-05-04 07:30:55 +00:00
$fields [ " hide " ] = $r [ 0 ][ " hide " ];
2017-04-04 17:48:25 +00:00
if ( $contact [ " network " ] == NETWORK_STATUSNET ) {
2016-01-23 21:36:15 +00:00
$contact [ " network " ] = NETWORK_OSTATUS ;
2017-04-04 17:48:25 +00:00
}
2016-01-07 22:43:16 +00:00
2016-04-20 05:00:55 +00:00
// Replace alternate OStatus user format with the primary one
fix_alternate_contact_address ( $contact );
2017-04-04 17:48:25 +00:00
if ( ! isset ( $contact [ " updated " ])) {
2017-04-13 19:25:00 +00:00
$contact [ " updated " ] = dbm :: date ();
2017-04-04 17:48:25 +00:00
}
2016-01-10 18:06:34 +00:00
2017-08-30 19:33:16 +00:00
if ( $contact [ " network " ] == NETWORK_TWITTER ) {
$contact [ " server_url " ] = 'http://twitter.com' ;
}
2016-02-14 10:56:23 +00:00
if ( $contact [ " server_url " ] == " " ) {
2017-08-30 18:05:41 +00:00
$data = Probe :: uri ( $contact [ " url " ]);
if ( $data [ " network " ] != NETWORK_PHANTOM ) {
$contact [ " server_url " ] = $data [ 'baseurl' ];
2017-04-04 17:48:25 +00:00
}
} else {
2016-02-14 10:56:23 +00:00
$contact [ " server_url " ] = normalise_link ( $contact [ " server_url " ]);
2017-04-04 17:48:25 +00:00
}
2016-02-14 10:56:23 +00:00
2017-06-08 02:00:59 +00:00
if (( $contact [ " addr " ] == " " ) && ( $contact [ " server_url " ] != " " ) && ( $contact [ " nick " ] != " " )) {
2016-02-14 10:56:23 +00:00
$hostname = str_replace ( " http:// " , " " , $contact [ " server_url " ]);
$contact [ " addr " ] = $contact [ " nick " ] . " @ " . $hostname ;
}
2016-01-23 21:36:15 +00:00
// Check if any field changed
$update = false ;
unset ( $fields [ " generation " ]);
2016-01-07 22:43:16 +00:00
2017-06-08 02:00:59 +00:00
if ((( $contact [ " generation " ] > 0 ) && ( $contact [ " generation " ] <= $r [ 0 ][ " generation " ])) || ( $r [ 0 ][ " generation " ] == 0 )) {
2017-06-18 21:14:52 +00:00
foreach ( $fields as $field => $data ) {
2016-02-13 11:26:58 +00:00
if ( $contact [ $field ] != $r [ 0 ][ $field ]) {
logger ( " Difference for contact " . $contact [ " url " ] . " in field ' " . $field . " '. New value: ' " . $contact [ $field ] . " ', old value ' " . $r [ 0 ][ $field ] . " ' " , LOGGER_DEBUG );
$update = true ;
}
2017-04-04 17:48:25 +00:00
}
2016-01-06 13:13:59 +00:00
2016-02-13 11:26:58 +00:00
if ( $contact [ " generation " ] < $r [ 0 ][ " generation " ]) {
logger ( " Difference for contact " . $contact [ " url " ] . " in field 'generation'. new value: ' " . $contact [ " generation " ] . " ', old value ' " . $r [ 0 ][ " generation " ] . " ' " , LOGGER_DEBUG );
$update = true ;
}
}
2016-01-06 13:13:59 +00:00
2016-01-23 21:36:15 +00:00
if ( $update ) {
2016-10-04 03:48:01 +00:00
logger ( " Update gcontact for " . $contact [ " url " ], LOGGER_DEBUG );
2017-09-17 08:13:10 +00:00
$condition = array ( '`nurl` = ? AND (`generation` = 0 OR `generation` >= ?)' ,
normalise_link ( $contact [ " url " ]), $contact [ " generation " ]);
$contact [ " updated " ] = dbm :: date ( $contact [ " updated " ]);
$updated = array ( 'photo' => $contact [ 'photo' ], 'name' => $contact [ 'name' ],
'nick' => $contact [ 'nick' ], 'addr' => $contact [ 'addr' ],
'network' => $contact [ 'network' ], 'birthday' => $contact [ 'birthday' ],
'gender' => $contact [ 'gender' ], 'keywords' => $contact [ 'keywords' ],
'hide' => $contact [ 'hide' ], 'nsfw' => $contact [ 'nsfw' ],
'contact-type' => $contact [ 'contact-type' ], 'alias' => $contact [ 'alias' ],
'notify' => $contact [ 'notify' ], 'url' => $contact [ 'url' ],
'location' => $contact [ 'location' ], 'about' => $contact [ 'about' ],
'generation' => $contact [ 'generation' ], 'updated' => $contact [ 'updated' ],
'server_url' => $contact [ 'server_url' ], 'connect' => $contact [ 'connect' ]);
dba :: update ( 'gcontact' , $updated , $condition , $fields );
2016-02-14 06:31:57 +00:00
// Now update the contact entry with the user id "0" as well.
// This is used for the shadow copies of public items.
$r = q ( " SELECT `id` FROM `contact` WHERE `nurl` = '%s' AND `uid` = 0 ORDER BY `id` LIMIT 1 " ,
dbesc ( normalise_link ( $contact [ " url " ])));
2017-04-04 17:48:25 +00:00
if ( dbm :: is_result ( $r )) {
2017-09-17 08:13:10 +00:00
logger ( " Update public contact " . $r [ 0 ][ " id " ], LOGGER_DEBUG );
2016-02-14 06:31:57 +00:00
update_contact_avatar ( $contact [ " photo " ], 0 , $r [ 0 ][ " id " ]);
2017-09-17 08:13:10 +00:00
$fields = array ( 'name' , 'nick' , 'addr' ,
'network' , 'bd' , 'gender' ,
'keywords' , 'alias' , 'contact-type' ,
'url' , 'location' , 'about' );
$old_contact = dba :: select ( 'contact' , $fields , array ( 'id' => $r [ 0 ][ " id " ]), array ( 'limit' => 1 ));
// Update it with the current values
$fields = array ( 'name' => $contact [ 'name' ], 'nick' => $contact [ 'nick' ],
'addr' => $contact [ 'addr' ], 'network' => $contact [ 'network' ],
'bd' => $contact [ 'birthday' ], 'gender' => $contact [ 'gender' ],
'keywords' => $contact [ 'keywords' ], 'alias' => $contact [ 'alias' ],
'contact-type' => $contact [ 'contact-type' ], 'url' => $contact [ 'url' ],
'location' => $contact [ 'location' ], 'about' => $contact [ 'about' ]);
dba :: update ( 'contact' , $fields , array ( 'id' => $r [ 0 ][ " id " ]), $old_contact );
2016-02-14 06:31:57 +00:00
}
2016-01-06 13:13:59 +00:00
}
2016-01-05 14:34:27 +00:00
return $gcontact_id ;
}
2016-01-10 18:06:34 +00:00
/**
* @ brief Updates the gcontact entry from probe
*
* @ param str $url profile link
*/
function update_gcontact_from_probe ( $url ) {
2017-11-07 02:22:52 +00:00
$data = Probe :: uri ( $url );
2016-01-10 18:06:34 +00:00
2016-04-20 06:27:11 +00:00
if ( in_array ( $data [ " network " ], array ( NETWORK_PHANTOM ))) {
2017-08-26 10:01:50 +00:00
logger ( " Invalid network for contact url " . $data [ " url " ] . " - Called by: " . System :: callstack (), LOGGER_DEBUG );
2016-02-13 11:26:58 +00:00
return ;
2016-04-20 05:48:21 +00:00
}
2016-02-13 11:26:58 +00:00
2017-03-23 06:45:00 +00:00
$data [ " server_url " ] = $data [ " baseurl " ];
2016-02-13 11:26:58 +00:00
update_gcontact ( $data );
2016-01-10 18:06:34 +00:00
}
2016-01-19 14:12:18 +00:00
2016-05-05 13:08:05 +00:00
/**
* @ brief Update the gcontact entry for a given user id
*
* @ param int $uid User ID
*/
function update_gcontact_for_user ( $uid ) {
$r = q ( " SELECT `profile`.`locality`, `profile`.`region`, `profile`.`country-name`,
`profile` . `name` , `profile` . `about` , `profile` . `gender` ,
`profile` . `pub_keywords` , `profile` . `dob` , `profile` . `photo` ,
`profile` . `net-publish` , `user` . `nickname` , `user` . `hidewall` ,
`contact` . `notify` , `contact` . `url` , `contact` . `addr`
FROM `profile`
INNER JOIN `user` ON `user` . `uid` = `profile` . `uid`
INNER JOIN `contact` ON `contact` . `uid` = `profile` . `uid`
WHERE `profile` . `uid` = % d AND `profile` . `is-default` AND `contact` . `self` " ,
intval ( $uid ));
$location = formatted_location ( array ( " locality " => $r [ 0 ][ " locality " ], " region " => $r [ 0 ][ " region " ],
" country-name " => $r [ 0 ][ " country-name " ]));
// The "addr" field was added in 3.4.3 so it can be empty for older users
2017-06-18 20:10:03 +00:00
if ( $r [ 0 ][ " addr " ] != " " ) {
2017-08-26 07:32:10 +00:00
$addr = $r [ 0 ][ " nickname " ] . '@' . str_replace ( array ( " http:// " , " https:// " ), " " , System :: baseUrl ());
2017-06-18 20:10:03 +00:00
} else {
2016-05-05 13:08:05 +00:00
$addr = $r [ 0 ][ " addr " ];
2017-06-18 20:10:03 +00:00
}
2016-05-05 13:08:05 +00:00
$gcontact = array ( " name " => $r [ 0 ][ " name " ], " location " => $location , " about " => $r [ 0 ][ " about " ],
" gender " => $r [ 0 ][ " gender " ], " keywords " => $r [ 0 ][ " pub_keywords " ],
" birthday " => $r [ 0 ][ " dob " ], " photo " => $r [ 0 ][ " photo " ],
" notify " => $r [ 0 ][ " notify " ], " url " => $r [ 0 ][ " url " ],
2017-06-08 02:00:59 +00:00
" hide " => ( $r [ 0 ][ " hidewall " ] || ! $r [ 0 ][ " net-publish " ]),
2016-05-05 13:08:05 +00:00
" nick " => $r [ 0 ][ " nickname " ], " addr " => $addr ,
2017-08-26 07:32:10 +00:00
" connect " => $addr , " server_url " => System :: baseUrl (),
2016-05-05 13:38:28 +00:00
" generation " => 1 , " network " => NETWORK_DFRN );
2016-05-05 13:08:05 +00:00
update_gcontact ( $gcontact );
}
2016-01-19 14:12:18 +00:00
/**
* @ brief Fetches users of given GNU Social server
*
* If the " Statistics " plugin is enabled ( See http :// gstools . org / for details ) we query user data with this .
*
* @ param str $server Server address
*/
function gs_fetch_users ( $server ) {
logger ( " Fetching users from GNU Social server " . $server , LOGGER_DEBUG );
$url = $server . " /main/statistics " ;
$result = z_fetch_url ( $url );
2017-06-18 20:10:03 +00:00
if ( ! $result [ " success " ]) {
2016-01-19 14:12:18 +00:00
return false ;
2017-06-18 20:10:03 +00:00
}
2016-01-19 14:12:18 +00:00
$statistics = json_decode ( $result [ " body " ]);
if ( is_object ( $statistics -> config )) {
2017-06-18 20:10:03 +00:00
if ( $statistics -> config -> instance_with_ssl ) {
2016-01-19 14:12:18 +00:00
$server = " https:// " ;
2017-06-18 20:10:03 +00:00
} else {
2016-01-19 14:12:18 +00:00
$server = " http:// " ;
2017-06-18 20:10:03 +00:00
}
2016-01-19 14:12:18 +00:00
$server .= $statistics -> config -> instance_address ;
$hostname = $statistics -> config -> instance_address ;
} else {
2017-06-18 20:10:03 +00:00
/// @TODO is_object() above means here no object, still $statistics is being used as object
if ( $statistics -> instance_with_ssl ) {
2016-01-19 14:12:18 +00:00
$server = " https:// " ;
2017-06-18 20:10:03 +00:00
} else {
2016-01-19 14:12:18 +00:00
$server = " http:// " ;
2017-06-18 20:10:03 +00:00
}
2016-01-19 14:12:18 +00:00
$server .= $statistics -> instance_address ;
$hostname = $statistics -> instance_address ;
}
2017-06-18 20:14:21 +00:00
if ( is_object ( $statistics -> users )) {
2017-06-18 21:14:52 +00:00
foreach ( $statistics -> users as $nick => $user ) {
2016-01-21 18:00:08 +00:00
$profile_url = $server . " / " . $user -> nickname ;
$contact = array ( " url " => $profile_url ,
" name " => $user -> fullname ,
" addr " => $user -> nickname . " @ " . $hostname ,
" nick " => $user -> nickname ,
" about " => $user -> bio ,
" network " => NETWORK_OSTATUS ,
2017-08-26 07:32:10 +00:00
" photo " => System :: baseUrl () . " /images/person-175.jpg " );
2016-01-21 18:00:08 +00:00
get_gcontact_id ( $contact );
}
2017-06-18 20:10:03 +00:00
}
2016-01-19 14:12:18 +00:00
}
/**
* @ brief Asking GNU Social server on a regular base for their user data
*
*/
function gs_discover () {
2017-11-07 02:22:52 +00:00
$requery_days = intval ( Config :: get ( " system " , " poco_requery_days " ));
2016-01-19 14:12:18 +00:00
$last_update = date ( " c " , time () - ( 60 * 60 * 24 * $requery_days ));
$r = q ( " SELECT `nurl`, `url` FROM `gserver` WHERE `last_contact` >= `last_failure` AND `network` = '%s' AND `last_poco_query` < '%s' ORDER BY RAND() LIMIT 5 " ,
dbesc ( NETWORK_OSTATUS ), dbesc ( $last_update ));
2017-06-18 20:10:03 +00:00
if ( ! dbm :: is_result ( $r )) {
2016-01-19 14:12:18 +00:00
return ;
2017-06-18 20:10:03 +00:00
}
2016-01-19 14:12:18 +00:00
2017-06-18 21:14:52 +00:00
foreach ( $r as $server ) {
2016-01-19 14:12:18 +00:00
gs_fetch_users ( $server [ " url " ]);
q ( " UPDATE `gserver` SET `last_poco_query` = '%s' WHERE `nurl` = '%s' " , dbesc ( datetime_convert ()), dbesc ( $server [ " nurl " ]));
}
}
2017-03-04 11:04:00 +00:00
/**
* @ brief Returns a list of all known servers
* @ return array List of server urls
*/
function poco_serverlist () {
2017-03-12 09:41:10 +00:00
$r = q ( " SELECT `url`, `site_name` AS `displayName`, `network`, `platform`, `version` FROM `gserver`
2017-03-04 11:04:00 +00:00
WHERE `network` IN ( '%s' , '%s' , '%s' ) AND `last_contact` > `last_failure`
ORDER BY `last_contact`
LIMIT 1000 " ,
dbesc ( NETWORK_DFRN ), dbesc ( NETWORK_DIASPORA ), dbesc ( NETWORK_OSTATUS ));
if ( ! dbm :: is_result ( $r )) {
return false ;
}
2017-06-18 20:10:03 +00:00
2017-03-12 09:41:10 +00:00
return $r ;
2017-03-04 11:04:00 +00:00
}