aboutsummaryrefslogtreecommitdiffstats
path: root/include/network.php
diff options
context:
space:
mode:
Diffstat (limited to 'include/network.php')
-rw-r--r--include/network.php1319
1 files changed, 476 insertions, 843 deletions
diff --git a/include/network.php b/include/network.php
index 66716ef9e..7e2dbf4cf 100644
--- a/include/network.php
+++ b/include/network.php
@@ -22,8 +22,8 @@ function get_capath() {
* @param int $redirects default 0
* internal use, recursion counter
* @param array $opts (optional parameters) associative array with:
- * * \b accept_content => supply Accept: header with 'accept_content' as the value
* * \b timeout => int seconds, default system config value or 60 seconds
+ * * \b headers => array of additional header fields
* * \b http_auth => username:password
* * \b novalidate => do not validate SSL certs, default is to validate using our CA list
* * \b nobody => only return the header
@@ -31,6 +31,7 @@ function get_capath() {
* * \b custom => custom request method: e.g. 'PUT', 'DELETE'
* * \b cookiejar => cookie file (write)
* * \b cookiefile => cookie file (read)
+ * * \b session => boolean; append session cookie *if* $url is our own site
*
* @return array an associative array with:
* * \e int \b return_code => HTTP return code or 0 if timeout or failure
@@ -74,8 +75,21 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
if(x($opts,'readfunc'))
@curl_setopt($ch, CURLOPT_READFUNCTION, $opts['readfunc']);
- if(x($opts,'headers'))
- @curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']);
+ // When using the session option and fetching from our own site,
+ // append the PHPSESSID cookie to any existing headers.
+ // Don't add to $opts['headers'] so that the cookie does not get
+ // sent to other sites via redirects
+
+ $instance_headers = ((array_key_exists('headers',$opts) && is_array($opts['headers'])) ? $opts['headers'] : []);
+
+ if(x($opts,'session')) {
+ if(strpos($url,z_root()) === 0) {
+ $instance_headers[] = 'Cookie: PHPSESSID=' . session_id();
+ }
+ }
+ if($instance_headers)
+ @curl_setopt($ch, CURLOPT_HTTPHEADER, $instance_headers);
+
if(x($opts,'nobody'))
@curl_setopt($ch, CURLOPT_NOBODY, $opts['nobody']);
@@ -91,6 +105,7 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== false) ? $curl_time : 60));
}
+
if(x($opts,'http_auth')) {
// "username" . ':' . "password"
@curl_setopt($ch, CURLOPT_USERPWD, $opts['http_auth']);
@@ -186,7 +201,6 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
* @param int $redirects = 0
* internal use, recursion counter
* @param array $opts (optional parameters)
- * 'accept_content' => supply Accept: header with 'accept_content' as the value
* 'timeout' => int seconds, default system config value or 60 seconds
* 'http_auth' => username:password
* 'novalidate' => do not validate SSL certs, default is to validate using our CA list
@@ -229,9 +243,16 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_HEADER, false);
}
- if(x($opts,'headers')) {
- @curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']);
+ $instance_headers = ((array_key_exists('headers',$opts) && is_array($opts['headers'])) ? $opts['headers'] : []);
+
+ if(x($opts,'session')) {
+ if(strpos($url,z_root()) === 0) {
+ $instance_headers[] = 'Cookie: PHPSESSID=' . session_id();
+ }
}
+ if($instance_headers)
+ @curl_setopt($ch, CURLOPT_HTTPHEADER, $instance_headers);
+
if(x($opts,'nobody'))
@curl_setopt($ch, CURLOPT_NOBODY, $opts['nobody']);
@@ -322,7 +343,7 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) {
if (isset($url_parsed)) {
curl_close($ch);
if($http_code == 303) {
- return z_fetch_url($newurl,false,$redirects++,$opts);
+ return z_fetch_url($newurl,false,++$redirects,$opts);
} else {
return z_post_url($newurl,$params,++$redirects,$opts);
}
@@ -376,36 +397,13 @@ function json_return_and_die($x, $content_type = 'application/json') {
killme();
}
-
-
-// Generic XML return
-// Outputs a basic dfrn XML status structure to STDOUT, with a <status> variable
-// of $st and an optional text <message> of $message and terminates the current process.
-
-
-function xml_status($st, $message = '') {
-
- $xml_message = ((strlen($message)) ? "\t<message>" . xmlify($message) . "</message>\r\n" : '');
-
- if($st)
- logger('xml_status returning non_zero: ' . $st . " message=" . $message);
-
- header( "Content-type: text/xml" );
- echo '<?xml version="1.0" encoding="UTF-8"?>'."\r\n";
- echo "<result>\r\n\t<status>$st</status>\r\n$xml_message</result>\r\n";
- killme();
-}
-
-
-
/**
- * @brief Send HTTP status header
+ * @brief Send HTTP status header.
*
* @param int $val
* integer HTTP status result value
* @param string $msg
* optional message
- * @returns nil
*/
function http_status($val, $msg = '') {
if ($val >= 400)
@@ -413,12 +411,11 @@ function http_status($val, $msg = '') {
if ($val >= 200 && $val < 300)
$msg = (($msg) ? $msg : 'OK');
- logger('http_status_exit ' . $val . ' ' . $msg);
+ logger(\App::$query_string . ':' . $val . ' ' . $msg);
header($_SERVER['SERVER_PROTOCOL'] . ' ' . $val . ' ' . $msg);
}
-
/**
* @brief Send HTTP status header and exit.
*
@@ -426,58 +423,57 @@ function http_status($val, $msg = '') {
* integer HTTP status result value
* @param string $msg
* optional message
- * @returns (does not return, process is terminated)
+ * @return does not return, process is terminated
*/
function http_status_exit($val, $msg = '') {
http_status($val, $msg);
killme();
}
-
-
-// convert an XML document to a normalised, case-corrected array
-// used by webfinger
-
-
+/**
+ * @brief convert an XML document to a normalised, case-corrected array used by webfinger.
+ *
+ * @param string|array|SimpleXMLElement $xml_element
+ * @param int $recursion_depth[in,out]
+ * @return NULL|string|array
+ */
function convert_xml_element_to_array($xml_element, &$recursion_depth=0) {
- // If we're getting too deep, bail out
- if ($recursion_depth > 512) {
- return(null);
- }
-
- if (!is_string($xml_element) &&
- !is_array($xml_element) &&
- (get_class($xml_element) == 'SimpleXMLElement')) {
- $xml_element_copy = $xml_element;
- $xml_element = get_object_vars($xml_element);
- }
+ // If we're getting too deep, bail out
+ if ($recursion_depth > 512) {
+ return(null);
+ }
- if (is_array($xml_element)) {
- $result_array = array();
- if (count($xml_element) <= 0) {
- return (trim(strval($xml_element_copy)));
- }
+ if (!is_string($xml_element) &&
+ !is_array($xml_element) &&
+ (get_class($xml_element) == 'SimpleXMLElement')) {
+ $xml_element_copy = $xml_element;
+ $xml_element = get_object_vars($xml_element);
+ }
- foreach($xml_element as $key=>$value) {
+ if (is_array($xml_element)) {
+ $result_array = array();
+ if (count($xml_element) <= 0) {
+ return (trim(strval($xml_element_copy)));
+ }
- $recursion_depth++;
- $result_array[strtolower($key)] =
+ foreach($xml_element as $key=>$value) {
+ $recursion_depth++;
+ $result_array[strtolower($key)] =
convert_xml_element_to_array($value, $recursion_depth);
- $recursion_depth--;
- }
- if ($recursion_depth == 0) {
- $temp_array = $result_array;
- $result_array = array(
- strtolower($xml_element_copy->getName()) => $temp_array,
- );
- }
-
- return ($result_array);
-
- } else {
- return (trim(strval($xml_element)));
+ $recursion_depth--;
}
+ if ($recursion_depth == 0) {
+ $temp_array = $result_array;
+ $result_array = array(
+ strtolower($xml_element_copy->getName()) => $temp_array,
+ );
+ }
+
+ return ($result_array);
+ } else {
+ return (trim(strval($xml_element)));
+ }
}
@@ -491,7 +487,7 @@ function z_dns_check($h,$check_mx = 0) {
if(is_array(\App::$config) && array_key_exists('system',\App::$config)
&& is_array(\App::$config['system'])
- && array_key_exists('do_not_check_dns',\App::$config['system'])
+ && array_key_exists('do_not_check_dns',\App::$config['system'])
&& \App::$config['system']['do_not_check_dns'])
return true;
@@ -499,56 +495,71 @@ function z_dns_check($h,$check_mx = 0) {
//$opts = DNS_A + DNS_CNAME + DNS_PTR;
//if($check_mx)
// $opts += DNS_MX;
- // Specific record type flags are unreliable on FreeBSD and Mac,
- // so now we'll ignore these and just check for the existence of any DNS record.
+ // Specific record type flags are unreliable on FreeBSD and Mac,
+ // so now we'll ignore these and just check for the existence of any DNS record.
return((@dns_get_record($h) || filter_var($h, FILTER_VALIDATE_IP)) ? true : false);
-
}
-// Take a URL from the wild, prepend http:// if necessary
-// and check DNS to see if it's real (or check if is a valid IP address)
-// return true if it's OK, false if something is wrong with it
-
-
+/**
+ * @brief Validates a given URL
+ *
+ * Take a URL from the wild, prepend http:// if necessary and check DNS to see
+ * if it's real (or check if is a valid IP address).
+ *
+ * @see z_dns_check()
+ *
+ * @param string $url[in,out] URL to check
+ * @return boolean Return true if it's OK, false if something is wrong with it
+ */
function validate_url(&$url) {
// no naked subdomains (allow localhost for tests)
- if(strpos($url,'.') === false && strpos($url,'/localhost/') === false)
+ if(strpos($url, '.') === false && strpos($url, '/localhost/') === false)
return false;
- if(substr($url,0,4) != 'http')
+
+ if(substr($url, 0, 4) != 'http')
$url = 'http://' . $url;
+
$h = @parse_url($url);
if(($h) && z_dns_check($h['host'])) {
return true;
}
+
return false;
}
-// checks that email is an actual resolvable internet address
-
-
+/**
+ * @brief Checks that email is an actual resolvable internet address.
+ *
+ * @param string $addr
+ * @return boolean
+ */
function validate_email($addr) {
- if(get_config('system','disable_email_validation'))
+ if(get_config('system', 'disable_email_validation'))
return true;
- if(! strpos($addr,'@'))
+ if(! strpos($addr, '@'))
return false;
- $h = substr($addr,strpos($addr,'@') + 1);
- if(($h) && z_dns_check($h,true)) {
+ $h = substr($addr, strpos($addr, '@') + 1);
+
+ if(($h) && z_dns_check($h, true)) {
return true;
}
+
return false;
}
-// Check $url against our list of allowed sites,
-// wildcards allowed. If allowed_sites is unset return true;
-// If url is allowed, return true.
-// otherwise, return false
-
-
+/**
+ * @brief Check $url against our list of allowed sites.
+ *
+ * Wildcards allowed. If allowed_sites is unset return true.
+ *
+ * @param string $url
+ * @return boolean Return true if url is allowed, otherwise return false
+ */
function allowed_url($url) {
$h = @parse_url($url);
@@ -557,7 +568,7 @@ function allowed_url($url) {
return false;
}
- $str_allowed = get_config('system','allowed_sites');
+ $str_allowed = get_config('system', 'allowed_sites');
if(! $str_allowed)
return true;
@@ -585,21 +596,23 @@ function allowed_url($url) {
return $found;
}
-// check if email address is allowed to register here.
-// Compare against our list (wildcards allowed).
-// Returns false if not allowed, true if allowed or if
-// allowed list is not configured.
-
-
+/**
+ * @brief Check if email address is allowed to register here.
+ *
+ * Compare against our list (wildcards allowed).
+ *
+ * @param string $email
+ * @return boolean Returns false if not allowed, true if allowed or if allowed list is
+ * not configured.
+ */
function allowed_email($email) {
-
- $domain = strtolower(substr($email,strpos($email,'@') + 1));
+ $domain = strtolower(substr($email, strpos($email, '@') + 1));
if(! $domain)
return false;
- $str_allowed = get_config('system','allowed_email');
- $str_not_allowed = get_config('system','not_allowed_email');
+ $str_allowed = get_config('system', 'allowed_email');
+ $str_not_allowed = get_config('system', 'not_allowed_email');
if(! $str_allowed && ! $str_not_allowed)
return true;
@@ -610,7 +623,7 @@ function allowed_email($email) {
$fnmatch = function_exists('fnmatch');
- $allowed = explode(',',$str_allowed);
+ $allowed = explode(',', $str_allowed);
if(count($allowed)) {
foreach($allowed as $a) {
@@ -622,7 +635,7 @@ function allowed_email($email) {
}
}
- $not_allowed = explode(',',$str_not_allowed);
+ $not_allowed = explode(',', $str_not_allowed);
if(count($not_allowed)) {
foreach($not_allowed as $na) {
@@ -639,6 +652,7 @@ function allowed_email($email) {
} elseif (!$str_allowed && !$found_not_allowed) {
$return = true;
}
+
return $return;
}
@@ -648,19 +662,24 @@ function parse_xml_string($s,$strict = true) {
if($strict) {
if(! strstr($s,'<?xml'))
return false;
+
$s2 = substr($s,strpos($s,'<?xml'));
}
else
$s2 = $s;
+
libxml_use_internal_errors(true);
$x = @simplexml_load_string($s2);
- if(! $x) {
+ if($x === false) {
logger('libxml: parse: error: ' . $s2, LOGGER_DATA);
- foreach(libxml_get_errors() as $err)
- logger('libxml: parse: ' . $err->code." at ".$err->line.":".$err->column." : ".$err->message, LOGGER_DATA);
+ foreach(libxml_get_errors() as $err) {
+ logger('libxml: parse: ' . $err->code . ' at ' . $err->line
+ . ':' . $err->column . ' : ' . $err->message, LOGGER_DATA);
+ }
libxml_clear_errors();
}
+
return $x;
}
@@ -676,7 +695,7 @@ function scale_external_images($s, $include_link = true, $scale_replace = false)
require_once('include/photo/photo_driver.php');
foreach($matches as $mtch) {
- logger('scale_external_image: ' . $mtch[2] . ' ' . $mtch[3]);
+ logger('data: ' . $mtch[2] . ' ' . $mtch[3]);
if(substr($mtch[1],0,1) == '=') {
$owidth = intval(substr($mtch[2],1));
@@ -727,12 +746,12 @@ function scale_external_images($s, $include_link = true, $scale_replace = false)
$ph->scaleImage(1024);
$new_width = $ph->getWidth();
$new_height = $ph->getHeight();
- logger('scale_external_images: ' . $orig_width . '->' . $new_width . 'w ' . $orig_height . '->' . $new_height . 'h' . ' match: ' . $mtch[0], LOGGER_DEBUG);
+ logger('data: ' . $orig_width . '->' . $new_width . 'w ' . $orig_height . '->' . $new_height . 'h' . ' match: ' . $mtch[0], LOGGER_DEBUG);
$s = str_replace($mtch[0],'[' . $tag . '=' . $new_width . 'x' . $new_height. ']' . $scaled . '[/' . $tag . ']'
. "\n" . (($include_link)
? '[zrl=' . $mtch[2] . ']' . t('view full size') . '[/zrl]' . "\n"
: ''),$s);
- logger('scale_external_images: new string: ' . $s, LOGGER_DEBUG);
+ logger('new string: ' . $s, LOGGER_DEBUG);
}
}
}
@@ -747,27 +766,31 @@ function scale_external_images($s, $include_link = true, $scale_replace = false)
}
/**
- * xml2array() will convert the given XML text to an array in the XML structure.
+ * @brief xml2array() will convert the given XML text to an array in the XML structure.
+ *
* Link: http://www.bin-co.com/php/scripts/xml2array/
- * Portions significantly re-written by mike@macgirvin.com for Friendica (namespaces, lowercase tags, get_attribute default changed, more...)
- * Arguments : $contents - The XML text
- * $namespaces - true or false include namespace information in the returned array as array elements.
- * $get_attributes - 1 or 0. If this is 1 the function will get the attributes as well as the tag values - this results in a different array structure in the return value.
- * $priority - Can be 'tag' or 'attribute'. This will change the way the resulting array sturcture. For 'tag', the tags are given more importance.
- * Return: The parsed XML in an array form. Use print_r() to see the resulting array structure.
+ * Portions significantly re-written by mike@macgirvin.com for Friendica
+ * (namespaces, lowercase tags, get_attribute default changed, more...)
+ *
* Examples: $array = xml2array(file_get_contents('feed.xml'));
- * $array = xml2array(file_get_contents('feed.xml', true, 1, 'attribute'));
+ * $array = xml2array(file_get_contents('feed.xml', true, 1, 'attribute'));
+ *
+ * @param string $contents The XML text
+ * @param boolean $namespaces true or false include namespace information in the returned array as array elements
+ * @param int $get_attributes 1 or 0. If this is 1 the function will get the attributes as well as the tag values - this results in a different array structure in the return value.
+ * @param string $priority Can be 'tag' or 'attribute'. This will change the way the resulting array sturcture. For 'tag', the tags are given more importance.
+ *
+ * @return array The parsed XML in an array form. Use print_r() to see the resulting array structure.
*/
-
function xml2array($contents, $namespaces = true, $get_attributes=1, $priority = 'attribute') {
- if(!$contents) return array();
+ if(!$contents)
+ return array();
if(!function_exists('xml_parser_create')) {
logger('xml2array: parser function missing');
return array();
}
-
libxml_use_internal_errors(true);
libxml_clear_errors();
@@ -793,6 +816,7 @@ function xml2array($contents, $namespaces = true, $get_attributes=1, $priority =
foreach(libxml_get_errors() as $err)
logger('libxml: parse: ' . $err->code . " at " . $err->line . ":" . $err->column . " : " . $err->message, LOGGER_DATA);
libxml_clear_errors();
+
return;
}
@@ -859,7 +883,6 @@ function xml2array($contents, $namespaces = true, $get_attributes=1, $priority =
$current[$tag]['0_attr'] = $current[$tag.'_attr'];
unset($current[$tag.'_attr']);
}
-
}
$last_item_index = $repeated_tag_index[$tag.'_'.$level]-1;
$current = &$current[$tag][$last_item_index];
@@ -870,7 +893,8 @@ function xml2array($contents, $namespaces = true, $get_attributes=1, $priority =
if(!isset($current[$tag])) { //New Key
$current[$tag] = $result;
$repeated_tag_index[$tag.'_'.$level] = 1;
- if($priority == 'tag' and $attributes_data) $current[$tag. '_attr'] = $attributes_data;
+ if($priority == 'tag' and $attributes_data)
+ $current[$tag. '_attr'] = $attributes_data;
} else { // If taken, put all things inside a list(array)
if(isset($current[$tag][0]) and is_array($current[$tag])) { // If it is already an array...
@@ -882,13 +906,11 @@ function xml2array($contents, $namespaces = true, $get_attributes=1, $priority =
$current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data;
}
$repeated_tag_index[$tag.'_'.$level]++;
-
} else { // If it is not an array...
$current[$tag] = array($current[$tag],$result); //...Make it an array using using the existing value and the new value
$repeated_tag_index[$tag.'_'.$level] = 1;
if($priority == 'tag' and $get_attributes) {
if(isset($current[$tag.'_attr'])) { // The attribute of the last(0th) tag must be moved as well
-
$current[$tag]['0_attr'] = $current[$tag.'_attr'];
unset($current[$tag.'_attr']);
}
@@ -961,53 +983,26 @@ function email_header_encode($in_str, $charset = 'UTF-8') {
return $out_str;
}
-function email_send($addr, $subject, $headers, $item) {
- //$headers .= 'MIME-Version: 1.0' . "\n";
- //$headers .= 'Content-Type: text/html; charset=UTF-8' . "\n";
- //$headers .= 'Content-Type: text/plain; charset=UTF-8' . "\n";
- //$headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n";
-
- $part = uniqid("", true);
-
- $html = prepare_body($item);
-
- $headers .= "Mime-Version: 1.0\n";
- $headers .= 'Content-Type: multipart/alternative; boundary="=_'.$part.'"'."\n\n";
-
- $body = "\n--=_".$part."\n";
- $body .= "Content-Transfer-Encoding: 8bit\n";
- $body .= "Content-Type: text/plain; charset=utf-8; format=flowed\n\n";
-
- $body .= html2plain($html)."\n";
-
- $body .= "--=_".$part."\n";
- $body .= "Content-Transfer-Encoding: 8bit\n";
- $body .= "Content-Type: text/html; charset=utf-8\n\n";
-
- $body .= '<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">'.$html."</body></html>\n";
-
- $body .= "--=_".$part."--";
-
- //$message = '<html><body>' . $html . '</body></html>';
- //$message = html2plain($html);
- logger('notifier: email delivery to ' . $addr);
- mail($addr, $subject, $body, $headers);
-}
-
-
-
-function discover_by_url($url,$arr = null) {
- require_once('library/HTML5/Parser.php');
+/**
+ * @brief Creates an xchan entry for URL.
+ *
+ * @param string $url URL to discover
+ * @param array $arr fallback values if scrape_feed() is empty
+ *
+ * @return boolean
+ */
+function discover_by_url($url, $arr = null) {
$x = scrape_feed($url);
if(! $x) {
if(! $arr)
return false;
+
$network = (($arr['network']) ? $arr['network'] : 'unknown');
- $name = (($arr['name']) ? $arr['name'] : 'unknown');
- $photo = (($arr['photo']) ? $arr['photo'] : '');
- $addr = (($arr['addr']) ? $arr['addr'] : '');
- $guid = $url;
+ $name = (($arr['name']) ? $arr['name'] : 'unknown');
+ $photo = (($arr['photo']) ? $arr['photo'] : '');
+ $addr = (($arr['addr']) ? $arr['addr'] : '');
+ $guid = $url;
}
$profile = $url;
@@ -1025,27 +1020,26 @@ function discover_by_url($url,$arr = null) {
// try and discover stuff from the feeed
- require_once('library/simplepie/simplepie.inc');
$feed = new SimplePie();
$level = 0;
- $x = z_fetch_url($guid,false,$level,array('novalidate' => true));
+ $x = z_fetch_url($guid, false, $level, array('novalidate' => true));
if(! $x['success']) {
- logger('probe_url: feed fetch failed for ' . $poll);
+ logger('Feed fetch failed for ' . $guid);
return false;
}
$xml = $x['body'];
- logger('probe_url: fetch feed: ' . $guid . ' returns: ' . $xml, LOGGER_DATA);
- logger('probe_url: scrape_feed: headers: ' . $x['header'], LOGGER_DATA);
+ logger('Fetch feed: ' . $guid . ' returns: ' . $xml, LOGGER_DATA);
+ logger('scrape_feed: headers: ' . $x['header'], LOGGER_DATA);
// Don't try and parse an empty string
$feed->set_raw_data(($xml) ? $xml : '<?xml version="1.0" encoding="utf-8" ?><xml></xml>');
$feed->init();
if($feed->error())
- logger('probe_url: scrape_feed: Error parsing XML: ' . $feed->error());
+ logger('scrape_feed: Error parsing XML: ' . $feed->error());
- $name = unxmlify(trim($feed->get_title()));
- $photo = $feed->get_image_url();
+ $name = unxmlify(trim($feed->get_title()));
+ $photo = $feed->get_image_url();
$author = $feed->get_author();
if($author) {
@@ -1083,7 +1077,7 @@ function discover_by_url($url,$arr = null) {
$profile = trim(unxmlify($author->get_link()));
}
if(! $photo) {
- $rawmedia = $item->get_item_tags('http://search.yahoo.com/mrss/','thumbnail');
+ $rawmedia = $item->get_item_tags('http://search.yahoo.com/mrss/', 'thumbnail');
if($rawmedia && $rawmedia[0]['attribs']['']['url'])
$photo = unxmlify($rawmedia[0]['attribs']['']['url']);
}
@@ -1097,7 +1091,7 @@ function discover_by_url($url,$arr = null) {
}
}
}
- if($poll === $profile)
+ if($guid === $profile)
$lnk = $feed->get_permalink();
if(isset($lnk) && strlen($lnk))
$profile = $lnk;
@@ -1109,9 +1103,6 @@ function discover_by_url($url,$arr = null) {
if(! $name)
$name = notags($feed->get_description());
- if(! $guid)
- return false;
-
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($guid)
);
@@ -1125,7 +1116,6 @@ function discover_by_url($url,$arr = null) {
[
'xchan_hash' => $guid,
'xchan_guid' => $guid,
- 'xchan_pubkey' => $pubkey,
'xchan_addr' => $addr,
'xchan_url' => $profile,
'xchan_name' => $name,
@@ -1143,30 +1133,17 @@ function discover_by_url($url,$arr = null) {
dbesc($photos[3]),
dbesc($guid)
);
- return true;
+ return true;
}
+function discover_by_webbie($webbie,$protocol = '') {
-function discover_by_webbie($webbie) {
- require_once('library/HTML5/Parser.php');
-
- $result = array();
+ $result = [];
$network = null;
- $diaspora = false;
- $gnusoc = false;
- $dfrn = false;
-
- $has_salmon = false;
- $salmon_key = false;
- $atom_feed = false;
- $diaspora_base = '';
- $diaspora_guid = '';
- $diaspora_key = '';
-
- $webbie = strtolower($webbie);
+// $webbie = strtolower($webbie);
$x = webfinger_rfc7033($webbie,true);
if($x && array_key_exists('links',$x) && $x['links']) {
@@ -1176,7 +1153,7 @@ function discover_by_webbie($webbie) {
// If we discover zot - don't search further; grab the info and get out of
// here.
- if($link['rel'] === PROTOCOL_ZOT) {
+ if($link['rel'] === PROTOCOL_ZOT && ((! $protocol) || (strtolower($protocol) === 'zot'))) {
logger('discover_by_webbie: zot found for ' . $webbie, LOGGER_DEBUG);
if(array_key_exists('zot',$x) && $x['zot']['success']) {
$i = import_xchan($x['zot']);
@@ -1191,317 +1168,23 @@ function discover_by_webbie($webbie) {
}
}
}
- if($link['rel'] == NAMESPACE_DFRN) {
- $dfrn = $link['href'];
- }
- if($link['rel'] == 'magic-public-key') {
- if(substr($link['href'],0,5) === 'data:') {
- $salmon_key = convert_salmon_key($link['href']);
- }
- }
- if($link['rel'] == 'salmon') {
- $has_salmon = true;
- $salmon = $link['href'];
- }
- if($link['rel'] == 'http://schemas.google.com/g/2010#updates-from') {
- $atom_feed = $link['href'];
- }
}
}
}
logger('webfinger: ' . print_r($x,true), LOGGER_DATA, LOG_INFO);
- $arr = array('address' => $webbie, 'success' => false, 'webfinger' => $x);
+ $arr = array('address' => $webbie, 'protocol' => $protocol, 'success' => false, 'webfinger' => $x);
call_hooks('discover_channel_webfinger', $arr);
if($arr['success'])
return true;
- $aliases = array();
-
- // Now let's make some decisions on what we may need
- // to obtain further info
-
- $probe_atom = false;
- $probe_old = false;
- $probe_hcard = false;
-
- $address = '';
- $location = '';
- $nickname = '';
- $fullname = '';
- $avatar = '';
- $pubkey = '';
-
- if(is_array($x)) {
- if(array_key_exists('address',$x))
- $address = $x['address'];
- if(array_key_exists('location',$x))
- $location = $x['location'];
- if(array_key_exists('nickname',$x))
- $nickname = $x['nickname'];
- }
-
- if(! $x)
- $probe_old = true;
-
-
- if((! $dfrn) && (! $has_salmon))
- $probe_old = true;
-
- if($probe_old) {
- $y = old_webfinger($webbie);
- if($y) {
- logger('old_webfinger: ' . print_r($x,true));
- foreach($y as $link) {
- if($link['@attributes']['rel'] === NAMESPACE_DFRN)
- $dfrn = unamp($link['@attributes']['href']);
- if($link['@attributes']['rel'] === 'salmon')
- $notify = unamp($link['@attributes']['href']);
- if($link['@attributes']['rel'] === NAMESPACE_FEED)
- $poll = unamp($link['@attributes']['href']);
- if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard')
- $hcard = unamp($link['@attributes']['href']);
- if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page')
- $profile = unamp($link['@attributes']['href']);
- if($link['@attributes']['rel'] === 'http://portablecontacts.net/spec/1.0')
- $poco = unamp($link['@attributes']['href']);
- if($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location') {
- $diaspora_base = unamp($link['@attributes']['href']);
- $diaspora = true;
- }
- if($link['@attributes']['rel'] === 'http://joindiaspora.com/guid') {
- $diaspora_guid = unamp($link['@attributes']['href']);
- $diaspora = true;
- }
- if($link['@attributes']['rel'] === 'diaspora-public-key') {
- $diaspora_key = base64_decode(unamp($link['@attributes']['href']));
- if(strstr($diaspora_key,'RSA '))
- $pubkey = rsatopem($diaspora_key);
- else
- $pubkey = $diaspora_key;
- $diaspora = true;
- }
- if($link['@attributes']['rel'] == 'magic-public-key') {
- if(substr($link['@attributes']['href'],0,5) === 'data:') {
- $salmon_key = convert_salmon_key($link['@attributes']['href']);
- }
- }
- if($link['@attributes']['rel'] == 'salmon') {
- $has_salmon = true;
- $salmon = $link['@attributes']['href'];
- }
-
- if($link['@attributes']['rel'] == 'http://schemas.google.com/g/2010#updates-from') {
- $atom_feed = $link['@attributes']['href'];
- }
- if($link['@attributes']['rel'] === 'alias') {
- $aliases[] = $link['@attributes']['href'];
- }
- if($link['@attributes']['rel'] === 'subject') {
- $subject = $link['@attributes']['href'];
- }
- }
- }
- }
-
- if($subject || $aliases) {
- if(strpos($webbie,'@')) {
- $rhs = substr($webbie,strpos($webbie,'@')+1);
- }
- else {
- $m = parse_url($webbie);
- if($m) {
- $rhs = $m['host'] . (($m['port']) ? ':' . $m['port'] : '');
- }
- }
-
- $v = array('subject' => $subject,'aliases' => $aliases);
- $address = find_webfinger_address($v,$rhs);
- $location = find_webfinger_location($v,$rhs);
- if($address)
- $nickname = substr($address,0,strpos($address,'@'));
-
- }
-
- if($salmon_key && $has_salmon && $atom_feed && (! $dfrn) && (! $diaspora)) {
- $gnusoc = true;
- $probe_atom = true;
- }
-
- if(! $pubkey)
- $pubkey = $salmon_key;
-
- if(($dfrn || $diaspora) && $hcard)
- $probe_hcard = true;
-
- if(! $fullname)
- $fullname = $nickname;
-
- if($probe_atom) {
- $k = z_fetch_url($atom_feed);
- if($k['success'])
- $feed_meta = feed_meta($k['body']);
- if($feed_meta) {
-
- // stash any discovered pubsubhubbub hubs in case we need to follow them
- // this will save an expensive lookup later
-
- if($feed_meta['hubs'] && $address) {
- set_xconfig($address,'system','push_hubs',$feed_meta['hubs']);
- set_xconfig($address,'system','feed_url',$atom_feed);
- }
- if($feed_meta['author']['author_name']) {
- $fullname = $feed_meta['author']['author_name'];
- }
- if(! $avatar) {
- if($feed_meta['author']['author_photo'])
- $avatar = $feed_meta['author']['author_photo'];
- }
-
- // for GNU-social over-ride any url aliases we may have picked up in webfinger
- // The author.uri element in the feed is likely to be more accurate
-
- if($gnusoc && $feed_meta['author']['author_uri'])
- $location = $feed_meta['author']['author_uri'];
- }
- }
- else {
- if($probe_hcard) {
- $vcard = scrape_vcard($hcard);
- if($vcard) {
- logger('vcard: ' . print_r($vcard,true), LOGGER_DATA);
- if($vcard['fn'])
- $fullname = $vcard['fn'];
- if($vcard['photo'] && (strpos($vcard['photo'],'http') !== 0))
- $vcard['photo'] = $diaspora_base . '/' . $vcard['photo'];
- if(($vcard['public_key']) && (! $pubkey)) {
- $diaspora_key = $vcard['public_key'];
- if(strstr($diaspora_key,'RSA '))
- $pubkey = rsatopem($diaspora_key);
- else
- $pubkey = $diaspora_key;
- }
- if(! $avatar)
- $avatar = $vcard['photo'];
- if($diaspora) {
- if(($vcard['uid']) && (! $diaspora_guid))
- $diaspora_guid = $vcard['uid'];
- if(($vcard['url']) && (! $diaspora_base))
- $diaspora_base = $vcard['url'];
-
-
-
-
- }
-
- }
- }
- }
-
- if(($profile) && (! $location))
- $location = $profile;
-
- if($location) {
- $m = parse_url($location);
- $base = $m['scheme'] . '://' . $m['host'];
- $host = $m['host'];
- }
-
-
- if($diaspora && $diaspora_base && $diaspora_guid) {
- if($dfrn)
- $network = 'friendica-over-diaspora';
- else
- $network = 'diaspora';
-
- $base = trim($diaspora_base,'/');
- $notify = $base . '/receive';
-
- }
- else {
- if($gnusoc) {
- $network = 'gnusoc';
- $notify = $salmon;
- }
- }
-
-
- logger('network: ' . $network);
- logger('address: ' . $address);
- logger('fullname: ' . $fullname);
- logger('pubkey: ' . $pubkey);
- logger('location: ' . $location);
-
-
-
- // if we have everything we need, let's create the records
-
- if($network && $address && $fullname && $pubkey && $location) {
- $r = q("select * from xchan where xchan_hash = '%s' limit 1",
- dbesc($address)
- );
- if($r) {
- $r = q("update xchan set xchan_name = '%s', xchan_network = '%s', xchan_name_date = '%s' where xchan_hash = '%s'",
- dbesc($fullname),
- dbesc($network),
- dbesc(datetime_convert()),
- dbesc($address)
- );
- }
- else {
- $r = xchan_store_lowlevel(
- [
- 'xchan_hash' => $address,
- 'xchan_guid' => (($diaspora_guid) ? $diaspora_guid : $location),
- 'xchan_pubkey' => $pubkey,
- 'xchan_addr' => $address,
- 'xchan_url' => $location,
- 'xchan_name' => $fullname,
- 'xchan_name_date' => datetime_convert(),
- 'xchan_network' => $network
- ]
- );
- }
-
- $r = q("select * from hubloc where hubloc_hash = '%s' limit 1",
- dbesc($address)
- );
-
- if(! $r) {
- $r = hubloc_store_lowlevel(
- [
- 'hubloc_guid' => (($diaspora_guid) ? $diaspora_guid : $location),
- 'hubloc_hash' => $address,
- 'hubloc_addr' => $address,
- 'hubloc_network' => $network,
- 'hubloc_url' => $base,
- 'hubloc_host' => $host,
- 'hubloc_callback' => $notify,
- 'hubloc_updated' => datetime_convert(),
- 'hubloc_primary' => 1
- ]
- );
- }
- $photos = import_xchan_photo($avatar,$address);
- $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'",
- dbescdate(datetime_convert()),
- dbesc($photos[0]),
- dbesc($photos[1]),
- dbesc($photos[2]),
- dbesc($photos[3]),
- dbesc($address)
- );
- return true;
- }
return false;
-}
-
+}
function webfinger_rfc7033($webbie,$zot = false) {
-
if(strpos($webbie,'@')) {
$lhs = substr($webbie,0,strpos($webbie,'@'));
$rhs = substr($webbie,strpos($webbie,'@')+1);
@@ -1520,92 +1203,26 @@ function webfinger_rfc7033($webbie,$zot = false) {
}
logger('fetching url from resource: ' . $rhs . ':' . $webbie);
- $s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : ''));
+ // The default curl Accept: header is */*, which is incorrectly handled by Mastodon servers
+ // and results in a 406 (Not Acceptable) response, and will also incorrectly produce an XML
+ // document if you use 'application/jrd+json, */*'. We could set this to application/jrd+json,
+ // but some test webfinger servers may not explicitly set the content type and they would be
+ // blocked. The best compromise until Mastodon is fixed is to remove the Accept header which is
+ // accomplished by setting it to nothing.
+
+ $counter = 0;
+ $s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : ''),
+ false, $counter, [ 'headers' => [ 'Accept:' ] ]);
if($s['success']) {
$j = json_decode($s['body'],true);
-
- // We could have a number of URL aliases and webbies
- // make an executive decision about the most likely "best" of each
- // by comparing against some examples from known networks we're likely to encounter.
- // Otherwise we have to store every alias that we may ever encounter and
- // validate every URL we ever find against every possible alias
-
- // @fixme pump.io is going to be a real bugger since it doesn't return subject or aliases
- // or provide lookup by url
-
- $j['address'] = find_webfinger_address($j,$rhs);
- $j['location'] = find_webfinger_location($j,$rhs);
- if($j['address'])
- $j['nickname'] = substr($j['address'],0,strpos($j['address'],'@'));
- }
- else
- return false;
-
- return($j);
-}
-
-function find_webfinger_address($j,$rhs) {
- if(is_array($j) && ($j)) {
- if(strpos($j['subject'],'acct:') !== false && strpos($j['subject'],'@' . $rhs))
- return str_replace('acct:','',$j['subject']);
- if($j['aliases']) {
- foreach($j['aliases'] as $alias) {
- if(strpos($alias,'acct:') !== false && strpos($alias,'@' . $rhs)) {
- return str_replace('acct:','',$alias);
- }
- }
- }
+ return($j);
}
- return '';
-}
-
-
-function find_webfinger_location($j,$rhs) {
- if(is_array($j) && ($j)) {
- if(strpos($j['subject'],'http') === 0) {
- $x = match_webfinger_location($j['subject'],$rhs);
- if($x)
- return $x;
- }
- if($j['aliases']) {
- foreach($j['aliases'] as $alias) {
- if(strpos($alias,'http') === 0) {
- $x = match_webfinger_location($alias,$rhs);
- if($x)
- return($x);
- }
- }
- }
- }
- return '';
-}
-
-function match_webfinger_location($s,$h) {
- // GNU-social and the older StatusNet - the $host/user/123 form doesn't work
- if(preg_match('|' . $h . '/index.php/user/([0-9]*?)$|',$s))
- return $s;
- // Redmatrix / hubzilla
- if(preg_match('|' . $h . '/channel/|',$s))
- return $s;
- // Friendica
- if(preg_match('|' . $h . '/profile/|',$s))
- return $s;
+ return false;
- $arr = array('test' => $s, 'host' => $h, 'success' => false);
- call_hooks('match_webfinger_location',$arr);
- if($arr['success'])
- return $s;
- return '';
}
-
-
-
-
-
-
function old_webfinger($webbie) {
$host = '';
@@ -1652,14 +1269,14 @@ function fetch_lrdd_template($host) {
}
if(! strpos($tpl,'{uri}'))
$tpl = '';
- return $tpl;
+ return $tpl;
}
function fetch_xrd_links($url) {
- logger('fetch_xrd_links: ' . $url, LOGGER_DEBUG);
+ logger('url: ' . $url, LOGGER_DEBUG);
$redirects = 0;
$x = z_fetch_url($url,false,$redirects,array('timeout' => 20));
@@ -1668,16 +1285,13 @@ function fetch_xrd_links($url) {
return array();
$xml = $x['body'];
- logger('fetch_xrd_links: ' . $xml, LOGGER_DATA);
+ logger('data: ' . $xml, LOGGER_DATA);
if ((! $xml) || (! stristr($xml,'<xrd')))
return array();
- // fix diaspora's bad xml
- $xml = str_replace(array('href=&quot;','&quot;/>'),array('href="','"/>'),$xml);
-
$h = parse_xml_string($xml);
- if(! $h)
+ if($h === false)
return array();
$arr = convert_xml_element_to_array($h);
@@ -1709,92 +1323,21 @@ function fetch_xrd_links($url) {
$links[]['@attributes'] = array('rel' => 'subject' , 'href' => $arr['xrd']['subject']);
}
- logger('fetch_xrd_links: ' . print_r($links,true), LOGGER_DATA);
+ logger('data: ' . print_r($links, true), LOGGER_DATA);
return $links;
}
-function scrape_vcard($url) {
-
- $ret = array();
-
- logger('scrape_vcard: url=' . $url);
-
- $x = z_fetch_url($url);
- if(! $x['success'])
- return $ret;
-
- $s = $x['body'];
-
- if(! $s)
- return $ret;
-
- $headers = $x['header'];
- $lines = explode("\n",$headers);
- if(count($lines)) {
- foreach($lines as $line) {
- // don't try and run feeds through the html5 parser
- if(stristr($line,'content-type:') && ((stristr($line,'application/atom+xml')) || (stristr($line,'application/rss+xml'))))
- return ret;
- }
- }
-
- try {
- $dom = HTML5_Parser::parse($s);
- } catch (DOMException $e) {
- logger('scrape_vcard: parse error: ' . $e);
- }
-
- if(! $dom)
- return $ret;
-
- // Pull out hCard profile elements
-
- $largest_photo = 0;
-
- $items = $dom->getElementsByTagName('*');
- foreach($items as $item) {
- if(attribute_contains($item->getAttribute('class'), 'vcard')) {
- $level2 = $item->getElementsByTagName('*');
- foreach($level2 as $x) {
- if(attribute_contains($x->getAttribute('id'),'pod_location'))
- $ret['pod_location'] = $x->textContent;
- if(attribute_contains($x->getAttribute('class'),'fn'))
- $ret['fn'] = $x->textContent;
- if(attribute_contains($x->getAttribute('class'),'uid'))
- $ret['uid'] = $x->textContent;
- if(attribute_contains($x->getAttribute('class'),'nickname'))
- $ret['nick'] = $x->textContent;
- if(attribute_contains($x->getAttribute('class'),'searchable'))
- $ret['searchable'] = $x->textContent;
- if(attribute_contains($x->getAttribute('class'),'key'))
- $ret['public_key'] = $x->textContent;
- if(attribute_contains($x->getAttribute('class'),'given_name'))
- $ret['given_name'] = $x->textContent;
- if(attribute_contains($x->getAttribute('class'),'family_name'))
- $ret['family_name'] = $x->textContent;
- if(attribute_contains($x->getAttribute('class'),'url'))
- $ret['url'] = $x->textContent;
-
- if((attribute_contains($x->getAttribute('class'),'photo'))
- || (attribute_contains($x->getAttribute('class'),'avatar'))) {
- $size = intval($x->getAttribute('width'));
- if(($size > $largest_photo) || (! $largest_photo)) {
- $ret['photo'] = $x->getAttribute('src');
- $largest_photo = $size;
- }
- }
- }
- }
- }
-
- return $ret;
-}
-
-
+/**
+ * @brief
+ *
+ * @param string $url The URL to scrape
+ * @return array
+ */
function scrape_feed($url) {
+ require_once('library/HTML5/Parser.php');
$ret = array();
$level = 0;
@@ -1807,15 +1350,14 @@ function scrape_feed($url) {
$code = $x['return_code'];
$s = $x['body'];
- logger('scrape_feed: returns: ' . $code . ' headers=' . $headers, LOGGER_DEBUG);
+ logger('returns: ' . $code . ' headers=' . $headers, LOGGER_DEBUG);
if(! $s) {
- logger('scrape_feed: no data returned for ' . $url);
+ logger('No data returned for ' . $url);
return $ret;
}
-
- $lines = explode("\n",$headers);
+ $lines = explode("\n", $headers);
if(count($lines)) {
foreach($lines as $line) {
if(stristr($line,'content-type:')) {
@@ -1839,15 +1381,14 @@ function scrape_feed($url) {
try {
$dom = HTML5_Parser::parse($s);
} catch (DOMException $e) {
- logger('scrape_feed: parse error: ' . $e);
+ logger('Parse error: ' . $e);
}
if(! $dom) {
- logger('scrape_feed: failed to parse.');
+ logger('Failed to parse.');
return $ret;
}
-
$head = $dom->getElementsByTagName('base');
if($head) {
foreach($head as $head0) {
@@ -1888,112 +1429,6 @@ function scrape_feed($url) {
-function service_plink($contact, $guid) {
-
- $plink = '';
-
- $m = parse_url($contact['xchan_url']);
- if($m) {
- $url = $m['scheme'] . '://' . $m['host'] . (($m['port']) ? ':' . $m['port'] : '');
- }
- else
- $url = 'https://' . substr($contact['xchan_addr'],strpos($contact['xchan_addr'],'@')+1);
-
- $handle = substr($contact['xchan_addr'], 0, strpos($contact['xchan_addr'],'@'));
-
- if($contact['xchan_network'] === 'diaspora')
- $plink = $url . '/posts/' . $guid;
- if($contact['xchan_network'] === 'friendica-over-diaspora')
- $plink = $url . '/display/' . $handle . '/' . $guid;
- if($contact['xchan_network'] === 'zot')
- $plink = $url . '/channel/' . $handle . '?f=&mid=' . $guid;
-
- return $plink;
-}
-
-
-function format_and_send_email($sender,$xchan,$item) {
-
- $title = $item['title'];
- $body = $item['body'];
-
- $textversion = strip_tags(html_entity_decode(bbcode(str_replace(array("\\r", "\\n"), array( "", "\n"), $body)),ENT_QUOTES,'UTF-8'));
-
- $htmlversion = bbcode(str_replace(array("\\r","\\n"), array("","<br />\n"),$body));
-
- $banner = t('$Projectname Notification');
- $product = t('$projectname'); // PLATFORM_NAME;
- $siteurl = z_root();
- $thanks = t('Thank You,');
- $sitename = get_config('system','sitename');
- $site_admin = sprintf( t('%s Administrator'), $sitename);
-
- // load the template for private message notifications
- $tpl = get_markup_template('email_notify_html.tpl');
- $email_html_body = replace_macros($tpl,array(
- '$banner' => $banner,
- '$notify_icon' => Zotlabs\Lib\System::get_notify_icon(),
- '$product' => $product,
- '$preamble' => '',
- '$sitename' => $sitename,
- '$siteurl' => $siteurl,
- '$source_name' => $sender['xchan_name'],
- '$source_link' => $sender['xchan_url'],
- '$source_photo' => $sender['xchan_photo_m'],
- '$username' => $xchan['xchan_name'],
- '$hsitelink' => $datarray['hsitelink'],
- '$hitemlink' => $datarray['hitemlink'],
- '$thanks' => $thanks,
- '$site_admin' => $site_admin,
- '$title' => $title,
- '$htmlversion' => $htmlversion,
- ));
-
- // load the template for private message notifications
- $tpl = get_markup_template('email_notify_text.tpl');
- $email_text_body = replace_macros($tpl, array(
- '$banner' => $banner,
- '$product' => $product,
- '$preamble' => '',
- '$sitename' => $sitename,
- '$siteurl' => $siteurl,
- '$source_name' => $sender['xchan_name'],
- '$source_link' => $sender['xchan_url'],
- '$source_photo' => $sender['xchan_photo_m'],
- '$username' => $xchan['xchan_name'],
- '$hsitelink' => $datarray['hsitelink'],
- '$hitemlink' => $datarray['hitemlink'],
- '$thanks' => $thanks,
- '$site_admin' => $site_admin,
- '$title' => $title,
- '$textversion' => $textversion
- ));
-
- $sender_name = t('Administrator');
-
- $hostname = App::get_hostname();
- if(strpos($hostname,':'))
- $hostname = substr($hostname,0,strpos($hostname,':'));
- $sender_email = get_config('system','reply_address');
- if(! $sender_email)
- $sender_email = 'noreply' . '@' . $hostname;
-
- // use the EmailNotification library to send the message
-
- Zotlabs\Lib\Enotify::send(array(
- 'fromName' => $product,
- 'fromEmail' => $sender_email,
- 'replyTo' => $sender_email,
- 'toEmail' => str_replace('mailto:','',$xchan['xchan_addr']),
- 'messageSubject' => (($title) ? $title : t('No Subject')),
- 'htmlVersion' => $email_html_body,
- 'textVersion' => $email_text_body,
- 'additionalMailHeader' => '',
- ));
-
-}
-
-
function do_delivery($deliveries) {
if(! (is_array($deliveries) && count($deliveries)))
@@ -2028,8 +1463,6 @@ function do_delivery($deliveries) {
if($deliver)
Zotlabs\Daemon\Master::Summon(array('Deliver',$deliver));
-
-
}
@@ -2086,7 +1519,7 @@ function get_site_info() {
$commit = '';
}
else {
- $version = $commit = '';
+ $version = $commit = '';
}
//Statistics
@@ -2103,49 +1536,53 @@ function get_site_info() {
foreach(App::$config['feature_lock'] as $k => $v) {
if($k === 'config_loaded')
continue;
+
$locked_features[$k] = intval($v);
}
}
-
- $data = Array(
- 'version' => $version,
- 'version_tag' => $tag,
- 'server_role' => Zotlabs\Lib\System::get_server_role(),
- 'commit' => $commit,
- 'url' => z_root(),
- 'plugins' => $visible_plugins,
- 'register_policy' => $register_policy[get_config('system','register_policy')],
- 'invitation_only' => intval(get_config('system','invitation_only')),
- 'directory_mode' => $directory_mode[get_config('system','directory_mode')],
- 'language' => get_config('system','language'),
- 'rss_connections' => intval(get_config('system','feed_contacts')),
- 'expiration' => $site_expire,
+ $data = [
+ 'url' => z_root(),
+ 'platform' => Zotlabs\Lib\System::get_platform_name(),
+ 'site_name' => (($site_name) ? $site_name : ''),
+ 'version' => $version,
+ 'version_tag' => $tag,
+ 'server_role' => Zotlabs\Lib\System::get_server_role(),
+ 'commit' => $commit,
+ 'plugins' => $visible_plugins,
+ 'register_policy' => $register_policy[get_config('system','register_policy')],
+ 'invitation_only' => intval(get_config('system','invitation_only')),
+ 'directory_mode' => $directory_mode[get_config('system','directory_mode')],
+ 'language' => get_config('system','language'),
+ 'rss_connections' => intval(get_config('system','feed_contacts')),
+ 'expiration' => $site_expire,
'default_service_restrictions' => $service_class,
- 'locked_features' => $locked_features,
- 'admin' => $admin,
- 'site_name' => (($site_name) ? $site_name : ''),
- 'platform' => Zotlabs\Lib\System::get_platform_name(),
- 'dbdriver' => DBA::$dba->getdriver(),
- 'lastpoll' => get_config('system','lastpoll'),
- 'info' => (($site_info) ? $site_info : ''),
- 'channels_total' => $channels_total_stat,
- 'channels_active_halfyear' => $channels_active_halfyear_stat,
- 'channels_active_monthly' => $channels_active_monthly_stat,
- 'local_posts' => $local_posts_stat,
- 'hide_in_statistics' => $hide_in_statistics
- );
+ 'locked_features' => $locked_features,
+ 'admin' => $admin,
+ 'dbdriver' => DBA::$dba->getdriver(),
+ 'lastpoll' => get_config('system','lastpoll'),
+ 'info' => (($site_info) ? $site_info : ''),
+ 'channels_total' => $channels_total_stat,
+ 'channels_active_halfyear' => $channels_active_halfyear_stat,
+ 'channels_active_monthly' => $channels_active_monthly_stat,
+ 'local_posts' => $local_posts_stat,
+ 'hide_in_statistics' => $hide_in_statistics
+ ];
+
return $data;
}
-
-
+/**
+ * @brief
+ *
+ * @param string $url
+ * @return boolean
+ */
function check_siteallowed($url) {
$retvalue = true;
-
$arr = array('url' => $url);
call_hooks('check_siteallowed',$arr);
@@ -2171,9 +1608,16 @@ function check_siteallowed($url) {
}
}
}
+
return $retvalue;
}
+/**
+ * @brief
+ *
+ * @param string $hash
+ * @return boolean
+ */
function check_channelallowed($hash) {
$retvalue = true;
@@ -2203,13 +1647,22 @@ function check_channelallowed($hash) {
}
}
}
+
return $retvalue;
}
function deliverable_singleton($channel_id,$xchan) {
+
+ if(array_key_exists('xchan_hash',$xchan))
+ $xchan_hash = $xchan['xchan_hash'];
+ elseif(array_key_exists('hubloc_hash',$xchan))
+ $xchan_hash = $xchan['hubloc_hash'];
+ else
+ return true;
+
$r = q("select abook_instance from abook where abook_channel = %d and abook_xchan = '%s' limit 1",
intval($channel_id),
- dbesc($xchan['xchan_hash'])
+ dbesc($xchan_hash)
);
if($r) {
if(! $r[0]['abook_instance'])
@@ -2233,24 +1686,30 @@ function get_repository_version($branch = 'master') {
return $matches[3];
}
return '?.?';
-
}
+/**
+ * @brief Get translated network name.
+ *
+ * @param string $s Network string, see boot.php
+ * @return string Translated name of the network
+ */
function network_to_name($s) {
$nets = array(
- NETWORK_DFRN => t('Friendica'),
- NETWORK_FRND => t('Friendica'),
- NETWORK_OSTATUS => t('OStatus'),
- NETWORK_GNUSOCIAL => t('GNU-Social'),
- NETWORK_FEED => t('RSS/Atom'),
- NETWORK_MAIL => t('Email'),
- NETWORK_DIASPORA => t('Diaspora'),
- NETWORK_FACEBOOK => t('Facebook'),
- NETWORK_ZOT => t('Zot'),
- NETWORK_LINKEDIN => t('LinkedIn'),
- NETWORK_XMPP => t('XMPP/IM'),
- NETWORK_MYSPACE => t('MySpace'),
+ NETWORK_DFRN => t('Friendica'),
+ NETWORK_FRND => t('Friendica'),
+ NETWORK_OSTATUS => t('OStatus'),
+ NETWORK_GNUSOCIAL => t('GNU-Social'),
+ NETWORK_FEED => t('RSS/Atom'),
+ NETWORK_ACTIVITYPUB => t('ActivityPub'),
+ NETWORK_MAIL => t('Email'),
+ NETWORK_DIASPORA => t('Diaspora'),
+ NETWORK_FACEBOOK => t('Facebook'),
+ NETWORK_ZOT => t('Zot'),
+ NETWORK_LINKEDIN => t('LinkedIn'),
+ NETWORK_XMPP => t('XMPP/IM'),
+ NETWORK_MYSPACE => t('MySpace'),
);
call_hooks('network_to_name', $nets);
@@ -2258,27 +1717,24 @@ function network_to_name($s) {
$search = array_keys($nets);
$replace = array_values($nets);
- return str_replace($search,$replace,$s);
-
+ return str_replace($search, $replace, $s);
}
-
+/**
+ * @brief Send a text email message.
+ *
+ * @param array $params an assoziative array with:
+ * * \e string \b fromName name of the sender
+ * * \e string \b fromEmail email of the sender
+ * * \e string \b replyTo replyTo address to direct responses
+ * * \e string \b toEmail destination email address
+ * * \e string \b messageSubject subject of the message
+ * * \e string \b htmlVersion html version of the message
+ * * \e string \b textVersion text only version of the message
+ * * \e string \b additionalMailHeader additions to the smtp mail header
+ */
function z_mail($params) {
- /**
- * @brief Send a text email message
- *
- * @param array $params an assoziative array with:
- * * \e string \b fromName name of the sender
- * * \e string \b fromEmail email of the sender
- * * \e string \b replyTo replyTo address to direct responses
- * * \e string \b toEmail destination email address
- * * \e string \b messageSubject subject of the message
- * * \e string \b htmlVersion html version of the message
- * * \e string \b textVersion text only version of the message
- * * \e string \b additionalMailHeader additions to the smtp mail header
- */
-
if(! $params['fromEmail']) {
$params['fromEmail'] = get_config('system','from_email');
if(! $params['fromEmail'])
@@ -2324,8 +1780,13 @@ function z_mail($params) {
return $res;
}
-// discover the best API path available for redmatrix/hubzilla servers
+/**
+ * @brief Discover the best API path available for redmatrix/hubzilla servers.
+ *
+ * @param string $host
+ * @return string
+ */
function probe_api_path($host) {
$schemes = ['https', 'http' ];
@@ -2335,10 +1796,182 @@ function probe_api_path($host) {
foreach($paths as $path) {
$curpath = $scheme . '://' . $host . $path;
$x = z_fetch_url($curpath);
- if($x['success'] && ! strlen($x['body'],'not implemented'))
- return str_replace('version','',$curpath);
+ if($x['success'] && ! strlen($x['body'], 'not implemented'))
+ return str_replace('version', '', $curpath);
}
}
return '';
}
+
+
+function scrape_vcard($url) {
+
+ require_once('library/HTML5/Parser.php');
+
+ $ret = array();
+
+ logger('url=' . $url);
+
+ $x = z_fetch_url($url);
+ if(! $x['success'])
+ return $ret;
+
+ $s = $x['body'];
+
+ if(! $s)
+ return $ret;
+
+ $headers = $x['header'];
+ $lines = explode("\n",$headers);
+ if(count($lines)) {
+ foreach($lines as $line) {
+ // don't try and run feeds through the html5 parser
+ if(stristr($line,'content-type:') && ((stristr($line,'application/atom+xml')) || (stristr($line,'application/rss+xml'))))
+ return ret;
+ }
+ }
+
+ try {
+ $dom = HTML5_Parser::parse($s);
+ } catch (DOMException $e) {
+ logger('Parse error: ' . $e);
+ }
+
+ if(! $dom)
+ return $ret;
+
+ // Pull out hCard profile elements
+
+ $largest_photo = 0;
+
+ $items = $dom->getElementsByTagName('*');
+ foreach($items as $item) {
+ if(attribute_contains($item->getAttribute('class'), 'vcard')) {
+ $level2 = $item->getElementsByTagName('*');
+ foreach($level2 as $x) {
+ if(attribute_contains($x->getAttribute('id'),'pod_location'))
+ $ret['pod_location'] = $x->textContent;
+ if(attribute_contains($x->getAttribute('class'),'fn'))
+ $ret['fn'] = $x->textContent;
+ if(attribute_contains($x->getAttribute('class'),'uid'))
+ $ret['uid'] = $x->textContent;
+ if(attribute_contains($x->getAttribute('class'),'nickname'))
+ $ret['nick'] = $x->textContent;
+ if(attribute_contains($x->getAttribute('class'),'searchable'))
+ $ret['searchable'] = $x->textContent;
+ if(attribute_contains($x->getAttribute('class'),'key'))
+ $ret['public_key'] = $x->textContent;
+ if(attribute_contains($x->getAttribute('class'),'given_name'))
+ $ret['given_name'] = $x->textContent;
+ if(attribute_contains($x->getAttribute('class'),'family_name'))
+ $ret['family_name'] = $x->textContent;
+ if(attribute_contains($x->getAttribute('class'),'url'))
+ $ret['url'] = $x->textContent;
+
+ if((attribute_contains($x->getAttribute('class'),'photo'))
+ || (attribute_contains($x->getAttribute('class'),'avatar'))) {
+ $size = intval($x->getAttribute('width'));
+ if(($size > $largest_photo) || (! $largest_photo)) {
+ $ret['photo'] = $x->getAttribute('src');
+ $largest_photo = $size;
+ }
+ }
+ }
+ }
+ }
+
+ return $ret;
+}
+
+function service_plink($contact, $guid) {
+
+ $plink = '';
+
+ $m = parse_url($contact['xchan_url']);
+ if($m) {
+ $url = $m['scheme'] . '://' . $m['host'] . (($m['port']) ? ':' . $m['port'] : '');
+ }
+ else {
+ $url = 'https://' . substr($contact['xchan_addr'],strpos($contact['xchan_addr'],'@')+1);
+ }
+
+ $handle = substr($contact['xchan_addr'], 0, strpos($contact['xchan_addr'],'@'));
+
+ $plink = $url . '/channel/' . $handle . '?f=&mid=' . $guid;
+
+ $x = [ 'xchan' => $contact, 'guid' => $guid, 'url' => $url, 'plink' => $plink ];
+ call_hooks('service_plink', $x);
+
+ return $x['plink'];
+}
+
+function getBestSupportedMimeType($mimeTypes = null, $acceptedTypes = false) {
+ // Values will be stored in this array
+
+ if($acceptedTypes === false)
+ $acceptedTypes = $_SERVER['HTTP_ACCEPT'];
+
+ $AcceptTypes = Array ();
+
+ // Accept header is case insensitive, and whitespace isn’t important
+ $accept = strtolower(str_replace(' ', '', $acceptedTypes));
+ // divide it into parts in the place of a ","
+ $accept = explode(',', $accept);
+ foreach ($accept as $a) {
+ // the default quality is 1.
+ $q = 1;
+ // check if there is a different quality
+ if (strpos($a, ';q=')) {
+ // divide "mime/type;q=X" into two parts: "mime/type" i "X"
+ list($a, $q) = explode(';q=', $a);
+ }
+ // mime-type $a is accepted with the quality $q
+ // WARNING: $q == 0 means, that mime-type isn’t supported!
+ $AcceptTypes[$a] = $q;
+ }
+ arsort($AcceptTypes);
+
+ // if no parameter was passed, just return parsed data
+ if (!$mimeTypes) return $AcceptTypes;
+
+ $mimeTypes = array_map('strtolower', (array)$mimeTypes);
+
+ // let’s check our supported types:
+ foreach ($AcceptTypes as $mime => $q) {
+ if ($q && in_array($mime, $mimeTypes)) return $mime;
+ }
+ // no mime-type found
+ return null;
+}
+
+
+function jsonld_document_loader($url) {
+
+ // perform caching for jsonld normaliser
+
+ require_once('library/jsonld/jsonld.php');
+
+ $cachepath = 'store/[data]/ldcache';
+ if(! is_dir($cachepath))
+ os_mkdir($cachepath,STORAGE_DEFAULT_PERMISSIONS,true);
+
+ $filename = $cachepath . '/' . urlencode($url);
+ if(file_exists($filename) && filemtime($filename) > time() - (12 * 60 * 60)) {
+ return json_decode(file_get_contents($filename));
+ }
+
+ $r = jsonld_default_document_loader($url);
+ if($r) {
+ file_put_contents($filename,json_encode($r));
+ return $r;
+ }
+
+ logger('not found');
+ if(file_exists($filename)) {
+ return json_decode(file_get_contents($filename));
+ }
+
+ return [];
+
+} \ No newline at end of file